diff --git a/.github/build.in.yml b/.github/build.in.yml
index 1151b959d0691..4d0134b8b6c39 100644
--- a/.github/build.in.yml
+++ b/.github/build.in.yml
@@ -1,4 +1,8 @@
-# This is the master file for autogenerating `.github/workflows/{bors, build_fork, build }.yml`.
+### NB: This is the master file for autogenerating
+### NB: `.github/workflows/{bors, build_fork, build}.yml`.
+### NB: If you need to edit any of those files, you should edit this file instead,
+### NB: and regenerate those files by manually running
+### NB: .github/workflows/mk_build_yml.sh
jobs:
# Cancels previous runs of jobs in this file
@@ -29,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
@@ -69,25 +73,6 @@ jobs:
run: |
./scripts/lint-bib.sh
- check_workflows:
- if: github.repository MAIN_OR_FORK 'leanprover-community/mathlib4'
- name: check workflowsJOB_NAME
- runs-on: ubuntu-latest
- steps:
- - name: cleanup
- run: |
- find . -name . -o -prune -exec rm -rf -- {} +
-
- - uses: actions/checkout@v4
-
- - name: update workflows
- run: |
- cd .github/workflows/
- ./mk_build_yml.sh
-
- - name: check that workflows were consistent
- run: git diff --exit-code
-
build:
if: github.repository MAIN_OR_FORK 'leanprover-community/mathlib4'
name: BuildJOB_NAME
@@ -107,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: |
@@ -130,9 +115,6 @@ jobs:
lean --version
lake --version
- - name: check {Mathlib, Tactic, Counterexamples, Archive}.lean are up to date
- run: lake exe mk_all --check
-
- name: build cache
run: |
lake build cache
@@ -151,8 +133,20 @@ jobs:
run: |
rm -rf .lake/build/lib/Mathlib/
# Fail quickly if the cache is completely cold, by checking for Mathlib.Init
- lake exe cache get Mathlib.Init
- lake build --no-build Mathlib.Init && lake exe cache get || echo "No cache for 'Mathlib.Init' available"
+ lake exe cache get #Mathlib.Init
+ #lake build --no-build Mathlib.Init && lake exe cache get || echo "No cache for 'Mathlib.Init' available"
+
+ - name: update {Mathlib, Tactic, Counterexamples, Archive}.lean
+ id: mk_all
+ run: |
+
+ if ! lake exe mk_all --check
+ then
+ echo "Not all lean files are in the import all files"
+ echo "mk_all=false" >> "${GITHUB_OUTPUT}"
+ else
+ echo "mk_all=true" >> "${GITHUB_OUTPUT}"
+ fi
- name: build mathlib
id: build
@@ -216,6 +210,14 @@ jobs:
MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }}
MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }}
+ - name: Check {Mathlib, Tactic, Counterexamples, Archive}.lean
+ run: |
+ if [ ${{ steps.mk_all.outputs.mk_all }} == "false" ]
+ then
+ echo "Please run 'lake exe mk_all' to regenerate the import all files"
+ exit 1
+ fi
+
- name: check for noisy stdout lines
id: noisy
run: |
@@ -276,7 +278,7 @@ jobs:
# Output is posted to the zulip topic
# https://leanprover.zulipchat.com/#narrow/stream/345428-mathlib-reviewers/topic/lean4checker
- - name: Post comments for lean-pr-testing branch
+ - name: Post comments for lean-pr-testing-NNNN and batteries-pr-testing-NNNN branches
if: always()
env:
TOKEN: ${{ secrets.LEAN_PR_TESTING }}
@@ -289,7 +291,8 @@ jobs:
LINT_OUTCOME: ${{ steps.lint.outcome }}
TEST_OUTCOME: ${{ steps.test.outcome }}
run: |
- scripts/lean-pr-testing-comments.sh
+ scripts/lean-pr-testing-comments.sh lean
+ scripts/lean-pr-testing-comments.sh batteries
final:
name: Post-CI jobJOB_NAME
@@ -300,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/PR_summary.yml b/.github/workflows/PR_summary.yml
index 25529d869f64b..bbde4ace8c7e5 100644
--- a/.github/workflows/PR_summary.yml
+++ b/.github/workflows/PR_summary.yml
@@ -55,12 +55,27 @@ jobs:
PR="${{ github.event.pull_request.number }}"
title="### PR summary"
+ graphAndHighPercentReports=$(python ./scripts/import-graph-report.py base.json head.json changed_files.txt)
+
## Import count comment
importCount=$(
- python ./scripts/import-graph-report.py base.json head.json changed_files.txt
+ printf '%s\n' "${graphAndHighPercentReports}" | sed '/^Import changes exceeding/Q'
./scripts/import_trans_difference.sh
)
+ ## High percentage imports
+ high_percentages=$(
+ printf '%s\n' "${graphAndHighPercentReports}" | sed -n '/^Import changes exceeding/,$p'
+ )
+ # if there are files with large increase in transitive imports, then we add the `large-import` label
+ if [ -n "${high_percentages}" ]
+ then
+ high_percentages=$'\n\n'"${high_percentages}"
+ gh pr edit "${PR}" --add-label large-import
+ else # otherwise, we remove the label
+ gh pr edit "${PR}" --remove-label large-import
+ fi
+
if [ "$(printf '%s' "${importCount}" | wc -l)" -gt 12 ]
then
importCount="$(printf '\n\n%s\n\n\n\n%s\n\n\n' "#### Import changes for modified files" "${importCount}")"
@@ -80,6 +95,6 @@ jobs:
currentHash="$(git rev-parse HEAD)"
hashURL="https://github.com/${{ github.repository }}/pull/${{ github.event.pull_request.number }}/commits/${currentHash}"
- message="$(printf '%s [%s](%s)\n\n%s\n\n---\n\n%s\n' "${title}" "$(git rev-parse --short HEAD)" "${hashURL}" "${importCount}" "${declDiff}")"
+ message="$(printf '%s [%s](%s)%s\n\n%s\n\n---\n\n%s\n' "${title}" "$(git rev-parse --short HEAD)" "${hashURL}" "${high_percentages}" "${importCount}" "${declDiff}")"
./scripts/update_PR_comment.sh "${message}" "${title}" "${PR}"
diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml
index dd9a83c59a2b3..5d422196fdf43 100644
--- a/.github/workflows/actionlint.yml
+++ b/.github/workflows/actionlint.yml
@@ -1,10 +1,5 @@
-name: Actionlint
+name: Check workflows
on:
- push:
- branches:
- - 'master'
- paths:
- - '.github/**'
pull_request:
paths:
- '.github/**'
@@ -14,7 +9,28 @@ jobs:
actionlint:
runs-on: ubuntu-latest
steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: actionlint
- uses: raven-actions/actionlint@v1
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: suggester / actionlint
+ uses: reviewdog/action-actionlint@v1
+ with:
+ tool_name: actionlint
+ fail_on_error: true
+
+ check_build_yml:
+ name: check workflows generated by build.in.yml
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: update workflows
+ run: |
+ cd .github/workflows/
+ ./mk_build_yml.sh
+
+ - name: suggester / build.in.yml
+ uses: reviewdog/action-suggester@v1
+ with:
+ tool_name: mk_build_yml.sh
+ fail_on_error: true
diff --git a/.github/workflows/add_label_from_diff.yaml b/.github/workflows/add_label_from_diff.yaml
new file mode 100644
index 0000000000000..271ac1b95ce59
--- /dev/null
+++ b/.github/workflows/add_label_from_diff.yaml
@@ -0,0 +1,42 @@
+name: Autolabel PRs
+
+on:
+ pull_request:
+ types: [opened]
+ push:
+ paths:
+ - scripts/autolabel.lean
+ - .github/workflows/add_label_from_diff.yaml
+
+jobs:
+ add_topic_label:
+ name: Add topic label
+ runs-on: ubuntu-latest
+ # Don't run on forks, where we wouldn't have permissions to add the label anyway.
+ if: github.repository == 'leanprover-community/mathlib4'
+ permissions:
+ issues: write
+ checks: write
+ pull-requests: write
+ contents: read
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: install elan
+ run: |
+ set -o pipefail
+ curl -sSfL https://github.com/leanprover/elan/releases/download/v3.1.1/elan-x86_64-unknown-linux-gnu.tar.gz | tar xz
+ ./elan-init -y --default-toolchain none
+ echo "$HOME/.elan/bin" >> "${GITHUB_PATH}"
+ - name: lake exe autolabel
+ run: |
+ # the checkout dance, to avoid a detached head
+ git checkout master
+ git checkout -
+ lake exe autolabel "$NUMBER"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GH_REPO: ${{ github.repository }}
+ NUMBER: ${{ github.event.number }}
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 41eca3afd4043..816f0864dc82c 100644
--- a/.github/workflows/bors.yml
+++ b/.github/workflows/bors.yml
@@ -1,7 +1,8 @@
# DO NOT EDIT THIS FILE!!!
# This file is automatically generated by mk_build_yml.sh
-# Edit .github/build.in.yml instead and run mk_build_yml.sh to update.
+# Edit .github/build.in.yml instead and run
+# .github/workflows/mk_build_yml.sh to update.
# Forks of mathlib and other projects should be able to use build_fork.yml directly
# The jobs in this file run on self-hosted workers and will not be run from external forks
@@ -42,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
@@ -82,25 +83,6 @@ jobs:
run: |
./scripts/lint-bib.sh
- check_workflows:
- if: github.repository == 'leanprover-community/mathlib4'
- name: check workflows
- runs-on: ubuntu-latest
- steps:
- - name: cleanup
- run: |
- find . -name . -o -prune -exec rm -rf -- {} +
-
- - uses: actions/checkout@v4
-
- - name: update workflows
- run: |
- cd .github/workflows/
- ./mk_build_yml.sh
-
- - name: check that workflows were consistent
- run: git diff --exit-code
-
build:
if: github.repository == 'leanprover-community/mathlib4'
name: Build
@@ -120,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: |
@@ -143,9 +125,6 @@ jobs:
lean --version
lake --version
- - name: check {Mathlib, Tactic, Counterexamples, Archive}.lean are up to date
- run: lake exe mk_all --check
-
- name: build cache
run: |
lake build cache
@@ -164,8 +143,20 @@ jobs:
run: |
rm -rf .lake/build/lib/Mathlib/
# Fail quickly if the cache is completely cold, by checking for Mathlib.Init
- lake exe cache get Mathlib.Init
- lake build --no-build Mathlib.Init && lake exe cache get || echo "No cache for 'Mathlib.Init' available"
+ lake exe cache get #Mathlib.Init
+ #lake build --no-build Mathlib.Init && lake exe cache get || echo "No cache for 'Mathlib.Init' available"
+
+ - name: update {Mathlib, Tactic, Counterexamples, Archive}.lean
+ id: mk_all
+ run: |
+
+ if ! lake exe mk_all --check
+ then
+ echo "Not all lean files are in the import all files"
+ echo "mk_all=false" >> "${GITHUB_OUTPUT}"
+ else
+ echo "mk_all=true" >> "${GITHUB_OUTPUT}"
+ fi
- name: build mathlib
id: build
@@ -229,6 +220,14 @@ jobs:
MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }}
MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }}
+ - name: Check {Mathlib, Tactic, Counterexamples, Archive}.lean
+ run: |
+ if [ ${{ steps.mk_all.outputs.mk_all }} == "false" ]
+ then
+ echo "Please run 'lake exe mk_all' to regenerate the import all files"
+ exit 1
+ fi
+
- name: check for noisy stdout lines
id: noisy
run: |
@@ -289,7 +288,7 @@ jobs:
# Output is posted to the zulip topic
# https://leanprover.zulipchat.com/#narrow/stream/345428-mathlib-reviewers/topic/lean4checker
- - name: Post comments for lean-pr-testing branch
+ - name: Post comments for lean-pr-testing-NNNN and batteries-pr-testing-NNNN branches
if: always()
env:
TOKEN: ${{ secrets.LEAN_PR_TESTING }}
@@ -302,7 +301,8 @@ jobs:
LINT_OUTCOME: ${{ steps.lint.outcome }}
TEST_OUTCOME: ${{ steps.test.outcome }}
run: |
- scripts/lean-pr-testing-comments.sh
+ scripts/lean-pr-testing-comments.sh lean
+ scripts/lean-pr-testing-comments.sh batteries
final:
name: Post-CI job
@@ -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 51161130cfb33..f1c9dfc8fc360 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,7 +1,8 @@
# DO NOT EDIT THIS FILE!!!
# This file is automatically generated by mk_build_yml.sh
-# Edit .github/build.in.yml instead and run mk_build_yml.sh to update.
+# Edit .github/build.in.yml instead and run
+# .github/workflows/mk_build_yml.sh to update.
# Forks of mathlib and other projects should be able to use build_fork.yml directly
# The jobs in this file run on self-hosted workers and will not be run from external forks
@@ -49,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
@@ -89,25 +90,6 @@ jobs:
run: |
./scripts/lint-bib.sh
- check_workflows:
- if: github.repository == 'leanprover-community/mathlib4'
- name: check workflows
- runs-on: ubuntu-latest
- steps:
- - name: cleanup
- run: |
- find . -name . -o -prune -exec rm -rf -- {} +
-
- - uses: actions/checkout@v4
-
- - name: update workflows
- run: |
- cd .github/workflows/
- ./mk_build_yml.sh
-
- - name: check that workflows were consistent
- run: git diff --exit-code
-
build:
if: github.repository == 'leanprover-community/mathlib4'
name: Build
@@ -127,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: |
@@ -150,9 +132,6 @@ jobs:
lean --version
lake --version
- - name: check {Mathlib, Tactic, Counterexamples, Archive}.lean are up to date
- run: lake exe mk_all --check
-
- name: build cache
run: |
lake build cache
@@ -171,8 +150,20 @@ jobs:
run: |
rm -rf .lake/build/lib/Mathlib/
# Fail quickly if the cache is completely cold, by checking for Mathlib.Init
- lake exe cache get Mathlib.Init
- lake build --no-build Mathlib.Init && lake exe cache get || echo "No cache for 'Mathlib.Init' available"
+ lake exe cache get #Mathlib.Init
+ #lake build --no-build Mathlib.Init && lake exe cache get || echo "No cache for 'Mathlib.Init' available"
+
+ - name: update {Mathlib, Tactic, Counterexamples, Archive}.lean
+ id: mk_all
+ run: |
+
+ if ! lake exe mk_all --check
+ then
+ echo "Not all lean files are in the import all files"
+ echo "mk_all=false" >> "${GITHUB_OUTPUT}"
+ else
+ echo "mk_all=true" >> "${GITHUB_OUTPUT}"
+ fi
- name: build mathlib
id: build
@@ -236,6 +227,14 @@ jobs:
MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }}
MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }}
+ - name: Check {Mathlib, Tactic, Counterexamples, Archive}.lean
+ run: |
+ if [ ${{ steps.mk_all.outputs.mk_all }} == "false" ]
+ then
+ echo "Please run 'lake exe mk_all' to regenerate the import all files"
+ exit 1
+ fi
+
- name: check for noisy stdout lines
id: noisy
run: |
@@ -296,7 +295,7 @@ jobs:
# Output is posted to the zulip topic
# https://leanprover.zulipchat.com/#narrow/stream/345428-mathlib-reviewers/topic/lean4checker
- - name: Post comments for lean-pr-testing branch
+ - name: Post comments for lean-pr-testing-NNNN and batteries-pr-testing-NNNN branches
if: always()
env:
TOKEN: ${{ secrets.LEAN_PR_TESTING }}
@@ -309,7 +308,8 @@ jobs:
LINT_OUTCOME: ${{ steps.lint.outcome }}
TEST_OUTCOME: ${{ steps.test.outcome }}
run: |
- scripts/lean-pr-testing-comments.sh
+ scripts/lean-pr-testing-comments.sh lean
+ scripts/lean-pr-testing-comments.sh batteries
final:
name: Post-CI job
@@ -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 f441af18b5045..b1bffcfcd5e0b 100644
--- a/.github/workflows/build_fork.yml
+++ b/.github/workflows/build_fork.yml
@@ -1,7 +1,8 @@
# DO NOT EDIT THIS FILE!!!
# This file is automatically generated by mk_build_yml.sh
-# Edit .github/build.in.yml instead and run mk_build_yml.sh to update.
+# Edit .github/build.in.yml instead and run
+# .github/workflows/mk_build_yml.sh to update.
# Forks of mathlib and other projects should be able to use build_fork.yml directly
# The jobs in this file run on GitHub-hosted workers and will only be run from external forks
@@ -46,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
@@ -86,25 +87,6 @@ jobs:
run: |
./scripts/lint-bib.sh
- check_workflows:
- if: github.repository != 'leanprover-community/mathlib4'
- name: check workflows (fork)
- runs-on: ubuntu-latest
- steps:
- - name: cleanup
- run: |
- find . -name . -o -prune -exec rm -rf -- {} +
-
- - uses: actions/checkout@v4
-
- - name: update workflows
- run: |
- cd .github/workflows/
- ./mk_build_yml.sh
-
- - name: check that workflows were consistent
- run: git diff --exit-code
-
build:
if: github.repository != 'leanprover-community/mathlib4'
name: Build (fork)
@@ -124,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: |
@@ -147,9 +129,6 @@ jobs:
lean --version
lake --version
- - name: check {Mathlib, Tactic, Counterexamples, Archive}.lean are up to date
- run: lake exe mk_all --check
-
- name: build cache
run: |
lake build cache
@@ -168,8 +147,20 @@ jobs:
run: |
rm -rf .lake/build/lib/Mathlib/
# Fail quickly if the cache is completely cold, by checking for Mathlib.Init
- lake exe cache get Mathlib.Init
- lake build --no-build Mathlib.Init && lake exe cache get || echo "No cache for 'Mathlib.Init' available"
+ lake exe cache get #Mathlib.Init
+ #lake build --no-build Mathlib.Init && lake exe cache get || echo "No cache for 'Mathlib.Init' available"
+
+ - name: update {Mathlib, Tactic, Counterexamples, Archive}.lean
+ id: mk_all
+ run: |
+
+ if ! lake exe mk_all --check
+ then
+ echo "Not all lean files are in the import all files"
+ echo "mk_all=false" >> "${GITHUB_OUTPUT}"
+ else
+ echo "mk_all=true" >> "${GITHUB_OUTPUT}"
+ fi
- name: build mathlib
id: build
@@ -233,6 +224,14 @@ jobs:
MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }}
MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }}
+ - name: Check {Mathlib, Tactic, Counterexamples, Archive}.lean
+ run: |
+ if [ ${{ steps.mk_all.outputs.mk_all }} == "false" ]
+ then
+ echo "Please run 'lake exe mk_all' to regenerate the import all files"
+ exit 1
+ fi
+
- name: check for noisy stdout lines
id: noisy
run: |
@@ -293,7 +292,7 @@ jobs:
# Output is posted to the zulip topic
# https://leanprover.zulipchat.com/#narrow/stream/345428-mathlib-reviewers/topic/lean4checker
- - name: Post comments for lean-pr-testing branch
+ - name: Post comments for lean-pr-testing-NNNN and batteries-pr-testing-NNNN branches
if: always()
env:
TOKEN: ${{ secrets.LEAN_PR_TESTING }}
@@ -306,7 +305,8 @@ jobs:
LINT_OUTCOME: ${{ steps.lint.outcome }}
TEST_OUTCOME: ${{ steps.test.outcome }}
run: |
- scripts/lean-pr-testing-comments.sh
+ scripts/lean-pr-testing-comments.sh lean
+ scripts/lean-pr-testing-comments.sh batteries
final:
name: Post-CI job (fork)
@@ -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 a73285496116b..16c75acafbf69 100644
--- a/.github/workflows/dependent-issues.yml
+++ b/.github/workflows/dependent-issues.yml
@@ -3,6 +3,7 @@ name: Dependent Issues
on:
schedule:
- cron: '*/15 * * * *' # run every 15 minutes
+ workflow_dispatch:
jobs:
cancel:
@@ -10,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 fdde8c185c5f9..b98c03bba301e 100644
--- a/.github/workflows/lean4checker.yml
+++ b/.github/workflows/lean4checker.yml
@@ -4,6 +4,7 @@ name: lean4checker Workflow
on:
schedule:
- cron: '0 0 * * *' # Runs at 00:00 UTC every day
+ workflow_dispatch:
jobs:
check-lean4checker:
@@ -24,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: |
@@ -69,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()
@@ -96,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()
@@ -109,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
@@ -123,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/merge_conflicts.yml b/.github/workflows/merge_conflicts.yml
index 68b53db526dad..d10c0233ceaad 100644
--- a/.github/workflows/merge_conflicts.yml
+++ b/.github/workflows/merge_conflicts.yml
@@ -3,6 +3,7 @@ name: Merge conflicts
on:
schedule:
- cron: '*/15 * * * *' # run every 15 minutes
+ workflow_dispatch:
jobs:
main:
diff --git a/.github/workflows/mk_build_yml.sh b/.github/workflows/mk_build_yml.sh
index c47d00142438a..435e7b4e4c6dc 100755
--- a/.github/workflows/mk_build_yml.sh
+++ b/.github/workflows/mk_build_yml.sh
@@ -1,5 +1,11 @@
#!/usr/bin/env bash
-set -ex
+
+# Make this script robust against unintentional errors.
+# See e.g. http://redsymbol.net/articles/unofficial-bash-strict-mode/ for explanation.
+set -euo pipefail
+IFS=$'\n\t'
+
+set -x
cd $(dirname "$(realpath "$0")")
header() {
@@ -7,7 +13,8 @@ header() {
# DO NOT EDIT THIS FILE!!!
# This file is automatically generated by mk_build_yml.sh
-# Edit .github/build.in.yml instead and run mk_build_yml.sh to update.
+# Edit .github/build.in.yml instead and run
+# .github/workflows/mk_build_yml.sh to update.
# Forks of mathlib and other projects should be able to use build_fork.yml directly
EOF
@@ -76,7 +83,7 @@ include() {
s/MAIN_OR_FORK/$3/g;
s/JOB_NAME/$4/g;
s/STYLE_LINT_RUNNER/$5/g;
- /^#.*autogenerating/d
+ /^### NB/d
" ../build.in.yml
}
diff --git a/.github/workflows/nightly_bump_toolchain.yml b/.github/workflows/nightly_bump_toolchain.yml
index ed8cd271a71b1..1d53a2c33a3da 100644
--- a/.github/workflows/nightly_bump_toolchain.yml
+++ b/.github/workflows/nightly_bump_toolchain.yml
@@ -1,9 +1,9 @@
name: Bump lean-toolchain on nightly-testing
on:
- workflow_dispatch:
schedule:
- cron: '0 10/3 * * *' # Run every three hours, starting at 11AM CET/2AM PT.
+ workflow_dispatch:
jobs:
update-toolchain:
diff --git a/.github/workflows/nightly_detect_failure.yml b/.github/workflows/nightly_detect_failure.yml
index e1cfd9147086b..0f52fa1c48fc2 100644
--- a/.github/workflows/nightly_detect_failure.yml
+++ b/.github/workflows/nightly_detect_failure.yml
@@ -23,6 +23,7 @@ jobs:
topic: 'Mathlib status updates'
content: |
❌ The latest CI for Mathlib's branch#nightly-testing has [failed](https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}) ([${{ github.sha }}](https://github.com/${{ github.repository }}/commit/${{ github.sha }})).
+ You can `git fetch; git checkout nightly-testing` and push a fix.
handle_success:
if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'nightly-testing' }}
@@ -210,7 +211,7 @@ jobs:
bump_branch_suffix = bump_branch.replace('bump/', '')
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 {bump_branch_suffix} {current_version}\n```\n"
+ payload += f"```bash\n./scripts/create-adaptation-pr.sh --bumpversion={bump_branch_suffix} --nightlydate={current_version} --nightlysha={sha}\n```\n"
# 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]:
diff --git a/.github/workflows/nightly_merge_master.yml b/.github/workflows/nightly_merge_master.yml
index 1321c9c54ca3b..d6f2480542294 100644
--- a/.github/workflows/nightly_merge_master.yml
+++ b/.github/workflows/nightly_merge_master.yml
@@ -4,7 +4,8 @@ name: Merge master to nightly
on:
schedule:
- - cron: '30 */3 * * *' # 8AM CET/11PM PT
+ - cron: '30 */3 * * *' # At minute 30 past every 3rd hour.
+ workflow_dispatch:
jobs:
merge-to-nightly:
diff --git a/.github/workflows/nolints.yml b/.github/workflows/nolints.yml
index 76f3590e4f585..33fda1bb1154c 100644
--- a/.github/workflows/nolints.yml
+++ b/.github/workflows/nolints.yml
@@ -2,7 +2,8 @@ name: update nolints
on:
schedule:
- - cron: "0 0 * * 0"
+ - cron: "0 0 * * 0" # At 00:00 UTC on Sunday.
+ workflow_dispatch:
jobs:
build:
@@ -15,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/technical_debt_metrics.yml b/.github/workflows/technical_debt_metrics.yml
index d7055c85e59ae..2a83b1d682cec 100644
--- a/.github/workflows/technical_debt_metrics.yml
+++ b/.github/workflows/technical_debt_metrics.yml
@@ -2,7 +2,8 @@ name: Weekly Technical Debt Counters
on:
schedule:
- - cron: '0 4 * * 1' # Run at 04:00 every Monday
+ - cron: '0 4 * * 1' # Run at 04:00 UTC every Monday
+ workflow_dispatch:
jobs:
run-script:
diff --git a/.github/workflows/update_dependencies.yml b/.github/workflows/update_dependencies.yml
index 02779cf664eca..27646aaec561b 100644
--- a/.github/workflows/update_dependencies.yml
+++ b/.github/workflows/update_dependencies.yml
@@ -3,6 +3,7 @@ name: Update Mathlib Dependencies
on:
schedule:
- cron: '0 * * * *' # This will run every hour
+ workflow_dispatch:
jobs:
update-dependencies:
@@ -56,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/.github/workflows/update_dependencies_zulip.yml b/.github/workflows/update_dependencies_zulip.yml
index 1f8a3b507374b..f4e72b01d7034 100644
--- a/.github/workflows/update_dependencies_zulip.yml
+++ b/.github/workflows/update_dependencies_zulip.yml
@@ -40,7 +40,7 @@ jobs:
});
}
} else {
- output += "No PR found for this run!";
+ output += "No PR found for this run! If you are feeling impatient and have write access, please go to the following page and click the "Run workflow" button!\nhttps://github.com/leanprover-community/mathlib4/actions/workflows/update_dependencies.yml";
}
return output;
diff --git a/.vscode/deprecated-alias.code-snippets b/.vscode/deprecated.code-snippets
similarity index 53%
rename from .vscode/deprecated-alias.code-snippets
rename to .vscode/deprecated.code-snippets
index c760b46045763..8be8e537cd5f0 100644
--- a/.vscode/deprecated-alias.code-snippets
+++ b/.vscode/deprecated.code-snippets
@@ -1,4 +1,11 @@
{
+ "Deprecation for mathlib": {
+ "scope": "lean4",
+ "prefix": "deprecated",
+ "body": [
+ "@[deprecated $1 (since := \"${CURRENT_YEAR}-${CURRENT_MONTH}-${CURRENT_DATE}\")]"
+ ]
+ },
"Deprecated alias for mathlib": {
"scope": "lean4",
"prefix": "deprecated alias",
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/Arithcc.lean b/Archive/Arithcc.lean
index 34d7291daf17c..7f9601849cfa4 100644
--- a/Archive/Arithcc.lean
+++ b/Archive/Arithcc.lean
@@ -279,10 +279,7 @@ theorem compiler_correctness
| const => simp [StateEq, step]; rfl
-- 5.II
| var =>
- simp [hmap, StateEq, step] -- Porting note: was `finish [hmap, StateEq, step]`
- constructor
- · simp_all only [read, loc]
- · rfl
+ simp_all [StateEq, StateEqRs, step]
-- 5.III
| sum =>
rename_i e_s₁ e_s₂ e_ih_s₁ e_ih_s₂
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/Statement.lean b/Archive/Examples/IfNormalization/Statement.lean
index dd642ec3af911..283f4eabf91e3 100644
--- a/Archive/Examples/IfNormalization/Statement.lean
+++ b/Archive/Examples/IfNormalization/Statement.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2023 Lean FRO LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
/-!
diff --git a/Archive/Examples/IfNormalization/WithoutAesop.lean b/Archive/Examples/IfNormalization/WithoutAesop.lean
index 13d0eb001998c..0f376cdbd1590 100644
--- a/Archive/Examples/IfNormalization/WithoutAesop.lean
+++ b/Archive/Examples/IfNormalization/WithoutAesop.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2023 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Chris Hughes, Scott Morrison
+Authors: Chris Hughes, Kim Morrison
-/
import Archive.Examples.IfNormalization.Statement
import Mathlib.Algebra.Order.Monoid.Canonical.Defs
@@ -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⟩
@@ -92,8 +92,8 @@ def normalize' (l : AList (fun _ : ℕ => Bool)) :
· simp_all
· have := ht₃ v
have := he₃ v
- simp_all? says simp_all only [normalized, Bool.and_eq_true, Bool.not_eq_true',
- AList.lookup_insert_eq_none, ne_eq, AList.lookup_insert]
+ simp_all? says simp_all only [normalized, Bool.and_eq_true, Bool.not_eq_eq_eq_not,
+ Bool.not_true, AList.lookup_insert_eq_none, ne_eq, AList.lookup_insert]
obtain ⟨⟨⟨tn, tc⟩, tr⟩, td⟩ := ht₂
split <;> rename_i h'
· subst h'
@@ -103,9 +103,9 @@ def normalize' (l : AList (fun _ : ℕ => Bool)) :
have := he₃ w
by_cases h : w = v
· subst h; simp_all
- · simp_all? says simp_all only [normalized, Bool.and_eq_true, Bool.not_eq_true',
- AList.lookup_insert_eq_none, ne_eq, not_false_eq_true, AList.lookup_insert_ne,
- implies_true]
+ · simp_all? says simp_all only [normalized, Bool.and_eq_true, Bool.not_eq_eq_eq_not,
+ Bool.not_true, AList.lookup_insert_eq_none, ne_eq, not_false_eq_true,
+ AList.lookup_insert_ne, implies_true]
obtain ⟨⟨⟨en, ec⟩, er⟩, ed⟩ := he₂
split at b <;> rename_i h'
· subst h'; simp_all
diff --git a/Archive/Examples/MersennePrimes.lean b/Archive/Examples/MersennePrimes.lean
index e10d955eb51ee..ed395b0b58e41 100644
--- a/Archive/Examples/MersennePrimes.lean
+++ b/Archive/Examples/MersennePrimes.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.NumberTheory.LucasLehmer
@@ -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/Hairer.lean b/Archive/Hairer.lean
index acd326c0b13bf..e9b91c32132a8 100644
--- a/Archive/Hairer.lean
+++ b/Archive/Hairer.lean
@@ -100,7 +100,7 @@ lemma inj_L : Injective (L ι) :=
fun g hg _h2g g_supp ↦ by
simpa [mul_comm (g _), L] using congr($hp ⟨g, g_supp.trans ball_subset_closedBall, hg⟩)
simp_rw [MvPolynomial.funext_iff, map_zero]
- refine fun x ↦ AnalyticOn.eval_linearMap (EuclideanSpace.equiv ι ℝ).toLinearMap p
+ refine fun x ↦ AnalyticOnNhd.eval_linearMap (EuclideanSpace.equiv ι ℝ).toLinearMap p
|>.eqOn_zero_of_preconnected_of_eventuallyEq_zero
(preconnectedSpace_iff_univ.mp inferInstance) (z₀ := 0) trivial
(Filter.mem_of_superset (Metric.ball_mem_nhds 0 zero_lt_one) ?_) trivial
diff --git a/Archive/Imo/Imo1962Q1.lean b/Archive/Imo/Imo1962Q1.lean
index 169a0d8dcaf98..d151c6df95fc3 100644
--- a/Archive/Imo/Imo1962Q1.lean
+++ b/Archive/Imo/Imo1962Q1.lean
@@ -32,110 +32,104 @@ def ProblemPredicate (n : ℕ) : Prop :=
First, it's inconvenient to work with digits, so let's simplify them out of the problem.
-/
-
abbrev ProblemPredicate' (c n : ℕ) : Prop :=
n = 10 * c + 6 ∧ 6 * 10 ^ (digits 10 c).length + c = 4 * n
-theorem without_digits {n : ℕ} (h1 : ProblemPredicate n) : ∃ c : ℕ, ProblemPredicate' c n := by
+lemma without_digits {n : ℕ} (hn : ProblemPredicate n) : ∃ c : ℕ, ProblemPredicate' c n := by
use n / 10
cases' n with n
- · have h2 : ¬ProblemPredicate 0 := by norm_num [ProblemPredicate]
+ · have hpp : ¬ProblemPredicate 0 := by norm_num [ProblemPredicate]
contradiction
· rw [ProblemPredicate, digits_def' (by decide : 2 ≤ 10) n.succ_pos, List.headI, List.tail_cons,
- List.concat_eq_append] at h1
+ List.concat_eq_append] at hn
constructor
- · rw [← h1.left, div_add_mod (n + 1) 10]
- · rw [← h1.right, ofDigits_append, ofDigits_digits, ofDigits_singleton, add_comm, mul_comm]
+ · rw [← hn.left, div_add_mod (n + 1) 10]
+ · rw [← hn.right, ofDigits_append, ofDigits_digits, ofDigits_singleton, add_comm, mul_comm]
/-!
Now we can eliminate possibilities for `(digits 10 c).length` until we get to the one that works.
-/
-
-theorem case_0_digit {c n : ℕ} (h1 : (digits 10 c).length = 0) : ¬ProblemPredicate' c n := by
- intro h2
- have h3 : 6 * 10 ^ 0 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [h1]
- have h4 : 6 * 10 ^ 0 + c = 4 * (10 * c + 6) := by rw [h3, h2.right, h2.left]
+lemma case_0_digits {c n : ℕ} (hc : (digits 10 c).length = 0) : ¬ProblemPredicate' c n := by
+ intro hpp
+ have hpow : 6 * 10 ^ 0 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [hc]
+ have hmul : 6 * 10 ^ 0 + c = 4 * (10 * c + 6) := by rw [hpow, hpp.right, hpp.left]
linarith
-theorem case_1_digit {c n : ℕ} (h1 : (digits 10 c).length = 1) : ¬ProblemPredicate' c n := by
- intro h2
- have h3 : 6 * 10 ^ 1 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [h1]
- have h4 : 6 * 10 ^ 1 + c = 4 * (10 * c + 6) := by rw [h3, h2.right, h2.left]
- have h6 : c > 0 := by linarith
+lemma case_1_digits {c n : ℕ} (hc : (digits 10 c).length = 1) : ¬ProblemPredicate' c n := by
+ intro hpp
+ have hpow : 6 * 10 ^ 1 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [hc]
+ have hmul : 6 * 10 ^ 1 + c = 4 * (10 * c + 6) := by rw [hpow, hpp.right, hpp.left]
+ have hpos : c > 0 := by linarith
linarith
-theorem case_2_digit {c n : ℕ} (h1 : (digits 10 c).length = 2) : ¬ProblemPredicate' c n := by
- intro h2
- have h3 : 6 * 10 ^ 2 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [h1]
- have h4 : 6 * 10 ^ 2 + c = 4 * (10 * c + 6) := by rw [h3, h2.right, h2.left]
- have h5 : c > 14 := by linarith
+lemma case_2_digits {c n : ℕ} (hc : (digits 10 c).length = 2) : ¬ProblemPredicate' c n := by
+ intro hpp
+ have hpow : 6 * 10 ^ 2 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [hc]
+ have hmul : 6 * 10 ^ 2 + c = 4 * (10 * c + 6) := by rw [hpow, hpp.right, hpp.left]
+ have hgt : c > 14 := by linarith
linarith
-theorem case_3_digit {c n : ℕ} (h1 : (digits 10 c).length = 3) : ¬ProblemPredicate' c n := by
- intro h2
- have h3 : 6 * 10 ^ 3 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [h1]
- have h4 : 6 * 10 ^ 3 + c = 4 * (10 * c + 6) := by rw [h3, h2.right, h2.left]
- have h5 : c > 153 := by linarith
+lemma case_3_digits {c n : ℕ} (hc : (digits 10 c).length = 3) : ¬ProblemPredicate' c n := by
+ intro hpp
+ have hpow : 6 * 10 ^ 3 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [hc]
+ have hmul : 6 * 10 ^ 3 + c = 4 * (10 * c + 6) := by rw [hpow, hpp.right, hpp.left]
+ have hgt : c > 153 := by linarith
linarith
-theorem case_4_digit {c n : ℕ} (h1 : (digits 10 c).length = 4) : ¬ProblemPredicate' c n := by
- intro h2
- have h3 : 6 * 10 ^ 4 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [h1]
- have h4 : 6 * 10 ^ 4 + c = 4 * (10 * c + 6) := by rw [h3, h2.right, h2.left]
- have h5 : c > 1537 := by linarith
+lemma case_4_digits {c n : ℕ} (hc : (digits 10 c).length = 4) : ¬ProblemPredicate' c n := by
+ intro hpp
+ have hpow : 6 * 10 ^ 4 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [hc]
+ have hmul : 6 * 10 ^ 4 + c = 4 * (10 * c + 6) := by rw [hpow, hpp.right, hpp.left]
+ have hgt : c > 1537 := by linarith
linarith
/-- Putting this inline causes a deep recursion error, so we separate it out. -/
-theorem helper_5_digit {c : ℤ} (h : 6 * 10 ^ 5 + c = 4 * (10 * c + 6)) : c = 15384 := by linarith
+private lemma helper_5_digits {c : ℤ} (hc : 6 * 10 ^ 5 + c = 4 * (10 * c + 6)) : c = 15384 := by
+ linarith
-theorem case_5_digit {c n : ℕ} (h1 : (digits 10 c).length = 5) (h2 : ProblemPredicate' c n) :
+lemma case_5_digits {c n : ℕ} (hc : (digits 10 c).length = 5) (hpp : ProblemPredicate' c n) :
c = 15384 := by
- have h3 : 6 * 10 ^ 5 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [h1]
- have h4 : 6 * 10 ^ 5 + c = 4 * (10 * c + 6) := by rw [h3, h2.right, h2.left]
+ have hpow : 6 * 10 ^ 5 + c = 6 * 10 ^ (digits 10 c).length + c := by rw [hc]
+ have hmul : 6 * 10 ^ 5 + c = 4 * (10 * c + 6) := by rw [hpow, hpp.right, hpp.left]
zify at *
- exact helper_5_digit h4
+ exact helper_5_digits hmul
/-- `linarith` fails on numbers this large, so this lemma spells out some of the arithmetic
that normally would be automated.
-/
-theorem case_more_digits {c n : ℕ} (h1 : (digits 10 c).length ≥ 6) (h2 : ProblemPredicate' c n) :
+lemma case_more_digits {c n : ℕ} (hc : (digits 10 c).length ≥ 6) (hpp : ProblemPredicate' c n) :
n ≥ 153846 := by
- have h3 : c ≠ 0 := by
- intro h4
- have h5 : (digits 10 c).length = 0 := by simp [h4]
- exact case_0_digit h5 h2
+ have hnz : c ≠ 0 := by
+ intro hc0
+ have hcl : (digits 10 c).length = 0 := by simp [hc0]
+ exact case_0_digits hcl hpp
calc
- n ≥ 10 * c := le.intro h2.left.symm
- _ ≥ 10 ^ (digits 10 c).length := base_pow_length_digits_le 10 c (by decide) h3
- _ ≥ 10 ^ 6 := pow_le_pow_right (by decide) h1
+ n ≥ 10 * c := le.intro hpp.left.symm
+ _ ≥ 10 ^ (digits 10 c).length := base_pow_length_digits_le 10 c (by decide) hnz
+ _ ≥ 10 ^ 6 := pow_right_mono₀ (by decide) hc
_ ≥ 153846 := by norm_num
/-!
Now we combine these cases to show that 153846 is the smallest solution.
-/
-
-theorem satisfied_by_153846 : ProblemPredicate 153846 := by
+lemma satisfied_by_153846 : ProblemPredicate 153846 := by
norm_num [ProblemPredicate]
decide
-theorem no_smaller_solutions (n : ℕ) (h1 : ProblemPredicate n) : n ≥ 153846 := by
- have ⟨c, h2⟩ := without_digits h1
- have h3 : (digits 10 c).length < 6 ∨ (digits 10 c).length ≥ 6 := by apply lt_or_ge
- cases h3 with
- | inr h3 => exact case_more_digits h3 h2
- | inl h3 =>
- interval_cases h : (digits 10 c).length
- · exfalso; exact case_0_digit h h2
- · exfalso; exact case_1_digit h h2
- · exfalso; exact case_2_digit h h2
- · exfalso; exact case_3_digit h h2
- · exfalso; exact case_4_digit h h2
- · have h4 : c = 15384 := case_5_digit h h2
- have h5 : n = 10 * 15384 + 6 := h4 ▸ h2.left
- norm_num at h5
- exact h5.ge
+lemma no_smaller_solutions (n : ℕ) (hn : ProblemPredicate n) : n ≥ 153846 := by
+ have ⟨c, hcn⟩ := without_digits hn
+ cases lt_or_ge (digits 10 c).length 6 with
+ | inl =>
+ interval_cases hc : (digits 10 c).length
+ · exfalso; exact case_0_digits hc hcn
+ · exfalso; exact case_1_digits hc hcn
+ · exfalso; exact case_2_digits hc hcn
+ · exfalso; exact case_3_digits hc hcn
+ · exfalso; exact case_4_digits hc hcn
+ · exact (case_5_digits hc hcn ▸ hcn.left).ge
+ | inr hge => exact case_more_digits hge hcn
end Imo1962Q1
diff --git a/Archive/Imo/Imo1972Q5.lean b/Archive/Imo/Imo1972Q5.lean
index f96965f9d6a75..ba2e4d8c6a0a0 100644
--- a/Archive/Imo/Imo1972Q5.lean
+++ b/Archive/Imo/Imo1972Q5.lean
@@ -50,7 +50,7 @@ theorem imo1972_q5 (f g : ℝ → ℝ) (hf1 : ∀ x, ∀ y, f (x + y) + f (x - y
calc
0 < ‖f x‖ := norm_pos_iff.mpr hx
_ ≤ k := hk₁ x
- rw [div_lt_iff]
+ rw [div_lt_iff₀]
· apply lt_mul_of_one_lt_right h₁ hneg
· exact zero_lt_one.trans hneg
-- Demonstrate that `k ≤ k'` using `hk₂`.
@@ -87,7 +87,7 @@ theorem imo1972_q5' (f g : ℝ → ℝ) (hf1 : ∀ x, ∀ y, f (x + y) + f (x -
have h : ∀ x, ‖f x‖ ≤ k := le_ciSup hf2
have hgy : 0 < ‖g y‖ := by linarith
have k_pos : 0 < k := lt_of_lt_of_le (norm_pos_iff.mpr hx) (h x)
- have : k / ‖g y‖ < k := (div_lt_iff hgy).mpr (lt_mul_of_one_lt_right k_pos H)
+ have : k / ‖g y‖ < k := (div_lt_iff₀ hgy).mpr (lt_mul_of_one_lt_right k_pos H)
have : k ≤ k / ‖g y‖ := by
suffices ∀ x, ‖f x‖ ≤ k / ‖g y‖ from ciSup_le this
intro x
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 6789efcbb837d..e8ca0c898f1d5 100644
--- a/Archive/Imo/Imo1986Q5.lean
+++ b/Archive/Imo/Imo1986Q5.lean
@@ -54,7 +54,7 @@ theorem map_of_lt_two (hx : x < 2) : f x = 2 / (2 - x) := by
have hx' : 0 < 2 - x := tsub_pos_of_lt hx
have hfx : f x ≠ 0 := hf.map_ne_zero_iff.2 hx
apply le_antisymm
- · rw [le_div_iff₀ hx', ← NNReal.le_div_iff' hfx, tsub_le_iff_right, ← hf.map_eq_zero,
+ · rw [le_div_iff₀ hx', ← le_div_iff₀' hfx.bot_lt, tsub_le_iff_right, ← hf.map_eq_zero,
hf.map_add, div_mul_cancel₀ _ hfx, hf.map_two, zero_mul]
· rw [div_le_iff₀' hx', ← hf.map_eq_zero]
refine (mul_eq_zero.1 ?_).resolve_right hfx
@@ -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/Imo1987Q1.lean b/Archive/Imo/Imo1987Q1.lean
index 36d3caf4a519e..d10995da9a7a4 100644
--- a/Archive/Imo/Imo1987Q1.lean
+++ b/Archive/Imo/Imo1987Q1.lean
@@ -47,14 +47,9 @@ def fixedPointsEquiv : { σx : α × Perm α // σx.2 σx.1 = σx.1 } ≃ Σ x :
theorem card_fixed_points :
card { σx : α × Perm α // σx.2 σx.1 = σx.1 } = card α * (card α - 1)! := by
simp only [card_congr (fixedPointsEquiv α), card_sigma, card_perm]
- conv_lhs =>
- congr
- next => skip
- intro
- rw [card_ofFinset (s := Finset.filter (· ∈ _) Finset.univ)]
- simp only [Set.mem_compl_iff, Set.mem_singleton_iff, Finset.filter_not, Finset.filter_eq',
- Finset.mem_univ, ↓reduceIte, Finset.subset_univ, Finset.card_sdiff, Finset.card_univ,
- Finset.card_singleton, sum_const, smul_eq_mul]
+ have (x) : ({x}ᶜ : Set α) = Finset.filter (· ≠ x) Finset.univ := by
+ ext; simp
+ simp [this]
/-- Given `α : Type*` and `k : ℕ`, `fiber α k` is the set of permutations of `α` with exactly `k`
fixed points. -/
diff --git a/Archive/Imo/Imo1994Q1.lean b/Archive/Imo/Imo1994Q1.lean
index e8d62532d713d..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
@@ -77,7 +77,7 @@ theorem imo1994_q1 (n : ℕ) (m : ℕ) (A : Finset ℕ) (hm : A.card = m + 1)
have hf : map f (Icc 0 k) ⊆ map a.toEmbedding (Ioc (rev k) (Fin.last m)) := by
intro x hx
simp only [Equiv.subLeft_apply, a, rev] at h
- simp only [mem_map, mem_Icc, mem_Ioc, Fin.zero_le, true_and_iff, Equiv.subLeft_apply,
+ simp only [mem_map, mem_Icc, mem_Ioc, Fin.zero_le, true_and, Equiv.subLeft_apply,
Function.Embedding.coeFn_mk, exists_prop, RelEmbedding.coe_toEmbedding, f, rev] at hx ⊢
rcases hx with ⟨i, ⟨hi, rfl⟩⟩
have h1 : a i + a (Fin.last m - k) ≤ n := by unfold_let; linarith only [h, a.monotone hi]
diff --git a/Archive/Imo/Imo1998Q2.lean b/Archive/Imo/Imo1998Q2.lean
index ac4e0dfb0f196..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
@@ -104,9 +104,9 @@ theorem A_fibre_over_contestant (c : C) :
(Finset.univ.filter fun p : JudgePair J => p.Agree r c ∧ p.Distinct) =
((A r).filter fun a : AgreedTriple C J => a.contestant = c).image Prod.snd := by
ext p
- simp only [A, Finset.mem_univ, Finset.mem_filter, Finset.mem_image, true_and_iff, exists_prop]
+ simp only [A, Finset.mem_univ, Finset.mem_filter, Finset.mem_image, exists_prop]
constructor
- · rintro ⟨h₁, h₂⟩; refine ⟨(c, p), ?_⟩; tauto
+ · rintro ⟨_, h₂⟩; refine ⟨(c, p), ?_⟩; tauto
· intro h; aesop
theorem A_fibre_over_contestant_card (c : C) :
diff --git a/Archive/Imo/Imo2006Q5.lean b/Archive/Imo/Imo2006Q5.lean
index 0e2398d7919ba..d317993a8c618 100644
--- a/Archive/Imo/Imo2006Q5.lean
+++ b/Archive/Imo/Imo2006Q5.lean
@@ -122,7 +122,7 @@ theorem Polynomial.iterate_comp_sub_X_ne {P : Polynomial ℤ} (hP : 1 < P.natDeg
(hk : 0 < k) : P.comp^[k] X - X ≠ 0 := by
rw [sub_ne_zero]
apply_fun natDegree
- simpa using (one_lt_pow hP hk.ne').ne'
+ simpa using (one_lt_pow₀ hP hk.ne').ne'
/-- We solve the problem for the specific case k = 2 first. -/
theorem imo2006_q5' {P : Polynomial ℤ} (hP : 1 < P.natDegree) :
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/Imo2013Q5.lean b/Archive/Imo/Imo2013Q5.lean
index 48e7486e9c230..225e64ae35b02 100644
--- a/Archive/Imo/Imo2013Q5.lean
+++ b/Archive/Imo/Imo2013Q5.lean
@@ -38,9 +38,9 @@ theorem le_of_all_pow_lt_succ {x y : ℝ} (hx : 1 < x) (hy : 1 < y)
have hterm : ∀ i : ℕ, i ∈ Finset.range n → 1 ≤ x ^ i * y ^ (n - 1 - i) := by
intro i _
calc
- 1 ≤ x ^ i := one_le_pow_of_one_le hx.le i
+ 1 ≤ x ^ i := one_le_pow₀ hx.le
_ = x ^ i * 1 := by ring
- _ ≤ x ^ i * y ^ (n - 1 - i) := by gcongr; apply one_le_pow_of_one_le hy.le
+ _ ≤ x ^ i * y ^ (n - 1 - i) := by gcongr; apply one_le_pow₀ hy.le
calc
(x - y) * (n : ℝ) = (n : ℝ) * (x - y) := by ring
_ = (∑ _i ∈ Finset.range n, (1 : ℝ)) * (x - y) := by
@@ -134,7 +134,7 @@ theorem fixed_point_of_pos_nat_pow {f : ℚ → ℝ} {n : ℕ} (hn : 0 < n)
(H1 : ∀ x y, 0 < x → 0 < y → f (x * y) ≤ f x * f y) (H4 : ∀ n : ℕ, 0 < n → (n : ℝ) ≤ f n)
(H5 : ∀ x : ℚ, 1 < x → (x : ℝ) ≤ f x) {a : ℚ} (ha1 : 1 < a) (hae : f a = a) :
f (a ^ n) = a ^ n := by
- have hh0 : (a : ℝ) ^ n ≤ f (a ^ n) := mod_cast H5 (a ^ n) (one_lt_pow ha1 hn.ne')
+ have hh0 : (a : ℝ) ^ n ≤ f (a ^ n) := mod_cast H5 (a ^ n) (one_lt_pow₀ ha1 hn.ne')
have hh1 :=
calc
f (a ^ n) ≤ f a ^ n := pow_f_le_f_pow hn ha1 H1 H4
@@ -206,7 +206,7 @@ theorem imo2013_q5 (f : ℚ → ℝ) (H1 : ∀ x y, 0 < x → 0 < y → f (x * y
intro n hn
calc
(x : ℝ) ^ n - 1 < f (x ^ n) :=
- mod_cast fx_gt_xm1 (one_le_pow_of_one_le hx.le n) H1 H2 H4
+ mod_cast fx_gt_xm1 (one_le_pow₀ hx.le) H1 H2 H4
_ ≤ f x ^ n := pow_f_le_f_pow hn hx H1 H4
have hx' : 1 < (x : ℝ) := mod_cast hx
have hxp : 0 < x := by positivity
diff --git a/Archive/Imo/Imo2019Q2.lean b/Archive/Imo/Imo2019Q2.lean
index db1650a221391..86353bd5b6d91 100644
--- a/Archive/Imo/Imo2019Q2.lean
+++ b/Archive/Imo/Imo2019Q2.lean
@@ -57,7 +57,7 @@ rather than more literally with `affineSegment`.
-/
-open Affine Affine.Simplex EuclideanGeometry FiniteDimensional
+open Affine Affine.Simplex EuclideanGeometry Module
open scoped Affine EuclideanGeometry Real
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/MiuLanguage/DecisionSuf.lean b/Archive/MiuLanguage/DecisionSuf.lean
index 161e777bc7f34..2f1f8bbf87750 100644
--- a/Archive/MiuLanguage/DecisionSuf.lean
+++ b/Archive/MiuLanguage/DecisionSuf.lean
@@ -265,7 +265,7 @@ theorem base_case_suf (en : Miustr) (h : Decstr en) (hu : count U en = 0) : Deri
rcases h with ⟨⟨mhead, nmtail⟩, hi⟩
have : en ≠ nil := by
intro k
- simp only [k, count, countP, countP.go, if_false, zero_mod, zero_ne_one, false_or_iff,
+ simp only [k, count, countP, countP.go, if_false, zero_mod, zero_ne_one, false_or,
reduceCtorEq] at hi
rcases exists_cons_of_ne_nil this with ⟨y, ys, rfl⟩
rcases mhead
diff --git a/Archive/Sensitivity.lean b/Archive/Sensitivity.lean
index 3ebec47f3b7d6..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 FiniteDimensional 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
@@ -374,7 +374,7 @@ theorem exists_eigenvalue (H : Set (Q m.succ)) (hH : Card H ≥ 2 ^ m + 1) :
suffices 0 < dim (W ⊓ img) by
exact mod_cast exists_mem_ne_zero_of_rank_pos this
have dim_le : dim (W ⊔ img) ≤ 2 ^ (m + 1 : Cardinal) := by
- convert ← rank_submodule_le (W ⊔ img)
+ convert ← Submodule.rank_le (W ⊔ img)
rw [← Nat.cast_succ]
apply dim_V
have dim_add : dim (W ⊔ img) + dim (W ⊓ img) = dim W + 2 ^ m := by
@@ -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/AbelRuffini.lean b/Archive/Wiedijk100Theorems/AbelRuffini.lean
index df179eb859924..36026dc2ddd76 100644
--- a/Archive/Wiedijk100Theorems/AbelRuffini.lean
+++ b/Archive/Wiedijk100Theorems/AbelRuffini.lean
@@ -115,7 +115,7 @@ theorem real_roots_Phi_ge_aux (hab : b < a) :
· have hf1 : f 1 < 0 := by simp [hf, hb]
have hfa : 0 ≤ f a := by
simp_rw [hf, ← sq]
- refine add_nonneg (sub_nonneg.mpr (pow_le_pow_right ha ?_)) ?_ <;> norm_num
+ refine add_nonneg (sub_nonneg.mpr (pow_right_mono₀ ha ?_)) ?_ <;> norm_num
obtain ⟨x, ⟨-, hx1⟩, hx2⟩ := intermediate_value_Ico' hle (hc _) (Set.mem_Ioc.mpr ⟨hf1, hf0⟩)
obtain ⟨y, ⟨hy1, -⟩, hy2⟩ := intermediate_value_Ioc ha (hc _) (Set.mem_Ioc.mpr ⟨hf1, hfa⟩)
exact ⟨x, y, (hx1.trans hy1).ne, hx2, hy2⟩
@@ -126,7 +126,7 @@ theorem real_roots_Phi_ge_aux (hab : b < a) :
f (-a) = (a : ℝ) ^ 2 - (a : ℝ) ^ 5 + b := by
norm_num [hf, ← sq, sub_eq_add_neg, add_comm, Odd.neg_pow (by decide : Odd 5)]
_ ≤ (a : ℝ) ^ 2 - (a : ℝ) ^ 3 + (a - 1) := by
- refine add_le_add (sub_le_sub_left (pow_le_pow_right ha ?_) _) ?_ <;> linarith
+ refine add_le_add (sub_le_sub_left (pow_right_mono₀ ha ?_) _) ?_ <;> linarith
_ = -((a : ℝ) - 1) ^ 2 * (a + 1) := by ring
_ ≤ 0 := by nlinarith
have ha' := neg_nonpos.mpr (hle.trans ha)
diff --git a/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean b/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean
index 19e2a5834b237..884fb11207295 100644
--- a/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean
+++ b/Archive/Wiedijk100Theorems/AscendingDescendingSequences.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
-/
+import Mathlib.Data.Finset.Max
import Mathlib.Data.Fintype.Powerset
/-!
@@ -38,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 =>
@@ -147,7 +148,7 @@ theorem erdos_szekeres {r s n : ℕ} {f : Fin n → α} (hn : r * s < n) (hf : I
have : image ab univ ⊆ ran := by
-- First some logical shuffling
rintro ⟨x₁, x₂⟩
- simp only [ran, mem_image, exists_prop, mem_range, mem_univ, mem_product, true_and_iff,
+ simp only [ran, mem_image, exists_prop, mem_range, mem_univ, mem_product, true_and,
Prod.ext_iff]
rintro ⟨i, rfl, rfl⟩
specialize q i
diff --git a/Archive/Wiedijk100Theorems/BallotProblem.lean b/Archive/Wiedijk100Theorems/BallotProblem.lean
index 79a0cf487315f..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,25 +188,25 @@ 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
- simp only [mem_inter_iff, mem_image, mem_setOf_eq, mem_empty_iff_false, iff_false_iff,
+ simp only [mem_inter_iff, mem_image, mem_setOf_eq, mem_empty_iff_false, iff_false,
not_and, forall_exists_index, and_imp]
rintro l _ rfl
norm_num
@@ -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.sub_eq_of_add_eq _ this, ENNReal.eq_div_iff, ENNReal.mul_sub, mul_one,
+ 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
@@ -262,15 +262,15 @@ theorem countedSequence_int_pos_counted_succ_succ (p q : ℕ) :
(_ : List.cons (-1) '' countedSequence (p + 1) q ∩ {l | l.headI = 1} = ∅), union_empty] <;>
· ext
simp only [mem_inter_iff, mem_image, mem_setOf_eq, and_iff_left_iff_imp, mem_empty_iff_false,
- iff_false_iff, not_and, forall_exists_index, and_imp]
+ iff_false, not_and, forall_exists_index, and_imp]
rintro y _ rfl
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 =
@@ -289,15 +289,15 @@ theorem countedSequence_int_neg_counted_succ_succ (p q : ℕ) :
empty_union] <;>
· ext
simp only [mem_inter_iff, mem_image, mem_setOf_eq, and_iff_left_iff_imp, mem_empty_iff_false,
- iff_false_iff, not_and, forall_exists_index, and_imp]
+ iff_false, not_and, forall_exists_index, and_imp]
rintro y _ rfl
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,
@@ -363,7 +363,7 @@ theorem ballot_problem :
rwa [ENNReal.toReal_eq_toReal (measure_lt_top _ _).ne] at this
simp only [Ne, ENNReal.div_eq_top, tsub_eq_zero_iff_le, Nat.cast_le, not_le,
add_eq_zero, Nat.cast_eq_zero, ENNReal.add_eq_top, ENNReal.natCast_ne_top, or_self_iff,
- not_false_iff, and_true_iff]
+ not_false_iff, and_true]
push_neg
exact ⟨fun _ _ => by linarith, (tsub_le_self.trans_lt (ENNReal.natCast_ne_top p).lt_top).ne⟩
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/CubingACube.lean b/Archive/Wiedijk100Theorems/CubingACube.lean
index 05b1712152b67..d7acf6143b041 100644
--- a/Archive/Wiedijk100Theorems/CubingACube.lean
+++ b/Archive/Wiedijk100Theorems/CubingACube.lean
@@ -71,7 +71,7 @@ theorem univ_pi_side (c : Cube n) : pi univ (side c) = c.toSet :=
theorem toSet_subset {c c' : Cube n} : c.toSet ⊆ c'.toSet ↔ ∀ j, c.side j ⊆ c'.side j := by
simp only [← univ_pi_side, univ_pi_subset_univ_pi_iff, (c.side_nonempty _).ne_empty, exists_false,
- or_false_iff]
+ or_false]
theorem toSet_disjoint {c c' : Cube n} :
Disjoint c.toSet c'.toSet ↔ ∃ j, Disjoint (c.side j) (c'.side j) := by
@@ -361,7 +361,7 @@ theorem smallest_onBoundary {j} (bi : OnBoundary (mi_mem_bcubes : mi h v ∈ _)
dsimp only [x]; rw [← bi, add_sub_assoc, add_lt_iff_neg_left, sub_lt_zero]
apply mi_strict_minimal (Ne.symm h2i') hi'
refine ⟨x, ⟨?_, ?_⟩, ?_⟩
- · simp only [side, neg_lt_zero, hw, add_lt_iff_neg_left, and_true_iff, mem_Ico, sub_eq_add_neg, x]
+ · simp only [side, neg_lt_zero, hw, add_lt_iff_neg_left, and_true, mem_Ico, sub_eq_add_neg, x]
rw [add_assoc, le_add_iff_nonneg_right, ← sub_eq_add_neg, sub_nonneg]
apply le_of_lt (w_lt_w h v hi')
· simp only [side, not_and_or, not_lt, not_le, mem_Ico]; left; exact hx
@@ -408,7 +408,7 @@ theorem mi_not_onBoundary (j : Fin n) : ¬OnBoundary (mi_mem_bcubes : mi h v ∈
have i'_i'' : i' ≠ i'' := by
rintro ⟨⟩
have : (cs i).b ∈ (cs i').toSet := by
- simp only [toSet, forall_iff_succ, hi.1, bottom_mem_side h2i', true_and_iff, mem_setOf_eq]
+ simp only [toSet, forall_iff_succ, hi.1, bottom_mem_side h2i', true_and, mem_setOf_eq]
intro j₂; by_cases hj₂ : j₂ = j
· simpa [p', side_tail, hj'.symm, hj₂] using hi''.2 j
· simpa [p, hj₂] using hi'.2 j₂
diff --git a/Archive/Wiedijk100Theorems/FriendshipGraphs.lean b/Archive/Wiedijk100Theorems/FriendshipGraphs.lean
index 30ac6b66643fd..860afa94c8e2e 100644
--- a/Archive/Wiedijk100Theorems/FriendshipGraphs.lean
+++ b/Archive/Wiedijk100Theorems/FriendshipGraphs.lean
@@ -179,7 +179,7 @@ theorem card_of_regular (hd : G.IsRegularOfDegree d) : d + (Fintype.card V - 1)
trans ((G.adjMatrix ℕ ^ 2) *ᵥ (fun _ => 1)) v
· rw [adjMatrix_sq_of_regular hG hd, mulVec, dotProduct, ← insert_erase (mem_univ v)]
simp only [sum_insert, mul_one, if_true, Nat.cast_id, eq_self_iff_true, mem_erase, not_true,
- Ne, not_false_iff, add_right_inj, false_and_iff, of_apply]
+ Ne, not_false_iff, add_right_inj, false_and, of_apply]
rw [Finset.sum_const_nat, card_erase_of_mem (mem_univ v), mul_one]; · rfl
intro x hx; simp [(ne_of_mem_erase hx).symm]
· rw [sq, ← mulVec_mulVec]
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 5895ebcb7fdd8..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,
@@ -206,7 +199,7 @@ theorem partialGF_prop (α : Type*) [CommSemiring α] (n : ℕ) (s : Finset ℕ)
· dsimp only
intro p₁ hp₁ p₂ hp₂ h
apply Nat.Partition.ext
- simp only [true_and_iff, mem_univ, mem_filter] at hp₁ hp₂
+ simp only [true_and, mem_univ, mem_filter] at hp₁ hp₂
ext i
simp only [φ, ne_eq, Multiset.mem_toFinset, not_not, smul_eq_mul, Finsupp.mk.injEq] at h
by_cases hi : i = 0
@@ -216,9 +209,9 @@ 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_iff, and_assoc]
+ · simp only [φ, mem_filter, mem_finsuppAntidiag, mem_univ, exists_prop, true_and, and_assoc]
rintro f ⟨hf, hf₃, hf₄⟩
have hf' : f ∈ finsuppAntidiag s n := mem_finsuppAntidiag.mpr ⟨hf, hf₃⟩
simp only [mem_finsuppAntidiag] at hf'
@@ -257,16 +250,12 @@ 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
· congr
- simp only [true_and_iff, forall_const, Set.mem_univ]
+ simp only [true_and, forall_const, Set.mem_univ]
· rw [Finset.prod_map]
simp_rw [num_series']
congr! 2 with x
@@ -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 74017293ce14b..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_le_pow_right 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/Cache/IO.lean b/Cache/IO.lean
index a2c34ef9a0e7e..43e3f70652623 100644
--- a/Cache/IO.lean
+++ b/Cache/IO.lean
@@ -137,7 +137,8 @@ private def CacheM.getContext : IO CacheM.Context := do
("Cli", LAKEPACKAGESDIR / "Cli"),
("ProofWidgets", LAKEPACKAGESDIR / "proofwidgets"),
("Qq", LAKEPACKAGESDIR / "Qq"),
- ("ImportGraph", LAKEPACKAGESDIR / "importGraph")
+ ("ImportGraph", LAKEPACKAGESDIR / "importGraph"),
+ ("LeanSearchClient", LAKEPACKAGESDIR / "LeanSearchClient")
]⟩
def CacheM.run (f : CacheM α) : IO α := do ReaderT.run f (← getContext)
@@ -337,7 +338,7 @@ def packCache (hashMap : HashMap) (overwrite verbose unpackedOnly : Bool)
/-- Gets the set of all cached files -/
def getLocalCacheSet : IO <| Lean.RBTree String compare := do
let paths ← getFilesWithExtension CACHEDIR "ltar"
- return .fromList (paths.data.map (·.withoutParent CACHEDIR |>.toString)) _
+ return .fromList (paths.toList.map (·.withoutParent CACHEDIR |>.toString)) _
def isPathFromMathlib (path : FilePath) : Bool :=
match path.components with
diff --git a/Cache/Requests.lean b/Cache/Requests.lean
index 5c4c6038aecaa..71b74cb4b051d 100644
--- a/Cache/Requests.lean
+++ b/Cache/Requests.lean
@@ -184,7 +184,7 @@ def UPLOAD_URL : String :=
/-- Formats the config file for `curl`, containing the list of files to be uploaded -/
def mkPutConfigContent (fileNames : Array String) (token : String) : IO String := do
let token := if useFROCache then "" else s!"?{token}" -- the FRO cache doesn't pass the token here
- let l ← fileNames.data.mapM fun fileName : String => do
+ let l ← fileNames.toList.mapM fun fileName : String => do
pure s!"-T {(IO.CACHEDIR / fileName).toString}\nurl = {mkFileURL UPLOAD_URL fileName}{token}"
return "\n".intercalate l
diff --git a/Counterexamples.lean b/Counterexamples.lean
index 3cc04e2e7faa1..85f441c3cd5d5 100644
--- a/Counterexamples.lean
+++ b/Counterexamples.lean
@@ -3,6 +3,7 @@ import Counterexamples.CharPZeroNeCharZero
import Counterexamples.CliffordAlgebraNotInjective
import Counterexamples.Cyclotomic105
import Counterexamples.DirectSumIsInternal
+import Counterexamples.GameMultiplication
import Counterexamples.Girard
import Counterexamples.HomogeneousPrimeNotPrime
import Counterexamples.LinearOrderWithPosMulPosEqZero
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/GameMultiplication.lean b/Counterexamples/GameMultiplication.lean
new file mode 100644
index 0000000000000..f28687f92e547
--- /dev/null
+++ b/Counterexamples/GameMultiplication.lean
@@ -0,0 +1,81 @@
+/-
+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.SetTheory.Game.Basic
+import Mathlib.Tactic.FinCases
+
+/-!
+# Multiplication of pre-games can't be lifted to the quotient
+
+We show that there exist equivalent pregames `x₁ ≈ x₂` and `y` such that `x₁ * y ≉ x₂ * y`. In
+particular, we cannot define the multiplication of games in general.
+
+The specific counterexample we use is `x₁ = y = {0 | 0}` and `x₂ = {-1, 0 | 0, 1}`. The first game
+is colloquially known as `star`, so we use the name `star'` for the second. We prove that
+`star ≈ star'` and `star * star ≈ star`, but `star' * star ≉ star`.
+-/
+
+namespace Counterexample
+
+namespace PGame
+
+open SetTheory PGame
+
+/-- The game `{-1, 0 | 0, 1}`, which is equivalent but not identical to `*`. -/
+def star' : PGame := ofLists [0, -1] [0, 1]
+
+/-- `*'` is its own negative. -/
+theorem neg_star' : -star' = star' := by
+ simp [star']
+
+/-- `*'` is equivalent to `*`. -/
+theorem star'_equiv_star : star' ≈ star := by
+ have le : star' ≤ star := by
+ apply PGame.le_of_forall_lf
+ · rintro ⟨i⟩
+ fin_cases i
+ · exact zero_lf_star
+ · exact (neg_lt_zero_iff.2 PGame.zero_lt_one).trans_lf zero_lf_star
+ · exact fun _ => lf_zero_le.2 ⟨⟨0, Nat.zero_lt_two⟩, le_rfl⟩
+ constructor
+ case' right => rw [← neg_le_neg_iff, neg_star, neg_star']
+ assumption'
+
+/-- The equation `** = *` is an identity, though not a relabelling. -/
+theorem star_sq : star * star ≈ star := by
+ have le : star * star ≤ star := by
+ rw [le_iff_forall_lf]
+ constructor <;>
+ intro i
+ · apply leftMoves_mul_cases i <;>
+ intro _ _
+ case' hl => rw [mul_moveLeft_inl]
+ case' hr => rw [mul_moveLeft_inr]
+ all_goals rw [lf_iff_game_lf]; simpa using zero_lf_star
+ · refine lf_zero.2 ⟨toRightMovesMul (Sum.inl default), ?_⟩
+ rintro (j | j) <;> -- Instance can't be inferred otherwise.
+ exact isEmptyElim j
+ constructor
+ case' right =>
+ rw [← neg_le_neg_iff];
+ apply (negMulRelabelling _ _).symm.equiv.1.trans;
+ rw [neg_star]
+ assumption'
+
+/-- `*'* ⧏ *` implies `*'* ≉ *`.-/
+theorem star'_mul_star_lf : star' * star ⧏ star := by
+ rw [lf_iff_exists_le]
+ refine Or.inr ⟨toRightMovesMul (Sum.inr ⟨⟨1, Nat.one_lt_two⟩, default⟩), ?_⟩
+ rw [mul_moveRight_inr, le_iff_game_le]
+ simp [star']
+
+/-- Pre-game multiplication cannot be lifted to games. -/
+theorem mul_not_lift : ∃ x₁ x₂ y : PGame, x₁ ≈ x₂ ∧ ¬ x₁ * y ≈ x₂ * y :=
+ ⟨_, _, _, ⟨star'_equiv_star, fun h ↦ (PGame.Equiv.trans h star_sq).ge.not_gf star'_mul_star_lf⟩⟩
+
+end PGame
+
+end Counterexample
diff --git a/Counterexamples/MapFloor.lean b/Counterexamples/MapFloor.lean
index 08097ff2b0b83..3263f315ca27f 100644
--- a/Counterexamples/MapFloor.lean
+++ b/Counterexamples/MapFloor.lean
@@ -125,7 +125,7 @@ theorem forgetEpsilons_apply (p : ℤ[ε]) : forgetEpsilons p = coeff p 0 :=
itself. -/
theorem forgetEpsilons_floor_lt (n : ℤ) :
forgetEpsilons ⌊(n - ↑ε : ℤ[ε])⌋ < ⌊forgetEpsilons (n - ↑ε)⌋ := by
- suffices ⌊(n - ↑ε : ℤ[ε])⌋ = n - 1 by simp [this]
+ suffices ⌊(n - ↑ε : ℤ[ε])⌋ = n - 1 by simp [map_sub, this]
have : (0 : ℤ[ε]) < ε := ⟨1, by simp⟩
exact (if_neg <| by rw [coeff_sub, intCast_coeff_zero]; simp [this]).trans (by
rw [coeff_sub, intCast_coeff_zero]; simp)
diff --git a/Counterexamples/Phillips.lean b/Counterexamples/Phillips.lean
index 755cb6b94dd69..177816e1a065b 100644
--- a/Counterexamples/Phillips.lean
+++ b/Counterexamples/Phillips.lean
@@ -6,7 +6,7 @@ Authors: Sébastien Gouëzel
import Mathlib.Analysis.NormedSpace.HahnBanach.Extension
import Mathlib.MeasureTheory.Integral.SetIntegral
import Mathlib.MeasureTheory.Measure.Lebesgue.Basic
-import Mathlib.Topology.ContinuousFunction.Bounded
+import Mathlib.Topology.ContinuousMap.Bounded
/-!
# A counterexample on Pettis integrability
@@ -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,20 +461,20 @@ 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 => ?_⟩
· have : univ \ {y | r x y} = {y | r y x} ∪ {x} := by
ext y
- simp only [true_and_iff, mem_univ, mem_setOf_eq, mem_insert_iff, union_singleton, mem_diff]
+ simp only [true_and, mem_univ, mem_setOf_eq, mem_insert_iff, union_singleton, mem_diff]
rcases trichotomous_of r x y with (h | rfl | h)
- · simp only [h, not_or, false_iff_iff, not_true]
+ · simp only [h, not_or, false_iff, not_true]
constructor
· rintro rfl; exact irrefl_of r y h
· exact asymm h
- · simp only [true_or_iff, eq_self_iff_true, iff_true_iff]; exact irrefl x
- · simp only [h, iff_true_iff, or_true_iff]; exact asymm h
+ · simp only [true_or, eq_self_iff_true, iff_true]; exact irrefl x
+ · simp only [h, iff_true, or_true]; exact asymm h
rw [this]
apply Countable.union _ (countable_singleton _)
rw [Cardinal.countable_iff_lt_aleph_one, ← Hcont]
@@ -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/SeminormLatticeNotDistrib.lean b/Counterexamples/SeminormLatticeNotDistrib.lean
index 770184c227ba7..e547175d5a7d5 100644
--- a/Counterexamples/SeminormLatticeNotDistrib.lean
+++ b/Counterexamples/SeminormLatticeNotDistrib.lean
@@ -57,14 +57,14 @@ theorem not_distrib : ¬(p ⊔ q1) ⊓ (p ⊔ q2) ≤ p ⊔ q1 ⊓ q2 := by
4 / 3 = 4 * (1 - 2 / 3) := by norm_num
_ ≤ 4 * (1 - x.snd) := by gcongr
_ ≤ 4 * |1 - x.snd| := by gcongr; apply le_abs_self
- _ = q2 ((1, 1) - x) := by simp; rfl
+ _ = q2 ((1, 1) - x) := rfl
_ ≤ (p ⊔ q2) ((1, 1) - x) := le_sup_right
_ ≤ (p ⊔ q1) x + (p ⊔ q2) ((1, 1) - x) := le_add_of_nonneg_left (apply_nonneg _ _)
· calc
4 / 3 = 2 / 3 + (1 - 1 / 3) := by norm_num
_ ≤ x.snd + (1 - x.fst) := by gcongr
_ ≤ |x.snd| + |1 - x.fst| := add_le_add (le_abs_self _) (le_abs_self _)
- _ ≤ p x + p ((1, 1) - x) := by exact add_le_add le_sup_right le_sup_left
+ _ ≤ p x + p ((1, 1) - x) := add_le_add le_sup_right le_sup_left
_ ≤ (p ⊔ q1) x + (p ⊔ q2) ((1, 1) - x) := add_le_add le_sup_left le_sup_left
· calc
4 / 3 = 4 * (1 / 3) := by norm_num
diff --git a/Counterexamples/SorgenfreyLine.lean b/Counterexamples/SorgenfreyLine.lean
index 746700b0769de..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 :=
@@ -141,7 +141,7 @@ theorem continuous_toReal : Continuous toReal :=
exact inf_le_left
instance : OrderClosedTopology ℝₗ :=
- ⟨isClosed_le_prod.preimage (continuous_toReal.prod_map continuous_toReal)⟩
+ ⟨isClosed_le_prod.preimage (continuous_toReal.prodMap continuous_toReal)⟩
instance : ContinuousAdd ℝₗ := by
refine ⟨continuous_iff_continuousAt.2 ?_⟩
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 4c21dc471afe4..65c21307d676d 100644
--- a/LongestPole/Main.lean
+++ b/LongestPole/Main.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import ImportGraph
import Mathlib.Data.String.Defs
@@ -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/SpeedCenterJson.lean b/LongestPole/SpeedCenterJson.lean
index 63cf423acecec..20a39f872dd0c 100644
--- a/LongestPole/SpeedCenterJson.lean
+++ b/LongestPole/SpeedCenterJson.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Lean.Data.Json
open Lean
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 b60027448a537..4d7dc462fafaa 100644
--- a/Mathlib.lean
+++ b/Mathlib.lean
@@ -32,10 +32,13 @@ import Mathlib.Algebra.Algebra.Subalgebra.Tower
import Mathlib.Algebra.Algebra.Subalgebra.Unitization
import Mathlib.Algebra.Algebra.Tower
import Mathlib.Algebra.Algebra.Unitization
+import Mathlib.Algebra.Algebra.ZMod
import Mathlib.Algebra.AlgebraicCard
import Mathlib.Algebra.Associated.Basic
import Mathlib.Algebra.Associated.OrderedCommMonoid
import Mathlib.Algebra.BigOperators.Associated
+import Mathlib.Algebra.BigOperators.Balance
+import Mathlib.Algebra.BigOperators.Expect
import Mathlib.Algebra.BigOperators.Fin
import Mathlib.Algebra.BigOperators.Finprod
import Mathlib.Algebra.BigOperators.Finsupp
@@ -55,7 +58,6 @@ import Mathlib.Algebra.BigOperators.Ring.Multiset
import Mathlib.Algebra.BigOperators.Ring.Nat
import Mathlib.Algebra.BigOperators.RingEquiv
import Mathlib.Algebra.BigOperators.WithTop
-import Mathlib.Algebra.Bounds
import Mathlib.Algebra.Category.AlgebraCat.Basic
import Mathlib.Algebra.Category.AlgebraCat.Limits
import Mathlib.Algebra.Category.AlgebraCat.Monoidal
@@ -64,6 +66,7 @@ import Mathlib.Algebra.Category.BialgebraCat.Basic
import Mathlib.Algebra.Category.BoolRing
import Mathlib.Algebra.Category.CoalgebraCat.Basic
import Mathlib.Algebra.Category.CoalgebraCat.ComonEquivalence
+import Mathlib.Algebra.Category.CoalgebraCat.Monoidal
import Mathlib.Algebra.Category.FGModuleCat.Basic
import Mathlib.Algebra.Category.FGModuleCat.Limits
import Mathlib.Algebra.Category.Grp.AB5
@@ -76,6 +79,7 @@ import Mathlib.Algebra.Category.Grp.EnoughInjectives
import Mathlib.Algebra.Category.Grp.EpiMono
import Mathlib.Algebra.Category.Grp.EquivalenceGroupAddGroup
import Mathlib.Algebra.Category.Grp.FilteredColimits
+import Mathlib.Algebra.Category.Grp.FiniteGrp
import Mathlib.Algebra.Category.Grp.ForgetCorepresentable
import Mathlib.Algebra.Category.Grp.Images
import Mathlib.Algebra.Category.Grp.Injective
@@ -96,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
@@ -110,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
@@ -141,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
@@ -148,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
@@ -207,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
@@ -218,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
@@ -241,6 +257,7 @@ import Mathlib.Algebra.Group.Embedding
import Mathlib.Algebra.Group.Equiv.Basic
import Mathlib.Algebra.Group.Equiv.TypeTags
import Mathlib.Algebra.Group.Even
+import Mathlib.Algebra.Group.EvenFunction
import Mathlib.Algebra.Group.Ext
import Mathlib.Algebra.Group.Fin.Basic
import Mathlib.Algebra.Group.Fin.Tuple
@@ -262,19 +279,24 @@ import Mathlib.Algebra.Group.Opposite
import Mathlib.Algebra.Group.PNatPowAssoc
import Mathlib.Algebra.Group.Pi.Basic
import Mathlib.Algebra.Group.Pi.Lemmas
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
+import Mathlib.Algebra.Group.Pointwise.Finset.Interval
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
+import Mathlib.Algebra.Group.Pointwise.Set.Card
import Mathlib.Algebra.Group.Prod
import Mathlib.Algebra.Group.Semiconj.Basic
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
@@ -282,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
@@ -289,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
@@ -298,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
@@ -316,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.Set
+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
@@ -339,6 +367,7 @@ import Mathlib.Algebra.Homology.ConcreteCategory
import Mathlib.Algebra.Homology.DerivedCategory.Basic
import Mathlib.Algebra.Homology.DerivedCategory.ExactFunctor
import Mathlib.Algebra.Homology.DerivedCategory.Ext.Basic
+import Mathlib.Algebra.Homology.DerivedCategory.Ext.ExactSequences
import Mathlib.Algebra.Homology.DerivedCategory.Ext.ExtClass
import Mathlib.Algebra.Homology.DerivedCategory.HomologySequence
import Mathlib.Algebra.Homology.DerivedCategory.ShortExact
@@ -403,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
@@ -459,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
@@ -475,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
@@ -486,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
@@ -500,7 +535,9 @@ import Mathlib.Algebra.Module.Torsion
import Mathlib.Algebra.Module.ULift
import Mathlib.Algebra.Module.ZLattice.Basic
import Mathlib.Algebra.Module.ZLattice.Covolume
+import Mathlib.Algebra.Module.ZMod
import Mathlib.Algebra.MonoidAlgebra.Basic
+import Mathlib.Algebra.MonoidAlgebra.Defs
import Mathlib.Algebra.MonoidAlgebra.Degree
import Mathlib.Algebra.MonoidAlgebra.Division
import Mathlib.Algebra.MonoidAlgebra.Grading
@@ -527,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
@@ -537,8 +579,11 @@ import Mathlib.Algebra.Order.Antidiag.Pi
import Mathlib.Algebra.Order.Antidiag.Prod
import Mathlib.Algebra.Order.Archimedean.Basic
import Mathlib.Algebra.Order.Archimedean.Hom
+import Mathlib.Algebra.Order.Archimedean.Submonoid
+import Mathlib.Algebra.Order.BigOperators.Expect
import Mathlib.Algebra.Order.BigOperators.Group.Finset
import Mathlib.Algebra.Order.BigOperators.Group.List
+import Mathlib.Algebra.Order.BigOperators.Group.LocallyFinite
import Mathlib.Algebra.Order.BigOperators.Group.Multiset
import Mathlib.Algebra.Order.BigOperators.GroupWithZero.List
import Mathlib.Algebra.Order.BigOperators.GroupWithZero.Multiset
@@ -557,6 +602,7 @@ import Mathlib.Algebra.Order.Field.Canonical.Defs
import Mathlib.Algebra.Order.Field.Defs
import Mathlib.Algebra.Order.Field.InjSurj
import Mathlib.Algebra.Order.Field.Pi
+import Mathlib.Algebra.Order.Field.Pointwise
import Mathlib.Algebra.Order.Field.Power
import Mathlib.Algebra.Order.Field.Rat
import Mathlib.Algebra.Order.Field.Subfield
@@ -568,6 +614,7 @@ import Mathlib.Algebra.Order.Group.Action
import Mathlib.Algebra.Order.Group.Action.Synonym
import Mathlib.Algebra.Order.Group.Basic
import Mathlib.Algebra.Order.Group.Bounds
+import Mathlib.Algebra.Order.Group.CompleteLattice
import Mathlib.Algebra.Order.Group.Cone
import Mathlib.Algebra.Order.Group.Defs
import Mathlib.Algebra.Order.Group.DenselyOrdered
@@ -578,8 +625,11 @@ import Mathlib.Algebra.Order.Group.Int
import Mathlib.Algebra.Order.Group.Lattice
import Mathlib.Algebra.Order.Group.MinMax
import Mathlib.Algebra.Order.Group.Nat
+import Mathlib.Algebra.Order.Group.Opposite
import Mathlib.Algebra.Order.Group.OrderIso
import Mathlib.Algebra.Order.Group.PiLex
+import Mathlib.Algebra.Order.Group.Pointwise.Bounds
+import Mathlib.Algebra.Order.Group.Pointwise.CompleteLattice
import Mathlib.Algebra.Order.Group.PosPart
import Mathlib.Algebra.Order.Group.Prod
import Mathlib.Algebra.Order.Group.Synonym
@@ -593,10 +643,13 @@ import Mathlib.Algebra.Order.GroupWithZero.Canonical
import Mathlib.Algebra.Order.GroupWithZero.Submonoid
import Mathlib.Algebra.Order.GroupWithZero.Synonym
import Mathlib.Algebra.Order.GroupWithZero.Unbundled
+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
@@ -612,6 +665,7 @@ import Mathlib.Algebra.Order.Module.Pointwise
import Mathlib.Algebra.Order.Module.Rat
import Mathlib.Algebra.Order.Module.Synonym
import Mathlib.Algebra.Order.Monoid.Basic
+import Mathlib.Algebra.Order.Monoid.Canonical.Basic
import Mathlib.Algebra.Order.Monoid.Canonical.Defs
import Mathlib.Algebra.Order.Monoid.Defs
import Mathlib.Algebra.Order.Monoid.NatCast
@@ -626,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
@@ -635,7 +690,6 @@ import Mathlib.Algebra.Order.Nonneg.Floor
import Mathlib.Algebra.Order.Nonneg.Module
import Mathlib.Algebra.Order.Nonneg.Ring
import Mathlib.Algebra.Order.Pi
-import Mathlib.Algebra.Order.Pointwise
import Mathlib.Algebra.Order.Positive.Field
import Mathlib.Algebra.Order.Positive.Ring
import Mathlib.Algebra.Order.Rearrangement
@@ -649,6 +703,7 @@ import Mathlib.Algebra.Order.Ring.Finset
import Mathlib.Algebra.Order.Ring.InjSurj
import Mathlib.Algebra.Order.Ring.Int
import Mathlib.Algebra.Order.Ring.Nat
+import Mathlib.Algebra.Order.Ring.Opposite
import Mathlib.Algebra.Order.Ring.Pow
import Mathlib.Algebra.Order.Ring.Prod
import Mathlib.Algebra.Order.Ring.Rat
@@ -660,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
@@ -667,12 +723,14 @@ import Mathlib.Algebra.Order.Sub.Unbundled.Basic
import Mathlib.Algebra.Order.Sub.Unbundled.Hom
import Mathlib.Algebra.Order.Sub.WithTop
import Mathlib.Algebra.Order.SuccPred
+import Mathlib.Algebra.Order.SuccPred.TypeTags
import Mathlib.Algebra.Order.Sum
import Mathlib.Algebra.Order.ToIntervalMod
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
@@ -716,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
@@ -759,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
@@ -766,6 +828,7 @@ import Mathlib.Algebra.Ring.Regular
import Mathlib.Algebra.Ring.Semiconj
import Mathlib.Algebra.Ring.Semireal.Defs
import Mathlib.Algebra.Ring.Subring.Basic
+import Mathlib.Algebra.Ring.Subring.IntPolynomial
import Mathlib.Algebra.Ring.Subring.MulOpposite
import Mathlib.Algebra.Ring.Subring.Order
import Mathlib.Algebra.Ring.Subring.Pointwise
@@ -777,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
@@ -814,8 +878,11 @@ 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
+import Mathlib.AlgebraicGeometry.EllipticCurve.VariableChange
import Mathlib.AlgebraicGeometry.EllipticCurve.Weierstrass
import Mathlib.AlgebraicGeometry.FunctionField
import Mathlib.AlgebraicGeometry.GammaSpecAdjunction
@@ -831,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
@@ -853,10 +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
@@ -887,26 +961,29 @@ 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
import Mathlib.Analysis.Analytic.Basic
import Mathlib.Analysis.Analytic.CPolynomial
+import Mathlib.Analysis.Analytic.ChangeOrigin
import Mathlib.Analysis.Analytic.Composition
import Mathlib.Analysis.Analytic.Constructions
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
@@ -930,18 +1007,25 @@ import Mathlib.Analysis.BoxIntegral.Partition.Split
import Mathlib.Analysis.BoxIntegral.Partition.SubboxInduction
import Mathlib.Analysis.BoxIntegral.Partition.Tagged
import Mathlib.Analysis.BoxIntegral.UnitPartition
+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
import Mathlib.Analysis.CStarAlgebra.Matrix
import Mathlib.Analysis.CStarAlgebra.Module.Constructions
import Mathlib.Analysis.CStarAlgebra.Module.Defs
@@ -949,6 +1033,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
@@ -961,9 +1046,12 @@ import Mathlib.Analysis.Calculus.Conformal.NormedSpace
import Mathlib.Analysis.Calculus.ContDiff.Basic
import Mathlib.Analysis.Calculus.ContDiff.Bounds
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
import Mathlib.Analysis.Calculus.Deriv.AffineMap
import Mathlib.Analysis.Calculus.Deriv.Basic
@@ -993,11 +1081,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
@@ -1049,6 +1140,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
@@ -1066,6 +1158,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
@@ -1076,6 +1169,7 @@ import Mathlib.Analysis.Convex.Cone.Extension
import Mathlib.Analysis.Convex.Cone.InnerDual
import Mathlib.Analysis.Convex.Cone.Pointed
import Mathlib.Analysis.Convex.Cone.Proper
+import Mathlib.Analysis.Convex.Continuous
import Mathlib.Analysis.Convex.Contractible
import Mathlib.Analysis.Convex.Deriv
import Mathlib.Analysis.Convex.EGauge
@@ -1112,6 +1206,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
@@ -1161,6 +1256,7 @@ import Mathlib.Analysis.LocallyConvex.ContinuousOfBounded
import Mathlib.Analysis.LocallyConvex.Polar
import Mathlib.Analysis.LocallyConvex.StrongTopology
import Mathlib.Analysis.LocallyConvex.WeakDual
+import Mathlib.Analysis.LocallyConvex.WeakSpace
import Mathlib.Analysis.LocallyConvex.WithSeminorms
import Mathlib.Analysis.Matrix
import Mathlib.Analysis.MeanInequalities
@@ -1175,6 +1271,7 @@ import Mathlib.Analysis.Normed.Affine.MazurUlam
import Mathlib.Analysis.Normed.Algebra.Basic
import Mathlib.Analysis.Normed.Algebra.Exponential
import Mathlib.Analysis.Normed.Algebra.MatrixExponential
+import Mathlib.Analysis.Normed.Algebra.Norm
import Mathlib.Analysis.Normed.Algebra.QuaternionExponential
import Mathlib.Analysis.Normed.Algebra.Spectrum
import Mathlib.Analysis.Normed.Algebra.TrivSqZeroExt
@@ -1183,6 +1280,8 @@ import Mathlib.Analysis.Normed.Algebra.UnitizationL1
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
@@ -1208,6 +1307,7 @@ import Mathlib.Analysis.Normed.Group.SemiNormedGrp.Kernels
import Mathlib.Analysis.Normed.Group.Seminorm
import Mathlib.Analysis.Normed.Group.Submodule
import Mathlib.Analysis.Normed.Group.Tannery
+import Mathlib.Analysis.Normed.Group.Ultra
import Mathlib.Analysis.Normed.Group.Uniform
import Mathlib.Analysis.Normed.Group.ZeroAtInfty
import Mathlib.Analysis.Normed.Lp.LpEquiv
@@ -1234,9 +1334,11 @@ import Mathlib.Analysis.Normed.Operator.WeakOperatorTopology
import Mathlib.Analysis.Normed.Order.Basic
import Mathlib.Analysis.Normed.Order.Lattice
import Mathlib.Analysis.Normed.Order.UpperLower
+import Mathlib.Analysis.Normed.Ring.IsPowMulFaithful
import Mathlib.Analysis.Normed.Ring.Seminorm
import Mathlib.Analysis.Normed.Ring.SeminormFromBounded
import Mathlib.Analysis.Normed.Ring.SeminormFromConst
+import Mathlib.Analysis.Normed.Ring.Ultra
import Mathlib.Analysis.Normed.Ring.Units
import Mathlib.Analysis.NormedSpace.BallAction
import Mathlib.Analysis.NormedSpace.ConformalLinearMap
@@ -1277,6 +1379,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
@@ -1300,6 +1403,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
@@ -1315,6 +1419,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
@@ -1357,6 +1462,7 @@ import Mathlib.CategoryTheory.Abelian.Exact
import Mathlib.CategoryTheory.Abelian.Ext
import Mathlib.CategoryTheory.Abelian.FunctorCategory
import Mathlib.CategoryTheory.Abelian.Generator
+import Mathlib.CategoryTheory.Abelian.GrothendieckAxioms
import Mathlib.CategoryTheory.Abelian.Images
import Mathlib.CategoryTheory.Abelian.Injective
import Mathlib.CategoryTheory.Abelian.InjectiveResolution
@@ -1383,6 +1489,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
@@ -1396,14 +1503,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
@@ -1424,6 +1534,7 @@ import Mathlib.CategoryTheory.Category.PartialFun
import Mathlib.CategoryTheory.Category.Pointed
import Mathlib.CategoryTheory.Category.Preorder
import Mathlib.CategoryTheory.Category.Quiv
+import Mathlib.CategoryTheory.Category.ReflQuiv
import Mathlib.CategoryTheory.Category.RelCat
import Mathlib.CategoryTheory.Category.TwoP
import Mathlib.CategoryTheory.Category.ULift
@@ -1431,8 +1542,11 @@ 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
import Mathlib.CategoryTheory.Closed.Types
@@ -1443,8 +1557,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
@@ -1473,6 +1590,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
@@ -1482,6 +1600,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
@@ -1509,11 +1628,16 @@ import Mathlib.CategoryTheory.Functor.KanExtension.Pointwise
import Mathlib.CategoryTheory.Functor.OfSequence
import Mathlib.CategoryTheory.Functor.ReflectsIso
import Mathlib.CategoryTheory.Functor.Trifunctor
+import Mathlib.CategoryTheory.Galois.Action
import Mathlib.CategoryTheory.Galois.Basic
import Mathlib.CategoryTheory.Galois.Decomposition
+import Mathlib.CategoryTheory.Galois.EssSurj
import Mathlib.CategoryTheory.Galois.Examples
+import Mathlib.CategoryTheory.Galois.Full
import Mathlib.CategoryTheory.Galois.GaloisObjects
+import Mathlib.CategoryTheory.Galois.IsFundamentalgroup
import Mathlib.CategoryTheory.Galois.Prorepresentability
+import Mathlib.CategoryTheory.Galois.Topology
import Mathlib.CategoryTheory.Generator
import Mathlib.CategoryTheory.GlueData
import Mathlib.CategoryTheory.GradedObject
@@ -1527,6 +1651,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
@@ -1585,11 +1710,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
@@ -1610,14 +1737,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
@@ -1625,6 +1755,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
@@ -1634,6 +1765,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
@@ -1653,6 +1785,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
@@ -1703,6 +1836,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
@@ -1744,6 +1878,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
@@ -1756,7 +1891,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
@@ -1798,6 +1934,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
@@ -1846,6 +1983,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
@@ -1867,7 +2005,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
@@ -1934,6 +2072,7 @@ import Mathlib.Combinatorics.Quiver.ConnectedComponent
import Mathlib.Combinatorics.Quiver.Covering
import Mathlib.Combinatorics.Quiver.Path
import Mathlib.Combinatorics.Quiver.Push
+import Mathlib.Combinatorics.Quiver.ReflQuiver
import Mathlib.Combinatorics.Quiver.SingleObj
import Mathlib.Combinatorics.Quiver.Subquiver
import Mathlib.Combinatorics.Quiver.Symmetric
@@ -2020,6 +2159,10 @@ 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
import Mathlib.Condensed.Equivalence
import Mathlib.Condensed.Explicit
@@ -2075,7 +2218,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
@@ -2100,11 +2242,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
@@ -2122,12 +2263,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
@@ -2141,6 +2287,7 @@ import Mathlib.Data.Finset.Grade
import Mathlib.Data.Finset.Image
import Mathlib.Data.Finset.Interval
import Mathlib.Data.Finset.Lattice
+import Mathlib.Data.Finset.Max
import Mathlib.Data.Finset.MulAntidiagonal
import Mathlib.Data.Finset.NAry
import Mathlib.Data.Finset.NatAntidiagonal
@@ -2153,9 +2300,6 @@ import Mathlib.Data.Finset.Pairwise
import Mathlib.Data.Finset.Pi
import Mathlib.Data.Finset.PiInduction
import Mathlib.Data.Finset.Piecewise
-import Mathlib.Data.Finset.Pointwise.Basic
-import Mathlib.Data.Finset.Pointwise.Card
-import Mathlib.Data.Finset.Pointwise.Interval
import Mathlib.Data.Finset.Powerset
import Mathlib.Data.Finset.Preimage
import Mathlib.Data.Finset.Prod
@@ -2215,7 +2359,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
@@ -2227,6 +2370,7 @@ import Mathlib.Data.Int.Cast.Prod
import Mathlib.Data.Int.CharZero
import Mathlib.Data.Int.ConditionallyCompleteOrder
import Mathlib.Data.Int.Defs
+import Mathlib.Data.Int.DivMod
import Mathlib.Data.Int.GCD
import Mathlib.Data.Int.Interval
import Mathlib.Data.Int.LeastGreatest
@@ -2242,6 +2386,7 @@ import Mathlib.Data.Int.Range
import Mathlib.Data.Int.Sqrt
import Mathlib.Data.Int.Star
import Mathlib.Data.Int.SuccPred
+import Mathlib.Data.Int.WithZero
import Mathlib.Data.LazyList.Basic
import Mathlib.Data.List.AList
import Mathlib.Data.List.Basic
@@ -2260,8 +2405,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
@@ -2277,7 +2424,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
@@ -2306,6 +2455,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
@@ -2346,10 +2496,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
@@ -2412,6 +2565,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
@@ -2487,7 +2645,9 @@ 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
import Mathlib.Data.Real.Pi.Wallis
import Mathlib.Data.Real.Pointwise
@@ -2518,6 +2678,7 @@ import Mathlib.Data.Set.Image
import Mathlib.Data.Set.Lattice
import Mathlib.Data.Set.List
import Mathlib.Data.Set.MemPartition
+import Mathlib.Data.Set.Monotone
import Mathlib.Data.Set.MulAntidiagonal
import Mathlib.Data.Set.NAry
import Mathlib.Data.Set.Notation
@@ -2540,6 +2701,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
@@ -2567,6 +2729,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
@@ -2582,20 +2745,24 @@ import Mathlib.Data.Vector3
import Mathlib.Data.W.Basic
import Mathlib.Data.W.Cardinal
import Mathlib.Data.W.Constructions
-import Mathlib.Data.ZMod.Algebra
import Mathlib.Data.ZMod.Basic
import Mathlib.Data.ZMod.Coprime
import Mathlib.Data.ZMod.Defs
import Mathlib.Data.ZMod.Factorial
import Mathlib.Data.ZMod.IntUnitsPower
-import Mathlib.Data.ZMod.Module
-import Mathlib.Data.ZMod.Parity
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
@@ -2606,6 +2773,7 @@ import Mathlib.Dynamics.BirkhoffSum.Basic
import Mathlib.Dynamics.BirkhoffSum.NormedSpace
import Mathlib.Dynamics.Circle.RotationNumber.TranslationNumber
import Mathlib.Dynamics.Ergodic.Action.Basic
+import Mathlib.Dynamics.Ergodic.Action.OfMinimal
import Mathlib.Dynamics.Ergodic.Action.Regular
import Mathlib.Dynamics.Ergodic.AddCircle
import Mathlib.Dynamics.Ergodic.Conservative
@@ -2621,12 +2789,16 @@ import Mathlib.Dynamics.OmegaLimit
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
+import Mathlib.FieldTheory.Differential.Basic
import Mathlib.FieldTheory.Extension
import Mathlib.FieldTheory.Finite.Basic
import Mathlib.FieldTheory.Finite.GaloisField
@@ -2634,7 +2806,9 @@ import Mathlib.FieldTheory.Finite.Polynomial
import Mathlib.FieldTheory.Finite.Trace
import Mathlib.FieldTheory.Finiteness
import Mathlib.FieldTheory.Fixed
-import Mathlib.FieldTheory.Galois
+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
@@ -2648,6 +2822,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
@@ -2720,6 +2895,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
@@ -2756,11 +2932,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
@@ -2783,6 +2962,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
@@ -2800,6 +2980,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
@@ -2808,10 +2989,13 @@ 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
import Mathlib.GroupTheory.Perm.ClosureSwap
+import Mathlib.GroupTheory.Perm.ConjAct
import Mathlib.GroupTheory.Perm.Cycle.Basic
import Mathlib.GroupTheory.Perm.Cycle.Concrete
import Mathlib.GroupTheory.Perm.Cycle.Factors
@@ -2829,6 +3013,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
@@ -2853,9 +3038,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
@@ -2864,6 +3046,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
@@ -2948,6 +3131,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
@@ -2996,12 +3180,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
@@ -3026,7 +3212,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
@@ -3036,6 +3224,7 @@ import Mathlib.LinearAlgebra.PiTensorProduct
import Mathlib.LinearAlgebra.Prod
import Mathlib.LinearAlgebra.Projection
import Mathlib.LinearAlgebra.Projectivization.Basic
+import Mathlib.LinearAlgebra.Projectivization.Constructions
import Mathlib.LinearAlgebra.Projectivization.Independence
import Mathlib.LinearAlgebra.Projectivization.Subspace
import Mathlib.LinearAlgebra.QuadraticForm.Basic
@@ -3051,13 +3240,16 @@ 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
import Mathlib.LinearAlgebra.RootSystem.Defs
+import Mathlib.LinearAlgebra.RootSystem.Finite.CanonicalBilinear
import Mathlib.LinearAlgebra.RootSystem.Hom
+import Mathlib.LinearAlgebra.RootSystem.OfBilinear
import Mathlib.LinearAlgebra.RootSystem.RootPairingCat
import Mathlib.LinearAlgebra.RootSystem.RootPositive
import Mathlib.LinearAlgebra.SModEq
@@ -3081,6 +3273,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
@@ -3109,10 +3302,12 @@ import Mathlib.Logic.Equiv.Pairwise
import Mathlib.Logic.Equiv.PartialEquiv
import Mathlib.Logic.Equiv.Set
import Mathlib.Logic.Equiv.TransferInstance
+import Mathlib.Logic.ExistsUnique
import Mathlib.Logic.Function.Basic
import Mathlib.Logic.Function.CompTypeclasses
import Mathlib.Logic.Function.Conjugate
import Mathlib.Logic.Function.Defs
+import Mathlib.Logic.Function.FiberPartition
import Mathlib.Logic.Function.FromTypes
import Mathlib.Logic.Function.Iterate
import Mathlib.Logic.Function.OfArity
@@ -3124,6 +3319,7 @@ import Mathlib.Logic.Lemmas
import Mathlib.Logic.Nonempty
import Mathlib.Logic.Nontrivial.Basic
import Mathlib.Logic.Nontrivial.Defs
+import Mathlib.Logic.OpClass
import Mathlib.Logic.Pairwise
import Mathlib.Logic.Relation
import Mathlib.Logic.Relator
@@ -3137,6 +3333,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
@@ -3150,9 +3347,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
@@ -3252,6 +3448,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
@@ -3265,6 +3462,8 @@ import Mathlib.MeasureTheory.MeasurableSpace.Embedding
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
@@ -3302,8 +3501,10 @@ 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
import Mathlib.MeasureTheory.Measure.Stieltjes
import Mathlib.MeasureTheory.Measure.Sub
import Mathlib.MeasureTheory.Measure.Tilted
@@ -3340,6 +3541,7 @@ import Mathlib.ModelTheory.DirectLimit
import Mathlib.ModelTheory.ElementaryMaps
import Mathlib.ModelTheory.ElementarySubstructures
import Mathlib.ModelTheory.Encoding
+import Mathlib.ModelTheory.Equivalence
import Mathlib.ModelTheory.FinitelyGenerated
import Mathlib.ModelTheory.Fraisse
import Mathlib.ModelTheory.Graph
@@ -3386,6 +3588,8 @@ import Mathlib.NumberTheory.EulerProduct.DirichletLSeries
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
@@ -3411,6 +3615,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
@@ -3450,8 +3655,10 @@ import Mathlib.NumberTheory.Multiplicity
import Mathlib.NumberTheory.NumberField.Basic
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
@@ -3502,6 +3709,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
@@ -3529,6 +3738,7 @@ import Mathlib.Order.CompactlyGenerated.Intervals
import Mathlib.Order.Compare
import Mathlib.Order.CompleteBooleanAlgebra
import Mathlib.Order.CompleteLattice
+import Mathlib.Order.CompleteLattice.Finset
import Mathlib.Order.CompleteLatticeIntervals
import Mathlib.Order.CompletePartialOrder
import Mathlib.Order.CompleteSublattice
@@ -3536,6 +3746,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
@@ -3546,8 +3757,15 @@ import Mathlib.Order.Disjointed
import Mathlib.Order.Estimator
import Mathlib.Order.Extension.Linear
import Mathlib.Order.Extension.Well
-import Mathlib.Order.Filter.Archimedean
import Mathlib.Order.Filter.AtTopBot
+import Mathlib.Order.Filter.AtTopBot.Archimedean
+import Mathlib.Order.Filter.AtTopBot.BigOperators
+import Mathlib.Order.Filter.AtTopBot.Field
+import Mathlib.Order.Filter.AtTopBot.Floor
+import Mathlib.Order.Filter.AtTopBot.Group
+import Mathlib.Order.Filter.AtTopBot.ModEq
+import Mathlib.Order.Filter.AtTopBot.Monoid
+import Mathlib.Order.Filter.AtTopBot.Ring
import Mathlib.Order.Filter.Bases
import Mathlib.Order.Filter.Basic
import Mathlib.Order.Filter.CardinalInter
@@ -3556,6 +3774,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
@@ -3567,7 +3786,6 @@ import Mathlib.Order.Filter.Interval
import Mathlib.Order.Filter.Ker
import Mathlib.Order.Filter.Lift
import Mathlib.Order.Filter.ListTraverse
-import Mathlib.Order.Filter.ModEq
import Mathlib.Order.Filter.NAry
import Mathlib.Order.Filter.Partial
import Mathlib.Order.Filter.Pi
@@ -3576,6 +3794,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
@@ -3620,7 +3839,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
@@ -3658,6 +3876,7 @@ import Mathlib.Order.RelIso.Basic
import Mathlib.Order.RelIso.Group
import Mathlib.Order.RelIso.Set
import Mathlib.Order.RelSeries
+import Mathlib.Order.Restriction
import Mathlib.Order.ScottContinuity
import Mathlib.Order.SemiconjSup
import Mathlib.Order.SetNotation
@@ -3669,6 +3888,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
@@ -3685,7 +3905,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
@@ -3693,11 +3912,13 @@ import Mathlib.Probability.Distributions.Exponential
import Mathlib.Probability.Distributions.Gamma
import Mathlib.Probability.Distributions.Gaussian
import Mathlib.Probability.Distributions.Geometric
+import Mathlib.Probability.Distributions.Pareto
import Mathlib.Probability.Distributions.Poisson
import Mathlib.Probability.Distributions.Uniform
import Mathlib.Probability.IdentDistrib
import Mathlib.Probability.Independence.Basic
import Mathlib.Probability.Independence.Conditional
+import Mathlib.Probability.Independence.Integrable
import Mathlib.Probability.Independence.Kernel
import Mathlib.Probability.Independence.ZeroOne
import Mathlib.Probability.Integration
@@ -3705,6 +3926,7 @@ import Mathlib.Probability.Kernel.Basic
import Mathlib.Probability.Kernel.Composition
import Mathlib.Probability.Kernel.CondDistrib
import Mathlib.Probability.Kernel.Condexp
+import Mathlib.Probability.Kernel.Defs
import Mathlib.Probability.Kernel.Disintegration.Basic
import Mathlib.Probability.Kernel.Disintegration.CDFToKernel
import Mathlib.Probability.Kernel.Disintegration.CondCDF
@@ -3713,6 +3935,7 @@ import Mathlib.Probability.Kernel.Disintegration.Integral
import Mathlib.Probability.Kernel.Disintegration.MeasurableStieltjes
import Mathlib.Probability.Kernel.Disintegration.StandardBorel
import Mathlib.Probability.Kernel.Disintegration.Unique
+import Mathlib.Probability.Kernel.Integral
import Mathlib.Probability.Kernel.IntegralCompProd
import Mathlib.Probability.Kernel.Invariance
import Mathlib.Probability.Kernel.MeasurableIntegral
@@ -3739,6 +3962,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
@@ -3774,15 +3998,18 @@ 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
import Mathlib.RingTheory.Coalgebra.Basic
import Mathlib.RingTheory.Coalgebra.Equiv
import Mathlib.RingTheory.Coalgebra.Hom
+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
@@ -3801,15 +4028,19 @@ import Mathlib.RingTheory.DedekindDomain.SelmerGroup
import Mathlib.RingTheory.Derivation.Basic
import Mathlib.RingTheory.Derivation.DifferentialRing
import Mathlib.RingTheory.Derivation.Lie
+import Mathlib.RingTheory.Derivation.MapCoeffs
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
@@ -3819,6 +4050,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
@@ -3845,18 +4077,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
@@ -3869,32 +4110,42 @@ 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
+import Mathlib.RingTheory.LocalProperties.Basic
+import Mathlib.RingTheory.LocalProperties.IntegrallyClosed
+import Mathlib.RingTheory.LocalProperties.Reduced
import Mathlib.RingTheory.LocalRing.Basic
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
import Mathlib.RingTheory.Localization.Away.AdjoinRoot
import Mathlib.RingTheory.Localization.Away.Basic
+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
@@ -3913,12 +4164,14 @@ import Mathlib.RingTheory.MvPolynomial.Basic
import Mathlib.RingTheory.MvPolynomial.Homogeneous
import Mathlib.RingTheory.MvPolynomial.Ideal
import Mathlib.RingTheory.MvPolynomial.Localization
-import Mathlib.RingTheory.MvPolynomial.NewtonIdentities
-import Mathlib.RingTheory.MvPolynomial.Symmetric
+import Mathlib.RingTheory.MvPolynomial.Symmetric.Defs
+import Mathlib.RingTheory.MvPolynomial.Symmetric.FundamentalTheorem
+import Mathlib.RingTheory.MvPolynomial.Symmetric.NewtonIdentities
import Mathlib.RingTheory.MvPolynomial.Tower
import Mathlib.RingTheory.MvPolynomial.WeightedHomogeneous
import Mathlib.RingTheory.MvPowerSeries.Basic
import Mathlib.RingTheory.MvPowerSeries.Inverse
+import Mathlib.RingTheory.MvPowerSeries.LexOrder
import Mathlib.RingTheory.MvPowerSeries.NoZeroDivisors
import Mathlib.RingTheory.MvPowerSeries.Trunc
import Mathlib.RingTheory.Nakayama
@@ -3978,8 +4231,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
@@ -3988,6 +4239,8 @@ import Mathlib.RingTheory.RingHom.Finite
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
@@ -3996,8 +4249,11 @@ import Mathlib.RingTheory.RootsOfUnity.Complex
import Mathlib.RingTheory.RootsOfUnity.Lemmas
import Mathlib.RingTheory.RootsOfUnity.Minpoly
import Mathlib.RingTheory.SimpleModule
+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
@@ -4005,13 +4261,17 @@ 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
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
import Mathlib.RingTheory.Valuation.AlgebraInstances
import Mathlib.RingTheory.Valuation.Basic
import Mathlib.RingTheory.Valuation.ExtendToLocalization
@@ -4022,6 +4282,7 @@ import Mathlib.RingTheory.Valuation.PrimeMultiplicity
import Mathlib.RingTheory.Valuation.Quotient
import Mathlib.RingTheory.Valuation.RamificationGroup
import Mathlib.RingTheory.Valuation.RankOne
+import Mathlib.RingTheory.Valuation.ValExtension
import Mathlib.RingTheory.Valuation.ValuationRing
import Mathlib.RingTheory.Valuation.ValuationSubring
import Mathlib.RingTheory.WittVector.Basic
@@ -4043,6 +4304,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
@@ -4051,7 +4314,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
@@ -4070,12 +4333,15 @@ 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
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
@@ -4083,9 +4349,11 @@ import Mathlib.SetTheory.Surreal.Multiplication
import Mathlib.SetTheory.ZFC.Basic
import Mathlib.SetTheory.ZFC.Ordinal
import Mathlib.SetTheory.ZFC.Rank
+import Mathlib.Std.Data.HashMap
import Mathlib.Tactic
import Mathlib.Tactic.Abel
import Mathlib.Tactic.AdaptationNote
+import Mathlib.Tactic.Algebraize
import Mathlib.Tactic.ApplyAt
import Mathlib.Tactic.ApplyCongr
import Mathlib.Tactic.ApplyFun
@@ -4108,13 +4376,25 @@ import Mathlib.Tactic.CancelDenoms.Core
import Mathlib.Tactic.Cases
import Mathlib.Tactic.CasesM
import Mathlib.Tactic.CategoryTheory.BicategoricalComp
+import Mathlib.Tactic.CategoryTheory.Bicategory.Basic
+import Mathlib.Tactic.CategoryTheory.Bicategory.Datatypes
+import Mathlib.Tactic.CategoryTheory.Bicategory.Normalize
+import Mathlib.Tactic.CategoryTheory.Bicategory.PureCoherence
import Mathlib.Tactic.CategoryTheory.BicategoryCoherence
import Mathlib.Tactic.CategoryTheory.Coherence
+import Mathlib.Tactic.CategoryTheory.Coherence.Basic
+import Mathlib.Tactic.CategoryTheory.Coherence.Datatypes
+import Mathlib.Tactic.CategoryTheory.Coherence.Normalize
+import Mathlib.Tactic.CategoryTheory.Coherence.PureCoherence
import Mathlib.Tactic.CategoryTheory.Elementwise
-import Mathlib.Tactic.CategoryTheory.Monoidal
+import Mathlib.Tactic.CategoryTheory.Monoidal.Basic
+import Mathlib.Tactic.CategoryTheory.Monoidal.Datatypes
+import Mathlib.Tactic.CategoryTheory.Monoidal.Normalize
+import Mathlib.Tactic.CategoryTheory.Monoidal.PureCoherence
import Mathlib.Tactic.CategoryTheory.MonoidalComp
import Mathlib.Tactic.CategoryTheory.Reassoc
import Mathlib.Tactic.CategoryTheory.Slice
+import Mathlib.Tactic.CategoryTheory.ToApp
import Mathlib.Tactic.Change
import Mathlib.Tactic.Check
import Mathlib.Tactic.Choose
@@ -4135,6 +4415,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
@@ -4154,6 +4435,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
@@ -4170,6 +4453,7 @@ import Mathlib.Tactic.FunProp.ToBatteries
import Mathlib.Tactic.FunProp.Types
import Mathlib.Tactic.GCongr
import Mathlib.Tactic.GCongr.Core
+import Mathlib.Tactic.GCongr.CoreAttrs
import Mathlib.Tactic.GCongr.ForwardAttr
import Mathlib.Tactic.Generalize
import Mathlib.Tactic.GeneralizeProofs
@@ -4204,15 +4488,20 @@ import Mathlib.Tactic.Linarith.Preprocessing
import Mathlib.Tactic.Linarith.Verification
import Mathlib.Tactic.LinearCombination
import Mathlib.Tactic.LinearCombination'
+import Mathlib.Tactic.LinearCombination.Lemmas
import Mathlib.Tactic.Linter
import Mathlib.Tactic.Linter.AdmitLinter
+import Mathlib.Tactic.Linter.DocPrime
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
@@ -4222,6 +4511,7 @@ import Mathlib.Tactic.Measurability.Init
import Mathlib.Tactic.MinImports
import Mathlib.Tactic.MkIffOfInductiveProp
import Mathlib.Tactic.ModCases
+import Mathlib.Tactic.Module
import Mathlib.Tactic.Monotonicity
import Mathlib.Tactic.Monotonicity.Attr
import Mathlib.Tactic.Monotonicity.Basic
@@ -4245,6 +4535,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
@@ -4269,7 +4560,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
@@ -4277,6 +4567,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
@@ -4331,6 +4622,9 @@ import Mathlib.Topology.AlexandrovDiscrete
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
import Mathlib.Topology.Algebra.Constructions.DomMulAct
@@ -4342,6 +4636,8 @@ 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
import Mathlib.Topology.Algebra.GroupWithZero
@@ -4367,6 +4663,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
@@ -4374,6 +4671,7 @@ import Mathlib.Topology.Algebra.Module.Simple
import Mathlib.Topology.Algebra.Module.Star
import Mathlib.Topology.Algebra.Module.StrongTopology
import Mathlib.Topology.Algebra.Module.UniformConvergence
+import Mathlib.Topology.Algebra.Module.WeakBilin
import Mathlib.Topology.Algebra.Module.WeakDual
import Mathlib.Topology.Algebra.Monoid
import Mathlib.Topology.Algebra.MulAction
@@ -4382,29 +4680,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
@@ -4422,6 +4722,7 @@ import Mathlib.Topology.Bornology.Basic
import Mathlib.Topology.Bornology.BoundedOperation
import Mathlib.Topology.Bornology.Constructions
import Mathlib.Topology.Bornology.Hom
+import Mathlib.Topology.CWComplex
import Mathlib.Topology.Category.Born
import Mathlib.Topology.Category.CompHaus.Basic
import Mathlib.Topology.Category.CompHaus.EffectiveEpi
@@ -4466,6 +4767,7 @@ import Mathlib.Topology.Category.TopCat.Limits.Products
import Mathlib.Topology.Category.TopCat.Limits.Pullbacks
import Mathlib.Topology.Category.TopCat.OpenNhds
import Mathlib.Topology.Category.TopCat.Opens
+import Mathlib.Topology.Category.TopCat.Sphere
import Mathlib.Topology.Category.TopCat.Yoneda
import Mathlib.Topology.Category.TopCommRingCat
import Mathlib.Topology.Category.UniformSpace
@@ -4473,8 +4775,10 @@ 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
import Mathlib.Topology.Compactness.Lindelof
import Mathlib.Topology.Compactness.LocallyCompact
import Mathlib.Topology.Compactness.Paracompact
@@ -4488,24 +4792,26 @@ import Mathlib.Topology.Connected.PathConnected
import Mathlib.Topology.Connected.Separation
import Mathlib.Topology.Connected.TotallyDisconnected
import Mathlib.Topology.Constructions
-import Mathlib.Topology.ContinuousFunction.Algebra
-import Mathlib.Topology.ContinuousFunction.Basic
-import Mathlib.Topology.ContinuousFunction.Bounded
-import Mathlib.Topology.ContinuousFunction.CocompactMap
-import Mathlib.Topology.ContinuousFunction.Compact
-import Mathlib.Topology.ContinuousFunction.CompactlySupported
-import Mathlib.Topology.ContinuousFunction.ContinuousMapZero
-import Mathlib.Topology.ContinuousFunction.Ideals
-import Mathlib.Topology.ContinuousFunction.LocallyConstant
-import Mathlib.Topology.ContinuousFunction.Ordered
-import Mathlib.Topology.ContinuousFunction.Polynomial
-import Mathlib.Topology.ContinuousFunction.Sigma
-import Mathlib.Topology.ContinuousFunction.StarOrdered
-import Mathlib.Topology.ContinuousFunction.StoneWeierstrass
-import Mathlib.Topology.ContinuousFunction.T0Sierpinski
-import Mathlib.Topology.ContinuousFunction.Units
-import Mathlib.Topology.ContinuousFunction.Weierstrass
-import Mathlib.Topology.ContinuousFunction.ZeroAtInfty
+import Mathlib.Topology.ContinuousMap.Algebra
+import Mathlib.Topology.ContinuousMap.Basic
+import Mathlib.Topology.ContinuousMap.Bounded
+import Mathlib.Topology.ContinuousMap.BoundedCompactlySupported
+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
+import Mathlib.Topology.ContinuousMap.Polynomial
+import Mathlib.Topology.ContinuousMap.Sigma
+import Mathlib.Topology.ContinuousMap.StarOrdered
+import Mathlib.Topology.ContinuousMap.StoneWeierstrass
+import Mathlib.Topology.ContinuousMap.T0Sierpinski
+import Mathlib.Topology.ContinuousMap.Units
+import Mathlib.Topology.ContinuousMap.Weierstrass
+import Mathlib.Topology.ContinuousMap.ZeroAtInfty
import Mathlib.Topology.ContinuousOn
import Mathlib.Topology.CountableSeparatingOn
import Mathlib.Topology.Covering
@@ -4524,15 +4830,20 @@ import Mathlib.Topology.EMetricSpace.Lipschitz
import Mathlib.Topology.EMetricSpace.Paracompact
import Mathlib.Topology.EMetricSpace.Pi
import Mathlib.Topology.ExtendFrom
+import Mathlib.Topology.Exterior
import Mathlib.Topology.ExtremallyDisconnected
import Mathlib.Topology.FiberBundle.Basic
import Mathlib.Topology.FiberBundle.Constructions
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
@@ -4564,8 +4875,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
@@ -4574,7 +4887,9 @@ import Mathlib.Topology.LocallyConstant.Algebra
import Mathlib.Topology.LocallyConstant.Basic
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
@@ -4597,6 +4912,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
@@ -4620,6 +4936,8 @@ import Mathlib.Topology.MetricSpace.ShrinkingLemma
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.TotallySeparated
import Mathlib.Topology.Metrizable.Basic
import Mathlib.Topology.Metrizable.ContinuousMap
import Mathlib.Topology.Metrizable.Uniformity
@@ -4633,6 +4951,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
@@ -4653,9 +4972,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
@@ -4663,11 +4984,13 @@ import Mathlib.Topology.Partial
import Mathlib.Topology.PartialHomeomorph
import Mathlib.Topology.PartitionOfUnity
import Mathlib.Topology.Perfect
+import Mathlib.Topology.PreorderRestrict
import Mathlib.Topology.QuasiSeparated
-import Mathlib.Topology.RestrictGenTopology
+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
@@ -4715,6 +5038,7 @@ import Mathlib.Topology.UniformSpace.Completion
import Mathlib.Topology.UniformSpace.Equicontinuity
import Mathlib.Topology.UniformSpace.Equiv
import Mathlib.Topology.UniformSpace.Matrix
+import Mathlib.Topology.UniformSpace.OfFun
import Mathlib.Topology.UniformSpace.Pi
import Mathlib.Topology.UniformSpace.Separation
import Mathlib.Topology.UniformSpace.UniformConvergence
diff --git a/Mathlib/Algebra/AddTorsor.lean b/Mathlib/Algebra/AddTorsor.lean
index c0ef691f61fae..d615b53f28671 100644
--- a/Mathlib/Algebra/AddTorsor.lean
+++ b/Mathlib/Algebra/AddTorsor.lean
@@ -3,7 +3,8 @@ Copyright (c) 2020 Joseph Myers. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Myers, Yury Kudryashov
-/
-import Mathlib.Data.Set.Pointwise.SMul
+import Mathlib.Algebra.Group.Action.Basic
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
/-!
# Torsors of additive group actions
@@ -53,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]
@@ -167,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]
@@ -247,7 +243,6 @@ instance instAddTorsor : AddTorsor (G × G') (P × P') where
zero_vadd _ := Prod.ext (zero_vadd _ _) (zero_vadd _ _)
add_vadd _ _ _ := Prod.ext (add_vadd _ _ _) (add_vadd _ _ _)
vsub p₁ p₂ := (p₁.1 -ᵥ p₂.1, p₁.2 -ᵥ p₂.2)
- nonempty := Prod.instNonempty
vsub_vadd' _ _ := Prod.ext (vsub_vadd _ _) (vsub_vadd _ _)
vadd_vsub' _ _ := Prod.ext (vadd_vsub _ _) (vadd_vsub _ _)
diff --git a/Mathlib/Algebra/Algebra/Basic.lean b/Mathlib/Algebra/Algebra/Basic.lean
index 27b7ad24b9d20..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
@@ -23,12 +24,12 @@ universe u v w u₁ v₁
namespace Algebra
-variable {R : Type u} {S : Type v} {A : Type w} {B : Type*}
+variable {R : Type u} {A : Type w}
section Semiring
-variable [CommSemiring R] [CommSemiring S]
-variable [Semiring A] [Algebra R A] [Semiring B] [Algebra R B]
+variable [CommSemiring R]
+variable [Semiring A] [Algebra R A]
section PUnit
@@ -185,8 +186,7 @@ theorem End_algebraMap_isUnit_inv_apply_eq_iff {x : R}
mpr := fun H =>
H.symm ▸ by
apply_fun ⇑h.unit.val using ((Module.End_isUnit_iff _).mp h).injective
- erw [End_isUnit_apply_inv_apply_of_isUnit]
- rfl }
+ simpa using End_isUnit_apply_inv_apply_of_isUnit h (x • m') }
theorem End_algebraMap_isUnit_inv_apply_eq_iff' {x : R}
(h : IsUnit (algebraMap R (Module.End S M) x)) (m m' : M) :
@@ -195,8 +195,7 @@ theorem End_algebraMap_isUnit_inv_apply_eq_iff' {x : R}
mpr := fun H =>
H.symm ▸ by
apply_fun (↑h.unit : M → M) using ((Module.End_isUnit_iff _).mp h).injective
- erw [End_isUnit_apply_inv_apply_of_isUnit]
- rfl }
+ simpa using End_isUnit_apply_inv_apply_of_isUnit h (x • m') |>.symm }
end
@@ -314,17 +313,6 @@ instance (priority := 100) CharZero.noZeroSMulDivisors_int [Ring R] [NoZeroDivis
[CharZero R] : NoZeroSMulDivisors ℤ R :=
NoZeroSMulDivisors.of_algebraMap_injective <| (algebraMap ℤ R).injective_int
-section Field
-
-variable [Field R] [Semiring A] [Algebra R A]
-
--- see note [lower instance priority]
-instance (priority := 100) Algebra.noZeroSMulDivisors [Nontrivial A] [NoZeroDivisors A] :
- NoZeroSMulDivisors R A :=
- NoZeroSMulDivisors.of_algebraMap_injective (algebraMap R A).injective
-
-end Field
-
end NoZeroSMulDivisors
section IsScalarTower
@@ -332,7 +320,6 @@ section IsScalarTower
variable {R : Type*} [CommSemiring R]
variable (A : Type*) [Semiring A] [Algebra R A]
variable {M : Type*} [AddCommMonoid M] [Module A M] [Module R M] [IsScalarTower R A M]
-variable {N : Type*} [AddCommMonoid N] [Module A N] [Module R N] [IsScalarTower R A N]
theorem algebra_compatible_smul (r : R) (m : M) : r • m = (algebraMap R A) r • m := by
rw [← one_smul A m, ← smul_assoc, Algebra.smul_def, mul_one, one_smul]
@@ -493,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))
@@ -522,3 +509,21 @@ lemma LinearEquiv.extendScalarsOfSurjective_symm (f : M ≃ₗ[R] N) :
(f.extendScalarsOfSurjective h).symm = f.symm.extendScalarsOfSurjective h := rfl
end surjective
+
+namespace algebraMap
+
+section CommSemiringCommSemiring
+
+variable {R A : Type*} [CommSemiring R] [CommSemiring A] [Algebra R A] {ι : Type*} {s : Finset ι}
+
+@[norm_cast]
+theorem coe_prod (a : ι → R) : (↑(∏ i ∈ s, a i : R) : A) = ∏ i ∈ s, (↑(a i) : A) :=
+ map_prod (algebraMap R A) a s
+
+@[norm_cast]
+theorem coe_sum (a : ι → R) : ↑(∑ i ∈ s, a i) = ∑ i ∈ s, (↑(a i) : A) :=
+ map_sum (algebraMap R A) a s
+
+end CommSemiringCommSemiring
+
+end algebraMap
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 10be082a45ea6..9683ddd51e176 100644
--- a/Mathlib/Algebra/Algebra/Defs.lean
+++ b/Mathlib/Algebra/Algebra/Defs.lean
@@ -3,7 +3,6 @@ Copyright (c) 2018 Kenny Lau. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kenny Lau, Yury Kudryashov
-/
-import Mathlib.Algebra.BigOperators.Group.Finset
import Mathlib.Algebra.Module.LinearMap.Defs
/-!
@@ -82,6 +81,7 @@ the second approach only when you need to weaken a condition on either `R` or `A
-/
assert_not_exists Field
+assert_not_exists Finset
assert_not_exists Module.End
universe u v w u₁ v₁
@@ -165,26 +165,6 @@ theorem coe_sub (a b : R) :
end CommRingRing
-section CommSemiringCommSemiring
-
-variable {R A : Type*} [CommSemiring R] [CommSemiring A] [Algebra R A]
-
--- direct to_additive fails because of some mix-up with polynomials
-@[norm_cast]
-theorem coe_prod {ι : Type*} {s : Finset ι} (a : ι → R) :
- (↑(∏ i ∈ s, a i : R) : A) = ∏ i ∈ s, (↑(a i) : A) :=
- map_prod (algebraMap R A) a s
-
--- to_additive fails for some reason
-@[norm_cast]
-theorem coe_sum {ι : Type*} {s : Finset ι} (a : ι → R) :
- ↑(∑ i ∈ s, a i) = ∑ i ∈ s, (↑(a i) : A) :=
- map_sum (algebraMap R A) a s
-
--- Porting note: removed attribute [to_additive] coe_prod; why should this be a `to_additive`?
-
-end CommSemiringCommSemiring
-
end algebraMap
/-- Creating an algebra from a morphism to the center of a semiring. -/
@@ -257,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 1336dd54b5ede..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]
@@ -86,6 +84,8 @@ variable [Algebra R A₁] [Algebra R A₂] [Algebra R A₃]
variable [Algebra R A₁'] [Algebra R A₂'] [Algebra R A₃']
variable (e : A₁ ≃ₐ[R] A₂)
+section coe
+
instance : EquivLike (A₁ ≃ₐ[R] A₂) A₁ A₂ where
coe f := f.toFun
inv f := f.invFun
@@ -106,22 +106,6 @@ instance : AlgEquivClass (A₁ ≃ₐ[R] A₂) R A₁ A₂ where
map_mul f := f.map_mul'
commutes f := f.commutes'
--- Porting note: the default simps projection was `e.toEquiv.toFun`, it should be `FunLike.coe`
-/-- See Note [custom simps projection] -/
-def Simps.apply (e : A₁ ≃ₐ[R] A₂) : A₁ → A₂ :=
- e
-
--- Porting note: the default simps projection was `e.toEquiv`, it should be `EquivLike.toEquiv`
-/-- See Note [custom simps projection] -/
-def Simps.toEquiv (e : A₁ ≃ₐ[R] A₂) : A₁ ≃ A₂ :=
- e
-
--- 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 :=
- rfl
-
@[ext]
theorem ext {f g : A₁ ≃ₐ[R] A₂} (h : ∀ a, f a = g a) : f = g :=
DFunLike.ext f g h
@@ -132,13 +116,6 @@ protected theorem congr_arg {f : A₁ ≃ₐ[R] A₂} {x x' : A₁} : x = x' →
protected theorem congr_fun {f g : A₁ ≃ₐ[R] A₂} (h : f = g) (x : A₁) : f x = g x :=
DFunLike.congr_fun h x
-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⟩
-
@[simp]
theorem coe_mk {toEquiv map_mul map_add commutes} :
⇑(⟨toEquiv, map_mul, map_add, commutes⟩ : A₁ ≃ₐ[R] A₂) = toEquiv :=
@@ -149,12 +126,23 @@ theorem mk_coe (e : A₁ ≃ₐ[R] A₂) (e' h₁ h₂ h₃ h₄ h₅) :
(⟨⟨e, e', h₁, h₂⟩, h₃, h₄, h₅⟩ : A₁ ≃ₐ[R] A₂) = e :=
ext fun _ => rfl
--- Porting note: `toFun_eq_coe` no longer needed in Lean4
-
@[simp]
theorem toEquiv_eq_coe : e.toEquiv = e :=
rfl
+@[simp]
+protected theorem coe_coe {F : Type*} [EquivLike F A₁ A₂] [AlgEquivClass F R A₁ A₂] (f : F) :
+ ⇑(f : A₁ ≃ₐ[R] A₂) = f :=
+ rfl
+
+theorem coe_fun_injective : @Function.Injective (A₁ ≃ₐ[R] A₂) (A₁ → A₂) fun e => (e : A₁ → A₂) :=
+ DFunLike.coe_injective
+
+instance hasCoeToRingEquiv : CoeOut (A₁ ≃ₐ[R] A₂) (A₁ ≃+* A₂) :=
+ ⟨AlgEquiv.toRingEquiv⟩
+
+-- Porting note: `toFun_eq_coe` no longer needed in Lean4
+
@[simp]
theorem toRingEquiv_eq_coe : e.toRingEquiv = e :=
rfl
@@ -173,41 +161,6 @@ theorem coe_ringEquiv' : (e.toRingEquiv : A₁ → A₂) = e :=
theorem coe_ringEquiv_injective : Function.Injective ((↑) : (A₁ ≃ₐ[R] A₂) → A₁ ≃+* A₂) :=
fun _ _ h => ext <| RingEquiv.congr_fun h
-@[deprecated map_add (since := "2024-06-20")]
-protected theorem map_add : ∀ x y, e (x + y) = e x + e y :=
- map_add e
-
-@[deprecated map_zero (since := "2024-06-20")]
-protected theorem map_zero : e 0 = 0 :=
- map_zero e
-
-@[deprecated map_mul (since := "2024-06-20")]
-protected theorem map_mul : ∀ x y, e (x * y) = e x * e y :=
- map_mul e
-
-@[deprecated map_one (since := "2024-06-20")]
-protected theorem map_one : e 1 = 1 :=
- map_one e
-
-@[simp]
-theorem commutes : ∀ r : R, e (algebraMap R A₁ r) = algebraMap R A₂ r :=
- e.commutes'
-
--- @[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 _ _ _
-
-@[deprecated map_sum (since := "2023-12-26")]
-protected theorem map_sum {ι : Type*} (f : ι → A₁) (s : Finset ι) :
- e (∑ x ∈ s, f x) = ∑ x ∈ s, e (f x) :=
- map_sum e f s
-
-@[deprecated map_finsupp_sum (since := "2024-06-20")]
-protected theorem map_finsupp_sum {α : Type*} [Zero α] {ι : Type*} (f : ι →₀ α) (g : ι → α → A₁) :
- e (f.sum g) = f.sum fun i b => e (g i b) :=
- map_finsupp_sum _ _ _
-
-- Porting note: Added [coe] attribute
/-- Interpret an algebra equivalence as an algebra homomorphism.
@@ -238,18 +191,64 @@ lemma toAlgHom_toRingHom : ((e : A₁ →ₐ[R] A₂) : A₁ →+* A₂) = e :=
theorem coe_ringHom_commutes : ((e : A₁ →ₐ[R] A₂) : A₁ →+* A₂) = ((e : A₁ ≃+* A₂) : A₁ →+* A₂) :=
rfl
+@[simp]
+theorem commutes : ∀ r : R, e (algebraMap R A₁ r) = algebraMap R A₂ r :=
+ e.commutes'
+
+end coe
+
+section map
+
+@[deprecated map_add (since := "2024-06-20")]
+protected theorem map_add : ∀ x y, e (x + y) = e x + e y :=
+ map_add e
+
+@[deprecated map_zero (since := "2024-06-20")]
+protected theorem map_zero : e 0 = 0 :=
+ map_zero e
+
+@[deprecated map_mul (since := "2024-06-20")]
+protected theorem map_mul : ∀ x y, e (x * y) = e x * e y :=
+ map_mul e
+
+@[deprecated map_one (since := "2024-06-20")]
+protected theorem map_one : e 1 = 1 :=
+ map_one e
+
+@[deprecated map_smul (since := "2024-06-20")]
+protected theorem map_smul (r : R) (x : A₁) : e (r • x) = r • e x :=
+ map_smul _ _ _
+
@[deprecated map_pow (since := "2024-06-20")]
protected theorem map_pow : ∀ (x : A₁) (n : ℕ), e (x ^ n) = e x ^ n :=
map_pow _
+@[deprecated map_sum (since := "2023-12-26")]
+protected theorem map_sum {ι : Type*} (f : ι → A₁) (s : Finset ι) :
+ e (∑ x ∈ s, f x) = ∑ x ∈ s, e (f x) :=
+ map_sum e f s
+
+@[deprecated map_finsupp_sum (since := "2024-06-20")]
+protected theorem map_finsupp_sum {α : Type*} [Zero α] {ι : Type*} (f : ι →₀ α) (g : ι → α → A₁) :
+ e (f.sum g) = f.sum fun i b => e (g i b) :=
+ map_finsupp_sum _ _ _
+
+end map
+
+section bijective
+
+protected theorem bijective : Function.Bijective e :=
+ EquivLike.bijective e
+
protected theorem injective : Function.Injective e :=
EquivLike.injective e
protected theorem surjective : Function.Surjective e :=
EquivLike.surjective e
-protected theorem bijective : Function.Bijective e :=
- EquivLike.bijective e
+end bijective
+
+section refl
/-- Algebra equivalences are reflexive. -/
@[refl]
@@ -267,6 +266,10 @@ theorem refl_toAlgHom : ↑(refl : A₁ ≃ₐ[R] A₁) = AlgHom.id R A₁ :=
theorem coe_refl : ⇑(refl : A₁ ≃ₐ[R] A₁) = id :=
rfl
+end refl
+
+section symm
+
/-- Algebra equivalences are symmetric. -/
@[symm]
def symm (e : A₁ ≃ₐ[R] A₂) : A₂ ≃ₐ[R] A₁ :=
@@ -277,19 +280,16 @@ def symm (e : A₁ ≃ₐ[R] A₂) : A₂ ≃ₐ[R] A₁ :=
change _ = e _
rw [e.commutes] }
-/-- See Note [custom simps projection] -/
-def Simps.symm_apply (e : A₁ ≃ₐ[R] A₂) : A₂ → A₁ :=
- e.symm
-
-initialize_simps_projections AlgEquiv (toFun → apply, invFun → symm_apply)
+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 :=
@@ -300,9 +300,6 @@ theorem coe_coe_symm_apply_coe_apply {F : Type*} [EquivLike F A₁ A₂] [AlgEqu
theorem symm_toEquiv_eq_symm {e : A₁ ≃ₐ[R] A₂} : (e : A₁ ≃ A₂).symm = e.symm :=
rfl
-theorem invFun_eq_symm {e : A₁ ≃ₐ[R] A₂} : e.invFun = e.symm :=
- rfl
-
@[simp]
theorem symm_symm (e : A₁ ≃ₐ[R] A₂) : e.symm.symm = e := rfl
@@ -338,12 +335,6 @@ theorem toRingEquiv_symm (f : A₁ ≃ₐ[R] A₁) : (f : A₁ ≃+* A₁).symm
theorem symm_toRingEquiv : (e.symm : A₂ ≃+* A₁) = (e : A₁ ≃+* A₂).symm :=
rfl
-/-- Algebra equivalences are transitive. -/
-@[trans]
-def trans (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) : A₁ ≃ₐ[R] A₃ :=
- { e₁.toRingEquiv.trans e₂.toRingEquiv with
- commutes' := fun r => show e₂.toFun (e₁.toFun _) = _ by rw [e₁.commutes', e₂.commutes'] }
-
@[simp]
theorem apply_symm_apply (e : A₁ ≃ₐ[R] A₂) : ∀ x, e (e.symm x) = x :=
e.toEquiv.apply_symm_apply
@@ -352,18 +343,11 @@ theorem apply_symm_apply (e : A₁ ≃ₐ[R] A₂) : ∀ x, e (e.symm x) = x :=
theorem symm_apply_apply (e : A₁ ≃ₐ[R] A₂) : ∀ x, e.symm (e x) = x :=
e.toEquiv.symm_apply_apply
-@[simp]
-theorem symm_trans_apply (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) (x : A₃) :
- (e₁.trans e₂).symm x = e₁.symm (e₂.symm x) :=
- rfl
-
-@[simp]
-theorem coe_trans (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) : ⇑(e₁.trans e₂) = e₂ ∘ e₁ :=
- rfl
+theorem symm_apply_eq (e : A₁ ≃ₐ[R] A₂) {x y} : e.symm x = y ↔ x = e y :=
+ e.toEquiv.symm_apply_eq
-@[simp]
-theorem trans_apply (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) (x : A₁) : (e₁.trans e₂) x = e₂ (e₁ x) :=
- rfl
+theorem eq_symm_apply (e : A₁ ≃ₐ[R] A₂) {x y} : y = e.symm x ↔ e y = x :=
+ e.toEquiv.eq_symm_apply
@[simp]
theorem comp_symm (e : A₁ ≃ₐ[R] A₂) : AlgHom.comp (e : A₁ →ₐ[R] A₂) ↑e.symm = AlgHom.id R A₂ := by
@@ -381,6 +365,51 @@ theorem leftInverse_symm (e : A₁ ≃ₐ[R] A₂) : Function.LeftInverse e.symm
theorem rightInverse_symm (e : A₁ ≃ₐ[R] A₂) : Function.RightInverse e.symm e :=
e.right_inv
+end symm
+
+section simps
+
+-- Porting note: the default simps projection was `e.toEquiv.toFun`, it should be `FunLike.coe`
+/-- See Note [custom simps projection] -/
+def Simps.apply (e : A₁ ≃ₐ[R] A₂) : A₁ → A₂ :=
+ e
+
+-- Porting note: the default simps projection was `e.toEquiv`, it should be `EquivLike.toEquiv`
+/-- See Note [custom simps projection] -/
+def Simps.toEquiv (e : A₁ ≃ₐ[R] A₂) : A₁ ≃ A₂ :=
+ e
+
+/-- See Note [custom simps projection] -/
+def Simps.symm_apply (e : A₁ ≃ₐ[R] A₂) : A₂ → A₁ :=
+ e.symm
+
+initialize_simps_projections AlgEquiv (toFun → apply, invFun → symm_apply)
+
+end simps
+
+section trans
+
+/-- Algebra equivalences are transitive. -/
+@[trans]
+def trans (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) : A₁ ≃ₐ[R] A₃ :=
+ { e₁.toRingEquiv.trans e₂.toRingEquiv with
+ commutes' := fun r => show e₂.toFun (e₁.toFun _) = _ by rw [e₁.commutes', e₂.commutes'] }
+
+@[simp]
+theorem coe_trans (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) : ⇑(e₁.trans e₂) = e₂ ∘ e₁ :=
+ rfl
+
+@[simp]
+theorem trans_apply (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) (x : A₁) : (e₁.trans e₂) x = e₂ (e₁ x) :=
+ rfl
+
+@[simp]
+theorem symm_trans_apply (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) (x : A₃) :
+ (e₁.trans e₂).symm x = e₁.symm (e₂.symm x) :=
+ rfl
+
+end trans
+
/-- If `A₁` is equivalent to `A₁'` and `A₂` is equivalent to `A₂'`, then the type of maps
`A₁ →ₐ[R] A₂` is equivalent to the type of maps `A₁' →ₐ[R] A₂'`. -/
@[simps apply]
@@ -591,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 ϕ
@@ -767,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 d15f9fc46298b..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 :=
@@ -421,11 +417,25 @@ def toNatAlgHom [Semiring R] [Semiring S] (f : R →+* S) : R →ₐ[ℕ] S :=
toFun := f
commutes' := fun n => by simp }
+@[simp]
+lemma toNatAlgHom_coe [Semiring R] [Semiring S] (f : R →+* S) :
+ ⇑f.toNatAlgHom = ⇑f := rfl
+
+lemma toNatAlgHom_apply [Semiring R] [Semiring S] (f : R →+* S) (x : R) :
+ f.toNatAlgHom x = f x := rfl
+
/-- Reinterpret a `RingHom` as a `ℤ`-algebra homomorphism. -/
-def toIntAlgHom [Ring R] [Ring S] [Algebra ℤ R] [Algebra ℤ S] (f : R →+* S) : R →ₐ[ℤ] S :=
+def toIntAlgHom [Ring R] [Ring S] (f : R →+* S) : R →ₐ[ℤ] S :=
{ f with commutes' := fun n => by simp }
-lemma toIntAlgHom_injective [Ring R] [Ring S] [Algebra ℤ R] [Algebra ℤ S] :
+@[simp]
+lemma toIntAlgHom_coe [Ring R] [Ring S] (f : R →+* S) :
+ ⇑f.toIntAlgHom = ⇑f := rfl
+
+lemma toIntAlgHom_apply [Ring R] [Ring S] (f : R →+* S) (x : R) :
+ f.toIntAlgHom x = f x := rfl
+
+lemma toIntAlgHom_injective [Ring R] [Ring S] :
Function.Injective (RingHom.toIntAlgHom : (R →+* S) → _) :=
fun _ _ e ↦ DFunLike.ext _ _ (fun x ↦ DFunLike.congr_fun e 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 ce534b664d2fa..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
@@ -726,6 +733,11 @@ theorem map_sup [IsScalarTower R B B] [SMulCommClass R B B]
((S ⊔ T).map f : NonUnitalSubalgebra R B) = S.map f ⊔ T.map f :=
(NonUnitalSubalgebra.gc_map_comap f).l_sup
+theorem map_inf [IsScalarTower R B B] [SMulCommClass R B B]
+ (f : F) (hf : Function.Injective f) (S T : NonUnitalSubalgebra R A) :
+ ((S ⊓ T).map f : NonUnitalSubalgebra R B) = S.map f ⊓ T.map f :=
+ SetLike.coe_injective (Set.image_inter hf)
+
@[simp, norm_cast]
theorem coe_inf (S T : NonUnitalSubalgebra R A) : (↑(S ⊓ T) : Set A) = (S : Set A) ∩ T :=
rfl
@@ -768,6 +780,13 @@ theorem coe_iInf {ι : Sort*} {S : ι → NonUnitalSubalgebra R A} :
theorem mem_iInf {ι : Sort*} {S : ι → NonUnitalSubalgebra R A} {x : A} :
(x ∈ ⨅ i, S i) ↔ ∀ i, x ∈ S i := by simp only [iInf, mem_sInf, Set.forall_mem_range]
+theorem map_iInf {ι : Sort*} [Nonempty ι]
+ [IsScalarTower R B B] [SMulCommClass R B B] (f : F)
+ (hf : Function.Injective f) (S : ι → NonUnitalSubalgebra R A) :
+ ((⨅ i, S i).map f : NonUnitalSubalgebra R B) = ⨅ i, (S i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ S)
+
@[simp]
theorem iInf_toSubmodule {ι : Sort*} (S : ι → NonUnitalSubalgebra R A) :
(⨅ i, S i).toSubmodule = ⨅ i, (S i).toSubmodule :=
diff --git a/Mathlib/Algebra/Algebra/Operations.lean b/Mathlib/Algebra/Algebra/Operations.lean
index 7b9e15a2ac242..a962fa9ac33d8 100644
--- a/Mathlib/Algebra/Algebra/Operations.lean
+++ b/Mathlib/Algebra/Algebra/Operations.lean
@@ -6,12 +6,12 @@ Authors: Kenny Lau
import Mathlib.Algebra.Algebra.Bilinear
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
-import Mathlib.Data.Finset.Pointwise.Basic
import Mathlib.Data.Set.Pointwise.BigOperators
import Mathlib.Data.Set.Semiring
import Mathlib.GroupTheory.GroupAction.SubMulAction.Pointwise
@@ -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]
@@ -364,7 +375,7 @@ theorem mul_smul_mul_eq_smul_mul_smul (x y : R) : (x * y) • (M * N) = (x • M
· rw [smul_add]
exact Submodule.add_mem _ hn hm
· rintro _ ⟨m, hm, rfl⟩ _ ⟨n, hn, rfl⟩
- erw [smul_mul_smul_comm x m y n]
+ simp_rw [DistribMulAction.toLinearMap_apply, smul_mul_smul_comm]
exact smul_mem_pointwise_smul _ _ _ (mul_mem_mul hm hn)
/-- Sub-R-modules of an R-algebra form an idempotent semiring. -/
@@ -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 e1b31d58f4dc6..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⟩
@@ -336,10 +339,11 @@ lemma zero_mem_spectrum_inr (R S : Type*) {A : Type*} [CommSemiring R]
lemma mem_spectrum_inr_of_not_isUnit {R A : Type*} [CommRing R]
[NonUnitalRing A] [Module R A] [IsScalarTower R A A] [SMulCommClass R A A]
(a : A) (r : R) (hr : ¬ IsUnit r) : r ∈ spectrum R (a : Unitization R A) :=
- fun h ↦ hr <| by simpa using h.map (fstHom 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/Spectrum.lean b/Mathlib/Algebra/Algebra/Spectrum.lean
index 2b7e28f8e2c29..65c69f706fb00 100644
--- a/Mathlib/Algebra/Algebra/Spectrum.lean
+++ b/Mathlib/Algebra/Algebra/Spectrum.lean
@@ -400,7 +400,7 @@ end CommSemiring
section CommRing
-variable {F R A B : Type*} [CommRing R] [Ring A] [Algebra R A] [Ring B] [Algebra R B]
+variable {F R A : Type*} [CommRing R] [Ring A] [Algebra R A]
variable [FunLike F A R] [AlgHomClass F R A R]
local notation "σ" => spectrum R
diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean
index 854c9922cd13d..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
@@ -678,6 +682,9 @@ theorem mul_mem_sup {S T : Subalgebra R A} {x y : A} (hx : x ∈ S) (hy : y ∈
theorem map_sup (f : A →ₐ[R] B) (S T : Subalgebra R A) : (S ⊔ T).map f = S.map f ⊔ T.map f :=
(Subalgebra.gc_map_comap f).l_sup
+theorem map_inf (f : A →ₐ[R] B) (hf : Function.Injective f) (S T : Subalgebra R A) :
+ (S ⊓ T).map f = S.map f ⊓ T.map f := SetLike.coe_injective (Set.image_inter hf)
+
@[simp, norm_cast]
theorem coe_inf (S T : Subalgebra R A) : (↑(S ⊓ T) : Set A) = (S ∩ T : Set A) := rfl
@@ -694,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
@@ -711,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]
@@ -718,17 +751,34 @@ theorem coe_iInf {ι : Sort*} {S : ι → Subalgebra R A} : (↑(⨅ i, S i) : S
theorem mem_iInf {ι : Sort*} {S : ι → Subalgebra R A} {x : A} : (x ∈ ⨅ i, S i) ↔ ∀ i, x ∈ S i := by
simp only [iInf, mem_sInf, Set.forall_mem_range]
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : A →ₐ[R] B) (hf : Function.Injective f)
+ (s : ι → Subalgebra R A) : (iInf s).map f = ⨅ (i : ι), (s i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ s)
+
open Subalgebra in
@[simp]
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
@@ -751,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/IsSimpleOrder.lean b/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean
index 468781008d3b8..2c9016caf3b6c 100644
--- a/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean
+++ b/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean
@@ -12,7 +12,7 @@ If `A` is a domain, and a finite-dimensional algebra over a field `F`, with prim
then there are no non-trivial `F`-subalgebras.
-/
-open FiniteDimensional Submodule
+open Module Submodule
theorem Subalgebra.isSimpleOrder_of_finrank_prime (F A) [Field F] [Ring A] [IsDomain A]
[Algebra F A] (hp : (finrank F A).Prime) : IsSimpleOrder (Subalgebra F A) :=
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/Subalgebra/Rank.lean b/Mathlib/Algebra/Algebra/Subalgebra/Rank.lean
index 1dac252bbf591..e4b3c91e4d894 100644
--- a/Mathlib/Algebra/Algebra/Subalgebra/Rank.lean
+++ b/Mathlib/Algebra/Algebra/Subalgebra/Rank.lean
@@ -18,7 +18,7 @@ satisfies strong rank condition, we put them into a separate file.
-/
-open FiniteDimensional
+open Module
namespace Subalgebra
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/Unitization.lean b/Mathlib/Algebra/Algebra/Unitization.lean
index 410c45a19b938..42a25ab336b19 100644
--- a/Mathlib/Algebra/Algebra/Unitization.lean
+++ b/Mathlib/Algebra/Algebra/Unitization.lean
@@ -751,6 +751,66 @@ theorem starLift_symm_apply_apply (φ : Unitization R A →⋆ₐ[R] C) (a : A)
end StarAlgHom
+section StarMap
+
+variable {R A B C : Type*} [CommSemiring R] [StarRing R]
+variable [NonUnitalSemiring A] [StarRing A] [Module R A] [SMulCommClass R A A] [IsScalarTower R A A]
+variable [NonUnitalSemiring B] [StarRing B] [Module R B] [SMulCommClass R B B] [IsScalarTower R B B]
+variable [NonUnitalSemiring C] [StarRing C] [Module R C] [SMulCommClass R C C] [IsScalarTower R C C]
+variable [StarModule R B] [StarModule R C]
+
+/-- The functorial map on morphisms between the category of non-unital C⋆-algebras with non-unital
+star homomorphisms and unital C⋆-algebras with unital star homomorphisms.
+
+This sends `φ : A →⋆ₙₐ[R] B` to a map `Unitization R A →⋆ₐ[R] Unitization R B` given by the formula
+`(r, a) ↦ (r, φ a)` (or perhaps more precisely,
+`algebraMap R _ r + ↑a ↦ algebraMap R _ r + ↑(φ a)`). -/
+@[simps!]
+def starMap (φ : A →⋆ₙₐ[R] B) : Unitization R A →⋆ₐ[R] Unitization R B :=
+ Unitization.starLift <| (Unitization.inrNonUnitalStarAlgHom R B).comp φ
+
+@[simp high]
+lemma starMap_inr (φ : A →⋆ₙₐ[R] B) (a : A) :
+ starMap φ (inr a) = inr (φ a) := by
+ simp
+
+@[simp high]
+lemma starMap_inl (φ : A →⋆ₙₐ[R] B) (r : R) :
+ starMap φ (inl r) = algebraMap R (Unitization R B) r := by
+ simp
+
+/-- If `φ : A →⋆ₙₐ[R] B` is injective, the lift `starMap φ : Unitization R A →⋆ₐ[R] Unitization R B`
+is also injective. -/
+lemma starMap_injective {φ : A →⋆ₙₐ[R] B} (hφ : Function.Injective φ) :
+ Function.Injective (starMap φ) := by
+ intro x y h
+ ext
+ · simpa using congr(fst $(h))
+ · exact hφ <| by simpa [algebraMap_eq_inl] using congr(snd $(h))
+
+/-- If `φ : A →⋆ₙₐ[R] B` is surjective, the lift
+`starMap φ : Unitization R A →⋆ₐ[R] Unitization R B` is also surjective. -/
+lemma starMap_surjective {φ : A →⋆ₙₐ[R] B} (hφ : Function.Surjective φ) :
+ Function.Surjective (starMap φ) := by
+ intro x
+ induction x using Unitization.ind with
+ | inl_add_inr r b =>
+ obtain ⟨a, rfl⟩ := hφ b
+ exact ⟨(r, a), by rfl⟩
+
+/-- `starMap` is functorial: `starMap (ψ.comp φ) = (starMap ψ).comp (starMap φ)`. -/
+lemma starMap_comp {φ : A →⋆ₙₐ[R] B} {ψ : B →⋆ₙₐ[R] C} :
+ starMap (ψ.comp φ) = (starMap ψ).comp (starMap φ) := by
+ ext; all_goals simp
+
+/-- `starMap` is functorial:
+`starMap (NonUnitalStarAlgHom.id R B) = StarAlgHom.id R (Unitization R B)`. -/
+@[simp]
+lemma starMap_id : starMap (NonUnitalStarAlgHom.id R B) = StarAlgHom.id R (Unitization R B) := by
+ ext; all_goals simp
+
+end StarMap
+
section StarNormal
variable {R A : Type*} [Semiring R]
diff --git a/Mathlib/Data/ZMod/Algebra.lean b/Mathlib/Algebra/Algebra/ZMod.lean
similarity index 97%
rename from Mathlib/Data/ZMod/Algebra.lean
rename to Mathlib/Algebra/Algebra/ZMod.lean
index 2f5737b396fd4..0d26ab239fe68 100644
--- a/Mathlib/Data/ZMod/Algebra.lean
+++ b/Mathlib/Algebra/Algebra/ZMod.lean
@@ -3,8 +3,8 @@ Copyright (c) 2021 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin
-/
-import Mathlib.Data.ZMod.Basic
import Mathlib.Algebra.Algebra.Defs
+import Mathlib.Data.ZMod.Basic
/-!
# The `ZMod n`-algebra structure on rings whose characteristic divides `n`
@@ -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/AlgebraicCard.lean b/Mathlib/Algebra/AlgebraicCard.lean
index 85eee288ffe90..f8be8db361367 100644
--- a/Mathlib/Algebra/AlgebraicCard.lean
+++ b/Mathlib/Algebra/AlgebraicCard.lean
@@ -10,10 +10,10 @@ import Mathlib.RingTheory.Algebraic
### Cardinality of algebraic numbers
In this file, we prove variants of the following result: the cardinality of algebraic numbers under
-an R-algebra is at most `# R[X] * ℵ₀`.
+an R-algebra is at most `#R[X] * ℵ₀`.
Although this can be used to prove that real or complex transcendental numbers exist, a more direct
-proof is given by `Liouville.is_transcendental`.
+proof is given by `Liouville.transcendental`.
-/
diff --git a/Mathlib/Algebra/Associated/Basic.lean b/Mathlib/Algebra/Associated/Basic.lean
index 70a806de2380a..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.
@@ -31,336 +24,12 @@ and prove basic properties of this quotient.
assert_not_exists OrderedCommMonoid
assert_not_exists Multiset
-variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*}
-
-section Prime
-
-variable [CommMonoidWithZero α]
-
-/-- 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 : α) : Prop :=
- p ≠ 0 ∧ ¬IsUnit p ∧ ∀ a b, p ∣ a * b → p ∣ a ∨ p ∣ b
-
-namespace Prime
-
-variable {p : α} (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 : α} (h : p ∣ a * b) : p ∣ a ∨ p ∣ b :=
- hp.2.2 a b h
-
-theorem dvd_mul {a b : α} : 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 : α} (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 : α} {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 : α} {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 : α) := fun h => h.ne_zero rfl
-
-@[simp]
-theorem not_prime_one : ¬Prime (1 : α) := fun h => h.not_unit isUnit_one
-
-section Map
-
-variable [CommMonoidWithZero β] {F : Type*} {G : Type*} [FunLike F α β]
-variable [MonoidWithZeroHomClass F α β] [FunLike G β α] [MulHomClass G β α]
-variable (f : F) (g : G) {p : α}
-
-theorem comap_prime (hinv : ∀ a, g (f a : β) = 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 : α ≃* β) : 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 α] {p : α} (hp : Prime p)
- {a b : α} : 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 α] {p a b : α} (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 α] {p a b : α} (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 α] {p a b : α}
- {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 {α : Type*} [CancelCommMonoidWithZero α] {p x y : α} (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 α] (p : α) : 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 α] {p : α} (hp : Irreducible p) : ¬p ∣ 1 :=
- mt (isUnit_of_dvd_one ·) hp.not_unit
-
-theorem isUnit_or_isUnit [Monoid α] {p : α} (hp : Irreducible p) {a b : α} (h : p = a * b) :
- IsUnit a ∨ IsUnit b :=
- hp.isUnit_or_isUnit' a b h
-
-end Irreducible
-
-theorem irreducible_iff [Monoid α] {p : α} :
- 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 α] : ¬Irreducible (1 : α) := by simp [irreducible_iff]
-
-theorem Irreducible.ne_one [Monoid α] : ∀ {p : α}, Irreducible p → p ≠ 1
- | _, hp, rfl => not_irreducible_one hp
-
-@[simp]
-theorem not_irreducible_zero [MonoidWithZero α] : ¬Irreducible (0 : α)
- | ⟨hn0, h⟩ =>
- have : IsUnit (0 : α) ∨ IsUnit (0 : α) := h 0 0 (mul_zero 0).symm
- this.elim hn0 hn0
-
-theorem Irreducible.ne_zero [MonoidWithZero α] : ∀ {p : α}, Irreducible p → p ≠ 0
- | _, hp, rfl => not_irreducible_zero hp
-
-theorem of_irreducible_mul {α} [Monoid α] {x y : α} : Irreducible (x * y) → IsUnit x ∨ IsUnit y
- | ⟨_, h⟩ => h _ _ rfl
-
-theorem not_irreducible_pow {α} [Monoid α] {x : α} {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 {α} [Monoid α] (x : α) (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 α] {p q : α} (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 α] {p q : α} (hp : Irreducible p) (hq : Irreducible q) :
- p ∣ q ↔ q ∣ p :=
- ⟨hp.dvd_symm hq, hq.dvd_symm hp⟩
-
-section
-
-variable [Monoid α]
-
-theorem irreducible_units_mul (a : αˣ) (b : α) : 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 : α} (h : IsUnit a) : Irreducible (a * b) ↔ Irreducible b :=
- let ⟨a, ha⟩ := h
- ha ▸ irreducible_units_mul a b
-
-theorem irreducible_mul_units (a : αˣ) (b : α) : 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 : α} (h : IsUnit a) : Irreducible (b * a) ↔ Irreducible b :=
- let ⟨a, ha⟩ := h
- ha ▸ irreducible_mul_units a b
-
-theorem irreducible_mul_iff {a b : α} :
- 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 α] {a : α}
-
-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 α]
-
-theorem Irreducible.prime_of_isPrimal {a : α}
- (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 α] {a : α} (irr : Irreducible a) : Prime a :=
- irr.prime_of_isPrimal (DecompositionMonoid.primal a)
-
-end CommMonoidWithZero
-
-section CancelCommMonoidWithZero
-
-variable [CancelCommMonoidWithZero α] {a p : α}
-
-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 α] {a : α} : Irreducible a ↔ Prime a :=
- ⟨Irreducible.prime, Prime.irreducible⟩
-
-theorem succ_dvd_or_succ_dvd_of_succ_sum_dvd_mul (hp : Prime p) {a b : α} {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
+variable {M N : Type*}
/-- Two elements of a `Monoid` are `Associated` if one of them is another one
multiplied by a unit on the right. -/
-def Associated [Monoid α] (x y : α) : Prop :=
- ∃ u : αˣ, x * u = y
+def Associated [Monoid M] (x y : M) : Prop :=
+ ∃ u : Mˣ, x * u = y
/-- Notation for two elements of a monoid are associated, i.e.
if one of them is another one multiplied by a unit on the right. -/
@@ -369,35 +38,35 @@ local infixl:50 " ~ᵤ " => Associated
namespace Associated
@[refl]
-protected theorem refl [Monoid α] (x : α) : x ~ᵤ x :=
+protected theorem refl [Monoid M] (x : M) : x ~ᵤ x :=
⟨1, by simp⟩
-protected theorem rfl [Monoid α] {x : α} : x ~ᵤ x :=
+protected theorem rfl [Monoid M] {x : M} : x ~ᵤ x :=
.refl x
-instance [Monoid α] : IsRefl α Associated :=
+instance [Monoid M] : IsRefl M Associated :=
⟨Associated.refl⟩
@[symm]
-protected theorem symm [Monoid α] : ∀ {x y : α}, x ~ᵤ y → y ~ᵤ x
+protected theorem symm [Monoid M] : ∀ {x y : M}, x ~ᵤ y → y ~ᵤ x
| x, _, ⟨u, rfl⟩ => ⟨u⁻¹, by rw [mul_assoc, Units.mul_inv, mul_one]⟩
-instance [Monoid α] : IsSymm α Associated :=
+instance [Monoid M] : IsSymm M Associated :=
⟨fun _ _ => Associated.symm⟩
-protected theorem comm [Monoid α] {x y : α} : x ~ᵤ y ↔ y ~ᵤ x :=
+protected theorem comm [Monoid M] {x y : M} : x ~ᵤ y ↔ y ~ᵤ x :=
⟨Associated.symm, Associated.symm⟩
@[trans]
-protected theorem trans [Monoid α] : ∀ {x y z : α}, x ~ᵤ y → y ~ᵤ z → x ~ᵤ z
+protected theorem trans [Monoid M] : ∀ {x y z : M}, x ~ᵤ y → y ~ᵤ z → x ~ᵤ z
| x, _, _, ⟨u, rfl⟩, ⟨v, rfl⟩ => ⟨u * v, by rw [Units.val_mul, mul_assoc]⟩
-instance [Monoid α] : IsTrans α Associated :=
+instance [Monoid M] : IsTrans M Associated :=
⟨fun _ _ _ => Associated.trans⟩
/-- The setoid of the relation `x ~ᵤ y` iff there is a unit `u` such that `x * u = y` -/
-protected def setoid (α : Type*) [Monoid α] :
- Setoid α where
+protected def setoid (M : Type*) [Monoid M] :
+ Setoid M where
r := Associated
iseqv := ⟨Associated.refl, Associated.symm, Associated.trans⟩
@@ -410,11 +79,11 @@ end Associated
attribute [local instance] Associated.setoid
-theorem unit_associated_one [Monoid α] {u : αˣ} : (u : α) ~ᵤ 1 :=
+theorem unit_associated_one [Monoid M] {u : Mˣ} : (u : M) ~ᵤ 1 :=
⟨u⁻¹, Units.mul_inv u⟩
@[simp]
-theorem associated_one_iff_isUnit [Monoid α] {a : α} : (a : α) ~ᵤ 1 ↔ IsUnit a :=
+theorem associated_one_iff_isUnit [Monoid M] {a : M} : (a : M) ~ᵤ 1 ↔ IsUnit a :=
Iff.intro
(fun h =>
let ⟨c, h⟩ := h.symm
@@ -422,98 +91,98 @@ theorem associated_one_iff_isUnit [Monoid α] {a : α} : (a : α) ~ᵤ 1 ↔ IsU
fun ⟨c, h⟩ => Associated.symm ⟨c, by simp [h]⟩
@[simp]
-theorem associated_zero_iff_eq_zero [MonoidWithZero α] (a : α) : a ~ᵤ 0 ↔ a = 0 :=
+theorem associated_zero_iff_eq_zero [MonoidWithZero M] (a : M) : a ~ᵤ 0 ↔ a = 0 :=
Iff.intro
(fun h => by
let ⟨u, h⟩ := h.symm
simpa using h.symm)
fun h => h ▸ Associated.refl a
-theorem associated_one_of_mul_eq_one [CommMonoid α] {a : α} (b : α) (hab : a * b = 1) : a ~ᵤ 1 :=
- show (Units.mkOfMulEqOne a b hab : α) ~ᵤ 1 from unit_associated_one
+theorem associated_one_of_mul_eq_one [CommMonoid M] {a : M} (b : M) (hab : a * b = 1) : a ~ᵤ 1 :=
+ show (Units.mkOfMulEqOne a b hab : M) ~ᵤ 1 from unit_associated_one
-theorem associated_one_of_associated_mul_one [CommMonoid α] {a b : α} : a * b ~ᵤ 1 → a ~ᵤ 1
+theorem associated_one_of_associated_mul_one [CommMonoid M] {a b : M} : a * b ~ᵤ 1 → a ~ᵤ 1
| ⟨u, h⟩ => associated_one_of_mul_eq_one (b * u) <| by simpa [mul_assoc] using h
-theorem associated_mul_unit_left {β : Type*} [Monoid β] (a u : β) (hu : IsUnit u) :
+theorem associated_mul_unit_left {N : Type*} [Monoid N] (a u : N) (hu : IsUnit u) :
Associated (a * u) a :=
let ⟨u', hu⟩ := hu
⟨u'⁻¹, hu ▸ Units.mul_inv_cancel_right _ _⟩
-theorem associated_unit_mul_left {β : Type*} [CommMonoid β] (a u : β) (hu : IsUnit u) :
+theorem associated_unit_mul_left {N : Type*} [CommMonoid N] (a u : N) (hu : IsUnit u) :
Associated (u * a) a := by
rw [mul_comm]
exact associated_mul_unit_left _ _ hu
-theorem associated_mul_unit_right {β : Type*} [Monoid β] (a u : β) (hu : IsUnit u) :
+theorem associated_mul_unit_right {N : Type*} [Monoid N] (a u : N) (hu : IsUnit u) :
Associated a (a * u) :=
(associated_mul_unit_left a u hu).symm
-theorem associated_unit_mul_right {β : Type*} [CommMonoid β] (a u : β) (hu : IsUnit u) :
+theorem associated_unit_mul_right {N : Type*} [CommMonoid N] (a u : N) (hu : IsUnit u) :
Associated a (u * a) :=
(associated_unit_mul_left a u hu).symm
-theorem associated_mul_isUnit_left_iff {β : Type*} [Monoid β] {a u b : β} (hu : IsUnit u) :
+theorem associated_mul_isUnit_left_iff {N : Type*} [Monoid N] {a u b : N} (hu : IsUnit u) :
Associated (a * u) b ↔ Associated a b :=
⟨(associated_mul_unit_right _ _ hu).trans, (associated_mul_unit_left _ _ hu).trans⟩
-theorem associated_isUnit_mul_left_iff {β : Type*} [CommMonoid β] {u a b : β} (hu : IsUnit u) :
+theorem associated_isUnit_mul_left_iff {N : Type*} [CommMonoid N] {u a b : N} (hu : IsUnit u) :
Associated (u * a) b ↔ Associated a b := by
rw [mul_comm]
exact associated_mul_isUnit_left_iff hu
-theorem associated_mul_isUnit_right_iff {β : Type*} [Monoid β] {a b u : β} (hu : IsUnit u) :
+theorem associated_mul_isUnit_right_iff {N : Type*} [Monoid N] {a b u : N} (hu : IsUnit u) :
Associated a (b * u) ↔ Associated a b :=
Associated.comm.trans <| (associated_mul_isUnit_left_iff hu).trans Associated.comm
-theorem associated_isUnit_mul_right_iff {β : Type*} [CommMonoid β] {a u b : β} (hu : IsUnit u) :
+theorem associated_isUnit_mul_right_iff {N : Type*} [CommMonoid N] {a u b : N} (hu : IsUnit u) :
Associated a (u * b) ↔ Associated a b :=
Associated.comm.trans <| (associated_isUnit_mul_left_iff hu).trans Associated.comm
@[simp]
-theorem associated_mul_unit_left_iff {β : Type*} [Monoid β] {a b : β} {u : Units β} :
+theorem associated_mul_unit_left_iff {N : Type*} [Monoid N] {a b : N} {u : Units N} :
Associated (a * u) b ↔ Associated a b :=
associated_mul_isUnit_left_iff u.isUnit
@[simp]
-theorem associated_unit_mul_left_iff {β : Type*} [CommMonoid β] {a b : β} {u : Units β} :
+theorem associated_unit_mul_left_iff {N : Type*} [CommMonoid N] {a b : N} {u : Units N} :
Associated (↑u * a) b ↔ Associated a b :=
associated_isUnit_mul_left_iff u.isUnit
@[simp]
-theorem associated_mul_unit_right_iff {β : Type*} [Monoid β] {a b : β} {u : Units β} :
+theorem associated_mul_unit_right_iff {N : Type*} [Monoid N] {a b : N} {u : Units N} :
Associated a (b * u) ↔ Associated a b :=
associated_mul_isUnit_right_iff u.isUnit
@[simp]
-theorem associated_unit_mul_right_iff {β : Type*} [CommMonoid β] {a b : β} {u : Units β} :
+theorem associated_unit_mul_right_iff {N : Type*} [CommMonoid N] {a b : N} {u : Units N} :
Associated a (↑u * b) ↔ Associated a b :=
associated_isUnit_mul_right_iff u.isUnit
-theorem Associated.mul_left [Monoid α] (a : α) {b c : α} (h : b ~ᵤ c) : a * b ~ᵤ a * c := by
+theorem Associated.mul_left [Monoid M] (a : M) {b c : M} (h : b ~ᵤ c) : a * b ~ᵤ a * c := by
obtain ⟨d, rfl⟩ := h; exact ⟨d, mul_assoc _ _ _⟩
-theorem Associated.mul_right [CommMonoid α] {a b : α} (h : a ~ᵤ b) (c : α) : a * c ~ᵤ b * c := by
+theorem Associated.mul_right [CommMonoid M] {a b : M} (h : a ~ᵤ b) (c : M) : a * c ~ᵤ b * c := by
obtain ⟨d, rfl⟩ := h; exact ⟨d, mul_right_comm _ _ _⟩
-theorem Associated.mul_mul [CommMonoid α] {a₁ a₂ b₁ b₂ : α}
+theorem Associated.mul_mul [CommMonoid M] {a₁ a₂ b₁ b₂ : M}
(h₁ : a₁ ~ᵤ b₁) (h₂ : a₂ ~ᵤ b₂) : a₁ * a₂ ~ᵤ b₁ * b₂ := (h₁.mul_right _).trans (h₂.mul_left _)
-theorem Associated.pow_pow [CommMonoid α] {a b : α} {n : ℕ} (h : a ~ᵤ b) : a ^ n ~ᵤ b ^ n := by
+theorem Associated.pow_pow [CommMonoid M] {a b : M} {n : ℕ} (h : a ~ᵤ b) : a ^ n ~ᵤ b ^ n := by
induction n with
| zero => simp [Associated.refl]
| succ n ih => convert h.mul_mul ih <;> rw [pow_succ']
-protected theorem Associated.dvd [Monoid α] {a b : α} : a ~ᵤ b → a ∣ b := fun ⟨u, hu⟩ =>
+protected theorem Associated.dvd [Monoid M] {a b : M} : a ~ᵤ b → a ∣ b := fun ⟨u, hu⟩ =>
⟨u, hu.symm⟩
-protected theorem Associated.dvd' [Monoid α] {a b : α} (h : a ~ᵤ b) : b ∣ a :=
+protected theorem Associated.dvd' [Monoid M] {a b : M} (h : a ~ᵤ b) : b ∣ a :=
h.symm.dvd
-protected theorem Associated.dvd_dvd [Monoid α] {a b : α} (h : a ~ᵤ b) : a ∣ b ∧ b ∣ a :=
+protected theorem Associated.dvd_dvd [Monoid M] {a b : M} (h : a ~ᵤ b) : a ∣ b ∧ b ∣ a :=
⟨h.dvd, h.symm.dvd⟩
-theorem associated_of_dvd_dvd [CancelMonoidWithZero α] {a b : α} (hab : a ∣ b) (hba : b ∣ a) :
+theorem associated_of_dvd_dvd [CancelMonoidWithZero M] {a b : M} (hab : a ∣ b) (hba : b ∣ a) :
a ~ᵤ b := by
rcases hab with ⟨c, rfl⟩
rcases hba with ⟨d, a_eq⟩
@@ -529,40 +198,40 @@ theorem associated_of_dvd_dvd [CancelMonoidWithZero α] {a b : α} (hab : a ∣
have hdc : d * c = 1 := mul_left_cancel₀ hac0 this
exact ⟨⟨c, d, hcd, hdc⟩, rfl⟩
-theorem dvd_dvd_iff_associated [CancelMonoidWithZero α] {a b : α} : a ∣ b ∧ b ∣ a ↔ a ~ᵤ b :=
+theorem dvd_dvd_iff_associated [CancelMonoidWithZero M] {a b : M} : a ∣ b ∧ b ∣ a ↔ a ~ᵤ b :=
⟨fun ⟨h1, h2⟩ => associated_of_dvd_dvd h1 h2, Associated.dvd_dvd⟩
-instance [CancelMonoidWithZero α] [DecidableRel ((· ∣ ·) : α → α → Prop)] :
- DecidableRel ((· ~ᵤ ·) : α → α → Prop) := fun _ _ => decidable_of_iff _ dvd_dvd_iff_associated
+instance [CancelMonoidWithZero M] [DecidableRel ((· ∣ ·) : M → M → Prop)] :
+ DecidableRel ((· ~ᵤ ·) : M → M → Prop) := fun _ _ => decidable_of_iff _ dvd_dvd_iff_associated
-theorem Associated.dvd_iff_dvd_left [Monoid α] {a b c : α} (h : a ~ᵤ b) : a ∣ c ↔ b ∣ c :=
+theorem Associated.dvd_iff_dvd_left [Monoid M] {a b c : M} (h : a ~ᵤ b) : a ∣ c ↔ b ∣ c :=
let ⟨_, hu⟩ := h
hu ▸ Units.mul_right_dvd.symm
-theorem Associated.dvd_iff_dvd_right [Monoid α] {a b c : α} (h : b ~ᵤ c) : a ∣ b ↔ a ∣ c :=
+theorem Associated.dvd_iff_dvd_right [Monoid M] {a b c : M} (h : b ~ᵤ c) : a ∣ b ↔ a ∣ c :=
let ⟨_, hu⟩ := h
hu ▸ Units.dvd_mul_right.symm
-theorem Associated.eq_zero_iff [MonoidWithZero α] {a b : α} (h : a ~ᵤ b) : a = 0 ↔ b = 0 := by
+theorem Associated.eq_zero_iff [MonoidWithZero M] {a b : M} (h : a ~ᵤ b) : a = 0 ↔ b = 0 := by
obtain ⟨u, rfl⟩ := h
rw [← Units.eq_mul_inv_iff_mul_eq, zero_mul]
-theorem Associated.ne_zero_iff [MonoidWithZero α] {a b : α} (h : a ~ᵤ b) : a ≠ 0 ↔ b ≠ 0 :=
+theorem Associated.ne_zero_iff [MonoidWithZero M] {a b : M} (h : a ~ᵤ b) : a ≠ 0 ↔ b ≠ 0 :=
not_congr h.eq_zero_iff
-theorem Associated.neg_left [Monoid α] [HasDistribNeg α] {a b : α} (h : Associated a b) :
+theorem Associated.neg_left [Monoid M] [HasDistribNeg M] {a b : M} (h : Associated a b) :
Associated (-a) b :=
let ⟨u, hu⟩ := h; ⟨-u, by simp [hu]⟩
-theorem Associated.neg_right [Monoid α] [HasDistribNeg α] {a b : α} (h : Associated a b) :
+theorem Associated.neg_right [Monoid M] [HasDistribNeg M] {a b : M} (h : Associated a b) :
Associated a (-b) :=
h.symm.neg_left.symm
-theorem Associated.neg_neg [Monoid α] [HasDistribNeg α] {a b : α} (h : Associated a b) :
+theorem Associated.neg_neg [Monoid M] [HasDistribNeg M] {a b : M} (h : Associated a b) :
Associated (-a) (-b) :=
h.neg_left.neg_right
-protected theorem Associated.prime [CommMonoidWithZero α] {p q : α} (h : p ~ᵤ q) (hp : Prime p) :
+protected theorem Associated.prime [CommMonoidWithZero M] {p q : M} (h : p ~ᵤ q) (hp : Prime p) :
Prime q :=
⟨h.ne_zero_iff.1 hp.ne_zero,
let ⟨u, hu⟩ := h
@@ -572,7 +241,7 @@ protected theorem Associated.prime [CommMonoidWithZero α] {p q : α} (h : p ~
intro a b
exact hp.dvd_or_dvd⟩⟩
-theorem prime_mul_iff [CancelCommMonoidWithZero α] {x y : α} :
+theorem prime_mul_iff [CancelCommMonoidWithZero M] {x y : M} :
Prime (x * y) ↔ (Prime x ∧ IsUnit y) ∨ (IsUnit x ∧ Prime y) := by
refine ⟨fun h ↦ ?_, ?_⟩
· rcases of_irreducible_mul h.irreducible with hx | hy
@@ -583,7 +252,7 @@ theorem prime_mul_iff [CancelCommMonoidWithZero α] {x y : α} :
· exact (associated_unit_mul_right y x hx).prime hy
@[simp]
-lemma prime_pow_iff [CancelCommMonoidWithZero α] {p : α} {n : ℕ} :
+lemma prime_pow_iff [CancelCommMonoidWithZero M] {p : M} {n : ℕ} :
Prime (p ^ n) ↔ Prime p ∧ n = 1 := by
refine ⟨fun hp ↦ ?_, fun ⟨hp, hn⟩ ↦ by simpa [hn]⟩
suffices n = 1 by aesop
@@ -598,7 +267,7 @@ lemma prime_pow_iff [CancelCommMonoidWithZero α] {p : α} {n : ℕ} :
· exfalso
exact hpn.not_unit (hp.pow n)
-theorem Irreducible.dvd_iff [Monoid α] {x y : α} (hx : Irreducible x) :
+theorem Irreducible.dvd_iff [Monoid M] {x y : M} (hx : Irreducible x) :
y ∣ x ↔ IsUnit y ∨ Associated x y := by
constructor
· rintro ⟨z, hz⟩
@@ -610,67 +279,67 @@ theorem Irreducible.dvd_iff [Monoid α] {x y : α} (hx : Irreducible x) :
· exact hy.dvd
· exact h.symm.dvd
-theorem Irreducible.associated_of_dvd [Monoid α] {p q : α} (p_irr : Irreducible p)
+theorem Irreducible.associated_of_dvd [Monoid M] {p q : M} (p_irr : Irreducible p)
(q_irr : Irreducible q) (dvd : p ∣ q) : Associated p q :=
((q_irr.dvd_iff.mp dvd).resolve_left p_irr.not_unit).symm
-theorem Irreducible.dvd_irreducible_iff_associated [Monoid α] {p q : α}
+theorem Irreducible.dvd_irreducible_iff_associated [Monoid M] {p q : M}
(pp : Irreducible p) (qp : Irreducible q) : p ∣ q ↔ Associated p q :=
⟨Irreducible.associated_of_dvd pp qp, Associated.dvd⟩
-theorem Prime.associated_of_dvd [CancelCommMonoidWithZero α] {p q : α} (p_prime : Prime p)
+theorem Prime.associated_of_dvd [CancelCommMonoidWithZero M] {p q : M} (p_prime : Prime p)
(q_prime : Prime q) (dvd : p ∣ q) : Associated p q :=
p_prime.irreducible.associated_of_dvd q_prime.irreducible dvd
-theorem Prime.dvd_prime_iff_associated [CancelCommMonoidWithZero α] {p q : α} (pp : Prime p)
+theorem Prime.dvd_prime_iff_associated [CancelCommMonoidWithZero M] {p q : M} (pp : Prime p)
(qp : Prime q) : p ∣ q ↔ Associated p q :=
pp.irreducible.dvd_irreducible_iff_associated qp.irreducible
-theorem Associated.prime_iff [CommMonoidWithZero α] {p q : α} (h : p ~ᵤ q) : Prime p ↔ Prime q :=
+theorem Associated.prime_iff [CommMonoidWithZero M] {p q : M} (h : p ~ᵤ q) : Prime p ↔ Prime q :=
⟨h.prime, h.symm.prime⟩
-protected theorem Associated.isUnit [Monoid α] {a b : α} (h : a ~ᵤ b) : IsUnit a → IsUnit b :=
+protected theorem Associated.isUnit [Monoid M] {a b : M} (h : a ~ᵤ b) : IsUnit a → IsUnit b :=
let ⟨u, hu⟩ := h
fun ⟨v, hv⟩ => ⟨v * u, by simp [hv, hu.symm]⟩
-theorem Associated.isUnit_iff [Monoid α] {a b : α} (h : a ~ᵤ b) : IsUnit a ↔ IsUnit b :=
+theorem Associated.isUnit_iff [Monoid M] {a b : M} (h : a ~ᵤ b) : IsUnit a ↔ IsUnit b :=
⟨h.isUnit, h.symm.isUnit⟩
-theorem Irreducible.isUnit_iff_not_associated_of_dvd [Monoid α]
- {x y : α} (hx : Irreducible x) (hy : y ∣ x) : IsUnit y ↔ ¬ Associated x y :=
+theorem Irreducible.isUnit_iff_not_associated_of_dvd [Monoid M]
+ {x y : M} (hx : Irreducible x) (hy : y ∣ x) : IsUnit y ↔ ¬ Associated x y :=
⟨fun hy hxy => hx.1 (hxy.symm.isUnit hy), (hx.dvd_iff.mp hy).resolve_right⟩
-protected theorem Associated.irreducible [Monoid α] {p q : α} (h : p ~ᵤ q) (hp : Irreducible p) :
+protected theorem Associated.irreducible [Monoid M] {p q : M} (h : p ~ᵤ q) (hp : Irreducible p) :
Irreducible q :=
⟨mt h.symm.isUnit hp.1,
let ⟨u, hu⟩ := h
fun a b hab =>
- have hpab : p = a * (b * (u⁻¹ : αˣ)) :=
+ have hpab : p = a * (b * (u⁻¹ : Mˣ)) :=
calc
- p = p * u * (u⁻¹ : αˣ) := by simp
+ p = p * u * (u⁻¹ : Mˣ) := by simp
_ = _ := by rw [hu]; simp [hab, mul_assoc]
(hp.isUnit_or_isUnit hpab).elim Or.inl fun ⟨v, hv⟩ => Or.inr ⟨v * u, by simp [hv]⟩⟩
-protected theorem Associated.irreducible_iff [Monoid α] {p q : α} (h : p ~ᵤ q) :
+protected theorem Associated.irreducible_iff [Monoid M] {p q : M} (h : p ~ᵤ q) :
Irreducible p ↔ Irreducible q :=
⟨h.irreducible, h.symm.irreducible⟩
-theorem Associated.of_mul_left [CancelCommMonoidWithZero α] {a b c d : α} (h : a * b ~ᵤ c * d)
+theorem Associated.of_mul_left [CancelCommMonoidWithZero M] {a b c d : M} (h : a * b ~ᵤ c * d)
(h₁ : a ~ᵤ c) (ha : a ≠ 0) : b ~ᵤ d :=
let ⟨u, hu⟩ := h
let ⟨v, hv⟩ := Associated.symm h₁
- ⟨u * (v : αˣ),
+ ⟨u * (v : Mˣ),
mul_left_cancel₀ ha
(by
- rw [← hv, mul_assoc c (v : α) d, mul_left_comm c, ← hu]
+ rw [← hv, mul_assoc c (v : M) d, mul_left_comm c, ← hu]
simp [hv.symm, mul_assoc, mul_comm, mul_left_comm])⟩
-theorem Associated.of_mul_right [CancelCommMonoidWithZero α] {a b c d : α} :
+theorem Associated.of_mul_right [CancelCommMonoidWithZero M] {a b c d : M} :
a * b ~ᵤ c * d → b ~ᵤ d → b ≠ 0 → a ~ᵤ c := by
rw [mul_comm a, mul_comm c]; exact Associated.of_mul_left
-theorem Associated.of_pow_associated_of_prime [CancelCommMonoidWithZero α] {p₁ p₂ : α} {k₁ k₂ : ℕ}
+theorem Associated.of_pow_associated_of_prime [CancelCommMonoidWithZero M] {p₁ p₂ : M} {k₁ k₂ : ℕ}
(hp₁ : Prime p₁) (hp₂ : Prime p₂) (hk₁ : 0 < k₁) (h : p₁ ^ k₁ ~ᵤ p₂ ^ k₂) : p₁ ~ᵤ p₂ := by
have : p₁ ∣ p₂ ^ k₂ := by
rw [← h.dvd_iff_dvd_right]
@@ -678,37 +347,37 @@ theorem Associated.of_pow_associated_of_prime [CancelCommMonoidWithZero α] {p
rw [← hp₁.dvd_prime_iff_associated hp₂]
exact hp₁.dvd_of_dvd_pow this
-theorem Associated.of_pow_associated_of_prime' [CancelCommMonoidWithZero α] {p₁ p₂ : α} {k₁ k₂ : ℕ}
+theorem Associated.of_pow_associated_of_prime' [CancelCommMonoidWithZero M] {p₁ p₂ : M} {k₁ k₂ : ℕ}
(hp₁ : Prime p₁) (hp₂ : Prime p₂) (hk₂ : 0 < k₂) (h : p₁ ^ k₁ ~ᵤ p₂ ^ k₂) : p₁ ~ᵤ p₂ :=
(h.symm.of_pow_associated_of_prime hp₂ hp₁ hk₂).symm
/-- See also `Irreducible.coprime_iff_not_dvd`. -/
-lemma Irreducible.isRelPrime_iff_not_dvd [Monoid α] {p n : α} (hp : Irreducible p) :
+lemma Irreducible.isRelPrime_iff_not_dvd [Monoid M] {p n : M} (hp : Irreducible p) :
IsRelPrime p n ↔ ¬ p ∣ n := by
refine ⟨fun h contra ↦ hp.not_unit (h dvd_rfl contra), fun hpn d hdp hdn ↦ ?_⟩
contrapose! hpn
suffices Associated p d from this.dvd.trans hdn
exact (hp.dvd_iff.mp hdp).resolve_left hpn
-lemma Irreducible.dvd_or_isRelPrime [Monoid α] {p n : α} (hp : Irreducible p) :
+lemma Irreducible.dvd_or_isRelPrime [Monoid M] {p n : M} (hp : Irreducible p) :
p ∣ n ∨ IsRelPrime p n := Classical.or_iff_not_imp_left.mpr hp.isRelPrime_iff_not_dvd.2
section UniqueUnits
-variable [Monoid α] [Unique αˣ]
+variable [Monoid M] [Subsingleton Mˣ]
-theorem associated_iff_eq {x y : α} : x ~ᵤ y ↔ x = y := by
+theorem associated_iff_eq {x y : M} : x ~ᵤ y ↔ x = y := by
constructor
· rintro ⟨c, rfl⟩
rw [units_eq_one c, Units.val_one, mul_one]
· rintro rfl
rfl
-theorem associated_eq_eq : (Associated : α → α → Prop) = Eq := by
+theorem associated_eq_eq : (Associated : M → M → Prop) = Eq := by
ext
rw [associated_iff_eq]
-theorem prime_dvd_prime_iff_eq {M : Type*} [CancelCommMonoidWithZero M] [Unique Mˣ] {p q : M}
+theorem prime_dvd_prime_iff_eq {M : Type*} [CancelCommMonoidWithZero M] [Subsingleton Mˣ] {p q : M}
(pp : Prime p) (qp : Prime q) : p ∣ q ↔ p = q := by
rw [pp.dvd_prime_iff_associated qp, ← associated_eq_eq]
@@ -716,7 +385,7 @@ end UniqueUnits
section UniqueUnits₀
-variable {R : Type*} [CancelCommMonoidWithZero R] [Unique Rˣ] {p₁ p₂ : R} {k₁ k₂ : ℕ}
+variable {R : Type*} [CancelCommMonoidWithZero R] [Subsingleton Rˣ] {p₁ p₂ : R} {k₁ k₂ : ℕ}
theorem eq_of_prime_pow_eq (hp₁ : Prime p₁) (hp₂ : Prime p₂) (hk₁ : 0 < k₁)
(h : p₁ ^ k₁ = p₂ ^ k₂) : p₁ = p₂ := by
@@ -732,86 +401,86 @@ end UniqueUnits₀
/-- The quotient of a monoid by the `Associated` relation. Two elements `x` and `y`
are associated iff there is a unit `u` such that `x * u = y`. There is a natural
- monoid structure on `Associates α`. -/
-abbrev Associates (α : Type*) [Monoid α] : Type _ :=
- Quotient (Associated.setoid α)
+ monoid structure on `Associates M`. -/
+abbrev Associates (M : Type*) [Monoid M] : Type _ :=
+ Quotient (Associated.setoid M)
namespace Associates
open Associated
-/-- The canonical quotient map from a monoid `α` into the `Associates` of `α` -/
-protected abbrev mk {α : Type*} [Monoid α] (a : α) : Associates α :=
+/-- The canonical quotient map from a monoid `M` into the `Associates` of `M` -/
+protected abbrev mk {M : Type*} [Monoid M] (a : M) : Associates M :=
⟦a⟧
-instance [Monoid α] : Inhabited (Associates α) :=
+instance [Monoid M] : Inhabited (Associates M) :=
⟨⟦1⟧⟩
-theorem mk_eq_mk_iff_associated [Monoid α] {a b : α} : Associates.mk a = Associates.mk b ↔ a ~ᵤ b :=
+theorem mk_eq_mk_iff_associated [Monoid M] {a b : M} : Associates.mk a = Associates.mk b ↔ a ~ᵤ b :=
Iff.intro Quotient.exact Quot.sound
-theorem quotient_mk_eq_mk [Monoid α] (a : α) : ⟦a⟧ = Associates.mk a :=
+theorem quotient_mk_eq_mk [Monoid M] (a : M) : ⟦a⟧ = Associates.mk a :=
rfl
-theorem quot_mk_eq_mk [Monoid α] (a : α) : Quot.mk Setoid.r a = Associates.mk a :=
+theorem quot_mk_eq_mk [Monoid M] (a : M) : Quot.mk Setoid.r a = Associates.mk a :=
rfl
@[simp]
-theorem quot_out [Monoid α] (a : Associates α) : Associates.mk (Quot.out a) = a := by
+theorem quot_out [Monoid M] (a : Associates M) : Associates.mk (Quot.out a) = a := by
rw [← quot_mk_eq_mk, Quot.out_eq]
-theorem mk_quot_out [Monoid α] (a : α) : Quot.out (Associates.mk a) ~ᵤ a := by
+theorem mk_quot_out [Monoid M] (a : M) : Quot.out (Associates.mk a) ~ᵤ a := by
rw [← Associates.mk_eq_mk_iff_associated, Associates.quot_out]
-theorem forall_associated [Monoid α] {p : Associates α → Prop} :
+theorem forall_associated [Monoid M] {p : Associates M → Prop} :
(∀ a, p a) ↔ ∀ a, p (Associates.mk a) :=
Iff.intro (fun h _ => h _) fun h a => Quotient.inductionOn a h
-theorem mk_surjective [Monoid α] : Function.Surjective (@Associates.mk α _) :=
+theorem mk_surjective [Monoid M] : Function.Surjective (@Associates.mk M _) :=
forall_associated.2 fun a => ⟨a, rfl⟩
-instance [Monoid α] : One (Associates α) :=
+instance [Monoid M] : One (Associates M) :=
⟨⟦1⟧⟩
@[simp]
-theorem mk_one [Monoid α] : Associates.mk (1 : α) = 1 :=
+theorem mk_one [Monoid M] : Associates.mk (1 : M) = 1 :=
rfl
-theorem one_eq_mk_one [Monoid α] : (1 : Associates α) = Associates.mk 1 :=
+theorem one_eq_mk_one [Monoid M] : (1 : Associates M) = Associates.mk 1 :=
rfl
@[simp]
-theorem mk_eq_one [Monoid α] {a : α} : Associates.mk a = 1 ↔ IsUnit a := by
+theorem mk_eq_one [Monoid M] {a : M} : Associates.mk a = 1 ↔ IsUnit a := by
rw [← mk_one, mk_eq_mk_iff_associated, associated_one_iff_isUnit]
-instance [Monoid α] : Bot (Associates α) :=
+instance [Monoid M] : Bot (Associates M) :=
⟨1⟩
-theorem bot_eq_one [Monoid α] : (⊥ : Associates α) = 1 :=
+theorem bot_eq_one [Monoid M] : (⊥ : Associates M) = 1 :=
rfl
-theorem exists_rep [Monoid α] (a : Associates α) : ∃ a0 : α, Associates.mk a0 = a :=
+theorem exists_rep [Monoid M] (a : Associates M) : ∃ a0 : M, Associates.mk a0 = a :=
Quot.exists_rep a
-instance [Monoid α] [Subsingleton α] :
- Unique (Associates α) where
+instance [Monoid M] [Subsingleton M] :
+ Unique (Associates M) where
default := 1
uniq := forall_associated.2 fun _ ↦ mk_eq_one.2 <| isUnit_of_subsingleton _
-theorem mk_injective [Monoid α] [Unique (Units α)] : Function.Injective (@Associates.mk α _) :=
+theorem mk_injective [Monoid M] [Subsingleton Mˣ] : Function.Injective (@Associates.mk M _) :=
fun _ _ h => associated_iff_eq.mp (Associates.mk_eq_mk_iff_associated.mp h)
section CommMonoid
-variable [CommMonoid α]
+variable [CommMonoid M]
-instance instMul : Mul (Associates α) :=
+instance instMul : Mul (Associates M) :=
⟨Quotient.map₂ (· * ·) fun _ _ h₁ _ _ h₂ ↦ h₁.mul_mul h₂⟩
-theorem mk_mul_mk {x y : α} : Associates.mk x * Associates.mk y = Associates.mk (x * y) :=
+theorem mk_mul_mk {x y : M} : Associates.mk x * Associates.mk y = Associates.mk (x * y) :=
rfl
-instance instCommMonoid : CommMonoid (Associates α) where
+instance instCommMonoid : CommMonoid (Associates M) where
one := 1
mul := (· * ·)
mul_one a' := Quotient.inductionOn a' fun a => show ⟦a * 1⟧ = ⟦a⟧ by simp
@@ -822,32 +491,32 @@ instance instCommMonoid : CommMonoid (Associates α) where
mul_comm a' b' :=
Quotient.inductionOn₂ a' b' fun a b => show ⟦a * b⟧ = ⟦b * a⟧ by rw [mul_comm]
-instance instPreorder : Preorder (Associates α) 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 : α →* Associates α where
+protected def mkMonoidHom : M →* Associates M where
toFun := Associates.mk
map_one' := mk_one
map_mul' _ _ := mk_mul_mk
@[simp]
-theorem mkMonoidHom_apply (a : α) : Associates.mkMonoidHom a = Associates.mk a :=
+theorem mkMonoidHom_apply (a : M) : Associates.mkMonoidHom a = Associates.mk a :=
rfl
-theorem associated_map_mk {f : Associates α →* α} (hinv : Function.RightInverse f Associates.mk)
- (a : α) : a ~ᵤ f (Associates.mk a) :=
+theorem associated_map_mk {f : Associates M →* M} (hinv : Function.RightInverse f Associates.mk)
+ (a : M) : a ~ᵤ f (Associates.mk a) :=
Associates.mk_eq_mk_iff_associated.1 (hinv (Associates.mk a)).symm
-theorem mk_pow (a : α) (n : ℕ) : Associates.mk (a ^ n) = Associates.mk a ^ n := by
+theorem mk_pow (a : M) (n : ℕ) : Associates.mk (a ^ n) = Associates.mk a ^ n := by
induction n <;> simp [*, pow_succ, Associates.mk_mul_mk.symm]
-theorem dvd_eq_le : ((· ∣ ·) : Associates α → Associates α → Prop) = (· ≤ ·) :=
+theorem dvd_eq_le : ((· ∣ ·) : Associates M → Associates M → Prop) = (· ≤ ·) :=
rfl
-instance uniqueUnits : Unique (Associates α)ˣ where
+instance uniqueUnits : Unique (Associates M)ˣ where
uniq := by
rintro ⟨a, b, hab, hba⟩
revert hab hba
@@ -858,16 +527,16 @@ instance uniqueUnits : Unique (Associates α)ˣ where
@[deprecated (since := "2024-07-22")] protected alias units_eq_one := Subsingleton.elim
@[simp]
-theorem coe_unit_eq_one (u : (Associates α)ˣ) : (u : Associates α) = 1 := by
+theorem coe_unit_eq_one (u : (Associates M)ˣ) : (u : Associates M) = 1 := by
simp [eq_iff_true_of_subsingleton]
-theorem isUnit_iff_eq_one (a : Associates α) : IsUnit a ↔ a = 1 :=
+theorem isUnit_iff_eq_one (a : Associates M) : IsUnit a ↔ a = 1 :=
Iff.intro (fun ⟨_, h⟩ => h ▸ coe_unit_eq_one _) fun h => h.symm ▸ isUnit_one
-theorem isUnit_iff_eq_bot {a : Associates α} : IsUnit a ↔ a = ⊥ := by
+theorem isUnit_iff_eq_bot {a : Associates M} : IsUnit a ↔ a = ⊥ := by
rw [Associates.isUnit_iff_eq_one, bot_eq_one]
-theorem isUnit_mk {a : α} : IsUnit (Associates.mk a) ↔ IsUnit a :=
+theorem isUnit_mk {a : M} : IsUnit (Associates.mk a) ↔ IsUnit a :=
calc
IsUnit (Associates.mk a) ↔ a ~ᵤ 1 := by
rw [isUnit_iff_eq_one, one_eq_mk_one, mk_eq_mk_iff_associated]
@@ -875,27 +544,27 @@ theorem isUnit_mk {a : α} : IsUnit (Associates.mk a) ↔ IsUnit a :=
section Order
-theorem mul_mono {a b c d : Associates α} (h₁ : a ≤ b) (h₂ : c ≤ d) : a * c ≤ b * d :=
+theorem mul_mono {a b c d : Associates M} (h₁ : a ≤ b) (h₂ : c ≤ d) : a * c ≤ b * d :=
let ⟨x, hx⟩ := h₁
let ⟨y, hy⟩ := h₂
⟨x * y, by simp [hx, hy, mul_comm, mul_assoc, mul_left_comm]⟩
-theorem one_le {a : Associates α} : 1 ≤ a :=
+theorem one_le {a : Associates M} : 1 ≤ a :=
Dvd.intro _ (one_mul a)
-theorem le_mul_right {a b : Associates α} : a ≤ a * b :=
+theorem le_mul_right {a b : Associates M} : a ≤ a * b :=
⟨b, rfl⟩
-theorem le_mul_left {a b : Associates α} : a ≤ b * a := by rw [mul_comm]; exact le_mul_right
+theorem le_mul_left {a b : Associates M} : a ≤ b * a := by rw [mul_comm]; exact le_mul_right
-instance instOrderBot : OrderBot (Associates α) where
+instance instOrderBot : OrderBot (Associates M) where
bot := 1
bot_le _ := one_le
end Order
@[simp]
-theorem mk_dvd_mk {a b : α} : Associates.mk a ∣ Associates.mk b ↔ a ∣ b := by
+theorem mk_dvd_mk {a b : M} : Associates.mk a ∣ Associates.mk b ↔ a ∣ b := by
simp only [dvd_def, mk_surjective.exists, mk_mul_mk, mk_eq_mk_iff_associated,
Associated.comm (x := b)]
constructor
@@ -904,18 +573,18 @@ theorem mk_dvd_mk {a b : α} : Associates.mk a ∣ Associates.mk b ↔ a ∣ b :
· rintro ⟨c, rfl⟩
use c
-theorem dvd_of_mk_le_mk {a b : α} : Associates.mk a ≤ Associates.mk b → a ∣ b :=
+theorem dvd_of_mk_le_mk {a b : M} : Associates.mk a ≤ Associates.mk b → a ∣ b :=
mk_dvd_mk.mp
-theorem mk_le_mk_of_dvd {a b : α} : a ∣ b → Associates.mk a ≤ Associates.mk b :=
+theorem mk_le_mk_of_dvd {a b : M} : a ∣ b → Associates.mk a ≤ Associates.mk b :=
mk_dvd_mk.mpr
-theorem mk_le_mk_iff_dvd {a b : α} : Associates.mk a ≤ Associates.mk b ↔ a ∣ b := mk_dvd_mk
+theorem mk_le_mk_iff_dvd {a b : M} : Associates.mk a ≤ Associates.mk b ↔ a ∣ b := mk_dvd_mk
@[deprecated (since := "2024-03-16")] alias mk_le_mk_iff_dvd_iff := mk_le_mk_iff_dvd
@[simp]
-theorem isPrimal_mk {a : α} : IsPrimal (Associates.mk a) ↔ IsPrimal a := by
+theorem isPrimal_mk {a : M} : IsPrimal (Associates.mk a) ↔ IsPrimal a := by
simp_rw [IsPrimal, forall_associated, mk_surjective.exists, mk_mul_mk, mk_dvd_mk]
constructor <;> intro h b c dvd <;> obtain ⟨a₁, a₂, h₁, h₂, eq⟩ := @h b c dvd
· obtain ⟨u, rfl⟩ := mk_eq_mk_iff_associated.mp eq.symm
@@ -925,80 +594,80 @@ theorem isPrimal_mk {a : α} : IsPrimal (Associates.mk a) ↔ IsPrimal a := by
@[deprecated (since := "2024-03-16")] alias isPrimal_iff := isPrimal_mk
@[simp]
-theorem decompositionMonoid_iff : DecompositionMonoid (Associates α) ↔ DecompositionMonoid α := by
+theorem decompositionMonoid_iff : DecompositionMonoid (Associates M) ↔ DecompositionMonoid M := by
simp_rw [_root_.decompositionMonoid_iff, forall_associated, isPrimal_mk]
-instance instDecompositionMonoid [DecompositionMonoid α] : DecompositionMonoid (Associates α) :=
+instance instDecompositionMonoid [DecompositionMonoid M] : DecompositionMonoid (Associates M) :=
decompositionMonoid_iff.mpr ‹_›
@[simp]
-theorem mk_isRelPrime_iff {a b : α} :
+theorem mk_isRelPrime_iff {a b : M} :
IsRelPrime (Associates.mk a) (Associates.mk b) ↔ IsRelPrime a b := by
simp_rw [IsRelPrime, forall_associated, mk_dvd_mk, isUnit_mk]
end CommMonoid
-instance [Zero α] [Monoid α] : Zero (Associates α) :=
+instance [Zero M] [Monoid M] : Zero (Associates M) :=
⟨⟦0⟧⟩
-instance [Zero α] [Monoid α] : Top (Associates α) :=
+instance [Zero M] [Monoid M] : Top (Associates M) :=
⟨0⟩
-@[simp] theorem mk_zero [Zero α] [Monoid α] : Associates.mk (0 : α) = 0 := rfl
+@[simp] theorem mk_zero [Zero M] [Monoid M] : Associates.mk (0 : M) = 0 := rfl
section MonoidWithZero
-variable [MonoidWithZero α]
+variable [MonoidWithZero M]
@[simp]
-theorem mk_eq_zero {a : α} : Associates.mk a = 0 ↔ a = 0 :=
+theorem mk_eq_zero {a : M} : Associates.mk a = 0 ↔ a = 0 :=
⟨fun h => (associated_zero_iff_eq_zero a).1 <| Quotient.exact h, fun h => h.symm ▸ rfl⟩
@[simp]
-theorem quot_out_zero : Quot.out (0 : Associates α) = 0 := by rw [← mk_eq_zero, quot_out]
+theorem quot_out_zero : Quot.out (0 : Associates M) = 0 := by rw [← mk_eq_zero, quot_out]
-theorem mk_ne_zero {a : α} : Associates.mk a ≠ 0 ↔ a ≠ 0 :=
+theorem mk_ne_zero {a : M} : Associates.mk a ≠ 0 ↔ a ≠ 0 :=
not_congr mk_eq_zero
-instance [Nontrivial α] : Nontrivial (Associates α) :=
+instance [Nontrivial M] : Nontrivial (Associates M) :=
⟨⟨1, 0, mk_ne_zero.2 one_ne_zero⟩⟩
-theorem exists_non_zero_rep {a : Associates α} : a ≠ 0 → ∃ a0 : α, a0 ≠ 0 ∧ Associates.mk a0 = a :=
+theorem exists_non_zero_rep {a : Associates M} : a ≠ 0 → ∃ a0 : M, a0 ≠ 0 ∧ Associates.mk a0 = a :=
Quotient.inductionOn a fun b nz => ⟨b, mt (congr_arg Quotient.mk'') nz, rfl⟩
end MonoidWithZero
section CommMonoidWithZero
-variable [CommMonoidWithZero α]
+variable [CommMonoidWithZero M]
-instance instCommMonoidWithZero : CommMonoidWithZero (Associates α) where
+instance instCommMonoidWithZero : CommMonoidWithZero (Associates M) where
zero_mul := forall_associated.2 fun a ↦ by rw [← mk_zero, mk_mul_mk, zero_mul]
mul_zero := forall_associated.2 fun a ↦ by rw [← mk_zero, mk_mul_mk, mul_zero]
-instance instOrderTop : OrderTop (Associates α) where
+instance instOrderTop : OrderTop (Associates M) where
top := 0
le_top := dvd_zero
-@[simp] protected theorem le_zero (a : Associates α) : a ≤ 0 := le_top
+@[simp] protected theorem le_zero (a : Associates M) : a ≤ 0 := le_top
-instance instBoundedOrder : BoundedOrder (Associates α) where
+instance instBoundedOrder : BoundedOrder (Associates M) where
-instance [DecidableRel ((· ∣ ·) : α → α → Prop)] :
- DecidableRel ((· ∣ ·) : Associates α → Associates α → Prop) := fun a b =>
+instance [DecidableRel ((· ∣ ·) : M → M → Prop)] :
+ DecidableRel ((· ∣ ·) : Associates M → Associates M → Prop) := fun a b =>
Quotient.recOnSubsingleton₂ a b fun _ _ => decidable_of_iff' _ mk_dvd_mk
-theorem Prime.le_or_le {p : Associates α} (hp : Prime p) {a b : Associates α} (h : p ≤ a * b) :
+theorem Prime.le_or_le {p : Associates M} (hp : Prime p) {a b : Associates M} (h : p ≤ a * b) :
p ≤ a ∨ p ≤ b :=
hp.2.2 a b h
@[simp]
-theorem prime_mk {p : α} : Prime (Associates.mk p) ↔ Prime p := by
+theorem prime_mk {p : M} : Prime (Associates.mk p) ↔ Prime p := by
rw [Prime, _root_.Prime, forall_associated]
simp only [forall_associated, mk_ne_zero, isUnit_mk, mk_mul_mk, mk_dvd_mk]
@[simp]
-theorem irreducible_mk {a : α} : Irreducible (Associates.mk a) ↔ Irreducible a := by
+theorem irreducible_mk {a : M} : Irreducible (Associates.mk a) ↔ Irreducible a := by
simp only [irreducible_iff, isUnit_mk, forall_associated, isUnit_mk, mk_mul_mk,
mk_eq_mk_iff_associated, Associated.comm (x := a)]
apply Iff.rfl.and
@@ -1009,7 +678,7 @@ theorem irreducible_mk {a : α} : Irreducible (Associates.mk a) ↔ Irreducible
simpa using h x (y * u) (mul_assoc _ _ _)
@[simp]
-theorem mk_dvdNotUnit_mk_iff {a b : α} :
+theorem mk_dvdNotUnit_mk_iff {a b : M} :
DvdNotUnit (Associates.mk a) (Associates.mk b) ↔ DvdNotUnit a b := by
simp only [DvdNotUnit, mk_ne_zero, mk_surjective.exists, isUnit_mk, mk_mul_mk,
mk_eq_mk_iff_associated, Associated.comm (x := b)]
@@ -1021,7 +690,7 @@ theorem mk_dvdNotUnit_mk_iff {a b : α} :
· rintro ⟨x, ⟨hx, rfl⟩⟩
use x
-theorem dvdNotUnit_of_lt {a b : Associates α} (hlt : a < b) : DvdNotUnit a b := by
+theorem dvdNotUnit_of_lt {a b : Associates M} (hlt : a < b) : DvdNotUnit a b := by
constructor
· rintro rfl
apply not_lt_of_le _ hlt
@@ -1033,46 +702,46 @@ theorem dvdNotUnit_of_lt {a b : Associates α} (hlt : a < b) : DvdNotUnit a b :=
simp
theorem irreducible_iff_prime_iff :
- (∀ a : α, Irreducible a ↔ Prime a) ↔ ∀ a : Associates α, Irreducible a ↔ Prime a := by
+ (∀ a : M, Irreducible a ↔ Prime a) ↔ ∀ a : Associates M, Irreducible a ↔ Prime a := by
simp_rw [forall_associated, irreducible_mk, prime_mk]
end CommMonoidWithZero
section CancelCommMonoidWithZero
-variable [CancelCommMonoidWithZero α]
+variable [CancelCommMonoidWithZero M]
-instance instPartialOrder : PartialOrder (Associates α) where
+instance instPartialOrder : PartialOrder (Associates M) where
le_antisymm := mk_surjective.forall₂.2 fun _a _b hab hba => mk_eq_mk_iff_associated.2 <|
associated_of_dvd_dvd (dvd_of_mk_le_mk hab) (dvd_of_mk_le_mk hba)
-instance instCancelCommMonoidWithZero : CancelCommMonoidWithZero (Associates α) :=
- { (by infer_instance : CommMonoidWithZero (Associates α)) with
+instance instCancelCommMonoidWithZero : CancelCommMonoidWithZero (Associates M) :=
+ { (by infer_instance : CommMonoidWithZero (Associates M)) with
mul_left_cancel_of_ne_zero := by
rintro ⟨a⟩ ⟨b⟩ ⟨c⟩ ha h
rcases Quotient.exact' h with ⟨u, hu⟩
have hu : a * (b * ↑u) = a * c := by rwa [← mul_assoc]
exact Quotient.sound' ⟨u, mul_left_cancel₀ (mk_ne_zero.1 ha) hu⟩ }
-theorem _root_.associates_irreducible_iff_prime [DecompositionMonoid α] {p : Associates α} :
+theorem _root_.associates_irreducible_iff_prime [DecompositionMonoid M] {p : Associates M} :
Irreducible p ↔ Prime p := irreducible_iff_prime
-instance : NoZeroDivisors (Associates α) := by infer_instance
+instance : NoZeroDivisors (Associates M) := by infer_instance
-theorem le_of_mul_le_mul_left (a b c : Associates α) (ha : a ≠ 0) : a * b ≤ a * c → b ≤ c
+theorem le_of_mul_le_mul_left (a b c : Associates M) (ha : a ≠ 0) : a * b ≤ a * c → b ≤ c
| ⟨d, hd⟩ => ⟨d, mul_left_cancel₀ ha <| by rwa [← mul_assoc]⟩
-theorem one_or_eq_of_le_of_prime {p m : Associates α} (hp : Prime p) (hle : m ≤ p) :
+theorem one_or_eq_of_le_of_prime {p m : Associates M} (hp : Prime p) (hle : m ≤ p) :
m = 1 ∨ m = p := by
rcases mk_surjective p with ⟨p, rfl⟩
rcases mk_surjective m with ⟨m, rfl⟩
simpa [mk_eq_mk_iff_associated, Associated.comm, -Quotient.eq]
using (prime_mk.1 hp).irreducible.dvd_iff.mp (mk_le_mk_iff_dvd.1 hle)
-theorem dvdNotUnit_iff_lt {a b : Associates α} : DvdNotUnit a b ↔ a < b :=
+theorem dvdNotUnit_iff_lt {a b : Associates M} : DvdNotUnit a b ↔ a < b :=
dvd_and_not_dvd_iff.symm
-theorem le_one_iff {p : Associates α} : p ≤ 1 ↔ p = 1 := by rw [← Associates.bot_eq_one, le_bot_iff]
+theorem le_one_iff {p : Associates M} : p ≤ 1 ↔ p = 1 := by rw [← Associates.bot_eq_one, le_bot_iff]
end CancelCommMonoidWithZero
@@ -1080,20 +749,7 @@ end Associates
section CommMonoidWithZero
-theorem DvdNotUnit.isUnit_of_irreducible_right [CommMonoidWithZero α] {p q : α}
- (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 α] {p q : α} (hp : ¬IsUnit p)
- (h : DvdNotUnit p q) : ¬Irreducible q :=
- mt h.isUnit_of_irreducible_right hp
-
-theorem DvdNotUnit.not_unit [CommMonoidWithZero α] {p q : α} (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 α] [Nontrivial α] {p q r : α}
+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'
obtain ⟨hp, x, hx⟩ := h
@@ -1104,33 +760,20 @@ end CommMonoidWithZero
section CancelCommMonoidWithZero
-theorem isUnit_of_associated_mul [CancelCommMonoidWithZero α] {p b : α} (h : Associated (p * b) p)
+theorem isUnit_of_associated_mul [CancelCommMonoidWithZero M] {p b : M} (h : Associated (p * b) p)
(hp : p ≠ 0) : IsUnit b := by
obtain ⟨a, ha⟩ := h
refine isUnit_of_mul_eq_one b a ((mul_right_inj' hp).mp ?_)
rwa [← mul_assoc, mul_one]
-theorem DvdNotUnit.not_associated [CancelCommMonoidWithZero α] {p q : α} (h : DvdNotUnit p q) :
+theorem DvdNotUnit.not_associated [CancelCommMonoidWithZero M] {p q : M} (h : DvdNotUnit p q) :
¬Associated p q := by
rintro ⟨a, rfl⟩
obtain ⟨hp, x, hx, hx'⟩ := h
rcases (mul_right_inj' hp).mp hx' with rfl
exact hx a.isUnit
-theorem DvdNotUnit.ne [CancelCommMonoidWithZero α] {p q : α} (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_unit [CancelCommMonoidWithZero α] {q : α} (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
-
-theorem dvd_prime_pow [CancelCommMonoidWithZero α] {p q : α} (hp : Prime p) (n : ℕ) :
+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
| zero =>
diff --git a/Mathlib/Algebra/Associated/OrderedCommMonoid.lean b/Mathlib/Algebra/Associated/OrderedCommMonoid.lean
index 16c1b23b72bf2..ab1745e4359de 100644
--- a/Mathlib/Algebra/Associated/OrderedCommMonoid.lean
+++ b/Mathlib/Algebra/Associated/OrderedCommMonoid.lean
@@ -23,14 +23,14 @@ Then we show that the quotient type `Associates` is a monoid
and prove basic properties of this quotient.
-/
-variable {α : Type*} [CancelCommMonoidWithZero α]
+variable {M : Type*} [CancelCommMonoidWithZero M]
namespace Associates
-instance instOrderedCommMonoid : OrderedCommMonoid (Associates α) where
- mul_le_mul_left := fun a _ ⟨d, hd⟩ c => hd.symm ▸ mul_assoc c a d ▸ le_mul_right (α := α)
+instance instOrderedCommMonoid : OrderedCommMonoid (Associates M) where
+ mul_le_mul_left := fun a _ ⟨d, hd⟩ c => hd.symm ▸ mul_assoc c a d ▸ le_mul_right
-instance : CanonicallyOrderedCommMonoid (Associates α) where
+instance : CanonicallyOrderedCommMonoid (Associates M) where
exists_mul_of_le h := h
le_self_mul _ b := ⟨b, rfl⟩
bot_le _ := one_le
diff --git a/Mathlib/Algebra/BigOperators/Associated.lean b/Mathlib/Algebra/BigOperators/Associated.lean
index b8b8178cc0aa7..1c4e80f7431fa 100644
--- a/Mathlib/Algebra/BigOperators/Associated.lean
+++ b/Mathlib/Algebra/BigOperators/Associated.lean
@@ -74,6 +74,46 @@ theorem exists_associated_mem_of_dvd_prod [CancelCommMonoidWithZero α] {p : α}
· rcases ih (fun r hr => hs _ (Multiset.mem_cons.2 (Or.inr hr))) h with ⟨q, hq₁, hq₂⟩
exact ⟨q, Multiset.mem_cons.2 (Or.inr hq₁), hq₂⟩
+open Submonoid in
+/-- Let x, y ∈ α. If x * y can be written as a product of units and prime elements, then x can be
+written as a product of units and prime elements. -/
+theorem divisor_closure_eq_closure [CancelCommMonoidWithZero α]
+ (x y : α) (hxy : x * y ∈ closure { r : α | IsUnit r ∨ Prime r}) :
+ x ∈ closure { r : α | IsUnit r ∨ Prime r} := by
+ obtain ⟨m, hm, hprod⟩ := exists_multiset_of_mem_closure hxy
+ induction m using Multiset.induction generalizing x y with
+ | empty =>
+ apply subset_closure
+ simp only [Set.mem_setOf]
+ simp only [Multiset.prod_zero] at hprod
+ left; exact isUnit_of_mul_eq_one _ _ hprod.symm
+ | @cons c s hind =>
+ simp only [Multiset.mem_cons, forall_eq_or_imp, Set.mem_setOf] at hm
+ simp only [Multiset.prod_cons] at hprod
+ simp only [Set.mem_setOf_eq] at hind
+ obtain ⟨ha₁ | ha₂, hs⟩ := hm
+ · rcases ha₁.exists_right_inv with ⟨k, hk⟩
+ refine hind x (y*k) ?_ hs ?_
+ · simp only [← mul_assoc, ← hprod, ← Multiset.prod_cons, mul_comm]
+ refine multiset_prod_mem _ _ (Multiset.forall_mem_cons.2 ⟨subset_closure (Set.mem_def.2 ?_),
+ Multiset.forall_mem_cons.2 ⟨subset_closure (Set.mem_def.2 ?_), (fun t ht =>
+ subset_closure (hs t ht))⟩⟩)
+ · left; exact isUnit_of_mul_eq_one_right _ _ hk
+ · left; exact ha₁
+ · rw [← mul_one s.prod, ← hk, ← mul_assoc, ← mul_assoc, mul_eq_mul_right_iff, mul_comm]
+ left; exact hprod
+ · rcases ha₂.dvd_mul.1 (Dvd.intro _ hprod) with ⟨c, hc⟩ | ⟨c, hc⟩
+ · rw [hc]; rw [hc, mul_assoc] at hprod
+ refine Submonoid.mul_mem _ (subset_closure (Set.mem_def.2 ?_))
+ (hind _ _ ?_ hs (mul_left_cancel₀ ha₂.ne_zero hprod))
+ · right; exact ha₂
+ rw [← mul_left_cancel₀ ha₂.ne_zero hprod]
+ exact multiset_prod_mem _ _ (fun t ht => subset_closure (hs t ht))
+ rw [hc, mul_comm x _, mul_assoc, mul_comm c _] at hprod
+ refine hind x c ?_ hs (mul_left_cancel₀ ha₂.ne_zero hprod)
+ rw [← mul_left_cancel₀ ha₂.ne_zero hprod]
+ exact multiset_prod_mem _ _ (fun t ht => subset_closure (hs t ht))
+
theorem Multiset.prod_primes_dvd [CancelCommMonoidWithZero α]
[∀ a : α, DecidablePred (Associated a)] {s : Multiset α} (n : α) (h : ∀ a ∈ s, Prime a)
(div : ∀ a ∈ s, a ∣ n) (uniq : ∀ a, s.countP (Associated a) ≤ 1) : s.prod ∣ n := by
@@ -95,7 +135,7 @@ theorem Multiset.prod_primes_dvd [CancelCommMonoidWithZero α]
Multiset.countP_pos] at this
exact this ⟨b, b_in_s, assoc.symm⟩
-theorem Finset.prod_primes_dvd [CancelCommMonoidWithZero α] [Unique αˣ] {s : Finset α} (n : α)
+theorem Finset.prod_primes_dvd [CancelCommMonoidWithZero α] [Subsingleton αˣ] {s : Finset α} (n : α)
(h : ∀ a ∈ s, Prime a) (div : ∀ a ∈ s, a ∣ n) : (∏ p ∈ s, p) ∣ n := by
classical
exact
@@ -147,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/Balance.lean b/Mathlib/Algebra/BigOperators/Balance.lean
new file mode 100644
index 0000000000000..1b2b2ca767a64
--- /dev/null
+++ b/Mathlib/Algebra/BigOperators/Balance.lean
@@ -0,0 +1,56 @@
+/-
+Copyright (c) 2023 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.BigOperators.Expect
+
+/-!
+# Balancing a function
+
+This file defines the balancing of a function `f`, defined as `f` minus its average.
+
+This is the unique function `g` such that `f a - f b = g a - g b` for all `a` and `b`, and
+`∑ a, g a = 0`. This is particularly useful in Fourier analysis as `f` and `g` then have the same
+Fourier transform, except in the `0`-th frequency where the Fourier transform of `g` vanishes.
+-/
+
+open Finset Function
+open scoped BigOperators
+
+variable {ι H F G : Type*}
+
+namespace Fintype
+
+section AddCommGroup
+variable [Fintype ι] [AddCommGroup G] [Module ℚ≥0 G] [AddCommGroup H] [Module ℚ≥0 H]
+
+/-- The balancing of a function, namely the function minus its average. -/
+def balance (f : ι → G) : ι → G := f - Function.const _ (𝔼 y, f y)
+
+lemma balance_apply (f : ι → G) (x : ι) : balance f x = f x - 𝔼 y, f y := rfl
+
+@[simp] lemma balance_zero : balance (0 : ι → G) = 0 := by simp [balance]
+
+@[simp] lemma balance_add (f g : ι → G) : balance (f + g) = balance f + balance g := by
+ simp only [balance, expect_add_distrib, ← const_add, add_sub_add_comm, Pi.add_apply]
+
+@[simp] lemma balance_sub (f g : ι → G) : balance (f - g) = balance f - balance g := by
+ simp only [balance, expect_sub_distrib, const_sub, sub_sub_sub_comm, Pi.sub_apply]
+
+@[simp] lemma balance_neg (f : ι → G) : balance (-f) = -balance f := by
+ simp only [balance, expect_neg_distrib, const_neg, neg_sub', Pi.neg_apply]
+
+@[simp] lemma sum_balance (f : ι → G) : ∑ x, balance f x = 0 := by
+ cases isEmpty_or_nonempty ι <;> simp [balance_apply]
+
+@[simp] lemma expect_balance (f : ι → G) : 𝔼 x, balance f x = 0 := by simp [expect]
+
+@[simp] lemma balance_idem (f : ι → G) : balance (balance f) = balance f := by
+ cases isEmpty_or_nonempty ι <;> ext x <;> simp [balance, expect_sub_distrib, univ_nonempty]
+
+@[simp] lemma map_balance [FunLike F G H] [LinearMapClass F ℚ≥0 G H] (g : F) (f : ι → G) (a : ι) :
+ g (balance f a) = balance (g ∘ f) a := by simp [balance, map_expect]
+
+end AddCommGroup
+end Fintype
diff --git a/Mathlib/Algebra/BigOperators/Expect.lean b/Mathlib/Algebra/BigOperators/Expect.lean
new file mode 100644
index 0000000000000..df5560dfae390
--- /dev/null
+++ b/Mathlib/Algebra/BigOperators/Expect.lean
@@ -0,0 +1,444 @@
+/-
+Copyright (c) 2024 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.Algebra.Rat
+import Mathlib.Algebra.BigOperators.GroupWithZero.Action
+import Mathlib.Algebra.BigOperators.Pi
+import Mathlib.Algebra.BigOperators.Ring
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
+import Mathlib.Algebra.Module.Pi
+import Mathlib.Data.Finset.Density
+import Mathlib.Data.Fintype.BigOperators
+
+/-!
+# Average over a finset
+
+This file defines `Finset.expect`, the average (aka expectation) of a function over a finset.
+
+## Notation
+
+* `𝔼 i ∈ s, f i` is notation for `Finset.expect s f`. It is the expectation of `f i` where `i`
+ ranges over the finite set `s` (either a `Finset` or a `Set` with a `Fintype` instance).
+* `𝔼 i, f i` is notation for `Finset.expect Finset.univ f`. It is the expectation of `f i` where `i`
+ ranges over the finite domain of `f`.
+* `𝔼 i ∈ s with p i, f i` is notation for `Finset.expect (Finset.filter p s) f`. This is referred to
+ as `expectWith` in lemma names.
+* `𝔼 (i ∈ s) (j ∈ t), f i j` is notation for `Finset.expect (s ×ˢ t) (fun ⟨i, j⟩ ↦ f i j)`.
+
+## Implementation notes
+
+This definition is a special case of the general convex comnination operator in a convex space.
+However:
+1. We don't yet have general convex spaces.
+2. The uniform weights case is a overwhelmingly useful special case which should have its own API.
+
+When convex spaces are finally defined, we should redefine `Finset.expect` in terms of that convex
+combination operator.
+
+## TODO
+
+* Connect `Finset.expect` with the expectation over `s` in the probability theory sense.
+* Give a formulation of Jensen's inequality in this language.
+-/
+
+open Finset Function
+open Fintype (card)
+open scoped Pointwise
+
+variable {ι κ M N : Type*}
+
+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 : ℚ≥0)⁻¹ • ∑ i ∈ s, f i
+
+namespace BigOperators
+open Batteries.ExtendedBinder Lean Meta
+
+/--
+* `𝔼 i ∈ s, f i` is notation for `Finset.expect s f`. It is the expectation of `f i` where `i`
+ ranges over the finite set `s` (either a `Finset` or a `Set` with a `Fintype` instance).
+* `𝔼 i, f i` is notation for `Finset.expect Finset.univ f`. It is the expectation of `f i` where `i`
+ ranges over the finite domain of `f`.
+* `𝔼 i ∈ s with p i, f i` is notation for `Finset.expect (Finset.filter p s) f`.
+* `𝔼 (i ∈ s) (j ∈ t), f i j` is notation for `Finset.expect (s ×ˢ t) (fun ⟨i, j⟩ ↦ f i j)`.
+
+These support destructuring, for example `𝔼 ⟨i, j⟩ ∈ s ×ˢ t, f i j`.
+
+Notation: `"𝔼" bigOpBinders* ("with" term)? "," term` -/
+scoped syntax (name := bigexpect) "𝔼 " bigOpBinders ("with " term)? ", " term:67 : term
+
+scoped macro_rules (kind := bigexpect)
+ | `(𝔼 $bs:bigOpBinders $[with $p?]?, $v) => do
+ let processed ← processBigOpBinders bs
+ let i ← bigOpBindersPattern processed
+ let s ← bigOpBindersProd processed
+ match p? with
+ | some p => `(Finset.expect (Finset.filter (fun $i ↦ $p) $s) (fun $i ↦ $v))
+ | none => `(Finset.expect $s (fun $i ↦ $v))
+
+open Lean Meta Parser.Term PrettyPrinter.Delaborator SubExpr
+open Batteries.ExtendedBinder
+
+/-- Delaborator for `Finset.expect`. The `pp.piBinderTypes` option controls whether
+to show the domain type when the expect is over `Finset.univ`. -/
+@[scoped delab app.Finset.expect] def delabFinsetExpect : Delab :=
+ whenPPOption getPPNotation <| withOverApp 6 <| do
+ let #[_, _, _, _, s, f] := (← getExpr).getAppArgs | failure
+ guard <| f.isLambda
+ let ppDomain ← getPPOption getPPPiBinderTypes
+ let (i, body) ← withAppArg <| withBindingBodyUnusedName fun i => do
+ return (i, ← delab)
+ if s.isAppOfArity ``Finset.univ 2 then
+ let binder ←
+ if ppDomain then
+ let ty ← withNaryArg 0 delab
+ `(bigOpBinder| $(.mk i):ident : $ty)
+ else
+ `(bigOpBinder| $(.mk i):ident)
+ `(𝔼 $binder:bigOpBinder, $body)
+ else
+ let ss ← withNaryArg 4 <| delab
+ `(𝔼 $(.mk i):ident ∈ $ss, $body)
+
+end BigOperators
+
+open scoped BigOperators
+
+namespace Finset
+section AddCommMonoid
+variable [AddCommMonoid M] [Module ℚ≥0 M] [AddCommMonoid N] [Module ℚ≥0 N] {s t : Finset ι}
+ {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]
+
+@[simp] lemma expect_empty (f : ι → M) : 𝔼 i ∈ ∅, f i = 0 := by simp [expect]
+@[simp] lemma expect_singleton (f : ι → M) (i : ι) : 𝔼 j ∈ {i}, f j = f i := by simp [expect]
+@[simp] lemma expect_const_zero (s : Finset ι) : 𝔼 _i ∈ s, (0 : M) = 0 := by simp [expect]
+
+@[congr]
+lemma expect_congr {t : Finset ι} (hst : s = t) (h : ∀ i ∈ t, f i = g i) :
+ 𝔼 i ∈ s, f i = 𝔼 i ∈ t, g i := by rw [expect, expect, sum_congr hst h, hst]
+
+lemma expectWith_congr (hst : s = t) (hpq : ∀ i ∈ t, p i ↔ q i) (h : ∀ i ∈ t, q i → f i = g i) :
+ 𝔼 i ∈ s with p i, f i = 𝔼 i ∈ t with q i, g i :=
+ expect_congr (by rw [hst, filter_inj'.2 hpq]) <| by simpa using h
+
+lemma expect_sum_comm (s : Finset ι) (t : Finset κ) (f : ι → κ → M) :
+ 𝔼 i ∈ s, ∑ j ∈ t, f i j = ∑ j ∈ t, 𝔼 i ∈ s, f i j := by
+ simpa only [expect, smul_sum] using sum_comm
+
+lemma expect_comm (s : Finset ι) (t : Finset κ) (f : ι → κ → M) :
+ 𝔼 i ∈ s, 𝔼 j ∈ t, f i j = 𝔼 j ∈ t, 𝔼 i ∈ s, f i j := by
+ rw [expect, expect, ← expect_sum_comm, ← expect_sum_comm, expect, expect, smul_comm, sum_comm]
+
+lemma expect_eq_zero (h : ∀ i ∈ s, f i = 0) : 𝔼 i ∈ s, f i = 0 :=
+ (expect_congr rfl h).trans s.expect_const_zero
+
+lemma exists_ne_zero_of_expect_ne_zero (h : 𝔼 i ∈ s, f i ≠ 0) : ∃ i ∈ s, f i ≠ 0 := by
+ contrapose! h; exact expect_eq_zero h
+
+lemma expect_add_distrib (s : Finset ι) (f g : ι → M) :
+ 𝔼 i ∈ s, (f i + g i) = 𝔼 i ∈ s, f i + 𝔼 i ∈ s, g i := by
+ simp [expect, sum_add_distrib]
+
+lemma expect_add_expect_comm (f₁ f₂ g₁ g₂ : ι → M) :
+ 𝔼 i ∈ s, (f₁ i + f₂ i) + 𝔼 i ∈ s, (g₁ i + g₂ i) =
+ 𝔼 i ∈ s, (f₁ i + g₁ i) + 𝔼 i ∈ s, (f₂ i + g₂ i) := by
+ 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 := 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) 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) / #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 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 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 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 else 0 := by
+ split_ifs <;> simp [expect, *]
+
+end DecidableEq
+
+section bij
+variable {t : Finset κ} {g : κ → M}
+
+/-- Reorder an average.
+
+The difference with `Finset.expect_bij'` is that the bijection is specified as a surjective
+injection, rather than by an inverse function.
+
+The difference with `Finset.expect_nbij` is that the bijection is allowed to use membership of the
+domain of the average, rather than being a non-dependent function. -/
+lemma expect_bij (i : ∀ a ∈ s, κ) (hi : ∀ a ha, i a ha ∈ t) (h : ∀ a ha, f a = g (i a ha))
+ (i_inj : ∀ a₁ ha₁ a₂ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂)
+ (i_surj : ∀ b ∈ t, ∃ a ha, i a ha = b) : 𝔼 i ∈ s, f i = 𝔼 i ∈ t, g i := by
+ simp_rw [expect, card_bij i hi i_inj i_surj, sum_bij i hi i_inj i_surj h]
+
+/-- Reorder an average.
+
+The difference with `Finset.expect_bij` is that the bijection is specified with an inverse, rather
+than as a surjective injection.
+
+The difference with `Finset.expect_nbij'` is that the bijection and its inverse are allowed to use
+membership of the domains of the averages, rather than being non-dependent functions. -/
+lemma expect_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) (h : ∀ a ha, f a = g (i a ha)) :
+ 𝔼 i ∈ s, f i = 𝔼 i ∈ t, g i := by
+ simp_rw [expect, card_bij' i j hi hj left_inv right_inv, sum_bij' i j hi hj left_inv right_inv h]
+
+/-- Reorder an average.
+
+The difference with `Finset.expect_nbij'` is that the bijection is specified as a surjective
+injection, rather than by an inverse function.
+
+The difference with `Finset.expect_bij` is that the bijection is a non-dependent function, rather
+than being allowed to use membership of the domain of the average. -/
+lemma expect_nbij (i : ι → κ) (hi : ∀ a ∈ s, i a ∈ t) (h : ∀ a ∈ s, f a = g (i a))
+ (i_inj : (s : Set ι).InjOn i) (i_surj : (s : Set ι).SurjOn i t) :
+ 𝔼 i ∈ s, f i = 𝔼 i ∈ t, g i := by
+ simp_rw [expect, card_nbij i hi i_inj i_surj, sum_nbij i hi i_inj i_surj h]
+
+/-- Reorder an average.
+
+The difference with `Finset.expect_nbij` is that the bijection is specified with an inverse, rather
+than as a surjective injection.
+
+The difference with `Finset.expect_bij'` is that the bijection and its inverse are non-dependent
+functions, rather than being allowed to use membership of the domains of the averages.
+
+The difference with `Finset.expect_equiv` is that bijectivity is only required to hold on the
+domains of the averages, rather than on the entire types. -/
+lemma expect_nbij' (i : ι → κ) (j : κ → ι) (hi : ∀ a ∈ s, i a ∈ t) (hj : ∀ a ∈ t, j a ∈ s)
+ (left_inv : ∀ a ∈ s, j (i a) = a) (right_inv : ∀ a ∈ t, i (j a) = a)
+ (h : ∀ a ∈ s, f a = g (i a)) : 𝔼 i ∈ s, f i = 𝔼 i ∈ t, g i := by
+ simp_rw [expect, card_nbij' i j hi hj left_inv right_inv,
+ sum_nbij' i j hi hj left_inv right_inv h]
+
+/-- `Finset.expect_equiv` is a specialization of `Finset.expect_bij` that automatically fills in
+most arguments. -/
+lemma expect_equiv (e : ι ≃ κ) (hst : ∀ i, i ∈ s ↔ e i ∈ t) (hfg : ∀ i ∈ s, f i = g (e i)) :
+ 𝔼 i ∈ s, f i = 𝔼 i ∈ t, g i := by simp_rw [expect, card_equiv e hst, sum_equiv e hst hfg]
+
+/-- Expectation over a product set equals the expectation of the fiberwise expectations.
+
+For rewriting in the reverse direction, use `Finset.expect_product'`. -/
+lemma expect_product (s : Finset ι) (t : Finset κ) (f : ι × κ → M) :
+ 𝔼 x ∈ s ×ˢ t, f x = 𝔼 i ∈ s, 𝔼 j ∈ t, f (i, j) := by
+ simp only [expect, card_product, sum_product, smul_sum, mul_inv, mul_smul, Nat.cast_mul]
+
+/-- Expectation over a product set equals the expectation of the fiberwise expectations.
+
+For rewriting in the reverse direction, use `Finset.expect_product`. -/
+lemma expect_product' (s : Finset ι) (t : Finset κ) (f : ι → κ → M) :
+ 𝔼 i ∈ s ×ˢ t, f i.1 i.2 = 𝔼 i ∈ s, 𝔼 j ∈ t, f i j := by
+ simp only [expect, card_product, sum_product', smul_sum, mul_inv, mul_smul, Nat.cast_mul]
+
+@[simp]
+lemma expect_image [DecidableEq ι] {m : κ → ι} (hm : (t : Set κ).InjOn m) :
+ 𝔼 i ∈ t.image m, f i = 𝔼 i ∈ t, f (m i) := by
+ simp_rw [expect, card_image_of_injOn hm, sum_image hm]
+
+end bij
+
+@[simp] lemma expect_inv_index [DecidableEq ι] [InvolutiveInv ι] (s : Finset ι) (f : ι → M) :
+ 𝔼 i ∈ s⁻¹, f i = 𝔼 i ∈ s, f i⁻¹ := expect_image inv_injective.injOn
+
+@[simp] lemma expect_neg_index [DecidableEq ι] [InvolutiveNeg ι] (s : Finset ι) (f : ι → M) :
+ 𝔼 i ∈ -s, f i = 𝔼 i ∈ s, f (-i) := expect_image neg_injective.injOn
+
+lemma _root_.map_expect {F : Type*} [FunLike F M N] [LinearMapClass F ℚ≥0 M N]
+ (g : F) (f : ι → M) (s : Finset ι) :
+ 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 • 𝔼 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₀]
+ exact mod_cast hs.card_ne_zero
+
+@[simp] lemma _root_.Fintype.card_smul_expect [Fintype ι] (f : ι → M) :
+ Fintype.card ι • 𝔼 i, f i = ∑ i, f i := Finset.card_smul_expect _ _
+
+@[simp] lemma expect_const (hs : s.Nonempty) (a : M) : 𝔼 _i ∈ s, a = a := by
+ rw [expect, sum_const, ← Nat.cast_smul_eq_nsmul ℚ≥0, inv_smul_smul₀]
+ exact mod_cast hs.card_ne_zero
+
+lemma smul_expect {G : Type*} [DistribSMul G M] [SMulCommClass G ℚ≥0 M] (a : G)
+ (s : Finset ι) (f : ι → M) : a • 𝔼 i ∈ s, f i = 𝔼 i ∈ s, a • f i := by
+ simp only [expect, smul_sum, smul_comm]
+
+end AddCommMonoid
+
+section AddCommGroup
+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
+ simp only [expect, sum_sub_distrib, smul_sub]
+
+@[simp]
+lemma expect_neg_distrib (s : Finset ι) (f : ι → M) : 𝔼 i ∈ s, -f i = -𝔼 i ∈ s, f i := by
+ simp [expect]
+
+end AddCommGroup
+
+section Semiring
+variable [Semiring M] [Module ℚ≥0 M]
+
+@[simp] lemma card_mul_expect (s : Finset ι) (f : ι → M) :
+ #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 _ _
+
+lemma expect_mul [IsScalarTower ℚ≥0 M M] (s : Finset ι) (f : ι → M) (a : M) :
+ (𝔼 i ∈ s, f i) * a = 𝔼 i ∈ s, f i * a := by rw [expect, expect, smul_mul_assoc, sum_mul]
+
+lemma mul_expect [SMulCommClass ℚ≥0 M M] (s : Finset ι) (f : ι → M) (a : M) :
+ a * 𝔼 i ∈ s, f i = 𝔼 i ∈ s, a * f i := by rw [expect, expect, mul_smul_comm, mul_sum]
+
+lemma expect_mul_expect [IsScalarTower ℚ≥0 M M] [SMulCommClass ℚ≥0 M M] (s : Finset ι)
+ (t : Finset κ) (f : ι → M) (g : κ → M) :
+ (𝔼 i ∈ s, f i) * 𝔼 j ∈ t, g j = 𝔼 i ∈ s, 𝔼 j ∈ t, f i * g j := by
+ simp_rw [expect_mul, mul_expect]
+
+end Semiring
+
+section CommSemiring
+variable [CommSemiring M] [Module ℚ≥0 M] [IsScalarTower ℚ≥0 M M] [SMulCommClass ℚ≥0 M M]
+
+lemma expect_pow (s : Finset ι) (f : ι → M) (n : ℕ) :
+ (𝔼 i ∈ s, f i) ^ n = 𝔼 p ∈ Fintype.piFinset fun _ : Fin n ↦ s, ∏ i, f (p i) := by
+ classical
+ rw [expect, smul_pow, sum_pow', expect, Fintype.card_piFinset_const, inv_pow, Nat.cast_pow]
+
+end CommSemiring
+
+section Semifield
+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
+ simp_rw [expect_univ, ite_mul, zero_mul, sum_ite_eq, if_pos (mem_univ _)]
+ rw [← @NNRat.cast_natCast M, ← NNRat.smul_def, inv_smul_smul₀]
+ simp [Fintype.card_ne_zero]
+
+lemma expect_boole_mul' [Fintype ι] [Nonempty ι] [DecidableEq ι] (f : ι → M) (i : ι) :
+ 𝔼 j, ite (j = i) (Fintype.card ι : M) 0 * f j = f i := by
+ 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 := 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) :
+ 𝔼 i, f i = (∑ i, f i) / Fintype.card ι := Finset.expect_eq_sum_div_card _ _
+
+lemma expect_div (s : Finset ι) (f : ι → M) (a : M) : (𝔼 i ∈ s, f i) / a = 𝔼 i ∈ s, f i / a := by
+ simp_rw [div_eq_mul_inv, expect_mul]
+
+end Semifield
+
+@[simp] lemma expect_apply {α : Type*} {π : α → Type*} [∀ a, CommSemiring (π a)]
+ [∀ a, Module ℚ≥0 (π a)] (s : Finset ι) (f : ι → ∀ a, π a) (a : α) :
+ (𝔼 i ∈ s, f i) a = 𝔼 i ∈ s, f i a := by simp [expect]
+
+end Finset
+
+namespace algebraMap
+variable [Semifield M] [CharZero M] [Semifield N] [CharZero N] [Algebra M N]
+
+@[simp, norm_cast]
+lemma coe_expect (s : Finset ι) (f : ι → M) : 𝔼 i ∈ s, f i = 𝔼 i ∈ s, (f i : N) :=
+ map_expect (algebraMap _ _) _ _
+
+end algebraMap
+
+namespace Fintype
+variable [Fintype ι] [Fintype κ]
+
+section AddCommMonoid
+variable [AddCommMonoid M] [Module ℚ≥0 M]
+
+/-- `Fintype.expect_bijective` is a variant of `Finset.expect_bij` that accepts
+`Function.Bijective`.
+
+See `Function.Bijective.expect_comp` for a version without `h`. -/
+lemma expect_bijective (e : ι → κ) (he : Bijective e) (f : ι → M) (g : κ → M)
+ (h : ∀ i, f i = g (e i)) : 𝔼 i, f i = 𝔼 i, g i :=
+ expect_nbij e (fun _ _ ↦ mem_univ _) (fun i _ ↦ h i) he.injective.injOn <| by
+ simpa using he.surjective.surjOn _
+
+/-- `Fintype.expect_equiv` is a specialization of `Finset.expect_bij` that automatically fills in
+most arguments.
+
+See `Equiv.expect_comp` for a version without `h`. -/
+lemma expect_equiv (e : ι ≃ κ) (f : ι → M) (g : κ → M) (h : ∀ i, f i = g (e i)) :
+ 𝔼 i, f i = 𝔼 i, g i := expect_bijective _ e.bijective f g h
+
+lemma expect_const [Nonempty ι] (a : M) : 𝔼 _i : ι, a = a := Finset.expect_const univ_nonempty _
+
+lemma expect_ite_zero (p : ι → Prop) [DecidablePred p] (h : ∀ i j, p i → p j → i = j) (a : M) :
+ 𝔼 i, ite (p i) a 0 = ite (∃ i, p i) (a /ℚ Fintype.card ι) 0 := by
+ simp [univ.expect_ite_zero p (by simpa using h), card_univ]
+
+variable [DecidableEq ι]
+
+@[simp] lemma expect_ite_mem (s : Finset ι) (f : ι → M) :
+ 𝔼 i, (if i ∈ s then f i else 0) = s.dens • 𝔼 i ∈ s, f i := by
+ simp [Finset.expect_ite_mem, dens]
+
+lemma expect_dite_eq (i : ι) (f : ∀ j, i = j → M) :
+ 𝔼 j, (if h : i = j then f j h else 0) = f i rfl /ℚ card ι := by simp [card_univ]
+
+lemma expect_dite_eq' (i : ι) (f : ∀ j, j = i → M) :
+ 𝔼 j, (if h : j = i then f j h else 0) = f i rfl /ℚ card ι := by simp [card_univ]
+
+lemma expect_ite_eq (i : ι) (f : ι → M) :
+ 𝔼 j, (if i = j then f j else 0) = f i /ℚ card ι := by simp [card_univ]
+
+lemma expect_ite_eq' (i : ι) (f : ι → M) :
+ 𝔼 j, (if j = i then f j else 0) = f i /ℚ card ι := by simp [card_univ]
+
+end AddCommMonoid
+
+section Semiring
+variable [Semiring M] [Module ℚ≥0 M]
+
+lemma expect_one [Nonempty ι] : 𝔼 _i : ι, (1 : M) = 1 := expect_const _
+
+lemma expect_mul_expect [IsScalarTower ℚ≥0 M M] [SMulCommClass ℚ≥0 M M] (f : ι → M)
+ (g : κ → M) : (𝔼 i, f i) * 𝔼 j, g j = 𝔼 i, 𝔼 j, f i * g j :=
+ Finset.expect_mul_expect ..
+
+end Semiring
+end Fintype
diff --git a/Mathlib/Algebra/BigOperators/Finprod.lean b/Mathlib/Algebra/BigOperators/Finprod.lean
index 751e627de3492..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
/-!
@@ -1011,7 +1012,7 @@ theorem Finset.mulSupport_of_fiberwise_prod_subset_image [DecidableEq β] (s : F
simp only [Finset.coe_image, Set.mem_image, Finset.mem_coe, Function.support_subset_iff]
intro b h
suffices (s.filter fun a : α => g a = b).Nonempty by
- simpa only [s.fiber_nonempty_iff_mem_image g b, Finset.mem_image, exists_prop]
+ simpa only [fiber_nonempty_iff_mem_image, Finset.mem_image, exists_prop]
exact Finset.nonempty_of_prod_ne_one h
/-- Note that `b ∈ (s.filter (fun ab => Prod.fst ab = a)).image Prod.snd` iff `(a, b) ∈ s` so
diff --git a/Mathlib/Algebra/BigOperators/Finsupp.lean b/Mathlib/Algebra/BigOperators/Finsupp.lean
index 25a6ab9d28063..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
@@ -249,12 +247,12 @@ theorem sum_apply [Zero M] [AddCommMonoid N] {f : α →₀ M} {g : α → M →
finset_sum_apply _ _ _
-- Porting note: inserted ⇑ on the rhs
-theorem coe_finset_sum [AddCommMonoid N] (S : Finset ι) (f : ι → α →₀ N) :
+@[simp, norm_cast] theorem coe_finset_sum [AddCommMonoid N] (S : Finset ι) (f : ι → α →₀ N) :
⇑(∑ i ∈ S, f i) = ∑ i ∈ S, ⇑(f i) :=
map_sum (coeFnAddHom : (α →₀ N) →+ _) _ _
-- Porting note: inserted ⇑ on the rhs
-theorem coe_sum [Zero M] [AddCommMonoid N] (f : α →₀ M) (g : α → M → β →₀ N) :
+@[simp, norm_cast] theorem coe_sum [Zero M] [AddCommMonoid N] (f : α →₀ M) (g : α → M → β →₀ N) :
⇑(f.sum g) = f.sum fun a₁ b => ⇑(g a₁ b) :=
coe_finset_sum _ _
@@ -346,8 +344,7 @@ def liftAddHom [AddZeroClass M] [AddCommMonoid N] : (α → M →+ N) ≃+ ((α
ext
simp [singleAddHom]
right_inv F := by
- -- Porting note: This was `ext` and used the wrong lemma
- apply Finsupp.addHom_ext'
+ ext
simp [singleAddHom, AddMonoidHom.comp, Function.comp_def]
map_add' F G := by
ext x
@@ -407,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 84b2a9a1ee80b..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
@@ -539,15 +539,18 @@ theorem prod_biUnion [DecidableEq α] {s : Finset γ} {t : γ → Finset α}
(hs : Set.PairwiseDisjoint (↑s) t) : ∏ x ∈ s.biUnion t, f x = ∏ x ∈ s, ∏ i ∈ t x, f i := by
rw [← disjiUnion_eq_biUnion _ _ hs, prod_disjiUnion]
-/-- Product over a sigma type equals the product of fiberwise products. For rewriting
+/-- The product over a sigma type equals the product of the fiberwise products. For rewriting
in the reverse direction, use `Finset.prod_sigma'`. -/
-@[to_additive "Sum over a sigma type equals the sum of fiberwise sums. For rewriting
+@[to_additive "The sum over a sigma type equals the sum of the fiberwise sums. For rewriting
in the reverse direction, use `Finset.sum_sigma'`"]
theorem prod_sigma {σ : α → Type*} (s : Finset α) (t : ∀ a, Finset (σ a)) (f : Sigma σ → β) :
∏ x ∈ s.sigma t, f x = ∏ a ∈ s, ∏ s ∈ t a, f ⟨a, s⟩ := by
simp_rw [← disjiUnion_map_sigma_mk, prod_disjiUnion, prod_map, Function.Embedding.sigmaMk_apply]
-@[to_additive]
+/-- The product over a sigma type equals the product of the fiberwise products. For rewriting
+in the reverse direction, use `Finset.prod_sigma`. -/
+@[to_additive "The sum over a sigma type equals the sum of the fiberwise sums. For rewriting
+in the reverse direction, use `Finset.sum_sigma`"]
theorem prod_sigma' {σ : α → Type*} (s : Finset α) (t : ∀ a, Finset (σ a)) (f : ∀ a, σ a → β) :
(∏ a ∈ s, ∏ s ∈ t a, f a s) = ∏ x ∈ s.sigma t, f x.1 x.2 :=
Eq.symm <| prod_sigma s t fun x => f x.1 x.2
@@ -673,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 _
@@ -701,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
@@ -756,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 :=
@@ -775,27 +778,32 @@ lemma prod_mul_prod_comm (f g h i : α → β) :
(∏ a ∈ s, f a * g a) * ∏ a ∈ s, h a * i a = (∏ a ∈ s, f a * h a) * ∏ a ∈ s, g a * i a := by
simp_rw [prod_mul_distrib, mul_mul_mul_comm]
-@[to_additive]
-theorem prod_product {s : Finset γ} {t : Finset α} {f : γ × α → β} :
+/-- The product over a product set equals the product of the fiberwise products. For rewriting
+in the reverse direction, use `Finset.prod_product'`. -/
+@[to_additive "The sum over a product set equals the sum of the fiberwise sums. For rewriting
+in the reverse direction, use `Finset.sum_product'`"]
+theorem prod_product (s : Finset γ) (t : Finset α) (f : γ × α → β) :
∏ x ∈ s ×ˢ t, f x = ∏ x ∈ s, ∏ y ∈ t, f (x, y) :=
prod_finset_product (s ×ˢ t) s (fun _a => t) fun _p => mem_product
-/-- An uncurried version of `Finset.prod_product`. -/
-@[to_additive "An uncurried version of `Finset.sum_product`"]
-theorem prod_product' {s : Finset γ} {t : Finset α} {f : γ → α → β} :
+/-- The product over a product set equals the product of the fiberwise products. For rewriting
+in the reverse direction, use `Finset.prod_product`. -/
+@[to_additive "The sum over a product set equals the sum of the fiberwise sums. For rewriting
+in the reverse direction, use `Finset.sum_product`"]
+theorem prod_product' (s : Finset γ) (t : Finset α) (f : γ → α → β) :
∏ x ∈ s ×ˢ t, f x.1 x.2 = ∏ x ∈ s, ∏ y ∈ t, f x y :=
- prod_product
+ prod_product ..
@[to_additive]
-theorem prod_product_right {s : Finset γ} {t : Finset α} {f : γ × α → β} :
+theorem prod_product_right (s : Finset γ) (t : Finset α) (f : γ × α → β) :
∏ x ∈ s ×ˢ t, f x = ∏ y ∈ t, ∏ x ∈ s, f (x, y) :=
prod_finset_product_right (s ×ˢ t) t (fun _a => s) fun _p => mem_product.trans and_comm
/-- An uncurried version of `Finset.prod_product_right`. -/
@[to_additive "An uncurried version of `Finset.sum_product_right`"]
-theorem prod_product_right' {s : Finset γ} {t : Finset α} {f : γ → α → β} :
+theorem prod_product_right' (s : Finset γ) (t : Finset α) (f : γ → α → β) :
∏ x ∈ s ×ˢ t, f x.1 x.2 = ∏ y ∈ t, ∏ x ∈ s, f x y :=
- prod_product_right
+ prod_product_right ..
/-- Generalization of `Finset.prod_comm` to the case when the inner `Finset`s depend on the outer
variable. -/
@@ -828,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]
@@ -838,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 => ?_
@@ -921,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
@@ -975,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 : κ → β)
@@ -1018,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))
@@ -1038,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]
@@ -1211,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 _
@@ -1256,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 _
@@ -1368,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
@@ -1459,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
@@ -1470,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]
@@ -1502,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]
@@ -1555,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]
@@ -1598,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
@@ -1632,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
@@ -1689,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)]
@@ -1768,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
@@ -1840,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 : β) :
@@ -2000,6 +2007,10 @@ lemma prod_ite_eq_ite_exists (p : ι → Prop) [DecidablePred p] (h : ∀ i j, p
variable [DecidableEq ι]
+@[to_additive]
+lemma prod_ite_mem (s : Finset ι) (f : ι → α) : ∏ i, (if i ∈ s then f i else 1) = ∏ i ∈ s, f i := by
+ simp
+
/-- See also `Finset.prod_dite_eq`. -/
@[to_additive "See also `Finset.sum_dite_eq`."] lemma prod_dite_eq (i : ι) (f : ∀ j, i = j → α) :
∏ j, (if h : i = j then f j h else 1) = f i rfl := by
@@ -2074,7 +2085,7 @@ theorem disjoint_list_sum_left {a : Multiset α} {l : List (Multiset α)} :
simp only [zero_disjoint, List.not_mem_nil, IsEmpty.forall_iff, forall_const, List.sum_nil]
| cons b bs ih =>
simp_rw [List.sum_cons, disjoint_add_left, List.mem_cons, forall_eq_or_imp]
- simp [and_congr_left_iff, iff_self_iff, ih]
+ simp [and_congr_left_iff, ih]
theorem disjoint_list_sum_right {a : Multiset α} {l : List (Multiset α)} :
Multiset.Disjoint a l.sum ↔ ∀ b ∈ l, Multiset.Disjoint a b := by
@@ -2093,7 +2104,7 @@ theorem disjoint_sum_right {a : Multiset α} {i : Multiset (Multiset α)} :
theorem disjoint_finset_sum_left {β : Type*} {i : Finset β} {f : β → Multiset α} {a : Multiset α} :
Multiset.Disjoint (i.sum f) a ↔ ∀ b ∈ i, Multiset.Disjoint (f b) a := by
convert @disjoint_sum_left _ a (map f i.val)
- simp [and_congr_left_iff, iff_self_iff]
+ simp [and_congr_left_iff]
theorem disjoint_finset_sum_right {β : Type*} {i : Finset β} {f : β → Multiset α}
{a : Multiset α} : Multiset.Disjoint a (i.sum f) ↔ ∀ b ∈ i, Multiset.Disjoint a (f b) := by
@@ -2246,13 +2257,9 @@ theorem toAdd_prod (s : Finset ι) (f : ι → Multiplicative α) :
end AddCommMonoid
-@[deprecated (since := "2023-12-23")] alias Equiv.prod_comp' := Fintype.prod_equiv
-@[deprecated (since := "2023-12-23")] alias Equiv.sum_comp' := Fintype.sum_equiv
-
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 bf6980cd573d9..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
@@ -125,7 +134,7 @@ theorem prod_replicate (n : ℕ) (a : M) : (replicate n a).prod = a ^ n := by
@[to_additive sum_eq_card_nsmul]
theorem prod_eq_pow_card (l : List M) (m : M) (h : ∀ x ∈ l, x = m) : l.prod = m ^ l.length := by
- rw [← prod_replicate, ← List.eq_replicate.mpr ⟨rfl, h⟩]
+ rw [← prod_replicate, ← List.eq_replicate_iff.mpr ⟨rfl, h⟩]
@[to_additive]
theorem prod_hom_rel (l : List ι) {r : M → N → Prop} {f : ι → M} {g : ι → N} (h₁ : r 1 1)
@@ -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 : ι → α} :
@@ -189,21 +198,14 @@ theorem prod_isUnit_iff {α : Type*} [CommMonoid α] {L : List α} :
exact fun m' h' ↦ Or.elim (eq_or_mem_of_mem_cons h') (fun H => H.substr h.1) fun H => ih h.2 _ H
@[to_additive (attr := simp)]
-theorem prod_take_mul_prod_drop : ∀ (L : List M) (i : ℕ), (L.take i).prod * (L.drop i).prod = L.prod
- | [], i => by simp [Nat.zero_le]
- | L, 0 => by simp
- | h :: t, n + 1 => by
- dsimp
- rw [prod_cons, prod_cons, mul_assoc, prod_take_mul_prod_drop t]
+theorem prod_take_mul_prod_drop (L : List M) (i : ℕ) :
+ (L.take i).prod * (L.drop i).prod = L.prod := by
+ simp [← prod_append]
@[to_additive (attr := simp)]
-theorem prod_take_succ :
- ∀ (L : List M) (i : ℕ) (p : i < L.length), (L.take (i + 1)).prod = (L.take i).prod * L[i]
- | [], i, p => by cases p
- | h :: t, 0, _ => rfl
- | h :: t, n + 1, p => by
- dsimp
- rw [prod_cons, prod_cons, prod_take_succ t n (Nat.lt_of_succ_lt_succ p), mul_assoc]
+theorem prod_take_succ (L : List M) (i : ℕ) (p : i < L.length) :
+ (L.take (i + 1)).prod = (L.take i).prod * L[i] := by
+ simp [take_succ, p]
/-- A list with product not one must have positive length. -/
@[to_additive "A list with sum not zero must have positive length."]
@@ -273,9 +275,9 @@ last. -/
@[to_additive
"A variant of `sum_range_succ` which pulls off the first term in the sum rather than the last."]
lemma prod_range_succ' (f : ℕ → M) (n : ℕ) :
- ((range n.succ).map f).prod = f 0 * ((range n).map fun i ↦ f i.succ).prod :=
- Nat.recOn n (show 1 * f 0 = f 0 * 1 by rw [one_mul, mul_one]) fun _ hd => by
- rw [List.prod_range_succ, hd, mul_assoc, ← List.prod_range_succ]
+ ((range n.succ).map f).prod = f 0 * ((range n).map fun i ↦ f i.succ).prod := by
+ rw [range_succ_eq_map]
+ simp [Function.comp_def]
@[to_additive] lemma prod_eq_one (hl : ∀ x ∈ l, x = 1) : l.prod = 1 := by
induction l with
@@ -322,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
@@ -349,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.fold_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
@@ -426,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)
@@ -625,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 Nat.add_comm Nat.add_assoc _ _).symm
+@[simp] lemma Nat.sum_eq_listSum (l : List ℕ) : Nat.sum l = l.sum := rfl
namespace List
@@ -646,20 +646,15 @@ lemma ranges_join (l : List ℕ) : l.ranges.join = range l.sum := by simp [range
lemma mem_mem_ranges_iff_lt_sum (l : List ℕ) {n : ℕ} :
(∃ s ∈ l.ranges, n ∈ s) ↔ n < l.sum := by simp [mem_mem_ranges_iff_lt_natSum]
-lemma countP_join (p : α → Bool) : ∀ L : List (List α), countP p L.join = (L.map (countP p)).sum
- | [] => rfl
- | a :: l => by rw [join, countP_append, map_cons, sum_cons, countP_join _ l]
-
-lemma count_join [BEq α] (L : List (List α)) (a : α) : L.join.count a = (L.map (count a)).sum :=
- countP_join _ _
-
@[simp]
theorem length_bind (l : List α) (f : α → List β) :
length (List.bind l f) = sum (map (length ∘ f) l) := by
rw [List.bind, length_join, map_map, Nat.sum_eq_listSum]
lemma countP_bind (p : β → Bool) (l : List α) (f : α → List β) :
- countP p (l.bind f) = sum (map (countP p ∘ f) l) := by rw [List.bind, countP_join, map_map]
+ countP p (l.bind f) = sum (map (countP p ∘ f) l) := by
+ rw [List.bind, countP_join, map_map]
+ simp
lemma count_bind [BEq β] (l : List α) (f : α → List β) (x : β) :
count x (l.bind f) = sum (map (count x ∘ f) l) := countP_bind _ _ _
diff --git a/Mathlib/Algebra/BigOperators/Group/Multiset.lean b/Mathlib/Algebra/BigOperators/Group/Multiset.lean
index 0d5d2fc6e95ea..a0bb921c056e3 100644
--- a/Mathlib/Algebra/BigOperators/Group/Multiset.lean
+++ b/Mathlib/Algebra/BigOperators/Group/Multiset.lean
@@ -36,21 +36,20 @@ variable [CommMonoid α] [CommMonoid β] {s t : Multiset α} {a : α} {m : Multi
"Sum of a multiset given a commutative additive monoid structure on `α`.
`sum {a, b, c} = a + b + c`"]
def prod : Multiset α → α :=
- foldr (· * ·) (fun x y z => by simp [mul_left_comm]) 1
+ foldr (· * ·) 1
@[to_additive]
theorem prod_eq_foldr (s : Multiset α) :
- prod s = foldr (· * ·) (fun x y z => by simp [mul_left_comm]) 1 s :=
+ prod s = foldr (· * ·) 1 s :=
rfl
@[to_additive]
theorem prod_eq_foldl (s : Multiset α) :
- prod s = foldl (· * ·) (fun x y z => by simp [mul_right_comm]) 1 s :=
- (foldr_swap _ _ _ _).trans (by simp [mul_comm])
+ prod s = foldl (· * ·) 1 s :=
+ (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
@@ -63,7 +62,7 @@ theorem prod_zero : @prod α _ 0 = 1 :=
@[to_additive (attr := simp)]
theorem prod_cons (a : α) (s) : prod (a ::ₘ s) = a * prod s :=
- foldr_cons _ _ _ _ _
+ foldr_cons _ _ _ _
@[to_additive (attr := simp)]
theorem prod_erase [DecidableEq α] (h : a ∈ s) : a * (s.erase a).prod = s.prod := by
@@ -122,6 +121,12 @@ lemma prod_eq_one (h : ∀ x ∈ s, x = (1 : α)) : s.prod = 1 := by
theorem pow_count [DecidableEq α] (a : α) : a ^ s.count a = (s.filter (Eq a)).prod := by
rw [filter_eq, prod_replicate]
+@[to_additive]
+theorem prod_hom_ne_zero {s : Multiset α} (hs : s ≠ 0) {F : Type*} [FunLike F α β]
+ [MulHomClass F α β] (f : F) :
+ (s.map f).prod = f s.prod := by
+ induction s using Quot.inductionOn; aesop (add simp List.prod_hom_nonempty)
+
@[to_additive]
theorem prod_hom (s : Multiset α) {F : Type*} [FunLike F α β]
[MonoidHomClass F α β] (f : F) :
@@ -135,6 +140,12 @@ theorem prod_hom' (s : Multiset ι) {F : Type*} [FunLike F α β]
convert (s.map g).prod_hom f
exact (map_map _ _ _).symm
+@[to_additive]
+theorem prod_hom₂_ne_zero [CommMonoid γ] {s : Multiset ι} (hs : s ≠ 0) (f : α → β → γ)
+ (hf : ∀ a b c d, f (a * b) (c * d) = f a c * f b d) (f₁ : ι → α) (f₂ : ι → β) :
+ (s.map fun i => f (f₁ i) (f₂ i)).prod = f (s.map f₁).prod (s.map f₂).prod := by
+ induction s using Quotient.inductionOn; aesop (add simp List.prod_hom₂_nonempty)
+
@[to_additive]
theorem prod_hom₂ [CommMonoid γ] (s : Multiset ι) (f : α → β → γ)
(hf : ∀ a b c d, f (a * b) (c * d) = f a c * f b d) (hf' : f 1 1 = 1) (f₁ : ι → α)
@@ -171,7 +182,7 @@ theorem prod_map_prod_map (m : Multiset β') (n : Multiset γ) {f : β' → γ
theorem prod_induction (p : α → Prop) (s : Multiset α) (p_mul : ∀ a b, p a → p b → p (a * b))
(p_one : p 1) (p_s : ∀ a ∈ s, p a) : p s.prod := by
rw [prod_eq_foldr]
- exact foldr_induction (· * ·) (fun x y z => by simp [mul_left_comm]) 1 p s p_mul p_one p_s
+ exact foldr_induction (· * ·) 1 p s p_mul p_one p_s
@[to_additive]
theorem prod_induction_nonempty (p : α → Prop) (p_mul : ∀ a b, p a → p b → p (a * b)) (hs : s ≠ ∅)
@@ -194,10 +205,19 @@ theorem prod_dvd_prod_of_le (h : s ≤ t) : s.prod ∣ t.prod := by
lemma _root_.map_multiset_prod [FunLike F α β] [MonoidHomClass F α β] (f : F) (s : Multiset α) :
f s.prod = (s.map f).prod := (s.prod_hom f).symm
+@[to_additive]
+lemma _root_.map_multiset_ne_zero_prod [FunLike F α β] [MulHomClass F α β] (f : F)
+ {s : Multiset α} (hs : s ≠ 0):
+ f s.prod = (s.map f).prod := (s.prod_hom_ne_zero hs f).symm
+
@[to_additive]
protected lemma _root_.MonoidHom.map_multiset_prod (f : α →* β) (s : Multiset α) :
f s.prod = (s.map f).prod := (s.prod_hom f).symm
+@[to_additive]
+protected lemma _root_.MulHom.map_multiset_ne_zero_prod (f : α →ₙ* β) (s : Multiset α)
+ (hs : s ≠ 0) : f s.prod = (s.map f).prod := (s.prod_hom_ne_zero hs f).symm
+
lemma dvd_prod : a ∈ s → a ∣ s.prod :=
Quotient.inductionOn s (fun l a h ↦ by simpa using List.dvd_prod h) a
@@ -273,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 7ad7cb7f697d9..6f377d4ff77be 100644
--- a/Mathlib/Algebra/BigOperators/GroupWithZero/Action.lean
+++ b/Mathlib/Algebra/BigOperators/GroupWithZero/Action.lean
@@ -12,6 +12,13 @@ import Mathlib.Algebra.BigOperators.Finprod
/-!
# Lemmas about group actions on big operators
+This file contains results about two kinds of actions:
+
+* sums over `DistribSMul`: `r • ∑ x ∈ s, f x = ∑ x ∈ s, r • f x`
+* products over `MulDistribMulAction` (with primed name): `r • ∏ x ∈ s, f x = ∏ x ∈ s, r • f x`
+* products over `SMulCommClass` (with unprimed name):
+ `b ^ s.card • ∏ x in s, f x = ∏ x in s, b • f x`
+
Note that analogous lemmas for `Module`s like `Finset.sum_smul` appear in other files.
-/
@@ -31,7 +38,7 @@ section
variable [Monoid α] [Monoid β] [MulDistribMulAction α β]
-theorem List.smul_prod {r : α} {l : List β} : r • l.prod = (l.map (r • ·)).prod :=
+theorem List.smul_prod' {r : α} {l : List β} : r • l.prod = (l.map (r • ·)).prod :=
map_list_prod (MulDistribMulAction.toMonoidHom β r) l
end
@@ -53,17 +60,72 @@ section
variable [Monoid α] [CommMonoid β] [MulDistribMulAction α β]
-theorem Multiset.smul_prod {r : α} {s : Multiset β} : r • s.prod = (s.map (r • ·)).prod :=
+theorem Multiset.smul_prod' {r : α} {s : Multiset β} : r • s.prod = (s.map (r • ·)).prod :=
(MulDistribMulAction.toMonoidHom β r).map_multiset_prod s
-theorem Finset.smul_prod {r : α} {f : γ → β} {s : Finset γ} :
+theorem Finset.smul_prod' {r : α} {f : γ → β} {s : Finset γ} :
(r • ∏ x ∈ s, f x) = ∏ x ∈ s, r • f x :=
map_prod (MulDistribMulAction.toMonoidHom β r) f s
-theorem smul_finprod {ι : Sort*} [Finite ι] {f : ι → β} (r : α) :
+theorem smul_finprod' {ι : Sort*} [Finite ι] {f : ι → β} (r : α) :
r • ∏ᶠ x : ι, f x = ∏ᶠ x : ι, r • (f x) := by
cases nonempty_fintype (PLift ι)
simp only [finprod_eq_prod_plift_of_mulSupport_subset (s := Finset.univ) (by simp),
- finprod_eq_prod_of_fintype, Finset.smul_prod]
+ 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
+
+@[to_additive]
+theorem smul_prod [Monoid α] [Monoid β] [MulAction α β] [IsScalarTower α β β] [SMulCommClass α β β]
+ (l : List β) (m : α) :
+ m ^ l.length • l.prod = (l.map (m • ·)).prod := by
+ induction l with
+ | nil => simp
+ | cons head tail ih => simp [← ih, smul_mul_smul_comm, pow_succ']
+
+end List
+
+namespace Multiset
+
+@[to_additive]
+theorem smul_prod [Monoid α] [CommMonoid β] [MulAction α β] [IsScalarTower α β β]
+ [SMulCommClass α β β] (s : Multiset β) (b : α) :
+ b ^ card s • s.prod = (s.map (b • ·)).prod :=
+ Quot.induction_on s <| by simp [List.smul_prod]
+
+end Multiset
+
+namespace Finset
+
+theorem smul_prod
+ [CommMonoid β] [Monoid α] [MulAction α β] [IsScalarTower α β β] [SMulCommClass α β β]
+ (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 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]
+
+theorem prod_smul
+ [CommMonoid β] [CommMonoid α] [MulAction α β] [IsScalarTower α β β] [SMulCommClass α β β]
+ (s : Finset β) (b : β → α) (f : β → β) :
+ ∏ i in s, b i • f i = (∏ i in s, b i) • ∏ i in s, f i := by
+ induction s using Finset.cons_induction_on with
+ | h₁ => simp
+ | h₂ hj ih => rw [prod_cons, ih, smul_mul_smul_comm, ← prod_cons hj, ← prod_cons hj]
+
+end Finset
diff --git a/Mathlib/Algebra/BigOperators/Intervals.lean b/Mathlib/Algebra/BigOperators/Intervals.lean
index fffc916fc80ef..00cf03b53b607 100644
--- a/Mathlib/Algebra/BigOperators/Intervals.lean
+++ b/Mathlib/Algebra/BigOperators/Intervals.lean
@@ -99,6 +99,12 @@ theorem prod_Ico_add [OrderedCancelAddCommMonoid α] [ExistsAddOfLE α] [Locally
convert prod_Ico_add' f a b c using 2
rw [add_comm]
+@[to_additive (attr := simp)]
+theorem prod_Ico_add_right_sub_eq [OrderedCancelAddCommMonoid α] [ExistsAddOfLE α]
+ [LocallyFiniteOrder α] [Sub α] [OrderedSub α] (a b c : α) :
+ ∏ x ∈ Ico (a + c) (b + c), f (x - c) = ∏ x ∈ Ico a b, f x := by
+ simp only [← map_add_right_Ico, prod_map, addRightEmbedding_apply, add_tsub_cancel_right]
+
@[to_additive]
theorem prod_Ico_succ_top {a b : ℕ} (hab : a ≤ b) (f : ℕ → M) :
(∏ k ∈ Ico a (b + 1), f k) = (∏ k ∈ Ico a b, f k) * f b := by
@@ -138,6 +144,11 @@ theorem prod_range_mul_prod_Ico (f : ℕ → M) {m n : ℕ} (h : m ≤ n) :
((∏ k ∈ range m, f k) * ∏ k ∈ Ico m n, f k) = ∏ k ∈ range n, f k :=
Nat.Ico_zero_eq_range ▸ Nat.Ico_zero_eq_range ▸ prod_Ico_consecutive f m.zero_le h
+@[to_additive]
+theorem prod_range_eq_mul_Ico (f : ℕ → M) {n : ℕ} (hn : 0 < n) :
+ ∏ x ∈ Finset.range n, f x = f 0 * ∏ x ∈ Ico 1 n, f x :=
+ Finset.range_eq_Ico ▸ Finset.prod_eq_prod_Ico_succ_bot hn f
+
@[to_additive]
theorem prod_Ico_eq_mul_inv {δ : Type*} [CommGroup δ] (f : ℕ → δ) {m n : ℕ} (h : m ≤ n) :
∏ k ∈ Ico m n, f k = (∏ k ∈ range n, f k) * (∏ k ∈ range m, f k)⁻¹ :=
@@ -241,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/Module.lean b/Mathlib/Algebra/BigOperators/Module.lean
index fd9ddbeeb76ee..2329df72948f4 100644
--- a/Mathlib/Algebra/BigOperators/Module.lean
+++ b/Mathlib/Algebra/BigOperators/Module.lean
@@ -31,24 +31,9 @@ theorem sum_Ico_by_parts (hmn : m < n) :
rw [← sum_Ico_sub_bot _ hmn, ← sum_Ico_succ_sub_top _ (Nat.le_sub_one_of_lt hmn),
Nat.sub_add_cancel (pos_of_gt hmn), sub_add_cancel]
rw [sum_eq_sum_Ico_succ_bot hmn]
- -- Porting note: the following used to be done with `conv`
- have h₃ : (Finset.sum (Ico (m + 1) n) fun i => f i • g i) =
- (Finset.sum (Ico (m + 1) n) fun i =>
- f i • ((Finset.sum (Finset.range (i + 1)) g) -
- (Finset.sum (Finset.range i) g))) := by
- congr; funext; rw [← sum_range_succ_sub_sum g]
- rw [h₃]
+ conv in (occs := 3) (f _ • g _) => rw [← sum_range_succ_sub_sum g]
simp_rw [smul_sub, sum_sub_distrib, h₂, h₁]
- -- Porting note: the following used to be done with `conv`
- have h₄ : ((((Finset.sum (Ico m (n - 1)) fun i => f i • Finset.sum (range (i + 1)) fun i => g i) +
- f (n - 1) • Finset.sum (range n) fun i => g i) -
- f m • Finset.sum (range (m + 1)) fun i => g i) -
- Finset.sum (Ico m (n - 1)) fun i => f (i + 1) • Finset.sum (range (i + 1)) fun i => g i) =
- f (n - 1) • (range n).sum g - f m • (range (m + 1)).sum g +
- Finset.sum (Ico m (n - 1)) (fun i => f i • (range (i + 1)).sum g -
- f (i + 1) • (range (i + 1)).sum g) := by
- rw [← add_sub, add_comm, ← add_sub, ← sum_sub_distrib]
- rw [h₄]
+ conv_lhs => congr; rfl; rw [← add_sub, add_comm, ← add_sub, ← sum_sub_distrib]
have : ∀ i, f i • G (i + 1) - f (i + 1) • G (i + 1) = -((f (i + 1) - f i) • G (i + 1)) := by
intro i
rw [sub_smul]
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 0cf28cc97f8a8..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
@@ -110,7 +110,7 @@ lemma prod_sum (s : Finset ι) (t : ∀ i, Finset (κ i)) (f : ∀ i, κ i →
∏ a ∈ s, ∑ b ∈ t a, f a b = ∑ p ∈ s.pi t, ∏ x ∈ s.attach, f x.1 (p x.1 x.2) := by
classical
induction s using Finset.induction with
- | empty => rw [pi_empty, sum_singleton]; rfl
+ | empty => simp
| insert ha ih =>
rename_i a s
have h₁ : ∀ x ∈ t a, ∀ y ∈ t a, x ≠ y →
@@ -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/Bounds.lean b/Mathlib/Algebra/Bounds.lean
deleted file mode 100644
index 8c9ff1cb53079..0000000000000
--- a/Mathlib/Algebra/Bounds.lean
+++ /dev/null
@@ -1,167 +0,0 @@
-/-
-Copyright (c) 2021 Yury Kudryashov. All rights reserved.
-Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Yury Kudryashov
--/
-import Mathlib.Algebra.Group.Pointwise.Set
-import Mathlib.Algebra.Order.Group.OrderIso
-import Mathlib.Algebra.Order.Monoid.Unbundled.OrderDual
-import Mathlib.Order.Bounds.OrderIso
-import Mathlib.Order.ConditionallyCompleteLattice.Basic
-
-/-!
-# Upper/lower bounds in ordered monoids and groups
-
-In this file we prove a few facts like “`-s` is bounded above iff `s` is bounded below”
-(`bddAbove_neg`).
--/
-
-
-open Function Set
-
-open Pointwise
-
-section InvNeg
-
-variable {G : Type*} [Group G] [Preorder G] [CovariantClass G G (· * ·) (· ≤ ·)]
- [CovariantClass G G (swap (· * ·)) (· ≤ ·)] {s : Set G} {a : G}
-
-@[to_additive (attr := simp)]
-theorem bddAbove_inv : BddAbove s⁻¹ ↔ BddBelow s :=
- (OrderIso.inv G).bddAbove_preimage
-
-@[to_additive (attr := simp)]
-theorem bddBelow_inv : BddBelow s⁻¹ ↔ BddAbove s :=
- (OrderIso.inv G).bddBelow_preimage
-
-@[to_additive]
-theorem BddAbove.inv (h : BddAbove s) : BddBelow s⁻¹ :=
- bddBelow_inv.2 h
-
-@[to_additive]
-theorem BddBelow.inv (h : BddBelow s) : BddAbove s⁻¹ :=
- bddAbove_inv.2 h
-
-@[to_additive (attr := simp)]
-theorem isLUB_inv : IsLUB s⁻¹ a ↔ IsGLB s a⁻¹ :=
- (OrderIso.inv G).isLUB_preimage
-
-@[to_additive]
-theorem isLUB_inv' : IsLUB s⁻¹ a⁻¹ ↔ IsGLB s a :=
- (OrderIso.inv G).isLUB_preimage'
-
-@[to_additive]
-theorem IsGLB.inv (h : IsGLB s a) : IsLUB s⁻¹ a⁻¹ :=
- isLUB_inv'.2 h
-
-@[to_additive (attr := simp)]
-theorem isGLB_inv : IsGLB s⁻¹ a ↔ IsLUB s a⁻¹ :=
- (OrderIso.inv G).isGLB_preimage
-
-@[to_additive]
-theorem isGLB_inv' : IsGLB s⁻¹ a⁻¹ ↔ IsLUB s a :=
- (OrderIso.inv G).isGLB_preimage'
-
-@[to_additive]
-theorem IsLUB.inv (h : IsLUB s a) : IsGLB s⁻¹ a⁻¹ :=
- isGLB_inv'.2 h
-
-@[to_additive]
-lemma BddBelow.range_inv {α : Type*} {f : α → G} (hf : BddBelow (range f)) :
- BddAbove (range (fun x => (f x)⁻¹)) :=
- hf.range_comp (OrderIso.inv G).monotone
-
-@[to_additive]
-lemma BddAbove.range_inv {α : Type*} {f : α → G} (hf : BddAbove (range f)) :
- BddBelow (range (fun x => (f x)⁻¹)) :=
- BddBelow.range_inv (G := Gᵒᵈ) hf
-
-end InvNeg
-
-section mul_add
-
-variable {M : Type*} [Mul M] [Preorder M] [CovariantClass M M (· * ·) (· ≤ ·)]
- [CovariantClass M M (swap (· * ·)) (· ≤ ·)]
-
-@[to_additive]
-theorem mul_mem_upperBounds_mul {s t : Set M} {a b : M} (ha : a ∈ upperBounds s)
- (hb : b ∈ upperBounds t) : a * b ∈ upperBounds (s * t) :=
- forall_image2_iff.2 fun _ hx _ hy => mul_le_mul' (ha hx) (hb hy)
-
-@[to_additive]
-theorem subset_upperBounds_mul (s t : Set M) :
- upperBounds s * upperBounds t ⊆ upperBounds (s * t) :=
- image2_subset_iff.2 fun _ hx _ hy => mul_mem_upperBounds_mul hx hy
-
-@[to_additive]
-theorem mul_mem_lowerBounds_mul {s t : Set M} {a b : M} (ha : a ∈ lowerBounds s)
- (hb : b ∈ lowerBounds t) : a * b ∈ lowerBounds (s * t) :=
- mul_mem_upperBounds_mul (M := Mᵒᵈ) ha hb
-
-@[to_additive]
-theorem subset_lowerBounds_mul (s t : Set M) :
- lowerBounds s * lowerBounds t ⊆ lowerBounds (s * t) :=
- subset_upperBounds_mul (M := Mᵒᵈ) _ _
-
-@[to_additive]
-theorem BddAbove.mul {s t : Set M} (hs : BddAbove s) (ht : BddAbove t) : BddAbove (s * t) :=
- (Nonempty.mul hs ht).mono (subset_upperBounds_mul s t)
-
-@[to_additive]
-theorem BddBelow.mul {s t : Set M} (hs : BddBelow s) (ht : BddBelow t) : BddBelow (s * t) :=
- (Nonempty.mul hs ht).mono (subset_lowerBounds_mul s t)
-
-@[to_additive]
-lemma BddAbove.range_mul {α : Type*} {f g : α → M} (hf : BddAbove (range f))
- (hg : BddAbove (range g)) : BddAbove (range (fun x => f x * g x)) :=
- BddAbove.range_comp (f := fun x => (⟨f x, g x⟩ : M × M))
- (bddAbove_range_prod.mpr ⟨hf, hg⟩) (Monotone.mul' monotone_fst monotone_snd)
-
-@[to_additive]
-lemma BddBelow.range_mul {α : Type*} {f g : α → M} (hf : BddBelow (range f))
- (hg : BddBelow (range g)) : BddBelow (range (fun x => f x * g x)) :=
- BddAbove.range_mul (M := Mᵒᵈ) hf hg
-
-end mul_add
-
-section ConditionallyCompleteLattice
-
-section Right
-
-variable {ι G : Type*} [Group G] [ConditionallyCompleteLattice G]
- [CovariantClass G G (Function.swap (· * ·)) (· ≤ ·)] [Nonempty ι] {f : ι → G}
-
-@[to_additive]
-theorem ciSup_mul (hf : BddAbove (range f)) (a : G) : (⨆ i, f i) * a = ⨆ i, f i * a :=
- (OrderIso.mulRight a).map_ciSup hf
-
-@[to_additive]
-theorem ciSup_div (hf : BddAbove (range f)) (a : G) : (⨆ i, f i) / a = ⨆ i, f i / a := by
- simp only [div_eq_mul_inv, ciSup_mul hf]
-
-@[to_additive]
-theorem ciInf_mul (hf : BddBelow (range f)) (a : G) : (⨅ i, f i) * a = ⨅ i, f i * a :=
- (OrderIso.mulRight a).map_ciInf hf
-
-@[to_additive]
-theorem ciInf_div (hf : BddBelow (range f)) (a : G) : (⨅ i, f i) / a = ⨅ i, f i / a := by
- simp only [div_eq_mul_inv, ciInf_mul hf]
-
-end Right
-
-section Left
-
-variable {ι : Sort*} {G : Type*} [Group G] [ConditionallyCompleteLattice G]
- [CovariantClass G G (· * ·) (· ≤ ·)] [Nonempty ι] {f : ι → G}
-
-@[to_additive]
-theorem mul_ciSup (hf : BddAbove (range f)) (a : G) : (a * ⨆ i, f i) = ⨆ i, a * f i :=
- (OrderIso.mulLeft a).map_ciSup hf
-
-@[to_additive]
-theorem mul_ciInf (hf : BddBelow (range f)) (a : G) : (a * ⨅ i, f i) = ⨅ i, a * f i :=
- (OrderIso.mulLeft a).map_ciInf hf
-
-end Left
-
-end ConditionallyCompleteLattice
diff --git a/Mathlib/Algebra/Category/AlgebraCat/Basic.lean b/Mathlib/Algebra/Category/AlgebraCat/Basic.lean
index 6d3c2563e4879..bafe58b5b5db8 100644
--- a/Mathlib/Algebra/Category/AlgebraCat/Basic.lean
+++ b/Mathlib/Algebra/Category/AlgebraCat/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Algebra.Subalgebra.Basic
import Mathlib.Algebra.FreeAlgebra
@@ -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 bdbde8808325a..7957211163d58 100644
--- a/Mathlib/Algebra/Category/AlgebraCat/Limits.lean
+++ b/Mathlib/Algebra/Category/AlgebraCat/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.AlgebraCat.Basic
import Mathlib.Algebra.Category.ModuleCat.Basic
@@ -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 cd040c2eefb18..28e837f52f457 100644
--- a/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean
+++ b/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean
@@ -55,43 +55,14 @@ instance : MonoidalCategoryStruct (AlgebraCat.{u} R) where
leftUnitor X := (Algebra.TensorProduct.lid R X).toAlgebraIso
rightUnitor X := (Algebra.TensorProduct.rid R R X).toAlgebraIso
-theorem forget₂_map_associator_hom (X Y Z : AlgebraCat.{u} R) :
- (forget₂ (AlgebraCat R) (ModuleCat R)).map (α_ X Y Z).hom =
- (α_
- (forget₂ _ (ModuleCat R) |>.obj X)
- (forget₂ _ (ModuleCat R) |>.obj Y)
- (forget₂ _ (ModuleCat R) |>.obj Z)).hom := by
- rfl
-
-theorem forget₂_map_associator_inv (X Y Z : AlgebraCat.{u} R) :
- (forget₂ (AlgebraCat R) (ModuleCat R)).map (α_ X Y Z).inv =
- (α_
- (forget₂ _ (ModuleCat R) |>.obj X)
- (forget₂ _ (ModuleCat R) |>.obj Y)
- (forget₂ _ (ModuleCat R) |>.obj Z)).inv := by
- rfl
-
-set_option maxHeartbeats 800000 in
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 => by
- dsimp only [forget₂_module_obj, forget₂_map_associator_hom]
- simp only [eqToIso_refl, Iso.refl_trans, Iso.refl_symm, Iso.trans_hom,
- MonoidalCategory.tensorIso_hom, Iso.refl_hom, MonoidalCategory.tensor_id]
- erw [Category.id_comp, Category.comp_id, MonoidalCategory.tensor_id, Category.id_comp]
- leftUnitor_eq := fun X => by
- dsimp only [forget₂_module_obj, forget₂_module_map, Iso.refl_symm, Iso.trans_hom,
- Iso.refl_hom, MonoidalCategory.tensorIso_hom]
- erw [Category.id_comp, MonoidalCategory.tensor_id, Category.id_comp]
- rfl
- rightUnitor_eq := fun X => by
- dsimp
- erw [Category.id_comp, MonoidalCategory.tensor_id, Category.id_comp]
- exact congr_arg LinearEquiv.toLinearMap <|
- TensorProduct.AlgebraTensorModule.rid_eq_rid R X }
+ 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 9936f06b55a0f..0a138d78803f1 100644
--- a/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean
+++ b/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean
@@ -15,7 +15,7 @@ Given a commutative ring `R`, this file defines the equivalence of categories be
`R`-coalgebras and comonoid objects in the category of `R`-modules.
We then use this to set up boilerplate for the `Coalgebra` instance on a tensor product of
-coalgebras defined in `Mathlib.RingTheory.Coalgebra.TensorProduct` in #11975.
+coalgebras defined in `Mathlib.RingTheory.Coalgebra.TensorProduct`.
## Implementation notes
@@ -23,7 +23,7 @@ We make the definition `CoalgebraCat.instMonoidalCategoryAux` in this file, whic
monoidal structure on `CoalgebraCat` induced by the equivalence with `Comon(R-Mod)`. We
use this to show the comultiplication and counit on a tensor product of coalgebras satisfy
the coalgebra axioms, but our actual `MonoidalCategory` instance on `CoalgebraCat` is
-constructed in `Mathlib.Algebra.Category.CoalgebraCat.Monoidal` in #11976 to have better
+constructed in `Mathlib.Algebra.Category.CoalgebraCat.Monoidal` to have better
definitional equalities.
-/
@@ -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 }
@@ -96,7 +96,7 @@ variable {R}
/-- The monoidal category structure on the category of `R`-coalgebras induced by the
equivalence with `Comon(R-Mod)`. This is just an auxiliary definition; the `MonoidalCategory`
-instance we make in `Mathlib.Algebra.Category.CoalgebraCat.Monoidal` in #11976 will have better
+instance we make in `Mathlib.Algebra.Category.CoalgebraCat.Monoidal` has better
definitional equalities. -/
noncomputable def instMonoidalCategoryAux : MonoidalCategory (CoalgebraCat R) :=
Monoidal.transport (comonEquivalence R).symm
@@ -116,9 +116,10 @@ theorem tensorObj_comul (K L : CoalgebraCat R) :
= (TensorProduct.tensorTensorTensorComm R K K L L).toLinearMap
∘ₗ TensorProduct.map Coalgebra.comul Coalgebra.comul := by
rw [ofComonObjCoalgebraStruct_comul]
- dsimp [ModuleCat.ofHom, -Mon_.monMonoidalStruct_tensorObj_X,
- instMonoidalCategoryStruct_tensorHom, ModuleCat.comp_def]
- simp only [BraidedCategory.unop_tensor_μ, tensor_μ_eq_tensorTensorTensorComm]
+ dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj]
+ simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, ModuleCat.of_coe, toComonObj_comul,
+ tensor_μ_eq_tensorTensorTensorComm]
+ rfl
theorem tensorHom_toLinearMap (f : M →ₗc[R] N) (g : P →ₗc[R] Q) :
(CoalgebraCat.ofHom f ⊗ CoalgebraCat.ofHom g).1.toLinearMap
@@ -143,22 +144,26 @@ theorem comul_tensorObj :
Coalgebra.comul (R := R) (A := (CoalgebraCat.of R M ⊗ CoalgebraCat.of R N : CoalgebraCat R))
= Coalgebra.comul (A := M ⊗[R] N) := by
rw [ofComonObjCoalgebraStruct_comul]
- dsimp [- Mon_.monMonoidalStruct_tensorObj_X, instMonoidalCategoryStruct_tensorHom,
- ModuleCat.comp_def, ModuleCat.ofHom, ModuleCat.of]
- simp only [BraidedCategory.unop_tensor_μ, tensor_μ_eq_tensorTensorTensorComm]
+ dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj,
+ instCoalgebraStruct_comul]
+ simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, of_carrier, of_isAddCommGroup,
+ of_isModule, toComonObj_comul, of_instCoalgebra, tensor_μ_eq_tensorTensorTensorComm]
+ rfl
theorem comul_tensorObj_tensorObj_right :
Coalgebra.comul (R := R) (A := (CoalgebraCat.of R M ⊗
(CoalgebraCat.of R N ⊗ CoalgebraCat.of R P) : CoalgebraCat R))
= Coalgebra.comul (A := M ⊗[R] N ⊗[R] P) := by
rw [ofComonObjCoalgebraStruct_comul]
- dsimp [- Mon_.monMonoidalStruct_tensorObj_X, instMonoidalCategoryStruct_tensorHom,
- ModuleCat.comp_def, ModuleCat.ofHom, ModuleCat.of]
+ dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj,
+ instCoalgebraStruct_comul]
+ simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, of_carrier, of_isAddCommGroup,
+ of_isModule, ModuleCat.of_coe, toComonObj_comul, of_instCoalgebra]
rw [ofComonObjCoalgebraStruct_comul]
- dsimp [- Mon_.monMonoidalStruct_tensorObj_X, instMonoidalCategoryStruct_tensorHom,
- ModuleCat.comp_def, ModuleCat.ofHom, ModuleCat.of]
+ dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj]
simp only [instMonoidalCategoryStruct_tensorObj, ModuleCat.MonoidalCategory.tensorObj,
- ModuleCat.coe_of, BraidedCategory.unop_tensor_μ, tensor_μ_eq_tensorTensorTensorComm]
+ ModuleCat.coe_of, Comon_.monoidal_tensorObj_comul, toComonObj_X, of_carrier, of_isAddCommGroup,
+ of_isModule, toComonObj_comul, of_instCoalgebra, tensor_μ_eq_tensorTensorTensorComm]
rfl
theorem comul_tensorObj_tensorObj_left :
@@ -166,13 +171,15 @@ theorem comul_tensorObj_tensorObj_left :
(A := ((CoalgebraCat.of R M ⊗ CoalgebraCat.of R N) ⊗ CoalgebraCat.of R P : CoalgebraCat R))
= Coalgebra.comul (A := (M ⊗[R] N) ⊗[R] P) := by
rw [ofComonObjCoalgebraStruct_comul]
- dsimp [- Mon_.monMonoidalStruct_tensorObj_X, instMonoidalCategoryStruct_tensorHom,
- ModuleCat.comp_def, ModuleCat.ofHom, ModuleCat.of]
+ dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj,
+ instCoalgebraStruct_comul]
+ simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, ModuleCat.of_coe, of_carrier,
+ of_isAddCommGroup, of_isModule, toComonObj_comul, of_instCoalgebra]
rw [ofComonObjCoalgebraStruct_comul]
- dsimp [- Mon_.monMonoidalStruct_tensorObj_X, instMonoidalCategoryStruct_tensorHom,
- ModuleCat.comp_def, ModuleCat.ofHom, ModuleCat.of]
+ dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj]
simp only [instMonoidalCategoryStruct_tensorObj, ModuleCat.MonoidalCategory.tensorObj,
- ModuleCat.coe_of, BraidedCategory.unop_tensor_μ, tensor_μ_eq_tensorTensorTensorComm]
+ ModuleCat.coe_of, Comon_.monoidal_tensorObj_comul, toComonObj_X, of_carrier, of_isAddCommGroup,
+ of_isModule, toComonObj_comul, of_instCoalgebra, tensor_μ_eq_tensorTensorTensorComm]
rfl
theorem counit_tensorObj :
diff --git a/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean b/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean
new file mode 100644
index 0000000000000..dbd37c50e0b59
--- /dev/null
+++ b/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean
@@ -0,0 +1,60 @@
+/-
+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.Coalgebra.TensorProduct
+
+/-!
+# The monoidal category structure on `R`-coalgebras
+
+In `Mathlib.RingTheory.Coalgebra.TensorProduct`, given two `R`-coalgebras `M, N`, we define a
+coalgebra instance on `M ⊗[R] N`, as well as the tensor product of two `CoalgHom`s as a
+`CoalgHom`, and the associator and left/right unitors for coalgebras as `CoalgEquiv`s.
+
+In this file, we declare a `MonoidalCategory` instance on the category of coalgebras, with data
+fields given by the definitions in `Mathlib.RingTheory.Coalgebra.TensorProduct`, and Prop
+fields proved by pulling back the `MonoidalCategory` instance on the category of modules,
+using `Monoidal.induced`.
+
+-/
+
+universe v u
+
+namespace CoalgebraCat
+variable (R : Type u) [CommRing R]
+
+open CategoryTheory Coalgebra
+open scoped TensorProduct MonoidalCategory
+
+@[simps]
+noncomputable instance instMonoidalCategoryStruct :
+ MonoidalCategoryStruct.{u} (CoalgebraCat R) where
+ tensorObj X Y := of R (X ⊗[R] Y)
+ whiskerLeft X _ _ f := ofHom (f.1.lTensor X)
+ whiskerRight f X := ofHom (f.1.rTensor X)
+ tensorHom f g := ofHom (Coalgebra.TensorProduct.map f.1 g.1)
+ tensorUnit := CoalgebraCat.of R R
+ associator X Y Z := (Coalgebra.TensorProduct.assoc R X Y Z).toCoalgebraCatIso
+ leftUnitor X := (Coalgebra.TensorProduct.lid R X).toCoalgebraCatIso
+ rightUnitor X := (Coalgebra.TensorProduct.rid R X).toCoalgebraCatIso
+
+/-- The data needed to induce a `MonoidalCategory` structure via
+`CoalgebraCat.instMonoidalCategoryStruct` and the forgetful functor to modules. -/
+@[simps]
+noncomputable def MonoidalCategory.inducingFunctorData :
+ Monoidal.InducingFunctorData (forget₂ (CoalgebraCat R) (ModuleCat R)) where
+ μ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
+ εIso := Iso.refl _
+ associator_eq X Y Z := TensorProduct.ext <| TensorProduct.ext <| by ext; rfl
+ leftUnitor_eq X := TensorProduct.ext <| by ext; rfl
+ rightUnitor_eq X := TensorProduct.ext <| by ext; rfl
+
+noncomputable instance instMonoidalCategory : MonoidalCategory (CoalgebraCat R) :=
+ Monoidal.induced (forget₂ _ (ModuleCat R)) (MonoidalCategory.inducingFunctorData R)
+
+end CoalgebraCat
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/FGModuleCat/Limits.lean b/Mathlib/Algebra/Category/FGModuleCat/Limits.lean
index 8faee2b976d4c..3e5af1918343b 100644
--- a/Mathlib/Algebra/Category/FGModuleCat/Limits.lean
+++ b/Mathlib/Algebra/Category/FGModuleCat/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.FGModuleCat.Basic
import Mathlib.Algebra.Category.ModuleCat.Limits
diff --git a/Mathlib/Algebra/Category/Grp/AB5.lean b/Mathlib/Algebra/Category/Grp/AB5.lean
index b3408f6ec5a77..2edc3d04999e0 100644
--- a/Mathlib/Algebra/Category/Grp/AB5.lean
+++ b/Mathlib/Algebra/Category/Grp/AB5.lean
@@ -9,6 +9,7 @@ import Mathlib.Algebra.Homology.ShortComplex.ExactFunctor
import Mathlib.CategoryTheory.Abelian.Exact
import Mathlib.Algebra.Category.Grp.FilteredColimits
import Mathlib.CategoryTheory.Abelian.FunctorCategory
+import Mathlib.CategoryTheory.Abelian.GrothendieckAxioms
/-!
# The category of abelian groups satisfies Grothendieck's axiom AB5
@@ -45,3 +46,9 @@ noncomputable instance :
noncomputable instance :
PreservesFiniteLimits <| colim (J := J) (C := AddCommGrp.{u}) := by
apply Functor.preservesFiniteLimitsOfPreservesHomology
+
+instance : HasFilteredColimits (AddCommGrp.{u}) where
+ HasColimitsOfShape := inferInstance
+
+noncomputable instance : AB5 (AddCommGrp.{u}) where
+ preservesFiniteLimits := fun _ => inferInstance
diff --git a/Mathlib/Algebra/Category/Grp/Adjunctions.lean b/Mathlib/Algebra/Category/Grp/Adjunctions.lean
index 0ae1a7d27e135..65064b1835e0b 100644
--- a/Mathlib/Algebra/Category/Grp/Adjunctions.lean
+++ b/Mathlib/Algebra/Category/Grp/Adjunctions.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johannes Hölzl
+Authors: Kim Morrison, Johannes Hölzl
-/
import Mathlib.Algebra.Category.Grp.Preadditive
import Mathlib.GroupTheory.FreeAbelianGroup
@@ -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
@@ -177,20 +177,18 @@ def MonCat.units : MonCat.{u} ⥤ Grp.{u} where
map_comp _ _ := MonoidHom.ext fun _ => Units.ext rfl
/-- The forgetful-units adjunction between `Grp` and `MonCat`. -/
-def Grp.forget₂MonAdj : forget₂ Grp MonCat ⊣ MonCat.units.{u} where
- homEquiv X Y :=
+def Grp.forget₂MonAdj : forget₂ Grp MonCat ⊣ MonCat.units.{u} := Adjunction.mk' {
+ 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 }
- homEquiv_unit := MonoidHom.ext fun _ => Units.ext rfl
- homEquiv_counit := MonoidHom.ext fun _ => rfl
+ naturality := by intros; exact MonoidHom.ext fun x => rfl } }
instance : MonCat.units.{u}.IsRightAdjoint :=
⟨_, ⟨Grp.forget₂MonAdj⟩⟩
@@ -204,20 +202,19 @@ def CommMonCat.units : CommMonCat.{u} ⥤ CommGrp.{u} where
map_comp _ _ := MonoidHom.ext fun _ => Units.ext rfl
/-- The forgetful-units adjunction between `CommGrp` and `CommMonCat`. -/
-def CommGrp.forget₂CommMonAdj : forget₂ CommGrp CommMonCat ⊣ CommMonCat.units.{u} where
- homEquiv X 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 }
- unit :=
- { app := fun X => { (@toUnits X _).toMonoidHom with }
- naturality := fun X Y f => MonoidHom.ext fun x => Units.ext rfl }
- counit :=
- { app := fun X => Units.coeHom X
- naturality := by intros; exact MonoidHom.ext fun x => rfl }
- homEquiv_unit := MonoidHom.ext fun _ => Units.ext rfl
- homEquiv_counit := MonoidHom.ext fun _ => rfl
+def CommGrp.forget₂CommMonAdj : forget₂ CommGrp CommMonCat ⊣ CommMonCat.units.{u} :=
+ Adjunction.mk' {
+ homEquiv := fun _ Y ↦
+ { toFun := fun f => MonoidHom.toHomUnits f
+ invFun := fun f => (Units.coeHom Y).comp f
+ 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 _ _ _ => MonoidHom.ext fun _ => Units.ext rfl }
+ counit :=
+ { app := fun X => Units.coeHom X
+ naturality := by intros; exact MonoidHom.ext fun x => rfl } }
instance : CommMonCat.units.{u}.IsRightAdjoint :=
⟨_, ⟨CommGrp.forget₂CommMonAdj⟩⟩
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 343c5d74d0527..cd3163c30ea9f 100644
--- a/Mathlib/Algebra/Category/Grp/Biproducts.lean
+++ b/Mathlib/Algebra/Category/Grp/Biproducts.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Pi.Lemmas
import Mathlib.Algebra.Category.Grp.Preadditive
@@ -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 a53daac3791a2..ffd0441416766 100644
--- a/Mathlib/Algebra/Category/Grp/Colimits.lean
+++ b/Mathlib/Algebra/Category/Grp/Colimits.lean
@@ -1,13 +1,13 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
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/FiniteGrp.lean b/Mathlib/Algebra/Category/Grp/FiniteGrp.lean
new file mode 100644
index 0000000000000..b1f4d7ead61ee
--- /dev/null
+++ b/Mathlib/Algebra/Category/Grp/FiniteGrp.lean
@@ -0,0 +1,79 @@
+/-
+Copyright (c) 2024 Jujian Zhang. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Jujian Zhang, Nailin Guan, Yuyang Zhao
+-/
+import Mathlib.Algebra.Category.Grp.Basic
+
+/-!
+
+## Main definitions and results
+
+* `FiniteGrp` is the category of finite groups.
+
+-/
+
+universe u v
+
+open CategoryTheory
+
+/-- The category of finite groups. -/
+@[pp_with_univ]
+structure FiniteGrp where
+ /-- A group that is finite -/
+ toGrp : Grp
+ [isFinite : Finite toGrp]
+
+/-- The category of finite additive groups. -/
+@[pp_with_univ]
+structure FiniteAddGrp where
+ /-- An add group that is finite -/
+ toAddGrp : AddGrp
+ [isFinite : Finite toAddGrp]
+
+attribute [to_additive] FiniteGrp
+
+namespace FiniteGrp
+
+@[to_additive]
+instance : CoeSort FiniteGrp.{u} (Type u) where
+ coe G := G.toGrp
+
+@[to_additive]
+instance : Category FiniteGrp := InducedCategory.category FiniteGrp.toGrp
+
+@[to_additive]
+instance : ConcreteCategory FiniteGrp := InducedCategory.concreteCategory FiniteGrp.toGrp
+
+@[to_additive]
+instance (G : FiniteGrp) : Group G := inferInstanceAs <| Group G.toGrp
+
+@[to_additive]
+instance (G : FiniteGrp) : Finite G := G.isFinite
+
+@[to_additive]
+instance (G H : FiniteGrp) : FunLike (G ⟶ H) G H :=
+ inferInstanceAs <| FunLike (G →* H) G H
+
+@[to_additive]
+instance (G H : FiniteGrp) : MonoidHomClass (G ⟶ H) G H :=
+ inferInstanceAs <| MonoidHomClass (G →* H) G H
+
+/-- Construct a term of `FiniteGrp` from a type endowed with the structure of a finite group. -/
+@[to_additive "Construct a term of `FiniteAddGrp` from a type endowed with the structure of a
+finite additive group."]
+def of (G : Type u) [Group G] [Finite G] : FiniteGrp where
+ toGrp := Grp.of G
+ isFinite := ‹_›
+
+/-- The morphism in `FiniteGrp`, induced from a morphism of the category `Grp`. -/
+@[to_additive "The morphism in `FiniteAddGrp`, induced from a morphism of the category `AddGrp`"]
+def ofHom {X Y : Type u} [Group X] [Finite X] [Group Y] [Finite Y] (f : X →* Y) : of X ⟶ of Y :=
+ Grp.ofHom f
+
+@[to_additive]
+lemma ofHom_apply {X Y : Type u} [Group X] [Finite X] [Group Y] [Finite Y] (f : X →* Y) (x : X) :
+ ofHom f x = f x :=
+ rfl
+
+end FiniteGrp
diff --git a/Mathlib/Algebra/Category/Grp/ForgetCorepresentable.lean b/Mathlib/Algebra/Category/Grp/ForgetCorepresentable.lean
index 7f0cd7d6755d1..c7caa5ef7b7ad 100644
--- a/Mathlib/Algebra/Category/Grp/ForgetCorepresentable.lean
+++ b/Mathlib/Algebra/Category/Grp/ForgetCorepresentable.lean
@@ -95,18 +95,18 @@ def AddCommGrp.coyonedaObjIsoForget :
coyoneda.obj (op (of (ULift.{u} ℤ))) ≅ forget AddCommGrp.{u} :=
(NatIso.ofComponents (fun M => (AddMonoidHom.fromULiftIntEquiv M.α).toIso))
-instance Grp.forget_corepresentable :
- (forget Grp.{u}).Corepresentable where
- has_corepresentation := ⟨_, ⟨Grp.coyonedaObjIsoForget⟩⟩
+instance Grp.forget_isCorepresentable :
+ (forget Grp.{u}).IsCorepresentable :=
+ Functor.IsCorepresentable.mk' Grp.coyonedaObjIsoForget
-instance CommGrp.forget_corepresentable :
- (forget CommGrp.{u}).Corepresentable where
- has_corepresentation := ⟨_, ⟨CommGrp.coyonedaObjIsoForget⟩⟩
+instance CommGrp.forget_isCorepresentable :
+ (forget CommGrp.{u}).IsCorepresentable :=
+ Functor.IsCorepresentable.mk' CommGrp.coyonedaObjIsoForget
-instance AddGrp.forget_corepresentable :
- (forget AddGrp.{u}).Corepresentable where
- has_corepresentation := ⟨_, ⟨AddGrp.coyonedaObjIsoForget⟩⟩
+instance AddGrp.forget_isCorepresentable :
+ (forget AddGrp.{u}).IsCorepresentable :=
+ Functor.IsCorepresentable.mk' AddGrp.coyonedaObjIsoForget
-instance AddCommGrp.forget_corepresentable :
- (forget AddCommGrp.{u}).Corepresentable where
- has_corepresentation := ⟨_, ⟨AddCommGrp.coyonedaObjIsoForget⟩⟩
+instance AddCommGrp.forget_isCorepresentable :
+ (forget AddCommGrp.{u}).IsCorepresentable :=
+ Functor.IsCorepresentable.mk' AddCommGrp.coyonedaObjIsoForget
diff --git a/Mathlib/Algebra/Category/Grp/Images.lean b/Mathlib/Algebra/Category/Grp/Images.lean
index 5dd6fd3f51b21..e3f6641b97ec8 100644
--- a/Mathlib/Algebra/Category/Grp/Images.lean
+++ b/Mathlib/Algebra/Category/Grp/Images.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.Grp.Abelian
import Mathlib.CategoryTheory.Limits.Shapes.Images
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/Kernels.lean b/Mathlib/Algebra/Category/Grp/Kernels.lean
index 8f367b2c6f460..577c21325b183 100644
--- a/Mathlib/Algebra/Category/Grp/Kernels.lean
+++ b/Mathlib/Algebra/Category/Grp/Kernels.lean
@@ -26,7 +26,7 @@ def kernelCone : KernelFork f :=
/-- The kernel of a group homomorphism is a kernel in the categorical sense. -/
def kernelIsLimit : IsLimit <| kernelCone f :=
Fork.IsLimit.mk _
- (fun s => (by exact Fork.ι s : _ →+ G).codRestrict _ fun c => f.mem_ker.mpr <|
+ (fun s => (by exact Fork.ι s : _ →+ G).codRestrict _ fun c => mem_ker.mpr <|
by exact DFunLike.congr_fun s.condition c)
(fun _ => by rfl)
(fun _ _ h => ext fun x => Subtype.ext_iff_val.mpr <| by exact DFunLike.congr_fun h x)
diff --git a/Mathlib/Algebra/Category/Grp/Limits.lean b/Mathlib/Algebra/Category/Grp/Limits.lean
index 1f73a158c1bf6..d9ca3a039ecba 100644
--- a/Mathlib/Algebra/Category/Grp/Limits.lean
+++ b/Mathlib/Algebra/Category/Grp/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.MonCat.Limits
import Mathlib.Algebra.Category.Grp.ForgetCorepresentable
@@ -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/Grp/ZModuleEquivalence.lean b/Mathlib/Algebra/Category/Grp/ZModuleEquivalence.lean
index fd9a529d37985..242349db0fa0c 100644
--- a/Mathlib/Algebra/Category/Grp/ZModuleEquivalence.lean
+++ b/Mathlib/Algebra/Category/Grp/ZModuleEquivalence.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.ModuleCat.Basic
diff --git a/Mathlib/Algebra/Category/Grp/Zero.lean b/Mathlib/Algebra/Category/Grp/Zero.lean
index 7ecca001e70ea..188eb7bd2216a 100644
--- a/Mathlib/Algebra/Category/Grp/Zero.lean
+++ b/Mathlib/Algebra/Category/Grp/Zero.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.Grp.Basic
import Mathlib.CategoryTheory.Limits.Shapes.ZeroObjects
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 9035d34b23389..229bb1717e4b4 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johan Commelin
+Authors: Kim Morrison, Johan Commelin
-/
import Mathlib.Algebra.Category.ModuleCat.Monoidal.Basic
import Mathlib.CategoryTheory.Monoidal.Functorial
@@ -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 c350e298ae22e..d2d388822bfff 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Algebra.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Algebra.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Algebra.RestrictScalars
import Mathlib.CategoryTheory.Linear.Basic
@@ -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 276eafcbb77e3..02972a04dba1a 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Pi.Lemmas
import Mathlib.CategoryTheory.Limits.Shapes.Biproducts
@@ -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 0417f8ed023f7..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
@@ -155,11 +155,11 @@ def restrictScalarsId'App (hf : f = RingHom.id R) (M : ModuleCat R) :
variable (hf : f = RingHom.id R)
-lemma restrictScalarsId'App_hom_apply (M : ModuleCat R) (x : M) :
+@[simp] lemma restrictScalarsId'App_hom_apply (M : ModuleCat R) (x : M) :
(restrictScalarsId'App f hf M).hom x = x :=
rfl
-lemma restrictScalarsId'App_inv_apply (M : ModuleCat R) (x : M) :
+@[simp] lemma restrictScalarsId'App_inv_apply (M : ModuleCat R) (x : M) :
(restrictScalarsId'App f hf M).inv x = x :=
rfl
@@ -202,11 +202,11 @@ def restrictScalarsComp'App (hgf : gf = g.comp f) (M : ModuleCat R₃) :
variable (hgf : gf = g.comp f)
-lemma restrictScalarsComp'App_hom_apply (M : ModuleCat R₃) (x : M) :
+@[simp] lemma restrictScalarsComp'App_hom_apply (M : ModuleCat R₃) (x : M) :
(restrictScalarsComp'App f g gf hgf M).hom x = x :=
rfl
-lemma restrictScalarsComp'App_inv_apply (M : ModuleCat R₃) (x : M) :
+@[simp] lemma restrictScalarsComp'App_inv_apply (M : ModuleCat R₃) (x : M) :
(restrictScalarsComp'App f g gf hgf M).inv x = x :=
rfl
@@ -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]
@@ -564,30 +564,31 @@ end RestrictionCoextensionAdj
/-- Restriction of scalars is left adjoint to coextension of scalars. -/
-- @[simps] Porting note: not in normal form and not used
def restrictCoextendScalarsAdj {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) :
- restrictScalars.{max v u₂,u₁,u₂} f ⊣ coextendScalars f where
- homEquiv X Y :=
- { toFun := RestrictionCoextensionAdj.HomEquiv.fromRestriction.{u₁,u₂,v} f
- invFun := RestrictionCoextensionAdj.HomEquiv.toRestriction.{u₁,u₂,v} f
- left_inv := fun g => LinearMap.ext fun x : X => by
- -- Porting note (#10745): once just simp
- rw [RestrictionCoextensionAdj.HomEquiv.toRestriction_apply, AddHom.toFun_eq_coe,
- LinearMap.coe_toAddHom, RestrictionCoextensionAdj.HomEquiv.fromRestriction_apply_apply,
- one_smul]
- right_inv := fun g => LinearMap.ext fun x => LinearMap.ext fun s : S => by
- -- Porting note (#10745): once just simp
- rw [RestrictionCoextensionAdj.HomEquiv.fromRestriction_apply_apply,
- RestrictionCoextensionAdj.HomEquiv.toRestriction_apply, AddHom.toFun_eq_coe,
- LinearMap.coe_toAddHom, LinearMap.map_smulₛₗ, RingHom.id_apply,
- CoextendScalars.smul_apply', one_mul] }
- unit := RestrictionCoextensionAdj.unit'.{u₁,u₂,v} f
- counit := RestrictionCoextensionAdj.counit'.{u₁,u₂,v} f
- homEquiv_unit := LinearMap.ext fun y => rfl
- homEquiv_counit := fun {X Y g} => LinearMap.ext <| by
- -- Porting note (#10745): previously simp [RestrictionCoextensionAdj.counit']
- intro x; dsimp
- rw [coe_comp, Function.comp]
- change _ = (((restrictScalars f).map g) x).toFun (1 : S)
- rw [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, restrictScalars.map_apply]
+ restrictScalars.{max v u₂,u₁,u₂} f ⊣ coextendScalars f :=
+ Adjunction.mk' {
+ homEquiv := fun X Y ↦
+ { toFun := RestrictionCoextensionAdj.HomEquiv.fromRestriction.{u₁,u₂,v} f
+ invFun := RestrictionCoextensionAdj.HomEquiv.toRestriction.{u₁,u₂,v} f
+ left_inv := fun g => LinearMap.ext fun x : X => by
+ -- Porting note (#10745): once just simp
+ rw [RestrictionCoextensionAdj.HomEquiv.toRestriction_apply, AddHom.toFun_eq_coe,
+ LinearMap.coe_toAddHom, RestrictionCoextensionAdj.HomEquiv.fromRestriction_apply_apply,
+ one_smul]
+ right_inv := fun g => LinearMap.ext fun x => LinearMap.ext fun s : S => by
+ -- Porting note (#10745): once just simp
+ rw [RestrictionCoextensionAdj.HomEquiv.fromRestriction_apply_apply,
+ RestrictionCoextensionAdj.HomEquiv.toRestriction_apply, AddHom.toFun_eq_coe,
+ LinearMap.coe_toAddHom, LinearMap.map_smulₛₗ, RingHom.id_apply,
+ CoextendScalars.smul_apply', one_mul] }
+ unit := RestrictionCoextensionAdj.unit'.{u₁,u₂,v} f
+ counit := RestrictionCoextensionAdj.counit'.{u₁,u₂,v} f
+ homEquiv_unit := LinearMap.ext fun _ => rfl
+ homEquiv_counit := fun {X Y g} => LinearMap.ext <| by
+ -- Porting note (#10745): previously simp [RestrictionCoextensionAdj.counit']
+ intro x; dsimp
+ rw [coe_comp, Function.comp]
+ change _ = (((restrictScalars f).map g) x).toFun (1 : S)
+ rw [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, restrictScalars.map_apply] }
instance {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) :
(restrictScalars.{max u₂ w} f).IsLeftAdjoint :=
@@ -797,31 +798,26 @@ scalars by `f` are adjoint to each other.
-/
-- @[simps] -- Porting note: removed not in normal form and not used
def extendRestrictScalarsAdj {R : Type u₁} {S : Type u₂} [CommRing R] [CommRing S] (f : R →+* S) :
- extendScalars.{u₁,u₂,max v u₂} f ⊣ restrictScalars.{max v u₂,u₁,u₂} f where
- homEquiv _ _ := ExtendRestrictScalarsAdj.homEquiv.{v,u₁,u₂} f
- unit := ExtendRestrictScalarsAdj.unit.{v,u₁,u₂} f
- counit := ExtendRestrictScalarsAdj.counit.{v,u₁,u₂} f
- homEquiv_unit {X Y g} := LinearMap.ext fun x => by
- dsimp
- rw [ModuleCat.coe_comp, Function.comp_apply, restrictScalars.map_apply]
- rfl
- homEquiv_counit {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]
- -- 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
- | add => rw [map_add, map_add]; congr 1
+ extendScalars.{u₁,u₂,max v u₂} f ⊣ restrictScalars.{max v u₂,u₁,u₂} f :=
+ Adjunction.mk' {
+ homEquiv := fun _ _ ↦ ExtendRestrictScalarsAdj.homEquiv.{v,u₁,u₂} f
+ unit := ExtendRestrictScalarsAdj.unit.{v,u₁,u₂} f
+ counit := ExtendRestrictScalarsAdj.counit.{v,u₁,u₂} f
+ homEquiv_unit := fun {X Y g} ↦ LinearMap.ext fun x => by
+ dsimp
+ rw [ModuleCat.coe_comp, Function.comp_apply, restrictScalars.map_apply]
+ rfl
+ homEquiv_counit := fun {X Y g} ↦ LinearMap.ext fun x => by
+ induction x using TensorProduct.induction_on with
+ | zero => rw [map_zero, map_zero]
+ | tmul =>
+ rw [ExtendRestrictScalarsAdj.homEquiv_symm_apply]
+ dsimp
+ rw [ModuleCat.coe_comp, Function.comp_apply]
+ -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
+ erw [ExtendRestrictScalarsAdj.Counit.map_apply]
+ dsimp
+ | add => rw [map_add, map_add]; congr 1 }
instance {R : Type u₁} {S : Type u₂} [CommRing R] [CommRing S] (f : R →+* S) :
(extendScalars.{u₁, u₂, max u₂ w} f).IsLeftAdjoint :=
diff --git a/Mathlib/Algebra/Category/ModuleCat/Colimits.lean b/Mathlib/Algebra/Category/ModuleCat/Colimits.lean
index ae030fd209955..d3858a83537a4 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Colimits.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Colimits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Joël Riou
+Authors: Kim Morrison, Joël Riou
-/
import Mathlib.Algebra.Category.ModuleCat.Basic
import Mathlib.CategoryTheory.ConcreteCategory.Elementwise
@@ -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/Differentials/Presheaf.lean b/Mathlib/Algebra/Category/ModuleCat/Differentials/Presheaf.lean
index b826d73a22b10..eef6ac3891d20 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Differentials/Presheaf.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Differentials/Presheaf.lean
@@ -78,7 +78,7 @@ variable (d : M.Derivation φ)
@[simps! d_apply]
def postcomp (f : M ⟶ N) : N.Derivation φ where
d := (f.app _).toAddMonoidHom.comp d.d
- d_map _ _ := by simp [naturality_apply]
+ d_map {X Y} g x := by simpa using naturality_apply f g (d.d x)
d_app {X} a := by
dsimp
erw [d_app, map_zero]
@@ -175,50 +175,44 @@ end Derivation'
namespace DifferentialsConstruction
-/-- Auxiliary definition for `relativeDifferentials'`. -/
-noncomputable def relativeDifferentials'BundledCore :
- BundledCorePresheafOfModules.{u} (R ⋙ forget₂ _ _) where
- obj X := CommRingCat.KaehlerDifferential (φ'.app X)
- map f := CommRingCat.KaehlerDifferential.map (φ'.naturality f)
-
/-- The presheaf of relative differentials of a morphism of presheaves of
commutative rings. -/
+@[simps (config := .lemmasOnly)]
noncomputable def relativeDifferentials' :
- PresheafOfModules.{u} (R ⋙ forget₂ _ _) :=
- (relativeDifferentials'BundledCore φ').toPresheafOfModules
-
-@[simp]
-lemma relativeDifferentials'_obj (X : Dᵒᵖ) :
- (relativeDifferentials' φ').obj X =
- CommRingCat.KaehlerDifferential (φ'.app X) := rfl
+ PresheafOfModules.{u} (R ⋙ forget₂ _ _) where
+ obj X := CommRingCat.KaehlerDifferential (φ'.app X)
+ map f := CommRingCat.KaehlerDifferential.map (φ'.naturality f)
+ map_id _ := by ext; simp; rfl
+ map_comp _ _ := by ext; simp; rfl
--- Note: this cannot be a simp lemma because `dsimp` would
--- simplify the composition of functors `R ⋙ forget₂ _ _`
-lemma relativeDifferentials'_map_apply {X Y : Dᵒᵖ} (f : X ⟶ Y)
- (x : CommRingCat.KaehlerDifferential (φ'.app X)) :
- (relativeDifferentials' φ').map f x =
- CommRingCat.KaehlerDifferential.map (φ'.naturality f) x := rfl
+attribute [simp] relativeDifferentials'_obj
-lemma relativeDifferentials'_map_d {X Y : Dᵒᵖ} (f : X ⟶ Y)
- (x : R.obj X) :
- (relativeDifferentials' φ').map f (CommRingCat.KaehlerDifferential.d x) =
- CommRingCat.KaehlerDifferential.d (R.map f x) := by
- rw [relativeDifferentials'_map_apply, CommRingCat.KaehlerDifferential.map_d]
+@[simp]
+lemma relativeDifferentials'_map_d {X Y : Dᵒᵖ} (f : X ⟶ Y) (x : R.obj X) :
+ DFunLike.coe (α := CommRingCat.KaehlerDifferential (φ'.app X))
+ (β := fun _ ↦ CommRingCat.KaehlerDifferential (φ'.app Y))
+ ((relativeDifferentials' φ').map f) (CommRingCat.KaehlerDifferential.d x) =
+ CommRingCat.KaehlerDifferential.d (R.map f x) :=
+ CommRingCat.KaehlerDifferential.map_d (φ'.naturality f) _
/-- The universal derivation. -/
noncomputable def derivation' : (relativeDifferentials' φ').Derivation' φ' :=
- Derivation'.mk (fun X ↦ CommRingCat.KaehlerDifferential.D (φ'.app X)) (fun X Y f x ↦ by
- rw [relativeDifferentials'_map_apply, CommRingCat.KaehlerDifferential.map_d])
+ Derivation'.mk (fun X ↦ CommRingCat.KaehlerDifferential.D (φ'.app X))
+ (fun _ _ f x ↦ (relativeDifferentials'_map_d φ' f x).symm)
/-- The derivation `Derivation' φ'` is universal. -/
noncomputable def isUniversal' : (derivation' φ').Universal :=
Derivation'.Universal.mk
- (fun {M'} d' ↦ Hom.mk'' (fun X ↦ (d'.app X).desc) (fun X Y f ↦
- CommRingCat.KaehlerDifferential.ext (fun b ↦ by
- dsimp [ModuleCat.ofHom]
- erw [restrictionApp_apply, restrictionApp_apply]
- simp only [relativeDifferentials'_map_d, ModuleCat.Derivation.desc_d,
- d'.app_apply, d'.d_map])))
+ (fun {M'} d' ↦
+ { app := fun X ↦ (d'.app X).desc
+ naturality := fun {X Y} f ↦ CommRingCat.KaehlerDifferential.ext (fun b ↦ by
+ dsimp
+ rw [ModuleCat.Derivation.desc_d, Derivation'.app_apply]
+ erw [relativeDifferentials'_map_d φ' f]
+ rw [ModuleCat.Derivation.desc_d]
+ dsimp
+ rw [Derivation.d_map]
+ dsimp) })
(fun {M'} d' ↦ by
ext X b
apply ModuleCat.Derivation.desc_d)
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 d6f7847ecf6bc..4ba5ef78289de 100644
--- a/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean
@@ -1,9 +1,9 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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/Free.lean b/Mathlib/Algebra/Category/ModuleCat/Free.lean
index ce028e860756f..9f822325b9425 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Free.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Free.lean
@@ -26,7 +26,7 @@ linear algebra, module, free
-/
-open CategoryTheory
+open CategoryTheory Module
namespace ModuleCat
@@ -144,7 +144,7 @@ theorem span_rightExact {w : ι' → S.X₃} (hv : ⊤ ≤ span R (range v))
· convert hw
simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, Sum.elim_comp_inr]
rw [ModuleCat.epi_iff_surjective] at hE
- rw [← Function.comp.assoc, Function.RightInverse.comp_eq_id (Function.rightInverse_invFun hE),
+ rw [← Function.comp_assoc, Function.RightInverse.comp_eq_id (Function.rightInverse_invFun hE),
Function.id_comp]
end Span
@@ -177,11 +177,11 @@ theorem free_shortExact_rank_add [Module.Free R S.X₁] [Module.Free R S.X₃]
theorem free_shortExact_finrank_add {n p : ℕ} [Module.Free R S.X₁] [Module.Free R S.X₃]
[Module.Finite R S.X₁] [Module.Finite R S.X₃]
- (hN : FiniteDimensional.finrank R S.X₁ = n)
- (hP : FiniteDimensional.finrank R S.X₃ = p)
+ (hN : Module.finrank R S.X₁ = n)
+ (hP : Module.finrank R S.X₃ = p)
[StrongRankCondition R] :
- FiniteDimensional.finrank R S.X₂ = n + p := by
- apply FiniteDimensional.finrank_eq_of_rank_eq
+ finrank R S.X₂ = n + p := by
+ apply finrank_eq_of_rank_eq
rw [free_shortExact_rank_add hS', ← hN, ← hP]
simp only [Nat.cast_add, finrank_eq_rank]
diff --git a/Mathlib/Algebra/Category/ModuleCat/Images.lean b/Mathlib/Algebra/Category/ModuleCat/Images.lean
index 78b8b35d12247..9a516ef12b9b4 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Images.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Images.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.ModuleCat.Abelian
import Mathlib.CategoryTheory.Limits.Shapes.Images
@@ -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/Limits.lean b/Mathlib/Algebra/Category/ModuleCat/Limits.lean
index 27b1d3ca656ff..5ad9e49af4722 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Limits.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.ModuleCat.Basic
import Mathlib.Algebra.Category.Grp.Limits
diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean
index 666c67174d69b..b801c34fa8861 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kevin Buzzard, Scott Morrison, Jakob von Raumer
+Authors: Kevin Buzzard, Kim Morrison, Jakob von Raumer
-/
import Mathlib.Algebra.Category.ModuleCat.Basic
import Mathlib.LinearAlgebra.TensorProduct.Basic
@@ -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 e741ce18b6323..979e0ee459b68 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kevin Buzzard, Scott Morrison, Jakob von Raumer
+Authors: Kevin Buzzard, Kim Morrison, Jakob von Raumer
-/
import Mathlib.CategoryTheory.Closed.Monoidal
import Mathlib.CategoryTheory.Linear.Yoneda
@@ -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 :=
@@ -77,8 +77,9 @@ should give a map `M ⊗ Hom(M, N) ⟶ N`, so we flip the order of the arguments
`Hom(M, N) ⟶ (M ⟶ N)` and uncurry the resulting map `M ⟶ Hom(M, N) ⟶ N.` -/
theorem ihom_ev_app (M N : ModuleCat.{u} R) :
(ihom.ev M).app N = TensorProduct.uncurry _ _ _ _ LinearMap.id.flip := by
+ rw [← MonoidalClosed.uncurry_id_eq_ev]
apply TensorProduct.ext'
- apply ModuleCat.monoidalClosed_uncurry
+ apply monoidalClosed_uncurry
/-- Describes the unit of the adjunction `M ⊗ - ⊣ Hom(M, -)`. Given an `R`-module `N` this should
define a map `N ⟶ Hom(M, M ⊗ N)`, which is given by flipping the arguments in the natural
diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Symmetric.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Symmetric.lean
index 673a3f1d577d1..75e4669e16efc 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Symmetric.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Symmetric.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kevin Buzzard, Scott Morrison, Jakob von Raumer
+Authors: Kevin Buzzard, Kim Morrison, Jakob von Raumer
-/
import Mathlib.CategoryTheory.Monoidal.Braided.Basic
import Mathlib.Algebra.Category.ModuleCat.Monoidal.Basic
@@ -88,14 +88,14 @@ theorem braiding_inv_apply {M N : ModuleCat.{u} R} (m : M) (n : N) :
rfl
theorem tensor_μ_eq_tensorTensorTensorComm {A B C D : ModuleCat R} :
- tensor_μ _ (A, B) (C, D) = (TensorProduct.tensorTensorTensorComm R A B C D).toLinearMap :=
+ tensor_μ A B C D = (TensorProduct.tensorTensorTensorComm R A B C D).toLinearMap :=
TensorProduct.ext <| TensorProduct.ext <| LinearMap.ext₂ fun _ _ =>
TensorProduct.ext <| LinearMap.ext₂ fun _ _ => rfl
@[simp]
theorem tensor_μ_apply
{A B C D : ModuleCat R} (x : A) (y : B) (z : C) (w : D) :
- tensor_μ _ (A, B) (C, D) ((x ⊗ₜ y) ⊗ₜ (z ⊗ₜ w)) = (x ⊗ₜ z) ⊗ₜ (y ⊗ₜ w) := rfl
+ tensor_μ A B C D ((x ⊗ₜ y) ⊗ₜ (z ⊗ₜ w)) = (x ⊗ₜ z) ⊗ₜ (y ⊗ₜ w) := rfl
end MonoidalCategory
diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean
index 5a9b76b43035b..653280c6b57bd 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison, Joël Riou
-/
import Mathlib.Algebra.Category.ModuleCat.ChangeOfRings
import Mathlib.Algebra.Category.Ring.Basic
@@ -9,22 +9,18 @@ import Mathlib.Algebra.Category.Ring.Basic
/-!
# Presheaves of modules over a presheaf of rings.
-We give a hands-on description of a presheaf of modules over a fixed presheaf of rings `R`,
-as a presheaf of abelian groups with additional data.
+Given a presheaf of rings `R : Cᵒᵖ ⥤ RingCat`, we define the category `PresheafOfModules R`.
+An object `M : PresheafOfModules R` consists of a family of modules
+`M.obj X : ModuleCat (R.obj X)` for all `X : Cᵒᵖ`, together with the data, for all `f : X ⟶ Y`,
+of a functorial linear map `M.map f` from `M.obj X` to the restriction
+of scalars of `M.obj Y` via `R.map f`.
-We also provide two alternative constructors :
-* When `M : CorePresheafOfModules R` consists of a family of unbundled modules over `R.obj X`
-for all `X`, the corresponding presheaf of modules is `M.toPresheafOfModules`.
-* When `M : BundledCorePresheafOfModules R` consists of a family of objects in
-`ModuleCat (R.obj X)` for all `X`, the corresponding presheaf of modules
-is `M.toPresheafOfModules`.
## Future work
* Compare this to the definition as a presheaf of pairs `(R, M)` with specified first part.
* Compare this to the definition as a module object of the presheaf of rings
thought of as a monoid object.
-* (Pre)sheaves of modules over a given sheaf of rings are an abelian category.
* Presheaves of modules over a presheaf of commutative rings form a monoidal category.
* Pushforward and pullback.
-/
@@ -33,148 +29,204 @@ universe v v₁ u₁ u
open CategoryTheory LinearMap Opposite
-variable {C : Type u₁} [Category.{v₁} C]
+variable {C : Type u₁} [Category.{v₁} C] {R : Cᵒᵖ ⥤ RingCat.{u}}
-/-- A presheaf of modules over a given presheaf of rings,
-described as a presheaf of abelian groups, and the extra data of the action at each object,
-and a condition relating functoriality and scalar multiplication. -/
-structure PresheafOfModules (R : Cᵒᵖ ⥤ RingCat.{u}) where
- presheaf : Cᵒᵖ ⥤ AddCommGrp.{v}
- module : ∀ X : Cᵒᵖ, Module (R.obj X) (presheaf.obj X) := by infer_instance
- map_smul : ∀ {X Y : Cᵒᵖ} (f : X ⟶ Y) (r : R.obj X) (x : presheaf.obj X),
- presheaf.map f (r • x) = R.map f r • presheaf.map f x := by aesop_cat
-
-variable {R : Cᵒᵖ ⥤ RingCat.{u}}
+variable (R) in
+/-- A presheaf of modules over `R : Cᵒᵖ ⥤ RingCat` consists of family of
+objects `obj X : ModuleCat (R.obj X)` for all `X : Cᵒᵖ` together with
+functorial maps `obj X ⟶ (ModuleCat.restrictScalars (R.map f)).obj (obj Y)`
+for all `f : X ⟶ Y` in `Cᵒᵖ`. -/
+structure PresheafOfModules where
+ /-- a family of modules over `R.obj X` for all `X` -/
+ obj (X : Cᵒᵖ) : ModuleCat.{v} (R.obj X)
+ /-- the restriction maps of a presheaf of modules -/
+ map {X Y : Cᵒᵖ} (f : X ⟶ Y) : obj X ⟶ (ModuleCat.restrictScalars (R.map f)).obj (obj Y)
+ map_id (X : Cᵒᵖ) :
+ map (𝟙 X) = (ModuleCat.restrictScalarsId' _ (R.map_id X)).inv.app _ := by aesop_cat
+ map_comp {X Y Z : Cᵒᵖ} (f : X ⟶ Y) (g : Y ⟶ Z) :
+ map (f ≫ g) = map f ≫ (ModuleCat.restrictScalars _).map (map g) ≫
+ (ModuleCat.restrictScalarsComp' _ _ _ (R.map_comp f g)).inv.app _ := by aesop_cat
namespace PresheafOfModules
-attribute [instance] PresheafOfModules.module
-
-/-- The bundled module over an object `X`. -/
-def obj (P : PresheafOfModules R) (X : Cᵒᵖ) : ModuleCat (R.obj X) :=
- ModuleCat.of _ (P.presheaf.obj X)
-
-/--
-If `P` is a presheaf of modules over a presheaf of rings `R`, both over some category `C`,
-and `f : X ⟶ Y` is a morphism in `Cᵒᵖ`, we construct the `R.map f`-semilinear map
-from the `R.obj X`-module `P.presheaf.obj X` to the `R.obj Y`-module `P.presheaf.obj Y`.
- -/
-def map (P : PresheafOfModules R) {X Y : Cᵒᵖ} (f : X ⟶ Y) :
- P.obj X →ₛₗ[R.map f] P.obj Y :=
- { toAddHom := (P.presheaf.map f).toAddHom,
- map_smul' := P.map_smul f, }
-
-theorem map_apply (P : PresheafOfModules R) {X Y : Cᵒᵖ} (f : X ⟶ Y) (x) :
- P.map f x = (P.presheaf.map f) x :=
- rfl
+attribute [simp] map_id map_comp
+attribute [reassoc] map_comp
-instance (X : Cᵒᵖ) : RingHomId (R.map (𝟙 X)) where
- eq_id := R.map_id X
+variable (M M₁ M₂ : PresheafOfModules.{v} R)
-instance {X Y Z : Cᵒᵖ} (f : X ⟶ Y) (g : Y ⟶ Z) :
- RingHomCompTriple (R.map f) (R.map g) (R.map (f ≫ g)) where
- comp_eq := (R.map_comp f g).symm
+lemma map_smul {X Y : Cᵒᵖ} (f : X ⟶ Y) (r : R.obj X) (m : M.obj X) :
+ M.map f (r • m) = R.map f r • M.map f m := by simp
-@[simp]
-theorem map_id (P : PresheafOfModules R) (X : Cᵒᵖ) :
- P.map (𝟙 X) = LinearMap.id' := by
- ext
- simp [map_apply]
+lemma congr_map_apply {X Y : Cᵒᵖ} {f g : X ⟶ Y} (h : f = g) (m : M.obj X) :
+ M.map f m = M.map g m := by rw [h]
-@[simp]
-theorem map_comp (P : PresheafOfModules R) {X Y Z : Cᵒᵖ} (f : X ⟶ Y) (g : Y ⟶ Z) :
- P.map (f ≫ g) = (P.map g).comp (P.map f) := by
- ext
- simp [map_apply]
+/-- A morphism of presheaves of modules consists of a family of linear maps which
+satisfy the naturality condition. -/
+@[ext]
+structure Hom where
+ /-- a family of linear maps `M₁.obj X ⟶ M₂.obj X` for all `X`. -/
+ 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) =
+ app X ≫ M₂.map f := by aesop_cat
-/-- A morphism of presheaves of modules. -/
-structure Hom (P Q : PresheafOfModules R) where
- hom : P.presheaf ⟶ Q.presheaf
- map_smul : ∀ (X : Cᵒᵖ) (r : R.obj X) (x : P.presheaf.obj X), hom.app X (r • x) = r • hom.app X x
+attribute [reassoc (attr := simp)] Hom.naturality
-namespace Hom
+instance : Category (PresheafOfModules.{v} R) where
+ Hom := Hom
+ id _ := { app := fun _ ↦ 𝟙 _ }
+ comp f g := { app := fun _ ↦ f.app _ ≫ g.app _ }
-/-- The identity morphism on a presheaf of modules. -/
-def id (P : PresheafOfModules R) : Hom P P where
- hom := 𝟙 _
- map_smul _ _ _ := rfl
+variable {M₁ M₂}
-/-- Composition of morphisms of presheaves of modules. -/
-def comp {P Q R : PresheafOfModules R} (f : Hom P Q) (g : Hom Q R) : Hom P R where
- hom := f.hom ≫ g.hom
- map_smul _ _ _ := by simp [Hom.map_smul]
+@[ext]
+lemma hom_ext {f g : M₁ ⟶ M₂} (h : ∀ (X : Cᵒᵖ), f.app X = g.app X) :
+ f = g := Hom.ext (by ext1; apply h)
-end Hom
+@[simp]
+lemma id_app (M : PresheafOfModules R) (X : Cᵒᵖ) : Hom.app (𝟙 M) X = 𝟙 _ := by
+ rfl
-instance : Category (PresheafOfModules R) where
- Hom := Hom
- id := Hom.id
- comp f g := Hom.comp f g
+@[simp]
+lemma comp_app {M₁ M₂ M₃ : PresheafOfModules R} (f : M₁ ⟶ M₂) (g : M₂ ⟶ M₃) (X : Cᵒᵖ) :
+ (f ≫ g).app X = f.app X ≫ g.app X := by
+ rfl
-namespace Hom
+lemma naturality_apply (f : M₁ ⟶ M₂) {X Y : Cᵒᵖ} (g : X ⟶ Y) (x : M₁.obj X) :
+ 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
-variable {P Q T : PresheafOfModules R}
+/-- 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)
+ map f := AddMonoidHom.mk' (M.map f) (by simp)
-variable (P) in
@[simp]
-lemma id_hom : Hom.hom (𝟙 P) = 𝟙 _ := rfl
-
-@[simp, reassoc]
-lemma comp_hom (f : P ⟶ Q) (g : Q ⟶ T) : (f ≫ g).hom = f.hom ≫ g.hom := rfl
-
-/--
-The `(X : Cᵒᵖ)`-component of morphism between presheaves of modules
-over a presheaf of rings `R`, as an `R.obj X`-linear map. -/
-def app (f : Hom P Q) (X : Cᵒᵖ) : P.obj X →ₗ[R.obj X] Q.obj X :=
- { toAddHom := (f.hom.app X).toAddHom
- map_smul' := f.map_smul X }
+lemma presheaf_obj_coe (X : Cᵒᵖ) :
+ (M.presheaf.obj X : Type _) = M.obj X := rfl
@[simp]
-lemma comp_app (f : P ⟶ Q) (g : Q ⟶ T) (X : Cᵒᵖ) :
- (f ≫ g).app X = (g.app X).comp (f.app X) := rfl
+lemma presheaf_map_apply_coe {X Y : Cᵒᵖ} (f : X ⟶ Y) (x : M.obj X) :
+ DFunLike.coe (α := M.obj X) (β := fun _ ↦ M.obj Y) (M.presheaf.map f) x = M.map f x := rfl
-@[ext]
-theorem ext {f g : P ⟶ Q} (w : ∀ X, f.app X = g.app X) : f = g := by
- cases f; cases g
- congr
- ext X x
- exact LinearMap.congr_fun (w X) x
+instance (M : PresheafOfModules R) (X : Cᵒᵖ) :
+ Module (R.obj X) (M.presheaf.obj X) :=
+ inferInstanceAs (Module (R.obj X) (M.obj X))
-instance : Zero (P ⟶ Q) := ⟨mk 0 (by
- intros
- simp only [Limits.zero_app, AddMonoidHom.zero_apply, smul_zero])⟩
+variable (R) in
+/-- The forgetful functor `PresheafOfModules R ⥤ Cᵒᵖ ⥤ Ab`. -/
+def toPresheaf : PresheafOfModules.{v} R ⥤ Cᵒᵖ ⥤ Ab where
+ obj M := M.presheaf
+ map f :=
+ { app := fun X ↦ AddMonoidHom.mk' (Hom.app f X) (by simp)
+ naturality := fun X Y g ↦ by ext x; exact naturality_apply f g x }
-variable (P Q)
+@[simp]
+lemma toPresheaf_obj_coe (X : Cᵒᵖ) :
+ (((toPresheaf R).obj M).obj X : Type _) = M.obj X := rfl
@[simp]
-lemma zero_app (X : Cᵒᵖ) : (0 : P ⟶ Q).app X = 0 := rfl
+lemma toPresheaf_map_app_apply (f : M₁ ⟶ M₂) (X : Cᵒᵖ) (x : M₁.obj X) :
+ DFunLike.coe (α := M₁.obj X) (β := fun _ ↦ M₂.obj X)
+ (((toPresheaf R).map f).app X) x = f.app X x := rfl
-variable {P Q}
+instance : (toPresheaf R).Faithful where
+ map_injective {_ _ f g} h := by
+ ext X x
+ exact congr_fun (((evaluation _ _).obj X ⋙ forget _).congr_map h) x
-instance : Add (P ⟶ Q) := ⟨fun f g => mk (f.hom + g.hom) (by
- intros
- simp only [NatTrans.app_add, AddCommGrp.hom_add_apply, map_smul, smul_add])⟩
+section
-@[simp]
-lemma add_app (f g : P ⟶ Q) (X : Cᵒᵖ) : (f + g).app X = f.app X + g.app X := rfl
+variable (M : Cᵒᵖ ⥤ Ab.{v}) [∀ X, Module (R.obj X) (M.obj X)]
+ (map_smul : ∀ ⦃X Y : Cᵒᵖ⦄ (f : X ⟶ Y) (r : R.obj X) (m : M.obj X),
+ M.map f (r • m) = R.map f r • M.map f m)
-instance : Sub (P ⟶ Q) := ⟨fun f g => mk (f.hom - g.hom) (by
- intros
- rw [NatTrans.app_sub, AddMonoidHom.sub_apply, AddMonoidHom.sub_apply,
- smul_sub, map_smul, map_smul])⟩
+/-- The object in `PresheafOfModules R` that is obtained from `M : Cᵒᵖ ⥤ Ab.{v}` such
+that for all `X : Cᵒᵖ`, `M.obj X` is a `R.obj X` module, in such a way that the
+restriction maps are semilinear. (This constructor should be used only in cases
+when the preferred constructor `PresheafOfModules.mk` is not as convenient as this one.) -/
+@[simps]
+def ofPresheaf : PresheafOfModules.{v} R where
+ obj X := ModuleCat.of _ (M.obj X)
+ map f :=
+ { toFun := fun x ↦ M.map f x
+ map_add' := by simp
+ map_smul' := fun r m ↦ map_smul f r m }
@[simp]
-lemma sub_app (f g : P ⟶ Q) (X : Cᵒᵖ) : (f - g).app X = f.app X - g.app X := rfl
-
-instance : Neg (P ⟶ Q) := ⟨fun f => mk (-f.hom) (by
- intros
- rw [NatTrans.app_neg, AddMonoidHom.neg_apply, AddMonoidHom.neg_apply,
- map_smul, smul_neg])⟩
+lemma ofPresheaf_presheaf : (ofPresheaf M map_smul).presheaf = M := rfl
-@[simp]
-lemma neg_app (f : P ⟶ Q) (X : Cᵒᵖ) : (-f).app X = -f.app X := rfl
+end
-instance : AddCommGroup (P ⟶ Q) where
+/-- The morphism of presheaves of modules `M₁ ⟶ M₂` given by a morphism
+of abelian presheaves `M₁.presheaf ⟶ M₂.presheaf`
+which satisfy a suitable linearity condition. -/
+@[simps]
+def homMk (φ : M₁.presheaf ⟶ M₂.presheaf)
+ (hφ : ∀ (X : Cᵒᵖ) (r : R.obj X) (m : M₁.obj X), φ.app X (r • m) = r • φ.app X m) :
+ M₁ ⟶ M₂ where
+ app X :=
+ { toFun := φ.app X
+ map_add' := by simp
+ map_smul' := hφ X }
+ naturality := fun f ↦ by
+ ext x
+ exact congr_fun ((forget _).congr_map (φ.naturality f)) x
+
+instance : Zero (M₁ ⟶ M₂) where
+ zero := { app := fun _ ↦ 0 }
+
+variable (M₁ M₂) in
+@[simp] lemma zero_app (X : Cᵒᵖ) : (0 : M₁ ⟶ M₂).app X = 0 := rfl
+
+instance : Neg (M₁ ⟶ M₂) where
+ neg f :=
+ { app := fun X ↦ -f.app X
+ naturality := fun {X Y} h ↦ by
+ ext x
+ dsimp
+ erw [map_neg]
+ rw [← naturality_apply]
+ rfl }
+
+instance : Add (M₁ ⟶ M₂) where
+ add f g :=
+ { app := fun X ↦ f.app X + g.app X
+ naturality := fun {X Y} h ↦ by
+ ext x
+ dsimp
+ erw [map_add]
+ rw [← naturality_apply, ← naturality_apply]
+ rfl }
+
+instance : Sub (M₁ ⟶ M₂) where
+ sub f g :=
+ { app := fun X ↦ f.app X - g.app X
+ naturality := fun {X Y} h ↦ by
+ ext x
+ dsimp
+ erw [map_sub]
+ rw [← naturality_apply, ← naturality_apply]
+ rfl }
+
+@[simp] lemma neg_app (f : M₁ ⟶ M₂) (X : Cᵒᵖ) : (-f).app X = -f.app X := rfl
+@[simp] lemma add_app (f g : M₁ ⟶ M₂) (X : Cᵒᵖ) : (f + g).app X = f.app X + g.app X := rfl
+@[simp] lemma sub_app (f g : M₁ ⟶ M₂) (X : Cᵒᵖ) : (f - g).app X = f.app X - g.app X := rfl
+
+instance : AddCommGroup (M₁ ⟶ M₂) where
add_assoc := by intros; ext1; simp only [add_app, add_assoc]
zero_add := by intros; ext1; simp only [add_app, zero_app, zero_add]
neg_add_cancel := by intros; ext1; simp only [add_app, neg_app, neg_add_cancel, zero_app]
@@ -185,41 +237,14 @@ instance : AddCommGroup (P ⟶ Q) where
zsmul := zsmulRec
instance : Preadditive (PresheafOfModules R) where
- add_comp := by intros; ext1; simp only [comp_app, add_app, comp_add]
- comp_add := by intros; ext1; simp only [comp_app, add_app, add_comp]
-
-end Hom
-
-lemma naturality_apply {P Q : PresheafOfModules R} (f : P ⟶ Q)
- {X Y : Cᵒᵖ} (g : X ⟶ Y) (x : P.obj X) :
- f.app Y (P.map g x) = Q.map g (f.app X x) :=
- congr_fun ((forget _).congr_map (f.hom.naturality g)) x
-
-variable (R)
-
-/-- The functor from presheaves of modules over a specified presheaf of rings,
-to presheaves of abelian groups.
--/
-@[simps obj]
-def toPresheaf : PresheafOfModules.{v} R ⥤ (Cᵒᵖ ⥤ AddCommGrp.{v}) where
- obj P := P.presheaf
- map f := f.hom
-
-variable {R}
-
-@[simp]
-lemma toPresheaf_map_app {P Q : PresheafOfModules R}
- (f : P ⟶ Q) (X : Cᵒᵖ) :
- ((toPresheaf R).map f).app X = (f.app X).toAddMonoidHom := rfl
instance : (toPresheaf R).Additive where
-instance : (toPresheaf R).Faithful where
- map_injective {P Q} f g h := by
- ext X x
- have eq := congr_app h X
- simp only [toPresheaf_obj, toPresheaf_map_app] at eq
- simp only [← toAddMonoidHom_coe, eq]
+lemma zsmul_app (n : ℤ) (f : M₁ ⟶ M₂) (X : Cᵒᵖ) : (n • f).app X = n • f.app X := by
+ ext x
+ change (toPresheaf R ⋙ (evaluation _ _).obj X).map (n • f) x = _
+ rw [Functor.map_zsmul]
+ rfl
variable (R)
@@ -230,215 +255,22 @@ def evaluation (X : Cᵒᵖ) : PresheafOfModules.{v} R ⥤ ModuleCat (R.obj X) w
obj M := M.obj X
map f := f.app X
-instance (X : Cᵒᵖ) : (evaluation R X).Additive where
-
-variable {R}
-
-/-- Given a presheaf of modules `M` on a category `C` and `f : X ⟶ Y` in `Cᵒᵖ`, this
-is the restriction map `M.obj X ⟶ M.obj Y`, considered as a linear map to
-the restriction of scalars of `M.obj Y`. -/
-noncomputable def restrictionApp {X Y : Cᵒᵖ} (f : X ⟶ Y) (M : PresheafOfModules.{v} R) :
- M.obj X ⟶ (ModuleCat.restrictScalars (R.map f)).obj (M.obj Y) :=
- ModuleCat.semilinearMapAddEquiv (R.map f) _ _ (M.map f)
-
-lemma restrictionApp_apply {X Y : Cᵒᵖ} (f : X ⟶ Y) (M : PresheafOfModules R) (x : M.obj X) :
- restrictionApp f M x = M.map f x := by
- rfl
-
-variable (R)
+instance (X : Cᵒᵖ) : (evaluation.{v} R X).Additive where
/-- The restriction natural transformation on presheaves of modules, considered as linear maps
to restriction of scalars. -/
@[simps]
noncomputable def restriction {X Y : Cᵒᵖ} (f : X ⟶ Y) :
evaluation R X ⟶ evaluation R Y ⋙ ModuleCat.restrictScalars (R.map f) where
- app := restrictionApp f
- naturality := fun M N φ => by
- ext x
- exact (congr_hom (φ.hom.naturality f) x).symm
-
-variable {R}
-
-@[reassoc (attr := simp)]
-lemma restrictionApp_naturality {X Y : Cᵒᵖ} (f : X ⟶ Y)
- {M N : PresheafOfModules R} (φ : M ⟶ N) :
- restrictionApp f M ≫ (ModuleCat.restrictScalars (R.map f)).map (Hom.app φ Y) =
- ModuleCat.ofHom (Hom.app φ X) ≫ restrictionApp f N :=
- ((restriction R f).naturality φ).symm
-
-attribute [local simp] restrictionApp_apply
-
-lemma restrictionApp_id (M : PresheafOfModules R) (X : Cᵒᵖ) :
- restrictionApp (𝟙 X) M =
- (ModuleCat.restrictScalarsId' (R.map (𝟙 X)) (R.map_id X)).inv.app (M.obj X) := by aesop
-
-lemma restrictionApp_comp (M : PresheafOfModules R) {X Y Z : Cᵒᵖ} (f : X ⟶ Y) (g : Y ⟶ Z) :
- restrictionApp (f ≫ g) M =
- restrictionApp f M ≫
- (ModuleCat.restrictScalars (R.map f)).map (restrictionApp g M) ≫
- (ModuleCat.restrictScalarsComp' _ _ _ (R.map_comp f g)).inv.app (M.obj Z) := by aesop
-
-namespace Hom
-
-variable {P Q : PresheafOfModules R} (app : ∀ X, P.obj X →ₗ[R.obj X] Q.obj X)
-
-section
-
-variable (naturality : ∀ ⦃X Y : Cᵒᵖ⦄ (f : X ⟶ Y) (x : P.obj X),
- app Y (P.map f x) = Q.map f (app X x))
-
-/-- A constructor for morphisms in `PresheafOfModules R` that is based on the data
-of a family of linear maps over the various rings `R.obj X`. -/
-def mk' : P ⟶ Q where
- hom :=
- { app := fun X => (app X).toAddMonoidHom
- naturality := fun _ _ f => AddCommGrp.ext (naturality f) }
- map_smul X := (app X).map_smul
-
-@[simp]
-lemma mk'_app : (mk' app naturality).app = app := rfl
-
-end
-
-/-- A constructor for morphisms in `PresheafOfModules R` that is based on the data
-of a family of linear maps over the various rings `R.obj X`, and for which the
-naturality condition is stated using the restriction of scalars. -/
-abbrev mk''
- (naturality : ∀ ⦃X Y : Cᵒᵖ⦄ (f : X ⟶ Y),
- restrictionApp f P ≫ (ModuleCat.restrictScalars (R.map f)).map (app Y) =
- ModuleCat.ofHom (app X) ≫ restrictionApp f Q) :
- P ⟶ Q :=
- mk' app (fun _ _ f x => congr_hom (naturality f) x)
-
-end Hom
-
-end PresheafOfModules
-
-variable (R) in
-/-- This structure contains the data and axioms in order to
-produce a `PresheafOfModules R` from a collection of types
-equipped with module structures over the various rings `R.obj X`.
-(See the constructor `PresheafOfModules.mk'`.) -/
-structure CorePresheafOfModules where
- /-- the datum of a type for each object in `Cᵒᵖ` -/
- obj (X : Cᵒᵖ) : Type v
- /-- the abelian group structure on the types `obj X` -/
- addCommGroup (X : Cᵒᵖ) : AddCommGroup (obj X) := by infer_instance
- /-- the module structure on the types `obj X` over the various rings `R.obj X` -/
- module (X : Cᵒᵖ) : Module (R.obj X) (obj X) := by infer_instance
- /-- the semi-linear restriction maps -/
- map {X Y : Cᵒᵖ} (f : X ⟶ Y) : obj X →ₛₗ[R.map f] obj Y
- /-- `map` is compatible with the identities -/
- map_id (X : Cᵒᵖ) (x : obj X) : map (𝟙 X) x = x := by aesop_cat
- /-- `map` is compatible with the composition -/
- map_comp {X Y Z : Cᵒᵖ} (f : X ⟶ Y) (g : Y ⟶ Z) (x : obj X) :
- map (f ≫ g) x = map g (map f x) := by aesop_cat
-
--- this example is meant to test automation: the axioms for `CorePresheafOfModules` are
--- automatically found if we use the data from `M : PresheafOfModules R`
-example (M : PresheafOfModules R) : CorePresheafOfModules R where
- obj X := M.obj X
- map f := M.map f
-
-namespace CorePresheafOfModules
-
-attribute [instance] addCommGroup module
-attribute [simp] map_id map_comp
-
-variable (M : CorePresheafOfModules R)
-
-/-- The presheaf of abelian groups attached to a `CorePresheafOfModules R`. -/
-@[simps]
-def presheaf : Cᵒᵖ ⥤ AddCommGrp.{v} where
- obj X := AddCommGrp.of (M.obj X)
- map f := AddCommGrp.ofHom (M.map f).toAddMonoidHom
-
-instance (X : Cᵒᵖ) : Module (R.obj X) (M.presheaf.obj X) := M.module X
-
-/-- Constructor for `PresheafOfModules R` based on a collection of types
-equipped with module structures over the various rings `R.obj X`, see
-the structure `CorePresheafOfModules`. -/
-def toPresheafOfModules : PresheafOfModules R where
- presheaf := M.presheaf
-
-@[simp]
-lemma toPresheafOfModules_obj (X : Cᵒᵖ) :
- M.toPresheafOfModules.obj X = ModuleCat.of _ (M.obj X) := rfl
-
-@[simp]
-lemma toPresheafOfModules_presheaf_map_apply {X Y : Cᵒᵖ} (f : X ⟶ Y) (x : M.obj X) :
- M.toPresheafOfModules.presheaf.map f x = M.map f x := rfl
-
-end CorePresheafOfModules
-
-variable (R) in
-/-- This structure contains the data and axioms in order to
-produce a `PresheafOfModules R` from a collection of objects
-of type `ModuleCat (R.obj X)` for all `X`, and restriction
-maps expressed as linear maps to restriction of scalars.
-(See the constructor `PresheafOfModules.mk''`.) -/
-structure BundledCorePresheafOfModules where
- /-- the datum of a `ModuleCat (R.obj X)` for each object in `Cᵒᵖ` -/
- obj (X : Cᵒᵖ) : ModuleCat.{v} (R.obj X)
- /-- the restriction maps as linear maps to restriction of scalars -/
- map {X Y : Cᵒᵖ} (f : X ⟶ Y) : obj X ⟶ (ModuleCat.restrictScalars (R.map f)).obj (obj Y)
- /-- `map` is compatible with the identities -/
- map_id (X : Cᵒᵖ) :
- map (𝟙 X) = (ModuleCat.restrictScalarsId' (R.map (𝟙 X)) (R.map_id X)).inv.app (obj X) := by
- aesop
- /-- `map` is compatible with the composition -/
- map_comp {X Y Z : Cᵒᵖ} (f : X ⟶ Y) (g : Y ⟶ Z) :
- map (f ≫ g) = map f ≫ (ModuleCat.restrictScalars (R.map f)).map (map g) ≫
- (ModuleCat.restrictScalarsComp' (R.map f) (R.map g) (R.map (f ≫ g))
- (R.map_comp f g)).inv.app (obj Z) := by aesop
-
-namespace BundledCorePresheafOfModules
-
-variable (M : BundledCorePresheafOfModules R)
-
-attribute [local simp] map_id map_comp
-
-/-- The obvious map `BundledCorePresheafOfModules R → CorePresheafOfModules R`. -/
-noncomputable def toCorePresheafOfModules : CorePresheafOfModules R where
- obj X := (M.obj X).carrier
- map {X Y} f := (ModuleCat.semilinearMapAddEquiv (R.map f) (M.obj X) (M.obj Y)).symm (M.map f)
-
-/-- Constructor for `PresheafOfModules R` based on a collection of objects
-of type `ModuleCat (R.obj X)` for all `X`, and restriction maps expressed
-as linear maps to restriction of scalars, see
-the structure `BundledCorePresheafOfModules`. -/
-noncomputable def toPresheafOfModules : PresheafOfModules R :=
- M.toCorePresheafOfModules.toPresheafOfModules
-
-@[simp]
-lemma toPresheafOfModules_obj (X : Cᵒᵖ) :
- M.toPresheafOfModules.obj X = (M.obj X).carrier := rfl
-
-@[simp]
-lemma toPresheafOfModules_presheaf_map_apply {X Y : Cᵒᵖ} (f : X ⟶ Y) (x : M.obj X) :
- M.toPresheafOfModules.presheaf.map f x = M.map f x := rfl
-
-@[simp]
-lemma restrictionApp_toPresheafOfModules {X Y : Cᵒᵖ} (f : X ⟶ Y) :
- PresheafOfModules.restrictionApp f M.toPresheafOfModules = M.map f := rfl
-
-end BundledCorePresheafOfModules
-
-namespace PresheafOfModules
-
-variable (R)
-
-/-- Auxiliary definition for `unit`. -/
-def unitCore : CorePresheafOfModules R where
- obj X := R.obj X
- map {X Y} f := by
- exact
- { toFun := (R.map f).toFun
- map_add' := by simp
- map_smul' := by simp }
+ app M := M.map f
/-- The obvious free presheaf of modules of rank `1`. -/
-abbrev unit : PresheafOfModules R := (unitCore R).toPresheafOfModules
+def unit : PresheafOfModules R where
+ obj X := ModuleCat.of _ (R.obj X)
+ map {X Y } f :=
+ { toFun := fun x ↦ R.map f x
+ map_add' := by simp
+ map_smul' := by aesop_cat }
lemma unit_map_one {X Y : Cᵒᵖ} (f : X ⟶ Y) : (unit R).map f (1 : R.obj X) = (1 : R.obj Y) :=
(R.map f).map_one
@@ -448,6 +280,10 @@ variable {R}
/-- The type of sections of a presheaf of modules. -/
def sections (M : PresheafOfModules.{v} R) : Type _ := (M.presheaf ⋙ forget _).sections
+/-- Given a presheaf of modules `M`, `s : M.sections` and `X : Cᵒᵖ`, this is the induced
+element in `M.obj X`. -/
+abbrev sections.eval {M : PresheafOfModules.{v} R} (s : M.sections) (X : Cᵒᵖ) : M.obj X := s.1 X
+
@[simp]
lemma sections_property {M : PresheafOfModules.{v} R} (s : M.sections)
{X Y : Cᵒᵖ} (f : X ⟶ Y) : M.map f (s.1 X) = s.1 Y := s.2 f
@@ -484,12 +320,12 @@ def unitHomEquiv (M : PresheafOfModules R) :
(unit R ⟶ M) ≃ M.sections where
toFun f := sectionsMk (fun X ↦ Hom.app f X (1 : R.obj X))
(by intros; rw [← naturality_apply, unit_map_one])
- invFun s := Hom.mk'
- (fun X => (LinearMap.ringLmapEquivSelf (R.obj X) ℤ (M.obj X)).symm (s.val X)) (by
- intro X Y p (x : R.obj X)
- dsimp
- rw [map_apply, M.map_smul, ← s.2 p]
- rfl)
+ invFun s :=
+ { app := fun X ↦ (LinearMap.ringLmapEquivSelf (R.obj X) ℤ (M.obj X)).symm (s.val X)
+ naturality := fun {X Y} f ↦ by
+ ext (x : R.obj X)
+ change R.map f x • s.eval Y = M.map f (x • s.eval X)
+ simp }
left_inv f := by
ext1 X
exact (LinearMap.ringLmapEquivSelf (R.obj X) ℤ (M.obj X)).symm_apply_apply (f.app X)
@@ -499,6 +335,8 @@ def unitHomEquiv (M : PresheafOfModules R) :
section module_over_initial
+variable (X : Cᵒᵖ) (hX : Limits.IsInitial X)
+
/-!
## `PresheafOfModules R ⥤ Cᵒᵖ ⥤ ModuleCat (R.obj X)` when `X` is initial
@@ -506,6 +344,36 @@ When `X` is initial, we have `Module (R.obj X) (M.obj c)` for any `c : Cᵒᵖ`.
-/
+section
+
+variable (M : PresheafOfModules.{v} R)
+
+/-- Auxiliary definition for `forgetToPresheafModuleCatObj`. -/
+noncomputable abbrev forgetToPresheafModuleCatObjObj (Y : Cᵒᵖ) : ModuleCat (R.obj X) :=
+ (ModuleCat.restrictScalars (R.map (hX.to Y))).obj (M.obj Y)
+
+@[simp]
+lemma forgetToPresheafModuleCatObjObj_coe (Y : Cᵒᵖ) :
+ (forgetToPresheafModuleCatObjObj X hX M Y : Type _) = M.obj Y := rfl
+
+/-- Auxiliary definition for `forgetToPresheafModuleCatObj`. -/
+def forgetToPresheafModuleCatObjMap {Y Z : Cᵒᵖ} (f : Y ⟶ Z) :
+ forgetToPresheafModuleCatObjObj X hX M Y ⟶
+ forgetToPresheafModuleCatObjObj X hX M Z where
+ toFun x := M.map f x
+ map_add' := by simp
+ map_smul' r x := by
+ simp only [ModuleCat.restrictScalars.smul_def, AddHom.toFun_eq_coe, AddHom.coe_mk,
+ RingHom.id_apply, M.map_smul]
+ rw [← CategoryTheory.comp_apply, ← R.map_comp]
+ congr
+ apply hX.hom_ext
+
+@[simp]
+lemma forgetToPresheafModuleCatObjMap_apply {Y Z : Cᵒᵖ} (f : Y ⟶ Z) (m : M.obj Y) :
+ DFunLike.coe (α := M.obj Y) (β := fun _ ↦ M.obj Z)
+ (forgetToPresheafModuleCatObjMap X hX M f) m = M.map f m := rfl
+
/--
Implementation of the functor `PresheafOfModules R ⥤ Cᵒᵖ ⥤ ModuleCat (R.obj X)`
when `X` is initial.
@@ -517,20 +385,11 @@ morphism level `(f : M ⟶ N) ↦ (c ↦ f(c))`.
@[simps]
noncomputable def forgetToPresheafModuleCatObj
(X : Cᵒᵖ) (hX : Limits.IsInitial X) (M : PresheafOfModules.{v} R) :
- Cᵒᵖ ⥤ ModuleCat (R.1.obj X) where
- obj c :=
- ModuleCat.restrictScalars (R.1.map (hX.to c)) |>.obj <| M.obj c
- map := fun {c₁ c₂} f =>
- { toFun := fun x => M.presheaf.map f x
- map_add' := M.presheaf.map f |>.map_add
- map_smul' := fun r (m : ModuleCat.restrictScalars _ |>.obj _) => by
- simp only [ModuleCat.restrictScalars.smul_def, RingHom.id_apply, M.map_smul]
- rw [← CategoryTheory.comp_apply, ← R.map_comp]
- congr
- apply hX.hom_ext }
- map_id := fun c => by ext; simp_rw [M.presheaf.map_id]; rfl
- map_comp := fun {c₁ c₂ c₃} f g => by
- ext x; simp_rw [M.presheaf.map_comp]; rfl
+ Cᵒᵖ ⥤ ModuleCat (R.obj X) where
+ obj Y := forgetToPresheafModuleCatObjObj X hX M Y
+ map f := forgetToPresheafModuleCatObjMap X hX M f
+
+end
/--
Implementation of the functor `PresheafOfModules R ⥤ Cᵒᵖ ⥤ ModuleCat (R.obj X)`
@@ -541,15 +400,15 @@ on `M(c)` is given by restriction of scalars along the unique morphism `R(c) ⟶
morphism level `(f : M ⟶ N) ↦ (c ↦ f(c))`.
-/
noncomputable def forgetToPresheafModuleCatMap
- (X : Cᵒᵖ) (hX : Limits.IsInitial X) {M N : PresheafOfModules.{v} R}
- (f : M ⟶ N) :
- forgetToPresheafModuleCatObj X hX M ⟶
- forgetToPresheafModuleCatObj X hX N :=
- { app := fun c =>
- { toFun := f.app c
- map_add' := (f.app c).map_add
- map_smul' := fun r (m : M.presheaf.obj c) => (f.app c).map_smul (R.1.map (hX.to c) _) m }
- naturality := fun {c₁ c₂} i => by ext x; exact congr($(f.hom.naturality i) x) }
+ (X : Cᵒᵖ) (hX : Limits.IsInitial X) {M N : PresheafOfModules.{v} R} (f : M ⟶ N) :
+ forgetToPresheafModuleCatObj X hX M ⟶ forgetToPresheafModuleCatObj X hX N where
+ app Y :=
+ { toFun := f.app Y
+ map_add' := by simp
+ map_smul' := fun r ↦ (f.app Y).map_smul (R.1.map (hX.to Y) _) }
+ naturality Y Z g := by
+ ext x
+ exact naturality_apply f g x
/--
The forgetful functor from presheaves of modules over a presheaf of rings `R` to presheaves of
@@ -561,7 +420,7 @@ morphism level `(f : M ⟶ N) ↦ (c ↦ f(c))`.
-/
@[simps]
noncomputable def forgetToPresheafModuleCat (X : Cᵒᵖ) (hX : Limits.IsInitial X) :
- PresheafOfModules.{v} R ⥤ Cᵒᵖ ⥤ ModuleCat (R.1.obj X) where
+ PresheafOfModules.{v} R ⥤ Cᵒᵖ ⥤ ModuleCat (R.obj X) where
obj M := forgetToPresheafModuleCatObj X hX M
map f := forgetToPresheafModuleCatMap X hX f
diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/ChangeOfRings.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/ChangeOfRings.lean
index c71d1bdc5ca09..987578da8c709 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/ChangeOfRings.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/ChangeOfRings.lean
@@ -25,34 +25,29 @@ variable {C : Type u'} [Category.{v'} C] {R R' : Cᵒᵖ ⥤ RingCat.{u}}
/-- The restriction of scalars of presheaves of modules, on objects. -/
@[simps]
-noncomputable def restrictScalarsBundledCore (M' : PresheafOfModules R') (α : R ⟶ R') :
- BundledCorePresheafOfModules R where
- obj X := (ModuleCat.restrictScalars (α.app X)).obj (M'.obj X)
- map {X Y} f :=
+noncomputable def restrictScalarsObj (M' : PresheafOfModules.{v} R') (α : R ⟶ R') :
+ PresheafOfModules R where
+ obj := fun X ↦ (ModuleCat.restrictScalars (α.app X)).obj (M'.obj X)
+ map := fun {X Y} f ↦
{ toFun := M'.map f
map_add' := map_add _
- map_smul' := fun r x ↦ by
+ map_smul' := fun r x ↦ (M'.map_smul f (α.app _ r) x).trans (by
have eq := RingHom.congr_fun (α.naturality f) r
- apply (M'.map_smul f (α.app _ r) x).trans
- dsimp at eq ⊢
+ dsimp at eq
rw [← eq]
- rfl }
- map_id X := by
- ext x
- exact LinearMap.congr_fun (M'.map_id X) x
- map_comp f g := by
- ext x
- exact LinearMap.congr_fun (M'.map_comp f g) x
+ rfl ) }
/-- The restriction of scalars functor `PresheafOfModules R' ⥤ PresheafOfModules R`
induced by a morphism of presheaves of rings `R ⟶ R'`. -/
@[simps]
noncomputable def restrictScalars (α : R ⟶ R') :
PresheafOfModules.{v} R' ⥤ PresheafOfModules.{v} R where
- obj M' := (M'.restrictScalarsBundledCore α).toPresheafOfModules
- map {M₁' M₂'} φ :=
- { hom := φ.hom
- map_smul := fun X r ↦ φ.map_smul X (α.app _ r) }
+ obj M' := M'.restrictScalarsObj α
+ map φ' :=
+ { app := fun X ↦ (ModuleCat.restrictScalars (α.app X)).map (Hom.app φ' X)
+ naturality := fun {X Y} f ↦ by
+ ext x
+ exact naturality_apply φ' f x }
instance (α : R ⟶ R') : (restrictScalars.{v} α).Additive where
@@ -61,4 +56,9 @@ instance : (restrictScalars (𝟙 R)).Full := inferInstanceAs (𝟭 _).Full
instance (α : R ⟶ R') : (restrictScalars α).Faithful where
map_injective h := (toPresheaf R').map_injective ((toPresheaf R).congr_map h)
+/-- The isomorphism `restrictScalars α ⋙ toPresheaf R ≅ toPresheaf R'` for any
+morphism of presheaves of rings `α : R ⟶ R'`. -/
+noncomputable def restrictScalarsCompToPresheaf (α : R ⟶ R') :
+ restrictScalars.{v} α ⋙ toPresheaf R ≅ toPresheaf R' := Iso.refl _
+
end PresheafOfModules
diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Colimits.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Colimits.lean
index ac5a7ef32dde8..f58ed17c074ed 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Colimits.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Colimits.lean
@@ -32,13 +32,14 @@ variable [∀ {X Y : Cᵒᵖ} (f : X ⟶ Y), PreservesColimit (F ⋙ evaluation
of the functors `evaluation R X` for all `X`. -/
def evaluationJointlyReflectsColimits (c : Cocone F)
(hc : ∀ (X : Cᵒᵖ), IsColimit ((evaluation R X).mapCocone c)) : IsColimit c where
- desc s := Hom.mk'' (fun X => (hc X).desc ((evaluation R X).mapCocone s)) (fun X Y f => by
- apply (hc X).hom_ext
- intro j
- erw [(hc X).fac_assoc ((evaluation R X).mapCocone s) j, ← restrictionApp_naturality_assoc]
- rw [← Functor.map_comp]
- erw [(hc Y).fac ((evaluation R Y).mapCocone s), restrictionApp_naturality]
- rfl)
+ desc s :=
+ { app := fun X => (hc X).desc ((evaluation R X).mapCocone s)
+ naturality := fun {X Y} f ↦ (hc X).hom_ext (fun j ↦ by
+ rw [(hc X).fac_assoc ((evaluation R X).mapCocone s) j]
+ have h₁ := (c.ι.app j).naturality f
+ have h₂ := (hc Y).fac ((evaluation R Y).mapCocone s)
+ dsimp at h₁ h₂ ⊢
+ simp only [← reassoc_of% h₁, ← Functor.map_comp, h₂, Hom.naturality]) }
fac s j := by
ext1 X
exact (hc X).fac ((evaluation R X).mapCocone s) j
@@ -57,53 +58,47 @@ instance {X Y : Cᵒᵖ} (f : X ⟶ Y) :
⟨_, isColimitOfPreserves (ModuleCat.restrictScalars (R.map f))
(colimit.isColimit (F ⋙ evaluation R Y))⟩
-/-- Given `F : J ⥤ PresheafOfModules.{v} R`, this is the `BundledCorePresheafOfModules R` which
-corresponds to the presheaf of modules which sends `X` to the colimit of `F ⋙ evaluation R X`. -/
+/-- Given `F : J ⥤ PresheafOfModules.{v} R`, this is the presheaf of modules obtained by
+taking a colimit in the category of modules over `R.obj X` for all `X`. -/
@[simps]
-noncomputable def colimitBundledCore : BundledCorePresheafOfModules R where
+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 [restrictionApp_id]
- rfl)
+ 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))]
- rw [restrictionApp_comp, ModuleCat.restrictScalarsComp'_inv_app, assoc, assoc,
+ 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]
rfl)
-/-- Given `F : J ⥤ PresheafOfModules.{v} R`, this is the canonical map
-`F.obj j ⟶ (colimitBundledCore F).toPresheafOfModules` for all `j : J`. -/
-noncomputable def colimitCoconeιApp (j : J) :
- F.obj j ⟶ (colimitBundledCore F).toPresheafOfModules :=
- PresheafOfModules.Hom.mk'' (fun X => colimit.ι (F ⋙ evaluation R X) j) (fun X Y f => by
- dsimp
- erw [colimit.ι_desc_assoc, assoc, ← ι_preservesColimitsIso_inv]
- rfl)
-
-@[reassoc (attr := simp)]
-lemma colimitCoconeιApp_naturality {i j : J} (f : i ⟶ j) :
- F.map f ≫ colimitCoconeιApp F j = colimitCoconeιApp F i := by
- ext1 X
- exact colimit.w (F ⋙ evaluation R X) f
-
/-- The (colimit) cocone for `F : J ⥤ PresheafOfModules.{v} R` that is constructed from
the colimit of `F ⋙ evaluation R X` for all `X`. -/
@[simps]
noncomputable def colimitCocone : Cocone F where
- pt := (colimitBundledCore F).toPresheafOfModules
- ι := { app := colimitCoconeιApp F }
+ pt := colimitPresheafOfModules F
+ ι :=
+ { app := fun j ↦
+ { app := fun X ↦ colimit.ι (F ⋙ evaluation R X) j
+ naturality := fun {X Y} f ↦ by
+ dsimp
+ erw [colimit.ι_desc_assoc, assoc, ← ι_preservesColimitIso_inv]
+ rfl }
+ naturality := fun {X Y} f ↦ by
+ ext1 X
+ simpa using colimit.w (F ⋙ evaluation R X) f }
/-- The cocone `colimitCocone F` is colimit for any `F : J ⥤ PresheafOfModules.{v} R`. -/
noncomputable def isColimitColimitCocone : IsColimit (colimitCocone F) :=
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 d547a5c07236e..127f29b50a89e 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Limits.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Limits.lean
@@ -33,12 +33,16 @@ variable [∀ X, Small.{v} ((F ⋙ evaluation R X) ⋙ forget _).sections]
of the functors `evaluation R X` for all `X`. -/
def evaluationJointlyReflectsLimits (c : Cone F)
(hc : ∀ (X : Cᵒᵖ), IsLimit ((evaluation R X).mapCone c)) : IsLimit c where
- lift s := Hom.mk'' (fun X => (hc X).lift ((evaluation R X).mapCone s)) (fun X Y f => by
- apply (isLimitOfPreserves (ModuleCat.restrictScalars (R.map f)) (hc Y)).hom_ext
- intro j
- rw [Functor.mapCone_π_app, assoc, assoc, ← Functor.map_comp]
- erw [restrictionApp_naturality, IsLimit.fac, restrictionApp_naturality, IsLimit.fac_assoc]
- rfl)
+ lift s :=
+ { app := fun X => (hc X).lift ((evaluation R X).mapCone s)
+ naturality := fun {X Y} f ↦ by
+ apply (isLimitOfPreserves (ModuleCat.restrictScalars (R.map f)) (hc Y)).hom_ext
+ intro j
+ have h₁ := (c.π.app j).naturality f
+ have h₂ := (hc X).fac ((evaluation R X).mapCone s) j
+ rw [Functor.mapCone_π_app, assoc, assoc, ← Functor.map_comp, IsLimit.fac]
+ dsimp at h₁ h₂ ⊢
+ rw [h₁, reassoc_of% h₂, Hom.naturality] }
fac s j := by
ext1 X
exact (hc X).fac ((evaluation R X).mapCone s) j
@@ -47,21 +51,19 @@ def evaluationJointlyReflectsLimits (c : Cone F)
apply (hc X).uniq ((evaluation R X).mapCone s)
intro j
dsimp
- rw [← hm]
- rfl
+ rw [← hm, comp_app]
instance {X Y : Cᵒᵖ} (f : X ⟶ Y) :
HasLimit (F ⋙ evaluation R Y ⋙ ModuleCat.restrictScalars (R.map f)) := by
change HasLimit ((F ⋙ evaluation R Y) ⋙ ModuleCat.restrictScalars (R.map f))
infer_instance
-set_option backward.isDefEq.lazyWhnfCore false in -- See https://github.com/leanprover-community/mathlib4/issues/12534
-/-- Given `F : J ⥤ PresheafOfModules.{v} R`, this is the `BundledCorePresheafOfModules R` which
-corresponds to the presheaf of modules which sends `X` to the limit of `F ⋙ evaluation R X`. -/
+/-- Given `F : J ⥤ PresheafOfModules.{v} R`, this is the presheaf of modules obtained by
+taking a limit in the category of modules over `R.obj X` for all `X`. -/
@[simps]
-noncomputable def limitBundledCore : BundledCorePresheafOfModules R where
+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
@@ -71,8 +73,9 @@ noncomputable def limitBundledCore : BundledCorePresheafOfModules R where
dsimp
simp only [limMap_π, Functor.comp_obj, evaluation_obj, whiskerLeft_app,
restriction_app, assoc]
- erw [preservesLimitsIso_hom_π]
- rw [← ModuleCat.restrictScalarsId'App_inv_naturality, restrictionApp_id]
+ erw [preservesLimitIso_hom_π]
+ rw [← ModuleCat.restrictScalarsId'App_inv_naturality, map_id,
+ ModuleCat.restrictScalarsId'_inv_app]
dsimp
map_comp {X Y Z} f g := by
dsimp
@@ -81,38 +84,33 @@ noncomputable def limitBundledCore : BundledCorePresheafOfModules R where
apply limit.hom_ext
intro j
simp only [Functor.comp_obj, evaluation_obj, limMap_π, whiskerLeft_app, restriction_app,
- Functor.map_comp, assoc, restrictionApp_comp]
- erw [preservesLimitsIso_hom_π, ← ModuleCat.restrictScalarsComp'App_inv_naturality]
+ map_comp, ModuleCat.restrictScalarsComp'_inv_app, Functor.map_comp, assoc]
+ 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
-/-- Given `F : J ⥤ PresheafOfModules.{v} R`, this is the canonical map
-`(limitBundledCore F).toPresheafOfModules ⟶ F.obj j` for all `j : J`. -/
-noncomputable def limitConeπApp (j : J) :
- (limitBundledCore F).toPresheafOfModules ⟶ F.obj j :=
- PresheafOfModules.Hom.mk'' (fun X => limit.π (F ⋙ evaluation R X) j) (fun X Y f => by
- dsimp
- simp only [assoc, preservesLimitsIso_inv_π]
- apply limMap_π)
-
-@[reassoc (attr := simp)]
-lemma limitConeπApp_naturality {i j : J} (f : i ⟶ j) :
- limitConeπApp F i ≫ F.map f = limitConeπApp F j := by
- ext1 X
- exact limit.w (F ⋙ evaluation R X) f
-
-/-- The (limit) cone for `F : J ⥤ PresheafOfModules.{v} R` that is constructed for the limit
+/-- The (limit) cone for `F : J ⥤ PresheafOfModules.{v} R` that is constructed from the limit
of `F ⋙ evaluation R X` for all `X`. -/
@[simps]
noncomputable def limitCone : Cone F where
- pt := (limitBundledCore F).toPresheafOfModules
- π := { app := limitConeπApp F }
+ pt := limitPresheafOfModules F
+ π :=
+ { app := fun j ↦
+ { app := fun X ↦ limit.π (F ⋙ evaluation R X) j
+ naturality := fun {X Y} f ↦ by
+ dsimp
+ simp only [assoc, preservesLimitIso_inv_π]
+ apply limMap_π }
+ naturality := fun {j j'} f ↦ by
+ ext1 X
+ simpa using (limit.w (F ⋙ evaluation R X) f).symm }
/-- The cone `limitCone F` is limit for any `F : J ⥤ PresheafOfModules.{v} R`. -/
noncomputable def isLimitLimitCone : IsLimit (limitCone F) :=
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/Pushforward.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Pushforward.lean
index dd5f7c91a4e3b..ae8b9e272a34a 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Pushforward.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Pushforward.lean
@@ -26,10 +26,6 @@ variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D]
namespace PresheafOfModules
-instance {R : Dᵒᵖ ⥤ RingCat.{u}} (P : PresheafOfModules.{v} R) (F : C ⥤ D) (X : Cᵒᵖ) :
- Module ((F.op ⋙ R).obj X) ((F.op ⋙ P.presheaf).obj X) :=
- inferInstanceAs (Module (R.obj (F.op.obj X)) (P.presheaf.obj (F.op.obj X)))
-
variable (F : C ⥤ D)
/-- The pushforward functor on presheaves of modules for a functor `F : C ⥤ D` and
@@ -37,12 +33,16 @@ variable (F : C ⥤ D)
by the precomposition with `F.op`. -/
def pushforward₀ (R : Dᵒᵖ ⥤ RingCat.{u}) :
PresheafOfModules.{v} R ⥤ PresheafOfModules.{v} (F.op ⋙ R) where
- obj P :=
- { presheaf := F.op ⋙ P.presheaf
- map_smul := by intros; apply P.map_smul }
- map {P Q} φ :=
- { hom := whiskerLeft F.op φ.hom
- map_smul := by intros; apply φ.map_smul }
+ obj M :=
+ { obj := fun X ↦ ModuleCat.of _ (M.obj (F.op.obj X))
+ map := fun {X Y} f ↦ M.map (F.op.map f)
+ map_id := fun X ↦ by
+ ext x
+ exact (M.congr_map_apply (F.op.map_id X) x).trans (by simp)
+ map_comp := fun f g ↦ by
+ ext x
+ exact (M.congr_map_apply (F.op.map_comp f g) x).trans (by simp) }
+ map {M₁ M₂} φ := { app := fun X ↦ φ.app _ }
/-- The pushforward of presheaves of modules commutes with the forgetful functor
to presheaves of abelian groups. -/
@@ -53,8 +53,10 @@ def pushforward₀CompToPresheaf (R : Dᵒᵖ ⥤ RingCat.{u}) :
variable {F}
variable {R : Dᵒᵖ ⥤ RingCat.{u}} {S : Cᵒᵖ ⥤ RingCat.{u}} (φ : S ⟶ F.op ⋙ R)
+attribute [local simp] pushforward₀ in
/-- The pushforward functor `PresheafOfModules R ⥤ PresheafOfModules S` induced by
a morphism of presheaves of rings `S ⟶ F.op ⋙ R`. -/
+@[simps! obj_obj]
noncomputable def pushforward : PresheafOfModules.{v} R ⥤ PresheafOfModules.{v} S :=
pushforward₀ F R ⋙ restrictScalars φ
@@ -64,21 +66,22 @@ noncomputable def pushforwardCompToPresheaf :
pushforward.{v} φ ⋙ toPresheaf _ ≅ toPresheaf _ ⋙ (whiskeringLeft _ _ _).obj F.op :=
Iso.refl _
--- unfortunately, `pushforward_obj_obj` and `pushforward_obj_map` cannot be both simp lemmas
-lemma pushforward_obj_obj (M : PresheafOfModules.{v} R) (X : Cᵒᵖ) :
- ((pushforward φ).obj M).obj X =
- (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop))) := rfl
-
@[simp]
lemma pushforward_obj_map_apply (M : PresheafOfModules.{v} R) {X Y : Cᵒᵖ} (f : X ⟶ Y)
(m : (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop)))) :
- ((pushforward φ).obj M).map f m = M.map (F.map f.unop).op m := by
- rfl
+ DFunLike.coe
+ (α := (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop))))
+ (β := fun _ ↦ (ModuleCat.restrictScalars (φ.app Y)).obj
+ (M.obj (Opposite.op (F.obj Y.unop)))) (((pushforward φ).obj M).map f) m =
+ M.map (F.map f.unop).op m := rfl
@[simp]
lemma pushforward_map_app_apply {M N : PresheafOfModules.{v} R} (α : M ⟶ N) (X : Cᵒᵖ)
(m : (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop)))) :
- ((pushforward φ).map α).app X m = α.app (Opposite.op (F.obj X.unop)) m := by
- rfl
+ DFunLike.coe
+ (α := (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop))))
+ (β := fun _ ↦ (ModuleCat.restrictScalars (φ.app X)).obj
+ (N.obj (Opposite.op (F.obj X.unop))))
+ (((pushforward φ).map α).app X) m = α.app (Opposite.op (F.obj X.unop)) m := rfl
end PresheafOfModules
diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafification.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafification.lean
index 8ec02b10ada53..55d42463d8a56 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafification.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafification.lean
@@ -43,15 +43,19 @@ the associated sheaf of modules functor `PresheafOfModules.{v} R₀ ⥤ SheafOfM
@[simps! (config := .lemmasOnly) map]
noncomputable def sheafification : PresheafOfModules.{v} R₀ ⥤ SheafOfModules.{v} R where
obj M₀ := sheafify α (CategoryTheory.toSheafify J M₀.presheaf)
- map f := sheafifyMap _ _ _ f ((presheafToSheaf J AddCommGrp).map f.hom) (by simp)
+ map f := sheafifyMap _ _ _ f
+ ((toPresheaf R₀ ⋙ presheafToSheaf J AddCommGrp).map f)
+ (by apply toSheafify_naturality)
map_id M₀ := by
ext1
apply (toPresheaf _).map_injective
- simp [toPresheaf, sheafify]
+ simp
+ rfl
map_comp _ _ := by
ext1
apply (toPresheaf _).map_injective
- simp [toPresheaf, sheafify]
+ simp
+ rfl
/-- The sheafification of presheaves of modules commutes with the functor which
forgets the module structures. -/
@@ -75,19 +79,19 @@ noncomputable def sheafificationHomEquiv
(P ⟶ (restrictScalars α).obj ((SheafOfModules.forget _).obj F)) := by
apply sheafifyHomEquiv
-lemma sheafificationHomEquiv_hom'
+lemma toPresheaf_map_sheafificationHomEquiv_def
{P : PresheafOfModules.{v} R₀} {F : SheafOfModules.{v} R}
(f : (sheafification α).obj P ⟶ F) :
- (sheafificationHomEquiv α f).hom =
- CategoryTheory.toSheafify J P.presheaf ≫ f.val.hom := rfl
+ (toPresheaf R₀).map (sheafificationHomEquiv α f) =
+ CategoryTheory.toSheafify J P.presheaf ≫ (toPresheaf R.val).map f.val := rfl
-lemma sheafificationHomEquiv_hom
+lemma toPresheaf_map_sheafificationHomEquiv
{P : PresheafOfModules.{v} R₀} {F : SheafOfModules.{v} R}
(f : (sheafification α).obj P ⟶ F) :
- (sheafificationHomEquiv α f).hom =
+ (toPresheaf R₀).map (sheafificationHomEquiv α f) =
(sheafificationAdjunction J AddCommGrp).homEquiv P.presheaf
((SheafOfModules.toSheaf _).obj F) ((SheafOfModules.toSheaf _).map f) := by
- rw [sheafificationHomEquiv_hom', Adjunction.homEquiv_unit]
+ rw [toPresheaf_map_sheafificationHomEquiv_def, Adjunction.homEquiv_unit]
dsimp
lemma toSheaf_map_sheafificationHomEquiv_symm
@@ -95,7 +99,7 @@ lemma toSheaf_map_sheafificationHomEquiv_symm
(g : P ⟶ (restrictScalars α).obj ((SheafOfModules.forget _).obj F)) :
(SheafOfModules.toSheaf _).map ((sheafificationHomEquiv α).symm g) =
(((sheafificationAdjunction J AddCommGrp).homEquiv
- P.presheaf ((SheafOfModules.toSheaf R).obj F)).symm g.hom) := by
+ P.presheaf ((SheafOfModules.toSheaf R).obj F)).symm ((toPresheaf R₀).map g)) := by
obtain ⟨f, rfl⟩ := (sheafificationHomEquiv α).surjective g
apply ((sheafificationAdjunction J AddCommGrp).homEquiv _ _).injective
rw [Equiv.apply_symm_apply, Adjunction.homEquiv_unit, Equiv.symm_apply_apply]
@@ -104,7 +108,6 @@ lemma toSheaf_map_sheafificationHomEquiv_symm
/-- Given a locally bijective morphism `α : R₀ ⟶ R.val` where `R₀` is a presheaf of rings
and `R` a sheaf of rings, this is the adjunction
`sheafification.{v} α ⊣ SheafOfModules.forget R ⋙ restrictScalars α`. -/
-@[simps! (config := .lemmasOnly) homEquiv_apply]
noncomputable def sheafificationAdjunction :
sheafification.{v} α ⊣ SheafOfModules.forget R ⋙ restrictScalars α :=
Adjunction.mkOfHomEquiv
@@ -113,19 +116,22 @@ noncomputable def sheafificationAdjunction :
apply (SheafOfModules.toSheaf _).map_injective
rw [Functor.map_comp]
erw [toSheaf_map_sheafificationHomEquiv_symm,
- toSheaf_map_sheafificationHomEquiv_symm]
- apply Adjunction.homEquiv_naturality_left_symm
+ toSheaf_map_sheafificationHomEquiv_symm α g]
+ rw [Functor.map_comp]
+ apply (CategoryTheory.sheafificationAdjunction J
+ AddCommGrp.{v}).homEquiv_naturality_left_symm
homEquiv_naturality_right := fun {P₀ M N} f g ↦ by
apply (toPresheaf _).map_injective
- dsimp [toPresheaf]
- erw [sheafificationHomEquiv_hom, sheafificationHomEquiv_hom]
- rw [Functor.map_comp]
- apply Adjunction.homEquiv_naturality_right }
+ erw [toPresheaf_map_sheafificationHomEquiv] }
+
+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
@[simp]
-lemma sheafificationAdjunction_unit_app_hom (M₀ : PresheafOfModules.{v} R₀) :
- ((sheafificationAdjunction α).unit.app M₀).hom = CategoryTheory.toSheafify J M₀.presheaf := by
- rfl
+lemma toPresheaf_map_sheafificationAdjunction_unit_app (M₀ : PresheafOfModules.{v} R₀) :
+ (toPresheaf _).map ((sheafificationAdjunction α).unit.app M₀) =
+ CategoryTheory.toSheafify J M₀.presheaf := rfl
instance : (sheafification.{v} α).IsLeftAdjoint :=
(sheafificationAdjunction α).isLeftAdjoint
diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean
index 0d10d6d1547c9..c00b766a8362d 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean
@@ -16,7 +16,7 @@ of the underlying presheaf of abelian groups of `M₀`, i.e. we have a locally b
map `φ : M₀.presheaf ⟶ A.val`, then we endow `A` with the structure of a
sheaf of modules over `R`: this is `PresheafOfModules.sheafify α φ`.
-In many application, the morphism `α` shall be the identity, but this more
+In many applications, the morphism `α` shall be the identity, but this more
general construction allows the sheafification of both the presheaf of rings
and the presheaf of modules.
@@ -42,7 +42,7 @@ variable {R : Cᵒᵖ ⥤ RingCat.{u}} {M : PresheafOfModules.{v} R} {X : C} {P
/-- The scalar multiplication of family of elements of a presheaf of modules `M` over `R`
by a family of elements of `R`. -/
def smul : FamilyOfElements (M.presheaf ⋙ forget _) P := fun Y f hf =>
- HSMul.hSMul (α := R.obj (Opposite.op Y)) (β := M.presheaf.obj (Opposite.op Y)) (r f hf) (m f hf)
+ HSMul.hSMul (α := R.obj (Opposite.op Y)) (β := M.obj (Opposite.op Y)) (r f hf) (m f hf)
end smul
@@ -57,7 +57,7 @@ include hA
lemma _root_.PresheafOfModules.Sheafify.app_eq_of_isLocallyInjective
{Y : C} (r₀ r₀' : R₀.obj (Opposite.op Y))
- (m₀ m₀' : M₀.presheaf.obj (Opposite.op Y))
+ (m₀ m₀' : M₀.obj (Opposite.op Y))
(hr₀ : α.app _ r₀ = α.app _ r₀')
(hm₀ : φ.app _ m₀ = φ.app _ m₀') :
φ.app _ (r₀ • m₀) = φ.app _ (r₀' • m₀') := by
@@ -72,16 +72,15 @@ lemma _root_.PresheafOfModules.Sheafify.app_eq_of_isLocallyInjective
lemma isCompatible_map_smul_aux {Y Z : C} (f : Y ⟶ X) (g : Z ⟶ Y)
(r₀ : R₀.obj (Opposite.op Y)) (r₀' : R₀.obj (Opposite.op Z))
- (m₀ : M₀.presheaf.obj (Opposite.op Y)) (m₀' : M₀.presheaf.obj (Opposite.op Z))
+ (m₀ : M₀.obj (Opposite.op Y)) (m₀' : M₀.obj (Opposite.op Z))
(hr₀ : α.app _ r₀ = R.map f.op r) (hr₀' : α.app _ r₀' = R.map (f.op ≫ g.op) r)
(hm₀ : φ.app _ m₀ = A.map f.op m) (hm₀' : φ.app _ m₀' = A.map (f.op ≫ g.op) m) :
- φ.app _ (M₀.presheaf.map g.op (r₀ • m₀)) = φ.app _ (r₀' • m₀') := by
+ φ.app _ (M₀.map g.op (r₀ • m₀)) = φ.app _ (r₀' • m₀') := by
rw [← PresheafOfModules.Sheafify.app_eq_of_isLocallyInjective α φ hA (R₀.map g.op r₀) r₀'
- (M₀.presheaf.map g.op m₀) m₀', M₀.map_smul]
+ (M₀.map g.op m₀) m₀', M₀.map_smul]
· 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
@@ -244,11 +240,11 @@ protected lemma smul_add : smul α φ r (m + m') = smul α φ r m + smul α φ r
refine J.intersection_covering (J.intersection_covering ?_ ?_) ?_
all_goals apply Presheaf.imageSieve_mem
apply A.isSeparated _ _ hS
- rintro Y f ⟨⟨⟨r₀, hr₀⟩, ⟨m₀ : M₀.presheaf.obj _, hm₀⟩⟩, ⟨m₀' : M₀.presheaf.obj _, hm₀'⟩⟩
- erw [(A.val.map f.op).map_add, map_smul_eq α φ r m f.op r₀ hr₀ m₀ hm₀,
+ rintro Y f ⟨⟨⟨r₀, hr₀⟩, ⟨m₀ : M₀.obj _, hm₀⟩⟩, ⟨m₀' : M₀.obj _, 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]
@@ -269,8 +265,8 @@ protected lemma mul_smul : smul α φ (r * r') m = smul α φ r (smul α φ r' m
refine J.intersection_covering (J.intersection_covering ?_ ?_) ?_
all_goals apply Presheaf.imageSieve_mem
apply A.isSeparated _ _ hS
- rintro Y f ⟨⟨⟨r₀ : R₀.obj _, hr₀⟩, ⟨r₀' : R₀.obj _, hr₀'⟩⟩, ⟨m₀ : M₀.presheaf.obj _, hm₀⟩⟩
- erw [map_smul_eq α φ (r * r') m f.op (r₀ * r₀')
+ rintro Y f ⟨⟨⟨r₀ : R₀.obj _, hr₀⟩, ⟨r₀' : R₀.obj _, hr₀'⟩⟩, ⟨m₀ : M₀.obj _, hm₀⟩⟩
+ 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
@@ -309,25 +305,28 @@ sheaf of abelian groups of a presheaf of modules `M₀` over `R₀`, this is
the sheaf of modules over `R` which is obtained by endowing the sections of
`A.val` with a scalar multiplication. -/
noncomputable def sheafify : SheafOfModules.{v} R where
- val :=
- { presheaf := A.val
- module := Sheafify.module α φ
- map_smul := fun _ _ _ => by apply Sheafify.map_smul }
+ val := letI := Sheafify.module α φ; ofPresheaf A.val (Sheafify.map_smul _ _)
isSheaf := A.cond
/-- The canonical morphism from a presheaf of modules to its associated sheaf. -/
-@[simps]
-def toSheafify : M₀ ⟶ (restrictScalars α).obj (sheafify α φ).val where
- hom := φ
- map_smul X r₀ m₀ := by
+def toSheafify : M₀ ⟶ (restrictScalars α).obj (sheafify α φ).val :=
+ homMk φ (fun X r₀ m₀ ↦ by
simpa using (Sheafify.map_smul_eq α φ (α.app _ r₀) (φ.app _ m₀) (𝟙 _)
- r₀ (by aesop) m₀ (by simp)).symm
+ r₀ (by aesop) m₀ (by simp)).symm)
+
+@[simp]
+lemma toSheafify_app_apply (X : Cᵒᵖ) (x : M₀.obj X) :
+ DFunLike.coe (α := M₀.obj X) (β := fun _ ↦ A.val.obj X)
+ ((toSheafify α φ).app X) x = φ.app X x := rfl
+
+@[simp]
+lemma toPresheaf_map_toSheafify : (toPresheaf R₀).map (toSheafify α φ) = φ := rfl
-instance : Presheaf.IsLocallyInjective J (toSheafify α φ).hom := by
- dsimp; infer_instance
+instance : IsLocallyInjective J (toSheafify α φ) := by
+ dsimp [IsLocallyInjective]; infer_instance
-instance : Presheaf.IsLocallySurjective J (toSheafify α φ).hom := by
- dsimp; infer_instance
+instance : IsLocallySurjective J (toSheafify α φ) := by
+ dsimp [IsLocallySurjective]; infer_instance
variable [J.WEqualsLocallyBijective AddCommGrp.{v}]
@@ -341,10 +340,10 @@ noncomputable def sheafifyHomEquiv' {F : PresheafOfModules.{v} R.val}
(homEquivOfIsLocallyBijective (f := toSheafify α φ)
(N := (restrictScalars α).obj F) hF)
-lemma comp_sheafifyHomEquiv'_symm_hom {F : PresheafOfModules.{v} R.val}
+lemma comp_toPresheaf_map_sheafifyHomEquiv'_symm_hom {F : PresheafOfModules.{v} R.val}
(hF : Presheaf.IsSheaf J F.presheaf) (f : M₀ ⟶ (restrictScalars α).obj F) :
- φ ≫ ((sheafifyHomEquiv' α φ hF).symm f).hom = f.hom :=
- congr_arg Hom.hom ((sheafifyHomEquiv' α φ hF).apply_symm_apply f)
+ φ ≫ (toPresheaf R.val).map ((sheafifyHomEquiv' α φ hF).symm f) = (toPresheaf R₀).map f :=
+ (toPresheaf _).congr_map ((sheafifyHomEquiv' α φ hF).apply_symm_apply f)
/-- The bijection
`(sheafify α φ ⟶ F) ≃ (M₀ ⟶ (restrictScalars α).obj ((SheafOfModules.forget _).obj F))`
@@ -367,17 +366,15 @@ variable {M₀' : PresheafOfModules.{v} R₀} {A' : Sheaf J AddCommGrp.{v}}
induced by morphisms `τ₀ : M₀ ⟶ M₀'` and `τ : A ⟶ A'`
which satisfy `τ₀.hom ≫ φ' = φ ≫ τ.val`. -/
@[simps]
-def sheafifyMap (fac : τ₀.hom ≫ φ' = φ ≫ τ.val) : sheafify α φ ⟶ sheafify α φ' where
- val :=
- { hom := τ.val
- map_smul := by
- let f := (sheafifyHomEquiv' α φ (by exact A'.cond)).symm (τ₀ ≫ toSheafify α φ')
- have eq : τ.val = f.hom := ((J.W_of_isLocallyBijective φ).homEquiv _ A'.cond).injective
- (by
- dsimp [f]
- erw [comp_sheafifyHomEquiv'_symm_hom]
- simp only [← fac, toSheafify_hom, Hom.comp_hom])
- convert f.map_smul }
+def sheafifyMap (fac : (toPresheaf R₀).map τ₀ ≫ φ' = φ ≫ τ.val) :
+ sheafify α φ ⟶ sheafify α φ' where
+ val := homMk τ.val (fun X r m ↦ by
+ let f := (sheafifyHomEquiv' α φ (by exact A'.cond)).symm (τ₀ ≫ toSheafify α φ')
+ suffices τ.val = (toPresheaf _).map f by simpa only [this] using (f.app X).map_smul r m
+ apply ((J.W_of_isLocallyBijective φ).homEquiv _ A'.cond).injective
+ dsimp [f]
+ erw [comp_toPresheaf_map_sheafifyHomEquiv'_symm_hom]
+ rw [← fac, Functor.map_comp, toPresheaf_map_toSheafify])
end
diff --git a/Mathlib/Algebra/Category/ModuleCat/Products.lean b/Mathlib/Algebra/Category/ModuleCat/Products.lean
index b4aa2e92eb57f..b986cea15a7f5 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Products.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Products.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.ModuleCat.Basic
import Mathlib.LinearAlgebra.Pi
diff --git a/Mathlib/Algebra/Category/ModuleCat/Projective.lean b/Mathlib/Algebra/Category/ModuleCat/Projective.lean
index cb26babea2730..7cc29fe3e1107 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Projective.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Projective.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Scott Morrison
+Authors: Markus Himmel, Kim Morrison
-/
import Mathlib.Algebra.Category.ModuleCat.EpiMono
import Mathlib.Algebra.Module.Projective
diff --git a/Mathlib/Algebra/Category/ModuleCat/Sheaf.lean b/Mathlib/Algebra/Category/ModuleCat/Sheaf.lean
index fb6b24bc7f604..3a23ba4b4c02e 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Sheaf.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Sheaf.lean
@@ -15,12 +15,6 @@ import Mathlib.CategoryTheory.Sites.Whiskering
In this file, we define the category `SheafOfModules R` when `R : Sheaf J RingCat`
is a sheaf of rings on a category `C` equipped with a Grothendieck topology `J`.
-## TODO
-* construct the associated sheaf: more precisely, given a morphism of `α : P ⟶ R.val`
-where `P` is a presheaf of rings and `R` a sheaf of rings such that `α` identifies
-`R` to the associated sheaf of `P`, then construct a sheafification functor
-`PresheafOfModules P ⥤ SheafOfModules R`.
-
-/
universe v v₁ u₁ u w
@@ -91,7 +85,7 @@ def evaluation (X : Cᵒᵖ) : SheafOfModules.{v} R ⥤ ModuleCat.{v} (R.val.obj
@[simps]
def toSheaf : SheafOfModules.{v} R ⥤ Sheaf J AddCommGrp.{v} where
obj M := ⟨_, M.isSheaf⟩
- map f := { val := f.val.hom }
+ map f := { val := (forget R ⋙ PresheafOfModules.toPresheaf R.val).map f }
/--
The forgetful functor from sheaves of modules over sheaf of ring `R` to sheaves of `R(X)`-module
@@ -185,36 +179,55 @@ end SheafOfModules
namespace PresheafOfModules
-variable {R : Cᵒᵖ ⥤ RingCat.{u}} {M₁ M₂ : PresheafOfModules.{v} R}
- (f : M₁ ⟶ M₂) {N : PresheafOfModules.{v} R}
- (hN : Presheaf.IsSheaf J N.presheaf)
- [J.WEqualsLocallyBijective AddCommGrp.{v}]
- [Presheaf.IsLocallySurjective J f.hom]
- [Presheaf.IsLocallyInjective J f.hom]
+variable (J)
+variable {R : Cᵒᵖ ⥤ RingCat.{u}} {M₁ M₂ : PresheafOfModules.{v} R} (f : M₁ ⟶ M₂)
+
+/-- A morphism of presheaves of modules is locally surjective
+if the underlying morphism of presheaves of abelian groups is. -/
+abbrev IsLocallySurjective : Prop :=
+ Presheaf.IsLocallySurjective J ((PresheafOfModules.toPresheaf R).map f)
+
+/-- A morphism of presheaves of modules is locally injective
+if the underlying morphism of presheaves of abelian groups is. -/
+abbrev IsLocallyInjective : Prop :=
+ Presheaf.IsLocallyInjective J ((PresheafOfModules.toPresheaf R).map f)
+
+variable {N : PresheafOfModules.{v} R} (hN : Presheaf.IsSheaf J N.presheaf)
+ [J.WEqualsLocallyBijective AddCommGrp.{v}]
+ [IsLocallySurjective J f] [IsLocallyInjective J f]
+
+variable {J}
/-- The bijection `(M₂ ⟶ N) ≃ (M₁ ⟶ N)` induced by a locally bijective morphism
`f : M₁ ⟶ M₂` of presheaves of modules, when `N` is a sheaf. -/
@[simps]
noncomputable def homEquivOfIsLocallyBijective : (M₂ ⟶ N) ≃ (M₁ ⟶ N) where
toFun φ := f ≫ φ
- invFun ψ :=
- { hom := ((J.W_of_isLocallyBijective f.hom).homEquiv _ hN).symm ψ.hom
- map_smul := by
- obtain ⟨φ, hφ⟩ := ((J.W_of_isLocallyBijective f.hom).homEquiv _ hN).surjective ψ.hom
+ invFun ψ := homMk (((J.W_of_isLocallyBijective
+ ((PresheafOfModules.toPresheaf R).map f)).homEquiv _ hN).symm
+ ((PresheafOfModules.toPresheaf R).map ψ)) (by
+ obtain ⟨φ, hφ⟩ := ((J.W_of_isLocallyBijective
+ ((PresheafOfModules.toPresheaf R).map f)).homEquiv _ hN).surjective
+ ((PresheafOfModules.toPresheaf R).map ψ)
simp only [← hφ, Equiv.symm_apply_apply]
- dsimp at hφ
+ replace hφ : ∀ (Z : Cᵒᵖ) (x : M₁.obj Z), φ.app Z (f.app Z x) = ψ.app Z x :=
+ fun Z x ↦ congr_fun ((forget _).congr_map (congr_app hφ Z)) x
intro X r y
- apply hN.isSeparated _ _ (Presheaf.imageSieve_mem J f.hom y)
- rintro Y p ⟨x, hx⟩
- have eq := ψ.map_smul _ (R.map p.op r) x
- simp only [← hφ] at eq
- dsimp at eq
- erw [← NatTrans.naturality_apply φ p.op (r • y), N.map_smul, M₂.map_smul,
- ← NatTrans.naturality_apply φ p.op y, ← hx, ← eq, f.map_smul]
- rfl }
+ apply hN.isSeparated _ _
+ (Presheaf.imageSieve_mem J ((toPresheaf R).map f) y)
+ rintro Y p ⟨x : M₁.obj _, hx : f.app _ x = M₂.map p.op y⟩
+ have hφ' : ∀ (z : M₂.obj X), φ.app _ (M₂.map p.op z) =
+ N.map p.op (φ.app _ z) := congr_fun ((forget _).congr_map (φ.naturality p.op))
+ change N.map p.op (φ.app X (r • y)) = N.map p.op (r • φ.app X y)
+ rw [← hφ', M₂.map_smul, ← hx, ← (f.app _).map_smul, hφ, (ψ.app _).map_smul,
+ ← hφ, hx, N.map_smul, hφ'])
left_inv φ := (toPresheaf _).map_injective
- (((J.W_of_isLocallyBijective f.hom).homEquiv _ hN).left_inv φ.hom)
+ (((J.W_of_isLocallyBijective
+ ((PresheafOfModules.toPresheaf R).map f)).homEquiv _ hN).left_inv
+ ((PresheafOfModules.toPresheaf R).map φ))
right_inv ψ := (toPresheaf _).map_injective
- (((J.W_of_isLocallyBijective f.hom).homEquiv _ hN).right_inv ψ.hom)
+ (((J.W_of_isLocallyBijective
+ ((PresheafOfModules.toPresheaf R).map f)).homEquiv _ hN).right_inv
+ ((PresheafOfModules.toPresheaf R).map ψ))
end PresheafOfModules
diff --git a/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean b/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean
index 906a646c6048c..53503eb352661 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean
@@ -45,22 +45,23 @@ namespace PresheafOfModules
variable {R R' : Cᵒᵖ ⥤ RingCat.{u}} (α : R ⟶ R')
{M₁ M₂ : PresheafOfModules.{v} R'}
-/-- The functor `PresheafOfModules.restrictScalars α` induces bijection on
+/-- The functor `PresheafOfModules.restrictScalars α` induces bijections on
morphisms if `α` is locally surjective and the target presheaf is a sheaf. -/
noncomputable def restrictHomEquivOfIsLocallySurjective
(hM₂ : Presheaf.IsSheaf J M₂.presheaf) [Presheaf.IsLocallySurjective J α] :
(M₁ ⟶ M₂) ≃ ((restrictScalars α).obj M₁ ⟶ (restrictScalars α).obj M₂) where
toFun f := (restrictScalars α).map f
- invFun g :=
- { hom := g.hom
- map_smul := fun X r' m => by
- apply hM₂.isSeparated _ _ (Presheaf.imageSieve_mem J α r')
- rintro Y p ⟨r : R.obj _, hr⟩
- erw [M₂.map_smul, ← NatTrans.naturality_apply g.hom p.op m,
- ← hr, ← g.map_smul _ r (M₁.presheaf.map p.op m),
- ← NatTrans.naturality_apply g.hom p.op (r' • m),
- M₁.map_smul p.op r' m, ← hr]
- rfl }
+ invFun g := homMk ((toPresheaf R).map g) (fun X r' m ↦ by
+ apply hM₂.isSeparated _ _ (Presheaf.imageSieve_mem J α r')
+ rintro Y p ⟨r : R.obj _, hr⟩
+ have hg : ∀ (z : M₁.obj X), g.app _ (M₁.map p.op z) = M₂.map p.op (g.app X z) :=
+ fun z ↦ congr_fun ((forget _).congr_map (g.naturality p.op)) z
+ change M₂.map p.op (g.app X (r' • m)) = M₂.map p.op (r' • show M₂.obj X from g.app X m)
+ dsimp at hg ⊢
+ rw [← hg, M₂.map_smul, ← hg, ← hr]
+ erw [← (g.app _).map_smul]
+ rw [M₁.map_smul, ← hr]
+ rfl)
left_inv _ := rfl
right_inv _ := rfl
diff --git a/Mathlib/Algebra/Category/ModuleCat/Simple.lean b/Mathlib/Algebra/Category/ModuleCat/Simple.lean
index f693c5fcbc18c..a36bd8151ab84 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Simple.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Simple.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2022 Pierre-Alexandre Bazin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Pierre-Alexandre Bazin, Scott Morrison
+Authors: Pierre-Alexandre Bazin, Kim Morrison
-/
import Mathlib.CategoryTheory.Simple
import Mathlib.Algebra.Category.ModuleCat.Subobject
@@ -34,7 +34,7 @@ instance simple_of_isSimpleModule [IsSimpleModule R M] : Simple (of R M) :=
instance isSimpleModule_of_simple (M : ModuleCat R) [Simple M] : IsSimpleModule R M :=
simple_iff_isSimpleModule.mp (Simple.of_iso (ofSelfIso M))
-open FiniteDimensional
+open Module
attribute [local instance] moduleOfAlgebraModule isScalarTower_of_algebra_moduleCat
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/ModuleCat/Tannaka.lean b/Mathlib/Algebra/Category/ModuleCat/Tannaka.lean
index 747def447779c..3d2e15121ab7e 100644
--- a/Mathlib/Algebra/Category/ModuleCat/Tannaka.lean
+++ b/Mathlib/Algebra/Category/ModuleCat/Tannaka.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.ModuleCat.Basic
import Mathlib.LinearAlgebra.Span
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 d4510713aa6c0..4dbb96dfa65aa 100644
--- a/Mathlib/Algebra/Category/MonCat/Basic.lean
+++ b/Mathlib/Algebra/Category/MonCat/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.ConcreteCategory.BundledHom
import Mathlib.Algebra.PUnitInstances.Algebra
@@ -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 98bd6071b109b..ac67635fefbbe 100644
--- a/Mathlib/Algebra/Category/MonCat/Colimits.lean
+++ b/Mathlib/Algebra/Category/MonCat/Colimits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.MonCat.Basic
import Mathlib.CategoryTheory.Limits.HasLimits
@@ -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 0de870438eedb..123dc3372c9c1 100644
--- a/Mathlib/Algebra/Category/MonCat/Limits.lean
+++ b/Mathlib/Algebra/Category/MonCat/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.MonCat.Basic
import Mathlib.Algebra.Group.Pi.Lemmas
@@ -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 49cbc29469c4e..968ee34718fb1 100644
--- a/Mathlib/Algebra/Category/Ring/Adjunctions.lean
+++ b/Mathlib/Algebra/Category/Ring/Adjunctions.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johannes Hölzl
+Authors: Kim Morrison, Johannes Hölzl
-/
import Mathlib.Algebra.Category.Ring.Basic
import Mathlib.Algebra.MvPolynomial.CommRing
@@ -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 f195911a46493..4d03754154342 100644
--- a/Mathlib/Algebra/Category/Ring/Basic.lean
+++ b/Mathlib/Algebra/Category/Ring/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johannes Hölzl, Yury Kudryashov
+Authors: Kim Morrison, Johannes Hölzl, Yury Kudryashov
-/
import Mathlib.Algebra.Category.Grp.Basic
import Mathlib.CategoryTheory.ConcreteCategory.ReflectsIso
@@ -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⟩
@@ -546,10 +539,16 @@ theorem coe_of (R : Type u) [CommRing R] : (CommRingCat.of R : Type u) = R :=
instance hasForgetToRingCat : HasForget₂ CommRingCat RingCat :=
BundledHom.forget₂ _ _
+@[simp] lemma forgetToRingCat_obj (A : CommRingCat.{u}) :
+ ((forget₂ _ RingCat).obj A : Type _) = A := rfl
+
+@[simp] lemma forgetToRingCat_map_apply {A B : CommRingCat.{u}} (f : A ⟶ B) (a : A) :
+ DFunLike.coe (α := A) (β := fun _ ↦ B) ((forget₂ _ RingCat).map f) a = f a := rfl
+
/-- 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⟩
@@ -601,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 5d7cc51769fd3..8e8ac95f71651 100644
--- a/Mathlib/Algebra/Category/Ring/Colimits.lean
+++ b/Mathlib/Algebra/Category/Ring/Colimits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.Ring.Basic
import Mathlib.CategoryTheory.Limits.HasLimits
@@ -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 a7f813b611915..bc7c9f6b9f853 100644
--- a/Mathlib/Algebra/Category/Ring/Limits.lean
+++ b/Mathlib/Algebra/Category/Ring/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Ring.Pi
import Mathlib.Algebra.Category.Ring.Basic
@@ -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 bbd284531afbf..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
@@ -70,8 +71,8 @@ theorem prime_dvd_char_iff_dvd_card {R : Type*} [CommRing R] [Fintype R] (p :
rw [mul_zero, ← mul_assoc, hu, one_mul] at hr₁
exact mt AddMonoid.addOrderOf_eq_one_iff.mpr (ne_of_eq_of_ne hr (Nat.Prime.ne_one Fact.out)) hr₁
-/-- A prime that does not divide the cardinality of a finite commutative ring `R`
-is a unit in `R`. -/
+/-- A prime that divides the cardinality of a finite commutative ring `R`
+isn't a unit in `R`. -/
theorem not_isUnit_prime_of_dvd_card {R : Type*} [CommRing R] [Fintype R] (p : ℕ) [Fact p.Prime]
(hp : p ∣ Fintype.card R) : ¬IsUnit (p : R) :=
mt (isUnit_iff_not_dvd_char R p).mp
diff --git a/Mathlib/Algebra/CharP/Defs.lean b/Mathlib/Algebra/CharP/Defs.lean
index b9c236c16d197..9c41f5a2b3741 100644
--- a/Mathlib/Algebra/CharP/Defs.lean
+++ b/Mathlib/Algebra/CharP/Defs.lean
@@ -3,21 +3,27 @@ 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
+open Set
+
variable (R : Type*)
namespace CharP
@@ -83,9 +89,6 @@ 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
@@ -93,10 +96,10 @@ variable [AddGroupWithOne R] (p : ℕ) [CharP R p] {a b : ℤ}
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, ← dvd_neg]
+ · rw [← neg_eq_zero, ← Int.cast_neg, ← Int.dvd_neg]
lift -a to ℕ using neg_nonneg.mpr (le_of_lt h) with b
rw [Int.cast_natCast, CharP.cast_eq_zero_iff R p, Int.natCast_dvd_natCast]
- · simp only [Int.cast_zero, eq_self_iff_true, dvd_zero]
+ · simp only [Int.cast_zero, eq_self_iff_true, Int.dvd_zero]
· lift a to ℕ using le_of_lt h with b
rw [Int.cast_natCast, CharP.cast_eq_zero_iff R p, Int.natCast_dvd_natCast]
@@ -181,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
@@ -201,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
@@ -233,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
@@ -261,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
@@ -306,112 +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 : ℕ) : CharP (Fin (n + 1)) (n + 1) where
- cast_eq_zero_iff' := by simp [Fin.ext_iff, Nat.dvd_iff_mod_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/Defs.lean b/Mathlib/Algebra/CharZero/Defs.lean
index 8f2cf74d4cef2..c82356e6fa6e7 100644
--- a/Mathlib/Algebra/CharZero/Defs.lean
+++ b/Mathlib/Algebra/CharZero/Defs.lean
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
import Mathlib.Data.Int.Cast.Defs
-import Mathlib.Algebra.NeZero
import Mathlib.Logic.Function.Basic
/-!
diff --git a/Mathlib/Algebra/CharZero/Lemmas.lean b/Mathlib/Algebra/CharZero/Lemmas.lean
index 4a3176488e297..5c3ac417809dd 100644
--- a/Mathlib/Algebra/CharZero/Lemmas.lean
+++ b/Mathlib/Algebra/CharZero/Lemmas.lean
@@ -79,7 +79,7 @@ variable {R : Type*} [NonAssocSemiring R] [NoZeroDivisors R] [CharZero R] {a : R
@[simp]
theorem add_self_eq_zero {a : R} : a + a = 0 ↔ a = 0 := by
- simp only [(two_mul a).symm, mul_eq_zero, two_ne_zero, false_or_iff]
+ simp only [(two_mul a).symm, mul_eq_zero, two_ne_zero, false_or]
end
@@ -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/ApproximationCorollaries.lean b/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean
index 34d81f490bea6..73f695ecae794 100644
--- a/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean
+++ b/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean
@@ -97,9 +97,9 @@ theorem of_convergence_epsilon :
have zero_lt_B : 0 < B := B_ineq.trans_lt' <| mod_cast fib_pos.2 n.succ_pos
have nB_pos : 0 < nB := nB_ineq.trans_lt' <| mod_cast fib_pos.2 <| succ_pos _
have zero_lt_mul_conts : 0 < B * nB := by positivity
- suffices 1 < ε * (B * nB) from (div_lt_iff zero_lt_mul_conts).mpr this
+ suffices 1 < ε * (B * nB) from (div_lt_iff₀ zero_lt_mul_conts).mpr this
-- use that `N' ≥ n` was obtained from the archimedean property to show the following
- calc 1 < ε * (N' : K) := (div_lt_iff' ε_pos).mp one_div_ε_lt_N'
+ calc 1 < ε * (N' : K) := (div_lt_iff₀' ε_pos).mp one_div_ε_lt_N'
_ ≤ ε * (B * nB) := ?_
-- cancel `ε`
gcongr
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 2adf582909701..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
@@ -166,9 +167,6 @@ theorem succ_succ_nth_conv'Aux_eq_succ_nth_conv'Aux_squashSeq :
gp_head.a / (gp_head.b + convs'Aux s.tail (m + 2)) =
convs'Aux (squashSeq s (m + 1)) (m + 2)
by simpa only [convs'Aux, s_head_eq]
- have : convs'Aux s.tail (m + 2) = convs'Aux (squashSeq s.tail m) (m + 1) := by
- refine IH gp_succ_n ?_
- simpa [Stream'.Seq.get?_tail] using s_succ_nth_eq
have : (squashSeq s (m + 1)).head = some gp_head :=
(squashSeq_nth_of_lt m.succ_pos).trans s_head_eq
simp_all [convs'Aux, squashSeq_succ_n_tail_eq_squashSeq_tail_n]
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 f1aa6c7623464..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,18 +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
- -- Porting note: this had been
- -- simp [LinearMap.map_add, hxi, hyj, toModule_totalize_of_le hik hi,
- -- toModule_totalize_of_le hjk hj]
- simp only [map_add]
- rw [toModule_totalize_of_le hik hi, toModule_totalize_of_le hjk hj]
- simp [hxi, hyj]⟩)
- fun a x ⟨i, hi, hxi⟩ =>
+ simp [LinearMap.map_add, hxi, hyj, toModule_totalize_of_le hik hi,
+ toModule_totalize_of_le hjk hj]⟩)
+ 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
@@ -462,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
@@ -668,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⟩}, ?_,
@@ -721,14 +718,11 @@ theorem of.zero_exact_aux [Nonempty ι] [IsDirected ι (· ≤ ·)] {x : FreeCom
dsimp only
rw [(f' i i _).map_mul]
· exact sub_self _
- all_goals tauto
- -- Porting note: was
- --exacts [sub_self _, Or.inl rfl, Or.inr (Or.inr rfl), Or.inr (Or.inl rfl)]
+ 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)
@@ -738,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⟩
@@ -867,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
@@ -944,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]⟩
@@ -969,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 c3b5c570dd966..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)
@@ -100,27 +100,26 @@ lemma trace_comp_eq_zero_of_commute_of_trace_restrict_eq_zero
[IsDomain R] [IsPrincipalIdealRing R] [Module.Free R M] [Module.Finite R M]
{f g : Module.End R M}
(h_comm : Commute f g)
- (hf : ⨆ μ, ⨆ k, f.genEigenspace μ k = ⊤)
- (hg : ∀ μ, trace R _ (g.restrict (f.mapsTo_iSup_genEigenspace_of_comm h_comm μ)) = 0) :
+ (hf : ⨆ μ, f.maxGenEigenspace μ = ⊤)
+ (hg : ∀ μ, trace R _ (g.restrict (f.mapsTo_maxGenEigenspace_of_comm h_comm μ)) = 0) :
trace R _ (g ∘ₗ f) = 0 := by
have hfg : ∀ μ,
- MapsTo (g ∘ₗ f) ↑(⨆ k, f.genEigenspace μ k) ↑(⨆ k, f.genEigenspace μ k) :=
- fun μ ↦ (f.mapsTo_iSup_genEigenspace_of_comm h_comm μ).comp
- (f.mapsTo_iSup_genEigenspace_of_comm rfl μ)
+ MapsTo (g ∘ₗ f) ↑(f.maxGenEigenspace μ) ↑(f.maxGenEigenspace μ) :=
+ fun μ ↦ (f.mapsTo_maxGenEigenspace_of_comm h_comm μ).comp
+ (f.mapsTo_maxGenEigenspace_of_comm rfl μ)
suffices ∀ μ, trace R _ ((g ∘ₗ f).restrict (hfg μ)) = 0 by
classical
have hds := DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top
- f.independent_genEigenspace hf
- have h_fin : {μ | ⨆ k, f.genEigenspace μ k ≠ ⊥}.Finite :=
- CompleteLattice.WellFounded.finite_ne_bot_of_independent IsWellFounded.wf
- f.independent_genEigenspace
+ f.independent_maxGenEigenspace hf
+ have h_fin : {μ | f.maxGenEigenspace μ ≠ ⊥}.Finite :=
+ 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_iSup_genEigenspace_of_comm h_comm μ))
- (f.restrict (f.mapsTo_iSup_genEigenspace_of_comm rfl μ)) :=
+ replace h_comm : Commute (g.restrict (f.mapsTo_maxGenEigenspace_of_comm h_comm μ))
+ (f.restrict (f.mapsTo_maxGenEigenspace_of_comm rfl μ)) :=
restrict_commute h_comm.symm _ _
rw [restrict_comp, trace_comp_eq_mul_of_commute_of_isNilpotent μ h_comm
- (f.isNilpotent_restrict_iSup_sub_algebraMap μ), hg, mul_zero]
+ (f.isNilpotent_restrict_maxGenEigenspace_sub_algebraMap μ), hg, mul_zero]
lemma mapsTo_biSup_of_mapsTo {ι : Type*} {N : ι → Submodule R M}
(s : Set ι) {f : Module.End R M} (hf : ∀ i, MapsTo f (N i) (N i)) :
diff --git a/Mathlib/Algebra/DirectSum/Module.lean b/Mathlib/Algebra/DirectSum/Module.lean
index bda16093f4ab9..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
@@ -279,7 +279,7 @@ theorem coeLinearMap_eq_dfinsupp_sum [DecidableEq M] (x : DirectSum ι fun i =>
simp only [coeLinearMap, toModule, DFinsupp.lsum, LinearEquiv.coe_mk, LinearMap.coe_mk,
AddHom.coe_mk]
rw [DFinsupp.sumAddHom_apply]
- simp only [LinearMap.toAddMonoidHom_coe, Submodule.coeSubtype]
+ simp only [LinearMap.toAddMonoidHom_coe, Submodule.coe_subtype]
@[simp]
theorem coeLinearMap_of (i : ι) (x : A i) : DirectSum.coeLinearMap A (of (fun i ↦ A i) i x) = x :=
@@ -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) :
@@ -349,7 +352,7 @@ theorem IsInternal.collectedBasis_coe (h : IsInternal A) {α : ι → Type*}
simp only [DFinsupp.mapRange_single, Basis.repr_symm_apply, linearCombination_single, one_smul,
toModule]
erw [DFinsupp.lsum_single]
- simp only [Submodule.coeSubtype]
+ simp only [Submodule.coe_subtype]
theorem IsInternal.collectedBasis_mem (h : IsInternal A) {α : ι → Type*}
(v : ∀ i, Basis (α i) R (A i)) (a : Σi, α i) : h.collectedBasis v a ∈ A a.1 := by simp
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 8a023b47a692f..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
@@ -323,19 +323,17 @@ theorem Exact.split_tfae' (h : Function.Exact f g) :
Function.Surjective g ∧ ∃ l, l ∘ₗ f = LinearMap.id,
∃ e : N ≃ₗ[R] M × P, f = e.symm ∘ₗ LinearMap.inl R M P ∧ g = LinearMap.snd R M P ∘ₗ e] := by
tfae_have 1 → 3
- · rintro ⟨hf, l, hl⟩
- exact ⟨_, (h.splitSurjectiveEquiv hf ⟨l, hl⟩).2⟩
+ | ⟨hf, l, hl⟩ => ⟨_, (h.splitSurjectiveEquiv hf ⟨l, hl⟩).2⟩
tfae_have 2 → 3
- · rintro ⟨hg, l, hl⟩
- exact ⟨_, (h.splitInjectiveEquiv hg ⟨l, hl⟩).2⟩
+ | ⟨hg, l, hl⟩ => ⟨_, (h.splitInjectiveEquiv hg ⟨l, hl⟩).2⟩
tfae_have 3 → 1
- · rintro ⟨e, e₁, e₂⟩
+ | ⟨e, e₁, e₂⟩ => by
have : Function.Injective f := e₁ ▸ e.symm.injective.comp LinearMap.inl_injective
- refine ⟨this, ⟨_, ((h.splitSurjectiveEquiv this).symm ⟨e, e₁, e₂⟩).2⟩⟩
+ exact ⟨this, ⟨_, ((h.splitSurjectiveEquiv this).symm ⟨e, e₁, e₂⟩).2⟩⟩
tfae_have 3 → 2
- · rintro ⟨e, e₁, e₂⟩
+ | ⟨e, e₁, e₂⟩ => by
have : Function.Surjective g := e₂ ▸ Prod.snd_surjective.comp e.surjective
- refine ⟨this, ⟨_, ((h.splitInjectiveEquiv this).symm ⟨e, e₁, e₂⟩).2⟩⟩
+ exact ⟨this, ⟨_, ((h.splitInjectiveEquiv this).symm ⟨e, e₁, e₂⟩).2⟩⟩
tfae_finish
/-- Equivalent characterizations of split exact sequences. Also known as the **Splitting lemma**. -/
@@ -347,10 +345,10 @@ theorem Exact.split_tfae
∃ l, g ∘ₗ l = LinearMap.id,
∃ l, l ∘ₗ f = LinearMap.id,
∃ e : N ≃ₗ[R] M × P, f = e.symm ∘ₗ LinearMap.inl R M P ∧ g = LinearMap.snd R M P ∘ₗ e] := by
- tfae_have 1 ↔ 3
- · simpa using (h.splitSurjectiveEquiv hf).nonempty_congr
- tfae_have 2 ↔ 3
- · simpa using (h.splitInjectiveEquiv hg).nonempty_congr
+ tfae_have 1 ↔ 3 := by
+ simpa using (h.splitSurjectiveEquiv hf).nonempty_congr
+ tfae_have 2 ↔ 3 := by
+ simpa using (h.splitInjectiveEquiv hg).nonempty_congr
tfae_finish
end split
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 fa1a788fb74a7..989ee8b232df3 100644
--- a/Mathlib/Algebra/Field/Basic.lean
+++ b/Mathlib/Algebra/Field/Basic.lean
@@ -18,16 +18,16 @@ open Function OrderDual Set
universe u
-variable {α β K : Type*}
+variable {K L : Type*}
section DivisionSemiring
-variable [DivisionSemiring α] {a b c d : α}
+variable [DivisionSemiring K] {a b c d : K}
-theorem add_div (a b c : α) : (a + b) / c = a / c + b / c := by simp_rw [div_eq_mul_inv, add_mul]
+theorem add_div (a b c : K) : (a + b) / c = a / c + b / c := by simp_rw [div_eq_mul_inv, add_mul]
@[field_simps]
-theorem div_add_div_same (a b c : α) : a / c + b / c = (a + b) / c :=
+theorem div_add_div_same (a b c : K) : a / c + b / c = (a + b) / c :=
(add_div _ _ _).symm
theorem same_add_div (h : b ≠ 0) : (b + a) / b = 1 + a / b := by rw [← div_self h, add_div]
@@ -49,15 +49,15 @@ theorem one_div_mul_add_mul_one_div_eq_one_div_add_one_div (ha : a ≠ 0) (hb :
1 / a * (a + b) * (1 / b) = 1 / a + 1 / b := by
simpa only [one_div] using (inv_add_inv' ha hb).symm
-theorem add_div_eq_mul_add_div (a b : α) (hc : c ≠ 0) : a + b / c = (a * c + b) / c :=
+theorem add_div_eq_mul_add_div (a b : K) (hc : c ≠ 0) : a + b / c = (a * c + b) / c :=
(eq_div_iff_mul_eq hc).2 <| by rw [right_distrib, div_mul_cancel₀ _ hc]
@[field_simps]
-theorem add_div' (a b c : α) (hc : c ≠ 0) : b + a / c = (b * c + a) / c := by
+theorem add_div' (a b c : K) (hc : c ≠ 0) : b + a / c = (b * c + a) / c := by
rw [add_div, mul_div_cancel_right₀ _ hc]
@[field_simps]
-theorem div_add' (a b c : α) (hc : c ≠ 0) : a / c + b = (a + b * c) / c := by
+theorem div_add' (a b c : K) (hc : c ≠ 0) : a / c + b = (a + b * c) / c := by
rwa [add_comm, add_div', add_comm]
protected theorem Commute.div_add_div (hbc : Commute b c) (hbd : Commute b d) (hb : b ≠ 0)
@@ -167,9 +167,9 @@ end DivisionRing
section Semifield
-variable [Semifield α] {a b c d : α}
+variable [Semifield K] {a b d : K}
-theorem div_add_div (a : α) (c : α) (hb : b ≠ 0) (hd : d ≠ 0) :
+theorem div_add_div (a : K) (c : K) (hb : b ≠ 0) (hd : d ≠ 0) :
a / b + c / d = (a * d + b * c) / (b * d) :=
(Commute.all b _).div_add_div (Commute.all _ _) hb hd
@@ -211,7 +211,7 @@ end Field
namespace RingHom
-protected theorem injective [DivisionRing α] [Semiring β] [Nontrivial β] (f : α →+* β) :
+protected theorem injective [DivisionRing K] [Semiring L] [Nontrivial L] (f : K →+* L) :
Injective f :=
(injective_iff_map_eq_zero f).2 fun _ ↦ (map_eq_zero f).1
@@ -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]
@@ -242,18 +242,18 @@ noncomputable abbrev Field.ofIsUnitOrEqZero [CommRing R] (h : ∀ a : R, IsUnit
end NoncomputableDefs
namespace Function.Injective
-variable [Zero α] [Add α] [Neg α] [Sub α] [One α] [Mul α] [Inv α] [Div α] [SMul ℕ α] [SMul ℤ α]
- [SMul ℚ≥0 α] [SMul ℚ α] [Pow α ℕ] [Pow α ℤ] [NatCast α] [IntCast α] [NNRatCast α] [RatCast α]
- (f : α → β) (hf : Injective f)
+variable [Zero K] [Add K] [Neg K] [Sub K] [One K] [Mul K] [Inv K] [Div K] [SMul ℕ K] [SMul ℤ K]
+ [SMul ℚ≥0 K] [SMul ℚ K] [Pow K ℕ] [Pow K ℤ] [NatCast K] [IntCast K] [NNRatCast K] [RatCast K]
+ (f : K → L) (hf : Injective f)
/-- Pullback a `DivisionSemiring` along an injective function. -/
-- See note [reducible non-instances]
-protected abbrev divisionSemiring [DivisionSemiring β] (zero : f 0 = 0) (one : f 1 = 1)
+protected abbrev divisionSemiring [DivisionSemiring L] (zero : f 0 = 0) (one : f 1 = 1)
(add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y)
(inv : ∀ x, f x⁻¹ = (f x)⁻¹) (div : ∀ x y, f (x / y) = f x / f y)
(nsmul : ∀ (n : ℕ) (x), f (n • x) = n • f x) (nnqsmul : ∀ (q : ℚ≥0) (x), f (q • x) = q • f x)
(npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n)
- (natCast : ∀ n : ℕ, f n = n) (nnratCast : ∀ q : ℚ≥0, f q = q) : DivisionSemiring α where
+ (natCast : ∀ n : ℕ, f n = n) (nnratCast : ∀ q : ℚ≥0, f q = q) : DivisionSemiring K where
toSemiring := hf.semiring f zero one add mul nsmul npow natCast
__ := hf.groupWithZero f zero one mul inv div npow zpow
nnratCast_def q := hf <| by rw [nnratCast, NNRat.cast_def, div, natCast, natCast]
@@ -262,7 +262,7 @@ protected abbrev divisionSemiring [DivisionSemiring β] (zero : f 0 = 0) (one :
/-- Pullback a `DivisionSemiring` along an injective function. -/
-- See note [reducible non-instances]
-protected abbrev divisionRing [DivisionRing β] (zero : f 0 = 0) (one : f 1 = 1)
+protected abbrev divisionRing [DivisionRing L] (zero : f 0 = 0) (one : f 1 = 1)
(add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y)
(neg : ∀ x, f (-x) = -f x) (sub : ∀ x y, f (x - y) = f x - f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹)
(div : ∀ x y, f (x / y) = f x / f y)
@@ -270,29 +270,29 @@ protected abbrev divisionRing [DivisionRing β] (zero : f 0 = 0) (one : f 1 = 1)
(nnqsmul : ∀ (q : ℚ≥0) (x), f (q • x) = q • f x) (qsmul : ∀ (q : ℚ) (x), f (q • x) = q • f x)
(npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n)
(natCast : ∀ n : ℕ, f n = n) (intCast : ∀ n : ℤ, f n = n) (nnratCast : ∀ q : ℚ≥0, f q = q)
- (ratCast : ∀ q : ℚ, f q = q) : DivisionRing α where
+ (ratCast : ∀ q : ℚ, f q = q) : DivisionRing K where
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]
-protected abbrev semifield [Semifield β] (zero : f 0 = 0) (one : f 1 = 1)
+protected abbrev semifield [Semifield L] (zero : f 0 = 0) (one : f 1 = 1)
(add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y)
(inv : ∀ x, f x⁻¹ = (f x)⁻¹) (div : ∀ x y, f (x / y) = f x / f y)
(nsmul : ∀ (n : ℕ) (x), f (n • x) = n • f x) (nnqsmul : ∀ (q : ℚ≥0) (x), f (q • x) = q • f x)
(npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n)
- (natCast : ∀ n : ℕ, f n = n) (nnratCast : ∀ q : ℚ≥0, f q = q) : Semifield α where
+ (natCast : ∀ n : ℕ, f n = n) (nnratCast : ∀ q : ℚ≥0, f q = q) : Semifield K where
toCommSemiring := hf.commSemiring f zero one add mul nsmul npow natCast
__ := hf.commGroupWithZero f zero one mul inv div npow zpow
__ := hf.divisionSemiring f zero one add mul inv div nsmul nnqsmul npow zpow natCast nnratCast
/-- Pullback a `Field` along an injective function. -/
-- See note [reducible non-instances]
-protected abbrev field [Field β] (zero : f 0 = 0) (one : f 1 = 1)
+protected abbrev field [Field L] (zero : f 0 = 0) (one : f 1 = 1)
(add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y)
(neg : ∀ x, f (-x) = -f x) (sub : ∀ x y, f (x - y) = f x - f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹)
(div : ∀ x y, f (x / y) = f x / f y)
@@ -301,7 +301,7 @@ protected abbrev field [Field β] (zero : f 0 = 0) (one : f 1 = 1)
(npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n)
(natCast : ∀ n : ℕ, f n = n) (intCast : ∀ n : ℤ, f n = n) (nnratCast : ∀ q : ℚ≥0, f q = q)
(ratCast : ∀ q : ℚ, f q = q) :
- Field α where
+ Field K where
toCommRing := hf.commRing f zero one add mul neg sub nsmul zsmul npow natCast intCast
__ := hf.divisionRing f zero one add mul neg sub inv div nsmul zsmul nnqsmul qsmul npow zpow
natCast intCast nnratCast ratCast
@@ -312,30 +312,30 @@ end Function.Injective
namespace OrderDual
-instance instRatCast [RatCast α] : RatCast αᵒᵈ := ‹_›
-instance instDivisionSemiring [DivisionSemiring α] : DivisionSemiring αᵒᵈ := ‹_›
-instance instDivisionRing [DivisionRing α] : DivisionRing αᵒᵈ := ‹_›
-instance instSemifield [Semifield α] : Semifield αᵒᵈ := ‹_›
-instance instField [Field α] : Field αᵒᵈ := ‹_›
+instance instRatCast [RatCast K] : RatCast Kᵒᵈ := ‹_›
+instance instDivisionSemiring [DivisionSemiring K] : DivisionSemiring Kᵒᵈ := ‹_›
+instance instDivisionRing [DivisionRing K] : DivisionRing Kᵒᵈ := ‹_›
+instance instSemifield [Semifield K] : Semifield Kᵒᵈ := ‹_›
+instance instField [Field K] : Field Kᵒᵈ := ‹_›
end OrderDual
-@[simp] lemma toDual_ratCast [RatCast α] (n : ℚ) : toDual (n : α) = n := rfl
+@[simp] lemma toDual_ratCast [RatCast K] (n : ℚ) : toDual (n : K) = n := rfl
-@[simp] lemma ofDual_ratCast [RatCast α] (n : ℚ) : (ofDual n : α) = n := rfl
+@[simp] lemma ofDual_ratCast [RatCast K] (n : ℚ) : (ofDual n : K) = n := rfl
/-! ### Lexicographic order -/
namespace Lex
-instance instRatCast [RatCast α] : RatCast (Lex α) := ‹_›
-instance instDivisionSemiring [DivisionSemiring α] : DivisionSemiring (Lex α) := ‹_›
-instance instDivisionRing [DivisionRing α] : DivisionRing (Lex α) := ‹_›
-instance instSemifield [Semifield α] : Semifield (Lex α) := ‹_›
-instance instField [Field α] : Field (Lex α) := ‹_›
+instance instRatCast [RatCast K] : RatCast (Lex K) := ‹_›
+instance instDivisionSemiring [DivisionSemiring K] : DivisionSemiring (Lex K) := ‹_›
+instance instDivisionRing [DivisionRing K] : DivisionRing (Lex K) := ‹_›
+instance instSemifield [Semifield K] : Semifield (Lex K) := ‹_›
+instance instField [Field K] : Field (Lex K) := ‹_›
end Lex
-@[simp] lemma toLex_ratCast [RatCast α] (n : ℚ) : toLex (n : α) = n := rfl
+@[simp] lemma toLex_ratCast [RatCast K] (n : ℚ) : toLex (n : K) = n := rfl
-@[simp] lemma ofLex_ratCast [RatCast α] (n : ℚ) : (ofLex n : α) = n := rfl
+@[simp] lemma ofLex_ratCast [RatCast K] (n : ℚ) : (ofLex n : K) = n := rfl
diff --git a/Mathlib/Algebra/Field/Defs.lean b/Mathlib/Algebra/Field/Defs.lean
index 4943b798adf4c..4bb07df74d908 100644
--- a/Mathlib/Algebra/Field/Defs.lean
+++ b/Mathlib/Algebra/Field/Defs.lean
@@ -45,8 +45,8 @@ field, division ring, skew field, skew-field, skewfield
assert_not_imported Mathlib.Tactic.Common
--- `NeZero` should not be needed in the basic algebraic hierarchy.
-assert_not_exists NeZero
+-- `NeZero` theory should not be needed in the basic algebraic hierarchy
+assert_not_imported Mathlib.Algebra.NeZero
assert_not_exists MonoidHom
@@ -54,7 +54,7 @@ open Function Set
universe u
-variable {α β K : Type*}
+variable {K : Type*}
/-- The default definition of the coercion `ℚ≥0 → K` for a division semiring `K`.
@@ -81,23 +81,23 @@ itself). See also note [forgetful inheritance].
If the division semiring has positive characteristic `p`, our division by zero convention forces
`nnratCast (1 / p) = 1 / 0 = 0`. -/
-class DivisionSemiring (α : Type*) extends Semiring α, GroupWithZero α, NNRatCast α where
+class DivisionSemiring (K : Type*) extends Semiring K, GroupWithZero K, NNRatCast K where
protected nnratCast := NNRat.castRec
/-- However `NNRat.cast` is defined, it must be propositionally equal to `a / b`.
Do not use this lemma directly. Use `NNRat.cast_def` instead. -/
- protected nnratCast_def (q : ℚ≥0) : (NNRat.cast q : α) = q.num / q.den := by intros; rfl
+ protected nnratCast_def (q : ℚ≥0) : (NNRat.cast q : K) = q.num / q.den := by intros; rfl
/-- Scalar multiplication by a nonnegative rational number.
Unless there is a risk of a `Module ℚ≥0 _` instance diamond, write `nnqsmul := _`. This will set
`nnqsmul` to `(NNRat.cast · * ·)` thanks to unification in the default proof of `nnqsmul_def`.
Do not use directly. Instead use the `•` notation. -/
- protected nnqsmul : ℚ≥0 → α → α
+ protected nnqsmul : ℚ≥0 → K → K
/-- However `qsmul` is defined, it must be propositionally equal to multiplication by `Rat.cast`.
Do not use this lemma directly. Use `NNRat.smul_def` instead. -/
- protected nnqsmul_def (q : ℚ≥0) (a : α) : nnqsmul q a = NNRat.cast q * a := by intros; rfl
+ protected nnqsmul_def (q : ℚ≥0) (a : K) : nnqsmul q a = NNRat.cast q * a := by intros; rfl
/-- A `DivisionRing` is a `Ring` with multiplicative inverses for nonzero elements.
@@ -109,48 +109,48 @@ See also note [forgetful inheritance]. Similarly, there are maps `nnratCast ℚ
If the division ring has positive characteristic `p`, our division by zero convention forces
`ratCast (1 / p) = 1 / 0 = 0`. -/
-class DivisionRing (α : Type*)
- extends Ring α, DivInvMonoid α, Nontrivial α, NNRatCast α, RatCast α where
+class DivisionRing (K : Type*)
+ extends Ring K, DivInvMonoid K, Nontrivial K, NNRatCast K, RatCast K where
/-- For a nonzero `a`, `a⁻¹` is a right multiplicative inverse. -/
- protected mul_inv_cancel : ∀ (a : α), a ≠ 0 → a * a⁻¹ = 1
+ protected mul_inv_cancel : ∀ (a : K), a ≠ 0 → a * a⁻¹ = 1
/-- The inverse of `0` is `0` by convention. -/
- protected inv_zero : (0 : α)⁻¹ = 0
+ protected inv_zero : (0 : K)⁻¹ = 0
protected nnratCast := NNRat.castRec
/-- However `NNRat.cast` is defined, it must be equal to `a / b`.
Do not use this lemma directly. Use `NNRat.cast_def` instead. -/
- protected nnratCast_def (q : ℚ≥0) : (NNRat.cast q : α) = q.num / q.den := by intros; rfl
+ protected nnratCast_def (q : ℚ≥0) : (NNRat.cast q : K) = q.num / q.den := by intros; rfl
/-- Scalar multiplication by a nonnegative rational number.
Unless there is a risk of a `Module ℚ≥0 _` instance diamond, write `nnqsmul := _`. This will set
`nnqsmul` to `(NNRat.cast · * ·)` thanks to unification in the default proof of `nnqsmul_def`.
Do not use directly. Instead use the `•` notation. -/
- protected nnqsmul : ℚ≥0 → α → α
+ protected nnqsmul : ℚ≥0 → K → K
/-- However `qsmul` is defined, it must be propositionally equal to multiplication by `Rat.cast`.
Do not use this lemma directly. Use `NNRat.smul_def` instead. -/
- protected nnqsmul_def (q : ℚ≥0) (a : α) : nnqsmul q a = NNRat.cast q * a := by intros; rfl
+ protected nnqsmul_def (q : ℚ≥0) (a : K) : nnqsmul q a = NNRat.cast q * a := by intros; rfl
protected ratCast := Rat.castRec
/-- However `Rat.cast q` is defined, it must be propositionally equal to `q.num / q.den`.
Do not use this lemma directly. Use `Rat.cast_def` instead. -/
- protected ratCast_def (q : ℚ) : (Rat.cast q : α) = q.num / q.den := by intros; rfl
+ protected ratCast_def (q : ℚ) : (Rat.cast q : K) = q.num / q.den := by intros; rfl
/-- Scalar multiplication by a rational number.
Unless there is a risk of a `Module ℚ _` instance diamond, write `qsmul := _`. This will set
`qsmul` to `(Rat.cast · * ·)` thanks to unification in the default proof of `qsmul_def`.
Do not use directly. Instead use the `•` notation. -/
- protected qsmul : ℚ → α → α
+ protected qsmul : ℚ → K → K
/-- However `qsmul` is defined, it must be propositionally equal to multiplication by `Rat.cast`.
Do not use this lemma directly. Use `Rat.cast_def` instead. -/
- protected qsmul_def (a : ℚ) (x : α) : qsmul a x = Rat.cast a * x := by intros; rfl
+ protected qsmul_def (a : ℚ) (x : K) : qsmul a x = Rat.cast a * x := by intros; rfl
-- see Note [lower instance priority]
-instance (priority := 100) DivisionRing.toDivisionSemiring [DivisionRing α] : DivisionSemiring α :=
- { ‹DivisionRing α› with }
+instance (priority := 100) DivisionRing.toDivisionSemiring [DivisionRing K] : DivisionSemiring K :=
+ { ‹DivisionRing K› with }
/-- A `Semifield` is a `CommSemiring` with multiplicative inverses for nonzero elements.
@@ -161,7 +161,7 @@ itself). See also note [forgetful inheritance].
If the semifield has positive characteristic `p`, our division by zero convention forces
`nnratCast (1 / p) = 1 / 0 = 0`. -/
-class Semifield (α : Type*) extends CommSemiring α, DivisionSemiring α, CommGroupWithZero α
+class Semifield (K : Type*) extends CommSemiring K, DivisionSemiring K, CommGroupWithZero K
/-- A `Field` is a `CommRing` with multiplicative inverses for nonzero elements.
@@ -175,26 +175,26 @@ If the field has positive characteristic `p`, our division by zero convention fo
class Field (K : Type u) extends CommRing K, DivisionRing K
-- see Note [lower instance priority]
-instance (priority := 100) Field.toSemifield [Field α] : Semifield α := { ‹Field α› with }
+instance (priority := 100) Field.toSemifield [Field K] : Semifield K := { ‹Field K› with }
namespace NNRat
-variable [DivisionSemiring α]
+variable [DivisionSemiring K]
-instance (priority := 100) smulDivisionSemiring : SMul ℚ≥0 α := ⟨DivisionSemiring.nnqsmul⟩
+instance (priority := 100) smulDivisionSemiring : SMul ℚ≥0 K := ⟨DivisionSemiring.nnqsmul⟩
-lemma cast_def (q : ℚ≥0) : (q : α) = q.num / q.den := DivisionSemiring.nnratCast_def _
-lemma smul_def (q : ℚ≥0) (a : α) : q • a = q * a := DivisionSemiring.nnqsmul_def q a
+lemma cast_def (q : ℚ≥0) : (q : K) = q.num / q.den := DivisionSemiring.nnratCast_def _
+lemma smul_def (q : ℚ≥0) (a : K) : q • a = q * a := DivisionSemiring.nnqsmul_def q a
-variable (α)
+variable (K)
-@[simp] lemma smul_one_eq_cast (q : ℚ≥0) : q • (1 : α) = q := by rw [NNRat.smul_def, mul_one]
+@[simp] lemma smul_one_eq_cast (q : ℚ≥0) : q • (1 : K) = q := by rw [NNRat.smul_def, mul_one]
@[deprecated (since := "2024-05-03")] alias smul_one_eq_coe := smul_one_eq_cast
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 8d57654e441ac..c1d8534cddfbe 100644
--- a/Mathlib/Algebra/Field/Subfield.lean
+++ b/Mathlib/Algebra/Field/Subfield.lean
@@ -126,20 +126,20 @@ variable (S)
/-- A subfield inherits a division ring structure -/
instance (priority := 75) toDivisionRing (s : S) : DivisionRing s :=
Subtype.coe_injective.divisionRing ((↑) : s → K)
- (by rfl) (by rfl) (by intros; rfl) (by intros; rfl) (by intros; rfl)
- (by intros; rfl) (by intros; rfl) (by intros; rfl) (by intros; rfl)
- (by intros; rfl) (coe_nnqsmul _) (coe_qsmul _) (by intros; rfl) (by intros; rfl)
- (by intros; rfl) (by intros; rfl) (by intros; rfl) (by intros; rfl)
+ rfl rfl (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ ↦ rfl)
+ (fun _ _ ↦ rfl) (fun _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl)
+ (fun _ _ ↦ rfl) (coe_nnqsmul _) (coe_qsmul _) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl)
+ (fun _ ↦ rfl) (fun _ ↦ rfl) (fun _ ↦ rfl) (fun _ ↦ rfl)
-- Prefer subclasses of `Field` over subclasses of `SubfieldClass`.
/-- A subfield of a field inherits a field structure -/
instance (priority := 75) toField {K} [Field K] [SetLike S K] [SubfieldClass S K] (s : S) :
Field s :=
Subtype.coe_injective.field ((↑) : s → K)
- (by rfl) (by rfl) (by intros; rfl) (by intros; rfl) (by intros; rfl)
- (by intros; rfl) (by intros; rfl) (by intros; rfl) (by intros; rfl) (by intros; rfl)
- (coe_nnqsmul _) (coe_qsmul _) (by intros; rfl) (by intros; rfl) (by intros; rfl)
- (by intros; rfl) (by intros; rfl) (by intros; rfl)
+ rfl rfl (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ ↦ rfl)
+ (fun _ _ ↦ rfl) (fun _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl)
+ (coe_nnqsmul _) (coe_qsmul _) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ ↦ rfl)
+ (fun _ ↦ rfl) (fun _ ↦ rfl) (fun _ ↦ rfl)
end SubfieldClass
@@ -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
@@ -313,15 +312,15 @@ instance : Pow s ℤ :=
instance toDivisionRing (s : Subfield K) : DivisionRing s :=
Subtype.coe_injective.divisionRing ((↑) : s → K) rfl rfl (fun _ _ ↦ rfl) (fun _ _ ↦ rfl)
(fun _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl)
- (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (by intros; rfl) (fun _ ↦ rfl) (fun _ ↦ rfl)
- (by intros; rfl) fun _ ↦ rfl
+ (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ ↦ rfl) (fun _ ↦ rfl)
+ (fun _ ↦ rfl) fun _ ↦ rfl
/-- A subfield inherits a field structure -/
instance toField {K} [Field K] (s : Subfield K) : Field s :=
Subtype.coe_injective.field ((↑) : s → K) rfl rfl (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl)
(fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl)
- (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (by intros; rfl) (fun _ => rfl)
- (fun _ => rfl) (by intros; rfl) fun _ => rfl
+ (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ ↦ rfl) (fun _ => rfl)
+ (fun _ => rfl) (fun _ ↦ rfl) fun _ => rfl
@[simp, norm_cast]
theorem coe_add (x y : s) : (↑(x + y) : K) = ↑x + ↑y :=
@@ -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
@@ -545,6 +543,13 @@ theorem mem_sInf {S : Set (Subfield K)} {x : K} : x ∈ sInf S ↔ ∀ p ∈ S,
Subring.mem_sInf.trans
⟨fun h p hp => h p.toSubring ⟨p, hp, rfl⟩, fun h _ ⟨p', hp', p_eq⟩ => p_eq ▸ h p' hp'⟩
+@[simp, norm_cast]
+theorem coe_iInf {ι : Sort*} {S : ι → Subfield K} : (↑(⨅ i, S i) : Set K) = ⋂ i, S i := by
+ simp only [iInf, coe_sInf, Set.biInter_range]
+
+theorem mem_iInf {ι : Sort*} {S : ι → Subfield K} {x : K} : (x ∈ ⨅ i, S i) ↔ ∀ i, x ∈ S i := by
+ simp only [iInf, mem_sInf, Set.forall_mem_range]
+
@[simp]
theorem sInf_toSubring (s : Set (Subfield K)) :
(sInf s).toSubring = ⨅ t ∈ s, Subfield.toSubring t := by
@@ -659,6 +664,14 @@ theorem map_iSup {ι : Sort*} (f : K →+* L) (s : ι → Subfield K) :
(iSup s).map f = ⨆ i, (s i).map f :=
(gc_map_comap f).l_iSup
+theorem map_inf (s t : Subfield K) (f : K →+* L) : (s ⊓ t).map f = s.map f ⊓ t.map f :=
+ SetLike.coe_injective (Set.image_inter f.injective)
+
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : K →+* L) (s : ι → Subfield K) :
+ (iInf s).map f = ⨅ i, (s i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective f.injective).image_iInter_eq (s := SetLike.coe ∘ s)
+
theorem comap_inf (s t : Subfield L) (f : K →+* L) : (s ⊓ t).comap f = s.comap f ⊓ t.comap f :=
(gc_map_comap f).u_inf
@@ -858,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 1b0f927525cca..78cdb51b06d87 100644
--- a/Mathlib/Algebra/Free.lean
+++ b/Mathlib/Algebra/Free.lean
@@ -6,7 +6,6 @@ Authors: Kenny Lau
import Mathlib.Algebra.Group.Equiv.Basic
import Mathlib.Control.Applicative
import Mathlib.Control.Traversable.Basic
-import Mathlib.Data.List.Basic
import Mathlib.Logic.Equiv.Defs
import Mathlib.Tactic.AdaptationNote
@@ -106,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)]
@@ -174,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])
@@ -240,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
@@ -261,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. -/
@@ -374,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
@@ -484,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
@@ -515,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
@@ -559,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. -/
@@ -588,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)
@@ -615,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])
@@ -662,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/FreeAlgebra.lean b/Mathlib/Algebra/FreeAlgebra.lean
index 09f5906b663fa..e844d11c4c136 100644
--- a/Mathlib/Algebra/FreeAlgebra.lean
+++ b/Mathlib/Algebra/FreeAlgebra.lean
@@ -1,12 +1,13 @@
/-
Copyright (c) 2020 Adam Topaz. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Adam Topaz, Eric Wieser
+Authors: Kim Morrison, Adam Topaz, Eric Wieser
-/
import Mathlib.Algebra.Algebra.Subalgebra.Basic
import Mathlib.Algebra.Algebra.Tower
import Mathlib.Algebra.MonoidAlgebra.NoZeroDivisors
import Mathlib.RingTheory.Adjoin.Basic
+import Mathlib.Algebra.MonoidAlgebra.Basic
/-!
# Free Algebras
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 e7ff47b1fe976..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
@@ -589,8 +582,8 @@ theorem exists_associated_pow_of_mul_eq_pow [GCDMonoid α] {a b c : α} (hab : I
use Units.mkOfMulEqOne _ _ h'
rw [Units.val_mkOfMulEqOne, ha']
-theorem exists_eq_pow_of_mul_eq_pow [GCDMonoid α] [Unique αˣ] {a b c : α} (hab : IsUnit (gcd a b))
- {k : ℕ} (h : a * b = c ^ k) : ∃ d : α, a = d ^ k :=
+theorem exists_eq_pow_of_mul_eq_pow [GCDMonoid α] [Subsingleton αˣ]
+ {a b c : α} (hab : IsUnit (gcd a b)) {k : ℕ} (h : a * b = c ^ k) : ∃ d : α, a = d ^ k :=
let ⟨d, hd⟩ := exists_associated_pow_of_mul_eq_pow hab h
⟨d, (associated_iff_eq.mp hd).symm⟩
@@ -666,7 +659,7 @@ theorem lcm_dvd_iff [GCDMonoid α] {a b c : α} : lcm a b ∣ c ↔ a ∣ c ∧
by_cases h : a = 0 ∨ b = 0
· rcases h with (rfl | rfl) <;>
simp (config := { contextual := true }) only [iff_def, lcm_zero_left, lcm_zero_right,
- zero_dvd_iff, dvd_zero, eq_self_iff_true, and_true_iff, imp_true_iff]
+ zero_dvd_iff, dvd_zero, eq_self_iff_true, and_true, imp_true_iff]
· obtain ⟨h1, h2⟩ := not_or.1 h
have h : gcd a b ≠ 0 := fun H => h1 ((gcd_eq_zero_iff _ _).1 H).1
rw [← mul_dvd_mul_iff_left h, (gcd_mul_lcm a b).dvd_iff_dvd_left, ←
@@ -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
@@ -769,7 +761,7 @@ theorem lcm_mul_left [NormalizedGCDMonoid α] (a b c : α) :
fun ha : a ≠ 0 =>
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 ▸
@@ -820,7 +812,7 @@ end GCDMonoid
section UniqueUnit
-variable [CancelCommMonoidWithZero α] [Unique αˣ]
+variable [CancelCommMonoidWithZero α] [Subsingleton αˣ]
-- see Note [lower instance priority]
instance (priority := 100) normalizationMonoidOfUniqueUnits : NormalizationMonoid α where
@@ -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)⁻¹
@@ -1306,10 +1295,10 @@ instance (priority := 100) : NormalizedGCDMonoid G₀ where
exact Associated.refl _
-- Porting note(#12129): additional beta reduction needed
· beta_reduce
- rw [if_neg (not_and_of_not_left _ ha), one_mul, if_neg (not_or_of_not ha hb)]
+ 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 62bd098ce1152..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
@@ -482,7 +477,7 @@ theorem geom_sum_pos' [LinearOrderedRing α] (hx : 0 < x + 1) (hn : n ≠ 0) :
theorem Odd.geom_sum_pos [LinearOrderedRing α] (h : Odd n) : 0 < ∑ i ∈ range n, x ^ i := by
rcases n with (_ | _ | k)
- · exact ((show ¬Odd 0 by decide) h).elim
+ · exact (Nat.not_odd_zero h).elim
· simp only [zero_add, range_one, sum_singleton, pow_zero, zero_lt_one]
rw [← Nat.not_even_iff_odd] at h
rcases lt_trichotomy (x + 1) 0 with (hx | hx | hx)
@@ -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 0179a285f612a..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
@@ -302,7 +301,7 @@ variable {A}
@[simp]
theorem mk_zero_smul {i} (a : A 0) (b : A i) : mk _ (a • b) = mk _ a * mk _ b :=
- Sigma.ext (zero_add _).symm <| eq_rec_heq _ _
+ Sigma.ext (zero_add _).symm <| eqRec_heq _ _
@[scoped simp]
theorem GradeZero.smul_eq_mul (a b : A 0) : a • b = a * b :=
@@ -321,7 +320,7 @@ variable {A}
@[simp]
theorem mk_zero_pow (a : A 0) (n : ℕ) : mk _ (a ^ n) = mk _ a ^ n :=
- Sigma.ext (nsmul_zero n).symm <| eq_rec_heq _ _
+ Sigma.ext (nsmul_zero n).symm <| eqRec_heq _ _
variable (A)
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 8092a68ff91c7..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 {R 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 e753d630bb914..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
/-!
@@ -184,6 +184,6 @@ def MulAction.prodEquiv :
congr 1
· funext; congr; ext m a; (conv_rhs => rw [← hN.one_smul a]); rfl
· ext n a; (conv_rhs => rw [← hM.one_smul (SMul.smul n a)]); rfl
- · apply heq_prop
+ · exact proof_irrel_heq ..
end Action_by_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 66268350d8718..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
@@ -195,6 +195,16 @@ instance instZero : Zero (AddChar A M) := ⟨1⟩
lemma one_eq_zero : (1 : AddChar A M) = (0 : AddChar A M) := rfl
+@[simp, norm_cast] lemma coe_eq_one : ⇑ψ = 1 ↔ ψ = 0 := by rw [← coe_zero, DFunLike.coe_fn_eq]
+
+@[simp] lemma toMonoidHomEquiv_zero : toMonoidHomEquiv (0 : AddChar A M) = 1 := rfl
+@[simp] lemma toMonoidHomEquiv_symm_one :
+ toMonoidHomEquiv.symm (1 : Multiplicative A →* M) = 0 := rfl
+
+@[simp] lemma toAddMonoidHomEquiv_zero : toAddMonoidHomEquiv (0 : AddChar A M) = 0 := rfl
+@[simp] lemma toAddMonoidHomEquiv_symm_zero :
+ toAddMonoidHomEquiv.symm (0 : A →+ Additive M) = 0 := rfl
+
instance instInhabited : Inhabited (AddChar A M) := ⟨1⟩
/-- Composing a `MonoidHom` with an `AddChar` yields another `AddChar`. -/
@@ -252,6 +262,8 @@ set_option linter.deprecated false in
lemma isNontrivial_iff_ne_trivial (ψ : AddChar A M) : IsNontrivial ψ ↔ ψ ≠ 1 :=
not_forall.symm.trans (DFunLike.ext_iff (f := ψ) (g := 1)).symm.not
+noncomputable instance : DecidableEq (AddChar A M) := Classical.decEq _
+
end Basic
section toCommMonoid
@@ -291,6 +303,11 @@ lemma mul_eq_add (ψ χ : AddChar A M) : ψ * χ = ψ + χ := rfl
lemma pow_eq_nsmul (ψ : AddChar A M) (n : ℕ) : ψ ^ n = n • ψ := rfl
lemma prod_eq_sum (s : Finset ι) (ψ : ι → AddChar A M) : ∏ i in s, ψ i = ∑ i in s, ψ i := rfl
+@[simp] lemma toMonoidHomEquiv_add (ψ φ : AddChar A M) :
+ toMonoidHomEquiv (ψ + φ) = toMonoidHomEquiv ψ * toMonoidHomEquiv φ := rfl
+@[simp] lemma toMonoidHomEquiv_symm_mul (ψ φ : Multiplicative A →* M) :
+ toMonoidHomEquiv.symm (ψ * φ) = toMonoidHomEquiv.symm ψ + toMonoidHomEquiv.symm φ := rfl
+
/-- The natural equivalence to `(Multiplicative A →* M)` is a monoid isomorphism. -/
def toMonoidHomMulEquiv : AddChar A M ≃* (Multiplicative A →* M) :=
{ toMonoidHomEquiv with map_mul' := fun φ ψ ↦ by rfl }
@@ -314,9 +331,10 @@ end toCommMonoid
section CommSemiring
variable {A R : Type*} [AddGroup A] [Fintype A] [CommSemiring R] [IsDomain R]
- [DecidableEq (AddChar A R)] {ψ : AddChar A R}
+ {ψ : AddChar A R}
-lemma sum_eq_ite (ψ : AddChar A R) : ∑ a, ψ a = if ψ = 0 then ↑(card A) else 0 := by
+lemma sum_eq_ite (ψ : AddChar A R) [Decidable (ψ = 0)] :
+ ∑ a, ψ a = if ψ = 0 then ↑(card A) else 0 := by
split_ifs with h
· simp [h, card_univ]
obtain ⟨x, hx⟩ := ne_one_iff.1 h
@@ -327,6 +345,7 @@ lemma sum_eq_ite (ψ : AddChar A R) : ∑ a, ψ a = if ψ = 0 then ↑(card A) e
variable [CharZero R]
lemma sum_eq_zero_iff_ne_zero : ∑ x, ψ x = 0 ↔ ψ ≠ 0 := by
+ classical
rw [sum_eq_ite, Ne.ite_eq_right_iff]; exact Nat.cast_ne_zero.2 Fintype.card_ne_zero
lemma sum_ne_zero_iff_eq_zero : ∑ x, ψ x ≠ 0 ↔ ψ = 0 := sum_eq_zero_iff_ne_zero.not_left
@@ -354,8 +373,8 @@ instance : AddCommGroup (AddChar A M) := Additive.addCommGroup
@[simp] lemma inv_apply (ψ : AddChar A M) (a : A) : ψ⁻¹ a = ψ (-a) := rfl
@[simp] lemma neg_apply (ψ : AddChar A M) (a : A) : (-ψ) a = ψ (-a) := rfl
-@[simp] lemma div_apply (ψ χ : AddChar A M) (a : A) : (ψ / χ) a = ψ a * χ (-a) := rfl
-@[simp] lemma sub_apply (ψ χ : AddChar A M) (a : A) : (ψ - χ) a = ψ a * χ (-a) := rfl
+lemma div_apply (ψ χ : AddChar A M) (a : A) : (ψ / χ) a = ψ a * χ (-a) := rfl
+lemma sub_apply (ψ χ : AddChar A M) (a : A) : (ψ - χ) a = ψ a * χ (-a) := rfl
end fromAddCommGroup
@@ -385,8 +404,7 @@ lemma map_zsmul_eq_zpow (ψ : AddChar A M) (n : ℤ) (a : A) : ψ (n • a) = (
end fromAddGrouptoDivisionMonoid
-section fromAddGrouptoDivisionCommMonoid
-
+section fromAddCommGrouptoDivisionCommMonoid
variable {A M : Type*} [AddCommGroup A] [DivisionCommMonoid M]
lemma inv_apply' (ψ : AddChar A M) (a : A) : ψ⁻¹ a = (ψ a)⁻¹ := by rw [inv_apply, map_neg_eq_inv]
@@ -398,13 +416,18 @@ lemma div_apply' (ψ χ : AddChar A M) (a : A) : (ψ / χ) a = ψ a / χ a := by
lemma sub_apply' (ψ χ : AddChar A M) (a : A) : (ψ - χ) a = ψ a / χ a := by
rw [sub_apply, map_neg_eq_inv, div_eq_mul_inv]
+@[simp] lemma zsmul_apply (n : ℤ) (ψ : AddChar A M) (a : A) : (n • ψ) a = ψ a ^ n := by
+ cases n <;> simp [-neg_apply, neg_apply']
+
+@[simp] lemma zpow_apply (ψ : AddChar A M) (n : ℤ) (a : A) : (ψ ^ n) a = ψ a ^ n := zsmul_apply ..
+
lemma map_sub_eq_div (ψ : AddChar A M) (a b : A) : ψ (a - b) = ψ a / ψ b :=
ψ.toMonoidHom.map_div _ _
lemma injective_iff {ψ : AddChar A M} : Injective ψ ↔ ∀ ⦃x⦄, ψ x = 1 → x = 0 :=
ψ.toMonoidHom.ker_eq_bot_iff.symm.trans eq_bot_iff
-end fromAddGrouptoDivisionCommMonoid
+end fromAddCommGrouptoDivisionCommMonoid
section MonoidWithZero
variable {A M₀ : Type*} [AddGroup A] [MonoidWithZero M₀] [Nontrivial M₀]
diff --git a/Mathlib/Algebra/Group/Basic.lean b/Mathlib/Algebra/Group/Basic.lean
index 8c68d20cf55f8..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} :
@@ -148,12 +146,12 @@ section CommSemigroup
variable [CommSemigroup G]
@[to_additive]
-theorem mul_left_comm : ∀ a b c : G, a * (b * c) = b * (a * c) :=
- left_comm Mul.mul mul_comm mul_assoc
+theorem mul_left_comm (a b c : G) : a * (b * c) = b * (a * c) := by
+ rw [← mul_assoc, mul_comm a, mul_assoc]
@[to_additive]
-theorem mul_right_comm : ∀ a b c : G, a * b * c = a * c * b :=
- right_comm Mul.mul mul_comm mul_assoc
+theorem mul_right_comm (a b c : G) : a * b * c = a * c * b := by
+ rw [mul_assoc, mul_comm b, mul_assoc]
@[to_additive]
theorem mul_mul_mul_comm (a b c d : G) : a * b * (c * d) = a * c * (b * d) := by
@@ -172,7 +170,7 @@ end CommSemigroup
attribute [local simp] mul_assoc sub_eq_add_neg
section Monoid
-variable [Monoid M] {a b c : M} {m n : ℕ}
+variable [Monoid M] {a b : M} {m n : ℕ}
@[to_additive boole_nsmul]
lemma pow_boole (P : Prop) [Decidable P] (a : 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
@@ -316,7 +314,7 @@ end InvolutiveInv
section DivInvMonoid
-variable [DivInvMonoid G] {a b c : G}
+variable [DivInvMonoid G]
@[to_additive, field_simps] -- The attributes are out of order on purpose
theorem inv_eq_one_div (x : G) : x⁻¹ = 1 / x := by rw [div_eq_mul_inv, one_mul]
@@ -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
@@ -586,14 +584,16 @@ theorem mul_div_mul_comm : a * b / (c * d) = a / c * (b / d) := by simp
| (n : ℕ) => by simp_rw [zpow_natCast, mul_pow]
| .negSucc n => by simp_rw [zpow_negSucc, ← inv_pow, mul_inv, mul_pow]
-@[to_additive (attr := simp) nsmul_sub]
+@[to_additive nsmul_sub]
lemma div_pow (a b : α) (n : ℕ) : (a / b) ^ n = a ^ n / b ^ n := by
simp only [div_eq_mul_inv, mul_pow, inv_pow]
-@[to_additive (attr := simp) zsmul_sub]
+@[to_additive zsmul_sub]
lemma div_zpow (a b : α) (n : ℤ) : (a / b) ^ n = a ^ n / b ^ n := by
simp only [div_eq_mul_inv, mul_zpow, inv_zpow]
+attribute [field_simps] div_pow div_zpow
+
end DivisionCommMonoid
section Group
@@ -643,6 +643,16 @@ theorem mul_eq_one_iff_eq_inv : a * b = 1 ↔ a = b⁻¹ :=
theorem mul_eq_one_iff_inv_eq : a * b = 1 ↔ a⁻¹ = b := by
rw [mul_eq_one_iff_eq_inv, inv_eq_iff_eq_inv]
+/-- Variant of `mul_eq_one_iff_eq_inv` with swapped equality. -/
+@[to_additive]
+theorem mul_eq_one_iff_eq_inv' : a * b = 1 ↔ b = a⁻¹ := by
+ rw [mul_eq_one_iff_inv_eq, eq_comm]
+
+/-- Variant of `mul_eq_one_iff_inv_eq` with swapped equality. -/
+@[to_additive]
+theorem mul_eq_one_iff_inv_eq' : a * b = 1 ↔ b⁻¹ = a := by
+ rw [mul_eq_one_iff_eq_inv, eq_comm]
+
@[to_additive]
theorem eq_inv_iff_mul_eq_one : a = b⁻¹ ↔ a * b = 1 :=
mul_eq_one_iff_eq_inv.symm
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/Commute/Defs.lean b/Mathlib/Algebra/Group/Commute/Defs.lean
index b7bcb09ff56a4..324484366c26a 100644
--- a/Mathlib/Algebra/Group/Commute/Defs.lean
+++ b/Mathlib/Algebra/Group/Commute/Defs.lean
@@ -181,7 +181,7 @@ end Monoid
section DivisionMonoid
-variable [DivisionMonoid G] {a b c d : G}
+variable [DivisionMonoid G] {a b : G}
@[to_additive]
protected theorem mul_inv (hab : Commute a b) : (a * b)⁻¹ = a⁻¹ * b⁻¹ := by rw [hab.eq, mul_inv_rev]
diff --git a/Mathlib/Algebra/Group/Commute/Hom.lean b/Mathlib/Algebra/Group/Commute/Hom.lean
index e4279c1534a47..f95402d1287eb 100644
--- a/Mathlib/Algebra/Group/Commute/Hom.lean
+++ b/Mathlib/Algebra/Group/Commute/Hom.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Kevin Buzzard, Scott Morrison, Johan Commelin, Chris Hughes,
+Authors: Patrick Massot, Kevin Buzzard, Kim Morrison, Johan Commelin, Chris Hughes,
Johannes Hölzl, Yury Kudryashov
-/
import Mathlib.Algebra.Group.Commute.Defs
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 d1d9eaf700eef..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
@@ -49,7 +49,6 @@ See the module `Algebra.AddTorsor` for a motivating example for the name `VAdd`
assert_not_exists MonoidWithZero
assert_not_exists DenselyOrdered
assert_not_exists Function.Injective.eq_iff
-assert_not_exists IsCommutative
universe u v w
@@ -169,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]
@@ -517,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
@@ -535,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. -/
@@ -553,7 +778,7 @@ instance AddMonoid.toNatSMul {M : Type*} [AddMonoid M] : SMul ℕ M :=
attribute [to_additive existing toNatSMul] Monoid.toNatPow
section Monoid
-variable {M : Type*} [Monoid M] {a b c : M} {m n : ℕ}
+variable {M : Type*} [Monoid M] {a b c : M}
@[to_additive (attr := simp) nsmul_eq_smul]
theorem npow_eq_pow (n : ℕ) (x : M) : Monoid.npow n x = x ^ n :=
@@ -633,17 +858,17 @@ section LeftCancelMonoid
/-- An additive monoid in which addition is left-cancellative.
Main examples are `ℕ` and groups. This is the right typeclass for many sum lemmas, as having a zero
is useful to define the sum over the empty set, so `AddLeftCancelSemigroup` is not enough. -/
-class AddLeftCancelMonoid (M : Type u) extends AddLeftCancelSemigroup M, AddMonoid M
+class AddLeftCancelMonoid (M : Type u) extends AddMonoid M, AddLeftCancelSemigroup M
attribute [instance 75] AddLeftCancelMonoid.toAddMonoid -- See note [lower cancel priority]
/-- A monoid in which multiplication is left-cancellative. -/
@[to_additive]
-class LeftCancelMonoid (M : Type u) extends LeftCancelSemigroup M, Monoid M
+class LeftCancelMonoid (M : Type u) extends Monoid M, LeftCancelSemigroup M
attribute [instance 75] LeftCancelMonoid.toMonoid -- See note [lower cancel priority]
-attribute [to_additive existing] LeftCancelMonoid.toMonoid
+attribute [to_additive existing] LeftCancelMonoid.toLeftCancelSemigroup
end LeftCancelMonoid
@@ -652,17 +877,17 @@ section RightCancelMonoid
/-- An additive monoid in which addition is right-cancellative.
Main examples are `ℕ` and groups. This is the right typeclass for many sum lemmas, as having a zero
is useful to define the sum over the empty set, so `AddRightCancelSemigroup` is not enough. -/
-class AddRightCancelMonoid (M : Type u) extends AddRightCancelSemigroup M, AddMonoid M
+class AddRightCancelMonoid (M : Type u) extends AddMonoid M, AddRightCancelSemigroup M
attribute [instance 75] AddRightCancelMonoid.toAddMonoid -- See note [lower cancel priority]
/-- A monoid in which multiplication is right-cancellative. -/
@[to_additive]
-class RightCancelMonoid (M : Type u) extends RightCancelSemigroup M, Monoid M
+class RightCancelMonoid (M : Type u) extends Monoid M, RightCancelSemigroup M
attribute [instance 75] RightCancelMonoid.toMonoid -- See note [lower cancel priority]
-attribute [to_additive existing] RightCancelMonoid.toMonoid
+attribute [to_additive existing] RightCancelMonoid.toRightCancelSemigroup
end RightCancelMonoid
@@ -680,17 +905,17 @@ class CancelMonoid (M : Type u) extends LeftCancelMonoid M, RightCancelMonoid M
attribute [to_additive existing] CancelMonoid.toRightCancelMonoid
/-- Commutative version of `AddCancelMonoid`. -/
-class AddCancelCommMonoid (M : Type u) extends AddLeftCancelMonoid M, AddCommMonoid M
+class AddCancelCommMonoid (M : Type u) extends AddCommMonoid M, AddLeftCancelMonoid M
attribute [instance 75] AddCancelCommMonoid.toAddCommMonoid -- See note [lower cancel priority]
/-- Commutative version of `CancelMonoid`. -/
@[to_additive]
-class CancelCommMonoid (M : Type u) extends LeftCancelMonoid M, CommMonoid M
+class CancelCommMonoid (M : Type u) extends CommMonoid M, LeftCancelMonoid M
attribute [instance 75] CancelCommMonoid.toCommMonoid -- See note [lower cancel priority]
-attribute [to_additive existing] CancelCommMonoid.toCommMonoid
+attribute [to_additive existing] CancelCommMonoid.toLeftCancelMonoid
-- see Note [lower instance priority]
@[to_additive]
@@ -808,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
@@ -849,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
@@ -880,7 +1105,7 @@ theorem exists_zpow_surjective (G : Type*) [Pow G ℤ] [IsCyclic G] :
section DivInvMonoid
-variable [DivInvMonoid G] {a b : G}
+variable [DivInvMonoid G]
@[to_additive (attr := simp) zsmul_eq_smul] theorem zpow_eq_pow (n : ℤ) (x : G) :
DivInvMonoid.zpow n x = x ^ n :=
@@ -1051,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 6e39d0838d7ec..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)
@@ -90,6 +90,12 @@ add_decl_doc MulEquiv.toEquiv
/-- The `MulHom` underlying a `MulEquiv`. -/
add_decl_doc MulEquiv.toMulHom
+/-- Notation for a `MulEquiv`. -/
+infixl:25 " ≃* " => MulEquiv
+
+/-- Notation for an `AddEquiv`. -/
+infixl:25 " ≃+ " => AddEquiv
+
/-- `MulEquivClass F A B` states that `F` is a type of multiplication-preserving morphisms.
You should extend this class when you extend `MulEquiv`. -/
-- TODO: make this a synonym for MulHomClass?
@@ -99,12 +105,6 @@ class MulEquivClass (F : Type*) (A B : outParam Type*) [Mul A] [Mul B] [EquivLik
/-- Preserves multiplication. -/
map_mul : ∀ (f : F) (a b), f (a * b) = f a * f b
-/-- Notation for a `MulEquiv`. -/
-infixl:25 " ≃* " => MulEquiv
-
-/-- Notation for an `AddEquiv`. -/
-infixl:25 " ≃+ " => AddEquiv
-
namespace MulEquivClass
variable (F)
@@ -130,7 +130,6 @@ instance (priority := 100) instMonoidHomClass
_ = e (EquivLike.inv e (1 : N)) := by rw [← map_mul, one_mul]
_ = 1 := EquivLike.right_inv e 1 }
-variable [EquivLike F α β]
variable {F}
@[to_additive (attr := simp)]
@@ -169,7 +168,9 @@ 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
@[to_additive]
instance : EquivLike (M ≃* N) M N where
@@ -183,13 +184,35 @@ instance : EquivLike (M ≃* N) M N where
congr
apply Equiv.coe_fn_injective h₁
+@[to_additive] -- shortcut instance that doesn't generate any subgoals
+instance : CoeFun (M ≃* N) fun _ ↦ M → N where
+ coe f := f
+
@[to_additive]
instance : MulEquivClass (M ≃* N) M N where
map_mul f := f.map_mul'
-@[to_additive] -- shortcut instance that doesn't generate any subgoals
-instance : CoeFun (M ≃* N) fun _ ↦ M → N where
- coe f := f
+/-- Two multiplicative isomorphisms agree if they are defined by the
+same underlying function. -/
+@[to_additive (attr := ext)
+ "Two additive isomorphisms agree if they are defined by the same underlying function."]
+theorem ext {f g : MulEquiv M N} (h : ∀ x, f x = g x) : f = g :=
+ DFunLike.ext f g h
+
+@[to_additive]
+protected theorem congr_arg {f : MulEquiv M N} {x x' : M} : x = x' → f x = f x' :=
+ DFunLike.congr_arg f
+
+@[to_additive]
+protected theorem congr_fun {f g : MulEquiv M N} (h : f = g) (x : M) : f x = g x :=
+ DFunLike.congr_fun h x
+
+@[to_additive (attr := simp)]
+theorem coe_mk (f : M ≃ N) (hf : ∀ x y, f (x * y) = f x * f y) : (mk f hf : M → N) = f := rfl
+
+@[to_additive (attr := simp)]
+theorem mk_coe (e : M ≃* N) (e' h₁ h₂ h₃) : (⟨⟨e, e', h₁, h₂⟩, h₃⟩ : M ≃* N) = e :=
+ ext fun _ => rfl
@[to_additive (attr := simp)]
theorem toEquiv_eq_coe (f : M ≃* N) : f.toEquiv = f :=
@@ -210,6 +233,14 @@ theorem coe_toEquiv (f : M ≃* N) : ⇑(f : M ≃ N) = f := rfl
@[to_additive (attr := simp 1100)]
theorem coe_toMulHom {f : M ≃* N} : (f.toMulHom : M → N) = f := rfl
+/-- Makes a multiplicative isomorphism from a bijection which preserves multiplication. -/
+@[to_additive "Makes an additive isomorphism from a bijection which preserves addition."]
+def mk' (f : M ≃ N) (h : ∀ x y, f (x * y) = f x * f y) : M ≃* N := ⟨f, h⟩
+
+end coe
+
+section map
+
/-- A multiplicative isomorphism preserves multiplication. -/
@[to_additive "An additive isomorphism preserves addition."]
protected theorem map_mul (f : M ≃* N) : ∀ x y, f (x * y) = f x * f y :=
@@ -218,9 +249,9 @@ protected theorem map_mul (f : M ≃* N) : ∀ x y, f (x * y) = f x * f y :=
attribute [deprecated map_mul (since := "2024-08-08")] MulEquiv.map_mul
attribute [deprecated map_add (since := "2024-08-08")] AddEquiv.map_add
-/-- Makes a multiplicative isomorphism from a bijection which preserves multiplication. -/
-@[to_additive "Makes an additive isomorphism from a bijection which preserves addition."]
-def mk' (f : M ≃ N) (h : ∀ x y, f (x * y) = f x * f y) : M ≃* N := ⟨f, h⟩
+end map
+
+section bijective
@[to_additive]
protected theorem bijective (e : M ≃* N) : Function.Bijective e :=
@@ -234,6 +265,14 @@ protected theorem injective (e : M ≃* N) : Function.Injective e :=
protected theorem surjective (e : M ≃* N) : Function.Surjective e :=
EquivLike.surjective e
+@[to_additive]
+theorem apply_eq_iff_eq (e : M ≃* N) {x y : M} : e x = e y ↔ x = y :=
+ e.injective.eq_iff
+
+end bijective
+
+section refl
+
/-- The identity map is a multiplicative isomorphism. -/
@[to_additive (attr := refl) "The identity map is an additive isomorphism."]
def refl (M : Type*) [Mul M] : M ≃* M :=
@@ -242,6 +281,16 @@ def refl (M : Type*) [Mul M] : M ≃* M :=
@[to_additive]
instance : Inhabited (M ≃* M) := ⟨refl M⟩
+@[to_additive (attr := simp)]
+theorem coe_refl : ↑(refl M) = id := rfl
+
+@[to_additive (attr := simp)]
+theorem refl_apply (m : M) : refl M m = m := rfl
+
+end refl
+
+section symm
+
/-- An alias for `h.symm.map_mul`. Introduced to fix the issue in
https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/!4.234183.20.60simps.60.20maximum.20recursion.20depth
-/
@@ -265,24 +314,9 @@ theorem coe_toEquiv_symm (f : M ≃* N) : ((f : M ≃ N).symm : N → M) = f.sym
@[to_additive (attr := simp)]
theorem equivLike_inv_eq_symm (f : M ≃* N) : EquivLike.inv f = f.symm := rfl
--- we don't hyperlink the note in the additive version, since that breaks syntax highlighting
--- in the whole file.
-
-/-- See Note [custom simps projection] -/
-@[to_additive "See Note [custom simps projection]"] -- this comment fixes the syntax highlighting "
-def Simps.symm_apply (e : M ≃* N) : N → M :=
- e.symm
-
-initialize_simps_projections AddEquiv (toFun → apply, invFun → symm_apply)
-
-initialize_simps_projections MulEquiv (toFun → apply, invFun → symm_apply)
-
@[to_additive (attr := simp)]
theorem toEquiv_symm (f : M ≃* N) : (f.symm : N ≃ M) = (f : M ≃ N).symm := rfl
-@[to_additive (attr := simp)]
-theorem coe_mk (f : M ≃ N) (hf : ∀ x y, f (x * y) = f x * f y) : (mk f hf : M → N) = f := rfl
-
-- Porting note: `toEquiv_mk` no longer needed in Lean4
@[to_additive (attr := simp)]
@@ -292,6 +326,10 @@ theorem symm_symm (f : M ≃* N) : f.symm.symm = f := rfl
theorem symm_bijective : Function.Bijective (symm : (M ≃* N) → N ≃* M) :=
Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩
+@[to_additive (attr := simp)]
+theorem mk_coe' (e : M ≃* N) (f h₁ h₂ h₃) : (MulEquiv.mk ⟨f, e, h₁, h₂⟩ h₃ : N ≃* M) = e.symm :=
+ symm_bijective.injective <| ext fun _ => rfl
+
@[to_additive (attr := simp)]
theorem symm_mk (f : M ≃ N) (h) :
(MulEquiv.mk f h).symm = ⟨f.symm, (MulEquiv.mk f h).symm_map_mul⟩ := rfl
@@ -299,13 +337,6 @@ theorem symm_mk (f : M ≃ N) (h) :
@[to_additive (attr := simp)]
theorem refl_symm : (refl M).symm = refl M := rfl
-/-- Transitivity of multiplication-preserving isomorphisms -/
-@[to_additive (attr := trans) "Transitivity of addition-preserving isomorphisms"]
-def trans (h1 : M ≃* N) (h2 : N ≃* P) : M ≃* P :=
- { h1.toEquiv.trans h2.toEquiv with
- map_mul' := fun x y => show h2 (h1 (x * y)) = h2 (h1 x) * h2 (h1 y) by
- rw [map_mul, map_mul] }
-
/-- `e.symm` is a right inverse of `e`, written as `e (e.symm y) = y`. -/
@[to_additive (attr := simp) "`e.symm` is a right inverse of `e`, written as `e (e.symm y) = y`."]
theorem apply_symm_apply (e : M ≃* N) (y : N) : e (e.symm y) = y :=
@@ -324,27 +355,6 @@ theorem symm_comp_self (e : M ≃* N) : e.symm ∘ e = id :=
theorem self_comp_symm (e : M ≃* N) : e ∘ e.symm = id :=
funext e.apply_symm_apply
-@[to_additive (attr := simp)]
-theorem coe_refl : ↑(refl M) = id := rfl
-
-@[to_additive (attr := simp)]
-theorem refl_apply (m : M) : refl M m = m := rfl
-
-@[to_additive (attr := simp)]
-theorem coe_trans (e₁ : M ≃* N) (e₂ : N ≃* P) : ↑(e₁.trans e₂) = e₂ ∘ e₁ := rfl
-
-@[to_additive (attr := simp)]
-theorem trans_apply (e₁ : M ≃* N) (e₂ : N ≃* P) (m : M) : e₁.trans e₂ m = e₂ (e₁ m) := rfl
-
-@[to_additive (attr := simp)]
-theorem symm_trans_apply (e₁ : M ≃* N) (e₂ : N ≃* P) (p : P) :
- (e₁.trans e₂).symm p = e₁.symm (e₂.symm p) := rfl
-
--- 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
-
@[to_additive]
theorem apply_eq_iff_symm_apply (e : M ≃* N) {x : M} {y : N} : e x = y ↔ x = e.symm y :=
e.toEquiv.apply_eq_iff_eq_symm_apply
@@ -378,35 +388,65 @@ theorem symm_comp_eq {α : Type*} (e : M ≃* N) (f : α → M) (g : α → N) :
e.toEquiv.symm_comp_eq f g
@[to_additive (attr := simp)]
-theorem symm_trans_self (e : M ≃* N) : e.symm.trans e = refl N :=
- DFunLike.ext _ _ e.apply_symm_apply
+theorem _root_.MulEquivClass.apply_coe_symm_apply {α β} [Mul α] [Mul β] {F} [EquivLike F α β]
+ [MulEquivClass F α β] (e : F) (x : β) :
+ e ((e : α ≃* β).symm x) = x :=
+ (e : α ≃* β).right_inv x
@[to_additive (attr := simp)]
-theorem self_trans_symm (e : M ≃* N) : e.trans e.symm = refl M :=
- DFunLike.ext _ _ e.symm_apply_apply
+theorem _root_.MulEquivClass.coe_symm_apply_apply {α β} [Mul α] [Mul β] {F} [EquivLike F α β]
+ [MulEquivClass F α β] (e : F) (x : α) :
+ (e : α ≃* β).symm (e x) = x :=
+ (e : α ≃* β).left_inv x
-/-- Two multiplicative isomorphisms agree if they are defined by the
-same underlying function. -/
-@[to_additive (attr := ext)
- "Two additive isomorphisms agree if they are defined by the same underlying function."]
-theorem ext {f g : MulEquiv M N} (h : ∀ x, f x = g x) : f = g :=
- DFunLike.ext f g h
+end symm
+
+section simps
+
+-- we don't hyperlink the note in the additive version, since that breaks syntax highlighting
+-- in the whole file.
+
+/-- See Note [custom simps projection] -/
+@[to_additive "See Note [custom simps projection]"] -- this comment fixes the syntax highlighting "
+def Simps.symm_apply (e : M ≃* N) : N → M :=
+ e.symm
+
+initialize_simps_projections AddEquiv (toFun → apply, invFun → symm_apply)
+
+initialize_simps_projections MulEquiv (toFun → apply, invFun → symm_apply)
+
+end simps
+
+section trans
+
+/-- Transitivity of multiplication-preserving isomorphisms -/
+@[to_additive (attr := trans) "Transitivity of addition-preserving isomorphisms"]
+def trans (h1 : M ≃* N) (h2 : N ≃* P) : M ≃* P :=
+ { h1.toEquiv.trans h2.toEquiv with
+ map_mul' := fun x y => show h2 (h1 (x * y)) = h2 (h1 x) * h2 (h1 y) by
+ rw [map_mul, map_mul] }
@[to_additive (attr := simp)]
-theorem mk_coe (e : M ≃* N) (e' h₁ h₂ h₃) : (⟨⟨e, e', h₁, h₂⟩, h₃⟩ : M ≃* N) = e :=
- ext fun _ => rfl
+theorem coe_trans (e₁ : M ≃* N) (e₂ : N ≃* P) : ↑(e₁.trans e₂) = e₂ ∘ e₁ := rfl
@[to_additive (attr := simp)]
-theorem mk_coe' (e : M ≃* N) (f h₁ h₂ h₃) : (MulEquiv.mk ⟨f, e, h₁, h₂⟩ h₃ : N ≃* M) = e.symm :=
- symm_bijective.injective <| ext fun _ => rfl
+theorem trans_apply (e₁ : M ≃* N) (e₂ : N ≃* P) (m : M) : e₁.trans e₂ m = e₂ (e₁ m) := rfl
-@[to_additive]
-protected theorem congr_arg {f : MulEquiv M N} {x x' : M} : x = x' → f x = f x' :=
- DFunLike.congr_arg f
+@[to_additive (attr := simp)]
+theorem symm_trans_apply (e₁ : M ≃* N) (e₂ : N ≃* P) (p : P) :
+ (e₁.trans e₂).symm p = e₁.symm (e₂.symm p) := rfl
-@[to_additive]
-protected theorem congr_fun {f g : MulEquiv M N} (h : f = g) (x : M) : f x = g x :=
- DFunLike.congr_fun h x
+@[to_additive (attr := simp)]
+theorem symm_trans_self (e : M ≃* N) : e.symm.trans e = refl N :=
+ DFunLike.ext _ _ e.apply_symm_apply
+
+@[to_additive (attr := simp)]
+theorem self_trans_symm (e : M ≃* N) : e.trans e.symm = refl M :=
+ DFunLike.ext _ _ e.symm_apply_apply
+
+end trans
+
+section unique
/-- The `MulEquiv` between two monoids with a unique element. -/
@[to_additive "The `AddEquiv` between two `AddMonoid`s with a unique element."]
@@ -420,6 +460,8 @@ instance {M N} [Unique M] [Unique N] [Mul M] [Mul N] : Unique (M ≃* N) where
default := mulEquivOfUnique
uniq _ := ext fun _ => Subsingleton.elim _ _
+end unique
+
end Mul
/-!
@@ -429,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/Equiv/TypeTags.lean b/Mathlib/Algebra/Group/Equiv/TypeTags.lean
index 812c4308708bd..78c085f074666 100644
--- a/Mathlib/Algebra/Group/Equiv/TypeTags.lean
+++ b/Mathlib/Algebra/Group/Equiv/TypeTags.lean
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Callum Sutton, Yury Kudryashov
-/
import Mathlib.Algebra.Group.Equiv.Basic
+import Mathlib.Algebra.Group.Prod
import Mathlib.Algebra.Group.TypeTags
/-!
@@ -11,7 +12,7 @@ import Mathlib.Algebra.Group.TypeTags
-/
-variable {G H : Type*}
+variable {ι G H : Type*}
/-- Reinterpret `G ≃+ H` as `Multiplicative G ≃* Multiplicative H`. -/
@[simps]
@@ -113,6 +114,38 @@ and multiplicative endomorphisms of `Multiplicative A`. -/
{ AddMonoidHom.toMultiplicative with
map_mul' := fun _ _ => rfl }
+/-- `Multiplicative (∀ i : ι, K i)` is equivalent to `∀ i : ι, Multiplicative (K i)`. -/
+@[simps]
+def MulEquiv.piMultiplicative (K : ι → Type*) [∀ i, Add (K i)] :
+ Multiplicative (∀ i : ι, K i) ≃* (∀ i : ι, Multiplicative (K i)) where
+ toFun x := fun i ↦ Multiplicative.ofAdd <| Multiplicative.toAdd x i
+ invFun x := Multiplicative.ofAdd fun i ↦ Multiplicative.toAdd (x i)
+ left_inv _ := rfl
+ right_inv _ := rfl
+ map_mul' _ _ := rfl
+
+variable (ι) (G) in
+/-- `Multiplicative (ι → G)` is equivalent to `ι → Multiplicative G`. -/
+abbrev MulEquiv.funMultiplicative [Add G] :
+ Multiplicative (ι → G) ≃* (ι → Multiplicative G) :=
+ MulEquiv.piMultiplicative fun _ ↦ G
+
+/-- `Additive (∀ i : ι, K i)` is equivalent to `∀ i : ι, Additive (K i)`. -/
+@[simps]
+def AddEquiv.piAdditive (K : ι → Type*) [∀ i, Mul (K i)] :
+ Additive (∀ i : ι, K i) ≃+ (∀ i : ι, Additive (K i)) where
+ toFun x := fun i ↦ Additive.ofMul <| Additive.toMul x i
+ invFun x := Additive.ofMul fun i ↦ Additive.toMul (x i)
+ left_inv _ := rfl
+ right_inv _ := rfl
+ map_add' _ _ := rfl
+
+variable (ι) (G) in
+/-- `Additive (ι → G)` is equivalent to `ι → Additive G`. -/
+abbrev AddEquiv.funAdditive [Mul G] :
+ Additive (ι → G) ≃+ (ι → Additive G) :=
+ AddEquiv.piAdditive fun _ ↦ G
+
section
variable (G) (H)
@@ -127,4 +160,26 @@ def AddEquiv.additiveMultiplicative [AddZeroClass G] : Additive (Multiplicative
def MulEquiv.multiplicativeAdditive [MulOneClass H] : Multiplicative (Additive H) ≃* H :=
AddEquiv.toMultiplicative'' (AddEquiv.refl (Additive H))
+/-- `Multiplicative (G × H)` is equivalent to `Multiplicative G × Multiplicative H`. -/
+@[simps]
+def MulEquiv.prodMultiplicative [Add G] [Add H] :
+ Multiplicative (G × H) ≃* Multiplicative G × Multiplicative H where
+ toFun x := (Multiplicative.ofAdd (Multiplicative.toAdd x).1,
+ Multiplicative.ofAdd (Multiplicative.toAdd x).2)
+ invFun := fun (x, y) ↦ Multiplicative.ofAdd (Multiplicative.toAdd x, Multiplicative.toAdd y)
+ left_inv _ := rfl
+ right_inv _ := rfl
+ map_mul' _ _ := rfl
+
+/-- `Additive (G × H)` is equivalent to `Additive G × Additive H`. -/
+@[simps]
+def AddEquiv.prodAdditive [Mul G] [Mul H] :
+ Additive (G × H) ≃+ Additive G × Additive H where
+ toFun x := (Additive.ofMul (Additive.toMul x).1,
+ Additive.ofMul (Additive.toMul x).2)
+ invFun := fun (x, y) ↦ Additive.ofMul (Additive.toMul x, Additive.toMul y)
+ left_inv _ := rfl
+ right_inv _ := rfl
+ map_add' _ _ := rfl
+
end
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
new file mode 100644
index 0000000000000..81ddf35dcd57c
--- /dev/null
+++ b/Mathlib/Algebra/Group/EvenFunction.lean
@@ -0,0 +1,150 @@
+/-
+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.BigOperators.Group.Finset
+import Mathlib.Algebra.Group.Action.Pi
+import Mathlib.Algebra.NoZeroSMulDivisors.Basic
+
+/-!
+# Even and odd functions
+
+We define even functions `α → β` assuming `α` has a negation, and odd functions assuming both `α`
+and `β` have negation.
+
+These definitions are `Function.Even` and `Function.Odd`; and they are `protected`, to avoid
+conflicting with the root-level definitions `Even` and `Odd` (which, for functions, mean that the
+function takes even resp. odd _values_, a wholly different concept).
+-/
+
+namespace Function
+
+variable {α β : Type*} [Neg α]
+
+/-- A function `f` is _even_ if it satisfies `f (-x) = f x` for all `x`. -/
+protected def Even (f : α → β) : Prop := ∀ a, f (-a) = f a
+
+/-- A function `f` is _odd_ if it satisfies `f (-x) = -f x` for all `x`. -/
+protected def Odd [Neg β] (f : α → β) : Prop := ∀ a, f (-a) = -(f a)
+
+/-- Any constant function is even. -/
+lemma Even.const (b : β) : Function.Even (fun _ : α ↦ b) := fun _ ↦ rfl
+
+/-- The zero function is even. -/
+lemma Even.zero [Zero β] : Function.Even (fun (_ : α) ↦ (0 : β)) := Even.const 0
+
+/-- The zero function is odd. -/
+lemma Odd.zero [NegZeroClass β] : Function.Odd (fun (_ : α) ↦ (0 : β)) := fun _ ↦ neg_zero.symm
+
+section composition
+
+variable {γ : Type*}
+
+/-- If `f` is arbitrary and `g` is even, then `f ∘ g` is even. -/
+lemma Even.left_comp {g : α → β} (hg : g.Even) (f : β → γ) : (f ∘ g).Even :=
+ (congr_arg f <| hg ·)
+
+/-- If `f` is even and `g` is odd, then `f ∘ g` is even. -/
+lemma Even.comp_odd [Neg β] {f : β → γ} (hf : f.Even) {g : α → β} (hg : g.Odd) :
+ (f ∘ g).Even := by
+ intro a
+ simp only [comp_apply, hg a, hf _]
+
+/-- If `f` and `g` are odd, then `f ∘ g` is odd. -/
+lemma Odd.comp_odd [Neg β] [Neg γ] {f : β → γ} (hf : f.Odd) {g : α → β} (hg : g.Odd) :
+ (f ∘ g).Odd := by
+ intro a
+ simp only [comp_apply, hg a, hf _]
+
+end composition
+
+lemma Even.add [Add β] {f g : α → β} (hf : f.Even) (hg : g.Even) : (f + g).Even := by
+ intro a
+ simp only [hf a, hg a, Pi.add_apply]
+
+lemma Odd.add [SubtractionCommMonoid β] {f g : α → β} (hf : f.Odd) (hg : g.Odd) : (f + g).Odd := by
+ intro a
+ simp only [hf a, hg a, Pi.add_apply, neg_add]
+
+section smul
+
+variable {γ : Type*} {f : α → β} {g : α → γ}
+
+lemma Even.smul_even [SMul β γ] (hf : f.Even) (hg : g.Even) : (f • g).Even := by
+ intro a
+ simp only [Pi.smul_apply', hf a, hg a]
+
+lemma Even.smul_odd [Monoid β] [AddGroup γ] [DistribMulAction β γ] (hf : f.Even) (hg : g.Odd) :
+ (f • g).Odd := by
+ intro a
+ simp only [Pi.smul_apply', hf a, hg a, smul_neg]
+
+lemma Odd.smul_even [Ring β] [AddCommGroup γ] [Module β γ] (hf : f.Odd) (hg : g.Even) :
+ (f • g).Odd := by
+ intro a
+ simp only [Pi.smul_apply', hf a, hg a, neg_smul]
+
+lemma Odd.smul_odd [Ring β] [AddCommGroup γ] [Module β γ] (hf : f.Odd) (hg : g.Odd) :
+ (f • g).Even := by
+ intro a
+ simp only [Pi.smul_apply', hf a, hg a, smul_neg, neg_smul, neg_neg]
+
+lemma Even.const_smul [SMul β γ] (hg : g.Even) (r : β) : (r • g).Even := by
+ intro a
+ simp only [Pi.smul_apply, hg a]
+
+lemma Odd.const_smul [Monoid β] [AddGroup γ] [DistribMulAction β γ] (hg : g.Odd) (r : β) :
+ (r • g).Odd := by
+ intro a
+ simp only [Pi.smul_apply, hg a, smul_neg]
+
+end smul
+
+section mul
+
+variable {R : Type*} [Mul R] {f g : α → R}
+
+lemma Even.mul_even (hf : f.Even) (hg : g.Even) : (f * g).Even := by
+ intro a
+ simp only [Pi.mul_apply, hf a, hg a]
+
+lemma Even.mul_odd [HasDistribNeg R] (hf : f.Even) (hg : g.Odd) : (f * g).Odd := by
+ intro a
+ simp only [Pi.mul_apply, hf a, hg a, mul_neg]
+
+lemma Odd.mul_even [HasDistribNeg R] (hf : f.Odd) (hg : g.Even) : (f * g).Odd := by
+ intro a
+ simp only [Pi.mul_apply, hf a, hg a, neg_mul]
+
+lemma Odd.mul_odd [HasDistribNeg R] (hf : f.Odd) (hg : g.Odd) : (f * g).Even := by
+ intro a
+ simp only [Pi.mul_apply, hf a, hg a, mul_neg, neg_mul, neg_neg]
+
+end mul
+
+section torsionfree
+
+-- need to redeclare variables since `InvolutiveNeg α` conflicts with `Neg α`
+variable {α β : Type*} [AddCommGroup β] [NoZeroSMulDivisors ℕ β] {f : α → β}
+
+/--
+If `f` is both even and odd, and its target is a torsion-free commutative additive group,
+then `f = 0`.
+-/
+lemma zero_of_even_and_odd [Neg α] (he : f.Even) (ho : f.Odd) : f = 0 := by
+ ext r
+ rw [Pi.zero_apply, ← neg_eq_self ℕ, ← ho, he]
+
+/-- The sum of the values of an odd function is 0. -/
+lemma Odd.sum_eq_zero [Fintype α] [InvolutiveNeg α] {f : α → β} (hf : f.Odd) : ∑ a, f a = 0 := by
+ simpa only [neg_eq_self ℕ, Finset.sum_neg_distrib, funext hf, Equiv.neg_apply] using
+ Equiv.sum_comp (.neg α) f
+
+/-- An odd function vanishes at zero. -/
+lemma Odd.map_zero [NegZeroClass α] (hf : f.Odd) : f 0 = 0 := by
+ simp only [← neg_eq_self ℕ, ← hf 0, neg_zero]
+
+end torsionfree
+
+end Function
diff --git a/Mathlib/Algebra/Group/Fin/Basic.lean b/Mathlib/Algebra/Group/Fin/Basic.lean
index 27b58e867117f..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 _ _ _)
@@ -89,17 +89,41 @@ lemma coe_sub_one (a : Fin (n + 1)) : ↑(a - 1) = if a = 0 then n else a - 1 :=
rwa [Fin.ext_iff] at h
@[simp]
+lemma lt_sub_iff {n : ℕ} {a b : Fin n} : a < a - b ↔ a < b := by
+ cases' n with n
+ · exact a.elim0
+ constructor
+ · contrapose!
+ intro h
+ obtain ⟨l, hl⟩ := Nat.exists_eq_add_of_le (Fin.not_lt.mp h)
+ simpa only [Fin.not_lt, le_iff_val_le_val, sub_def, hl, ← Nat.add_assoc, Nat.add_mod_left,
+ Nat.mod_eq_of_lt, Nat.sub_add_cancel b.is_lt.le] using
+ (le_trans (mod_le _ _) (le_add_left _ _))
+ · intro h
+ rw [lt_iff_val_lt_val, sub_def]
+ simp only
+ obtain ⟨k, hk⟩ := Nat.exists_eq_add_of_lt b.is_lt
+ have : n + 1 - b = k + 1 := by
+ simp_rw [hk, Nat.add_assoc, Nat.add_sub_cancel_left]
+ -- simp_rw because, otherwise, rw tries to rewrite inside `b : Fin (n + 1)`
+ rw [this, Nat.mod_eq_of_lt (hk.ge.trans_lt' ?_), Nat.lt_add_left_iff_pos] <;>
+ omega
+
+@[simp]
+lemma sub_le_iff {n : ℕ} {a b : Fin n} : a - b ≤ a ↔ b ≤ a := by
+ rw [← not_iff_not, Fin.not_le, Fin.not_le, lt_sub_iff]
+
+@[simp]
+lemma lt_one_iff {n : ℕ} (x : Fin (n + 2)) : x < 1 ↔ x = 0 := by
+ simp [lt_iff_val_lt_val, Fin.ext_iff]
+
lemma lt_sub_one_iff {k : Fin (n + 2)} : k < k - 1 ↔ k = 0 := by
- rcases k with ⟨_ | k, hk⟩
- · simp only [zero_eta, zero_sub, lt_iff_val_lt_val, val_zero, coe_neg_one, zero_lt_succ]
- have : (n + 1 + (k + 1)) % (n + 2) = k % (n + 2) := by
- rw [Nat.add_comm, Nat.add_right_comm, Nat.add_assoc, Nat.add_assoc, add_mod_right]
- simp [lt_iff_val_lt_val, Fin.ext_iff, Fin.coe_sub, this, mod_eq_of_lt ((lt_succ_self _).trans hk)]
+ simp
@[simp] lemma le_sub_one_iff {k : Fin (n + 1)} : k ≤ k - 1 ↔ k = 0 := by
cases n
· simp [fin_one_eq_zero k]
- simp [-val_fin_le, le_def]
+ simp only [le_def]
rw [← lt_sub_one_iff, le_iff_lt_or_eq, val_fin_lt, val_inj, lt_sub_one_iff, or_iff_left_iff_imp,
eq_comm, sub_eq_iff_eq_add]
simp
@@ -112,4 +136,15 @@ lemma sub_one_lt_iff {k : Fin (n + 1)} : k - 1 < k ↔ 0 < k :=
lemma neg_natCast_eq_one (n : ℕ) : -(n : Fin (n + 1)) = 1 := by
simp only [natCast_eq_last, neg_last]
+lemma rev_add (a b : Fin n) : rev (a + b) = rev a - b := by
+ cases' n
+ · exact a.elim0
+ rw [← last_sub, ← last_sub, sub_add_eq_sub_sub]
+
+lemma rev_sub (a b : Fin n) : rev (a - b) = rev a + b := by
+ rw [rev_eq_iff, rev_add, rev_rev]
+
+lemma add_lt_left_iff {n : ℕ} {a b : Fin n} : a + b < a ↔ rev b < a := by
+ rw [← rev_lt_rev, Iff.comm, ← rev_lt_rev, rev_add, lt_sub_iff, rev_rev]
+
end Fin
diff --git a/Mathlib/Algebra/Group/Hom/Basic.lean b/Mathlib/Algebra/Group/Hom/Basic.lean
index bac422e61797b..114dff59a75ba 100644
--- a/Mathlib/Algebra/Group/Hom/Basic.lean
+++ b/Mathlib/Algebra/Group/Hom/Basic.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Kevin Buzzard, Scott Morrison, Johan Commelin, Chris Hughes,
+Authors: Patrick Massot, Kevin Buzzard, Kim Morrison, Johan Commelin, Chris Hughes,
Johannes Hölzl, Yury Kudryashov
-/
import Mathlib.Algebra.Group.Basic
@@ -14,9 +14,9 @@ import Mathlib.Algebra.Group.Hom.Defs
-- `NeZero` cannot be additivised, hence its theory should be developed outside of the
-- `Algebra.Group` folder.
-assert_not_exists NeZero
+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/CompTypeclasses.lean b/Mathlib/Algebra/Group/Hom/CompTypeclasses.lean
index 5f9f1cea90e7a..0bdd4b963dd4a 100644
--- a/Mathlib/Algebra/Group/Hom/CompTypeclasses.lean
+++ b/Mathlib/Algebra/Group/Hom/CompTypeclasses.lean
@@ -39,7 +39,7 @@ section MonoidHomCompTriple
namespace MonoidHom
/-- Class of composing triples -/
-class CompTriple {M N P : Type*} [Monoid M] [Monoid N] [Monoid P]
+class CompTriple {M N P : Type*} [Monoid M] [Monoid N] [Monoid P]
(φ : M →* N) (ψ : N →* P) (χ : outParam (M →* P)) : Prop where
/-- The maps form a commuting triangle -/
comp_eq : ψ.comp φ = χ
@@ -48,7 +48,6 @@ attribute [simp] CompTriple.comp_eq
namespace CompTriple
-variable {M' : Type*} [Monoid M']
variable {M N P : Type*} [Monoid M] [Monoid N] [Monoid P]
/-- Class of Id maps -/
diff --git a/Mathlib/Algebra/Group/Hom/Defs.lean b/Mathlib/Algebra/Group/Hom/Defs.lean
index b75baec7c85f7..14f51627f6d9d 100644
--- a/Mathlib/Algebra/Group/Hom/Defs.lean
+++ b/Mathlib/Algebra/Group/Hom/Defs.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Kevin Buzzard, Scott Morrison, Johan Commelin, Chris Hughes,
+Authors: Patrick Massot, Kevin Buzzard, Kim Morrison, Johan Commelin, Chris Hughes,
Johannes Hölzl, Yury Kudryashov
-/
import Mathlib.Algebra.Group.Pi.Basic
@@ -143,8 +143,9 @@ homomorphisms.
You should also extend this typeclass when you extend `AddMonoidHom`.
-/
-class AddMonoidHomClass (F M N : Type*) [AddZeroClass M] [AddZeroClass N] [FunLike F M N]
- extends AddHomClass F M N, ZeroHomClass F M N : Prop
+class AddMonoidHomClass (F : Type*) (M N : outParam Type*)
+ [AddZeroClass M] [AddZeroClass N] [FunLike F M N]
+ extends AddHomClass F M N, ZeroHomClass F M N : Prop
-- Instances and lemmas are defined below through `@[to_additive]`.
end add_zero
@@ -184,9 +185,29 @@ instance OneHom.funLike : FunLike (OneHom M N) M N where
instance OneHom.oneHomClass : OneHomClass (OneHom M N) M N where
map_one := OneHom.map_one'
+library_note "low priority simp lemmas"
+/--
+The hom class hierarchy allows for a single lemma, such as `map_one`, to apply to a large variety
+of morphism types, so long as they have an instance of `OneHomClass`. For example, this applies to
+to `MonoidHom`, `RingHom`, `AlgHom`, `StarAlgHom`, as well as their `Equiv` variants, etc. However,
+precisely because these lemmas are so widely applicable, they keys in the `simp` discrimination tree
+are necessarily highly non-specific. For example, the key for `map_one` is
+`@DFunLike.coe _ _ _ _ _ 1`.
+
+Consequently, whenever lean sees `⇑f 1`, for some `f : F`, it will attempt to synthesize a
+`OneHomClass F ?A ?B` instance. If no such instance exists, then Lean will need to traverse (almost)
+the entirety of the `FunLike` hierarchy in order to determine this because so many classes have a
+`OneHomClass` instance (in fact, this problem is likely worse for `ZeroHomClass`). This can lead to
+a significant performance hit when `map_one` fails to apply.
+
+To avoid this problem, we mark these widely applicable simp lemmas with key discimination tree keys
+with `low` priority in order to ensure that they are not tried first.
+-/
+
variable [FunLike F M N]
-@[to_additive (attr := simp)]
+/-- See note [low priority simp lemmas] -/
+@[to_additive (attr := simp low)]
theorem map_one [OneHomClass F M N] (f : F) : f 1 = 1 :=
OneHomClass.map_one f
@@ -277,7 +298,8 @@ instance MulHom.mulHomClass : MulHomClass (M →ₙ* N) M N where
variable [FunLike F M N]
-@[to_additive (attr := simp)]
+/-- See note [low priority simp lemmas] -/
+@[to_additive (attr := simp low)]
theorem map_mul [MulHomClass F M N] (f : F) (x y : M) : f (x * y) = f x * f y :=
MulHomClass.map_mul f x y
@@ -391,8 +413,10 @@ lemma map_comp_div' [DivInvMonoid G] [DivInvMonoid H] [MonoidHomClass F G H] (f
(hf : ∀ a, f a⁻¹ = (f a)⁻¹) (g h : ι → G) : f ∘ (g / h) = f ∘ g / f ∘ h := by
ext; simp [map_div' f hf]
-/-- Group homomorphisms preserve inverse. -/
-@[to_additive (attr := simp) "Additive group homomorphisms preserve negation."]
+/-- Group homomorphisms preserve inverse.
+
+See note [low priority simp lemmas] -/
+@[to_additive (attr := simp low) "Additive group homomorphisms preserve negation."]
theorem map_inv [Group G] [DivisionMonoid H] [MonoidHomClass F G H]
(f : F) (a : G) : f a⁻¹ = (f a)⁻¹ :=
eq_inv_of_mul_eq_one_left <| map_mul_eq_one f <| inv_mul_cancel _
@@ -410,8 +434,10 @@ theorem map_mul_inv [Group G] [DivisionMonoid H] [MonoidHomClass F G H] (f : F)
lemma map_comp_mul_inv [Group G] [DivisionMonoid H] [MonoidHomClass F G H] (f : F) (g h : ι → G) :
f ∘ (g * h⁻¹) = f ∘ g * (f ∘ h)⁻¹ := by simp
-/-- Group homomorphisms preserve division. -/
-@[to_additive (attr := simp) "Additive group homomorphisms preserve subtraction."]
+/-- Group homomorphisms preserve division.
+
+See note [low priority simp lemmas] -/
+@[to_additive (attr := simp low) "Additive group homomorphisms preserve subtraction."]
theorem map_div [Group G] [DivisionMonoid H] [MonoidHomClass F G H] (f : F) :
∀ a b, f (a / b) = f a / f b := map_div' _ <| map_inv f
@@ -419,14 +445,15 @@ theorem map_div [Group G] [DivisionMonoid H] [MonoidHomClass F G H] (f : F) :
lemma map_comp_div [Group G] [DivisionMonoid H] [MonoidHomClass F G H] (f : F) (g h : ι → G) :
f ∘ (g / h) = f ∘ g / f ∘ h := by ext; simp
-@[to_additive (attr := simp) (reorder := 9 10)]
+/-- See note [low priority simp lemmas] -/
+@[to_additive (attr := simp low) (reorder := 9 10)]
theorem map_pow [Monoid G] [Monoid H] [MonoidHomClass F G H] (f : F) (a : G) :
∀ n : ℕ, f (a ^ n) = f a ^ n
| 0 => by rw [pow_zero, pow_zero, map_one]
| n + 1 => by rw [pow_succ, pow_succ, map_mul, map_pow f a n]
@[to_additive (attr := simp)]
-lemma map_comp_pow [Group G] [DivisionMonoid H] [MonoidHomClass F G H] (f : F) (g : ι → G) (n : ℕ) :
+lemma map_comp_pow [Monoid G] [Monoid H] [MonoidHomClass F G H] (f : F) (g : ι → G) (n : ℕ) :
f ∘ (g ^ n) = f ∘ g ^ n := by ext; simp
@[to_additive]
@@ -440,8 +467,10 @@ lemma map_comp_zpow' [DivInvMonoid G] [DivInvMonoid H] [MonoidHomClass F G H] (f
(hf : ∀ x : G, f x⁻¹ = (f x)⁻¹) (g : ι → G) (n : ℤ) : f ∘ (g ^ n) = f ∘ g ^ n := by
ext; simp [map_zpow' f hf]
-/-- Group homomorphisms preserve integer power. -/
-@[to_additive (attr := simp) (reorder := 9 10)
+/-- Group homomorphisms preserve integer power.
+
+See note [low priority simp lemmas] -/
+@[to_additive (attr := simp low) (reorder := 9 10)
"Additive group homomorphisms preserve integer scaling."]
theorem map_zpow [Group G] [DivisionMonoid H] [MonoidHomClass F G H]
(f : F) (g : G) (n : ℤ) : f (g ^ n) = f g ^ n := map_zpow' f (map_inv f) g n
@@ -838,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⟩
@@ -879,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
@@ -930,8 +959,6 @@ instance [MulOneClass M] [MulOneClass N] : Inhabited (M →* N) := ⟨1⟩
namespace MonoidHom
-variable [Group G] [CommGroup H]
-
@[to_additive (attr := simp)]
theorem one_comp [MulOneClass M] [MulOneClass N] [MulOneClass P] (f : M →* N) :
(1 : N →* P).comp f = 1 := rfl
diff --git a/Mathlib/Algebra/Group/Hom/End.lean b/Mathlib/Algebra/Group/Hom/End.lean
index 207791e8b527c..caa7de5333f3d 100644
--- a/Mathlib/Algebra/Group/Hom/End.lean
+++ b/Mathlib/Algebra/Group/Hom/End.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Kevin Buzzard, Scott Morrison, Johan Commelin, Chris Hughes,
+Authors: Patrick Massot, Kevin Buzzard, Kim Morrison, Johan Commelin, Chris Hughes,
Johannes Hölzl, Yury Kudryashov
-/
import Mathlib.Algebra.Group.Commute.Defs
@@ -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/Hom/Instances.lean b/Mathlib/Algebra/Group/Hom/Instances.lean
index 3b1f5e56a0684..f3371cbd05280 100644
--- a/Mathlib/Algebra/Group/Hom/Instances.lean
+++ b/Mathlib/Algebra/Group/Hom/Instances.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Kevin Buzzard, Scott Morrison, Johan Commelin, Chris Hughes,
+Authors: Patrick Massot, Kevin Buzzard, Kim Morrison, Johan Commelin, Chris Hughes,
Johannes Hölzl, Yury Kudryashov
-/
import Mathlib.Algebra.Group.Hom.Basic
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 07ef939bb18eb..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
@@ -131,13 +131,13 @@ instance instMonoid [Monoid α] : Monoid αᵐᵒᵖ where
@[to_additive]
instance instLeftCancelMonoid [RightCancelMonoid α] : LeftCancelMonoid αᵐᵒᵖ where
- toLeftCancelSemigroup := instLeftCancelSemigroup
- __ := instMonoid
+ toMonoid := instMonoid
+ __ := instLeftCancelSemigroup
@[to_additive]
instance instRightCancelMonoid [LeftCancelMonoid α] : RightCancelMonoid αᵐᵒᵖ where
- toRightCancelSemigroup := instRightCancelSemigroup
- __ := instMonoid
+ toMonoid := instMonoid
+ __ := instRightCancelSemigroup
@[to_additive]
instance instCancelMonoid [CancelMonoid α] : CancelMonoid αᵐᵒᵖ where
@@ -151,8 +151,8 @@ instance instCommMonoid [CommMonoid α] : CommMonoid αᵐᵒᵖ where
@[to_additive]
instance instCancelCommMonoid [CancelCommMonoid α] : CancelCommMonoid αᵐᵒᵖ where
- toLeftCancelMonoid := instLeftCancelMonoid
- __ := instCommMonoid
+ toCommMonoid := instCommMonoid
+ __ := instLeftCancelMonoid
@[to_additive AddOpposite.instSubNegMonoid]
instance instDivInvMonoid [DivInvMonoid α] : DivInvMonoid αᵐᵒᵖ where
@@ -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 f3bc2c5b9eb5b..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} :=
@@ -38,6 +37,15 @@ theorem Set.preimage_one {α β : Type*} [One β] (s : Set β) [Decidable ((1 :
(1 : α → β) ⁻¹' s = if (1 : β) ∈ s then Set.univ else ∅ :=
Set.preimage_const 1 s
+namespace Pi
+
+variable {α β : Type*} [Preorder α] [Preorder β]
+
+@[to_additive] lemma one_mono [One β] : Monotone (1 : α → β) := monotone_const
+@[to_additive] lemma one_anti [One β] : Antitone (1 : α → β) := antitone_const
+
+end Pi
+
namespace MulHom
@[to_additive]
@@ -59,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`. -/
@@ -239,6 +247,15 @@ theorem Pi.mulSingle_div [∀ i, Group <| f i] (i : I) (x y : f i) :
mulSingle i (x / y) = mulSingle i x / mulSingle i y :=
(MonoidHom.mulSingle f i).map_div x y
+@[to_additive]
+theorem Pi.mulSingle_pow [∀ i, Monoid (f i)] (i : I) (x : f i) (n : ℕ) :
+ mulSingle i (x ^ n) = mulSingle i x ^ n :=
+ (MonoidHom.mulSingle f i).map_pow x n
+
+@[to_additive]
+theorem Pi.mulSingle_zpow [∀ i, Group (f i)] (i : I) (x : f i) (n : ℤ) :
+ mulSingle i (x ^ n) = mulSingle i x ^ n :=
+ (MonoidHom.mulSingle f i).map_zpow x n
/-- The injection into a pi group at different indices commutes.
@@ -319,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/Data/Finset/Pointwise/Basic.lean b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean
similarity index 77%
rename from Mathlib/Data/Finset/Pointwise/Basic.lean
rename to Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean
index 0ed2c95d8cb3c..1f5104d65643a 100644
--- a/Mathlib/Data/Finset/Pointwise/Basic.lean
+++ b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean
@@ -5,11 +5,11 @@ 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
import Mathlib.Data.Set.Pointwise.ListOfFn
+import Mathlib.Data.Set.Pointwise.SMul
/-!
# Pointwise operations of finsets
@@ -53,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
@@ -92,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
@@ -168,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
@@ -208,17 +217,18 @@ theorem card_inv_le : s⁻¹.card ≤ s.card :=
theorem inv_empty : (∅ : Finset α)⁻¹ = ∅ :=
image_empty _
-@[to_additive (attr := simp, aesop safe apply (rule_sets := [finsetNonempty]))]
+@[to_additive (attr := simp)]
theorem inv_nonempty_iff : s⁻¹.Nonempty ↔ s.Nonempty := image_nonempty
alias ⟨Nonempty.of_inv, Nonempty.inv⟩ := inv_nonempty_iff
attribute [to_additive] Nonempty.inv Nonempty.of_inv
+attribute [aesop safe apply (rule_sets := [finsetNonempty])] Nonempty.inv Nonempty.neg
@[to_additive (attr := simp)]
theorem inv_eq_empty : s⁻¹ = ∅ ↔ s = ∅ := image_eq_empty
-@[to_additive (attr := mono)]
+@[to_additive (attr := mono, gcongr)]
theorem inv_subset_inv (h : s ⊆ t) : s⁻¹ ⊆ t⁻¹ :=
image_subset_image h
@@ -253,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
@@ -269,6 +283,9 @@ theorem coe_inv (s : Finset α) : ↑s⁻¹ = (s : Set α)⁻¹ := coe_image.tra
@[to_additive (attr := simp)]
theorem card_inv (s : Finset α) : s⁻¹.card = s.card := card_image_of_injective _ inv_injective
+@[to_additive (attr := simp)]
+lemma dens_inv [Fintype α] (s : Finset α) : s⁻¹.dens = s.dens := by simp [dens]
+
@[to_additive (attr := simp)]
theorem preimage_inv (s : Finset α) : s.preimage (·⁻¹) inv_injective.injOn = s⁻¹ :=
coe_injective <| by rw [coe_preimage, Set.inv_preimage, coe_inv]
@@ -281,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 -/
@@ -339,11 +514,11 @@ theorem mul_empty (s : Finset α) : s * ∅ = ∅ :=
theorem mul_eq_empty : s * t = ∅ ↔ s = ∅ ∨ t = ∅ :=
image₂_eq_empty_iff
-@[to_additive (attr := simp, aesop safe apply (rule_sets := [finsetNonempty]))]
+@[to_additive (attr := simp)]
theorem mul_nonempty : (s * t).Nonempty ↔ s.Nonempty ∧ t.Nonempty :=
image₂_nonempty_iff
-@[to_additive]
+@[to_additive (attr := aesop safe apply (rule_sets := [finsetNonempty]))]
theorem Nonempty.mul : s.Nonempty → t.Nonempty → (s * t).Nonempty :=
Nonempty.image₂
@@ -355,19 +530,15 @@ 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} :=
image₂_singleton
-@[to_additive (attr := mono)]
+@[to_additive (attr := mono, gcongr)]
theorem mul_subset_mul : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ * t₁ ⊆ s₂ * t₂ :=
image₂_subset
@@ -414,12 +585,21 @@ theorem union_mul_inter_subset_union : (s₁ ∪ s₂) * (t₁ ∩ t₂) ⊆ s
`s'`, `t'` such that `s' ⊆ s`, `t' ⊆ t` and `u ⊆ s' + t'`."]
theorem subset_mul {s t : Set α} :
↑u ⊆ s * t → ∃ s' t' : Finset α, ↑s' ⊆ s ∧ ↑t' ⊆ t ∧ u ⊆ s' * t' :=
- subset_image₂
+ subset_set_image₂
@[to_additive]
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
@@ -523,11 +703,11 @@ theorem div_empty (s : Finset α) : s / ∅ = ∅ :=
theorem div_eq_empty : s / t = ∅ ↔ s = ∅ ∨ t = ∅ :=
image₂_eq_empty_iff
-@[to_additive (attr := simp, aesop safe apply (rule_sets := [finsetNonempty]))]
+@[to_additive (attr := simp)]
theorem div_nonempty : (s / t).Nonempty ↔ s.Nonempty ∧ t.Nonempty :=
image₂_nonempty_iff
-@[to_additive]
+@[to_additive (attr := aesop safe apply (rule_sets := [finsetNonempty]))]
theorem Nonempty.div : s.Nonempty → t.Nonempty → (s / t).Nonempty :=
Nonempty.image₂
@@ -547,13 +727,11 @@ 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
-@[to_additive (attr := mono)]
+@[to_additive (attr := mono, gcongr)]
theorem div_subset_div : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ / t₁ ⊆ s₂ / t₂ :=
image₂_subset
@@ -600,7 +778,7 @@ theorem union_div_inter_subset_union : (s₁ ∪ s₂) / (t₁ ∩ t₂) ⊆ s
`s'`, `t'` such that `s' ⊆ s`, `t' ⊆ t` and `u ⊆ s' - t'`."]
theorem subset_div {s t : Set α} :
↑u ⊆ s / t → ∃ s' t' : Finset α, ↑s' ⊆ s ∧ ↑t' ⊆ t ∧ u ⊆ s' / t' :=
- subset_image₂
+ subset_set_image₂
@[to_additive (attr := simp (default + 1))]
lemma sup_div_le [SemilatticeSup β] [OrderBot β] {s t : Finset α} {f : α → β} {a : β} :
@@ -804,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 _⟩
@@ -856,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 _ _)
@@ -895,6 +1083,18 @@ theorem isUnit_coe : IsUnit (s : Set α) ↔ IsUnit s := by
@[to_additive (attr := simp)]
lemma univ_div_univ [Fintype α] : (univ / univ : Finset α) = univ := by simp [div_eq_mul_inv]
+@[to_additive] lemma subset_div_left (ht : 1 ∈ t) : s ⊆ s / t := by
+ rw [div_eq_mul_inv]; exact subset_mul_left _ <| by simpa
+
+@[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. -/
@@ -903,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 α β]
@@ -987,12 +1136,12 @@ to
∃ a, s = {a} ∧ IsUnit a -/
-- @[simp]
theorem isUnit_iff_singleton : IsUnit s ↔ ∃ a, s = {a} := by
- simp only [isUnit_iff, Group.isUnit, and_true_iff]
+ simp only [isUnit_iff, Group.isUnit, and_true]
@[simp]
theorem isUnit_iff_singleton_aux {α} [Group α] {s : Finset α} :
(∃ a, s = {a} ∧ IsUnit a) ↔ ∃ a, s = {a} := by
- simp only [Group.isUnit, and_true_iff]
+ simp only [Group.isUnit, and_true]
@[to_additive (attr := simp)]
theorem image_mul_left :
@@ -1017,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 :
@@ -1067,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, aesop safe apply (rule_sets := [finsetNonempty]))]
-theorem smul_nonempty_iff : (s • t).Nonempty ↔ s.Nonempty ∧ t.Nonempty :=
- image₂_nonempty_iff
-
-@[to_additive]
-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)]
-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_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}`. -/
@@ -1238,10 +1245,11 @@ theorem vsub_empty (s : Finset β) : s -ᵥ (∅ : Finset β) = ∅ :=
theorem vsub_eq_empty : s -ᵥ t = ∅ ↔ s = ∅ ∨ t = ∅ :=
image₂_eq_empty_iff
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem vsub_nonempty : (s -ᵥ t : Finset α).Nonempty ↔ s.Nonempty ∧ t.Nonempty :=
image₂_nonempty_iff
+@[aesop safe apply (rule_sets := [finsetNonempty])]
theorem Nonempty.vsub : s.Nonempty → t.Nonempty → (s -ᵥ t : Finset α).Nonempty :=
Nonempty.image₂
@@ -1258,11 +1266,10 @@ 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
-@[mono]
+@[mono, gcongr]
theorem vsub_subset_vsub : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ -ᵥ t₁ ⊆ s₂ -ᵥ t₂ :=
image₂_subset
@@ -1297,98 +1304,10 @@ end
finsets `s'`, `t'` such that `s' ⊆ s`, `t' ⊆ t` and `u ⊆ s' -ᵥ t'`. -/
theorem subset_vsub {s t : Set β} :
↑u ⊆ s -ᵥ t → ∃ s' t' : Finset β, ↑s' ⊆ s ∧ ↑t' ⊆ t ∧ u ⊆ s' -ᵥ t' :=
- subset_image₂
+ subset_set_image₂
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, aesop safe apply (rule_sets := [finsetNonempty]))]
-theorem smul_finset_nonempty : (a • s).Nonempty ↔ s.Nonempty :=
- image_nonempty
-
-@[to_additive]
-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)]
-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]
-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 γ]
@@ -1458,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
@@ -1569,6 +1446,17 @@ theorem singleton_mul_inter : {a} * (s ∩ t) = {a} * s ∩ ({a} * t) :=
theorem card_le_card_mul_left {s : Finset α} (hs : s.Nonempty) : t.card ≤ (s * t).card :=
card_le_card_image₂_left _ hs mul_right_injective
+/--
+The size of `s * s` is at least the size of `s`, version with left-cancellative multiplication.
+See `card_le_card_mul_self'` for the version with right-cancellative multiplication.
+-/
+@[to_additive
+"The size of `s + s` is at least the size of `s`, version with left-cancellative addition.
+See `card_le_card_add_self'` for the version with right-cancellative addition."
+]
+theorem card_le_card_mul_self {s : Finset α} : s.card ≤ (s * s).card := by
+ cases s.eq_empty_or_nonempty <;> simp [card_le_card_mul_left, *]
+
end IsLeftCancelMul
section
@@ -1587,8 +1475,40 @@ theorem inter_mul_singleton : s ∩ t * {a} = s * {a} ∩ (t * {a}) :=
theorem card_le_card_mul_right {t : Finset α} (ht : t.Nonempty) : s.card ≤ (s * t).card :=
card_le_card_image₂_right _ ht mul_left_injective
+/--
+The size of `s * s` is at least the size of `s`, version with right-cancellative multiplication.
+See `card_le_card_mul_self` for the version with left-cancellative multiplication.
+-/
+@[to_additive
+"The size of `s + s` is at least the size of `s`, version with right-cancellative addition.
+See `card_le_card_add_self` for the version with left-cancellative addition."
+]
+theorem card_le_card_mul_self' {s : Finset α} : s.card ≤ (s * s).card := by
+ cases s.eq_empty_or_nonempty <;> simp [card_le_card_mul_right, *]
+
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 α}
@@ -1598,6 +1518,9 @@ variable [Group α] [DecidableEq α] {s t : Finset α}
@[to_additive] lemma card_le_card_div_right (ht : t.Nonempty) : s.card ≤ (s / t).card :=
card_le_card_image₂_right _ ht fun _ ↦ div_left_injective
+@[to_additive] lemma card_le_card_div_self : s.card ≤ (s / s).card := by
+ cases s.eq_empty_or_nonempty <;> simp [card_le_card_div_left, *]
+
end Group
open Pointwise
@@ -1671,6 +1594,9 @@ theorem smul_univ [Fintype β] {s : Finset α} (hs : s.Nonempty) : s • (univ :
theorem card_smul_finset (a : α) (s : Finset β) : (a • s).card = s.card :=
card_image_of_injective _ <| MulAction.injective _
+@[to_additive (attr := simp)]
+lemma dens_smul_finset [Fintype β] (a : α) (s : Finset β) : (a • s).dens = s.dens := by simp [dens]
+
/-- If the left cosets of `t` by elements of `s` are disjoint (but not necessarily distinct!), then
the size of `t` divides the size of `s • t`. -/
@[to_additive "If the left cosets of `t` by elements of `s` are disjoint (but not necessarily
@@ -1708,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 ι]
@@ -1945,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)] :
@@ -1997,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/Data/Finset/Pointwise/Interval.lean b/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean
similarity index 92%
rename from Mathlib/Data/Finset/Pointwise/Interval.lean
rename to Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean
index 9178e9e993251..479121a3d4a1b 100644
--- a/Mathlib/Data/Finset/Pointwise/Interval.lean
+++ b/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean
@@ -3,7 +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 Mathlib.Data.Finset.Pointwise.Basic
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
import Mathlib.Data.Set.Pointwise.Interval
import Mathlib.Order.Interval.Finset.Defs
@@ -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.lean b/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean
similarity index 64%
rename from Mathlib/Algebra/Group/Pointwise/Set.lean
rename to Mathlib/Algebra/Group/Pointwise/Set/Basic.lean
index 6106467593c54..e62af9d0fc374 100644
--- a/Mathlib/Algebra/Group/Pointwise/Set.lean
+++ b/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean
@@ -22,6 +22,11 @@ For sets `s` and `t` and scalar `a`:
* `-s`: Negation, set of all `-x` where `x ∈ s`.
* `s / t`: Division, set of all `x / y` where `x ∈ s` and `y ∈ t`.
* `s - t`: Subtraction, set of all `x - y` where `x ∈ s` and `y ∈ t`.
+* `s • t`: Scalar multiplication, set of all `x • y` where `x ∈ s` and `y ∈ t`.
+* `s +ᵥ t`: Scalar addition, set of all `x +ᵥ y` where `x ∈ s` and `y ∈ t`.
+* `s -ᵥ t`: Scalar subtraction, set of all `x -ᵥ y` where `x ∈ s` and `y ∈ t`.
+* `a • s`: Scaling, set of all `a • x` where `x ∈ s`.
+* `a +ᵥ s`: Translation, set of all `a +ᵥ x` where `x ∈ s`.
For `α` a semigroup/monoid, `Set α` is a semigroup/monoid.
As an unfortunate side effect, this means that `n • s`, where `n : ℕ`, is ambiguous between
@@ -62,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*}
@@ -84,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
@@ -125,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 -/
@@ -176,10 +184,18 @@ theorem union_inv : (s ∪ t)⁻¹ = s⁻¹ ∪ t⁻¹ :=
theorem iInter_inv (s : ι → Set α) : (⋂ i, s i)⁻¹ = ⋂ i, (s i)⁻¹ :=
preimage_iInter
+@[to_additive (attr := simp)]
+theorem sInter_inv (S : Set (Set α)) : (⋂₀ S)⁻¹ = ⋂ s ∈ S, s⁻¹ :=
+ preimage_sInter
+
@[to_additive (attr := simp)]
theorem iUnion_inv (s : ι → Set α) : (⋃ i, s i)⁻¹ = ⋃ i, (s i)⁻¹ :=
preimage_iUnion
+@[to_additive (attr := simp)]
+theorem sUnion_inv (S : Set (Set α)) : (⋃₀ S)⁻¹ = ⋃ s ∈ S, s⁻¹ :=
+ preimage_sUnion
+
@[to_additive (attr := simp)]
theorem compl_inv : sᶜ⁻¹ = s⁻¹ᶜ :=
preimage_compl
@@ -231,7 +247,7 @@ theorem inv_insert (a : α) (s : Set α) : (insert a s)⁻¹ = insert a⁻¹ s
@[to_additive]
theorem inv_range {ι : Sort*} {f : ι → α} : (range f)⁻¹ = range fun i => (f i)⁻¹ := by
rw [← image_inv]
- exact (range_comp _ _).symm
+ exact (range_comp ..).symm
open MulOpposite
@@ -314,12 +330,11 @@ 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
-@[to_additive (attr := mono)]
+@[to_additive (attr := mono, gcongr)]
theorem mul_subset_mul : s₁ ⊆ t₁ → s₂ ⊆ t₂ → s₁ * s₂ ⊆ t₁ * t₂ :=
image2_subset
@@ -369,47 +384,63 @@ theorem iUnion_mul_right_image : ⋃ a ∈ t, (· * a) '' s = s * t :=
@[to_additive]
theorem iUnion_mul (s : ι → Set α) (t : Set α) : (⋃ i, s i) * t = ⋃ i, s i * t :=
- image2_iUnion_left _ _ _
+ image2_iUnion_left ..
@[to_additive]
theorem mul_iUnion (s : Set α) (t : ι → Set α) : (s * ⋃ i, t i) = ⋃ i, s * t i :=
- image2_iUnion_right _ _ _
+ image2_iUnion_right ..
+
+@[to_additive]
+theorem sUnion_mul (S : Set (Set α)) (t : Set α) : ⋃₀ S * t = ⋃ s ∈ S, s * t :=
+ image2_sUnion_left ..
+
+@[to_additive]
+theorem mul_sUnion (s : Set α) (T : Set (Set α)) : s * ⋃₀ T = ⋃ t ∈ T, s * t :=
+ image2_sUnion_right ..
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[to_additive]
theorem iUnion₂_mul (s : ∀ i, κ i → Set α) (t : Set α) :
(⋃ (i) (j), s i j) * t = ⋃ (i) (j), s i j * t :=
- image2_iUnion₂_left _ _ _
+ image2_iUnion₂_left ..
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[to_additive]
theorem mul_iUnion₂ (s : Set α) (t : ∀ i, κ i → Set α) :
(s * ⋃ (i) (j), t i j) = ⋃ (i) (j), s * t i j :=
- image2_iUnion₂_right _ _ _
+ image2_iUnion₂_right ..
@[to_additive]
theorem iInter_mul_subset (s : ι → Set α) (t : Set α) : (⋂ i, s i) * t ⊆ ⋂ i, s i * t :=
- Set.image2_iInter_subset_left _ _ _
+ Set.image2_iInter_subset_left ..
@[to_additive]
theorem mul_iInter_subset (s : Set α) (t : ι → Set α) : (s * ⋂ i, t i) ⊆ ⋂ i, s * t i :=
- image2_iInter_subset_right _ _ _
+ image2_iInter_subset_right ..
+
+@[to_additive]
+lemma mul_sInter_subset (s : Set α) (T : Set (Set α)) :
+ s * ⋂₀ T ⊆ ⋂ t ∈ T, s * t := image2_sInter_right_subset s T (fun a b => a * b)
+
+@[to_additive]
+lemma sInter_mul_subset (S : Set (Set α)) (t : Set α) :
+ ⋂₀ S * t ⊆ ⋂ s ∈ S, s * t := image2_sInter_left_subset S t (fun a b => a * b)
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[to_additive]
theorem iInter₂_mul_subset (s : ∀ i, κ i → Set α) (t : Set α) :
(⋂ (i) (j), s i j) * t ⊆ ⋂ (i) (j), s i j * t :=
- image2_iInter₂_subset_left _ _ _
+ image2_iInter₂_subset_left ..
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[to_additive]
theorem mul_iInter₂_subset (s : Set α) (t : ∀ i, κ i → Set α) :
(s * ⋂ (i) (j), t i j) ⊆ ⋂ (i) (j), s * t i j :=
- image2_iInter₂_subset_right _ _ _
+ image2_iInter₂_subset_right ..
/-- The singleton operation as a `MulHom`. -/
@[to_additive "The singleton operation as an `AddHom`."]
@@ -502,12 +533,11 @@ 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
-@[to_additive (attr := mono)]
+@[to_additive (attr := mono, gcongr)]
theorem div_subset_div : s₁ ⊆ t₁ → s₂ ⊆ t₂ → s₁ / s₂ ⊆ t₁ / t₂ :=
image2_subset
@@ -557,50 +587,390 @@ theorem iUnion_div_right_image : ⋃ a ∈ t, (· / a) '' s = s / t :=
@[to_additive]
theorem iUnion_div (s : ι → Set α) (t : Set α) : (⋃ i, s i) / t = ⋃ i, s i / t :=
- image2_iUnion_left _ _ _
+ image2_iUnion_left ..
@[to_additive]
theorem div_iUnion (s : Set α) (t : ι → Set α) : (s / ⋃ i, t i) = ⋃ i, s / t i :=
- image2_iUnion_right _ _ _
+ image2_iUnion_right ..
+
+@[to_additive]
+theorem sUnion_div (S : Set (Set α)) (t : Set α) : ⋃₀ S / t = ⋃ s ∈ S, s / t :=
+ image2_sUnion_left ..
+
+@[to_additive]
+theorem div_sUnion (s : Set α) (T : Set (Set α)) : s / ⋃₀ T = ⋃ t ∈ T, s / t :=
+ image2_sUnion_right ..
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[to_additive]
theorem iUnion₂_div (s : ∀ i, κ i → Set α) (t : Set α) :
(⋃ (i) (j), s i j) / t = ⋃ (i) (j), s i j / t :=
- image2_iUnion₂_left _ _ _
+ image2_iUnion₂_left ..
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[to_additive]
theorem div_iUnion₂ (s : Set α) (t : ∀ i, κ i → Set α) :
(s / ⋃ (i) (j), t i j) = ⋃ (i) (j), s / t i j :=
- image2_iUnion₂_right _ _ _
+ image2_iUnion₂_right ..
@[to_additive]
theorem iInter_div_subset (s : ι → Set α) (t : Set α) : (⋂ i, s i) / t ⊆ ⋂ i, s i / t :=
- image2_iInter_subset_left _ _ _
+ image2_iInter_subset_left ..
@[to_additive]
theorem div_iInter_subset (s : Set α) (t : ι → Set α) : (s / ⋂ i, t i) ⊆ ⋂ i, s / t i :=
- image2_iInter_subset_right _ _ _
+ image2_iInter_subset_right ..
+
+@[to_additive]
+theorem sInter_div_subset (S : Set (Set α)) (t : Set α) : ⋂₀ S / t ⊆ ⋂ s ∈ S, s / t :=
+ image2_sInter_subset_left ..
+
+@[to_additive]
+theorem div_sInter_subset (s : Set α) (T : Set (Set α)) : s / ⋂₀ T ⊆ ⋂ t ∈ T, s / t :=
+ image2_sInter_subset_right ..
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[to_additive]
theorem iInter₂_div_subset (s : ∀ i, κ i → Set α) (t : Set α) :
(⋂ (i) (j), s i j) / t ⊆ ⋂ (i) (j), s i j / t :=
- image2_iInter₂_subset_left _ _ _
+ image2_iInter₂_subset_left ..
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[to_additive]
theorem div_iInter₂_subset (s : Set α) (t : ∀ i, κ i → Set α) :
(s / ⋂ (i) (j), t i j) ⊆ ⋂ (i) (j), s / t i j :=
- image2_iInter₂_subset_right _ _ _
+ image2_iInter₂_subset_right ..
end Div
+/-! ### Translation/scaling of sets -/
+
+section SMul
+
+/-- The dilation of set `x • s` is defined as `{x • y | y ∈ s}` in locale `Pointwise`. -/
+@[to_additive
+"The translation of set `x +ᵥ s` is defined as `{x +ᵥ y | y ∈ s}` in locale `Pointwise`."]
+protected def smulSet [SMul α β] : SMul α (Set β) where smul a := image (a • ·)
+
+/-- The pointwise scalar multiplication of sets `s • t` is defined as `{x • y | x ∈ s, y ∈ t}` in
+locale `Pointwise`. -/
+@[to_additive
+"The pointwise scalar addition of sets `s +ᵥ t` is defined as `{x +ᵥ y | x ∈ s, y ∈ t}` in locale
+`Pointwise`."]
+protected def smul [SMul α β] : SMul (Set α) (Set β) where smul := image2 (· • ·)
+
+scoped[Pointwise] attribute [instance] Set.smulSet Set.smul
+scoped[Pointwise] attribute [instance] Set.vaddSet Set.vadd
+
+section SMul
+variable {ι : Sort*} {κ : ι → Sort*} [SMul α β] {s s₁ s₂ : Set α} {t t₁ t₂ u : Set β} {a : α}
+ {b : β}
+
+@[to_additive (attr := simp)] lemma image2_smul : image2 SMul.smul s t = s • t := rfl
+
+@[to_additive vadd_image_prod]
+lemma image_smul_prod : (fun x : α × β ↦ x.fst • x.snd) '' s ×ˢ t = s • t := image_prod _
+
+@[to_additive] lemma mem_smul : b ∈ s • t ↔ ∃ x ∈ s, ∃ y ∈ t, x • y = b := Iff.rfl
+
+@[to_additive] lemma smul_mem_smul : a ∈ s → b ∈ t → a • b ∈ s • t := mem_image2_of_mem
+
+@[to_additive (attr := simp)] lemma empty_smul : (∅ : Set α) • t = ∅ := image2_empty_left
+@[to_additive (attr := simp)] lemma smul_empty : s • (∅ : Set β) = ∅ := image2_empty_right
+
+@[to_additive (attr := simp)] lemma smul_eq_empty : s • t = ∅ ↔ s = ∅ ∨ t = ∅ := image2_eq_empty_iff
+
+@[to_additive (attr := simp)]
+lemma smul_nonempty : (s • t).Nonempty ↔ s.Nonempty ∧ t.Nonempty := image2_nonempty_iff
+
+@[to_additive] lemma Nonempty.smul : s.Nonempty → t.Nonempty → (s • t).Nonempty := .image2
+@[to_additive] lemma Nonempty.of_smul_left : (s • t).Nonempty → s.Nonempty := .of_image2_left
+@[to_additive] lemma Nonempty.of_smul_right : (s • t).Nonempty → t.Nonempty := .of_image2_right
+
+@[to_additive (attr := simp low+1)]
+lemma smul_singleton : s • ({b} : Set β) = (· • b) '' s := image2_singleton_right
+
+@[to_additive (attr := simp low+1)]
+lemma singleton_smul : ({a} : Set α) • t = a • t := image2_singleton_left
+
+@[to_additive (attr := simp high)]
+lemma singleton_smul_singleton : ({a} : Set α) • ({b} : Set β) = {a • b} := image2_singleton
+
+@[to_additive (attr := mono, gcongr)]
+lemma smul_subset_smul : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ • t₁ ⊆ s₂ • t₂ := image2_subset
+
+@[to_additive] lemma smul_subset_smul_left : t₁ ⊆ t₂ → s • t₁ ⊆ s • t₂ := image2_subset_left
+@[to_additive] lemma smul_subset_smul_right : s₁ ⊆ s₂ → s₁ • t ⊆ s₂ • t := image2_subset_right
+
+@[to_additive] lemma smul_subset_iff : s • t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a • b ∈ u := image2_subset_iff
+
+@[to_additive] lemma union_smul : (s₁ ∪ s₂) • t = s₁ • t ∪ s₂ • t := image2_union_left
+@[to_additive] lemma smul_union : s • (t₁ ∪ t₂) = s • t₁ ∪ s • t₂ := image2_union_right
+
+@[to_additive]
+lemma inter_smul_subset : (s₁ ∩ s₂) • t ⊆ s₁ • t ∩ s₂ • t := image2_inter_subset_left
+
+@[to_additive]
+lemma smul_inter_subset : s • (t₁ ∩ t₂) ⊆ s • t₁ ∩ s • t₂ := image2_inter_subset_right
+
+@[to_additive]
+lemma inter_smul_union_subset_union : (s₁ ∩ s₂) • (t₁ ∪ t₂) ⊆ s₁ • t₁ ∪ s₂ • t₂ :=
+ image2_inter_union_subset_union
+
+@[to_additive]
+lemma union_smul_inter_subset_union : (s₁ ∪ s₂) • (t₁ ∩ t₂) ⊆ s₁ • t₁ ∪ s₂ • t₂ :=
+ image2_union_inter_subset_union
+
+@[to_additive] lemma iUnion_smul_left_image : ⋃ a ∈ s, a • t = s • t := iUnion_image_left _
+
+@[to_additive]
+lemma iUnion_smul_right_image : ⋃ a ∈ t, (· • a) '' s = s • t := iUnion_image_right _
+
+@[to_additive]
+lemma iUnion_smul (s : ι → Set α) (t : Set β) : (⋃ i, s i) • t = ⋃ i, s i • t :=
+ image2_iUnion_left ..
+
+@[to_additive]
+lemma smul_iUnion (s : Set α) (t : ι → Set β) : (s • ⋃ i, t i) = ⋃ i, s • t i :=
+ image2_iUnion_right ..
+
+@[to_additive]
+lemma sUnion_smul (S : Set (Set α)) (t : Set β) : ⋃₀ S • t = ⋃ s ∈ S, s • t :=
+ image2_sUnion_left ..
+
+@[to_additive]
+lemma smul_sUnion (s : Set α) (T : Set (Set β)) : s • ⋃₀ T = ⋃ t ∈ T, s • t :=
+ image2_sUnion_right ..
+
+@[to_additive]
+lemma iUnion₂_smul (s : ∀ i, κ i → Set α) (t : Set β) :
+ (⋃ i, ⋃ j, s i j) • t = ⋃ i, ⋃ j, s i j • t := image2_iUnion₂_left ..
+
+@[to_additive]
+lemma smul_iUnion₂ (s : Set α) (t : ∀ i, κ i → Set β) :
+ (s • ⋃ i, ⋃ j, t i j) = ⋃ i, ⋃ j, s • t i j := image2_iUnion₂_right ..
+
+@[to_additive]
+lemma iInter_smul_subset (s : ι → Set α) (t : Set β) : (⋂ i, s i) • t ⊆ ⋂ i, s i • t :=
+ image2_iInter_subset_left ..
+
+@[to_additive]
+lemma smul_iInter_subset (s : Set α) (t : ι → Set β) : (s • ⋂ i, t i) ⊆ ⋂ i, s • t i :=
+ image2_iInter_subset_right ..
+
+@[to_additive]
+lemma sInter_smul_subset (S : Set (Set α)) (t : Set β) : ⋂₀ S • t ⊆ ⋂ s ∈ S, s • t :=
+ image2_sInter_left_subset S t (fun a x => a • x)
+
+@[to_additive]
+lemma smul_sInter_subset (s : Set α) (T : Set (Set β)) : s • ⋂₀ T ⊆ ⋂ t ∈ T, s • t :=
+ image2_sInter_right_subset s T (fun a x => a • x)
+
+@[to_additive]
+lemma iInter₂_smul_subset (s : ∀ i, κ i → Set α) (t : Set β) :
+ (⋂ i, ⋂ j, s i j) • t ⊆ ⋂ i, ⋂ j, s i j • t := image2_iInter₂_subset_left ..
+
+@[to_additive]
+lemma smul_iInter₂_subset (s : Set α) (t : ∀ i, κ i → Set β) :
+ (s • ⋂ i, ⋂ j, t i j) ⊆ ⋂ i, ⋂ j, s • t i j := image2_iInter₂_subset_right ..
+
+@[to_additive]
+lemma smul_set_subset_smul {s : Set α} : a ∈ s → a • t ⊆ s • t := image_subset_image2_right
+
+@[to_additive (attr := simp)]
+lemma iUnion_smul_set (s : Set α) (t : Set β) : ⋃ a ∈ s, a • t = s • t := iUnion_image_left _
+
+end SMul
+
+section SMulSet
+variable {ι : Sort*} {κ : ι → Sort*} [SMul α β] {s t t₁ t₂ : Set β} {a : α} {b : β} {x y : β}
+
+@[to_additive] lemma image_smul : (fun x ↦ a • x) '' t = a • t := rfl
+
+scoped[Pointwise] attribute [simp] Set.image_smul Set.image_vadd
+
+@[to_additive] lemma mem_smul_set : x ∈ a • t ↔ ∃ y, y ∈ t ∧ a • y = x := Iff.rfl
+
+@[to_additive] lemma smul_mem_smul_set : b ∈ s → a • b ∈ a • s := mem_image_of_mem _
+
+@[to_additive (attr := simp)] lemma smul_set_empty : a • (∅ : Set β) = ∅ := image_empty _
+@[to_additive (attr := simp)] lemma smul_set_eq_empty : a • s = ∅ ↔ s = ∅ := image_eq_empty
+
+@[to_additive (attr := simp)]
+lemma smul_set_nonempty : (a • s).Nonempty ↔ s.Nonempty := image_nonempty
+
+@[to_additive (attr := simp)]
+lemma smul_set_singleton : a • ({b} : Set β) = {a • b} := image_singleton
+
+@[to_additive (attr := gcongr)] lemma smul_set_mono : s ⊆ t → a • s ⊆ a • t := image_subset _
+
+@[to_additive]
+lemma smul_set_subset_iff : a • s ⊆ t ↔ ∀ ⦃b⦄, b ∈ s → a • b ∈ t :=
+ image_subset_iff
+
+@[to_additive]
+lemma smul_set_union : a • (t₁ ∪ t₂) = a • t₁ ∪ a • t₂ :=
+ image_union ..
+
+@[to_additive]
+lemma smul_set_insert (a : α) (b : β) (s : Set β) : a • insert b s = insert (a • b) (a • s) :=
+ image_insert_eq ..
+
+@[to_additive]
+lemma smul_set_inter_subset : a • (t₁ ∩ t₂) ⊆ a • t₁ ∩ a • t₂ :=
+ image_inter_subset ..
+
+@[to_additive]
+lemma smul_set_iUnion (a : α) (s : ι → Set β) : a • ⋃ i, s i = ⋃ i, a • s i :=
+ image_iUnion
+
+@[to_additive]
+lemma smul_set_iUnion₂ (a : α) (s : ∀ i, κ i → Set β) :
+ a • ⋃ i, ⋃ j, s i j = ⋃ i, ⋃ j, a • s i j := image_iUnion₂ ..
+
+@[to_additive]
+lemma smul_set_sUnion (a : α) (S : Set (Set β)) : a • ⋃₀ S = ⋃ s ∈ S, a • s := by
+ rw [sUnion_eq_biUnion, smul_set_iUnion₂]
+
+@[to_additive]
+lemma smul_set_iInter_subset (a : α) (t : ι → Set β) : a • ⋂ i, t i ⊆ ⋂ i, a • t i :=
+ image_iInter_subset ..
+
+@[to_additive]
+lemma smul_set_sInter_subset (a : α) (S : Set (Set β)) :
+ a • ⋂₀ S ⊆ ⋂ s ∈ S, a • s := image_sInter_subset ..
+
+@[to_additive]
+lemma smul_set_iInter₂_subset (a : α) (t : ∀ i, κ i → Set β) :
+ a • ⋂ i, ⋂ j, t i j ⊆ ⋂ i, ⋂ j, a • t i j := image_iInter₂_subset ..
+
+@[to_additive] lemma Nonempty.smul_set : s.Nonempty → (a • s).Nonempty := Nonempty.image _
+
+end SMulSet
+
+variable {s s₁ s₂ : Set α} {t t₁ t₂ : Set β} {a : α} {b : β}
+
+@[to_additive]
+lemma range_smul_range {ι κ : Type*} [SMul α β] (b : ι → α) (c : κ → β) :
+ range b • range c = range fun p : ι × κ ↦ b p.1 • c p.2 :=
+ image2_range ..
+
+@[to_additive]
+lemma smul_set_range [SMul α β] {ι : Sort*} (a : α) (f : ι → β) :
+ a • range f = range fun i ↦ a • f i :=
+ (range_comp ..).symm
+
+@[to_additive] lemma range_smul [SMul α β] {ι : Sort*} (a : α) (f : ι → β) :
+ range (fun i ↦ a • f i) = a • range f := (smul_set_range ..).symm
+
+end SMul
+
+section VSub
+variable {ι : Sort*} {κ : ι → Sort*} [VSub α β] {s s₁ s₂ t t₁ t₂ : Set β} {u : Set α} {a : α}
+ {b c : β}
+
+instance vsub : VSub (Set α) (Set β) where vsub := image2 (· -ᵥ ·)
+
+@[simp] lemma image2_vsub : (image2 VSub.vsub s t : Set α) = s -ᵥ t := rfl
+
+lemma image_vsub_prod : (fun x : β × β ↦ x.fst -ᵥ x.snd) '' s ×ˢ t = s -ᵥ t := image_prod _
+
+lemma mem_vsub : a ∈ s -ᵥ t ↔ ∃ x ∈ s, ∃ y ∈ t, x -ᵥ y = a := Iff.rfl
+
+lemma vsub_mem_vsub (hb : b ∈ s) (hc : c ∈ t) : b -ᵥ c ∈ s -ᵥ t := mem_image2_of_mem hb hc
+
+@[simp] lemma empty_vsub (t : Set β) : ∅ -ᵥ t = ∅ := image2_empty_left
+@[simp] lemma vsub_empty (s : Set β) : s -ᵥ ∅ = ∅ := image2_empty_right
+
+@[simp] lemma vsub_eq_empty : s -ᵥ t = ∅ ↔ s = ∅ ∨ t = ∅ := image2_eq_empty_iff
+
+@[simp]
+lemma vsub_nonempty : (s -ᵥ t : Set α).Nonempty ↔ s.Nonempty ∧ t.Nonempty := image2_nonempty_iff
+
+lemma Nonempty.vsub : s.Nonempty → t.Nonempty → (s -ᵥ t : Set α).Nonempty := .image2
+lemma Nonempty.of_vsub_left : (s -ᵥ t : Set α).Nonempty → s.Nonempty := .of_image2_left
+lemma Nonempty.of_vsub_right : (s -ᵥ t : Set α).Nonempty → t.Nonempty := .of_image2_right
+
+@[simp low+1]
+lemma vsub_singleton (s : Set β) (b : β) : s -ᵥ {b} = (· -ᵥ b) '' s := image2_singleton_right
+
+@[simp low+1]
+lemma singleton_vsub (t : Set β) (b : β) : {b} -ᵥ t = (b -ᵥ ·) '' t := image2_singleton_left
+
+@[simp high] lemma singleton_vsub_singleton : ({b} : Set β) -ᵥ {c} = {b -ᵥ c} := image2_singleton
+
+@[mono] lemma vsub_subset_vsub : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ -ᵥ t₁ ⊆ s₂ -ᵥ t₂ := image2_subset
+
+lemma vsub_subset_vsub_left : t₁ ⊆ t₂ → s -ᵥ t₁ ⊆ s -ᵥ t₂ := image2_subset_left
+lemma vsub_subset_vsub_right : s₁ ⊆ s₂ → s₁ -ᵥ t ⊆ s₂ -ᵥ t := image2_subset_right
+
+lemma vsub_subset_iff : s -ᵥ t ⊆ u ↔ ∀ x ∈ s, ∀ y ∈ t, x -ᵥ y ∈ u := image2_subset_iff
+
+lemma vsub_self_mono (h : s ⊆ t) : s -ᵥ s ⊆ t -ᵥ t := vsub_subset_vsub h h
+
+lemma union_vsub : s₁ ∪ s₂ -ᵥ t = s₁ -ᵥ t ∪ (s₂ -ᵥ t) := image2_union_left
+lemma vsub_union : s -ᵥ (t₁ ∪ t₂) = s -ᵥ t₁ ∪ (s -ᵥ t₂) := image2_union_right
+
+lemma inter_vsub_subset : s₁ ∩ s₂ -ᵥ t ⊆ (s₁ -ᵥ t) ∩ (s₂ -ᵥ t) := image2_inter_subset_left
+lemma vsub_inter_subset : s -ᵥ t₁ ∩ t₂ ⊆ (s -ᵥ t₁) ∩ (s -ᵥ t₂) := image2_inter_subset_right
+
+lemma inter_vsub_union_subset_union : s₁ ∩ s₂ -ᵥ (t₁ ∪ t₂) ⊆ s₁ -ᵥ t₁ ∪ (s₂ -ᵥ t₂) :=
+ image2_inter_union_subset_union
+
+lemma union_vsub_inter_subset_union : s₁ ∪ s₂ -ᵥ t₁ ∩ t₂ ⊆ s₁ -ᵥ t₁ ∪ (s₂ -ᵥ t₂) :=
+ image2_union_inter_subset_union
+
+lemma iUnion_vsub_left_image : ⋃ a ∈ s, (a -ᵥ ·) '' t = s -ᵥ t := iUnion_image_left _
+lemma iUnion_vsub_right_image : ⋃ a ∈ t, (· -ᵥ a) '' s = s -ᵥ t := iUnion_image_right _
+
+lemma iUnion_vsub (s : ι → Set β) (t : Set β) : (⋃ i, s i) -ᵥ t = ⋃ i, s i -ᵥ t :=
+ image2_iUnion_left ..
+
+lemma vsub_iUnion (s : Set β) (t : ι → Set β) : (s -ᵥ ⋃ i, t i) = ⋃ i, s -ᵥ t i :=
+ image2_iUnion_right ..
+
+lemma sUnion_vsub (S : Set (Set β)) (t : Set β) : ⋃₀ S -ᵥ t = ⋃ s ∈ S, s -ᵥ t :=
+ image2_sUnion_left ..
+
+lemma vsub_sUnion (s : Set β) (T : Set (Set β)) : s -ᵥ ⋃₀ T = ⋃ t ∈ T, s -ᵥ t :=
+ image2_sUnion_right ..
+
+lemma iUnion₂_vsub (s : ∀ i, κ i → Set β) (t : Set β) :
+ (⋃ i, ⋃ j, s i j) -ᵥ t = ⋃ i, ⋃ j, s i j -ᵥ t := image2_iUnion₂_left ..
+
+lemma vsub_iUnion₂ (s : Set β) (t : ∀ i, κ i → Set β) :
+ (s -ᵥ ⋃ i, ⋃ j, t i j) = ⋃ i, ⋃ j, s -ᵥ t i j := image2_iUnion₂_right ..
+
+lemma iInter_vsub_subset (s : ι → Set β) (t : Set β) : (⋂ i, s i) -ᵥ t ⊆ ⋂ i, s i -ᵥ t :=
+ image2_iInter_subset_left ..
+
+lemma vsub_iInter_subset (s : Set β) (t : ι → Set β) : (s -ᵥ ⋂ i, t i) ⊆ ⋂ i, s -ᵥ t i :=
+ image2_iInter_subset_right ..
+
+lemma sInter_vsub_subset (S : Set (Set β)) (t : Set β) : ⋂₀ S -ᵥ t ⊆ ⋂ s ∈ S, s -ᵥ t :=
+ image2_sInter_subset_left ..
+
+lemma vsub_sInter_subset (s : Set β) (T : Set (Set β)) : s -ᵥ ⋂₀ T ⊆ ⋂ t ∈ T, s -ᵥ t :=
+ image2_sInter_subset_right ..
+
+lemma iInter₂_vsub_subset (s : ∀ i, κ i → Set β) (t : Set β) :
+ (⋂ i, ⋂ j, s i j) -ᵥ t ⊆ ⋂ i, ⋂ j, s i j -ᵥ t := image2_iInter₂_subset_left ..
+
+lemma vsub_iInter₂_subset (s : Set β) (t : ∀ i, κ i → Set β) :
+ s -ᵥ ⋂ i, ⋂ j, t i j ⊆ ⋂ i, ⋂ j, s -ᵥ t i j := image2_iInter₂_subset_right ..
+
+end VSub
+
+open Pointwise
+
+@[to_additive]
+lemma image_smul_comm [SMul α β] [SMul α γ] (f : β → γ) (a : α) (s : Set β) :
+ (∀ b, f (a • b) = a • f b) → f '' (a • s) = a • f '' s := image_comm
+
open Pointwise
/-- Repeated pointwise addition (not the same as pointwise repeated addition!) of a `Set`. See
@@ -729,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 _⟩
@@ -769,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
@@ -816,6 +1193,18 @@ theorem isUnit_iff : IsUnit s ↔ ∃ a, s = {a} ∧ IsUnit a := by
@[to_additive (attr := simp)]
lemma univ_div_univ : (univ / univ : Set α) = univ := by simp [div_eq_mul_inv]
+@[to_additive] lemma subset_div_left (ht : 1 ∈ t) : s ⊆ s / t := by
+ rw [div_eq_mul_inv]; exact subset_mul_left _ <| by simpa
+
+@[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. -/
@@ -825,6 +1214,8 @@ protected noncomputable def divisionCommMonoid [DivisionCommMonoid α] :
DivisionCommMonoid (Set α) :=
{ Set.divisionMonoid, Set.commSemigroup with }
+scoped[Pointwise] attribute [instance] Set.divisionCommMonoid Set.subtractionCommMonoid
+
section Group
variable [Group α] {s t : Set α} {a b : α}
@@ -855,7 +1246,7 @@ theorem isUnit_singleton (a : α) : IsUnit ({a} : Set α) :=
@[to_additive (attr := simp)]
theorem isUnit_iff_singleton : IsUnit s ↔ ∃ a, s = {a} := by
- simp only [isUnit_iff, Group.isUnit, and_true_iff]
+ simp only [isUnit_iff, Group.isUnit, and_true]
@[to_additive (attr := simp)]
theorem image_mul_left : (a * ·) '' t = (a⁻¹ * ·) ⁻¹' t := by
@@ -896,12 +1287,12 @@ theorem preimage_mul_right_one' : (· * b⁻¹) ⁻¹' 1 = {b} := by simp
@[to_additive (attr := simp)]
theorem mul_univ (hs : s.Nonempty) : s * (univ : Set α) = univ :=
let ⟨a, ha⟩ := hs
- eq_univ_of_forall fun b => ⟨a, ha, a⁻¹ * b, trivial, mul_inv_cancel_left _ _⟩
+ eq_univ_of_forall fun b => ⟨a, ha, a⁻¹ * b, trivial, mul_inv_cancel_left ..⟩
@[to_additive (attr := simp)]
theorem univ_mul (ht : t.Nonempty) : (univ : Set α) * t = univ :=
let ⟨a, ha⟩ := ht
- eq_univ_of_forall fun b => ⟨b * a⁻¹, trivial, a, ha, inv_mul_cancel_right _ _⟩
+ eq_univ_of_forall fun b => ⟨b * a⁻¹, trivial, a, ha, inv_mul_cancel_right ..⟩
end Group
@@ -918,12 +1309,12 @@ lemma mul_subset_range {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m)
rintro _ ⟨a, ha, b, hb, rfl⟩
obtain ⟨a, rfl⟩ := hs ha
obtain ⟨b, rfl⟩ := ht hb
- exact ⟨a * b, map_mul _ _ _⟩
+ exact ⟨a * b, map_mul ..⟩
@[to_additive]
theorem preimage_mul_preimage_subset {s t : Set β} : m ⁻¹' s * m ⁻¹' t ⊆ m ⁻¹' (s * t) := by
rintro _ ⟨_, _, _, _, rfl⟩
- exact ⟨_, ‹_›, _, ‹_›, (map_mul m _ _).symm⟩
+ exact ⟨_, ‹_›, _, ‹_›, (map_mul m ..).symm⟩
@[to_additive]
lemma preimage_mul (hm : Injective m) {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) :
@@ -947,12 +1338,12 @@ lemma div_subset_range {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m)
rintro _ ⟨a, ha, b, hb, rfl⟩
obtain ⟨a, rfl⟩ := hs ha
obtain ⟨b, rfl⟩ := ht hb
- exact ⟨a / b, map_div _ _ _⟩
+ exact ⟨a / b, map_div ..⟩
@[to_additive]
theorem preimage_div_preimage_subset {s t : Set β} : m ⁻¹' s / m ⁻¹' t ⊆ m ⁻¹' (s / t) := by
rintro _ ⟨_, _, _, _, rfl⟩
- exact ⟨_, ‹_›, _, ‹_›, (map_div m _ _).symm⟩
+ exact ⟨_, ‹_›, _, ‹_›, (map_div m ..).symm⟩
@[to_additive]
lemma preimage_div (hm : Injective m) {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) :
diff --git a/Mathlib/Algebra/Group/Pointwise/Set/Card.lean b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean
new file mode 100644
index 0000000000000..80a073b792385
--- /dev/null
+++ b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean
@@ -0,0 +1,86 @@
+/-
+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.Data.Set.Pointwise.Finite
+import Mathlib.SetTheory.Cardinal.Finite
+
+/-!
+# Cardinalities of pointwise operations on sets
+-/
+
+open scoped Cardinal Pointwise
+
+namespace Set
+variable {G M α : Type*}
+
+section Mul
+variable [Mul M] {s t : Set M}
+
+@[to_additive]
+lemma _root_.Cardinal.mk_mul_le : #(s * t) ≤ #s * #t := by
+ rw [← image2_mul]; exact Cardinal.mk_image2_le
+
+variable [IsCancelMul M]
+
+@[to_additive]
+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]
+ 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 Mul
+
+section InvolutiveInv
+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 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 G] {s t : Set G}
+
+@[to_additive]
+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 50077030df988..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 }
@@ -218,12 +218,14 @@ instance [RightCancelSemigroup G] [RightCancelSemigroup H] : RightCancelSemigrou
@[to_additive]
instance [LeftCancelMonoid M] [LeftCancelMonoid N] : LeftCancelMonoid (M × N) :=
{ mul_one := by simp,
- one_mul := by simp }
+ one_mul := by simp
+ mul_left_cancel := by simp }
@[to_additive]
instance [RightCancelMonoid M] [RightCancelMonoid N] : RightCancelMonoid (M × N) :=
{ mul_one := by simp,
- one_mul := by simp }
+ one_mul := by simp
+ mul_right_cancel := by simp }
@[to_additive]
instance [CancelMonoid M] [CancelMonoid N] : CancelMonoid (M × N) :=
@@ -235,7 +237,7 @@ instance instCommMonoid [CommMonoid M] [CommMonoid N] : CommMonoid (M × N) :=
@[to_additive]
instance [CancelCommMonoid M] [CancelCommMonoid N] : CancelCommMonoid (M × N) :=
- { mul_comm := fun ⟨m₁, n₁⟩ ⟨_, _⟩ => by rw [mk_mul_mk, mk_mul_mk, mul_comm m₁, mul_comm n₁] }
+ { mul_left_cancel := by simp }
@[to_additive]
instance instCommGroup [CommGroup G] [CommGroup H] : CommGroup (G × H) :=
@@ -585,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/Defs.lean b/Mathlib/Algebra/Group/Semiconj/Defs.lean
index b00ac04224406..cfeabeb0d12db 100644
--- a/Mathlib/Algebra/Group/Semiconj/Defs.lean
+++ b/Mathlib/Algebra/Group/Semiconj/Defs.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.Defs
-import Mathlib.Init.Logic
+import Mathlib.Order.Defs
/-!
# Semiconjugate elements of a semigroup
@@ -115,7 +115,7 @@ end Monoid
section Group
-variable [Group G] {a x y : G}
+variable [Group G]
/-- `a` semiconjugates `x` to `a * x * a⁻¹`. -/
@[to_additive "`a` semiconjugates `x` to `a + x + -a`."]
diff --git a/Mathlib/Algebra/Group/Semiconj/Units.lean b/Mathlib/Algebra/Group/Semiconj/Units.lean
index b842e2c11bc3b..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
@@ -32,7 +32,7 @@ assert_not_exists DenselyOrdered
open scoped Int
-variable {M G : Type*}
+variable {M : Type*}
namespace SemiconjBy
diff --git a/Mathlib/Algebra/Group/Subgroup/Basic.lean b/Mathlib/Algebra/Group/Subgroup/Basic.lean
index 383594bd1b22c..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`
@@ -69,7 +62,7 @@ Definitions in the file:
* `MonoidHom.ker f` : the kernel of a group homomorphism `f` is the subgroup of elements `x : G`
such that `f x = 1`
-* `MonoidHom.eq_locus f g` : given group homomorphisms `f`, `g`, the elements of `G` such that
+* `MonoidHom.eqLocus f g` : given group homomorphisms `f`, `g`, the elements of `G` such that
`f x = g x` form a subgroup of `G`
## Implementation notes
@@ -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 G : 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 G : 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 G : 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 G : 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)] -- This can be proved by `Submonoid.mk_eq_one`
-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]
@@ -1205,6 +716,16 @@ theorem map_iSup {ι : Sort*} (f : G →* N) (s : ι → Subgroup G) :
(iSup s).map f = ⨆ i, (s i).map f :=
(gc_map_comap f).l_iSup
+@[to_additive]
+theorem map_inf (H K : Subgroup G) (f : G →* N) (hf : Function.Injective f) :
+ (H ⊓ K).map f = H.map f ⊓ K.map f := SetLike.coe_injective (Set.image_inter hf)
+
+@[to_additive]
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : G →* N) (hf : Function.Injective f)
+ (s : ι → Subgroup G) : (iInf s).map f = ⨅ i, (s i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ s)
+
@[to_additive]
theorem comap_sup_comap_le (H K : Subgroup N) (f : G →* N) :
comap f H ⊔ comap f K ≤ comap f (H ⊔ K) :=
@@ -1386,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
@@ -1483,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.
@@ -1616,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⟩
@@ -1717,39 +1157,13 @@ This may be easier to work with, as it avoids inequalities and negations. -/
theorem _root_.normalizerCondition_iff_only_full_group_self_normalizing :
NormalizerCondition G ↔ ∀ H : Subgroup G, H.normalizer = H → H = ⊤ := by
apply forall_congr'; intro H
- simp only [lt_iff_le_and_ne, le_normalizer, true_and_iff, le_top, Ne]
+ simp only [lt_iff_le_and_ne, le_normalizer, le_top, Ne]
tauto
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
@@ -1771,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
@@ -1874,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]
@@ -1885,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
@@ -1899,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)))
@@ -1907,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 _
@@ -1924,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]
@@ -1953,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
@@ -2094,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⟩⟩
@@ -2124,10 +1532,14 @@ def ker (f : G →* M) : Subgroup G :=
f x⁻¹ = f x * f x⁻¹ := by rw [hx, one_mul]
_ = 1 := by rw [← map_mul, mul_inv_cancel, map_one] }
-@[to_additive]
-theorem mem_ker (f : G →* M) {x : G} : x ∈ f.ker ↔ f x = 1 :=
+@[to_additive (attr := simp)]
+theorem mem_ker {f : G →* M} {x : G} : x ∈ f.ker ↔ f x = 1 :=
Iff.rfl
+@[to_additive]
+theorem div_mem_ker_iff (f : G →* N) {x y : G} : x / y ∈ ker f ↔ f x = f y := by
+ rw [mem_ker, map_div, div_eq_one]
+
@[to_additive]
theorem coe_ker (f : G →* M) : (f.ker : Set G) = (f : G → M) ⁻¹' {1} :=
rfl
@@ -2141,7 +1553,7 @@ theorem ker_toHomUnits {M} [Monoid M] (f : G →* M) : f.toHomUnits.ker = f.ker
theorem eq_iff (f : G →* M) {x y : G} : f x = f y ↔ y⁻¹ * x ∈ f.ker := by
constructor <;> intro h
· rw [mem_ker, map_mul, h, ← map_mul, inv_mul_cancel, map_one]
- · rw [← one_mul x, ← mul_inv_cancel y, mul_assoc, map_mul, f.mem_ker.1 h, mul_one]
+ · rw [← one_mul x, ← mul_inv_cancel y, mul_assoc, map_mul, mem_ker.1 h, mul_one]
@[to_additive]
instance decidableMemKer [DecidableEq M] (f : G →* M) : DecidablePred (· ∈ f.ker) := fun x =>
@@ -2179,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 = ⊥ :=
@@ -2212,13 +1624,13 @@ theorem range_le_ker_iff (f : G →* G') (g : G' →* G'') : f.range ≤ g.ker
@[to_additive]
instance (priority := 100) normal_ker (f : G →* M) : f.ker.Normal :=
⟨fun x hx y => by
- rw [mem_ker, map_mul, map_mul, f.mem_ker.1 hx, mul_one, map_mul_eq_one f (mul_inv_cancel y)]⟩
+ rw [mem_ker, map_mul, map_mul, mem_ker.1 hx, mul_one, map_mul_eq_one f (mul_inv_cancel y)]⟩
@[to_additive (attr := simp)]
-lemma ker_fst : ker (fst G G') = .prod ⊥ ⊤ := SetLike.ext fun _ => (and_true_iff _).symm
+lemma ker_fst : ker (fst G G') = .prod ⊥ ⊤ := SetLike.ext fun _ => (iff_of_eq (and_true _)).symm
@[to_additive (attr := simp)]
-lemma ker_snd : ker (snd G G') = .prod ⊤ ⊥ := SetLike.ext fun _ => (true_and_iff _).symm
+lemma ker_snd : ker (snd G G') = .prod ⊤ ⊥ := SetLike.ext fun _ => (iff_of_eq (true_and _)).symm
@[simp]
theorem coe_toAdditive_ker (f : G →* G') :
@@ -2380,7 +1792,7 @@ theorem map_le_map_iff {f : G →* N} {H K : Subgroup G} : H.map f ≤ K.map f
@[to_additive]
theorem map_le_map_iff' {f : G →* N} {H K : Subgroup G} :
H.map f ≤ K.map f ↔ H ⊔ f.ker ≤ K ⊔ f.ker := by
- simp only [map_le_map_iff, sup_le_iff, le_sup_right, and_true_iff]
+ simp only [map_le_map_iff, sup_le_iff, le_sup_right, and_true]
@[to_additive]
theorem map_eq_map_iff {f : G →* N} {H K : Subgroup G} :
@@ -2585,7 +1997,7 @@ See `MonoidHom.eq_liftOfRightInverse` for the uniqueness lemma.
def liftOfRightInverse (hf : Function.RightInverse f_inv f) :
{ g : G₁ →* G₃ // f.ker ≤ g.ker } ≃ (G₂ →* G₃) where
toFun g := f.liftOfRightInverseAux f_inv hf g.1 g.2
- invFun φ := ⟨φ.comp f, fun x hx => (mem_ker _).mpr <| by simp [(mem_ker _).mp hx]⟩
+ invFun φ := ⟨φ.comp f, fun x hx ↦ mem_ker.mpr <| by simp [mem_ker.mp hx]⟩
left_inv g := by
ext
simp only [comp_apply, liftOfRightInverseAux_comp_apply, Subtype.coe_mk]
@@ -2744,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⟩
@@ -2865,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₂) :
@@ -2917,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/Finite.lean b/Mathlib/Algebra/Group/Subgroup/Finite.lean
index b4dc8b267698d..6e5342a357f4e 100644
--- a/Mathlib/Algebra/Group/Subgroup/Finite.lean
+++ b/Mathlib/Algebra/Group/Subgroup/Finite.lean
@@ -165,9 +165,11 @@ theorem pi_mem_of_mulSingle_mem_aux [DecidableEq η] (I : Finset η) {H : Subgro
x ∈ H := by
induction I using Finset.induction_on generalizing x with
| empty =>
- convert one_mem H
- ext i
- exact h1 i (Finset.not_mem_empty i)
+ have : x = 1 := by
+ ext i
+ exact h1 i (Finset.not_mem_empty i)
+ rw [this]
+ exact one_mem H
| insert hnmem ih =>
rename_i i I
have : x = Function.update x i 1 * Pi.mulSingle i (x i) := by
diff --git a/Mathlib/Algebra/Group/Subgroup/MulOpposite.lean b/Mathlib/Algebra/Group/Subgroup/MulOpposite.lean
index df6846f493e89..296424c376749 100644
--- a/Mathlib/Algebra/Group/Subgroup/MulOpposite.lean
+++ b/Mathlib/Algebra/Group/Subgroup/MulOpposite.lean
@@ -181,7 +181,7 @@ theorem op_closure (s : Set G) : (closure s).op = closure (MulOpposite.unop ⁻
@[to_additive]
theorem unop_closure (s : Set Gᵐᵒᵖ) : (closure s).unop = closure (MulOpposite.op ⁻¹' s) := by
rw [← op_inj, op_unop, op_closure]
- rfl
+ simp_rw [Set.preimage_preimage, MulOpposite.op_unop, Set.preimage_id']
/-- Bijection between a subgroup `H` and its opposite. -/
@[to_additive (attr := simps!) "Bijection between an additive subgroup `H` and its opposite."]
diff --git a/Mathlib/Algebra/Group/Subgroup/Order.lean b/Mathlib/Algebra/Group/Subgroup/Order.lean
index 663b28585b310..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
@@ -14,13 +15,14 @@ import Mathlib.Algebra.Order.Group.Unbundled.Abs
open Subgroup
-@[simp] theorem abs_mem_iff {S G} [AddGroup G] [LinearOrder G] {_ : SetLike S G}
- [NegMemClass S G] {H : S} {x : G} : |x| ∈ H ↔ x ∈ H := by
- cases abs_choice x <;> simp [*]
+@[to_additive (attr := simp)]
+theorem mabs_mem_iff {S G} [Group G] [LinearOrder G] {_ : SetLike S G}
+ [InvMemClass S G] {H : S} {x : G} : |x|ₘ ∈ H ↔ x ∈ H := by
+ cases mabs_choice x <;> simp [*]
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 1f026608f9626..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,11 +72,11 @@ 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_iff, coe_toSubmonoid, union_subset_iff, subset_closure, inv_subset_closure]
+ · simp only [true_and, coe_toSubmonoid, union_subset_iff, subset_closure, inv_subset_closure]
/-- For subgroups generated by a single element, see the simpler `zpow_induction_left`. -/
@[to_additive (attr := elab_as_elim)
@@ -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
@@ -392,6 +396,13 @@ theorem Normal.conjAct {G : Type*} [Group G] {H : Subgroup G} (hH : H.Normal) (g
theorem smul_normal (g : G) (H : Subgroup G) [h : Normal H] : MulAut.conj g • H = H :=
h.conjAct g
+theorem normalCore_eq_iInf_conjAct (H : Subgroup G) :
+ H.normalCore = ⨅ (g : ConjAct G), g • H := by
+ ext g
+ simp only [Subgroup.normalCore, Subgroup.mem_iInf, Subgroup.mem_pointwise_smul_iff_inv_smul_mem]
+ refine ⟨fun h x ↦ h x⁻¹, fun h x ↦ ?_⟩
+ simpa only [ConjAct.toConjAct_inv, inv_inv] using h x⁻¹
+
end Group
section GroupWithZero
@@ -536,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/MulOpposite.lean b/Mathlib/Algebra/Group/Submonoid/MulOpposite.lean
index ce69dc1d1759d..9157b526b564c 100644
--- a/Mathlib/Algebra/Group/Submonoid/MulOpposite.lean
+++ b/Mathlib/Algebra/Group/Submonoid/MulOpposite.lean
@@ -164,7 +164,7 @@ theorem op_closure (s : Set M) : (closure s).op = closure (MulOpposite.unop ⁻
@[to_additive]
theorem unop_closure (s : Set Mᵐᵒᵖ) : (closure s).unop = closure (MulOpposite.op ⁻¹' s) := by
rw [← op_inj, op_unop, op_closure]
- rfl
+ simp_rw [Set.preimage_preimage, MulOpposite.op_unop, Set.preimage_id']
/-- Bijection between a submonoid `H` and its opposite. -/
@[to_additive (attr := simps!) "Bijection between an additive submonoid `H` and its opposite."]
diff --git a/Mathlib/Algebra/Group/Submonoid/Operations.lean b/Mathlib/Algebra/Group/Submonoid/Operations.lean
index 04c31e0b2686f..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
@@ -274,6 +274,16 @@ theorem map_sup (S T : Submonoid M) (f : F) : (S ⊔ T).map f = S.map f ⊔ T.ma
theorem map_iSup {ι : Sort*} (f : F) (s : ι → Submonoid M) : (iSup s).map f = ⨆ i, (s i).map f :=
(gc_map_comap f : GaloisConnection (map f) (comap f)).l_iSup
+@[to_additive]
+theorem map_inf (S T : Submonoid M) (f : F) (hf : Function.Injective f) :
+ (S ⊓ T).map f = S.map f ⊓ T.map f := SetLike.coe_injective (Set.image_inter hf)
+
+@[to_additive]
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : F) (hf : Function.Injective f)
+ (s : ι → Submonoid M) : (iInf s).map f = ⨅ i, (s i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ s)
+
@[to_additive]
theorem comap_inf (S T : Submonoid N) (f : F) : (S ⊓ T).comap f = S.comap f ⊓ T.comap f :=
(gc_map_comap f : GaloisConnection (map f) (comap f)).u_inf
@@ -397,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."]
@@ -577,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`. -/
@@ -710,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
@@ -855,8 +718,8 @@ that `f x = 1` -/
def mker (f : F) : Submonoid M :=
(⊥ : Submonoid N).comap f
-@[to_additive]
-theorem mem_mker (f : F) {x : M} : x ∈ mker f ↔ f x = 1 :=
+@[to_additive (attr := simp)]
+theorem mem_mker {f : F} {x : M} : x ∈ mker f ↔ f x = 1 :=
Iff.rfl
@[to_additive]
@@ -865,7 +728,7 @@ theorem coe_mker (f : F) : (mker f : Set M) = (f : M → N) ⁻¹' {1} :=
@[to_additive]
instance decidableMemMker [DecidableEq N] (f : F) : DecidablePred (· ∈ mker f) := fun x =>
- decidable_of_iff (f x = 1) (mem_mker f)
+ decidable_of_iff (f x = 1) mem_mker
@[to_additive]
theorem comap_mker (g : N →* P) (f : M →* N) : g.mker.comap f = mker (comp g f) :=
@@ -914,10 +777,10 @@ theorem mker_inr : mker (inr M N) = ⊥ := by
simp [mem_mker]
@[to_additive (attr := simp)]
-lemma mker_fst : mker (fst M N) = .prod ⊥ ⊤ := SetLike.ext fun _ => (and_true_iff _).symm
+lemma mker_fst : mker (fst M N) = .prod ⊥ ⊤ := SetLike.ext fun _ => (iff_of_eq (and_true _)).symm
@[to_additive (attr := simp)]
-lemma mker_snd : mker (snd M N) = .prod ⊤ ⊥ := SetLike.ext fun _ => (true_and_iff _).symm
+lemma mker_snd : mker (snd M N) = .prod ⊤ ⊥ := SetLike.ext fun _ => (iff_of_eq (true_and _)).symm
/-- The `MonoidHom` from the preimage of a submonoid to itself. -/
@[to_additive (attr := simps)
@@ -1172,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 4f86ed34a4d25..5f2d5a377ff34 100644
--- a/Mathlib/Algebra/Group/Subsemigroup/Operations.lean
+++ b/Mathlib/Algebra/Group/Subsemigroup/Operations.lean
@@ -278,6 +278,16 @@ theorem map_iSup {ι : Sort*} (f : M →ₙ* N) (s : ι → Subsemigroup M) :
(iSup s).map f = ⨆ i, (s i).map f :=
(gc_map_comap f).l_iSup
+@[to_additive]
+theorem map_inf (S T : Subsemigroup M) (f : M →ₙ* N) (hf : Function.Injective f) :
+ (S ⊓ T).map f = S.map f ⊓ T.map f := SetLike.coe_injective (Set.image_inter hf)
+
+@[to_additive]
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : M →ₙ* N) (hf : Function.Injective f)
+ (s : ι → Subsemigroup M) : (iInf s).map f = ⨅ i, (s i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ s)
+
@[to_additive]
theorem comap_inf (S T : Subsemigroup N) (f : M →ₙ* N) : (S ⊓ T).comap f = S.comap f ⊓ T.comap f :=
(gc_map_comap f).u_inf
@@ -407,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)
@@ -488,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/ULift.lean b/Mathlib/Algebra/Group/ULift.lean
index 423ee6578ba6b..ce331c7da8288 100644
--- a/Mathlib/Algebra/Group/ULift.lean
+++ b/Mathlib/Algebra/Group/ULift.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Equiv.Basic
import Mathlib.Algebra.Group.InjSurj
diff --git a/Mathlib/Algebra/Group/UniqueProds/Basic.lean b/Mathlib/Algebra/Group/UniqueProds/Basic.lean
index b6782d02bf0b3..78c9df91994a4 100644
--- a/Mathlib/Algebra/Group/UniqueProds/Basic.lean
+++ b/Mathlib/Algebra/Group/UniqueProds/Basic.lean
@@ -3,8 +3,8 @@ 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.Pointwise.Finset.Basic
import Mathlib.Data.DFinsupp.Basic
-import Mathlib.Data.Finset.Pointwise.Basic
import Mathlib.Algebra.Group.ULift
import Mathlib.Data.Finsupp.Defs
@@ -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`. -/
@@ -70,13 +72,16 @@ variable {G H : Type*} [Mul G] [Mul H] {A B : Finset G} {a0 b0 : G}
theorem of_subsingleton [Subsingleton G] : UniqueMul A B a0 b0 := by
simp [UniqueMul, eq_iff_true_of_subsingleton]
-@[to_additive]
-theorem of_card_le_one (hA : A.Nonempty) (hB : B.Nonempty) (hA1 : A.card ≤ 1) (hB1 : B.card ≤ 1) :
+@[to_additive of_card_le_one]
+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
exact ⟨a, ha, b, hb, fun _ _ ha' hb' _ ↦ ⟨hA1 ha' ha, hB1 hb' hb⟩⟩
+@[deprecated (since := "2024-09-23")]
+alias _root_.UniqueAdd.of_card_nonpos := UniqueAdd.of_card_le_one
+
@[to_additive]
theorem mt (h : UniqueMul A B a0 b0) :
∀ ⦃a b⦄, a ∈ A → b ∈ B → a ≠ a0 ∨ b ≠ b0 → a * b ≠ a0 * b0 := fun _ _ ha hb k ↦ by
@@ -113,9 +118,9 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
exact Prod.mk.inj_iff.mp (J (x, y) ⟨Finset.mk_mem_product hx hy, l⟩))⟩
open Finset in
-@[to_additive]
+@[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
@@ -124,13 +129,16 @@ theorem iff_card_le_one [DecidableEq G] (ha0 : a0 ∈ A) (hb0 : b0 ∈ B) :
· rw [h1.2, h2.2]
· exact Prod.ext_iff.1 (@h (a, b) (a0, b0) ⟨⟨ha, hb⟩, he⟩ ⟨⟨ha0, hb0⟩, rfl⟩)
+@[deprecated (since := "2024-09-23")]
+alias _root_.UniqueAdd.iff_card_nonpos := UniqueAdd.iff_card_le_one
+
-- Porting note: mathport warning: expanding binder collection
-- (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
@[to_additive]
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
@@ -204,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
@@ -239,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
@@ -248,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
@@ -382,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
@@ -433,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
@@ -478,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
@@ -530,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)
@@ -573,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
@@ -607,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 a42617a760e41..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,9 +425,7 @@ 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 [Unique Mˣ] (u : Mˣ) : u = 1 := by subsingleton
-
-@[to_additive] lemma isUnit_iff_eq_one [Unique Mˣ] {x : M} : IsUnit x ↔ x = 1 :=
+@[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⟩
end Monoid
@@ -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 353b3a6e27864..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"]
@@ -112,6 +112,16 @@ def recOneCoe {C : WithOne α → Sort*} (h₁ : C 1) (h₂ : ∀ a : α, C a) :
| Option.none => h₁
| Option.some x => h₂ x
+@[to_additive (attr := simp)]
+lemma recOneCoe_one {C : WithOne α → Sort*} (h₁ h₂) :
+ recOneCoe h₁ h₂ (1 : WithOne α) = (h₁ : C 1) :=
+ rfl
+
+@[to_additive (attr := simp)]
+lemma recOneCoe_coe {C : WithOne α → Sort*} (h₁ h₂) (a : α) :
+ recOneCoe h₁ h₂ (a : WithOne α) = (h₂ : ∀ a : α, C a) a :=
+ rfl
+
/-- Deconstruct an `x : WithOne α` to the underlying value in `α`, given a proof that `x ≠ 1`. -/
@[to_additive unzero
"Deconstruct an `x : WithZero α` to the underlying value in `α`, given a proof that `x ≠ 0`."]
diff --git a/Mathlib/Algebra/Group/ZeroOne.lean b/Mathlib/Algebra/Group/ZeroOne.lean
index 3e72968095621..8822f97d1d17e 100644
--- a/Mathlib/Algebra/Group/ZeroOne.lean
+++ b/Mathlib/Algebra/Group/ZeroOne.lean
@@ -6,17 +6,10 @@ Authors: Gabriel Ebner, Mario Carneiro
import Mathlib.Tactic.ToAdditive
/-!
-## Classes for `Zero` and `One`
--/
-
-class Zero.{u} (α : Type u) where
- zero : α
+## Typeclass `One`
-instance (priority := 300) Zero.toOfNat0 {α} [Zero α] : OfNat α (nat_lit 0) where
- ofNat := ‹Zero α›.1
-
-instance (priority := 200) Zero.ofOfNat0 {α} [OfNat α (nat_lit 0)] : Zero α where
- zero := 0
+`Zero` has already been defined in Lean.
+-/
universe u
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 d523dffe4f80d..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]
@@ -89,6 +89,6 @@ def DistribMulAction.prodEquiv : DistribMulAction (M × N) α ≃
congr 1
· funext i; congr; ext m a; clear i; (conv_rhs => rw [← one_smul N a]); rfl
· ext n a; (conv_rhs => rw [← one_smul M (SMul.smul n a)]); rfl
- · apply heq_prop
+ · exact proof_irrel_heq ..
end Action_by_Prod
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 78525d46a0706..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
@@ -291,7 +299,7 @@ end GroupWithZero
section GroupWithZero
-variable [GroupWithZero G₀] {a b c : G₀}
+variable [GroupWithZero G₀] {a : G₀}
@[simp]
theorem zero_div (a : G₀) : 0 / a = 0 := by rw [div_eq_mul_inv, zero_mul]
@@ -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]
@@ -411,8 +422,7 @@ lemma zpow_add' {m n : ℤ} (h : a ≠ 0 ∨ m + n ≠ 0 ∨ m = 0 ∧ n = 0) :
· simp [hn]
by_cases ha : a = 0
· subst a
- simp only [false_or_iff, eq_self_iff_true, not_true, Ne, hm, hn, false_and_iff,
- or_false_iff] at h
+ simp only [false_or, eq_self_iff_true, not_true, Ne, hm, hn, false_and, or_false] at h
rw [zero_zpow _ h, zero_zpow _ hm, zero_mul]
· exact zpow_add₀ ha m n
@@ -422,7 +432,7 @@ end GroupWithZero
section CommGroupWithZero
-variable [CommGroupWithZero G₀] {a b c d : G₀}
+variable [CommGroupWithZero G₀]
theorem div_mul_eq_mul_div₀ (a b c : G₀) : a / c * b = a * b / c := by
simp_rw [div_eq_mul_inv, mul_assoc, mul_comm c⁻¹]
diff --git a/Mathlib/Algebra/GroupWithZero/Commute.lean b/Mathlib/Algebra/GroupWithZero/Commute.lean
index 59423cb09016f..5190f384c283e 100644
--- a/Mathlib/Algebra/GroupWithZero/Commute.lean
+++ b/Mathlib/Algebra/GroupWithZero/Commute.lean
@@ -14,7 +14,7 @@ import Mathlib.Tactic.Nontriviality
assert_not_exists DenselyOrdered
-variable {α M₀ G₀ M₀' G₀' F F' : Type*}
+variable {M₀ G₀ : Type*}
variable [MonoidWithZero M₀]
namespace Ring
@@ -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₀] {a : G₀} {m n : ℕ}
+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 b3d73d7ba0a35..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₀`. -/
@@ -159,17 +159,17 @@ class MulDivCancelClass (M₀ : Type*) [MonoidWithZero M₀] [Div M₀] : Prop w
protected mul_div_cancel (a b : M₀) : b ≠ 0 → a * b / b = a
section MulDivCancelClass
-variable [MonoidWithZero M₀] [Div M₀] [MulDivCancelClass M₀] {a b : M₀}
+variable [MonoidWithZero M₀] [Div M₀] [MulDivCancelClass M₀]
-@[simp] lemma mul_div_cancel_right₀ (a : M₀) (hb : b ≠ 0) : a * b / b = a :=
+@[simp] lemma mul_div_cancel_right₀ (a : M₀) {b : M₀} (hb : b ≠ 0) : a * b / b = a :=
MulDivCancelClass.mul_div_cancel _ _ hb
end MulDivCancelClass
section MulDivCancelClass
-variable [CommMonoidWithZero M₀] [Div M₀] [MulDivCancelClass M₀] {a b : M₀}
+variable [CommMonoidWithZero M₀] [Div M₀] [MulDivCancelClass M₀]
-@[simp] lemma mul_div_cancel_left₀ (b : M₀) (ha : a ≠ 0) : a * b / a = b := by
+@[simp] lemma mul_div_cancel_left₀ (b : M₀) {a : M₀} (ha : a ≠ 0) : a * b / a = b := by
rw [mul_comm, mul_div_cancel_right₀ _ ha]
end MulDivCancelClass
@@ -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]
@@ -216,7 +215,7 @@ end
section GroupWithZero
-variable [GroupWithZero G₀] {a b c g h x : G₀}
+variable [GroupWithZero G₀] {a b : G₀}
@[simp]
theorem mul_inv_cancel_right₀ (h : b ≠ 0) (a : G₀) : a * b * b⁻¹ = a :=
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 2b8dcaded4211..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
@@ -40,6 +40,12 @@ lemma indicator_mul_right (s : Set ι) (f g : ι → M₀) :
· rfl
· rw [mul_zero]
+lemma indicator_mul_const (s : Set ι) (f : ι → M₀) (a : M₀) (i : ι) :
+ s.indicator (f · * a) i = s.indicator f i * a := by rw [indicator_mul_left]
+
+lemma indicator_const_mul (s : Set ι) (f : ι → M₀) (a : M₀) (i : ι) :
+ s.indicator (a * f ·) i = a * s.indicator f i := by rw [indicator_mul_right]
+
lemma inter_indicator_mul (f g : ι → M₀) (i : ι) :
(s ∩ t).indicator (fun j ↦ f j * g j) i = s.indicator f i * t.indicator g i := by
rw [← Set.indicator_indicator]
diff --git a/Mathlib/Algebra/GroupWithZero/InjSurj.lean b/Mathlib/Algebra/GroupWithZero/InjSurj.lean
index d7a7ff367118a..75dc801b0bbb6 100644
--- a/Mathlib/Algebra/GroupWithZero/InjSurj.lean
+++ b/Mathlib/Algebra/GroupWithZero/InjSurj.lean
@@ -19,7 +19,7 @@ variable {M₀ G₀ M₀' G₀' : Type*}
section MulZeroClass
-variable [MulZeroClass M₀] {a b : M₀}
+variable [MulZeroClass M₀]
/-- Pull back a `MulZeroClass` instance along an injective function.
See note [reducible non-instances]. -/
@@ -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 3c09328f414ca..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) :
@@ -304,7 +304,7 @@ theorem mk_mem_nonZeroDivisors_associates : Associates.mk a ∈ (Associates M₀
/-- The non-zero divisors of associates of a monoid with zero `M₀` are isomorphic to the associates
of the non-zero divisors of `M₀` under the map `⟨⟦a⟧, _⟩ ↦ ⟦⟨a, _⟩⟧`. -/
def associatesNonZeroDivisorsEquiv : (Associates M₀)⁰ ≃* Associates M₀⁰ where
- toEquiv := .subtypeQuotientEquivQuotientSubtype (s₂ := Associated.setoid _)
+ toEquiv := .subtypeQuotientEquivQuotientSubtype _ (s₂ := Associated.setoid _)
(· ∈ nonZeroDivisors _)
(by simp [mem_nonZeroDivisors_iff, Quotient.forall, Associates.mk_mul_mk])
(by simp [Associated.setoid])
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.lean b/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Basic.lean
similarity index 97%
rename from Mathlib/Algebra/GroupWithZero/Pointwise/Set.lean
rename to Mathlib/Algebra/GroupWithZero/Pointwise/Set/Basic.lean
index 653b0ea020618..ec178273360b2 100644
--- a/Mathlib/Algebra/GroupWithZero/Pointwise/Set.lean
+++ b/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Basic.lean
@@ -3,7 +3,7 @@ Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Floris van Doorn
-/
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Algebra.GroupWithZero.Basic
/-!
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/Semiconj.lean b/Mathlib/Algebra/GroupWithZero/Semiconj.lean
index f3798456188e4..0dfc56212073d 100644
--- a/Mathlib/Algebra/GroupWithZero/Semiconj.lean
+++ b/Mathlib/Algebra/GroupWithZero/Semiconj.lean
@@ -13,7 +13,7 @@ import Mathlib.Algebra.Group.Semiconj.Units
assert_not_exists DenselyOrdered
-variable {α M₀ G₀ M₀' G₀' F F' : Type*}
+variable {G₀ : Type*}
namespace SemiconjBy
diff --git a/Mathlib/Algebra/GroupWithZero/ULift.lean b/Mathlib/Algebra/GroupWithZero/ULift.lean
index 2e370b30faa0a..f178a5b637230 100644
--- a/Mathlib/Algebra/GroupWithZero/ULift.lean
+++ b/Mathlib/Algebra/GroupWithZero/ULift.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.ULift
import Mathlib.Algebra.GroupWithZero.InjSurj
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 c413ab0a165b8..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`. -/
@@ -94,7 +121,6 @@ def invMonoidWithZeroHom {G₀ : Type*} [CommGroupWithZero G₀] : G₀ →*₀
namespace Units
variable [GroupWithZero G₀]
-variable {a b : G₀}
@[simp]
theorem smul_mk0 {α : Type*} [SMul G₀ α] {g : G₀} (hg : g ≠ 0) (a : α) : mk0 g hg • a = g • a :=
@@ -108,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 1a8e376d48a1d..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
@@ -266,6 +266,43 @@ def unitsWithZeroEquiv : (WithZero α)ˣ ≃* α where
right_inv _ := rfl
map_mul' _ _ := coe_inj.mp <| by simp only [Units.val_mul, coe_unzero, coe_mul]
+/-- Any group with zero is isomorphic to adjoining `0` to the units of itself. -/
+def withZeroUnitsEquiv {G : Type*} [GroupWithZero G]
+ [DecidablePred (fun a : G ↦ a = 0)] :
+ WithZero Gˣ ≃* G where
+ toFun := WithZero.recZeroCoe 0 Units.val
+ invFun a := if h : a = 0 then 0 else (Units.mk0 a h : Gˣ)
+ left_inv := (by induction · <;> simp)
+ right_inv _ := by simp only; split <;> simp_all
+ map_mul' x y := by
+ induction x <;> induction y <;>
+ simp [← WithZero.coe_mul, ← Units.val_mul]
+
+/-- A version of `Equiv.optionCongr` for `WithZero`. -/
+noncomputable def _root_.MulEquiv.withZero [Group β] (e : α ≃* β) :
+ WithZero α ≃* WithZero β where
+ toFun := map' e.toMonoidHom
+ invFun := map' e.symm.toMonoidHom
+ left_inv := (by induction · <;> simp)
+ right_inv := (by induction · <;> simp)
+ map_mul' x y := by
+ induction x <;> induction y <;>
+ simp
+
+/-- The inverse of `MulEquiv.withZero`. -/
+protected noncomputable def _root_.MulEquiv.unzero [Group β] (e : WithZero α ≃* WithZero β) :
+ α ≃* β where
+ toFun x := unzero (x := e x) (by simp [ne_eq, ← e.eq_symm_apply])
+ invFun x := unzero (x := e.symm x) (by simp [e.symm_apply_eq])
+ left_inv _ := by simp
+ right_inv _ := by simp
+ map_mul' _ _ := by
+ simp only [coe_mul, map_mul]
+ generalize_proofs A B C
+ suffices ((unzero A : β) : WithZero β) = (unzero B) * (unzero C) by
+ rwa [← WithZero.coe_mul, WithZero.coe_inj] at this
+ simp
+
end Group
instance commGroupWithZero [CommGroup α] : CommGroupWithZero (WithZero α) :=
diff --git a/Mathlib/Algebra/HierarchyDesign.lean b/Mathlib/Algebra/HierarchyDesign.lean
index 862788ae48368..b2fe9b97fe510 100644
--- a/Mathlib/Algebra/HierarchyDesign.lean
+++ b/Mathlib/Algebra/HierarchyDesign.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Eric Wieser
+Authors: Kim Morrison, Eric Wieser
-/
import Mathlib.Init
import Batteries.Util.LibraryNote
diff --git a/Mathlib/Algebra/Homology/Additive.lean b/Mathlib/Algebra/Homology/Additive.lean
index b2988fbd4aba9..5fbebb2c8beb9 100644
--- a/Mathlib/Algebra/Homology/Additive.lean
+++ b/Mathlib/Algebra/Homology/Additive.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Homology.Single
import Mathlib.CategoryTheory.Preadditive.AdditiveFunctor
@@ -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 0b02a3d3140cd..e9554f54c2961 100644
--- a/Mathlib/Algebra/Homology/Augment.lean
+++ b/Mathlib/Algebra/Homology/Augment.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Homology.Single
@@ -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/BifunctorAssociator.lean b/Mathlib/Algebra/Homology/BifunctorAssociator.lean
index 70f0ff7943445..77c349d2de113 100644
--- a/Mathlib/Algebra/Homology/BifunctorAssociator.lean
+++ b/Mathlib/Algebra/Homology/BifunctorAssociator.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joël Riou
-/
import Mathlib.CategoryTheory.GradedObject.Associator
-import Mathlib.CategoryTheory.Preadditive.AdditiveFunctor
+import Mathlib.CategoryTheory.Linear.LinearFunctor
import Mathlib.Algebra.Homology.Bifunctor
/-!
@@ -187,6 +187,212 @@ lemma ι_mapBifunctor₁₂Desc (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃)
end
+variable (F₁₂ G)
+
+/-- The first differential on a summand
+of `mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄`. -/
+noncomputable def d₁ (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) :
+ (G.obj ((F₁₂.obj (K₁.X i₁)).obj (K₂.X i₂))).obj (K₃.X i₃) ⟶
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j :=
+ (ComplexShape.ε₁ c₁₂ c₃ c₄ (ComplexShape.π c₁ c₂ c₁₂ ⟨i₁, i₂⟩, i₃) *
+ ComplexShape.ε₁ c₁ c₂ c₁₂ (i₁, i₂)) •
+ (G.map ((F₁₂.map (K₁.d i₁ (c₁.next i₁))).app (K₂.X i₂))).app (K₃.X i₃) ≫
+ ιOrZero F₁₂ G K₁ K₂ K₃ c₁₂ c₄ _ i₂ i₃ j
+
+lemma d₁_eq_zero (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) (h : ¬ c₁.Rel i₁ (c₁.next i₁)) :
+ d₁ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j = 0 := by
+ dsimp [d₁]
+ rw [shape _ _ _ h, Functor.map_zero, zero_app, Functor.map_zero, zero_app, zero_comp, smul_zero]
+
+lemma d₁_eq {i₁ i₁' : ι₁} (h₁ : c₁.Rel i₁ i₁') (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) :
+ d₁ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j =
+ (ComplexShape.ε₁ c₁₂ c₃ c₄ (ComplexShape.π c₁ c₂ c₁₂ ⟨i₁, i₂⟩, i₃) *
+ ComplexShape.ε₁ c₁ c₂ c₁₂ (i₁, i₂) ) •
+ (G.map ((F₁₂.map (K₁.d i₁ i₁')).app (K₂.X i₂))).app (K₃.X i₃) ≫
+ ιOrZero F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁' i₂ i₃ j := by
+ obtain rfl := c₁.next_eq' h₁
+ rfl
+
+/-- The second differential on a summand
+of `mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄`. -/
+noncomputable def d₂ (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) :
+ (G.obj ((F₁₂.obj (K₁.X i₁)).obj (K₂.X i₂))).obj (K₃.X i₃) ⟶
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j :=
+ (c₁₂.ε₁ c₃ c₄ (ComplexShape.π c₁ c₂ c₁₂ ⟨i₁, i₂⟩, i₃) * c₁.ε₂ c₂ c₁₂ (i₁, i₂)) •
+ (G.map ((F₁₂.obj (K₁.X i₁)).map (K₂.d i₂ (c₂.next i₂)))).app (K₃.X i₃) ≫
+ ιOrZero F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ _ i₃ j
+
+lemma d₂_eq_zero (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) (h : ¬ c₂.Rel i₂ (c₂.next i₂)) :
+ d₂ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j = 0 := by
+ dsimp [d₂]
+ rw [shape _ _ _ h, Functor.map_zero, Functor.map_zero, zero_app, zero_comp, smul_zero]
+
+lemma d₂_eq (i₁ : ι₁) {i₂ i₂' : ι₂} (h₂ : c₂.Rel i₂ i₂') (i₃ : ι₃) (j : ι₄) :
+ d₂ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j =
+ (c₁₂.ε₁ c₃ c₄ (ComplexShape.π c₁ c₂ c₁₂ ⟨i₁, i₂⟩, i₃) * c₁.ε₂ c₂ c₁₂ (i₁, i₂)) •
+ (G.map ((F₁₂.obj (K₁.X i₁)).map (K₂.d i₂ i₂'))).app (K₃.X i₃) ≫
+ ιOrZero F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ _ i₃ j := by
+ obtain rfl := c₂.next_eq' h₂
+ rfl
+
+/-- The third differential on a summand
+of `mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄`. -/
+noncomputable def d₃ (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) :
+ (G.obj ((F₁₂.obj (K₁.X i₁)).obj (K₂.X i₂))).obj (K₃.X i₃) ⟶
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j :=
+ (ComplexShape.ε₂ c₁₂ c₃ c₄ (c₁.π c₂ c₁₂ (i₁, i₂), i₃)) •
+ (G.obj ((F₁₂.obj (K₁.X i₁)).obj (K₂.X i₂))).map (K₃.d i₃ (c₃.next i₃)) ≫
+ ιOrZero F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ _ j
+
+lemma d₃_eq_zero (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) (h : ¬ c₃.Rel i₃ (c₃.next i₃)) :
+ d₃ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j = 0 := by
+ dsimp [d₃]
+ rw [shape _ _ _ h, Functor.map_zero, zero_comp, smul_zero]
+
+lemma d₃_eq (i₁ : ι₁) (i₂ : ι₂) {i₃ i₃' : ι₃} (h₃ : c₃.Rel i₃ i₃') (j : ι₄) :
+ d₃ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j =
+ (ComplexShape.ε₂ c₁₂ c₃ c₄ (c₁.π c₂ c₁₂ (i₁, i₂), i₃)) •
+ (G.obj ((F₁₂.obj (K₁.X i₁)).obj (K₂.X i₂))).map (K₃.d i₃ i₃') ≫
+ ιOrZero F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ _ j := by
+ obtain rfl := c₃.next_eq' h₃
+ rfl
+
+
+section
+
+variable [HasGoodTrifunctor₁₂Obj F₁₂ G K₁ K₂ K₃ c₁₂ c₄]
+variable (j j' : ι₄)
+
+/-- The first differential on `mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄`. -/
+noncomputable def D₁ :
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j ⟶
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j' :=
+ mapBifunctor₁₂Desc (fun i₁ i₂ i₃ _ ↦ d₁ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j')
+
+/-- The second differential on `mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄`. -/
+noncomputable def D₂ :
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j ⟶
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j' :=
+ mapBifunctor₁₂Desc (fun i₁ i₂ i₃ _ ↦ d₂ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j')
+
+/-- The third differential on `mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄`. -/
+noncomputable def D₃ :
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j ⟶
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j' :=
+ mapBifunctor.D₂ _ _ _ _ _ _
+
+end
+
+section
+
+variable (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j j' : ι₄)
+ (h : ComplexShape.r c₁ c₂ c₃ c₁₂ c₄ (i₁, i₂, i₃) = j)
+
+@[reassoc (attr := simp)]
+lemma ι_D₁ [HasGoodTrifunctor₁₂Obj F₁₂ G K₁ K₂ K₃ c₁₂ c₄] :
+ ι F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j h ≫ D₁ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ j j' =
+ d₁ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j' := by
+ simp [D₁]
+
+@[reassoc (attr := simp)]
+lemma ι_D₂ [HasGoodTrifunctor₁₂Obj F₁₂ G K₁ K₂ K₃ c₁₂ c₄] :
+ ι F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j h ≫ D₂ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ j j' =
+ d₂ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j' := by
+ simp [D₂]
+
+@[reassoc (attr := simp)]
+lemma ι_D₃ :
+ ι F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j h ≫ D₃ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ j j' =
+ d₃ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j' := by
+ simp only [ι_eq _ _ _ _ _ _ _ _ _ _ _ _ rfl h, D₃, assoc, mapBifunctor.ι_D₂]
+ by_cases h₁ : c₃.Rel i₃ (c₃.next i₃)
+ · rw [d₃_eq _ _ _ _ _ _ _ _ _ h₁]
+ by_cases h₂ : ComplexShape.π c₁₂ c₃ c₄ (c₁.π c₂ c₁₂ (i₁, i₂), c₃.next i₃) = j'
+ · rw [mapBifunctor.d₂_eq _ _ _ _ _ h₁ _ h₂,
+ ιOrZero_eq _ _ _ _ _ _ _ _ _ _ _ h₂,
+ Linear.comp_units_smul, smul_left_cancel_iff,
+ ι_eq _ _ _ _ _ _ _ _ _ _ _ _ rfl h₂,
+ NatTrans.naturality_assoc]
+ · rw [mapBifunctor.d₂_eq_zero' _ _ _ _ _ h₁ _ h₂, comp_zero,
+ ιOrZero_eq_zero _ _ _ _ _ _ _ _ _ _ _ h₂, comp_zero, smul_zero]
+ · rw [mapBifunctor.d₂_eq_zero _ _ _ _ _ _ _ h₁, comp_zero,
+ d₃_eq_zero _ _ _ _ _ _ _ _ _ _ _ h₁]
+
+end
+
+lemma d_eq (j j' : ι₄) [HasGoodTrifunctor₁₂Obj F₁₂ G K₁ K₂ K₃ c₁₂ c₄] :
+ (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).d j j' =
+ D₁ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ j j' + D₂ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ j j' +
+ D₃ F₁₂ G K₁ K₂ K₃ c₁₂ c₄ j j' := by
+ rw [mapBifunctor.d_eq]
+ congr 1
+ ext i₁ i₂ i₃ h
+ simp only [Preadditive.comp_add, ι_D₁, ι_D₂]
+ rw [ι_eq _ _ _ _ _ _ _ _ _ _ _ _ rfl h, assoc, mapBifunctor.ι_D₁]
+ set i₁₂ := ComplexShape.π c₁ c₂ c₁₂ ⟨i₁, i₂⟩
+ by_cases h₁ : c₁₂.Rel i₁₂ (c₁₂.next i₁₂)
+ · by_cases h₂ : ComplexShape.π c₁₂ c₃ c₄ (c₁₂.next i₁₂, i₃) = j'
+ · rw [mapBifunctor.d₁_eq _ _ _ _ h₁ _ _ h₂]
+ simp only [mapBifunctor.d_eq, Functor.map_add, NatTrans.app_add, Preadditive.add_comp,
+ smul_add, Preadditive.comp_add, Linear.comp_units_smul]
+ congr 1
+ · rw [← NatTrans.comp_app_assoc, ← Functor.map_comp,
+ mapBifunctor.ι_D₁]
+ by_cases h₃ : c₁.Rel i₁ (c₁.next i₁)
+ · have h₄ := (ComplexShape.next_π₁ c₂ c₁₂ h₃ i₂).symm
+ rw [mapBifunctor.d₁_eq _ _ _ _ h₃ _ _ h₄,
+ d₁_eq _ _ _ _ _ _ _ h₃,
+ ιOrZero_eq _ _ _ _ _ _ _ _ _ _ _ (by rw [← h₂, ← h₄]; rfl),
+ ι_eq _ _ _ _ _ _ _ _ _ _ (c₁₂.next i₁₂) _ h₄ h₂,
+ Functor.map_units_smul, Functor.map_comp, NatTrans.app_units_zsmul,
+ NatTrans.comp_app, Linear.units_smul_comp, assoc, smul_smul]
+ · rw [d₁_eq_zero _ _ _ _ _ _ _ _ _ _ _ h₃,
+ mapBifunctor.d₁_eq_zero _ _ _ _ _ _ _ h₃,
+ Functor.map_zero, zero_app, zero_comp, smul_zero]
+ · rw [← NatTrans.comp_app_assoc, ← Functor.map_comp,
+ mapBifunctor.ι_D₂]
+ by_cases h₃ : c₂.Rel i₂ (c₂.next i₂)
+ · have h₄ := (ComplexShape.next_π₂ c₁ c₁₂ i₁ h₃).symm
+ rw [mapBifunctor.d₂_eq _ _ _ _ _ h₃ _ h₄,
+ d₂_eq _ _ _ _ _ _ _ _ h₃,
+ ιOrZero_eq _ _ _ _ _ _ _ _ _ _ _ (by rw [← h₂, ← h₄]; rfl),
+ ι_eq _ _ _ _ _ _ _ _ _ _ (c₁₂.next i₁₂) _ h₄ h₂,
+ Functor.map_units_smul, Functor.map_comp, NatTrans.app_units_zsmul,
+ NatTrans.comp_app, Linear.units_smul_comp, assoc, smul_smul]
+ · rw [d₂_eq_zero _ _ _ _ _ _ _ _ _ _ _ h₃,
+ mapBifunctor.d₂_eq_zero _ _ _ _ _ _ _ h₃,
+ Functor.map_zero, zero_app, zero_comp, smul_zero]
+ · rw [mapBifunctor.d₁_eq_zero' _ _ _ _ h₁ _ _ h₂, comp_zero]
+ trans 0 + 0
+ · simp
+ · congr 1
+ · by_cases h₃ : c₁.Rel i₁ (c₁.next i₁)
+ · rw [d₁_eq _ _ _ _ _ _ _ h₃, ιOrZero_eq_zero, comp_zero, smul_zero]
+ dsimp [ComplexShape.r]
+ intro h₄
+ apply h₂
+ rw [← h₄, ComplexShape.next_π₁ c₂ c₁₂ h₃ i₂]
+ · rw [d₁_eq_zero _ _ _ _ _ _ _ _ _ _ _ h₃]
+ · by_cases h₃ : c₂.Rel i₂ (c₂.next i₂)
+ · rw [d₂_eq _ _ _ _ _ _ _ _ h₃, ιOrZero_eq_zero, comp_zero, smul_zero]
+ dsimp [ComplexShape.r]
+ intro h₄
+ apply h₂
+ rw [← h₄, ComplexShape.next_π₂ c₁ c₁₂ i₁ h₃]
+ · rw [d₂_eq_zero _ _ _ _ _ _ _ _ _ _ _ h₃]
+ · rw [mapBifunctor.d₁_eq_zero _ _ _ _ _ _ _ h₁, comp_zero,
+ d₁_eq_zero, d₂_eq_zero, zero_add]
+ · intro h₂
+ apply h₁
+ have := ComplexShape.rel_π₂ c₁ c₁₂ i₁ h₂
+ rw [c₁₂.next_eq' this]
+ exact this
+ · intro h₂
+ apply h₁
+ have := ComplexShape.rel_π₁ c₂ c₁₂ h₂ i₂
+ rw [c₁₂.next_eq' this]
+ exact this
+
end mapBifunctor₁₂
end HomologicalComplex
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/ComplexShape.lean b/Mathlib/Algebra/Homology/ComplexShape.lean
index e4da8ba92cfdf..2b46e9d743bc7 100644
--- a/Mathlib/Algebra/Homology/ComplexShape.lean
+++ b/Mathlib/Algebra/Homology/ComplexShape.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison
+Authors: Johan Commelin, Kim Morrison
-/
import Mathlib.Algebra.Group.Defs
import Mathlib.Logic.Relation
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/DerivedCategory/Ext/Basic.lean b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean
index 781e2de9cf31f..774df032bb48c 100644
--- a/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean
+++ b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean
@@ -36,7 +36,6 @@ sheaves over `X` shall be in `Type u`.
## TODO
* compute `Ext X Y 0`
-* construct the covariant long exact sequences of `Ext`.
* construct the contravariant long exact sequences of `Ext`.
-/
diff --git a/Mathlib/Algebra/Homology/DerivedCategory/Ext/ExactSequences.lean b/Mathlib/Algebra/Homology/DerivedCategory/Ext/ExactSequences.lean
new file mode 100644
index 0000000000000..427dd7ae80159
--- /dev/null
+++ b/Mathlib/Algebra/Homology/DerivedCategory/Ext/ExactSequences.lean
@@ -0,0 +1,164 @@
+/-
+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.Homology.DerivedCategory.Ext.ExtClass
+import Mathlib.Algebra.Homology.ShortComplex.Ab
+import Mathlib.CategoryTheory.Triangulated.Yoneda
+
+/-!
+# Long exact sequences of `Ext`-groups
+
+In this file, we obtain the covariant long exact sequence of `Ext`:
+`Ext X S.X₁ n₀ → Ext X S.X₂ n₀ → Ext X S.X₃ n₀ → Ext X S.X₁ n₁ → Ext X S.X₂ n₁ → Ext X S.X₃ n₁`
+when `S` is a short exact short complex in an abelian category `C`, `n₀ + 1 = n₁` and `X : C`.
+
+-/
+
+universe w' w v u
+
+namespace CategoryTheory
+
+open Opposite DerivedCategory
+
+variable {C : Type u} [Category.{v} C] [Abelian C] [HasExt.{w} C]
+
+namespace Abelian
+
+namespace Ext
+
+section CovariantSequence
+
+lemma hom_comp_singleFunctor_map_shift [HasDerivedCategory.{w'} C]
+ {X Y Z : C} {n : ℕ} (x : Ext X Y n) (f : Y ⟶ Z) :
+ x.hom ≫ ((DerivedCategory.singleFunctor C 0).map f)⟦(n : ℤ)⟧' =
+ (x.comp (mk₀ f) (add_zero n)).hom := by
+ simp only [comp_hom, mk₀_hom, ShiftedHom.comp_mk₀]
+
+variable {X : C} {S : ShortComplex C} (hS : S.ShortExact)
+
+lemma preadditiveCoyoneda_homologySequenceδ_singleTriangle_apply
+ [HasDerivedCategory.{w'} C] {X : C} {n₀ : ℕ} (x : Ext X S.X₃ n₀)
+ {n₁ : ℕ} (h : n₀ + 1 = n₁) :
+ (preadditiveCoyoneda.obj (op ((singleFunctor C 0).obj X))).homologySequenceδ
+ hS.singleTriangle n₀ n₁ (by omega) x.hom =
+ (x.comp hS.extClass h).hom := by
+ rw [Pretriangulated.preadditiveCoyoneda_homologySequenceδ_apply,
+ comp_hom, hS.extClass_hom, ShiftedHom.comp]
+ rfl
+
+variable (X)
+
+include hS in
+/-- Alternative formulation of `covariant_sequence_exact₂` -/
+lemma covariant_sequence_exact₂' (n : ℕ) :
+ (ShortComplex.mk (AddCommGrp.ofHom ((mk₀ S.f).postcomp X (add_zero n)))
+ (AddCommGrp.ofHom ((mk₀ S.g).postcomp X (add_zero n))) (by
+ ext x
+ dsimp [AddCommGrp.ofHom]
+ simp only [comp_assoc_of_third_deg_zero, mk₀_comp_mk₀, ShortComplex.zero, mk₀_zero,
+ comp_zero]
+ rfl)).Exact := by
+ letI := HasDerivedCategory.standard C
+ have := (preadditiveCoyoneda.obj (op ((singleFunctor C 0).obj X))).homologySequence_exact₂ _
+ (hS.singleTriangle_distinguished) n
+ rw [ShortComplex.ab_exact_iff_function_exact] at this ⊢
+ apply Function.Exact.of_ladder_addEquiv_of_exact' (e₁ := Ext.homAddEquiv)
+ (e₂ := Ext.homAddEquiv) (e₃ := Ext.homAddEquiv) (H := this)
+ all_goals ext x; apply hom_comp_singleFunctor_map_shift (C := C)
+
+section
+
+variable (n₀ n₁ : ℕ) (h : n₀ + 1 = n₁)
+
+/-- Alternative formulation of `covariant_sequence_exact₃` -/
+lemma covariant_sequence_exact₃' :
+ (ShortComplex.mk (AddCommGrp.ofHom ((mk₀ S.g).postcomp X (add_zero n₀)))
+ (AddCommGrp.ofHom (hS.extClass.postcomp X h)) (by
+ ext x
+ dsimp [AddCommGrp.ofHom]
+ simp only [comp_assoc_of_second_deg_zero, ShortComplex.ShortExact.comp_extClass,
+ comp_zero]
+ rfl)).Exact := by
+ letI := HasDerivedCategory.standard C
+ have := (preadditiveCoyoneda.obj (op ((singleFunctor C 0).obj X))).homologySequence_exact₃ _
+ (hS.singleTriangle_distinguished) n₀ n₁ (by omega)
+ rw [ShortComplex.ab_exact_iff_function_exact] at this ⊢
+ apply Function.Exact.of_ladder_addEquiv_of_exact' (e₁ := Ext.homAddEquiv)
+ (e₂ := Ext.homAddEquiv) (e₃ := Ext.homAddEquiv) (H := this)
+ · ext x; apply hom_comp_singleFunctor_map_shift (C := C)
+ · ext x
+ exact preadditiveCoyoneda_homologySequenceδ_singleTriangle_apply hS x h
+
+/-- Alternative formulation of `covariant_sequence_exact₁` -/
+lemma covariant_sequence_exact₁' :
+ (ShortComplex.mk
+ (AddCommGrp.ofHom (hS.extClass.postcomp X h))
+ (AddCommGrp.ofHom ((mk₀ S.f).postcomp X (add_zero n₁))) (by
+ ext x
+ dsimp [AddCommGrp.ofHom]
+ simp only [comp_assoc_of_third_deg_zero, ShortComplex.ShortExact.extClass_comp, comp_zero]
+ rfl)).Exact := by
+ letI := HasDerivedCategory.standard C
+ have := (preadditiveCoyoneda.obj (op ((singleFunctor C 0).obj X))).homologySequence_exact₁ _
+ (hS.singleTriangle_distinguished) n₀ n₁ (by omega)
+ rw [ShortComplex.ab_exact_iff_function_exact] at this ⊢
+ apply Function.Exact.of_ladder_addEquiv_of_exact' (e₁ := Ext.homAddEquiv)
+ (e₂ := Ext.homAddEquiv) (e₃ := Ext.homAddEquiv) (H := this)
+ · ext x
+ exact preadditiveCoyoneda_homologySequenceδ_singleTriangle_apply hS x h
+ · ext x; apply hom_comp_singleFunctor_map_shift (C := C)
+
+open ComposableArrows
+
+/-- Given a short exact short complex `S` in an abelian category `C` and an object `X : C`,
+this is the long exact sequence
+`Ext X S.X₁ n₀ → Ext X S.X₂ n₀ → Ext X S.X₃ n₀ → Ext X S.X₁ n₁ → Ext X S.X₂ n₁ → Ext X S.X₃ n₁`
+when `n₀ + 1 = n₁` -/
+noncomputable def covariantSequence : ComposableArrows AddCommGrp.{w} 5 :=
+ mk₅ (AddCommGrp.ofHom ((mk₀ S.f).postcomp X (add_zero n₀)))
+ (AddCommGrp.ofHom ((mk₀ S.g).postcomp X (add_zero n₀)))
+ (AddCommGrp.ofHom (hS.extClass.postcomp X h))
+ (AddCommGrp.ofHom ((mk₀ S.f).postcomp X (add_zero n₁)))
+ (AddCommGrp.ofHom ((mk₀ S.g).postcomp X (add_zero n₁)))
+
+lemma covariantSequence_exact :
+ (covariantSequence X hS n₀ n₁ h).Exact :=
+ exact_of_δ₀ (covariant_sequence_exact₂' X hS n₀).exact_toComposableArrows
+ (exact_of_δ₀ (covariant_sequence_exact₃' X hS n₀ n₁ h).exact_toComposableArrows
+ (exact_of_δ₀ (covariant_sequence_exact₁' X hS n₀ n₁ h).exact_toComposableArrows
+ (covariant_sequence_exact₂' X hS n₁).exact_toComposableArrows))
+
+end
+
+lemma covariant_sequence_exact₁ {n₁ : ℕ} (x₁ : Ext X S.X₁ n₁)
+ (hx₁ : x₁.comp (mk₀ S.f) (add_zero n₁) = 0) {n₀ : ℕ} (hn₀ : n₀ + 1 = n₁) :
+ ∃ (x₃ : Ext X S.X₃ n₀), x₃.comp hS.extClass hn₀ = x₁ := by
+ have := covariant_sequence_exact₁' X hS n₀ n₁ hn₀
+ rw [ShortComplex.ab_exact_iff] at this
+ exact this x₁ hx₁
+
+include hS in
+lemma covariant_sequence_exact₂ {n : ℕ} (x₂ : Ext X S.X₂ n)
+ (hx₂ : x₂.comp (mk₀ S.g) (add_zero n) = 0) :
+ ∃ (x₁ : Ext X S.X₁ n), x₁.comp (mk₀ S.f) (add_zero n) = x₂ := by
+ have := covariant_sequence_exact₂' X hS n
+ rw [ShortComplex.ab_exact_iff] at this
+ exact this x₂ hx₂
+
+lemma covariant_sequence_exact₃ {n₀ : ℕ} (x₃ : Ext X S.X₃ n₀) {n₁ : ℕ} (hn₁ : n₀ + 1 = n₁)
+ (hx₃ : x₃.comp hS.extClass hn₁ = 0) :
+ ∃ (x₂ : Ext X S.X₂ n₀), x₂.comp (mk₀ S.g) (add_zero n₀) = x₃ := by
+ have := covariant_sequence_exact₃' X hS n₀ n₁ hn₁
+ rw [ShortComplex.ab_exact_iff] at this
+ exact this x₃ hx₃
+
+end CovariantSequence
+
+end Ext
+
+end Abelian
+
+end CategoryTheory
diff --git a/Mathlib/Algebra/Homology/DerivedCategory/Ext/ExtClass.lean b/Mathlib/Algebra/Homology/DerivedCategory/Ext/ExtClass.lean
index 9a636124ff714..2869c7955e0c0 100644
--- a/Mathlib/Algebra/Homology/DerivedCategory/Ext/ExtClass.lean
+++ b/Mathlib/Algebra/Homology/DerivedCategory/Ext/ExtClass.lean
@@ -29,6 +29,8 @@ namespace ShortComplex
variable (S : ShortComplex C)
+lemma ext_mk₀_f_comp_ext_mk₀_g : (Ext.mk₀ S.f).comp (Ext.mk₀ S.g) (zero_add 0) = 0 := by simp
+
namespace ShortExact
variable {S}
diff --git a/Mathlib/Algebra/Homology/DifferentialObject.lean b/Mathlib/Algebra/Homology/DifferentialObject.lean
index cd85f3f0e9e6c..d1b9484894419 100644
--- a/Mathlib/Algebra/Homology/DifferentialObject.lean
+++ b/Mathlib/Algebra/Homology/DifferentialObject.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Homology.HomologicalComplex
import Mathlib.CategoryTheory.DifferentialObject
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 c693b7880842a..634f2df3056f2 100644
--- a/Mathlib/Algebra/Homology/HomologicalBicomplex.lean
+++ b/Mathlib/Algebra/Homology/HomologicalBicomplex.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Joël Riou
+Authors: Kim Morrison, Joël Riou
-/
import Mathlib.Algebra.Homology.HomologicalComplex
@@ -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. -/
@@ -205,7 +205,7 @@ def XXIsoOfEq {x₁ y₁ : I₁} (h₁ : x₁ = y₁) {x₂ y₂ : I₂} (h₂ :
@[simp]
lemma XXIsoOfEq_rfl (i₁ : I₁) (i₂ : I₂) :
- K.XXIsoOfEq (rfl : i₁ = i₁) (rfl : i₂ = i₂) = Iso.refl _ := rfl
+ K.XXIsoOfEq _ _ _ (rfl : i₁ = i₁) (rfl : i₂ = i₂) = Iso.refl _ := rfl
end HomologicalComplex₂
diff --git a/Mathlib/Algebra/Homology/HomologicalComplex.lean b/Mathlib/Algebra/Homology/HomologicalComplex.lean
index 59f2a43f6c5a1..03b17997ea652 100644
--- a/Mathlib/Algebra/Homology/HomologicalComplex.lean
+++ b/Mathlib/Algebra/Homology/HomologicalComplex.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison
+Authors: Johan Commelin, Kim Morrison
-/
import Mathlib.Algebra.Homology.ComplexShape
import Mathlib.CategoryTheory.Subobject.Limits
@@ -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 4ee6bcba875ef..82243da05a6b3 100644
--- a/Mathlib/Algebra/Homology/Homotopy.lean
+++ b/Mathlib/Algebra/Homology/Homotopy.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Homology.Linear
import Mathlib.Algebra.Homology.ShortComplex.HomologicalComplex
@@ -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.lean b/Mathlib/Algebra/Homology/HomotopyCategory.lean
index a938f482ae5ea..93400ddd35d94 100644
--- a/Mathlib/Algebra/Homology/HomotopyCategory.lean
+++ b/Mathlib/Algebra/Homology/HomotopyCategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Homology.Homotopy
import Mathlib.Algebra.Homology.Linear
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/ImageToKernel.lean b/Mathlib/Algebra/Homology/ImageToKernel.lean
index 0924d56092539..16f064b89a76f 100644
--- a/Mathlib/Algebra/Homology/ImageToKernel.lean
+++ b/Mathlib/Algebra/Homology/ImageToKernel.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Subobject.Limits
diff --git a/Mathlib/Algebra/Homology/LocalCohomology.lean b/Mathlib/Algebra/Homology/LocalCohomology.lean
index e6bcfa9d338a5..f8d4b17460856 100644
--- a/Mathlib/Algebra/Homology/LocalCohomology.lean
+++ b/Mathlib/Algebra/Homology/LocalCohomology.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2023 Emily Witt. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Emily Witt, Scott Morrison, Jake Levinson, Sam van Gool
+Authors: Emily Witt, Kim Morrison, Jake Levinson, Sam van Gool
-/
import Mathlib.RingTheory.Ideal.Basic
import Mathlib.Algebra.Category.ModuleCat.Colimits
@@ -206,34 +206,21 @@ 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
-- The inclusions `J^n1 ≤ J'` and `J^n2 ≤ J'` always form a triangle, based on
-- which exponent is larger.
rcases le_total (unop j1.left) (unop j2.left) with h | h
- · right; exact ⟨CostructuredArrow.homMk (homOfLE h).op (AsTrue.get trivial)⟩
- · left; exact ⟨CostructuredArrow.homMk (homOfLE h).op (AsTrue.get trivial)⟩
+ · right; exact ⟨CostructuredArrow.homMk (homOfLE h).op rfl⟩
+ · left; exact ⟨CostructuredArrow.homMk (homOfLE h).op rfl⟩
example : HasColimitsOfSize.{0, 0, u, u + 1} (ModuleCat.{u, u} R) := inferInstance
/-- Local cohomology (defined in terms of powers of `J`) agrees with local
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/QuasiIso.lean b/Mathlib/Algebra/Homology/QuasiIso.lean
index dbb3e8cbd051b..47a65f02f7de3 100644
--- a/Mathlib/Algebra/Homology/QuasiIso.lean
+++ b/Mathlib/Algebra/Homology/QuasiIso.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Joël Riou
+Authors: Kim Morrison, Joël Riou
-/
import Mathlib.Algebra.Homology.Homotopy
diff --git a/Mathlib/Algebra/Homology/ShortComplex/Ab.lean b/Mathlib/Algebra/Homology/ShortComplex/Ab.lean
index 8b76e44a2ca8c..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
@@ -109,6 +109,18 @@ lemma ab_exact_iff :
obtain ⟨x₁, rfl⟩ := h x₂ hx₂
exact ⟨x₁, rfl⟩
+lemma ab_exact_iff_function_exact :
+ S.Exact ↔ Function.Exact S.f S.g := by
+ rw [S.ab_exact_iff]
+ apply forall_congr'
+ intro x₂
+ constructor
+ · intro h
+ refine ⟨h, ?_⟩
+ rintro ⟨x₁, rfl⟩
+ simp only [ab_zero_apply]
+ · tauto
+
lemma ab_exact_iff_ker_le_range : S.Exact ↔ S.g.ker ≤ S.f.range := S.ab_exact_iff
lemma ab_exact_iff_range_eq_ker : S.Exact ↔ S.f.range = S.g.ker := by
@@ -117,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/ExactFunctor.lean b/Mathlib/Algebra/Homology/ShortComplex/ExactFunctor.lean
index 974a1c8685585..d61079ee62930 100644
--- a/Mathlib/Algebra/Homology/ShortComplex/ExactFunctor.lean
+++ b/Mathlib/Algebra/Homology/ShortComplex/ExactFunctor.lean
@@ -116,7 +116,7 @@ lemma preservesFiniteLimits_tfae : List.TFAE
Nonempty <| PreservesFiniteLimits F
] := by
tfae_have 1 → 2
- · rintro hF S ⟨hS, hf⟩
+ | hF, S, ⟨hS, hf⟩ => by
have := preservesMonomorphisms_of_preserves_shortExact_left F hF
refine ⟨?_, inferInstance⟩
let T := ShortComplex.mk S.f (Abelian.coimage.π S.g) (Abelian.comp_coimage_π_eq_zero S.zero)
@@ -129,7 +129,7 @@ lemma preservesFiniteLimits_tfae : List.TFAE
exact (exact_iff_of_epi_of_isIso_of_mono φ).1 (hF T ⟨(S.exact_iff_exact_coimage_π).1 hS⟩).1
tfae_have 2 → 3
- · intro hF X Y f
+ | hF, X, Y, f => by
refine ⟨preservesLimitOfPreservesLimitCone (kernelIsKernel f) ?_⟩
apply (KernelFork.isLimitMapConeEquiv _ F).2
let S := ShortComplex.mk _ _ (kernel.condition f)
@@ -138,13 +138,13 @@ lemma preservesFiniteLimits_tfae : List.TFAE
exact hS.1.fIsKernel
tfae_have 3 → 4
- · intro hF
+ | hF => by
have := fun X Y (f : X ⟶ Y) ↦ (hF f).some
exact ⟨preservesFiniteLimitsOfPreservesKernels F⟩
tfae_have 4 → 1
- · rintro ⟨_⟩ S hS
- exact (S.map F).exact_and_mono_f_iff_f_is_kernel |>.2 ⟨KernelFork.mapIsLimit _ hS.fIsKernel F⟩
+ | ⟨_⟩, S, hS =>
+ (S.map F).exact_and_mono_f_iff_f_is_kernel |>.2 ⟨KernelFork.mapIsLimit _ hS.fIsKernel F⟩
tfae_finish
@@ -175,7 +175,7 @@ lemma preservesFiniteColimits_tfae : List.TFAE
Nonempty <| PreservesFiniteColimits F
] := by
tfae_have 1 → 2
- · rintro hF S ⟨hS, hf⟩
+ | hF, S, ⟨hS, hf⟩ => by
have := preservesEpimorphisms_of_preserves_shortExact_right F hF
refine ⟨?_, inferInstance⟩
let T := ShortComplex.mk (Abelian.image.ι S.f) S.g (Abelian.image_ι_comp_eq_zero S.zero)
@@ -188,7 +188,7 @@ lemma preservesFiniteColimits_tfae : List.TFAE
exact (exact_iff_of_epi_of_isIso_of_mono φ).2 (hF T ⟨(S.exact_iff_exact_image_ι).1 hS⟩).1
tfae_have 2 → 3
- · intro hF X Y f
+ | hF, X, Y, f => by
refine ⟨preservesColimitOfPreservesColimitCocone (cokernelIsCokernel f) ?_⟩
apply (CokernelCofork.isColimitMapCoconeEquiv _ F).2
let S := ShortComplex.mk _ _ (cokernel.condition f)
@@ -197,14 +197,13 @@ lemma preservesFiniteColimits_tfae : List.TFAE
exact hS.1.gIsCokernel
tfae_have 3 → 4
- · intro hF
+ | hF => by
have := fun X Y (f : X ⟶ Y) ↦ (hF f).some
exact ⟨preservesFiniteColimitsOfPreservesCokernels F⟩
tfae_have 4 → 1
- · rintro ⟨_⟩ S hS
- exact (S.map F).exact_and_epi_g_iff_g_is_cokernel |>.2
- ⟨CokernelCofork.mapIsColimit _ hS.gIsCokernel F⟩
+ | ⟨_⟩, S, hS => (S.map F).exact_and_epi_g_iff_g_is_cokernel |>.2
+ ⟨CokernelCofork.mapIsColimit _ hS.gIsCokernel F⟩
tfae_finish
@@ -224,7 +223,7 @@ lemma exact_tfae : List.TFAE
Nonempty (PreservesFiniteLimits F) ∧ Nonempty (PreservesFiniteColimits F)
] := by
tfae_have 1 → 3
- · intro hF
+ | hF => by
refine ⟨fun {X Y} f ↦ ?_, fun {X Y} f ↦ ?_⟩
· have h := (preservesFiniteLimits_tfae F |>.out 0 2 |>.1 fun S hS ↦
And.intro (hF S hS).exact (hF S hS).mono_f)
@@ -234,7 +233,7 @@ lemma exact_tfae : List.TFAE
exact h f |>.some
tfae_have 2 → 1
- · intro hF S hS
+ | hF, S, hS => by
have : Mono (S.map F).f := exact_iff_mono _ (by simp) |>.1 <|
hF (.mk (0 : 0 ⟶ S.X₁) S.f <| by simp) (exact_iff_mono _ (by simp) |>.2 hS.mono_f)
have : Epi (S.map F).g := exact_iff_epi _ (by simp) |>.1 <|
@@ -242,13 +241,11 @@ lemma exact_tfae : List.TFAE
exact ⟨hF S hS.exact⟩
tfae_have 3 → 4
- · rintro ⟨h⟩
- exact ⟨⟨preservesFiniteLimitsOfPreservesHomology F⟩,
- ⟨preservesFiniteColimitsOfPreservesHomology F⟩⟩
+ | ⟨h⟩ => ⟨⟨preservesFiniteLimitsOfPreservesHomology F⟩,
+ ⟨preservesFiniteColimitsOfPreservesHomology F⟩⟩
tfae_have 4 → 2
- · rintro ⟨⟨h1⟩, ⟨h2⟩⟩
- exact fun _ h ↦ h.map F
+ | ⟨⟨h1⟩, ⟨h2⟩⟩, _, h => h.map F
tfae_finish
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 833e8089b75d2..a9cbef23cd3c9 100644
--- a/Mathlib/Algebra/Homology/Single.lean
+++ b/Mathlib/Algebra/Homology/Single.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Homology.HomologicalComplex
@@ -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/Homology/TotalComplex.lean b/Mathlib/Algebra/Homology/TotalComplex.lean
index 73fb3959181c0..645d747de064f 100644
--- a/Mathlib/Algebra/Homology/TotalComplex.lean
+++ b/Mathlib/Algebra/Homology/TotalComplex.lean
@@ -260,7 +260,7 @@ noncomputable def ιTotal (i₁ : I₁) (i₂ : I₂) (i₁₂ : I₁₂)
@[reassoc (attr := simp)]
lemma XXIsoOfEq_hom_ιTotal {x₁ y₁ : I₁} (h₁ : x₁ = y₁) {x₂ y₂ : I₂} (h₂ : x₂ = y₂)
(i₁₂ : I₁₂) (h : ComplexShape.π c₁ c₂ c₁₂ (y₁, y₂) = i₁₂) :
- (K.XXIsoOfEq h₁ h₂).hom ≫ K.ιTotal c₁₂ y₁ y₂ i₁₂ h =
+ (K.XXIsoOfEq _ _ _ h₁ h₂).hom ≫ K.ιTotal c₁₂ y₁ y₂ i₁₂ h =
K.ιTotal c₁₂ x₁ x₂ i₁₂ (by rw [h₁, h₂, h]) := by
subst h₁ h₂
simp
@@ -268,7 +268,7 @@ lemma XXIsoOfEq_hom_ιTotal {x₁ y₁ : I₁} (h₁ : x₁ = y₁) {x₂ y₂ :
@[reassoc (attr := simp)]
lemma XXIsoOfEq_inv_ιTotal {x₁ y₁ : I₁} (h₁ : x₁ = y₁) {x₂ y₂ : I₂} (h₂ : x₂ = y₂)
(i₁₂ : I₁₂) (h : ComplexShape.π c₁ c₂ c₁₂ (x₁, x₂) = i₁₂) :
- (K.XXIsoOfEq h₁ h₂).inv ≫ K.ιTotal c₁₂ x₁ x₂ i₁₂ h =
+ (K.XXIsoOfEq _ _ _ h₁ h₂).inv ≫ K.ιTotal c₁₂ x₁ x₂ i₁₂ h =
K.ιTotal c₁₂ y₁ y₂ i₁₂ (by rw [← h, h₁, h₂]) := by
subst h₁ h₂
simp
diff --git a/Mathlib/Algebra/Homology/TotalComplexShift.lean b/Mathlib/Algebra/Homology/TotalComplexShift.lean
index 8d32945310df2..345677aa57934 100644
--- a/Mathlib/Algebra/Homology/TotalComplexShift.lean
+++ b/Mathlib/Algebra/Homology/TotalComplexShift.lean
@@ -129,7 +129,7 @@ noncomputable def totalShift₁XIso (n n' : ℤ) (h : n + x = n') :
(((shiftFunctor₁ C x).obj K).total (up ℤ)).X n ≅ (K.total (up ℤ)).X n' where
hom := totalDesc _ (fun p q hpq => K.ιTotal (up ℤ) (p + x) q n' (by dsimp at hpq ⊢; omega))
inv := totalDesc _ (fun p q hpq =>
- (K.XXIsoOfEq (Int.sub_add_cancel p x) rfl).inv ≫
+ (K.XXIsoOfEq _ _ _ (Int.sub_add_cancel p x) rfl).inv ≫
((shiftFunctor₁ C x).obj K).ιTotal (up ℤ) (p - x) q n
(by dsimp at hpq ⊢; omega))
hom_inv_id := by
@@ -235,7 +235,7 @@ noncomputable def totalShift₂XIso (n n' : ℤ) (h : n + y = n') :
hom := totalDesc _ (fun p q hpq => (p * y).negOnePow • K.ιTotal (up ℤ) p (q + y) n'
(by dsimp at hpq ⊢; omega))
inv := totalDesc _ (fun p q hpq => (p * y).negOnePow •
- (K.XXIsoOfEq rfl (Int.sub_add_cancel q y)).inv ≫
+ (K.XXIsoOfEq _ _ _ rfl (Int.sub_add_cancel q y)).inv ≫
((shiftFunctor₂ C y).obj K).ιTotal (up ℤ) p (q - y) n (by dsimp at hpq ⊢; omega))
hom_inv_id := by
ext p q h
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/Abelian.lean b/Mathlib/Algebra/Lie/Abelian.lean
index 9d26a486b09c5..1c88f3135e544 100644
--- a/Mathlib/Algebra/Lie/Abelian.lean
+++ b/Mathlib/Algebra/Lie/Abelian.lean
@@ -201,20 +201,21 @@ def maxTrivLinearMapEquivLieModuleHom : maxTrivSubmodule R L (M →ₗ[R] N) ≃
@[simp]
theorem coe_maxTrivLinearMapEquivLieModuleHom (f : maxTrivSubmodule R L (M →ₗ[R] N)) :
- (maxTrivLinearMapEquivLieModuleHom f : M → N) = f := by ext; rfl
+ (maxTrivLinearMapEquivLieModuleHom (M := M) (N := N) f : M → N) = f := by ext; rfl
@[simp]
theorem coe_maxTrivLinearMapEquivLieModuleHom_symm (f : M →ₗ⁅R,L⁆ N) :
- (maxTrivLinearMapEquivLieModuleHom.symm f : M → N) = f :=
+ (maxTrivLinearMapEquivLieModuleHom (M := M) (N := N) |>.symm f : M → N) = f :=
rfl
@[simp]
theorem coe_linearMap_maxTrivLinearMapEquivLieModuleHom (f : maxTrivSubmodule R L (M →ₗ[R] N)) :
- (maxTrivLinearMapEquivLieModuleHom f : M →ₗ[R] N) = (f : M →ₗ[R] N) := by ext; rfl
+ (maxTrivLinearMapEquivLieModuleHom (M := M) (N := N) f : M →ₗ[R] N) = (f : M →ₗ[R] N) := by
+ ext; rfl
@[simp]
theorem coe_linearMap_maxTrivLinearMapEquivLieModuleHom_symm (f : M →ₗ⁅R,L⁆ N) :
- (maxTrivLinearMapEquivLieModuleHom.symm f : M →ₗ[R] N) = (f : M →ₗ[R] N) :=
+ (maxTrivLinearMapEquivLieModuleHom (M := M) (N := N) |>.symm f : M →ₗ[R] N) = (f : M →ₗ[R] N) :=
rfl
end LieModule
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/Basic.lean b/Mathlib/Algebra/Lie/Basic.lean
index 40207bffb861a..cb37eac2841ca 100644
--- a/Mathlib/Algebra/Lie/Basic.lean
+++ b/Mathlib/Algebra/Lie/Basic.lean
@@ -269,10 +269,10 @@ attribute [coe] LieHom.toLinearMap
instance : Coe (L₁ →ₗ⁅R⁆ L₂) (L₁ →ₗ[R] L₂) :=
⟨LieHom.toLinearMap⟩
-instance : FunLike (L₁ →ₗ⁅R⁆ L₂) L₁ L₂ :=
- { coe := fun f => f.toFun,
- coe_injective' := fun x y h =>
- by cases x; cases y; simp at h; simp [h] }
+instance : FunLike (L₁ →ₗ⁅R⁆ L₂) L₁ L₂ where
+ coe f := f.toFun
+ coe_injective' x y h := by
+ cases x; cases y; simp at h; simp [h]
initialize_simps_projections LieHom (toFun → apply)
@@ -471,13 +471,12 @@ instance hasCoeToLieHom : Coe (L₁ ≃ₗ⁅R⁆ L₂) (L₁ →ₗ⁅R⁆ L₂
instance hasCoeToLinearEquiv : Coe (L₁ ≃ₗ⁅R⁆ L₂) (L₁ ≃ₗ[R] L₂) :=
⟨toLinearEquiv⟩
-instance : EquivLike (L₁ ≃ₗ⁅R⁆ L₂) L₁ L₂ :=
- { coe := fun f => f.toFun,
- inv := fun f => f.invFun,
- left_inv := fun f => f.left_inv,
- right_inv := fun f => f.right_inv,
- coe_injective' := fun f g h₁ h₂ =>
- by cases f; cases g; simp at h₁ h₂; simp [*] }
+instance : EquivLike (L₁ ≃ₗ⁅R⁆ L₂) L₁ L₂ where
+ coe f := f.toFun
+ inv f := f.invFun
+ left_inv f := f.left_inv
+ right_inv f := f.right_inv
+ coe_injective' f g h₁ h₂ := by cases f; cases g; simp at h₁ h₂; simp [*]
theorem coe_to_lieHom (e : L₁ ≃ₗ⁅R⁆ L₂) : ⇑(e : L₁ →ₗ⁅R⁆ L₂) = e :=
rfl
@@ -622,10 +621,9 @@ attribute [coe] LieModuleHom.toLinearMap
instance : CoeOut (M →ₗ⁅R,L⁆ N) (M →ₗ[R] N) :=
⟨LieModuleHom.toLinearMap⟩
-instance : FunLike (M →ₗ⁅R, L⁆ N) M N :=
- { coe := fun f => f.toFun,
- coe_injective' := fun x y h =>
- by cases x; cases y; simp at h; simp [h] }
+instance : FunLike (M →ₗ⁅R, L⁆ N) M N where
+ coe f := f.toFun
+ coe_injective' x y h := by cases x; cases y; simp at h; simp [h]
initialize_simps_projections LieModuleHom (toFun → apply)
@@ -855,13 +853,12 @@ instance hasCoeToLieModuleHom : Coe (M ≃ₗ⁅R,L⁆ N) (M →ₗ⁅R,L⁆ N)
instance hasCoeToLinearEquiv : CoeOut (M ≃ₗ⁅R,L⁆ N) (M ≃ₗ[R] N) :=
⟨toLinearEquiv⟩
-instance : EquivLike (M ≃ₗ⁅R,L⁆ N) M N :=
- { coe := fun f => f.toFun,
- inv := fun f => f.invFun,
- left_inv := fun f => f.left_inv,
- right_inv := fun f => f.right_inv,
- coe_injective' := fun f g h₁ h₂ =>
- by cases f; cases g; simp at h₁ h₂; simp [*] }
+instance : EquivLike (M ≃ₗ⁅R,L⁆ N) M N where
+ coe f := f.toFun
+ inv f := f.invFun
+ left_inv f := f.left_inv
+ right_inv f := f.right_inv
+ coe_injective' f g h₁ h₂ := by cases f; cases g; simp at h₁ h₂; simp [*]
@[simp] lemma coe_coe (e : M ≃ₗ⁅R,L⁆ N) : ⇑(e : M →ₗ⁅R,L⁆ N) = e := rfl
diff --git a/Mathlib/Algebra/Lie/CartanExists.lean b/Mathlib/Algebra/Lie/CartanExists.lean
index bbdbc280d8416..5ee149734e3b5 100644
--- a/Mathlib/Algebra/Lie/CartanExists.lean
+++ b/Mathlib/Algebra/Lie/CartanExists.lean
@@ -39,7 +39,7 @@ variable [Module.Finite K L]
variable [Module.Finite R L] [Module.Free R L]
variable [Module.Finite R M] [Module.Free R M]
-open FiniteDimensional LieSubalgebra Module.Free Polynomial
+open Module LieSubalgebra Module.Free Polynomial
variable (K)
@@ -117,7 +117,7 @@ section Field
variable {K L : Type*} [Field K] [LieRing L] [LieAlgebra K L] [Module.Finite K L]
-open FiniteDimensional LieSubalgebra LieSubmodule Polynomial Cardinal LieModule engel_isBot_of_isMin
+open Module LieSubalgebra LieSubmodule Polynomial Cardinal LieModule engel_isBot_of_isMin
#adaptation_note /-- otherwise there is a spurious warning on `contrapose!` below. -/
set_option linter.unusedVariables false in
@@ -164,13 +164,6 @@ lemma engel_isBot_of_isMin (hLK : finrank K L ≤ #K) (U : LieSubalgebra K L)
-- viewed as endomorphism of `E`. Note that `χ` is polynomial in its argument `r`.
-- Similarly: `ψ r` is the characteristic polynomial of `⁅r • u + x, _⁆`
-- viewed as endomorphism of `Q`. Note that `ψ` is polynomial in its argument `r`.
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- letI := E.instLieRingModuleSubtypeMemSubmodule
- letI : LieModule K U E := LieSubmodule.instLieModule E
let χ : Polynomial (K[X]) := lieCharpoly K E x' u
let ψ : Polynomial (K[X]) := lieCharpoly K Q x' u
-- It suffices to show that `χ` is the monomial `X ^ r`.
@@ -217,7 +210,7 @@ lemma engel_isBot_of_isMin (hLK : finrank K L ≤ #K) (U : LieSubalgebra K L)
obtain hz₀|hz₀ := eq_or_ne z 0
· -- If `z = 0`, then `⁅α • u + x, x⁆` vanishes and we use our assumption `x ≠ 0`.
refine ⟨⟨x, self_mem_engel K x⟩, ?_, ?_⟩
- · simpa [coe_bracket_of_module, ne_eq, Submodule.mk_eq_zero] using hx₀
+ · exact Subtype.coe_ne_coe.mp hx₀
· dsimp only [z] at hz₀
simp only [coe_bracket_of_module, hz₀, LieHom.map_zero, LinearMap.zero_apply]
-- If `z ≠ 0`, then `⁅α • u + x, z⁆` vanishes per axiom of Lie algebras
@@ -367,7 +360,7 @@ lemma exists_isCartanSubalgebra_engel_of_finrank_le_card (h : finrank K L ≤ #K
suffices finrank K (engel K x) ≤ finrank K (engel K y) by
suffices engel K y = engel K x from this.ge
apply LieSubalgebra.to_submodule_injective
- exact eq_of_le_of_finrank_le hyx this
+ exact Submodule.eq_of_le_of_finrank_le hyx this
rw [(isRegular_iff_finrank_engel_eq_rank K x).mp hx]
apply rank_le_finrank_engel
diff --git a/Mathlib/Algebra/Lie/CartanSubalgebra.lean b/Mathlib/Algebra/Lie/CartanSubalgebra.lean
index f5d08788b2163..c904d1921c59f 100644
--- a/Mathlib/Algebra/Lie/CartanSubalgebra.lean
+++ b/Mathlib/Algebra/Lie/CartanSubalgebra.lean
@@ -107,7 +107,7 @@ end LieSubalgebra
theorem LieIdeal.normalizer_eq_top {R : Type u} {L : Type v} [CommRing R] [LieRing L]
[LieAlgebra R L] (I : LieIdeal R L) : (I : LieSubalgebra R L).normalizer = ⊤ := by
ext x
- simpa only [LieSubalgebra.mem_normalizer_iff, LieSubalgebra.mem_top, iff_true_iff] using
+ simpa only [LieSubalgebra.mem_normalizer_iff, LieSubalgebra.mem_top, iff_true] using
fun y hy => I.lie_mem hy
open LieIdeal
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 0d155c7a5b6fe..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]
@@ -120,6 +120,30 @@ theorem ext_of_lieSpan_eq_top (s : Set L) (hs : LieSubalgebra.lieSpan R L s =
(h : Set.EqOn D1 D2 s) : D1 = D2 :=
ext fun _ => eqOn_lieSpan h <| hs.symm ▸ trivial
+section
+
+open Finset Nat
+
+/-- The general Leibniz rule for Lie derivatives. -/
+theorem iterate_apply_lie (D : LieDerivation R L L) (n : ℕ) (a b : L) :
+ D^[n] ⁅a, b⁆ = ∑ ij in antidiagonal n, choose n ij.1 • ⁅D^[ij.1] a, D^[ij.2] b⁆ := by
+ induction n with
+ | zero => simp
+ | succ n ih =>
+ rw [sum_antidiagonal_choose_succ_nsmul (M := L) (fun i j => ⁅D^[i] a, D^[j] b⁆) n]
+ simp only [Function.iterate_succ_apply', ih, map_sum, map_nsmul, apply_lie_eq_add, smul_add,
+ sum_add_distrib, add_right_inj]
+ refine sum_congr rfl fun ⟨i, j⟩ hij ↦ ?_
+ rw [n.choose_symm_of_eq_add (mem_antidiagonal.1 hij).symm]
+
+/-- Alternate version of the general Leibniz rule for Lie derivatives. -/
+theorem iterate_apply_lie' (D : LieDerivation R L L) (n : ℕ) (a b : L) :
+ D^[n] ⁅a, b⁆ = ∑ i in range (n + 1), n.choose i • ⁅D^[i] a, D^[n - i] b⁆ := by
+ rw [iterate_apply_lie D n a b]
+ exact sum_antidiagonal_eq_sum_range_succ (fun i j ↦ n.choose i • ⁅D^[i] a, D^[j] b⁆) n
+
+end
+
instance instZero : Zero (LieDerivation R L M) where
zero :=
{ toLinearMap := 0
diff --git a/Mathlib/Algebra/Lie/Derivation/Killing.lean b/Mathlib/Algebra/Lie/Derivation/Killing.lean
index f7aca54a214c2..65e346eb954d5 100644
--- a/Mathlib/Algebra/Lie/Derivation/Killing.lean
+++ b/Mathlib/Algebra/Lie/Derivation/Killing.lean
@@ -86,16 +86,10 @@ instance instIsKilling_range_ad : LieAlgebra.IsKilling R 𝕀 :=
/-- The restriction of the Killing form of a finite-dimensional Killing Lie algebra to the range of
the adjoint action is nondegenerate. -/
-lemma killingForm_restrict_range_ad_nondegenerate : ((killingForm R 𝔻).restrict 𝕀).Nondegenerate :=
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- letI := LieDerivation.IsKilling.instIsKilling_range_ad R L
- letI := LieSubalgebra.lieAlgebra R (LieDerivation R L L) (LieDerivation.ad R L).range
- letI := LieSubalgebra.lieRing R (LieDerivation R L L) (LieDerivation.ad R L).range
- killingForm_restrict_range_ad R L ▸ LieAlgebra.IsKilling.killingForm_nondegenerate R _
+lemma killingForm_restrict_range_ad_nondegenerate :
+ ((killingForm R 𝔻).restrict 𝕀).Nondegenerate := by
+ convert LieAlgebra.IsKilling.killingForm_nondegenerate R 𝕀
+ exact killingForm_restrict_range_ad R L
/-- The range of the adjoint action on a finite-dimensional Killing Lie algebra is full. -/
@[simp]
diff --git a/Mathlib/Algebra/Lie/DirectSum.lean b/Mathlib/Algebra/Lie/DirectSum.lean
index f4d73a8802ef0..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]
@@ -229,20 +229,10 @@ variable {L : Type w} [LieRing L] [LieAlgebra R L] (I : ι → LieIdeal R L)
[this Zulip thread](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/
Typeclass.20resolution.20under.20binders/near/245151099). -/
instance lieRingOfIdeals : LieRing (⨁ i, I i) :=
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- letI : (i : ι) → LieRing (I i) := fun _ => LieIdeal.lieRing ..
DirectSum.lieRing fun i => ↥(I i)
/-- See `DirectSum.lieRingOfIdeals` comment. -/
instance lieAlgebraOfIdeals : LieAlgebra R (⨁ i, I i) :=
- #adaptation_note /-- After lean4#5020, many instances for Lie algebras and manifolds are no
- longer found. -/
- letI : (i : ι) → LieAlgebra R (I i) := fun _ => LieIdeal.lieAlgebra ..
- letI : (i : ι) → LieRing (I i) := fun _ => LieIdeal.lieRing ..
DirectSum.lieAlgebra fun i => ↥(I i)
end Ideals
diff --git a/Mathlib/Algebra/Lie/EngelSubalgebra.lean b/Mathlib/Algebra/Lie/EngelSubalgebra.lean
index 031da676554e7..6720922dae1f2 100644
--- a/Mathlib/Algebra/Lie/EngelSubalgebra.lean
+++ b/Mathlib/Algebra/Lie/EngelSubalgebra.lean
@@ -113,12 +113,6 @@ lemma normalizer_eq_self_of_engel_le [IsArtinian R L]
rwa [← lie_skew, neg_mem_iff (G := L)]
have aux₂ : ∀ n ∈ N, ⁅x, n⁆ ∈ N := fun n hn ↦ le_normalizer H (aux₁ _ hn)
let dx : N →ₗ[R] N := (ad R L x).restrict aux₂
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- have : IsArtinian R { x // x ∈ N } := isArtinian_submodule' _
obtain ⟨k, hk⟩ : ∃ a, ∀ b ≥ a, Codisjoint (LinearMap.ker (dx ^ b)) (LinearMap.range (dx ^ b)) :=
eventually_atTop.mp <| dx.eventually_codisjoint_ker_pow_range_pow
specialize hk (k+1) (Nat.le_add_right k 1)
@@ -133,8 +127,9 @@ lemma normalizer_eq_self_of_engel_le [IsArtinian R L]
clear hk; revert hy
generalize k+1 = k
induction k generalizing y with
- | zero => cases y; intro hy; simp only [pow_zero, LinearMap.one_apply]; exact
- (AddSubmonoid.mk_eq_zero N.toAddSubmonoid).mp hy
+ | zero =>
+ cases y; intro hy; simp only [pow_zero, LinearMap.one_apply]
+ exact (AddSubmonoid.mk_eq_zero N.toAddSubmonoid).mp hy
| succ k ih => simp only [pow_succ, LinearMap.mem_ker, LinearMap.mul_apply] at ih ⊢; apply ih
· rw [← Submodule.map_le_iff_le_comap]
apply le_sup_of_le_right
@@ -142,7 +137,7 @@ lemma normalizer_eq_self_of_engel_le [IsArtinian R L]
rintro _ ⟨y, rfl⟩
simp only [pow_succ', LinearMap.mul_apply, Submodule.mem_comap, mem_coe_submodule]
apply aux₁
- simp only [Submodule.coeSubtype, SetLike.coe_mem]
+ simp only [Submodule.coe_subtype, SetLike.coe_mem]
/-- A Lie subalgebra of a Noetherian Lie algebra is nilpotent
if it is contained in the Engel subalgebra of all its elements. -/
diff --git a/Mathlib/Algebra/Lie/IdealOperations.lean b/Mathlib/Algebra/Lie/IdealOperations.lean
index 99a95d581f6e3..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']
@@ -213,12 +213,6 @@ theorem map_bracket_eq [LieModule R L M] : map f ⁅I, N⁆ = ⁅I, map f N⁆ :
exact ⟨x, ⟨f n, (mem_map (f n)).mpr ⟨n, hn, rfl⟩⟩, hm⟩
· rintro ⟨x, ⟨m₂, hm₂ : m₂ ∈ map f N⟩, rfl⟩
obtain ⟨n, hn, rfl⟩ := (mem_map m₂).mp hm₂
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- letI : Bracket I M := LieRingModule.toBracket
exact ⟨⁅x, n⁆, ⟨x, ⟨n, hn⟩, rfl⟩, by simp⟩
theorem comap_bracket_eq [LieModule R L M] (hf₁ : f.ker = ⊥) (hf₂ : N₂ ≤ f.range) :
@@ -281,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/InvariantForm.lean b/Mathlib/Algebra/Lie/InvariantForm.lean
index dea6e6da8c49d..e95fdc8b0f1bf 100644
--- a/Mathlib/Algebra/Lie/InvariantForm.lean
+++ b/Mathlib/Algebra/Lie/InvariantForm.lean
@@ -124,14 +124,14 @@ variable (hΦ_inv : Φ.lieInvariant L) (hΦ_refl : Φ.IsRefl)
variable (hL : ∀ I : LieIdeal K L, IsAtom I → ¬IsLieAbelian I)
include hΦ_nondeg hΦ_refl hL
-open FiniteDimensional Submodule in
+open Module Submodule in
lemma orthogonal_isCompl_coe_submodule (I : LieIdeal K L) (hI : IsAtom I) :
IsCompl I.toSubmodule (orthogonal Φ hΦ_inv I).toSubmodule := by
rw [orthogonal_toSubmodule, LinearMap.BilinForm.isCompl_orthogonal_iff_disjoint hΦ_refl,
← orthogonal_toSubmodule _ hΦ_inv, ← LieSubmodule.disjoint_iff_coe_toSubmodule]
exact orthogonal_disjoint Φ hΦ_nondeg hΦ_inv hL I hI
-open FiniteDimensional Submodule in
+open Module Submodule in
lemma orthogonal_isCompl (I : LieIdeal K L) (hI : IsAtom I) :
IsCompl I (orthogonal Φ hΦ_inv I) := by
rw [LieSubmodule.isCompl_iff_coe_toSubmodule]
@@ -151,7 +151,7 @@ lemma restrict_orthogonal_nondegenerate (I : LieIdeal K L) (hI : IsAtom I) :
LinearMap.BilinForm.orthogonal_orthogonal hΦ_nondeg hΦ_refl]
exact (orthogonal_isCompl_coe_submodule Φ hΦ_nondeg hΦ_inv hΦ_refl hL I hI).symm
-open FiniteDimensional Submodule in
+open Module Submodule in
lemma atomistic : ∀ I : LieIdeal K L, sSup {J : LieIdeal K L | IsAtom J ∧ J ≤ I} = I := by
intro I
apply le_antisymm
diff --git a/Mathlib/Algebra/Lie/Killing.lean b/Mathlib/Algebra/Lie/Killing.lean
index 45f1f3365045c..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 ⊤ = ⊥
@@ -111,7 +111,7 @@ lemma isKilling_of_equiv [IsKilling R L] (e : L ≃ₗ⁅R⁆ L') : IsKilling R
refine ⟨fun hx' ↦ ?_, fun hx y _ ↦ hx ▸ LinearMap.map_zero₂ (killingForm R L') y⟩
suffices e.symm x' ∈ LinearMap.ker (killingForm R L) by
rw [IsKilling.ker_killingForm_eq_bot] at this
- simpa using (e : L ≃ₗ[R] L').congr_arg this
+ simpa [map_zero] using (e : L ≃ₗ[R] L').congr_arg this
ext y
replace hx' : ∀ y', killingForm R L' x' y' = 0 := by simpa using hx'
specialize hx' (e y)
diff --git a/Mathlib/Algebra/Lie/Nilpotent.lean b/Mathlib/Algebra/Lie/Nilpotent.lean
index fd18eb25f5cf4..84d773813fa84 100644
--- a/Mathlib/Algebra/Lie/Nilpotent.lean
+++ b/Mathlib/Algebra/Lie/Nilpotent.lean
@@ -412,13 +412,6 @@ lemma disjoint_lowerCentralSeries_maxTrivSubmodule_iff [IsNilpotent R L M] :
suffices ¬ Nontrivial (lowerCentralSeriesLast R L M) by
exact this (nontrivial_lowerCentralSeriesLast R L M)
rw [h.eq_bot, le_bot_iff] at this
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- letI unique : Unique (⊥ : LieSubmodule R L M) := Submodule.uniqueBot
- letI subsing : Subsingleton (⊥ : LieSubmodule R L M) := Unique.instSubsingleton
exact this ▸ not_nontrivial _
theorem nontrivial_max_triv_of_isNilpotent [Nontrivial M] [IsNilpotent R L M] :
@@ -595,18 +588,7 @@ theorem LieModule.isNilpotent_of_top_iff :
Equiv.lieModule_isNilpotent_iff LieSubalgebra.topEquiv (1 : M ≃ₗ[R] M) fun _ _ => rfl
@[simp] lemma LieModule.isNilpotent_of_top_iff' :
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- letI : LieRingModule L (⊤ : LieSubmodule R L M) :=
- LieSubmodule.instLieRingModuleSubtypeMemSubmodule ..
IsNilpotent R L {x // x ∈ (⊤ : LieSubmodule R L M)} ↔ IsNilpotent R L M :=
- letI : LieRingModule L (⊤ : LieSubmodule R L M) :=
- LieSubmodule.instLieRingModuleSubtypeMemSubmodule ..
- letI : LieModule R L {x // x ∈ (⊤ : LieSubmodule R L M)} :=
- LieSubmodule.instLieModule ⊤
Equiv.lieModule_isNilpotent_iff 1 (LinearEquiv.ofTop ⊤ rfl) fun _ _ ↦ rfl
end Morphisms
@@ -662,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/NonUnitalNonAssocAlgebra.lean b/Mathlib/Algebra/Lie/NonUnitalNonAssocAlgebra.lean
index b8581efcc454c..124c5f21cd8a8 100644
--- a/Mathlib/Algebra/Lie/NonUnitalNonAssocAlgebra.lean
+++ b/Mathlib/Algebra/Lie/NonUnitalNonAssocAlgebra.lean
@@ -23,7 +23,7 @@ algebra and we provide some basic definitions for doing so here.
## Main definitions
- * `CommutatorRing` turns a Lie ring into a `NonUnitalNonAssocSemiring` by turning its
+ * `CommutatorRing` turns a Lie ring into a `NonUnitalNonAssocRing` by turning its
`Bracket` (denoted `⁅ , ⁆`) into a `Mul` (denoted `*`).
* `LieHom.toNonUnitalAlgHom`
@@ -37,17 +37,17 @@ universe u v w
variable (R : Type u) (L : Type v) [CommRing R] [LieRing L] [LieAlgebra R L]
-/-- Type synonym for turning a `LieRing` into a `NonUnitalNonAssocSemiring`.
+/-- Type synonym for turning a `LieRing` into a `NonUnitalNonAssocRing`.
-A `LieRing` can be regarded as a `NonUnitalNonAssocSemiring` by turning its
+A `LieRing` can be regarded as a `NonUnitalNonAssocRing` by turning its
`Bracket` (denoted `⁅, ⁆`) into a `Mul` (denoted `*`). -/
def CommutatorRing (L : Type v) : Type v := L
-/-- A `LieRing` can be regarded as a `NonUnitalNonAssocSemiring` by turning its
+/-- A `LieRing` can be regarded as a `NonUnitalNonAssocRing` by turning its
`Bracket` (denoted `⁅, ⁆`) into a `Mul` (denoted `*`). -/
-instance : NonUnitalNonAssocSemiring (CommutatorRing L) :=
- show NonUnitalNonAssocSemiring L from
- { (inferInstance : AddCommMonoid L) with
+instance : NonUnitalNonAssocRing (CommutatorRing L) :=
+ show NonUnitalNonAssocRing L from
+ { (inferInstance : AddCommGroup L) with
mul := Bracket.bracket
left_distrib := lie_add
right_distrib := add_lie
@@ -64,11 +64,11 @@ instance : LieRing (CommutatorRing L) := show LieRing L by infer_instance
instance : LieAlgebra R (CommutatorRing L) := show LieAlgebra R L by infer_instance
-/-- Regarding the `LieRing` of a `LieAlgebra` as a `NonUnitalNonAssocSemiring`, we can
+/-- Regarding the `LieRing` of a `LieAlgebra` as a `NonUnitalNonAssocRing`, we can
reinterpret the `smul_lie` law as an `IsScalarTower`. -/
instance isScalarTower : IsScalarTower R (CommutatorRing L) (CommutatorRing L) := ⟨smul_lie⟩
-/-- Regarding the `LieRing` of a `LieAlgebra` as a `NonUnitalNonAssocSemiring`, we can
+/-- Regarding the `LieRing` of a `LieAlgebra` as a `NonUnitalNonAssocRing`, we can
reinterpret the `lie_smul` law as an `SMulCommClass`. -/
instance smulCommClass : SMulCommClass R (CommutatorRing L) (CommutatorRing L) :=
⟨fun t x y => (lie_smul t x y).symm⟩
@@ -80,7 +80,7 @@ namespace LieHom
variable {R L}
variable {L₂ : Type w} [LieRing L₂] [LieAlgebra R L₂]
-/-- Regarding the `LieRing` of a `LieAlgebra` as a `NonUnitalNonAssocSemiring`, we can
+/-- Regarding the `LieRing` of a `LieAlgebra` as a `NonUnitalNonAssocRing`, we can
regard a `LieHom` as a `NonUnitalAlgHom`. -/
@[simps]
def toNonUnitalAlgHom (f : L →ₗ⁅R⁆ L₂) : CommutatorRing L →ₙₐ[R] CommutatorRing L₂ :=
diff --git a/Mathlib/Algebra/Lie/OfAssociative.lean b/Mathlib/Algebra/Lie/OfAssociative.lean
index fbf65f369ddf6..10d1f4dcca458 100644
--- a/Mathlib/Algebra/Lie/OfAssociative.lean
+++ b/Mathlib/Algebra/Lie/OfAssociative.lean
@@ -300,7 +300,10 @@ theorem toEnd_comp_subtype_mem (m : M) (hm : m ∈ (N : Submodule R M)) :
@[simp]
theorem toEnd_restrict_eq_toEnd (h := N.toEnd_comp_subtype_mem x) :
(toEnd R L M x).restrict h = toEnd R L N x := by
- ext; simp only [LinearMap.restrict_apply, toEnd_apply_apply]; rfl
+ ext
+ simp only [LinearMap.restrict_coe_apply, toEnd_apply_apply, ← coe_bracket,
+ SetLike.coe_eq_coe]
+ rfl
lemma mapsTo_pow_toEnd_sub_algebraMap {φ : R} {k : ℕ} {x : L} :
MapsTo ((toEnd R L M x - algebraMap R (Module.End R M) φ) ^ k) N N := by
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/Rank.lean b/Mathlib/Algebra/Lie/Rank.lean
index 3fabb5568a84c..c9c5877344913 100644
--- a/Mathlib/Algebra/Lie/Rank.lean
+++ b/Mathlib/Algebra/Lie/Rank.lean
@@ -65,13 +65,13 @@ lemma rank_eq_natTrailingDegree [Nontrivial R] [DecidableEq ι] :
rank R L M = (polyCharpoly φ b).natTrailingDegree := by
apply nilRank_eq_polyCharpoly_natTrailingDegree
-open FiniteDimensional
+open Module
include bₘ in
lemma rank_le_card [Nontrivial R] : rank R L M ≤ Fintype.card ιₘ :=
nilRank_le_card _ bₘ
-open FiniteDimensional
+open Module
lemma rank_le_finrank [Nontrivial R] : rank R L M ≤ finrank R M :=
nilRank_le_finrank _
@@ -103,7 +103,7 @@ section IsDomain
variable (L)
variable [IsDomain R]
-open Cardinal FiniteDimensional MvPolynomial in
+open Cardinal Module MvPolynomial in
lemma exists_isRegular_of_finrank_le_card (h : finrank R M ≤ #R) :
∃ x : L, IsRegular R M x :=
LinearMap.exists_isNilRegular_of_finrank_le_card _ h
@@ -138,7 +138,7 @@ lemma rank_eq_natTrailingDegree [Nontrivial R] [DecidableEq ι] :
rank R L = (polyCharpoly (ad R L).toLinearMap b).natTrailingDegree := by
apply nilRank_eq_polyCharpoly_natTrailingDegree
-open FiniteDimensional
+open Module
include b in
lemma rank_le_card [Nontrivial R] : rank R L ≤ Fintype.card ι :=
@@ -175,7 +175,7 @@ section IsDomain
variable (L)
variable [IsDomain R]
-open Cardinal FiniteDimensional MvPolynomial in
+open Cardinal Module MvPolynomial in
lemma exists_isRegular_of_finrank_le_card (h : finrank R L ≤ #R) :
∃ x : L, IsRegular R x :=
LinearMap.exists_isNilRegular_of_finrank_le_card _ h
@@ -191,7 +191,7 @@ namespace LieAlgebra
variable (K : Type*) {L : Type*} [Field K] [LieRing L] [LieAlgebra K L] [Module.Finite K L]
-open FiniteDimensional LieSubalgebra
+open Module LieSubalgebra
lemma finrank_engel (x : L) :
finrank K (engel K x) = (ad K L x).charpoly.natTrailingDegree :=
diff --git a/Mathlib/Algebra/Lie/Semisimple/Basic.lean b/Mathlib/Algebra/Lie/Semisimple/Basic.lean
index 7768d66b3c772..ada8114afb6da 100644
--- a/Mathlib/Algebra/Lie/Semisimple/Basic.lean
+++ b/Mathlib/Algebra/Lie/Semisimple/Basic.lean
@@ -140,11 +140,12 @@ lemma isSimple_of_isAtom (I : LieIdeal R L) (hI : IsAtom I) : IsSimple R I where
Submodule.mem_toAddSubmonoid]
apply add_mem
-- Now `⁅a, y⁆ ∈ J` since `a ∈ I`, `y ∈ J`, and `J` is an ideal of `I`.
- · simp only [Submodule.mem_map, LieSubmodule.mem_coeSubmodule, Submodule.coeSubtype,
- Subtype.exists, exists_and_right, exists_eq_right, ha, lie_mem_left, exists_true_left]
+ · simp only [Submodule.mem_map, LieSubmodule.mem_coeSubmodule, Subtype.exists]
+ erw [Submodule.coe_subtype]
+ simp only [exists_and_right, exists_eq_right, ha, lie_mem_left, exists_true_left]
exact lie_mem_right R I J ⟨a, ha⟩ y hy
-- Finally `⁅b, y⁆ = 0`, by the independence of the atoms.
- · suffices ⁅b, y.val⁆ = 0 by simp only [this, zero_mem]
+ · suffices ⁅b, y.val⁆ = 0 by erw [this]; simp only [zero_mem]
rw [← LieSubmodule.mem_bot (R := R) (L := L),
← (IsSemisimple.setIndependent_isAtom hI).eq_bot]
exact ⟨lie_mem_right R L I b y y.2, lie_mem_left _ _ _ _ _ hb⟩ }
@@ -157,7 +158,11 @@ lemma isSimple_of_isAtom (I : LieIdeal R L) (hI : IsAtom I) : IsSimple R I where
rw [eq_bot_iff] at this ⊢
intro x hx
suffices x ∈ J → x = 0 from this hx
- simpa [J'] using @this x.1
+ have := @this x.1
+ simp only [LieIdeal.incl_coe, LieIdeal.coe_to_lieSubalgebra_to_submodule,
+ LieSubmodule.mem_mk_iff', Submodule.mem_map, LieSubmodule.mem_coeSubmodule, Subtype.exists,
+ LieSubmodule.mem_bot, ZeroMemClass.coe_eq_zero, forall_exists_index, and_imp, J'] at this
+ exact fun _ ↦ this (↑x) x.property hx rfl
-- We need to show that `J = ⊥`.
-- Since `J` is an ideal of `L`, and `I` is an atom,
-- it suffices to show that `J < I`.
@@ -276,7 +281,6 @@ instance (priority := 100) instHasTrivialRadical : HasTrivialRadical R L := by
intro x y
ext
simp only [LieIdeal.coe_bracket_of_module, LieSubmodule.coe_bracket, ZeroMemClass.coe_zero]
- letI : Bracket I I := LieRingModule.toBracket
have : (⁅(⟨x, hJ' x.2⟩ : I), ⟨y, hJ' y.2⟩⁆ : I) = 0 := trivial_lie_zero _ _ _ _
apply_fun Subtype.val at this
exact this
@@ -302,14 +306,6 @@ theorem subsingleton_of_hasTrivialRadical_lie_abelian [HasTrivialRadical R L] [h
theorem abelian_radical_of_hasTrivialRadical [HasTrivialRadical R L] :
IsLieAbelian (radical R L) := by
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- letI : Unique (⊥ : LieIdeal R L) := Submodule.uniqueBot
- letI : Subsingleton (⊥ : LieIdeal R L) := Unique.instSubsingleton
- letI : LieModule.IsTrivial L (⊥ : LieIdeal R L) := LieModule.instIsTrivialOfSubsingleton' ..
rw [HasTrivialRadical.radical_eq_bot]; exact LieIdeal.isLieAbelian_of_trivial ..
/-- The two properties shown to be equivalent here are possible definitions for a Lie algebra
diff --git a/Mathlib/Algebra/Lie/SkewAdjoint.lean b/Mathlib/Algebra/Lie/SkewAdjoint.lean
index bf72da94b1715..4ba8facc11fda 100644
--- a/Mathlib/Algebra/Lie/SkewAdjoint.lean
+++ b/Mathlib/Algebra/Lie/SkewAdjoint.lean
@@ -126,10 +126,9 @@ def skewAdjointMatricesLieSubalgebraEquiv (P : Matrix n n R) (h : Invertible P)
exact this
simp [Matrix.IsSkewAdjoint, J.isAdjointPair_equiv _ _ P (isUnit_of_invertible P)]
--- TODO(mathlib4#6607): fix elaboration so annotation on `A` isn't needed
theorem skewAdjointMatricesLieSubalgebraEquiv_apply (P : Matrix n n R) (h : Invertible P)
(A : skewAdjointMatricesLieSubalgebra J) :
- ↑(skewAdjointMatricesLieSubalgebraEquiv J P h A) = P⁻¹ * (A : Matrix n n R) * P := by
+ ↑(skewAdjointMatricesLieSubalgebraEquiv J P h A) = P⁻¹ * A * P := by
simp [skewAdjointMatricesLieSubalgebraEquiv]
/-- An equivalence of matrix algebras commuting with the transpose endomorphisms restricts to an
diff --git a/Mathlib/Algebra/Lie/Sl2.lean b/Mathlib/Algebra/Lie/Sl2.lean
index 04d470605c27a..0fb0a5807b82b 100644
--- a/Mathlib/Algebra/Lie/Sl2.lean
+++ b/Mathlib/Algebra/Lie/Sl2.lean
@@ -148,7 +148,7 @@ lemma exists_nat [IsNoetherian R M] [NoZeroSMulDivisors R M] [IsDomain R] [CharZ
{μ - 2 * n | n : ℕ}
(fun ⟨s, hs⟩ ↦ ψ Classical.choose hs)
(fun ⟨r, hr⟩ ↦ by simp [lie_h_pow_toEnd_f P, Classical.choose_spec hr, contra,
- Module.End.HasEigenvector, Module.End.mem_eigenspace_iff])).finite
+ Module.End.hasEigenvector_iff, Module.End.mem_eigenspace_iff])).finite
lemma pow_toEnd_f_ne_zero_of_eq_nat
[CharZero R] [NoZeroSMulDivisors R M]
diff --git a/Mathlib/Algebra/Lie/Solvable.lean b/Mathlib/Algebra/Lie/Solvable.lean
index 6e125fbedd552..1ce5fd8fdcf58 100644
--- a/Mathlib/Algebra/Lie/Solvable.lean
+++ b/Mathlib/Algebra/Lie/Solvable.lean
@@ -198,7 +198,7 @@ namespace LieAlgebra
class IsSolvable : Prop where
solvable : ∃ k, derivedSeries R L k = ⊥
-instance isSolvableBot : IsSolvable R ((⊥ : LieIdeal R L)) :=
+instance isSolvableBot : IsSolvable R (⊥ : LieIdeal R L) :=
⟨⟨0, Subsingleton.elim _ ⊥⟩⟩
instance isSolvableAdd {I J : LieIdeal R L} [hI : IsSolvable R I] [hJ : IsSolvable R J] :
@@ -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 ⊢
@@ -287,12 +287,9 @@ instance [IsSolvable R L] : IsSolvable R (⊤ : LieSubalgebra R L) := by
@[simp] lemma radical_eq_top_of_isSolvable [IsSolvable R L] :
radical R L = ⊤ := by
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- rw [eq_top_iff]; exact le_sSup <| LieAlgebra.instIsSolvableSubtypeMemLieSubalgebraTop R L
+ rw [eq_top_iff]
+ have h : IsSolvable R (⊤ : LieSubalgebra R L) := inferInstance
+ exact le_sSup h
/-- Given a solvable Lie ideal `I` with derived series `I = D₀ ≥ D₁ ≥ ⋯ ≥ Dₖ = ⊥`, this is the
natural number `k` (the number of inclusions).
@@ -338,6 +335,9 @@ noncomputable def derivedAbelianOfIdeal (I : LieIdeal R L) : LieIdeal R L :=
| 0 => ⊥
| k + 1 => derivedSeriesOfIdeal R L k I
+instance : Unique {x // x ∈ (⊥ : LieIdeal R L)} :=
+ inferInstanceAs <| Unique {x // x ∈ (⊥ : Submodule R L)}
+
theorem abelian_derivedAbelianOfIdeal (I : LieIdeal R L) :
IsLieAbelian (derivedAbelianOfIdeal I) := by
dsimp only [derivedAbelianOfIdeal]
diff --git a/Mathlib/Algebra/Lie/Subalgebra.lean b/Mathlib/Algebra/Lie/Subalgebra.lean
index 37990704ca9da..6421cf0fe0753 100644
--- a/Mathlib/Algebra/Lie/Subalgebra.lean
+++ b/Mathlib/Algebra/Lie/Subalgebra.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Oliver Nash
-/
import Mathlib.Algebra.Lie.Basic
-import Mathlib.RingTheory.Noetherian
+import Mathlib.RingTheory.Artinian
/-!
# Lie subalgebras
@@ -107,6 +107,9 @@ instance [SMul R₁ R] [Module R₁ L] [IsScalarTower R₁ R L] (L' : LieSubalge
instance (L' : LieSubalgebra R L) [IsNoetherian R L] : IsNoetherian R L' :=
isNoetherian_submodule' _
+instance (L' : LieSubalgebra R L) [IsArtinian R L] : IsArtinian R L' :=
+ isArtinian_submodule' _
+
end
/-- A Lie subalgebra forms a new Lie algebra. -/
@@ -221,7 +224,7 @@ variable [Module R M]
`L`, we may regard `M` as a Lie module of `L'` by restriction. -/
instance lieModule [LieModule R L M] : LieModule R L' M where
smul_lie t x m := by
- rw [coe_bracket_of_module]; erw [smul_lie]; simp only [coe_bracket_of_module]
+ rw [coe_bracket_of_module, Submodule.coe_smul_of_tower, smul_lie, coe_bracket_of_module]
lie_smul t x m := by simp only [coe_bracket_of_module, lie_smul]
/-- An `L`-equivariant map of Lie modules `M → N` is `L'`-equivariant for any Lie subalgebra
@@ -292,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]
@@ -458,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 }
@@ -691,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 9a496ce1a3f1e..f09b3652b769d 100644
--- a/Mathlib/Algebra/Lie/Submodule.lean
+++ b/Mathlib/Algebra/Lie/Submodule.lean
@@ -72,18 +72,18 @@ instance : Zero (LieSubmodule R L M) :=
instance : Inhabited (LieSubmodule R L M) :=
⟨0⟩
-instance coeSubmodule : CoeOut (LieSubmodule R L M) (Submodule R M) :=
+instance (priority := high) coeSort : CoeSort (LieSubmodule R L M) (Type w) where
+ coe N := { x : M // x ∈ N }
+
+instance (priority := mid) coeSubmodule : CoeOut (LieSubmodule R L M) (Submodule R M) :=
⟨toSubmodule⟩
-instance instCanLiftSubmoduleLieSubmodule : CanLift (Submodule R M) (LieSubmodule R L M) (·)
- (fun N ↦ ∀ {x : L} {m : M}, m ∈ N → ⁅x, m⁆ ∈ N) where
- prf N hN := ⟨⟨N, hN⟩, rfl⟩
@[norm_cast]
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) :=
@@ -109,7 +109,7 @@ theorem mem_coe {x : M} : x ∈ (N : Set M) ↔ x ∈ N :=
protected theorem zero_mem : (0 : M) ∈ N :=
zero_mem N
--- Porting note (#10618): @[simp] can prove this
+@[simp]
theorem mk_eq_zero {x} (h : x ∈ N) : (⟨x, h⟩ : N) = 0 ↔ x = 0 :=
Subtype.ext_iff_val
@@ -156,17 +156,6 @@ instance : LieRingModule L N where
lie_add := by intro x m n; apply SetCoe.ext; apply lie_add
leibniz_lie := by intro x y m; apply SetCoe.ext; apply leibniz_lie
-instance module' {S : Type*} [Semiring S] [SMul S R] [Module S M] [IsScalarTower S R M] :
- Module S N :=
- N.toSubmodule.module'
-
-instance : Module R N :=
- N.toSubmodule.module
-
-instance {S : Type*} [Semiring S] [SMul S R] [SMul Sᵐᵒᵖ R] [Module S M] [Module Sᵐᵒᵖ M]
- [IsScalarTower S R M] [IsScalarTower Sᵐᵒᵖ R M] [IsCentralScalar S M] : IsCentralScalar S N :=
- N.toSubmodule.isCentralScalar
-
@[simp, norm_cast]
theorem coe_zero : ((0 : N) : M) = (0 : M) :=
rfl
@@ -189,10 +178,19 @@ theorem coe_smul (t : R) (m : N) : (↑(t • m) : M) = t • (m : M) :=
@[simp, norm_cast]
theorem coe_bracket (x : L) (m : N) :
- letI : Bracket L N := LieRingModule.toBracket
(↑⁅x, m⁆ : M) = ⁅x, ↑m⁆ :=
rfl
+-- Copying instances from `Submodule` for correct discrimination keys
+instance [IsNoetherian R M] (N : LieSubmodule R L M) : IsNoetherian R N :=
+ inferInstanceAs <| IsNoetherian R N.toSubmodule
+
+instance [IsArtinian R M] (N : LieSubmodule R L M) : IsArtinian R N :=
+ inferInstanceAs <| IsArtinian R N.toSubmodule
+
+instance [NoZeroSMulDivisors R M] : NoZeroSMulDivisors R N :=
+ inferInstanceAs <| NoZeroSMulDivisors R N.toSubmodule
+
variable [LieAlgebra R L] [LieModule R L M]
instance instLieModule : LieModule R L N where
@@ -249,7 +247,6 @@ instance LieIdeal.lieRingModule {R L : Type*} [CommRing R] [LieRing L] [LieAlgeb
@[simp]
theorem LieIdeal.coe_bracket_of_module {R L : Type*} [CommRing R] [LieRing L] [LieAlgebra R L]
(I : LieIdeal R L) [LieRingModule L M] (x : I) (m : M) :
- letI : Bracket I M := LieRingModule.toBracket
⁅x, m⁆ = ⁅(↑x : L), m⁆ :=
LieSubalgebra.coe_bracket_of_module (I : LieSubalgebra R L) x m
@@ -325,6 +322,9 @@ theorem coeSubmodule_le_coeSubmodule : (N : Submodule R M) ≤ N' ↔ N ≤ N' :
instance : Bot (LieSubmodule R L M) :=
⟨0⟩
+instance instUniqueBot : Unique (⊥ : LieSubmodule R L M) :=
+ inferInstanceAs <| Unique (⊥ : Submodule R M)
+
@[simp]
theorem bot_coe : ((⊥ : LieSubmodule R L M) : Set M) = {0} :=
rfl
@@ -547,10 +547,11 @@ theorem mem_sup (x : M) : x ∈ N ⊔ N' ↔ ∃ y ∈ N, ∃ z ∈ N', y + z =
nonrec theorem eq_bot_iff : N = ⊥ ↔ ∀ m : M, m ∈ N → m = 0 := by rw [eq_bot_iff]; exact Iff.rfl
-instance subsingleton_of_bot : Subsingleton (LieSubmodule R L ↑(⊥ : LieSubmodule R L M)) := by
+instance subsingleton_of_bot : Subsingleton (LieSubmodule R L (⊥ : LieSubmodule R L M)) := by
apply subsingleton_of_bot_eq_top
- ext ⟨x, hx⟩; change x ∈ ⊥ at hx; rw [Submodule.mem_bot] at hx; subst hx
- simp only [true_iff_iff, eq_self_iff_true, Submodule.mk_eq_zero, LieSubmodule.mem_bot, mem_top]
+ ext ⟨_, hx⟩
+ simp only [mem_bot, mk_eq_zero, mem_top, iff_true]
+ exact hx
instance : IsModularLattice (LieSubmodule R L M) where
sup_inf_le_assoc_of_le _ _ := by
@@ -830,9 +831,9 @@ theorem comap_incl_eq_top : N₂.comap N.incl = ⊤ ↔ N ≤ N₂ := by
LieSubmodule.top_coeSubmodule, Submodule.comap_subtype_eq_top, coeSubmodule_le_coeSubmodule]
theorem comap_incl_eq_bot : N₂.comap N.incl = ⊥ ↔ N ⊓ N₂ = ⊥ := by
- simp only [← LieSubmodule.coe_toSubmodule_eq_iff, LieSubmodule.coeSubmodule_comap,
- LieSubmodule.incl_coe, LieSubmodule.bot_coeSubmodule, ← Submodule.disjoint_iff_comap_eq_bot,
- disjoint_iff, inf_coe_toSubmodule]
+ simp only [← coe_toSubmodule_eq_iff, coeSubmodule_comap, incl_coe, bot_coeSubmodule,
+ inf_coe_toSubmodule]
+ rw [← Submodule.disjoint_iff_comap_eq_bot, disjoint_iff]
@[mono]
theorem map_mono (h : N ≤ N₂) : N.map f ≤ N₂.map f :=
@@ -884,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
@@ -987,9 +988,9 @@ same as ideals of `L` contained in `I`. -/
instance subsingleton_of_bot : Subsingleton (LieIdeal R (⊥ : LieIdeal R L)) := by
apply subsingleton_of_bot_eq_top
ext ⟨x, hx⟩
- rw [LieSubmodule.bot_coeSubmodule, Submodule.mem_bot] at hx
+ rw [LieSubmodule.mem_bot] at hx
subst hx
- simp only [Submodule.mk_eq_zero, LieSubmodule.mem_bot, LieSubmodule.mem_top]
+ simp only [LieSubmodule.mk_eq_zero, LieSubmodule.mem_bot, LieSubmodule.mem_top]
end LieIdeal
@@ -1048,6 +1049,7 @@ theorem ker_le_comap : f.ker ≤ J.comap f :=
theorem ker_coeSubmodule : LieSubmodule.toSubmodule (ker f) = LinearMap.ker (f : L →ₗ[R] L') :=
rfl
+variable {f} in
@[simp]
theorem mem_ker {x : L} : x ∈ ker f ↔ f x = 0 :=
show x ∈ LieSubmodule.toSubmodule (f.ker) ↔ _ by
@@ -1155,9 +1157,12 @@ theorem map_sup_ker_eq_map : LieIdeal.map f (I ⊔ f.ker) = LieIdeal.map f I :=
suffices LieIdeal.map f (I ⊔ f.ker) ≤ LieIdeal.map f I by
exact le_antisymm this (LieIdeal.map_mono le_sup_left)
apply LieSubmodule.lieSpan_mono
- rintro x ⟨y, hy₁, hy₂⟩; rw [← hy₂]
- erw [LieSubmodule.mem_sup] at hy₁;obtain ⟨z₁, hz₁, z₂, hz₂, hy⟩ := hy₁; rw [← hy]
- rw [f.coe_toLinearMap, f.map_add, f.mem_ker.mp hz₂, add_zero]; exact ⟨z₁, hz₁, rfl⟩
+ rintro x ⟨y, hy₁, hy₂⟩
+ rw [← hy₂]
+ erw [LieSubmodule.mem_sup] at hy₁
+ obtain ⟨z₁, hz₁, z₂, hz₂, hy⟩ := hy₁
+ rw [← hy]
+ rw [f.coe_toLinearMap, f.map_add, LieHom.mem_ker.mp hz₂, add_zero]; exact ⟨z₁, hz₁, rfl⟩
@[simp]
theorem map_sup_ker_eq_map' :
@@ -1249,7 +1254,7 @@ theorem ker_eq_bot : f.ker = ⊥ ↔ Function.Injective f := by
variable {f}
@[simp]
-theorem mem_ker (m : M) : m ∈ f.ker ↔ f m = 0 :=
+theorem mem_ker {m : M} : m ∈ f.ker ↔ f m = 0 :=
Iff.rfl
@[simp]
@@ -1257,7 +1262,7 @@ theorem ker_id : (LieModuleHom.id : M →ₗ⁅R,L⁆ M).ker = ⊥ :=
rfl
@[simp]
-theorem comp_ker_incl : f.comp f.ker.incl = 0 := by ext ⟨m, hm⟩; exact (mem_ker m).mp hm
+theorem comp_ker_incl : f.comp f.ker.incl = 0 := by ext ⟨m, hm⟩; exact mem_ker.mp hm
theorem le_ker_iff_map (M' : LieSubmodule R L M) : M' ≤ f.ker ↔ LieSubmodule.map f M' = ⊥ := by
rw [ker, eq_bot_iff, LieSubmodule.map_le_iff_le_comap]
@@ -1270,11 +1275,11 @@ def range : LieSubmodule R L N :=
(LieSubmodule.map f ⊤).copy (Set.range f) Set.image_univ.symm
@[simp]
-theorem coe_range : (f.range : Set N) = Set.range f :=
+theorem coe_range : f.range = Set.range f :=
rfl
@[simp]
-theorem coeSubmodule_range : (f.range : Submodule R N) = LinearMap.range (f : M →ₗ[R] N) :=
+theorem coeSubmodule_range : f.range = LinearMap.range (f : M →ₗ[R] N) :=
rfl
@[simp]
@@ -1293,7 +1298,7 @@ def codRestrict (P : LieSubmodule R L N) (f : M →ₗ⁅R,L⁆ N) (h : ∀ m, f
M →ₗ⁅R,L⁆ P where
toFun := f.toLinearMap.codRestrict P h
__ := f.toLinearMap.codRestrict P h
- map_lie' {x m} := by ext; simp; rfl
+ map_lie' {x m} := by ext; simp
@[simp]
lemma codRestrict_apply (P : LieSubmodule R L N) (f : M →ₗ⁅R,L⁆ N) (h : ∀ m, f m ∈ P) (m : M) :
@@ -1310,13 +1315,17 @@ variable [AddCommGroup M] [Module R M] [LieRingModule L M]
variable (N : LieSubmodule R L M)
@[simp]
-theorem ker_incl : N.incl.ker = ⊥ := by simp [← LieSubmodule.coe_toSubmodule_eq_iff]
+theorem ker_incl : N.incl.ker = ⊥ := (LieModuleHom.ker_eq_bot N.incl).mpr <| injective_incl N
@[simp]
-theorem range_incl : N.incl.range = N := by simp [← LieSubmodule.coe_toSubmodule_eq_iff]
+theorem range_incl : N.incl.range = N := by
+ simp only [← coe_toSubmodule_eq_iff, LieModuleHom.coeSubmodule_range, incl_coe]
+ rw [Submodule.range_subtype]
@[simp]
-theorem comap_incl_self : comap N.incl N = ⊤ := by simp [← LieSubmodule.coe_toSubmodule_eq_iff]
+theorem comap_incl_self : comap N.incl N = ⊤ := by
+ simp only [← coe_toSubmodule_eq_iff, coeSubmodule_comap, incl_coe, top_coeSubmodule]
+ rw [Submodule.comap_subtype_self]
theorem map_incl_top : (⊤ : LieSubmodule R L N).map N.incl = N := by simp
@@ -1377,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 c44b1b7b2474c..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⁆ :=
@@ -201,8 +201,8 @@ theorem lieIdeal_oper_eq_tensor_map_range :
TensorProduct.map_range_eq_span_tmul, Submodule.map_span]
congr; ext m; constructor
· rintro ⟨⟨x, hx⟩, ⟨n, hn⟩, rfl⟩; use x ⊗ₜ n; constructor
- · use ⟨x, hx⟩, ⟨n, hn⟩; simp
+ · use ⟨x, hx⟩, ⟨n, hn⟩; rfl
· simp
- · rintro ⟨t, ⟨⟨x, hx⟩, ⟨n, hn⟩, rfl⟩, h⟩; rw [← h]; use ⟨x, hx⟩, ⟨n, hn⟩; simp
+ · rintro ⟨t, ⟨⟨x, hx⟩, ⟨n, hn⟩, rfl⟩, h⟩; rw [← h]; use ⟨x, hx⟩, ⟨n, hn⟩; rfl
end LieSubmodule
diff --git a/Mathlib/Algebra/Lie/TraceForm.lean b/Mathlib/Algebra/Lie/TraceForm.lean
index 06be6aac63a94..2d1253e2b18c9 100644
--- a/Mathlib/Algebra/Lie/TraceForm.lean
+++ b/Mathlib/Algebra/Lie/TraceForm.lean
@@ -38,7 +38,7 @@ variable (R K L M : Type*) [CommRing R] [LieRing L] [LieAlgebra R L]
local notation "φ" => LieModule.toEnd R L M
open LinearMap (trace)
-open Set FiniteDimensional
+open Set Module
namespace LieModule
@@ -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]
@@ -226,9 +227,9 @@ lemma traceForm_eq_sum_genWeightSpaceOf
convert finite_genWeightSpaceOf_ne_bot R L M z
exact LieSubmodule.coeSubmodule_eq_bot_iff (genWeightSpaceOf M _ _)
classical
- have hds := DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top
- (LieSubmodule.independent_iff_coe_toSubmodule.mp <| independent_genWeightSpaceOf R L M z)
- (IsTriangularizable.iSup_eq_top z)
+ have h := LieSubmodule.independent_iff_coe_toSubmodule.mp <| independent_genWeightSpaceOf R L M z
+ have hds := DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top h <| by
+ simp [← LieSubmodule.iSup_coe_toSubmodule]
simp only [LinearMap.coeFn_sum, Finset.sum_apply, traceForm_apply_apply,
LinearMap.trace_eq_sum_trace_restrict' hds hfin hxy]
exact Finset.sum_congr (by simp) (fun χ _ ↦ rfl)
@@ -276,9 +277,9 @@ 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
- · exact 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 ⊗ₜ x)) (le_refl 1) hz
+ (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)
/-- A nilpotent Lie algebra with a representation whose trace form is non-singular is Abelian. -/
@@ -302,7 +303,10 @@ variable [IsDomain R] [IsPrincipalIdealRing R]
lemma trace_eq_trace_restrict_of_le_idealizer
(hy' : ∀ m ∈ N, (φ x ∘ₗ φ y) m ∈ N := fun m _ ↦ N.lie_mem (N.mem_idealizer.mp (h hy) m)) :
trace R M (φ x ∘ₗ φ y) = trace R N ((φ x ∘ₗ φ y).restrict hy') := by
- suffices ∀ m, ⁅x, ⁅y, m⁆⁆ ∈ N by simp [(φ x ∘ₗ φ y).trace_restrict_eq_of_forall_mem _ this]
+ suffices ∀ m, ⁅x, ⁅y, m⁆⁆ ∈ N by
+ have : (trace R { x // x ∈ N }) ((φ x ∘ₗ φ y).restrict _) = (trace R M) (φ x ∘ₗ φ y) :=
+ (φ x ∘ₗ φ y).trace_restrict_eq_of_forall_mem _ this
+ simp [this]
exact fun m ↦ N.lie_mem (h hy m)
include h in
@@ -322,14 +326,8 @@ lemma traceForm_eq_zero_of_isTrivial [LieModule.IsTrivial I N] :
let hy' : ∀ m ∈ N, (φ x ∘ₗ φ y) m ∈ N := fun m _ ↦ N.lie_mem (N.mem_idealizer.mp (h hy) m)
suffices (φ x ∘ₗ φ y).restrict hy' = 0 by
simp [this, N.trace_eq_trace_restrict_of_le_idealizer I h x hy]
- ext n
+ ext (n : N)
suffices ⁅y, (n : M)⁆ = 0 by simp [this]
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- letI : Bracket I N := LieRingModule.toBracket
exact Submodule.coe_eq_zero.mpr (LieModule.IsTrivial.trivial (⟨y, hy⟩ : I) n)
end LieSubmodule
@@ -395,7 +393,7 @@ lemma killingForm_eq :
end LieIdeal
-open LieModule FiniteDimensional
+open LieModule Module
open Submodule (span subset_span)
namespace LieModule
@@ -416,6 +414,8 @@ lemma traceForm_eq_sum_finrank_nsmul_mul (x y : L) :
← traceForm_genWeightSpace_eq K L M _ x y]
rfl
+/-- See also `LieModule.traceForm_eq_sum_finrank_nsmul'` for an expression omitting the zero
+weights. -/
lemma traceForm_eq_sum_finrank_nsmul :
traceForm K L M = ∑ χ : Weight K L M, finrank K (genWeightSpace M χ) •
(χ : L →ₗ[K] K).smulRight (χ : L →ₗ[K] K) := by
@@ -423,6 +423,21 @@ lemma traceForm_eq_sum_finrank_nsmul :
rw [traceForm_eq_sum_finrank_nsmul_mul, ← Finset.sum_attach]
simp
+/-- A variant of `LieModule.traceForm_eq_sum_finrank_nsmul` in which the sum is taken only over the
+non-zero weights. -/
+lemma traceForm_eq_sum_finrank_nsmul' :
+ traceForm K L M = ∑ χ in {χ : Weight K L M | χ.IsNonZero}, finrank K (genWeightSpace M χ) •
+ (χ : L →ₗ[K] K).smulRight (χ : L →ₗ[K] K) := by
+ classical
+ suffices ∑ χ in {χ : Weight K L M | χ.IsZero}, finrank K (genWeightSpace M χ) •
+ (χ : L →ₗ[K] K).smulRight (χ : L →ₗ[K] K) = 0 by
+ rw [traceForm_eq_sum_finrank_nsmul,
+ ← Finset.sum_filter_add_sum_filter_not (p := fun χ : Weight K L M ↦ χ.IsNonZero)]
+ simp [this]
+ refine Finset.sum_eq_zero fun χ hχ ↦ ?_
+ replace hχ : (χ : L →ₗ[K] K) = 0 := by simpa [← Weight.coe_toLinear_eq_zero_iff] using hχ
+ simp [hχ]
+
-- The reverse inclusion should also hold: TODO prove this!
lemma range_traceForm_le_span_weight :
LinearMap.range (traceForm K L M) ≤ span K (range (Weight.toLinear K L M)) := by
diff --git a/Mathlib/Algebra/Lie/Weights/Basic.lean b/Mathlib/Algebra/Lie/Weights/Basic.lean
index 5652899b49468..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]
+ 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,
@@ -219,13 +219,6 @@ instance [Subsingleton M] : IsEmpty (Weight R L M) :=
⟨fun h ↦ h.2 (Subsingleton.elim _ _)⟩
instance [Nontrivial (genWeightSpace M (0 : L → R))] : Zero (Weight R L M) :=
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- letI : Unique (⊥ : LieSubmodule R L M) := Submodule.uniqueBot
- letI : Subsingleton (⊥ : LieSubmodule R L M) := Unique.instSubsingleton
⟨0, fun e ↦ not_nontrivial (⊥ : LieSubmodule R L M) (e ▸ ‹_›)⟩
@[simp]
@@ -254,6 +247,8 @@ abbrev IsNonZero (χ : Weight R L M) := ¬ IsZero (χ : Weight R L M)
lemma isNonZero_iff_ne_zero [Nontrivial (genWeightSpace M (0 : L → R))] {χ : Weight R L M} :
χ.IsNonZero ↔ χ ≠ 0 := isZero_iff_eq_zero.not
+noncomputable instance : DecidablePred (IsNonZero (R := R) (L := L) (M := M)) := Classical.decPred _
+
variable (R L M) in
/-- The set of weights is equivalent to a subtype. -/
def equivSetOf : Weight R L M ≃ {χ : L → R | genWeightSpace M χ ≠ ⊥} where
@@ -272,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 [Module.End.maxGenEigenspace, genWeightSpaceOf] 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]
@@ -313,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] at hm
+ rwa [Module.End.maxGenEigenspace_eq, Module.End.genEigenspace_nat] at hm
variable (R) in
theorem exists_genWeightSpace_zero_le_ker_of_isNoetherian
@@ -330,7 +325,9 @@ lemma isNilpotent_toEnd_sub_algebraMap [IsNoetherian R M] (χ : L → R) (x : L)
obtain ⟨k, hk⟩ := exists_genWeightSpace_le_ker_of_isNoetherian M χ x
use k
ext ⟨m, hm⟩
- simpa [this, LinearMap.pow_restrict _, LinearMap.restrict_apply] using hk hm
+ simp only [this, LinearMap.pow_restrict _, LinearMap.zero_apply, ZeroMemClass.coe_zero,
+ ZeroMemClass.coe_eq_zero]
+ exact ZeroMemClass.coe_eq_zero.mp (hk hm)
/-- A (nilpotent) Lie algebra acts nilpotently on the zero weight space of a Noetherian Lie
module. -/
@@ -590,12 +587,7 @@ private lemma isCompl_genWeightSpace_zero_posFittingComp_aux
· suffices IsNilpotent R L M by simp [M₀, M₁, isCompl_top_bot]
replace h : M₀ = ⊤ := by simpa [M₀, genWeightSpace]
rw [← LieModule.isNilpotent_of_top_iff', ← h]
- #adaptation_note
- /--
- After lean4#5020, many instances for Lie algebras and manifolds are no longer found.
- See https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/.2316244.20adaptations.20for.20nightly-2024-08-28/near/466219124
- -/
- exact LieModule.instIsNilpotentSubtypeMemSubmoduleGenWeightSpaceOfNatForallOfIsNoetherian M
+ infer_instance
· set M₀ₓ := genWeightSpaceOf M (0 : R) x
set M₁ₓ := posFittingCompOf R M x
set M₀ₓ₀ := genWeightSpace M₀ₓ (0 : L → R)
@@ -638,7 +630,8 @@ end fitting_decomposition
lemma disjoint_genWeightSpaceOf [NoZeroSMulDivisors R M] {x : L} {φ₁ φ₂ : R} (h : φ₁ ≠ φ₂) :
Disjoint (genWeightSpaceOf M φ₁ x) (genWeightSpaceOf M φ₂ x) := by
rw [LieSubmodule.disjoint_iff_coe_toSubmodule]
- exact Module.End.disjoint_iSup_genEigenspace _ h
+ dsimp [genWeightSpaceOf]
+ exact Module.End.disjoint_genEigenspace _ h _ _
lemma disjoint_genWeightSpace [NoZeroSMulDivisors R M] {χ₁ χ₂ : L → R} (h : χ₁ ≠ χ₂) :
Disjoint (genWeightSpace M χ₁) (genWeightSpace M χ₂) := by
@@ -656,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 χ :=
@@ -707,17 +663,16 @@ lemma independent_genWeightSpace' [NoZeroSMulDivisors R M] :
lemma independent_genWeightSpaceOf [NoZeroSMulDivisors R M] (x : L) :
CompleteLattice.Independent fun (χ : R) ↦ genWeightSpaceOf M χ x := by
rw [LieSubmodule.independent_iff_coe_toSubmodule]
- exact (toEnd R L M x).independent_genEigenspace
+ dsimp [genWeightSpaceOf]
+ 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
@@ -730,26 +685,29 @@ 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) :
⨆ (φ : R), genWeightSpaceOf M φ x = ⊤ := by
rw [← LieSubmodule.coe_toSubmodule_eq_iff, LieSubmodule.iSup_coe_toSubmodule,
LieSubmodule.top_coeSubmodule]
- exact IsTriangularizable.iSup_eq_top x
+ dsimp [genWeightSpaceOf]
+ exact IsTriangularizable.maxGenEigenspace_eq_top x
-open LinearMap FiniteDimensional in
+open LinearMap Module in
@[simp]
lemma trace_toEnd_genWeightSpace [IsDomain R] [IsPrincipalIdealRing R]
[Module.Free R M] [Module.Finite R M] (χ : L → R) (x : L) :
@@ -763,56 +721,30 @@ lemma trace_toEnd_genWeightSpace [IsDomain R] [IsPrincipalIdealRing R]
section field
-open FiniteDimensional
+open Module
variable (K)
variable [Field K] [LieAlgebra K L] [Module K M] [LieModule K L M] [LieAlgebra.IsNilpotent K L]
[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.
See also `LieModule.iSup_genWeightSpace_eq_top'`. -/
lemma iSup_genWeightSpace_eq_top [IsTriangularizable K L M] :
⨆ χ : L → K, genWeightSpace M χ = ⊤ := by
- generalize h_dim : finrank K M = n
- induction n using Nat.strongRecOn generalizing M with | ind n ih => ?_
- obtain h' | ⟨y : L, hy : ¬ ∃ φ, genWeightSpaceOf M φ y = ⊤⟩ :=
- forall_or_exists_not (fun (x : L) ↦ ∃ (φ : K), genWeightSpaceOf M φ x = ⊤)
- · choose χ hχ using h'
- replace hχ : genWeightSpace M χ = ⊤ := by simpa only [genWeightSpace, hχ] using iInf_top
- exact eq_top_iff.mpr <| hχ ▸ le_iSup (genWeightSpace M) χ
- · replace hy : ∀ φ, finrank K (genWeightSpaceOf M φ y) < n := fun φ ↦ by
- simp_rw [not_exists, ← lt_top_iff_ne_top] at hy; exact h_dim ▸ Submodule.finrank_lt (hy φ)
- replace ih : ∀ φ, ⨆ χ : L → K, genWeightSpace (genWeightSpaceOf M φ y) χ = ⊤ :=
- fun φ ↦ ih _ (hy φ) (genWeightSpaceOf M φ y) rfl
- replace ih : ∀ φ, ⨆ (χ : L → K) (_ : χ y = φ),
- genWeightSpace (genWeightSpaceOf M φ y) χ = ⊤ := by
- intro φ
- suffices ∀ χ : L → K, χ y ≠ φ → genWeightSpace (genWeightSpaceOf M φ y) χ = ⊥ by
- specialize ih φ; rw [iSup_split, biSup_congr this] at ih; simpa using ih
- intro χ hχ
- rw [eq_bot_iff, ← (genWeightSpaceOf M φ y).ker_incl, LieModuleHom.ker,
- ← LieSubmodule.map_le_iff_le_comap, map_genWeightSpace_eq_of_injective
- (genWeightSpaceOf M φ y).injective_incl, LieSubmodule.range_incl, ← disjoint_iff_inf_le]
- exact (disjoint_genWeightSpaceOf K L M hχ).mono_left
- (genWeightSpace_le_genWeightSpaceOf M y χ)
- replace ih : ∀ φ, ⨆ (χ : L → K) (_ : χ y = φ), genWeightSpace M χ = genWeightSpaceOf M φ y := by
- intro φ
- have (χ : L → K) (hχ : χ y = φ) : genWeightSpace M χ =
- (genWeightSpace (genWeightSpaceOf M φ y) χ).map (genWeightSpaceOf M φ y).incl := by
- rw [← hχ, genWeightSpace_genWeightSpaceOf_map_incl]
- simp_rw [biSup_congr this, ← LieSubmodule.map_iSup, ih, LieModuleHom.map_top,
- LieSubmodule.range_incl]
- simpa only [← ih, iSup_comm (ι := K), iSup_iSup_eq_right] using
- iSup_genWeightSpaceOf_eq_top K L M y
+ simp only [← LieSubmodule.coe_toSubmodule_eq_iff, LieSubmodule.iSup_coe_toSubmodule,
+ 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) ?_
+ 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 152536e842483..e494e0e19ba5d 100644
--- a/Mathlib/Algebra/Lie/Weights/Cartan.lean
+++ b/Mathlib/Algebra/Lie/Weights/Cartan.lean
@@ -88,7 +88,7 @@ def rootSpaceWeightSpaceProductAux {χ₁ χ₂ χ₃ : H → R} (hχ : χ₁ +
{ toFun := fun m =>
⟨⁅(x : L), (m : M)⁆,
hχ ▸ lie_mem_genWeightSpace_of_mem_genWeightSpace x.property m.property⟩
- map_add' := fun m n => by simp only [Submodule.coe_add, lie_add, AddMemClass.mk_add_mk]
+ map_add' := fun m n => by simp only [LieSubmodule.coe_add, lie_add, AddMemClass.mk_add_mk]
map_smul' := fun t m => by
dsimp only
conv_lhs =>
@@ -97,7 +97,7 @@ def rootSpaceWeightSpaceProductAux {χ₁ χ₂ χ₃ : H → R} (hχ : χ₁ +
rfl }
map_add' x y := by
ext m
- simp only [Submodule.coe_add, add_lie, LinearMap.coe_mk, AddHom.coe_mk, LinearMap.add_apply,
+ simp only [LieSubmodule.coe_add, add_lie, LinearMap.coe_mk, AddHom.coe_mk, LinearMap.add_apply,
AddMemClass.mk_add_mk]
map_smul' t x := by
simp only [RingHom.id_apply]
@@ -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χ : χ₁ + χ₂ = χ₃) :
@@ -117,7 +115,6 @@ def rootSpaceWeightSpaceProduct (χ₁ χ₂ χ₃ : H → R) (hχ : χ₁ + χ
ext m
simp only [rootSpaceWeightSpaceProductAux]
dsimp
- repeat rw [LieSubmodule.coe_bracket]
simp only [LieSubalgebra.coe_bracket_of_module, lie_lie] }
@[simp]
@@ -271,7 +268,9 @@ lemma mem_corootSpace {x : H} :
have : x ∈ corootSpace α ↔
(x : L) ∈ LieSubmodule.map H.toLieSubmodule.incl (corootSpace α) := by
rw [corootSpace]
- simpa using exists_congr fun _ ↦ H.toLieSubmodule.injective_incl.eq_iff.symm
+ simp only [rootSpaceProduct_def, LieModuleHom.mem_range, LieSubmodule.mem_map,
+ LieSubmodule.incl_apply, SetLike.coe_eq_coe, exists_eq_right]
+ rfl
simp_rw [this, corootSpace, ← LieModuleHom.map_top, ← LieSubmodule.mem_coeSubmodule,
LieSubmodule.coeSubmodule_map, LieSubmodule.top_coeSubmodule, ← TensorProduct.span_tmul_eq_top,
LinearMap.map_span, Set.image, Set.mem_setOf_eq, exists_exists_exists_and_eq]
@@ -288,9 +287,9 @@ lemma mem_corootSpace' {x : H} :
erw [← (H : Submodule R L).injective_subtype.mem_set_image (s := Submodule.span R s)]
rw [mem_image]
simp_rw [SetLike.mem_coe]
- rw [← Submodule.mem_map, Submodule.coeSubtype, Submodule.map_span, mem_corootSpace, ← this]
+ rw [← Submodule.mem_map, Submodule.coe_subtype, Submodule.map_span, mem_corootSpace, ← this]
ext u
- simp only [Submodule.coeSubtype, mem_image, Subtype.exists, LieSubalgebra.mem_coe_submodule,
+ simp only [Submodule.coe_subtype, mem_image, Subtype.exists, LieSubalgebra.mem_coe_submodule,
exists_and_right, exists_eq_right, mem_setOf_eq, s]
refine ⟨fun ⟨_, y, hy, z, hz, hyz⟩ ↦ ⟨y, hy, z, hz, hyz⟩,
fun ⟨y, hy, z, hz, hyz⟩ ↦ ⟨?_, y, hy, z, hz, hyz⟩⟩
diff --git a/Mathlib/Algebra/Lie/Weights/Chain.lean b/Mathlib/Algebra/Lie/Weights/Chain.lean
index 4207a1056e76d..4107e1e4cd27f 100644
--- a/Mathlib/Algebra/Lie/Weights/Chain.lean
+++ b/Mathlib/Algebra/Lie/Weights/Chain.lean
@@ -41,7 +41,7 @@ We provide basic definitions and results to support `α`-chain techniques in thi
-/
-open FiniteDimensional Function Set
+open Module Function Set
variable {R L : Type*} [CommRing R] [LieRing L] [LieAlgebra R L]
(M : Type*) [AddCommGroup M] [Module R M] [LieRingModule L M] [LieModule R L M]
@@ -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) :=
@@ -212,11 +212,16 @@ lemma exists_forall_mem_corootSpace_smul_add_eq_zero
have h₃ : genWeightSpaceChain M α χ p q = ⨆ i ∈ Finset.Ioo p q, N i := by
simp_rw [genWeightSpaceChain_def', LieSubmodule.iSup_coe_toSubmodule]
rw [← trace_toEnd_genWeightSpaceChain_eq_zero M α χ p q hp hq hx,
- ← LieSubmodule.toEnd_restrict_eq_toEnd,
- LinearMap.trace_eq_sum_trace_restrict_of_eq_biSup _ h₁ h₂ (genWeightSpaceChain M α χ p q) h₃]
+ ← LieSubmodule.toEnd_restrict_eq_toEnd]
+ -- The lines below illustrate the cost of treating `LieSubmodule` as both a
+ -- `Submodule` and a `LieSubmodule` simultaneously.
+ erw [LinearMap.trace_eq_sum_trace_restrict_of_eq_biSup _ h₁ h₂ (genWeightSpaceChain M α χ p q) h₃]
+ simp_rw [LieSubmodule.toEnd_restrict_eq_toEnd]
dsimp [N]
- simp_rw [LieSubmodule.toEnd_restrict_eq_toEnd,
- trace_toEnd_genWeightSpace, Pi.add_apply, Pi.smul_apply, smul_add, ← smul_assoc,
+ convert_to _ =
+ ∑ k ∈ Finset.Ioo p q, (LinearMap.trace R { x // x ∈ (genWeightSpace M (k • α + χ)) })
+ ((toEnd R { x // x ∈ H } { x // x ∈ genWeightSpace M (k • α + χ) }) x)
+ simp_rw [trace_toEnd_genWeightSpace, Pi.add_apply, Pi.smul_apply, smul_add, ← smul_assoc,
Finset.sum_add_distrib, ← Finset.sum_smul, natCast_zsmul]
end IsCartanSubalgebra
diff --git a/Mathlib/Algebra/Lie/Weights/Killing.lean b/Mathlib/Algebra/Lie/Weights/Killing.lean
index 30db9a4835dcf..3fe00e4149748 100644
--- a/Mathlib/Algebra/Lie/Weights/Killing.lean
+++ b/Mathlib/Algebra/Lie/Weights/Killing.lean
@@ -85,7 +85,7 @@ end IsKilling
section Field
-open FiniteDimensional LieModule Set
+open Module LieModule Set
open Submodule (span subset_span)
variable [FiniteDimensional K L] (H : LieSubalgebra K L) [H.IsCartanSubalgebra]
@@ -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
@@ -534,7 +535,9 @@ lemma _root_.IsSl2Triple.h_eq_coroot {α : Weight K H L} (hα : α.IsNonZero)
lemma finrank_rootSpace_eq_one (α : Weight K H L) (hα : α.IsNonZero) :
finrank K (rootSpace H α) = 1 := by
suffices ¬ 1 < finrank K (rootSpace H α) by
- have h₀ : finrank K (rootSpace H α) ≠ 0 := by simpa using α.genWeightSpace_ne_bot
+ have h₀ : finrank K (rootSpace H α) ≠ 0 := by
+ convert_to finrank K (rootSpace H α).toSubmodule ≠ 0
+ simpa using α.genWeightSpace_ne_bot
omega
intro contra
obtain ⟨h, e, f, ht, heα, hfα⟩ := exists_isSl2Triple_of_weight_isNonZero hα
@@ -545,7 +548,7 @@ lemma finrank_rootSpace_eq_one (α : Weight K H L) (hα : α.IsNonZero) :
have : killingForm K L y f = 0 := by simpa [F, traceForm_comm] using hy
simpa [this] using lie_eq_killingForm_smul_of_mem_rootSpace_of_mem_rootSpace_neg hyα hfα
have P : ht.symm.HasPrimitiveVectorWith y (-2 : K) :=
- { ne_zero := by simpa using hy₀
+ { ne_zero := by simpa [LieSubmodule.mk_eq_zero] using hy₀
lie_h := by simp only [neg_smul, neg_lie, neg_inj, ht.h_eq_coroot hα heα hfα,
← H.coe_bracket_of_module, lie_eq_smul_of_mem_rootSpace hyα (coroot α),
root_apply_coroot hα]
@@ -554,6 +557,16 @@ lemma finrank_rootSpace_eq_one (α : Weight K H L) (hα : α.IsNonZero) :
replace hn : -2 = (n : ℤ) := by norm_cast at hn
omega
+/-- The collection of roots as a `Finset`. -/
+noncomputable abbrev _root_.LieSubalgebra.root : Finset (Weight K H L) := {α | α.IsNonZero}
+
+lemma restrict_killingForm_eq_sum :
+ (killingForm K L).restrict H = ∑ α in H.root, (α : H →ₗ[K] K).smulRight (α : H →ₗ[K] K) := by
+ rw [restrict_killingForm, traceForm_eq_sum_finrank_nsmul' K H L]
+ refine Finset.sum_congr rfl fun χ hχ ↦ ?_
+ replace hχ : χ.IsNonZero := by simpa [LieSubalgebra.root] using hχ
+ simp [finrank_rootSpace_eq_one _ hχ]
+
end CharZero
end IsKilling
diff --git a/Mathlib/Algebra/Lie/Weights/Linear.lean b/Mathlib/Algebra/Lie/Weights/Linear.lean
index a1acd2a519eaa..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
@@ -100,19 +100,19 @@ instance instLinearWeightsOfIsLieAbelian [IsLieAbelian L] [NoZeroSMulDivisors R
simp_rw [Ne, ← LieSubmodule.coe_toSubmodule_eq_iff, genWeightSpace, genWeightSpaceOf,
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] 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] }
section FiniteDimensional
-open FiniteDimensional
+open Module
variable [IsDomain R] [IsPrincipalIdealRing R] [Module.Free R M] [Module.Finite R M]
[LieAlgebra.IsNilpotent R L]
@@ -237,9 +237,9 @@ lemma exists_forall_lie_eq_smul [LinearWeights R L M] [IsNoetherian R M] (χ : W
(LieSubmodule.nontrivial_iff_ne_bot R L M).mpr χ.genWeightSpace_ne_bot
obtain ⟨⟨⟨m, _⟩, hm₁⟩, hm₂⟩ :=
@exists_ne _ (nontrivial_max_triv_of_isNilpotent R L (shiftedGenWeightSpace R L M χ)) 0
- simp_rw [LieSubmodule.mem_coeSubmodule, mem_maxTrivSubmodule, Subtype.ext_iff,
+ simp_rw [mem_maxTrivSubmodule, Subtype.ext_iff,
ZeroMemClass.coe_zero] at hm₁
- refine ⟨m, by simpa using hm₂, ?_⟩
+ refine ⟨m, by simpa [LieSubmodule.mk_eq_zero] using hm₂, ?_⟩
intro x
have := hm₁ x
rwa [coe_lie_shiftedGenWeightSpace_apply, sub_eq_zero] at this
diff --git a/Mathlib/Algebra/Lie/Weights/RootSystem.lean b/Mathlib/Algebra/Lie/Weights/RootSystem.lean
index f306237f00379..d2a8a94210cd9 100644
--- a/Mathlib/Algebra/Lie/Weights/RootSystem.lean
+++ b/Mathlib/Algebra/Lie/Weights/RootSystem.lean
@@ -5,6 +5,7 @@ Authors: Andrew Yang
-/
import Mathlib.Algebra.Lie.Weights.Killing
import Mathlib.LinearAlgebra.RootSystem.Basic
+import Mathlib.LinearAlgebra.RootSystem.Finite.CanonicalBilinear
import Mathlib.Algebra.Algebra.Rat
/-!
@@ -376,7 +377,7 @@ variable (H)
/-- The root system of a finite-dimensional Lie algebra with non-degenerate Killing form over a
field of characteristic zero, relative to a splitting Cartan subalgebra. -/
def rootSystem :
- RootSystem {α : Weight K H L // α.IsNonZero} K (Dual K H) H :=
+ RootSystem H.root K (Dual K H) H :=
RootSystem.mk'
IsReflexive.toPerfectPairingDual
{ toFun := (↑)
@@ -384,14 +385,20 @@ def rootSystem :
intro α β h; ext x; simpa using LinearMap.congr_fun h x }
{ toFun := coroot ∘ (↑)
inj' := by rintro ⟨α, hα⟩ ⟨β, hβ⟩ h; simpa using h }
- (fun α ↦ by simpa using root_apply_coroot α.property)
+ (fun ⟨α, hα⟩ ↦ by simpa using root_apply_coroot <| by simpa using hα)
(by
rintro ⟨α, hα⟩ - ⟨⟨β, hβ⟩, rfl⟩
simp only [Function.Embedding.coeFn_mk, IsReflexive.toPerfectPairingDual_toLin,
Function.comp_apply, Set.mem_range, Subtype.exists, exists_prop]
- exact ⟨reflectRoot α β, reflectRoot_isNonZero α β hβ, rfl⟩)
+ exact ⟨reflectRoot α β, (by simpa using reflectRoot_isNonZero α β <| by simpa using hβ), rfl⟩)
(by convert span_weight_isNonZero_eq_top K L H; ext; simp)
+@[simp]
+lemma corootForm_rootSystem_eq_killing :
+ (rootSystem H).CorootForm = (killingForm K L).restrict H := by
+ rw [restrict_killingForm_eq_sum, RootPairing.CorootForm, ← Finset.sum_coe_sort (s := H.root)]
+ rfl
+
@[simp] lemma rootSystem_toPerfectPairing_apply (f x) : (rootSystem H).toPerfectPairing f x = f x :=
rfl
@[deprecated (since := "2024-09-09")]
@@ -405,12 +412,12 @@ theorem isCrystallographic_rootSystem : (rootSystem H).IsCrystallographic := by
exact ⟨chainBotCoeff β.1 α.1 - chainTopCoeff β.1 α.1, by simp [apply_coroot_eq_cast β.1 α.1]⟩
theorem isReduced_rootSystem : (rootSystem H).IsReduced := by
- intro α β e
+ intro ⟨α, hα⟩ ⟨β, hβ⟩ e
rw [LinearIndependent.pair_iff' ((rootSystem H).ne_zero _), not_forall] at e
simp only [Nat.succ_eq_add_one, Nat.reduceAdd, rootSystem_root_apply, ne_eq, not_not] at e
obtain ⟨u, hu⟩ := e
obtain (h | h) :=
- eq_neg_or_eq_of_eq_smul α.1 β.1 β.2 u (by ext x; exact DFunLike.congr_fun hu.symm x)
+ eq_neg_or_eq_of_eq_smul α β (by simpa using hβ) u (by ext x; exact DFunLike.congr_fun hu.symm x)
· right; ext x; simpa [neg_eq_iff_eq_neg] using DFunLike.congr_fun h.symm x
· left; ext x; simpa using DFunLike.congr_fun h.symm x
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 8c4bcc0fd4def..daf547441d69c 100644
--- a/Mathlib/Algebra/ModEq.lean
+++ b/Mathlib/Algebra/ModEq.lean
@@ -3,9 +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.GroupTheory.QuotientGroup.Basic
+import Mathlib.Algebra.Group.Subgroup.ZPowers
+import Mathlib.Algebra.NoZeroSMulDivisors.Basic
+import Mathlib.Algebra.Order.Ring.Int
+import Mathlib.Data.Int.ModEq
+import Mathlib.GroupTheory.QuotientGroup.Defs
/-!
# Equality modulo an element
@@ -171,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/Algebra.lean b/Mathlib/Algebra/Module/Algebra.lean
index d2cee9bce327b..6fb1b53849c2b 100644
--- a/Mathlib/Algebra/Module/Algebra.lean
+++ b/Mathlib/Algebra/Module/Algebra.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Module.Defs
import Mathlib.Algebra.Algebra.Basic
diff --git a/Mathlib/Algebra/Module/Basic.lean b/Mathlib/Algebra/Module/Basic.lean
index 2e3fb20b33d35..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,32 +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
-
-variable [Ring R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M]
-
-instance [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) :
@@ -135,7 +116,7 @@ lemma support_smul_subset_right [Zero M] [SMulZeroClass R M] (f : α → R) (g :
lemma support_const_smul_of_ne_zero [Zero R] [Zero M] [SMulWithZero R M] [NoZeroSMulDivisors R M]
(c : R) (g : α → M) (hc : c ≠ 0) : support (c • g) = support g :=
- ext fun x ↦ by simp only [hc, mem_support, Pi.smul_apply, Ne, smul_eq_zero, false_or_iff]
+ ext fun x ↦ by simp only [hc, mem_support, Pi.smul_apply, Ne, smul_eq_zero, false_or]
lemma support_smul [Zero R] [Zero M] [SMulWithZero R M] [NoZeroSMulDivisors R M] (f : α → R)
(g : α → M) : support (f • g) = support f ∩ support g :=
diff --git a/Mathlib/Algebra/Module/BigOperators.lean b/Mathlib/Algebra/Module/BigOperators.lean
index 6c34557954a88..9be3a61dd0e46 100644
--- a/Mathlib/Algebra/Module/BigOperators.lean
+++ b/Mathlib/Algebra/Module/BigOperators.lean
@@ -15,7 +15,7 @@ variable {ι κ α β R M : Type*}
section AddCommMonoid
-variable [Semiring R] [AddCommMonoid M] [Module R M] (r s : R) (x y : M)
+variable [Semiring R] [AddCommMonoid M] [Module R M]
theorem List.sum_smul {l : List R} {x : M} : l.sum • x = (l.map fun r ↦ r • x).sum :=
map_list_sum ((smulAddHom R M).flip x) l
@@ -41,19 +41,19 @@ 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,
- sum_ite_mem, inter_self]
+ Finset.sum_ite_mem, inter_self]
end Fintype
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 3d210451cac46..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]
@@ -122,7 +123,7 @@ protected theorem smul_def (f : M ≃ₗ[R] M) (a : M) : f • a = f a :=
/-- `LinearEquiv.applyDistribMulAction` is faithful. -/
instance apply_faithfulSMul : FaithfulSMul (M ≃ₗ[R] M) M :=
- ⟨@fun _ _ ↦ LinearEquiv.ext⟩
+ ⟨LinearEquiv.ext⟩
instance apply_smulCommClass [SMul S R] [SMul S M] [IsScalarTower S R M] :
SMulCommClass S (M ≃ₗ[R] M) M where
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 e442944e3cb7b..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 _ _
@@ -933,9 +911,8 @@ end Actions
section RestrictScalarsAsLinearMap
-variable {R S M N : Type*} [Semiring R] [Semiring S] [AddCommGroup M] [AddCommGroup N] [Module R M]
- [Module R N] [Module S M] [Module S N]
- [LinearMap.CompatibleSMul M N R S]
+variable {R S M N P : Type*} [Semiring R] [Semiring S] [AddCommMonoid M] [AddCommMonoid N]
+ [Module R M] [Module R N] [Module S M] [Module S N] [CompatibleSMul M N R S]
variable (R S M N) in
@[simp]
@@ -948,7 +925,9 @@ theorem restrictScalars_add (f g : M →ₗ[S] N) :
rfl
@[simp]
-theorem restrictScalars_neg (f : M →ₗ[S] N) : (-f).restrictScalars R = -f.restrictScalars R :=
+theorem restrictScalars_neg {M N : Type*} [AddCommGroup M] [AddCommGroup N]
+ [Module R M] [Module R N] [Module S M] [Module S N] [CompatibleSMul M N R S]
+ (f : M →ₗ[S] N) : (-f).restrictScalars R = -f.restrictScalars R :=
rfl
variable {R₁ : Type*} [Semiring R₁] [Module R₁ N] [SMulCommClass S R₁ N] [SMulCommClass R R₁ N]
@@ -958,6 +937,18 @@ theorem restrictScalars_smul (c : R₁) (f : M →ₗ[S] N) :
(c • f).restrictScalars R = c • f.restrictScalars R :=
rfl
+@[simp]
+lemma restrictScalars_comp [AddCommMonoid P] [Module S P] [Module R P]
+ [CompatibleSMul N P R S] [CompatibleSMul M P R S] (f : N →ₗ[S] P) (g : M →ₗ[S] N) :
+ (f ∘ₗ g).restrictScalars R = f.restrictScalars R ∘ₗ g.restrictScalars R := by
+ rfl
+
+@[simp]
+lemma restrictScalars_trans {T : Type*} [CommSemiring T] [Module T M] [Module T N]
+ [CompatibleSMul M N S T] [CompatibleSMul M N R T] (f : M →ₗ[T] N) :
+ (f.restrictScalars S).restrictScalars R = f.restrictScalars R :=
+ rfl
+
variable (S M N R R₁)
/-- `LinearMap.restrictScalars` as a `LinearMap`. -/
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/Polynomial.lean b/Mathlib/Algebra/Module/LinearMap/Polynomial.lean
index 6f0b08d7782c3..823b874234f59 100644
--- a/Mathlib/Algebra/Module/LinearMap/Polynomial.lean
+++ b/Mathlib/Algebra/Module/LinearMap/Polynomial.lean
@@ -351,7 +351,7 @@ lemma polyCharpolyAux_basisIndep {ιM' : Type*} [Fintype ιM'] [DecidableEq ιM'
end aux
-open FiniteDimensional Matrix
+open Module Matrix
variable [Module.Free R M] [Module.Finite R M] (b : Basis ι R L)
@@ -479,11 +479,11 @@ lemma polyCharpoly_coeff_nilRank_ne_zero :
rw [nilRank_eq_polyCharpoly_natTrailingDegree _ b]
apply polyCharpoly_coeff_nilRankAux_ne_zero
-open FiniteDimensional Module.Free
+open Module Module.Free
lemma nilRank_le_card {ι : Type*} [Fintype ι] (b : Basis ι R M) : nilRank φ ≤ Fintype.card ι := by
apply Polynomial.natTrailingDegree_le_of_ne_zero
- rw [← FiniteDimensional.finrank_eq_card_basis b, ← polyCharpoly_natDegree φ (chooseBasis R L),
+ rw [← Module.finrank_eq_card_basis b, ← polyCharpoly_natDegree φ (chooseBasis R L),
Polynomial.coeff_natDegree, (polyCharpoly_monic _ _).leadingCoeff]
apply one_ne_zero
@@ -538,7 +538,7 @@ section IsDomain
variable [IsDomain R]
-open Cardinal FiniteDimensional MvPolynomial Module.Free in
+open Cardinal Module MvPolynomial Module.Free in
lemma exists_isNilRegular_of_finrank_le_card (h : finrank R M ≤ #R) :
∃ x : L, IsNilRegular φ x := by
let b := chooseBasis R L
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 45ebbceedbb8a..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
@@ -402,6 +403,29 @@ noncomputable instance isModule' : Module R (LocalizedModule S M) :=
theorem smul'_mk (r : R) (s : S) (m : M) : r • mk m s = mk (r • m) s := by
erw [mk_smul_mk r m 1 s, one_mul]
+lemma smul_eq_iff_of_mem
+ (r : R) (hr : r ∈ S) (x y : LocalizedModule S M) :
+ r • x = y ↔ x = Localization.mk 1 ⟨r, hr⟩ • y := by
+ induction x using induction_on with
+ | h m s =>
+ induction y using induction_on with
+ | h n t =>
+ rw [smul'_mk, mk_smul_mk, one_smul, mk_eq, mk_eq]
+ simp only [Subtype.exists, Submonoid.mk_smul, exists_prop]
+ fconstructor
+ · rintro ⟨a, ha, eq1⟩
+ refine ⟨a, ha, ?_⟩
+ rw [mul_smul, ← eq1, Submonoid.mk_smul, smul_comm r t]
+ · rintro ⟨a, ha, eq1⟩
+ refine ⟨a, ha, ?_⟩
+ rw [← eq1, mul_comm, mul_smul, Submonoid.mk_smul]
+ rfl
+
+lemma eq_zero_of_smul_eq_zero
+ (r : R) (hr : r ∈ S) (x : LocalizedModule S M) (hx : r • x = 0) : x = 0 := by
+ rw [smul_eq_iff_of_mem (hr := hr)] at hx
+ rw [hx, smul_zero]
+
theorem smul'_mul {A : Type*} [Semiring A] [Algebra R A] (x : T) (p₁ p₂ : LocalizedModule S A) :
x • p₁ * p₂ = x • (p₁ * p₂) := by
induction p₁, p₂ using induction_on₂ with | _ a₁ s₁ a₂ s₂ => _
@@ -461,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
@@ -605,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, ←
@@ -625,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
@@ -979,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]
@@ -1015,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ₛ`. -/
@@ -1045,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)
@@ -1056,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`.-/
@@ -1083,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. -/
@@ -1111,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. -/
@@ -1124,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]
@@ -1160,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/PID.lean b/Mathlib/Algebra/Module/PID.lean
index 65924b9cdde6d..a00bd3ef0ee93 100644
--- a/Mathlib/Algebra/Module/PID.lean
+++ b/Mathlib/Algebra/Module/PID.lean
@@ -225,7 +225,7 @@ theorem torsion_by_prime_power_decomposition (hN : Module.IsTorsion' N (Submonoi
⟨(@hN x).choose, by rw [← Quotient.mk_smul, (@hN x).choose_spec, Quotient.mk_zero]⟩
· have hs' := congr_arg (Submodule.map <| mkQ <| R ∙ s j) hs
rw [Submodule.map_span, Submodule.map_top, range_mkQ] at hs'; simp only [mkQ_apply] at hs'
- simp only [s']; rw [← Function.comp.assoc, Set.range_comp (_ ∘ s), Fin.range_succAbove]
+ simp only [s']; rw [← Function.comp_assoc, Set.range_comp (_ ∘ s), Fin.range_succAbove]
rw [← Set.range_comp, ← Set.insert_image_compl_eq_range _ j, Function.comp_apply,
(Quotient.mk_eq_zero _).mpr (Submodule.mem_span_singleton_self _), span_insert_zero] at hs'
exact hs'
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 ea72b33e221e7..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. -/
@@ -140,12 +144,6 @@ instance [h : ∀ i : ι, Projective R (A i)] : Projective R (Π₀ i, A i) :=
ext i x j
simp only [comp_apply, id_apply, DFinsupp.lsingle_apply, DFinsupp.coprodMap_apply_single, hg]
-end Semiring
-
-section Ring
-
-variable {R : Type u} [Ring R] {P : Type v} [AddCommGroup P] [Module R P]
-
/-- Free modules are projective. -/
theorem Projective.of_basis {ι : Type*} (b : Basis ι R P) : Projective R P := by
-- need P →ₗ (P →₀ R) for definition of projective.
@@ -159,9 +157,6 @@ theorem Projective.of_basis {ι : Type*} (b : Basis ι R P) : Projective R P :=
instance (priority := 100) Projective.of_free [Module.Free R P] : Module.Projective R P :=
.of_basis <| Module.Free.chooseBasis R P
-variable {R₀ M N} [CommRing R₀] [Algebra R₀ R] [AddCommGroup M] [Module R₀ M] [Module R M]
-variable [IsScalarTower R₀ R M] [AddCommGroup N] [Module R₀ N]
-
theorem Projective.of_split [Module.Projective R M]
(i : P →ₗ[R] M) (s : M →ₗ[R] P) (H : s.comp i = LinearMap.id) : Module.Projective R P := by
obtain ⟨g, hg⟩ := projective_lifting_property (Finsupp.linearCombination R id) s
@@ -174,6 +169,34 @@ theorem Projective.of_equiv [Module.Projective R M]
(e : M ≃ₗ[R] P) : Module.Projective R P :=
Projective.of_split e.symm e.toLinearMap (by ext; simp)
+/-- A quotient of a projective module is projective iff it is a direct summand. -/
+theorem Projective.iff_split_of_projective [Module.Projective R M] (s : M →ₗ[R] P)
+ (hs : Function.Surjective s) :
+ 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
+
+variable {R : Type u} [Ring R] {P : Type v} [AddCommMonoid P] [Module R P]
+variable {R₀ M N} [CommRing R₀] [Algebra R₀ R] [AddCommGroup M] [Module R₀ M] [Module R M]
+variable [IsScalarTower R₀ R M] [AddCommGroup N] [Module R₀ N]
+
/-- A module is projective iff it is the direct summand of a free module. -/
theorem Projective.iff_split : Module.Projective R P ↔
∃ (M : Type max u v) (_ : AddCommGroup M) (_ : Module R M) (_ : Module.Free R M)
@@ -181,12 +204,6 @@ theorem Projective.iff_split : Module.Projective R P ↔
⟨fun ⟨i, hi⟩ ↦ ⟨P →₀ R, _, _, inferInstance, i, Finsupp.linearCombination R id, LinearMap.ext hi⟩,
fun ⟨_, _, _, _, i, s, H⟩ ↦ Projective.of_split i s H⟩
-/-- A quotient of a projective module is projective iff it is a direct summand. -/
-theorem Projective.iff_split_of_projective [Module.Projective R M] (s : M →ₗ[R] P)
- (hs : Function.Surjective s) :
- Module.Projective R P ↔ ∃ i, s ∘ₗ i = LinearMap.id :=
- ⟨fun _ ↦ projective_lifting_property _ _ hs, fun ⟨i, H⟩ ↦ Projective.of_split i s H⟩
-
set_option maxSynthPendingDepth 2 in
open TensorProduct in
instance Projective.tensorProduct [hM : Module.Projective R M] [hN : Module.Projective R₀ N] :
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 bacd3bc47d6b5..11fcc080a6112 100644
--- a/Mathlib/Algebra/Module/Submodule/Bilinear.lean
+++ b/Mathlib/Algebra/Module/Submodule/Bilinear.lean
@@ -55,14 +55,16 @@ 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
- intro a ha
- apply @span_induction' R N _ _ _ t
- intro b hb
- exact subset_span ⟨_, ‹_›, _, ‹_›, rfl⟩
- all_goals intros; simp only [*, add_mem, smul_mem, zero_mem, _root_.map_zero, map_add,
- LinearMap.zero_apply, LinearMap.add_apply, LinearMap.smul_apply,
- map_smul]
+ apply @span_induction R M _ _ _ s
+ on_goal 1 =>
+ intro a ha
+ apply @span_induction R N _ _ _ t
+ · intro b hb
+ exact subset_span ⟨_, ‹_›, _, ‹_›, rfl⟩
+ all_goals
+ intros
+ simp only [*, add_mem, smul_mem, zero_mem, _root_.map_zero, map_add,
+ LinearMap.zero_apply, LinearMap.add_apply, LinearMap.smul_apply, map_smul]
· rw [span_le, image2_subset_iff]
intro a ha b hb
exact apply_mem_map₂ _ (subset_span ha) (subset_span hb)
@@ -78,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/Lattice.lean b/Mathlib/Algebra/Module/Submodule/Lattice.lean
index 1b9c97d71bbe6..3e15b4721bc18 100644
--- a/Mathlib/Algebra/Module/Submodule/Lattice.lean
+++ b/Mathlib/Algebra/Module/Submodule/Lattice.lean
@@ -241,6 +241,10 @@ theorem mem_finset_inf {ι} {s : Finset ι} {p : ι → Submodule R M} {x : M} :
x ∈ s.inf p ↔ ∀ i ∈ s, x ∈ p i := by
simp only [← SetLike.mem_coe, finset_inf_coe, Set.mem_iInter]
+lemma inf_iInf {ι : Type*} [Nonempty ι] {p : ι → Submodule R M} (q : Submodule R M) :
+ q ⊓ ⨅ i, p i = ⨅ i, q ⊓ p i :=
+ SetLike.coe_injective <| by simpa only [inf_coe, iInf_coe] using Set.inter_iInter _ _
+
theorem mem_sup_left {S T : Submodule R M} : ∀ {x : M}, x ∈ S → x ∈ S ⊔ T := by
have : S ≤ S ⊔ T := le_sup_left
rw [LE.le] at this
@@ -287,7 +291,7 @@ theorem toAddSubmonoid_sSup (s : Set (Submodule R M)) :
{ toAddSubmonoid := sSup (toAddSubmonoid '' s)
smul_mem' := fun t {m} h ↦ by
simp_rw [AddSubsemigroup.mem_carrier, AddSubmonoid.mem_toSubsemigroup, sSup_eq_iSup'] at h ⊢
- refine AddSubmonoid.iSup_induction'
+ refine AddSubmonoid.iSup_induction' _
(C := fun x _ ↦ t • x ∈ ⨆ p : toAddSubmonoid '' s, (p : AddSubmonoid M)) ?_ ?_
(fun x y _ _ ↦ ?_) h
· rintro ⟨-, ⟨p : Submodule R M, hp : p ∈ s, rfl⟩⟩ x (hx : x ∈ p)
diff --git a/Mathlib/Algebra/Module/Submodule/LinearMap.lean b/Mathlib/Algebra/Module/Submodule/LinearMap.lean
index 4ff64ac81d3b1..36b04e8dc9c3d 100644
--- a/Mathlib/Algebra/Module/Submodule/LinearMap.lean
+++ b/Mathlib/Algebra/Module/Submodule/LinearMap.lean
@@ -75,9 +75,11 @@ theorem subtype_apply (x : p) : p.subtype x = x :=
rfl
@[simp]
-theorem coeSubtype : (Submodule.subtype p : p → M) = Subtype.val :=
+theorem coe_subtype : (Submodule.subtype p : p → M) = Subtype.val :=
rfl
+@[deprecated (since := "2024-09-27")] alias coeSubtype := coe_subtype
+
theorem injective_subtype : Injective p.subtype :=
Subtype.coe_injective
@@ -181,6 +183,13 @@ lemma restrict_comp
(g ∘ₗ f).restrict hfg = (g.restrict hg) ∘ₗ (f.restrict hf) :=
rfl
+-- TODO Consider defining `Algebra R (p.compatibleMaps p)`, `AlgHom` version of `LinearMap.restrict`
+lemma restrict_smul_one
+ {R M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] {p : Submodule R M}
+ (μ : R) (h : ∀ x ∈ p, (μ • (1 : Module.End R M)) x ∈ p := fun _ ↦ p.smul_mem μ) :
+ (μ • 1 : Module.End R M).restrict h = μ • (1 : Module.End R p) :=
+ rfl
+
lemma restrict_commute {f g : M →ₗ[R] M} (h : Commute f g) {p : Submodule R M}
(hf : MapsTo f p p) (hg : MapsTo g p p) :
Commute (f.restrict hf) (g.restrict hg) := by
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 eaf5c011557e5..022184894e59c 100644
--- a/Mathlib/Algebra/Module/Submodule/Map.lean
+++ b/Mathlib/Algebra/Module/Submodule/Map.lean
@@ -99,11 +99,12 @@ theorem map_comp [RingHomSurjective σ₂₃] [RingHomSurjective σ₁₃] (f :
(g : M₂ →ₛₗ[σ₂₃] M₃) (p : Submodule R M) : map (g.comp f : M →ₛₗ[σ₁₃] M₃) p = map g (map f p) :=
SetLike.coe_injective <| by simp only [← image_comp, map_coe, LinearMap.coe_comp, comp_apply]
+@[gcongr]
theorem map_mono {f : F} {p p' : Submodule R M} : p ≤ p' → map f p ≤ map f p' :=
image_subset _
@[simp]
-theorem map_zero : map (0 : M →ₛₗ[σ₁₂] M₂) p = ⊥ :=
+protected theorem map_zero : map (0 : M →ₛₗ[σ₁₂] M₂) p = ⊥ :=
have : ∃ x : M, x ∈ p := ⟨0, p.zero_mem⟩
ext <| by simp [this, eq_comm]
@@ -119,6 +120,10 @@ theorem map_inf (f : F) {p q : Submodule R M} (hf : Injective f) :
(p ⊓ q).map f = p.map f ⊓ q.map f :=
SetLike.coe_injective <| Set.image_inter hf
+lemma map_iInf {ι : Type*} [Nonempty ι] {p : ι → Submodule R M} (f : F) (hf : Injective f) :
+ (⨅ i, p i).map f = ⨅ i, (p i).map f :=
+ SetLike.coe_injective <| by simpa only [map_coe, iInf_coe] using hf.injOn.image_iInter_eq
+
theorem range_map_nonempty (N : Submodule R M) :
(Set.range (fun ϕ => Submodule.map ϕ N : (M →ₛₗ[σ₁₂] M₂) → Submodule R₂ M₂)).Nonempty :=
⟨_, Set.mem_range.mpr ⟨0, rfl⟩⟩
@@ -186,6 +191,7 @@ theorem comap_comp (f : M →ₛₗ[σ₁₂] M₂) (g : M₂ →ₛₗ[σ₂₃
comap (g.comp f : M →ₛₗ[σ₁₃] M₃) p = comap f (comap g p) :=
rfl
+@[gcongr]
theorem comap_mono {f : F} {q q' : Submodule R₂ M₂} : q ≤ q' → comap f q ≤ comap f q' :=
preimage_mono
@@ -284,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
@@ -355,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₂]
@@ -457,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.
@@ -624,7 +639,7 @@ This is `LinearEquiv.ofSubmodule'` but with `map` on the right instead of `comap
def submoduleMap (p : Submodule R M) : p ≃ₛₗ[σ₁₂] ↥(p.map (e : M →ₛₗ[σ₁₂] M₂) : Submodule R₂ M₂) :=
{ ((e : M →ₛₗ[σ₁₂] M₂).domRestrict p).codRestrict (p.map (e : M →ₛₗ[σ₁₂] M₂)) fun x =>
⟨x, by
- simp only [LinearMap.domRestrict_apply, eq_self_iff_true, and_true_iff, SetLike.coe_mem,
+ simp only [LinearMap.domRestrict_apply, eq_self_iff_true, and_true, SetLike.coe_mem,
SetLike.mem_coe]⟩ with
invFun := fun y =>
⟨(e.symm : M₂ →ₛₗ[σ₂₁] M) y, by
diff --git a/Mathlib/Algebra/Module/Submodule/Pointwise.lean b/Mathlib/Algebra/Module/Submodule/Pointwise.lean
index 031be85372fc7..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
@@ -418,7 +419,7 @@ lemma set_smul_eq_map [SMulCommClass R R N] :
exact ⟨Finsupp.single r ⟨n, hn⟩, Finsupp.single_mem_supported _ _ hr, by simp⟩
· intro x hx
obtain ⟨c, hc, rfl⟩ := hx
- simp only [LinearMap.coe_comp, coeSubtype, Finsupp.coe_lsum, Finsupp.sum, Function.comp_apply]
+ simp only [LinearMap.coe_comp, coe_subtype, Finsupp.coe_lsum, Finsupp.sum, Function.comp_apply]
rw [AddSubmonoid.coe_finset_sum]
refine Submodule.sum_mem (p := sR • N) (t := c.support) ?_ _ ⟨sR • N, ?_⟩
· rintro r hr
@@ -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 ecd92053f2c94..096deecf0532a 100644
--- a/Mathlib/Algebra/Module/Torsion.lean
+++ b/Mathlib/Algebra/Module/Torsion.lean
@@ -3,11 +3,11 @@ Copyright (c) 2022 Pierre-Alexandre Bazin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Pierre-Alexandre Bazin
-/
-import Mathlib.LinearAlgebra.Isomorphisms
+import Mathlib.Algebra.DirectSum.Module
+import Mathlib.Algebra.Module.ZMod
import Mathlib.GroupTheory.Torsion
+import Mathlib.LinearAlgebra.Isomorphisms
import Mathlib.RingTheory.Coprime.Ideal
-import Mathlib.Data.ZMod.Module
-import Mathlib.Algebra.DirectSum.Module
/-!
# Torsion submodules
@@ -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/ULift.lean b/Mathlib/Algebra/Module/ULift.lean
index 730083e6948c9..1517ff6089728 100644
--- a/Mathlib/Algebra/Module/ULift.lean
+++ b/Mathlib/Algebra/Module/ULift.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.GroupWithZero.ULift
import Mathlib.Algebra.Ring.ULift
diff --git a/Mathlib/Algebra/Module/ZLattice/Basic.lean b/Mathlib/Algebra/Module/ZLattice/Basic.lean
index 1b656c31bf115..8113915f8a6a5 100644
--- a/Mathlib/Algebra/Module/ZLattice/Basic.lean
+++ b/Mathlib/Algebra/Module/ZLattice/Basic.lean
@@ -17,21 +17,31 @@ subgroup of `E` such that `L` spans `E` over `K`.
A `ℤ`-lattice `L` can be defined in two ways:
* For `b` a basis of `E`, then `L = Submodule.span ℤ (Set.range b)` is a ℤ-lattice of `E`
-* As an `AddSubgroup E` with the additional properties:
+* As an`ℤ-submodule` of `E` with the additional properties:
* `DiscreteTopology L`, that is `L` is discrete
* `Submodule.span ℝ (L : Set E) = ⊤`, that is `L` spans `E` over `K`.
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.
-* `ZLattice.module_free`: an AddSubgroup of `E` that is discrete and spans `E` over `K` is a free
+* `ZLattice.module_free`: a `ℤ`-submodule of `E` that is discrete and spans `E` over `K` is a free
`ℤ`-module
-* `ZLattice.rank`: an AddSubgroup of `E` that is discrete and spans `E` over `K` is a free
-`ℤ`-module of `ℤ`-rank equal to the `K`-rank of `E`
+* `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
+
+A `ZLattice` could be defined either as a `AddSubgroup E` or a `Submodule ℤ E`. However, the module
+aspect appears to be the more useful one (especially in computations involving basis) and is also
+consistent with the `ZSpan` construction of `ℤ`-lattices.
+
-/
@@ -51,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}
@@ -269,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]
@@ -310,17 +325,22 @@ theorem fundamentalDomain_measurableSet [MeasurableSpace E] [OpensMeasurableSpac
by `ZSpan.fundamentalDomain` is a fundamental domain. -/
protected theorem isAddFundamentalDomain [Finite ι] [MeasurableSpace E] [OpensMeasurableSpace E]
(μ : Measure E) :
- IsAddFundamentalDomain (span ℤ (Set.range b)).toAddSubgroup (fundamentalDomain b) μ := by
+ IsAddFundamentalDomain (span ℤ (Set.range b)) (fundamentalDomain b) μ := by
cases nonempty_fintype ι
exact IsAddFundamentalDomain.mk' (nullMeasurableSet (fundamentalDomain_measurableSet b))
fun x => exist_unique_vadd_mem_fundamentalDomain b x
+/-- A version of `ZSpan.isAddFundamentalDomain` for `AddSubgroup`. -/
+protected theorem isAddFundamentalDomain' [Finite ι] [MeasurableSpace E] [OpensMeasurableSpace E]
+ (μ : Measure E) :
+ IsAddFundamentalDomain (span ℤ (Set.range b)).toAddSubgroup (fundamentalDomain b) μ :=
+ ZSpan.isAddFundamentalDomain b μ
+
theorem measure_fundamentalDomain_ne_zero [Finite ι] [MeasurableSpace E] [BorelSpace E]
{μ : Measure E} [Measure.IsAddHaarMeasure μ] :
μ (fundamentalDomain b) ≠ 0 := by
convert (ZSpan.isAddFundamentalDomain b μ).measure_ne_zero (NeZero.ne μ)
- simp only [mem_toAddSubgroup]
- infer_instance
+ exact (inferInstance : VAddInvariantMeasure (span ℤ (Set.range b)).toAddSubgroup E μ)
theorem measure_fundamentalDomain [Fintype ι] [DecidableEq ι] [MeasurableSpace E] (μ : Measure E)
[BorelSpace E] [Measure.IsAddHaarMeasure μ] (b₀ : Basis ι ℝ E) :
@@ -372,27 +392,28 @@ end ZSpan
section ZLattice
-open Submodule FiniteDimensional
+open Submodule Module ZSpan
-- TODO: generalize this class to other rings than `ℤ`
-/-- An `L : Addsubgroup E` where `E` is a vector space over a normed field `K` is a `ℤ`-lattice if
+/-- `L : Submodule ℤ E` where `E` is a vector space over a normed field `K` is a `ℤ`-lattice if
it is discrete and spans `E` over `K`. -/
class IsZLattice (K : Type*) [NormedField K] {E : Type*} [NormedAddCommGroup E] [NormedSpace K E]
- (L : AddSubgroup E) [DiscreteTopology L] : Prop where
+ (L : Submodule ℤ E) [DiscreteTopology L] : Prop where
/-- `L` spans the full space `E` over `K`. -/
span_top : span K (L : Set E) = ⊤
theorem _root_.ZSpan.isZLattice {E ι : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
[Finite ι] (b : Basis ι ℝ E) :
- IsZLattice ℝ (span ℤ (Set.range b)).toAddSubgroup where
+ 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 : AddSubgroup E) [DiscreteTopology L]
+variable [ProperSpace E] (L : Submodule ℤ E) [DiscreteTopology L]
-theorem ZLattice.FG [hs : IsZLattice K L] : AddSubgroup.FG L := by
- suffices (AddSubgroup.toIntSubmodule L).FG by exact (fg_iff_add_subgroup_fg _).mp this
+theorem Zlattice.FG [hs : IsZLattice K L] : L.FG := by
obtain ⟨s, ⟨h_incl, ⟨h_span, h_lind⟩⟩⟩ := exists_linearIndependent K (L : Set E)
-- Let `s` be a maximal `K`-linear independent family of elements of `L`. We show that
-- `L` is finitely generated (as a ℤ-module) because it fits in the exact sequence
@@ -401,25 +422,26 @@ theorem ZLattice.FG [hs : IsZLattice K L] : AddSubgroup.FG L := by
· -- Let `b` be the `K`-basis of `E` formed by the vectors in `s`. The elements of
-- `L ⧸ span ℤ s = L ⧸ span ℤ b` are in bijection with elements of `L ∩ fundamentalDomain b`
-- so there are finitely many since `fundamentalDomain b` is bounded.
- refine fg_def.mpr ⟨map (span ℤ s).mkQ (AddSubgroup.toIntSubmodule L), ?_, span_eq _⟩
+ refine fg_def.mpr ⟨map (span ℤ s).mkQ L, ?_, span_eq _⟩
let b := Basis.mk h_lind (by
rw [← hs.span_top, ← h_span]
exact span_mono (by simp only [Subtype.range_coe_subtype, Set.setOf_mem_eq, subset_rfl]))
rw [show span ℤ s = span ℤ (Set.range b) by simp [b, Basis.coe_mk, Subtype.range_coe_subtype]]
have : Fintype s := h_lind.setFinite.fintype
- refine Set.Finite.of_finite_image (f := ((↑) : _ → E) ∘ ZSpan.quotientEquiv b) ?_
- (Function.Injective.injOn (Subtype.coe_injective.comp (ZSpan.quotientEquiv b).injective))
- have : Set.Finite ((ZSpan.fundamentalDomain b) ∩ L) :=
- Metric.finite_isBounded_inter_isClosed (ZSpan.fundamentalDomain_isBounded b) inferInstance
+ refine Set.Finite.of_finite_image (f := ((↑) : _ → E) ∘ quotientEquiv b) ?_
+ (Function.Injective.injOn (Subtype.coe_injective.comp (quotientEquiv b).injective))
+ have : ((fundamentalDomain b) ∩ L).Finite := by
+ change ((fundamentalDomain b) ∩ L.toAddSubgroup).Finite
+ have : DiscreteTopology L.toAddSubgroup := (inferInstance : DiscreteTopology L)
+ exact Metric.finite_isBounded_inter_isClosed (fundamentalDomain_isBounded b) inferInstance
refine Set.Finite.subset this ?_
rintro _ ⟨_, ⟨⟨x, ⟨h_mem, rfl⟩⟩, rfl⟩⟩
- rw [Function.comp_apply, mkQ_apply, ZSpan.quotientEquiv_apply_mk, ZSpan.fractRestrict_apply]
+ rw [Function.comp_apply, mkQ_apply, quotientEquiv_apply_mk, fractRestrict_apply]
refine ⟨?_, ?_⟩
- · exact ZSpan.fract_mem_fundamentalDomain b x
- · rw [ZSpan.fract, SetLike.mem_coe, sub_eq_add_neg]
- refine AddSubgroup.add_mem _ h_mem
- (neg_mem (Set.mem_of_subset_of_mem ?_ (Subtype.mem (ZSpan.floor b x))))
- rw [show (L : Set E) = AddSubgroup.toIntSubmodule L by rfl]
+ · exact fract_mem_fundamentalDomain b x
+ · rw [fract, SetLike.mem_coe, sub_eq_add_neg]
+ refine Submodule.add_mem _ h_mem
+ (neg_mem (Set.mem_of_subset_of_mem ?_ (Subtype.mem (floor b x))))
rw [SetLike.coe_subset_coe, Basis.coe_mk, Subtype.range_coe_subtype, Set.setOf_mem_eq]
exact span_le.mpr h_incl
· -- `span ℤ s` is finitely generated because `s` is finite
@@ -427,46 +449,38 @@ theorem ZLattice.FG [hs : IsZLattice K L] : AddSubgroup.FG L := by
exact fg_span (LinearIndependent.setFinite h_lind)
theorem ZLattice.module_finite [IsZLattice K L] : Module.Finite ℤ L :=
- Module.Finite.iff_addGroup_fg.mpr ((AddGroup.fg_iff_addSubgroup_fg L).mpr (FG K L))
+ Module.Finite.iff_fg.mpr (Zlattice.FG K L)
-instance instModuleFinite_of_discrete_addSubgroup {E : Type*} [NormedAddCommGroup E]
- [NormedSpace ℝ E] [FiniteDimensional ℝ E] (L : AddSubgroup E) [DiscreteTopology L] :
+instance instModuleFinite_of_discrete_submodule {E : Type*} [NormedAddCommGroup E]
+ [NormedSpace ℝ E] [FiniteDimensional ℝ E] (L : Submodule ℤ E) [DiscreteTopology L] :
Module.Finite ℤ L := by
let f := (span ℝ (L : Set E)).subtype
- let L₀ := (AddSubgroup.toIntSubmodule L).comap (f.restrictScalars ℤ)
+ let L₀ := L.comap (f.restrictScalars ℤ)
have h_img : f '' L₀ = L := by
rw [← LinearMap.coe_restrictScalars ℤ f, ← Submodule.map_coe (f.restrictScalars ℤ),
- Submodule.map_comap_eq_self, AddSubgroup.coe_toIntSubmodule]
+ Submodule.map_comap_eq_self]
exact fun x hx ↦ LinearMap.mem_range.mpr ⟨⟨x, Submodule.subset_span hx⟩, rfl⟩
suffices Module.Finite ℤ L₀ by
- have : L₀.map (f.restrictScalars ℤ) = (AddSubgroup.toIntSubmodule L) :=
+ have : L₀.map (f.restrictScalars ℤ) = L :=
SetLike.ext'_iff.mpr h_img
convert this ▸ Module.Finite.map L₀ (f.restrictScalars ℤ)
- have : DiscreteTopology L₀.toAddSubgroup := by
+ have : DiscreteTopology L₀ := by
refine DiscreteTopology.preimage_of_continuous_injective (L : Set E) ?_ (injective_subtype _)
exact LinearMap.continuous_of_finiteDimensional f
- have : IsZLattice ℝ L₀.toAddSubgroup := ⟨by
+ have : IsZLattice ℝ L₀ := ⟨by
rw [← (Submodule.map_injective_of_injective (injective_subtype _)).eq_iff, Submodule.map_span,
- Submodule.map_top, range_subtype, coe_toAddSubgroup, h_img]⟩
- exact ZLattice.module_finite ℝ L₀.toAddSubgroup
+ Submodule.map_top, range_subtype, h_img]⟩
+ exact ZLattice.module_finite ℝ L₀
theorem ZLattice.module_free [IsZLattice K L] : Module.Free ℤ L := by
have : Module.Finite ℤ L := module_finite K L
have : Module ℚ E := Module.compHom E (algebraMap ℚ K)
- have : NoZeroSMulDivisors ℤ E := RatModule.noZeroSMulDivisors
- have : NoZeroSMulDivisors ℤ L := by
- change NoZeroSMulDivisors ℤ (AddSubgroup.toIntSubmodule L)
- exact noZeroSMulDivisors _
infer_instance
-instance instModuleFree_of_discrete_addSubgroup {E : Type*} [NormedAddCommGroup E]
- [NormedSpace ℝ E] [FiniteDimensional ℝ E] (L : AddSubgroup E) [DiscreteTopology L] :
+instance instModuleFree_of_discrete_submodule {E : Type*} [NormedAddCommGroup E]
+ [NormedSpace ℝ E] [FiniteDimensional ℝ E] (L : Submodule ℤ E) [DiscreteTopology L] :
Module.Free ℤ L := by
have : Module ℚ E := Module.compHom E (algebraMap ℚ ℝ)
- have : NoZeroSMulDivisors ℤ E := RatModule.noZeroSMulDivisors
- have : NoZeroSMulDivisors ℤ L := by
- change NoZeroSMulDivisors ℤ (AddSubgroup.toIntSubmodule L)
- exact noZeroSMulDivisors _
infer_instance
theorem ZLattice.rank [hs : IsZLattice K L] : finrank ℤ L = finrank K E := by
@@ -478,10 +492,10 @@ theorem ZLattice.rank [hs : IsZLattice K L] : finrank ℤ L = finrank K E := by
-- Let `b` be a `ℤ`-basis of `L` formed of vectors of `E`
let b := Subtype.val ∘ b₀
have : LinearIndependent ℤ b :=
- LinearIndependent.map' b₀.linearIndependent (L.toIntSubmodule.subtype) (ker_subtype _)
+ LinearIndependent.map' b₀.linearIndependent (L.subtype) (ker_subtype _)
-- We prove some assertions that will be useful later on
- have h_spanL : span ℤ (Set.range b) = AddSubgroup.toIntSubmodule L := by
- convert congrArg (map (Submodule.subtype (AddSubgroup.toIntSubmodule L))) b₀.span_eq
+ have h_spanL : span ℤ (Set.range b) = L := by
+ convert congrArg (map (Submodule.subtype L)) b₀.span_eq
· rw [map_span, Set.range_comp]
rfl
· exact (map_subtype_top _).symm
@@ -527,24 +541,25 @@ theorem ZLattice.rank [hs : IsZLattice K L] : finrank ℤ L = finrank K E := by
-- But that follows from the fact that there exist `n, m : ℕ`, `n ≠ m`
-- such that `(n - m) • v ∈ span ℤ e` which is true since `n ↦ ZSpan.fract e (n • v)`
-- takes value into the finite set `fundamentalDomain e ∩ L`
- have h_mapsto : Set.MapsTo (fun n : ℤ => ZSpan.fract e (n • v)) Set.univ
+ have h_mapsto : Set.MapsTo (fun n : ℤ => fract e (n • v)) Set.univ
(Metric.closedBall 0 (∑ i, ‖e i‖) ∩ (L : Set E)) := by
rw [Set.mapsTo_inter, Set.mapsTo_univ_iff, Set.mapsTo_univ_iff]
- refine ⟨fun _ ↦ mem_closedBall_zero_iff.mpr (ZSpan.norm_fract_le e _), fun _ => ?_⟩
- · change _ ∈ AddSubgroup.toIntSubmodule L
- rw [← h_spanL]
+ refine ⟨fun _ ↦ mem_closedBall_zero_iff.mpr (norm_fract_le e _), fun _ => ?_⟩
+ · rw [← h_spanL]
refine sub_mem ?_ ?_
· exact zsmul_mem (subset_span (Set.diff_subset hv)) _
· exact span_mono (by simp [e, ht_inc]) (coe_mem _)
- have h_finite : Set.Finite (Metric.closedBall 0 (∑ i, ‖e i‖) ∩ (L : Set E)) :=
- Metric.finite_isBounded_inter_isClosed Metric.isBounded_closedBall inferInstance
+ have h_finite : Set.Finite (Metric.closedBall 0 (∑ i, ‖e i‖) ∩ (L : Set E)) := by
+ change ((_ : Set E) ∩ L.toAddSubgroup).Finite
+ have : DiscreteTopology L.toAddSubgroup := (inferInstance : DiscreteTopology L)
+ exact Metric.finite_isBounded_inter_isClosed Metric.isBounded_closedBall inferInstance
obtain ⟨n, -, m, -, h_neq, h_eq⟩ := Set.Infinite.exists_ne_map_eq_of_mapsTo
Set.infinite_univ h_mapsto h_finite
have h_nz : (-n + m : ℚ) ≠ 0 := by
rwa [Ne, add_eq_zero_iff_eq_neg.not, neg_inj, Rat.coe_int_inj, ← Ne]
apply (smul_mem_iff _ h_nz).mp
refine span_subset_span ℤ ℚ _ ?_
- rwa [add_smul, neg_smul, SetLike.mem_coe, ← ZSpan.fract_eq_fract, Int.cast_smul_eq_zsmul ℚ,
+ rwa [add_smul, neg_smul, SetLike.mem_coe, ← fract_eq_fract, Int.cast_smul_eq_zsmul ℚ,
Int.cast_smul_eq_zsmul ℚ]
· -- To prove that `finrank K E ≤ finrank ℤ L`, we use the fact `b` generates `E` over `K`
-- and thus `finrank K E ≤ card b = finrank ℤ L`
@@ -557,51 +572,126 @@ variable {ι : Type*} [hs : IsZLattice K L] (b : Basis ι ℤ L)
/-- Any `ℤ`-basis of `L` is also a `K`-basis of `E`. -/
def Basis.ofZLatticeBasis :
Basis ι K E := by
- have : Finite ℤ L := ZLattice.module_finite K L
+ have : Module.Finite ℤ L := ZLattice.module_finite K L
have : Free ℤ L := ZLattice.module_free K L
let e := Basis.indexEquiv (Free.chooseBasis ℤ L) b
have : Fintype ι := Fintype.ofEquiv _ e
- refine basisOfTopLeSpanOfCardEqFinrank (L.subtype.toIntLinearMap ∘ b) ?_ ?_
+ refine basisOfTopLeSpanOfCardEqFinrank (L.subtype ∘ b) ?_ ?_
· rw [← span_span_of_tower ℤ, Set.range_comp, ← map_span, Basis.span_eq, Submodule.map_top,
- top_le_iff, AddMonoidHom.coe_toIntLinearMap_range, AddSubgroup.subtype_range,
- AddSubgroup.coe_toIntSubmodule, hs.span_top]
+ range_subtype, top_le_iff, hs.span_top]
· rw [← Fintype.card_congr e, ← finrank_eq_card_chooseBasisIndex, ZLattice.rank K L]
@[simp]
theorem Basis.ofZLatticeBasis_apply (i : ι) :
- b.ofZLatticeBasis K L i = b i := by simp [Basis.ofZLatticeBasis]
+ b.ofZLatticeBasis K L i = b i := by simp [Basis.ofZLatticeBasis]
@[simp]
theorem Basis.ofZLatticeBasis_repr_apply (x : L) (i : ι) :
(b.ofZLatticeBasis K L).repr x i = b.repr x i := by
- suffices ((b.ofZLatticeBasis K L).repr.toLinearMap.restrictScalars ℤ) ∘ₗ L.subtype.toIntLinearMap
+ suffices ((b.ofZLatticeBasis K L).repr.toLinearMap.restrictScalars ℤ) ∘ₗ L.subtype
= Finsupp.mapRange.linearMap (Algebra.linearMap ℤ K) ∘ₗ b.repr.toLinearMap by
exact DFunLike.congr_fun (LinearMap.congr_fun this x) i
refine Basis.ext b fun i ↦ ?_
simp_rw [LinearMap.coe_comp, Function.comp_apply, LinearMap.coe_restrictScalars,
- LinearEquiv.coe_coe, AddMonoidHom.coe_toIntLinearMap, AddSubgroup.coeSubtype,
- ← b.ofZLatticeBasis_apply K, repr_self, Finsupp.mapRange.linearMap_apply,
- Finsupp.mapRange_single, Algebra.linearMap_apply, map_one]
+ LinearEquiv.coe_coe, coe_subtype, ← b.ofZLatticeBasis_apply K, repr_self,
+ Finsupp.mapRange.linearMap_apply, Finsupp.mapRange_single, Algebra.linearMap_apply, map_one]
theorem Basis.ofZLatticeBasis_span :
- (span ℤ (Set.range (b.ofZLatticeBasis K))).toAddSubgroup = L := by
- calc (span ℤ (Set.range (b.ofZLatticeBasis K))).toAddSubgroup
- _ = (span ℤ (L.subtype.toIntLinearMap '' (Set.range b))).toAddSubgroup := by congr; ext; simp
- _ = (map L.subtype.toIntLinearMap (span ℤ (Set.range b))).toAddSubgroup := by
- rw [Submodule.map_span]
+ (span ℤ (Set.range (b.ofZLatticeBasis K))) = L := by
+ calc (span ℤ (Set.range (b.ofZLatticeBasis K)))
+ _ = (span ℤ (L.subtype '' (Set.range b))) := by congr; ext; simp
+ _ = (map L.subtype (span ℤ (Set.range b))) := by rw [Submodule.map_span]
_ = L := by simp [b.span_eq]
+open MeasureTheory in
theorem ZLattice.isAddFundamentalDomain {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- [FiniteDimensional ℝ E] {L : AddSubgroup E} [DiscreteTopology L] [IsZLattice ℝ L] [Finite ι]
- (b : Basis ι ℤ L) [MeasurableSpace E] [OpensMeasurableSpace E] (μ : MeasureTheory.Measure E) :
- MeasureTheory.IsAddFundamentalDomain L (ZSpan.fundamentalDomain (b.ofZLatticeBasis ℝ)) μ := by
+ [FiniteDimensional ℝ E] {L : Submodule ℤ E} [DiscreteTopology L] [IsZLattice ℝ L] [Finite ι]
+ (b : Basis ι ℤ L) [MeasurableSpace E] [OpensMeasurableSpace E] (μ : Measure E) :
+ IsAddFundamentalDomain L (fundamentalDomain (b.ofZLatticeBasis ℝ)) μ := by
convert ZSpan.isAddFundamentalDomain (b.ofZLatticeBasis ℝ) μ
all_goals exact (b.ofZLatticeBasis_span ℝ).symm
-instance instCountable_of_discrete_addSubgroup {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- [FiniteDimensional ℝ E] (L : AddSubgroup E) [DiscreteTopology L] [IsZLattice ℝ L] :
+instance instCountable_of_discrete_submodule {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
+ [FiniteDimensional ℝ E] (L : Submodule ℤ E) [DiscreteTopology L] [IsZLattice ℝ L] :
Countable L := by
- simp_rw [← (Module.Free.chooseBasis ℤ L).ofZLatticeBasis_span ℝ, mem_toAddSubgroup]
+ 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 4979ca5872ab3..f5740d29e7505 100644
--- a/Mathlib/Algebra/Module/ZLattice/Covolume.lean
+++ b/Mathlib/Algebra/Module/ZLattice/Covolume.lean
@@ -8,9 +8,9 @@ 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 `AddSubgroup E` that spans `E` over `ℝ`.
+Let `L` be a `ℤ`-lattice `L` defined as a discrete `ℤ`-submodule of `E` that spans `E` over `ℝ`.
## Main definitions and results
@@ -29,14 +29,11 @@ noncomputable section
namespace ZLattice
-open Submodule MeasureTheory FiniteDimensional 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 : AddSubgroup 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
@@ -49,37 +46,52 @@ section Real
variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E]
variable [MeasurableSpace E] [BorelSpace E]
-variable (L : AddSubgroup E) [DiscreteTopology L] [IsZLattice ℝ L]
+variable (L : Submodule ℤ E) [DiscreteTopology L] [IsZLattice ℝ L]
variable (μ : Measure E := by volume_tac) [Measure.IsAddHaarMeasure μ]
theorem covolume_eq_measure_fundamentalDomain {F : Set E} (h : IsAddFundamentalDomain L F μ) :
- covolume L μ = (μ F).toReal := congr_arg ENNReal.toReal (h.covolume_eq_volume μ)
+ covolume L μ = (μ F).toReal := by
+ have : MeasurableVAdd L E := (inferInstance : MeasurableVAdd L.toAddSubgroup E)
+ have : VAddInvariantMeasure L E μ := (inferInstance : VAddInvariantMeasure L.toAddSubgroup E μ)
+ exact congr_arg ENNReal.toReal (h.covolume_eq_volume μ)
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
exact b.ofZLatticeBasis_apply ℝ L _
-theorem covolume_eq_det {ι : Type*} [Fintype ι] [DecidableEq ι] (L : AddSubgroup (ι → ℝ))
+theorem covolume_eq_det {ι : Type*} [Fintype ι] [DecidableEq ι] (L : Submodule ℤ (ι → ℝ))
[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/Data/ZMod/Module.lean b/Mathlib/Algebra/Module/ZMod.lean
similarity index 94%
rename from Mathlib/Data/ZMod/Module.lean
rename to Mathlib/Algebra/Module/ZMod.lean
index 64cb1d86b6160..961af9fe2c048 100644
--- a/Mathlib/Data/ZMod/Module.lean
+++ b/Mathlib/Algebra/Module/ZMod.lean
@@ -5,7 +5,6 @@ Authors: Lawrence Wu
-/
import Mathlib.Algebra.Module.Submodule.Lattice
import Mathlib.Data.ZMod.Basic
-import Mathlib.Order.OmegaCompletePartialOrder
/-!
# The `ZMod n`-module structure on Abelian groups whose elements have order dividing `n`
@@ -92,9 +91,8 @@ theorem toZModSubmodule_symm :
⇑((toZModSubmodule n).symm : _ ≃o AddSubgroup M) = Submodule.toAddSubgroup :=
rfl
-@[simp]
-theorem coe_toZModSubmodule (S : AddSubgroup M) : (toZModSubmodule n S : Set M) = S :=
- rfl
+@[simp] lemma coe_toZModSubmodule (S : AddSubgroup M) : (toZModSubmodule n S : Set M) = S := rfl
+@[simp] lemma mem_toZModSubmodule {S : AddSubgroup M} : x ∈ toZModSubmodule n S ↔ x ∈ S := .rfl
@[simp]
theorem toZModSubmodule_toAddSubgroup (S : AddSubgroup M) :
diff --git a/Mathlib/Algebra/MonoidAlgebra/Basic.lean b/Mathlib/Algebra/MonoidAlgebra/Basic.lean
index 23c0fabadf6c7..e5d8512805835 100644
--- a/Mathlib/Algebra/MonoidAlgebra/Basic.lean
+++ b/Mathlib/Algebra/MonoidAlgebra/Basic.lean
@@ -1,10 +1,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, Yury Kudryashov, Scott Morrison
+Authors: Johannes Hölzl, Yury Kudryashov, Kim Morrison
-/
-import Mathlib.Algebra.Algebra.Equiv
+import Mathlib.Algebra.MonoidAlgebra.Defs
import Mathlib.Algebra.Algebra.NonUnitalHom
+import Mathlib.Algebra.Algebra.Equiv
import Mathlib.Algebra.BigOperators.Finsupp
import Mathlib.Algebra.Module.BigOperators
import Mathlib.Data.Finsupp.Basic
@@ -13,43 +14,8 @@ import Mathlib.LinearAlgebra.Finsupp
/-!
# Monoid algebras
-When the domain of a `Finsupp` has a multiplicative or additive structure, we can define
-a convolution product. To mathematicians this structure is known as the "monoid algebra",
-i.e. the finite formal linear combinations over a given semiring of elements of the monoid.
-The "group ring" ℤ[G] or the "group algebra" k[G] are typical uses.
-
-In fact the construction of the "monoid algebra" makes sense when `G` is not even a monoid, but
-merely a magma, i.e., when `G` carries a multiplication which is not required to satisfy any
-conditions at all. In this case the construction yields a not-necessarily-unital,
-not-necessarily-associative algebra but it is still adjoint to the forgetful functor from such
-algebras to magmas, and we prove this as `MonoidAlgebra.liftMagma`.
-
-In this file we define `MonoidAlgebra k G := G →₀ k`, and `AddMonoidAlgebra k G`
-in the same way, and then define the convolution product on these.
-
-When the domain is additive, this is used to define polynomials:
-```
-Polynomial R := AddMonoidAlgebra R ℕ
-MvPolynomial σ α := AddMonoidAlgebra R (σ →₀ ℕ)
-```
-
-When the domain is multiplicative, e.g. a group, this will be used to define the group ring.
-
-## Notation
-
-We introduce the notation `R[A]` for `AddMonoidAlgebra R A`.
-
-## Implementation note
-Unfortunately because additive and multiplicative structures both appear in both cases,
-it doesn't appear to be possible to make much use of `to_additive`, and we just settle for
-saying everything twice.
-
-Similarly, I attempted to just define
-`k[G] := MonoidAlgebra k (Multiplicative G)`, but the definitional equality
-`Multiplicative G = G` leaks through everywhere, and seems impossible to use.
-/
-
noncomputable section
open Finset
@@ -62,518 +28,10 @@ variable (k : Type u₁) (G : Type u₂) (H : Type*) {R : Type*}
/-! ### Multiplicative monoids -/
-
-section
-
-variable [Semiring k]
-
-/-- The monoid algebra over a semiring `k` generated by the monoid `G`.
-It is the type of finite formal `k`-linear combinations of terms of `G`,
-endowed with the convolution product.
--/
-def MonoidAlgebra : Type max u₁ u₂ :=
- G →₀ k
-
--- Porting note: The compiler couldn't derive this.
-instance MonoidAlgebra.inhabited : Inhabited (MonoidAlgebra k G) :=
- inferInstanceAs (Inhabited (G →₀ k))
-
--- Porting note: The compiler couldn't derive this.
-instance MonoidAlgebra.addCommMonoid : AddCommMonoid (MonoidAlgebra k G) :=
- inferInstanceAs (AddCommMonoid (G →₀ k))
-
-instance MonoidAlgebra.instIsCancelAdd [IsCancelAdd k] : IsCancelAdd (MonoidAlgebra k G) :=
- inferInstanceAs (IsCancelAdd (G →₀ k))
-
-instance MonoidAlgebra.coeFun : CoeFun (MonoidAlgebra k G) fun _ => G → k :=
- Finsupp.instCoeFun
-
-end
-
namespace MonoidAlgebra
variable {k G}
-section
-
-variable [Semiring k] [NonUnitalNonAssocSemiring R]
-
--- Porting note: `reducible` cannot be `local`, so we replace some definitions and theorems with
--- new ones which have new types.
-
-abbrev single (a : G) (b : k) : MonoidAlgebra k G := Finsupp.single a b
-
-theorem single_zero (a : G) : (single a 0 : MonoidAlgebra k G) = 0 := Finsupp.single_zero a
-
-theorem single_add (a : G) (b₁ b₂ : k) : single a (b₁ + b₂) = single a b₁ + single a b₂ :=
- Finsupp.single_add a b₁ b₂
-
-@[simp]
-theorem sum_single_index {N} [AddCommMonoid N] {a : G} {b : k} {h : G → k → N}
- (h_zero : h a 0 = 0) :
- (single a b).sum h = h a b := Finsupp.sum_single_index h_zero
-
-@[simp]
-theorem sum_single (f : MonoidAlgebra k G) : f.sum single = f :=
- Finsupp.sum_single f
-
-theorem single_apply {a a' : G} {b : k} [Decidable (a = a')] :
- single a b a' = if a = a' then b else 0 :=
- Finsupp.single_apply
-
-@[simp]
-theorem single_eq_zero {a : G} {b : k} : single a b = 0 ↔ b = 0 := Finsupp.single_eq_zero
-
-abbrev mapDomain {G' : Type*} (f : G → G') (v : MonoidAlgebra k G) : MonoidAlgebra k G' :=
- Finsupp.mapDomain f v
-
-theorem mapDomain_sum {k' G' : Type*} [Semiring k'] {f : G → G'} {s : MonoidAlgebra k' G}
- {v : G → k' → MonoidAlgebra k G} :
- mapDomain f (s.sum v) = s.sum fun a b => mapDomain f (v a b) :=
- Finsupp.mapDomain_sum
-
-/-- A non-commutative version of `MonoidAlgebra.lift`: given an additive homomorphism `f : k →+ R`
-and a homomorphism `g : G → R`, returns the additive homomorphism from
-`MonoidAlgebra k G` such that `liftNC f g (single a b) = f b * g a`. If `f` is a ring homomorphism
-and the range of either `f` or `g` is in center of `R`, then the result is a ring homomorphism. If
-`R` is a `k`-algebra and `f = algebraMap k R`, then the result is an algebra homomorphism called
-`MonoidAlgebra.lift`. -/
-def liftNC (f : k →+ R) (g : G → R) : MonoidAlgebra k G →+ R :=
- liftAddHom fun x : G => (AddMonoidHom.mulRight (g x)).comp f
-
-@[simp]
-theorem liftNC_single (f : k →+ R) (g : G → R) (a : G) (b : k) :
- liftNC f g (single a b) = f b * g a :=
- liftAddHom_apply_single _ _ _
-
-end
-
-section Mul
-
-variable [Semiring k] [Mul G]
-
-/-- The multiplication in a monoid algebra. We make it irreducible so that Lean doesn't unfold
-it trying to unify two things that are different. -/
-@[irreducible] def mul' (f g : MonoidAlgebra k G) : MonoidAlgebra k G :=
- f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => single (a₁ * a₂) (b₁ * b₂)
-
-/-- The product of `f g : MonoidAlgebra k G` is the finitely supported function
- whose value at `a` is the sum of `f x * g y` over all pairs `x, y`
- such that `x * y = a`. (Think of the group ring of a group.) -/
-instance instMul : Mul (MonoidAlgebra k G) := ⟨MonoidAlgebra.mul'⟩
-
-theorem mul_def {f g : MonoidAlgebra k G} :
- f * g = f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => single (a₁ * a₂) (b₁ * b₂) := by
- with_unfolding_all rfl
-
-instance nonUnitalNonAssocSemiring : NonUnitalNonAssocSemiring (MonoidAlgebra k G) :=
- { Finsupp.instAddCommMonoid with
- -- Porting note: `refine` & `exact` are required because `simp` behaves differently.
- left_distrib := fun f g h => by
- haveI := Classical.decEq G
- simp only [mul_def]
- refine Eq.trans (congr_arg (sum f) (funext₂ fun a₁ b₁ => sum_add_index ?_ ?_)) ?_ <;>
- simp only [mul_add, mul_zero, single_zero, single_add, forall_true_iff, sum_add]
- right_distrib := fun f g h => by
- haveI := Classical.decEq G
- simp only [mul_def]
- refine Eq.trans (sum_add_index ?_ ?_) ?_ <;>
- simp only [add_mul, zero_mul, single_zero, single_add, forall_true_iff, sum_zero, sum_add]
- zero_mul := fun f => by
- simp only [mul_def]
- exact sum_zero_index
- mul_zero := fun f => by
- simp only [mul_def]
- exact Eq.trans (congr_arg (sum f) (funext₂ fun a₁ b₁ => sum_zero_index)) sum_zero }
-
-variable [Semiring R]
-
-theorem liftNC_mul {g_hom : Type*} [FunLike g_hom G R] [MulHomClass g_hom G R]
- (f : k →+* R) (g : g_hom) (a b : MonoidAlgebra k G)
- (h_comm : ∀ {x y}, y ∈ a.support → Commute (f (b x)) (g y)) :
- liftNC (f : k →+ R) g (a * b) = liftNC (f : k →+ R) g a * liftNC (f : k →+ R) g b := by
- conv_rhs => rw [← sum_single a, ← sum_single b]
- -- Porting note: `(liftNC _ g).map_finsupp_sum` → `map_finsupp_sum`
- simp_rw [mul_def, map_finsupp_sum, liftNC_single, Finsupp.sum_mul, Finsupp.mul_sum]
- refine Finset.sum_congr rfl fun y hy => Finset.sum_congr rfl fun x _hx => ?_
- simp [mul_assoc, (h_comm hy).left_comm]
-
-end Mul
-
-section Semigroup
-
-variable [Semiring k] [Semigroup G] [Semiring R]
-
-instance nonUnitalSemiring : NonUnitalSemiring (MonoidAlgebra k G) :=
- { MonoidAlgebra.nonUnitalNonAssocSemiring with
- mul_assoc := fun f g h => by
- -- Porting note: `reducible` cannot be `local` so proof gets long.
- simp only [mul_def]
- rw [sum_sum_index]; congr; ext a₁ b₁
- rw [sum_sum_index, sum_sum_index]; congr; ext a₂ b₂
- rw [sum_sum_index, sum_single_index]; congr; ext a₃ b₃
- rw [sum_single_index, mul_assoc, mul_assoc]
- all_goals simp only [single_zero, single_add, forall_true_iff, add_mul,
- mul_add, zero_mul, mul_zero, sum_zero, sum_add] }
-
-end Semigroup
-
-section One
-
-variable [NonAssocSemiring R] [Semiring k] [One G]
-
-/-- The unit of the multiplication is `single 1 1`, i.e. the function
- that is `1` at `1` and zero elsewhere. -/
-instance one : One (MonoidAlgebra k G) :=
- ⟨single 1 1⟩
-
-theorem one_def : (1 : MonoidAlgebra k G) = single 1 1 :=
- rfl
-
-@[simp]
-theorem liftNC_one {g_hom : Type*} [FunLike g_hom G R] [OneHomClass g_hom G R]
- (f : k →+* R) (g : g_hom) :
- liftNC (f : k →+ R) g 1 = 1 := by simp [one_def]
-
-end One
-
-section MulOneClass
-
-variable [Semiring k] [MulOneClass G]
-
-instance nonAssocSemiring : NonAssocSemiring (MonoidAlgebra k G) :=
- { MonoidAlgebra.nonUnitalNonAssocSemiring with
- natCast := fun n => single 1 n
- natCast_zero := by simp
- natCast_succ := fun _ => by simp; rfl
- one_mul := fun f => by
- simp only [mul_def, one_def, sum_single_index, zero_mul, single_zero, sum_zero, zero_add,
- one_mul, sum_single]
- mul_one := fun f => by
- simp only [mul_def, one_def, sum_single_index, mul_zero, single_zero, sum_zero, add_zero,
- mul_one, sum_single] }
-
-theorem natCast_def (n : ℕ) : (n : MonoidAlgebra k G) = single (1 : G) (n : k) :=
- rfl
-
-@[deprecated (since := "2024-04-17")]
-alias nat_cast_def := natCast_def
-
-end MulOneClass
-
-/-! #### Semiring structure -/
-
-
-section Semiring
-
-variable [Semiring k] [Monoid G]
-
-instance semiring : Semiring (MonoidAlgebra k G) :=
- { MonoidAlgebra.nonUnitalSemiring,
- MonoidAlgebra.nonAssocSemiring with }
-
-variable [Semiring R]
-
-/-- `liftNC` as a `RingHom`, for when `f x` and `g y` commute -/
-def liftNCRingHom (f : k →+* R) (g : G →* R) (h_comm : ∀ x y, Commute (f x) (g y)) :
- MonoidAlgebra k G →+* R :=
- { liftNC (f : k →+ R) g with
- map_one' := liftNC_one _ _
- map_mul' := fun _a _b => liftNC_mul _ _ _ _ fun {_ _} _ => h_comm _ _ }
-
-end Semiring
-
-instance nonUnitalCommSemiring [CommSemiring k] [CommSemigroup G] :
- NonUnitalCommSemiring (MonoidAlgebra k G) :=
- { MonoidAlgebra.nonUnitalSemiring with
- mul_comm := fun f g => by
- simp only [mul_def, Finsupp.sum, mul_comm]
- rw [Finset.sum_comm]
- simp only [mul_comm] }
-
-instance nontrivial [Semiring k] [Nontrivial k] [Nonempty G] : Nontrivial (MonoidAlgebra k G) :=
- Finsupp.instNontrivial
-
-/-! #### Derived instances -/
-
-
-section DerivedInstances
-
-instance commSemiring [CommSemiring k] [CommMonoid G] : CommSemiring (MonoidAlgebra k G) :=
- { MonoidAlgebra.nonUnitalCommSemiring, MonoidAlgebra.semiring with }
-
-instance unique [Semiring k] [Subsingleton k] : Unique (MonoidAlgebra k G) :=
- Finsupp.uniqueOfRight
-
-instance addCommGroup [Ring k] : AddCommGroup (MonoidAlgebra k G) :=
- Finsupp.instAddCommGroup
-
-instance nonUnitalNonAssocRing [Ring k] [Mul G] : NonUnitalNonAssocRing (MonoidAlgebra k G) :=
- { MonoidAlgebra.addCommGroup, MonoidAlgebra.nonUnitalNonAssocSemiring with }
-
-instance nonUnitalRing [Ring k] [Semigroup G] : NonUnitalRing (MonoidAlgebra k G) :=
- { MonoidAlgebra.addCommGroup, MonoidAlgebra.nonUnitalSemiring with }
-
-instance nonAssocRing [Ring k] [MulOneClass G] : NonAssocRing (MonoidAlgebra k G) :=
- { MonoidAlgebra.addCommGroup,
- MonoidAlgebra.nonAssocSemiring with
- intCast := fun z => single 1 (z : k)
- -- Porting note: Both were `simpa`.
- intCast_ofNat := fun n => by simp; rfl
- intCast_negSucc := fun n => by simp; rfl }
-
-theorem intCast_def [Ring k] [MulOneClass G] (z : ℤ) :
- (z : MonoidAlgebra k G) = single (1 : G) (z : k) :=
- rfl
-
-@[deprecated (since := "2024-04-17")]
-alias int_cast_def := intCast_def
-
-instance ring [Ring k] [Monoid G] : Ring (MonoidAlgebra k G) :=
- { MonoidAlgebra.nonAssocRing, MonoidAlgebra.semiring with }
-
-instance nonUnitalCommRing [CommRing k] [CommSemigroup G] :
- NonUnitalCommRing (MonoidAlgebra k G) :=
- { MonoidAlgebra.nonUnitalCommSemiring, MonoidAlgebra.nonUnitalRing with }
-
-instance commRing [CommRing k] [CommMonoid G] : CommRing (MonoidAlgebra k G) :=
- { MonoidAlgebra.nonUnitalCommRing, MonoidAlgebra.ring with }
-
-variable {S : Type*}
-
-instance smulZeroClass [Semiring k] [SMulZeroClass R k] : SMulZeroClass R (MonoidAlgebra k G) :=
- Finsupp.smulZeroClass
-
-instance distribSMul [Semiring k] [DistribSMul R k] : DistribSMul R (MonoidAlgebra k G) :=
- Finsupp.distribSMul _ _
-
-instance distribMulAction [Monoid R] [Semiring k] [DistribMulAction R k] :
- DistribMulAction R (MonoidAlgebra k G) :=
- Finsupp.distribMulAction G k
-
-instance module [Semiring R] [Semiring k] [Module R k] : Module R (MonoidAlgebra k G) :=
- Finsupp.module G k
-
-instance faithfulSMul [Semiring k] [SMulZeroClass R k] [FaithfulSMul R k] [Nonempty G] :
- FaithfulSMul R (MonoidAlgebra k G) :=
- Finsupp.faithfulSMul
-
-instance isScalarTower [Semiring k] [SMulZeroClass R k] [SMulZeroClass S k] [SMul R S]
- [IsScalarTower R S k] : IsScalarTower R S (MonoidAlgebra k G) :=
- Finsupp.isScalarTower G k
-
-instance smulCommClass [Semiring k] [SMulZeroClass R k] [SMulZeroClass S k] [SMulCommClass R S k] :
- SMulCommClass R S (MonoidAlgebra k G) :=
- Finsupp.smulCommClass G k
-
-instance isCentralScalar [Semiring k] [SMulZeroClass R k] [SMulZeroClass Rᵐᵒᵖ k]
- [IsCentralScalar R k] : IsCentralScalar R (MonoidAlgebra k G) :=
- Finsupp.isCentralScalar G k
-
-/-- This is not an instance as it conflicts with `MonoidAlgebra.distribMulAction` when `G = kˣ`.
--/
-def comapDistribMulActionSelf [Group G] [Semiring k] : DistribMulAction G (MonoidAlgebra k G) :=
- Finsupp.comapDistribMulAction
-
-end DerivedInstances
-
-section MiscTheorems
-
-variable [Semiring k]
-
--- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
-
-theorem mul_apply [DecidableEq G] [Mul G] (f g : MonoidAlgebra k G) (x : G) :
- (f * g) x = f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => if a₁ * a₂ = x then b₁ * b₂ else 0 := by
- -- Porting note: `reducible` cannot be `local` so proof gets long.
- rw [mul_def, Finsupp.sum_apply]; congr; ext
- rw [Finsupp.sum_apply]; congr; ext
- apply single_apply
-
-theorem mul_apply_antidiagonal [Mul G] (f g : MonoidAlgebra k G) (x : G) (s : Finset (G × G))
- (hs : ∀ {p : G × G}, p ∈ s ↔ p.1 * p.2 = x) : (f * g) x = ∑ p ∈ s, f p.1 * g p.2 := by
- classical exact
- let F : G × G → k := fun p => if p.1 * p.2 = x then f p.1 * g p.2 else 0
- 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 := Finset.sum_product.symm
- _ = ∑ p ∈ (f.support ×ˢ g.support).filter fun p : G × G => 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, 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 ⊢
- by_cases h1 : f p.1 = 0
- · rw [h1, zero_mul]
- · rw [hp hps h1, mul_zero]
-
-@[simp]
-theorem single_mul_single [Mul G] {a₁ a₂ : G} {b₁ b₂ : k} :
- single a₁ b₁ * single a₂ b₂ = single (a₁ * a₂) (b₁ * b₂) := by
- rw [mul_def]
- exact (sum_single_index (by simp only [zero_mul, single_zero, sum_zero])).trans
- (sum_single_index (by rw [mul_zero, single_zero]))
-
-theorem single_commute_single [Mul G] {a₁ a₂ : G} {b₁ b₂ : k}
- (ha : Commute a₁ a₂) (hb : Commute b₁ b₂) :
- Commute (single a₁ b₁) (single a₂ b₂) :=
- single_mul_single.trans <| congr_arg₂ single ha hb |>.trans single_mul_single.symm
-
-theorem single_commute [Mul G] {a : G} {b : k} (ha : ∀ a', Commute a a') (hb : ∀ b', Commute b b') :
- ∀ f : MonoidAlgebra k G, Commute (single a b) f :=
- suffices AddMonoidHom.mulLeft (single a b) = AddMonoidHom.mulRight (single a b) from
- DFunLike.congr_fun this
- addHom_ext' fun a' => AddMonoidHom.ext fun b' => single_commute_single (ha a') (hb b')
-
-@[simp]
-theorem single_pow [Monoid G] {a : G} {b : k} : ∀ n : ℕ, single a b ^ n = single (a ^ n) (b ^ n)
- | 0 => by
- simp only [pow_zero]
- rfl
- | n + 1 => by simp only [pow_succ, single_pow n, single_mul_single]
-
-section
-
-/-- Like `Finsupp.mapDomain_zero`, but for the `1` we define in this file -/
-@[simp]
-theorem mapDomain_one {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [One α] [One α₂]
- {F : Type*} [FunLike F α α₂] [OneHomClass F α α₂] (f : F) :
- (mapDomain f (1 : MonoidAlgebra β α) : MonoidAlgebra β α₂) = (1 : MonoidAlgebra β α₂) := by
- simp_rw [one_def, mapDomain_single, map_one]
-
-/-- Like `Finsupp.mapDomain_add`, but for the convolutive multiplication we define in this file -/
-theorem mapDomain_mul {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Mul α] [Mul α₂]
- {F : Type*} [FunLike F α α₂] [MulHomClass F α α₂] (f : F) (x y : MonoidAlgebra β α) :
- mapDomain f (x * y) = mapDomain f x * mapDomain f y := by
- simp_rw [mul_def, mapDomain_sum, mapDomain_single, map_mul]
- rw [Finsupp.sum_mapDomain_index]
- · congr
- ext a b
- rw [Finsupp.sum_mapDomain_index]
- · simp
- · simp [mul_add]
- · simp
- · simp [add_mul]
-
-variable (k G)
-
-/-- The embedding of a magma into its magma algebra. -/
-@[simps]
-def ofMagma [Mul G] : G →ₙ* MonoidAlgebra k G where
- toFun a := single a 1
- map_mul' a b := by simp only [mul_def, mul_one, sum_single_index, single_eq_zero, mul_zero]
-
-/-- The embedding of a unital magma into its magma algebra. -/
-@[simps]
-def of [MulOneClass G] : G →* MonoidAlgebra k G :=
- { ofMagma k G with
- toFun := fun a => single a 1
- map_one' := rfl }
-
-end
-
-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]
-
-theorem of_injective [MulOneClass G] [Nontrivial k] :
- Function.Injective (of k G) := fun a b h => by
- simpa using (single_eq_single_iff _ _ _ _).mp h
-
-theorem of_commute [MulOneClass G] {a : G} (h : ∀ a', Commute a a') (f : MonoidAlgebra k G) :
- Commute (of k G a) f :=
- single_commute h Commute.one_left f
-
-/-- `Finsupp.single` as a `MonoidHom` from the product type into the monoid algebra.
-
-Note the order of the elements of the product are reversed compared to the arguments of
-`Finsupp.single`.
--/
-@[simps]
-def singleHom [MulOneClass G] : k × G →* MonoidAlgebra k G where
- toFun a := single a.2 a.1
- map_one' := rfl
- map_mul' _a _b := single_mul_single.symm
-
-theorem mul_single_apply_aux [Mul G] (f : MonoidAlgebra k G) {r : k} {x y z : G}
- (H : ∀ a, a * x = z ↔ a = y) : (f * single x r) z = f y * r := by
- classical exact
- have A :
- ∀ a₁ b₁,
- ((single x r).sum fun a₂ b₂ => ite (a₁ * a₂ = z) (b₁ * b₂) 0) =
- ite (a₁ * x = z) (b₁ * r) 0 :=
- fun a₁ b₁ => sum_single_index <| by simp
- calc
- (HMul.hMul (β := MonoidAlgebra k G) f (single x r)) z =
- sum f fun a b => if a = y then b * r else 0 := by simp only [mul_apply, A, H]
- _ = if y ∈ f.support then f y * r else 0 := f.support.sum_ite_eq' _ _
- _ = f y * r := by split_ifs with h <;> simp at h <;> simp [h]
-
-theorem mul_single_one_apply [MulOneClass G] (f : MonoidAlgebra k G) (r : k) (x : G) :
- (HMul.hMul (β := MonoidAlgebra k G) f (single 1 r)) x = f x * r :=
- f.mul_single_apply_aux fun a => by rw [mul_one]
-
-theorem mul_single_apply_of_not_exists_mul [Mul G] (r : k) {g g' : G} (x : MonoidAlgebra k G)
- (h : ¬∃ d, g' = d * g) : (x * single g r) g' = 0 := by
- classical
- rw [mul_apply, Finsupp.sum_comm, Finsupp.sum_single_index]
- swap
- · simp_rw [Finsupp.sum, mul_zero, ite_self, Finset.sum_const_zero]
- · apply Finset.sum_eq_zero
- simp_rw [ite_eq_right_iff]
- rintro g'' _hg'' rfl
- exfalso
- exact h ⟨_, rfl⟩
-
-theorem single_mul_apply_aux [Mul G] (f : MonoidAlgebra k G) {r : k} {x y z : G}
- (H : ∀ a, x * a = y ↔ a = z) : (single x r * f) y = r * f z := by
- classical exact
- have : (f.sum fun a b => ite (x * a = y) (0 * b) 0) = 0 := by simp
- calc
- (HMul.hMul (α := MonoidAlgebra k G) (single x r) f) y =
- sum f fun a b => ite (x * a = y) (r * b) 0 :=
- (mul_apply _ _ _).trans <| sum_single_index this
- _ = f.sum fun a b => ite (a = z) (r * b) 0 := by simp only [H]
- _ = if z ∈ f.support then r * f z else 0 := f.support.sum_ite_eq' _ _
- _ = _ := by split_ifs with h <;> simp at h <;> simp [h]
-
-theorem single_one_mul_apply [MulOneClass G] (f : MonoidAlgebra k G) (r : k) (x : G) :
- (single (1 : G) r * f) x = r * f x :=
- f.single_mul_apply_aux fun a => by rw [one_mul]
-
-theorem single_mul_apply_of_not_exists_mul [Mul G] (r : k) {g g' : G} (x : MonoidAlgebra k G)
- (h : ¬∃ d, g' = g * d) : (single g r * x) g' = 0 := by
- classical
- rw [mul_apply, Finsupp.sum_single_index]
- swap
- · simp_rw [Finsupp.sum, zero_mul, ite_self, Finset.sum_const_zero]
- · apply Finset.sum_eq_zero
- simp_rw [ite_eq_right_iff]
- rintro g'' _hg'' rfl
- exfalso
- exact h ⟨_, rfl⟩
-
-theorem liftNC_smul [MulOneClass G] {R : Type*} [Semiring R] (f : k →+* R) (g : G →* R) (c : k)
- (φ : MonoidAlgebra k G) : liftNC (f : k →+ R) g (c • φ) = f c * liftNC (f : k →+ R) g φ := by
- 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 => ?_
- -- 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]
- -- 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]
-
-end MiscTheorems
-
/-! #### Non-unital, non-associative algebra structure -/
@@ -581,42 +39,6 @@ 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 => ?_
- -- 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]⟩
-
-/-- 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 => ?_
- -- 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]⟩
-
-instance smulCommClass_symm_self [SMulCommClass k R k] :
- SMulCommClass (MonoidAlgebra k G) R (MonoidAlgebra k G) :=
- ⟨fun t a b => by
- haveI := SMulCommClass.symm k R k
- rw [← smul_comm]⟩
-
variable {A : Type u₃} [NonUnitalNonAssocSemiring A]
/-- A non_unital `k`-algebra homomorphism from `MonoidAlgebra k G` is uniquely defined by its
@@ -668,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]
@@ -678,57 +99,8 @@ end NonUnitalNonAssocAlgebra
/-! #### Algebra structure -/
-
section Algebra
--- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
-
-theorem single_one_comm [CommSemiring k] [MulOneClass G] (r : k) (f : MonoidAlgebra k G) :
- single (1 : G) r * f = f * single (1 : G) r :=
- single_commute Commute.one_left (Commute.all _) f
-
-/-- `Finsupp.single 1` as a `RingHom` -/
-@[simps]
-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] }
-
-/-- If `f : G → H` is a multiplicative homomorphism between two monoids, then
-`Finsupp.mapDomain f` is a ring homomorphism between their monoid algebras. -/
-@[simps]
-def mapDomainRingHom (k : Type*) {H F : Type*} [Semiring k] [Monoid G] [Monoid H]
- [FunLike F G H] [MonoidHomClass F G H] (f : F) : MonoidAlgebra k G →+* MonoidAlgebra k H :=
- { (Finsupp.mapDomain.addMonoidHom f : MonoidAlgebra k G →+ MonoidAlgebra k H) with
- map_one' := mapDomain_one f
- map_mul' := fun x y => mapDomain_mul f x y }
-
-/-- If two ring homomorphisms from `MonoidAlgebra k G` are equal on all `single a 1`
-and `single 1 b`, then they are equal. -/
-theorem ringHom_ext {R} [Semiring k] [MulOneClass G] [Semiring R] {f g : MonoidAlgebra k G →+* R}
- (h₁ : ∀ b, f (single 1 b) = g (single 1 b)) (h_of : ∀ a, f (single a 1) = g (single a 1)) :
- f = g :=
- RingHom.coe_addMonoidHom_injective <|
- addHom_ext fun a b => by
- rw [← single, ← one_mul a, ← mul_one b, ← single_mul_single]
- -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
- erw [AddMonoidHom.coe_coe f, AddMonoidHom.coe_coe g]; rw [f.map_mul, g.map_mul, h₁, h_of]
-
-/-- If two ring homomorphisms from `MonoidAlgebra k G` are equal on all `single a 1`
-and `single 1 b`, then they are equal.
-
-See note [partially-applied ext lemmas]. -/
-@[ext high]
-theorem ringHom_ext' {R} [Semiring k] [MulOneClass G] [Semiring R] {f g : MonoidAlgebra k G →+* R}
- (h₁ : f.comp singleOneRingHom = g.comp singleOneRingHom)
- (h_of :
- (f : MonoidAlgebra k G →* R).comp (of k G) = (g : MonoidAlgebra k G →* R).comp (of k G)) :
- f = g :=
- ringHom_ext (RingHom.congr_fun h₁) (DFunLike.congr_fun h_of)
-
/-- The instance `Algebra k (MonoidAlgebra A G)` whenever we have `Algebra k A`.
In particular this provides the instance `Algebra k (MonoidAlgebra k G)`.
@@ -736,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]
@@ -752,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 }
@@ -769,15 +139,6 @@ theorem single_algebraMap_eq_algebraMap_mul_of {A : Type*} [CommSemiring k] [Sem
[Algebra k A] [Monoid G] (a : G) (b : k) :
single a (algebraMap k A b) = algebraMap k (MonoidAlgebra A G) b * of A G a := by simp
-theorem induction_on [Semiring k] [Monoid G] {p : MonoidAlgebra k G → Prop} (f : MonoidAlgebra k G)
- (hM : ∀ g, p (of k G g)) (hadd : ∀ f g : MonoidAlgebra k G, p f → p g → p (f + g))
- (hsmul : ∀ (r : k) (f), p f → p (r • f)) : p f := by
- 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]
-
end Algebra
section lift
@@ -975,678 +336,17 @@ end
end
-section
-
-universe ui
-
-variable {ι : Type ui}
-
--- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
-
-theorem prod_single [CommSemiring k] [CommMonoid G] {s : Finset ι} {a : ι → G} {b : ι → k} :
- (∏ i ∈ s, single (a i) (b i)) = single (∏ i ∈ s, a i) (∏ i ∈ s, b i) :=
- Finset.cons_induction_on s rfl fun a s has ih => by
- rw [prod_cons has, ih, single_mul_single, prod_cons has, prod_cons has]
-
-end
-
-section
-
--- We now prove some additional statements that hold for group algebras.
-variable [Semiring k] [Group G]
-
--- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
-
-@[simp]
-theorem mul_single_apply (f : MonoidAlgebra k G) (r : k) (x y : G) :
- (f * single x r) y = f (y * x⁻¹) * r :=
- f.mul_single_apply_aux fun _a => eq_mul_inv_iff_mul_eq.symm
-
-@[simp]
-theorem single_mul_apply (r : k) (x : G) (f : MonoidAlgebra k G) (y : G) :
- (single x r * f) y = r * f (x⁻¹ * y) :=
- f.single_mul_apply_aux fun _z => eq_inv_mul_iff_mul_eq.symm
-
-theorem mul_apply_left (f g : MonoidAlgebra k G) (x : G) :
- (f * g) x = f.sum fun a b => b * g (a⁻¹ * x) :=
- calc
- (f * g) x = sum f fun a b => (single a b * g) x := by
- rw [← Finsupp.sum_apply, ← Finsupp.sum_mul g f, f.sum_single]
- _ = _ := by simp only [single_mul_apply, Finsupp.sum]
-
--- If we'd assumed `CommSemiring`, we could deduce this from `mul_apply_left`.
-theorem mul_apply_right (f g : MonoidAlgebra k G) (x : G) :
- (f * g) x = g.sum fun a b => f (x * a⁻¹) * b :=
- calc
- (f * g) x = sum g fun a b => (f * single a b) x := by
- rw [← Finsupp.sum_apply, ← Finsupp.mul_sum f g, g.sum_single]
- _ = _ := by simp only [mul_single_apply, Finsupp.sum]
-
-end
-
-section Opposite
-
-open Finsupp MulOpposite
-
-variable [Semiring k]
-
-/-- The opposite of a `MonoidAlgebra R I` equivalent as a ring to
-the `MonoidAlgebra Rᵐᵒᵖ Iᵐᵒᵖ` over the opposite ring, taking elements to their opposite. -/
-@[simps! (config := { simpRhs := true }) apply symm_apply]
-protected noncomputable def opRingEquiv [Monoid G] :
- (MonoidAlgebra k G)ᵐᵒᵖ ≃+* MonoidAlgebra kᵐᵒᵖ Gᵐᵒᵖ :=
- { opAddEquiv.symm.trans <|
- (Finsupp.mapRange.addEquiv (opAddEquiv : k ≃+ kᵐᵒᵖ)).trans <| Finsupp.domCongr opEquiv with
- map_mul' := by
- -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
- 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 := (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₂ => ?_
- -- 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,
- AddMonoidHom.coe_mulLeft, AddMonoidHom.compl₂_apply]
- -- 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]
- simp }
-
--- @[simp] -- Porting note (#10618): simp can prove this
-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
-
-end Opposite
-
-section Submodule
-
-variable [CommSemiring k] [Monoid G]
-variable {V : Type*} [AddCommMonoid V]
-variable [Module k V] [Module (MonoidAlgebra k G) V] [IsScalarTower k (MonoidAlgebra k G) V]
-
-/-- A submodule over `k` which is stable under scalar multiplication by elements of `G` is a
-submodule over `MonoidAlgebra k G` -/
-def submoduleOfSMulMem (W : Submodule k V) (h : ∀ (g : G) (v : V), v ∈ W → of k G g • v ∈ W) :
- Submodule (MonoidAlgebra k G) V where
- carrier := W
- zero_mem' := W.zero_mem'
- add_mem' := W.add_mem'
- smul_mem' := by
- intro f v hv
- rw [← Finsupp.sum_single f, Finsupp.sum, Finset.sum_smul]
- simp_rw [← smul_of, smul_assoc]
- exact Submodule.sum_smul_mem W _ fun g _ => h g v hv
-
-end Submodule
-
end MonoidAlgebra
-/-! ### Additive monoids -/
-
-
-section
-
-variable [Semiring k]
-
-/-- The monoid algebra over a semiring `k` generated by the additive monoid `G`.
-It is the type of finite formal `k`-linear combinations of terms of `G`,
-endowed with the convolution product.
--/
-def AddMonoidAlgebra :=
- G →₀ k
-
-@[inherit_doc]
-scoped[AddMonoidAlgebra] notation:9000 R:max "[" A "]" => AddMonoidAlgebra R A
-
-namespace AddMonoidAlgebra
-
--- Porting note: The compiler couldn't derive this.
-instance inhabited : Inhabited k[G] :=
- inferInstanceAs (Inhabited (G →₀ k))
-
--- Porting note: The compiler couldn't derive this.
-instance addCommMonoid : AddCommMonoid k[G] :=
- inferInstanceAs (AddCommMonoid (G →₀ k))
-
-instance instIsCancelAdd [IsCancelAdd k] : IsCancelAdd (AddMonoidAlgebra k G) :=
- inferInstanceAs (IsCancelAdd (G →₀ k))
-
-instance coeFun : CoeFun k[G] fun _ => G → k :=
- Finsupp.instCoeFun
-
-end AddMonoidAlgebra
-
-end
-
-namespace AddMonoidAlgebra
-
-variable {k G}
-
-section
-
-variable [Semiring k] [NonUnitalNonAssocSemiring R]
-
--- Porting note: `reducible` cannot be `local`, so we replace some definitions and theorems with
--- new ones which have new types.
-
-abbrev single (a : G) (b : k) : k[G] := Finsupp.single a b
-
-theorem single_zero (a : G) : (single a 0 : k[G]) = 0 := Finsupp.single_zero a
-
-theorem single_add (a : G) (b₁ b₂ : k) : single a (b₁ + b₂) = single a b₁ + single a b₂ :=
- Finsupp.single_add a b₁ b₂
-
-@[simp]
-theorem sum_single_index {N} [AddCommMonoid N] {a : G} {b : k} {h : G → k → N}
- (h_zero : h a 0 = 0) :
- (single a b).sum h = h a b := Finsupp.sum_single_index h_zero
-
-@[simp]
-theorem sum_single (f : k[G]) : f.sum single = f :=
- Finsupp.sum_single f
-
-theorem single_apply {a a' : G} {b : k} [Decidable (a = a')] :
- single a b a' = if a = a' then b else 0 :=
- Finsupp.single_apply
-
-@[simp]
-theorem single_eq_zero {a : G} {b : k} : single a b = 0 ↔ b = 0 := Finsupp.single_eq_zero
-
-abbrev mapDomain {G' : Type*} (f : G → G') (v : k[G]) : k[G'] :=
- Finsupp.mapDomain f v
-
-theorem mapDomain_sum {k' G' : Type*} [Semiring k'] {f : G → G'} {s : AddMonoidAlgebra k' G}
- {v : G → k' → k[G]} :
- mapDomain f (s.sum v) = s.sum fun a b => mapDomain f (v a b) :=
- Finsupp.mapDomain_sum
-
-theorem mapDomain_single {G' : Type*} {f : G → G'} {a : G} {b : k} :
- mapDomain f (single a b) = single (f a) b :=
- Finsupp.mapDomain_single
-
-/-- A non-commutative version of `AddMonoidAlgebra.lift`: given an additive homomorphism
-`f : k →+ R` and a map `g : Multiplicative G → R`, returns the additive
-homomorphism from `k[G]` such that `liftNC f g (single a b) = f b * g a`. If `f`
-is a ring homomorphism and the range of either `f` or `g` is in center of `R`, then the result is a
-ring homomorphism. If `R` is a `k`-algebra and `f = algebraMap k R`, then the result is an algebra
-homomorphism called `AddMonoidAlgebra.lift`. -/
-def liftNC (f : k →+ R) (g : Multiplicative G → R) : k[G] →+ R :=
- liftAddHom fun x : G => (AddMonoidHom.mulRight (g <| Multiplicative.ofAdd x)).comp f
-
-@[simp]
-theorem liftNC_single (f : k →+ R) (g : Multiplicative G → R) (a : G) (b : k) :
- liftNC f g (single a b) = f b * g (Multiplicative.ofAdd a) :=
- liftAddHom_apply_single _ _ _
-
-end
-
-section Mul
-
-variable [Semiring k] [Add G]
-
-/-- The product of `f g : k[G]` is the finitely supported function
- whose value at `a` is the sum of `f x * g y` over all pairs `x, y`
- such that `x + y = a`. (Think of the product of multivariate
- polynomials where `α` is the additive monoid of monomial exponents.) -/
-instance hasMul : Mul k[G] :=
- ⟨fun f g => MonoidAlgebra.mul' (G := Multiplicative G) f g⟩
-
-theorem mul_def {f g : k[G]} :
- f * g = f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => single (a₁ + a₂) (b₁ * b₂) :=
- MonoidAlgebra.mul_def (G := Multiplicative G)
-
-instance nonUnitalNonAssocSemiring : NonUnitalNonAssocSemiring k[G] :=
- { Finsupp.instAddCommMonoid with
- -- Porting note: `refine` & `exact` are required because `simp` behaves differently.
- left_distrib := fun f g h => by
- haveI := Classical.decEq G
- simp only [mul_def]
- refine Eq.trans (congr_arg (sum f) (funext₂ fun a₁ b₁ => sum_add_index ?_ ?_)) ?_ <;>
- simp only [mul_add, mul_zero, single_zero, single_add, forall_true_iff, sum_add]
- right_distrib := fun f g h => by
- haveI := Classical.decEq G
- simp only [mul_def]
- refine Eq.trans (sum_add_index ?_ ?_) ?_ <;>
- simp only [add_mul, zero_mul, single_zero, single_add, forall_true_iff, sum_zero, sum_add]
- zero_mul := fun f => by
- simp only [mul_def]
- exact sum_zero_index
- mul_zero := fun f => by
- 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 _ => ?_`
- nsmul_zero := by
- intros
- refine Finsupp.ext fun _ => ?_
- simp [-nsmul_eq_mul, add_smul]
- nsmul_succ := by
- intros
- refine Finsupp.ext fun _ => ?_
- simp [-nsmul_eq_mul, add_smul] }
-
-variable [Semiring R]
-
-theorem liftNC_mul {g_hom : Type*}
- [FunLike g_hom (Multiplicative G) R] [MulHomClass g_hom (Multiplicative G) R]
- (f : k →+* R) (g : g_hom) (a b : k[G])
- (h_comm : ∀ {x y}, y ∈ a.support → Commute (f (b x)) (g <| Multiplicative.ofAdd y)) :
- liftNC (f : k →+ R) g (a * b) = liftNC (f : k →+ R) g a * liftNC (f : k →+ R) g b :=
- (MonoidAlgebra.liftNC_mul f g _ _ @h_comm : _)
-
-end Mul
-
-section One
-
-variable [Semiring k] [Zero G] [NonAssocSemiring R]
-
-/-- The unit of the multiplication is `single 0 1`, i.e. the function
- that is `1` at `0` and zero elsewhere. -/
-instance one : One k[G] :=
- ⟨single 0 1⟩
-
-theorem one_def : (1 : k[G]) = single 0 1 :=
- rfl
-
-@[simp]
-theorem liftNC_one {g_hom : Type*}
- [FunLike g_hom (Multiplicative G) R] [OneHomClass g_hom (Multiplicative G) R]
- (f : k →+* R) (g : g_hom) : liftNC (f : k →+ R) g 1 = 1 :=
- (MonoidAlgebra.liftNC_one f g : _)
-
-end One
-
-section Semigroup
-
-variable [Semiring k] [AddSemigroup G]
-
-instance nonUnitalSemiring : NonUnitalSemiring k[G] :=
- { AddMonoidAlgebra.nonUnitalNonAssocSemiring with
- mul_assoc := fun f g h => by
- -- Porting note: `reducible` cannot be `local` so proof gets long.
- simp only [mul_def]
- rw [sum_sum_index]; congr; ext a₁ b₁
- rw [sum_sum_index, sum_sum_index]; congr; ext a₂ b₂
- rw [sum_sum_index, sum_single_index]; congr; ext a₃ b₃
- rw [sum_single_index, mul_assoc, add_assoc]
- all_goals simp only [single_zero, single_add, forall_true_iff, add_mul,
- mul_add, zero_mul, mul_zero, sum_zero, sum_add] }
-
-end Semigroup
-
-section MulOneClass
-
-variable [Semiring k] [AddZeroClass G]
-
-instance nonAssocSemiring : NonAssocSemiring k[G] :=
- { AddMonoidAlgebra.nonUnitalNonAssocSemiring with
- natCast := fun n => single 0 n
- natCast_zero := by simp
- natCast_succ := fun _ => by simp; rfl
- one_mul := fun f => by
- simp only [mul_def, one_def, sum_single_index, zero_mul, single_zero, sum_zero, zero_add,
- one_mul, sum_single]
- mul_one := fun f => by
- simp only [mul_def, one_def, sum_single_index, mul_zero, single_zero, sum_zero, add_zero,
- mul_one, sum_single] }
-
-theorem natCast_def (n : ℕ) : (n : k[G]) = single (0 : G) (n : k) :=
- rfl
-
-@[deprecated (since := "2024-04-17")]
-alias nat_cast_def := natCast_def
-
-end MulOneClass
-
-/-! #### Semiring structure -/
-
-
-section Semiring
-
-instance smulZeroClass [Semiring k] [SMulZeroClass R k] : SMulZeroClass R k[G] :=
- Finsupp.smulZeroClass
-
-variable [Semiring k] [AddMonoid G]
-
-instance semiring : Semiring k[G] :=
- { AddMonoidAlgebra.nonUnitalSemiring,
- AddMonoidAlgebra.nonAssocSemiring with }
-
-variable [Semiring R]
-
-/-- `liftNC` as a `RingHom`, for when `f` and `g` commute -/
-def liftNCRingHom (f : k →+* R) (g : Multiplicative G →* R) (h_comm : ∀ x y, Commute (f x) (g y)) :
- k[G] →+* R :=
- { liftNC (f : k →+ R) g with
- map_one' := liftNC_one _ _
- map_mul' := fun _a _b => liftNC_mul _ _ _ _ fun {_ _} _ => h_comm _ _ }
-
-end Semiring
-
-instance nonUnitalCommSemiring [CommSemiring k] [AddCommSemigroup G] :
- NonUnitalCommSemiring k[G] :=
- { AddMonoidAlgebra.nonUnitalSemiring with
- mul_comm := @mul_comm (MonoidAlgebra k <| Multiplicative G) _ }
-
-instance nontrivial [Semiring k] [Nontrivial k] [Nonempty G] : Nontrivial k[G] :=
- Finsupp.instNontrivial
-
-/-! #### Derived instances -/
-
-
-section DerivedInstances
-
-instance commSemiring [CommSemiring k] [AddCommMonoid G] : CommSemiring k[G] :=
- { AddMonoidAlgebra.nonUnitalCommSemiring, AddMonoidAlgebra.semiring with }
-
-instance unique [Semiring k] [Subsingleton k] : Unique k[G] :=
- Finsupp.uniqueOfRight
-
-instance addCommGroup [Ring k] : AddCommGroup k[G] :=
- Finsupp.instAddCommGroup
-
-instance nonUnitalNonAssocRing [Ring k] [Add G] : NonUnitalNonAssocRing k[G] :=
- { AddMonoidAlgebra.addCommGroup, AddMonoidAlgebra.nonUnitalNonAssocSemiring with }
-
-instance nonUnitalRing [Ring k] [AddSemigroup G] : NonUnitalRing k[G] :=
- { AddMonoidAlgebra.addCommGroup, AddMonoidAlgebra.nonUnitalSemiring with }
-
-instance nonAssocRing [Ring k] [AddZeroClass G] : NonAssocRing k[G] :=
- { AddMonoidAlgebra.addCommGroup,
- AddMonoidAlgebra.nonAssocSemiring with
- intCast := fun z => single 0 (z : k)
- -- Porting note: Both were `simpa`.
- intCast_ofNat := fun n => by simp; rfl
- intCast_negSucc := fun n => by simp; rfl }
-
-theorem intCast_def [Ring k] [AddZeroClass G] (z : ℤ) :
- (z : k[G]) = single (0 : G) (z : k) :=
- rfl
-
-@[deprecated (since := "2024-04-17")]
-alias int_cast_def := intCast_def
-
-instance ring [Ring k] [AddMonoid G] : Ring k[G] :=
- { AddMonoidAlgebra.nonAssocRing, AddMonoidAlgebra.semiring with }
-
-instance nonUnitalCommRing [CommRing k] [AddCommSemigroup G] :
- NonUnitalCommRing k[G] :=
- { AddMonoidAlgebra.nonUnitalCommSemiring, AddMonoidAlgebra.nonUnitalRing with }
-
-instance commRing [CommRing k] [AddCommMonoid G] : CommRing k[G] :=
- { AddMonoidAlgebra.nonUnitalCommRing, AddMonoidAlgebra.ring with }
-
-variable {S : Type*}
-
-instance distribSMul [Semiring k] [DistribSMul R k] : DistribSMul R k[G] :=
- Finsupp.distribSMul G k
-
-instance distribMulAction [Monoid R] [Semiring k] [DistribMulAction R k] :
- DistribMulAction R k[G] :=
- Finsupp.distribMulAction G k
-
-instance faithfulSMul [Semiring k] [SMulZeroClass R k] [FaithfulSMul R k] [Nonempty G] :
- FaithfulSMul R k[G] :=
- Finsupp.faithfulSMul
-
-instance module [Semiring R] [Semiring k] [Module R k] : Module R k[G] :=
- Finsupp.module G k
-
-instance isScalarTower [Semiring k] [SMulZeroClass R k] [SMulZeroClass S k] [SMul R S]
- [IsScalarTower R S k] : IsScalarTower R S k[G] :=
- Finsupp.isScalarTower G k
-
-instance smulCommClass [Semiring k] [SMulZeroClass R k] [SMulZeroClass S k] [SMulCommClass R S k] :
- SMulCommClass R S k[G] :=
- Finsupp.smulCommClass G k
-
-instance isCentralScalar [Semiring k] [SMulZeroClass R k] [SMulZeroClass Rᵐᵒᵖ k]
- [IsCentralScalar R k] : IsCentralScalar R k[G] :=
- Finsupp.isCentralScalar G k
-
-/-! It is hard to state the equivalent of `DistribMulAction G k[G]`
-because we've never discussed actions of additive groups. -/
-
-
-end DerivedInstances
-
-section MiscTheorems
-
-variable [Semiring k]
-
-theorem mul_apply [DecidableEq G] [Add G] (f g : k[G]) (x : G) :
- (f * g) x = f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => if a₁ + a₂ = x then b₁ * b₂ else 0 :=
- @MonoidAlgebra.mul_apply k (Multiplicative G) _ _ _ _ _ _
-
-theorem mul_apply_antidiagonal [Add G] (f g : k[G]) (x : G) (s : Finset (G × G))
- (hs : ∀ {p : G × G}, p ∈ s ↔ p.1 + p.2 = x) : (f * g) x = ∑ p ∈ s, f p.1 * g p.2 :=
- @MonoidAlgebra.mul_apply_antidiagonal k (Multiplicative G) _ _ _ _ _ s @hs
-
-theorem single_mul_single [Add G] {a₁ a₂ : G} {b₁ b₂ : k} :
- single a₁ b₁ * single a₂ b₂ = single (a₁ + a₂) (b₁ * b₂) :=
- @MonoidAlgebra.single_mul_single k (Multiplicative G) _ _ _ _ _ _
-
-theorem single_commute_single [Add G] {a₁ a₂ : G} {b₁ b₂ : k}
- (ha : AddCommute a₁ a₂) (hb : Commute b₁ b₂) :
- Commute (single a₁ b₁) (single a₂ b₂) :=
- @MonoidAlgebra.single_commute_single k (Multiplicative G) _ _ _ _ _ _ ha hb
-
--- This should be a `@[simp]` lemma, but the simp_nf linter times out if we add this.
--- Probably the correct fix is to make a `[Add]MonoidAlgebra.single` with the correct type,
--- instead of relying on `Finsupp.single`.
-theorem single_pow [AddMonoid G] {a : G} {b : k} : ∀ n : ℕ, single a b ^ n = single (n • a) (b ^ n)
- | 0 => by
- simp only [pow_zero, zero_nsmul]
- rfl
- | n + 1 => by
- rw [pow_succ, pow_succ, single_pow n, single_mul_single, add_nsmul, one_nsmul]
-
-/-- Like `Finsupp.mapDomain_zero`, but for the `1` we define in this file -/
-@[simp]
-theorem mapDomain_one {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Zero α] [Zero α₂]
- {F : Type*} [FunLike F α α₂] [ZeroHomClass F α α₂] (f : F) :
- (mapDomain f (1 : AddMonoidAlgebra β α) : AddMonoidAlgebra β α₂) =
- (1 : AddMonoidAlgebra β α₂) := by
- simp_rw [one_def, mapDomain_single, map_zero]
-
-/-- Like `Finsupp.mapDomain_add`, but for the convolutive multiplication we define in this file -/
-theorem mapDomain_mul {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Add α] [Add α₂]
- {F : Type*} [FunLike F α α₂] [AddHomClass F α α₂] (f : F) (x y : AddMonoidAlgebra β α) :
- mapDomain f (x * y) = mapDomain f x * mapDomain f y := by
- simp_rw [mul_def, mapDomain_sum, mapDomain_single, map_add]
- rw [Finsupp.sum_mapDomain_index]
- · congr
- ext a b
- rw [Finsupp.sum_mapDomain_index]
- · simp
- · simp [mul_add]
- · simp
- · simp [add_mul]
-
-section
-
-variable (k G)
-
-/-- The embedding of an additive magma into its additive magma algebra. -/
-@[simps]
-def ofMagma [Add G] : Multiplicative G →ₙ* k[G] where
- toFun a := single a 1
- map_mul' a b := by simp only [mul_def, mul_one, sum_single_index, single_eq_zero, mul_zero]; rfl
-
-/-- Embedding of a magma with zero into its magma algebra. -/
-def of [AddZeroClass G] : Multiplicative G →* k[G] :=
- { ofMagma k G with
- toFun := fun a => single a 1
- map_one' := rfl }
-
-/-- Embedding of a magma with zero `G`, into its magma algebra, having `G` as source. -/
-def of' : G → k[G] := fun a => single a 1
-
-end
-
-@[simp]
-theorem of_apply [AddZeroClass G] (a : Multiplicative G) :
- of k G a = single (Multiplicative.toAdd a) 1 :=
- rfl
-
-@[simp]
-theorem of'_apply (a : G) : of' k G a = single a 1 :=
- rfl
-
-theorem of'_eq_of [AddZeroClass G] (a : G) : of' k G a = of k G (.ofAdd a) := rfl
-
-theorem of_injective [Nontrivial k] [AddZeroClass G] : Function.Injective (of k G) :=
- MonoidAlgebra.of_injective
-
-theorem of'_commute [AddZeroClass G] {a : G} (h : ∀ a', AddCommute a a')
- (f : AddMonoidAlgebra k G) :
- Commute (of' k G a) f :=
- MonoidAlgebra.of_commute (G := Multiplicative G) h f
-
-/-- `Finsupp.single` as a `MonoidHom` from the product type into the additive monoid algebra.
-
-Note the order of the elements of the product are reversed compared to the arguments of
-`Finsupp.single`.
--/
-@[simps]
-def singleHom [AddZeroClass G] : k × Multiplicative G →* k[G] where
- toFun a := single (Multiplicative.toAdd a.2) a.1
- map_one' := rfl
- map_mul' _a _b := single_mul_single.symm
-
-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
-
-theorem mul_single_zero_apply [AddZeroClass G] (f : k[G]) (r : k) (x : G) :
- (f * single (0 : G) r) x = f x * r :=
- f.mul_single_apply_aux r _ _ _ fun a => by rw [add_zero]
-
-theorem mul_single_apply_of_not_exists_add [Add G] (r : k) {g g' : G} (x : k[G])
- (h : ¬∃ d, g' = d + g) : (x * single g r) g' = 0 :=
- @MonoidAlgebra.mul_single_apply_of_not_exists_mul k (Multiplicative G) _ _ _ _ _ _ h
-
-theorem single_mul_apply_aux [Add G] (f : k[G]) (r : k) (x y z : G)
- (H : ∀ a, x + a = y ↔ a = z) : (single x r * f) y = r * f z :=
- @MonoidAlgebra.single_mul_apply_aux k (Multiplicative G) _ _ _ _ _ _ _ H
-
-theorem single_zero_mul_apply [AddZeroClass G] (f : k[G]) (r : k) (x : G) :
- (single (0 : G) r * f) x = r * f x :=
- f.single_mul_apply_aux r _ _ _ fun a => by rw [zero_add]
-
-theorem single_mul_apply_of_not_exists_add [Add G] (r : k) {g g' : G} (x : k[G])
- (h : ¬∃ d, g' = g + d) : (single g r * x) g' = 0 :=
- @MonoidAlgebra.single_mul_apply_of_not_exists_mul k (Multiplicative G) _ _ _ _ _ _ h
-
-theorem mul_single_apply [AddGroup G] (f : k[G]) (r : k) (x y : G) :
- (f * single x r) y = f (y - x) * r :=
- (sub_eq_add_neg y x).symm ▸ @MonoidAlgebra.mul_single_apply k (Multiplicative G) _ _ _ _ _ _
-
-theorem single_mul_apply [AddGroup G] (r : k) (x : G) (f : k[G]) (y : G) :
- (single x r * f) y = r * f (-x + y) :=
- @MonoidAlgebra.single_mul_apply k (Multiplicative G) _ _ _ _ _ _
-
-theorem liftNC_smul {R : Type*} [AddZeroClass G] [Semiring R] (f : k →+* R)
- (g : Multiplicative G →* R) (c : k) (φ : MonoidAlgebra k G) :
- liftNC (f : k →+ R) g (c • φ) = f c * liftNC (f : k →+ R) g φ :=
- @MonoidAlgebra.liftNC_smul k (Multiplicative G) _ _ _ _ f g c φ
-
-theorem induction_on [AddMonoid G] {p : k[G] → Prop} (f : k[G])
- (hM : ∀ g, p (of k G (Multiplicative.ofAdd g)))
- (hadd : ∀ f g : k[G], p f → p g → p (f + g))
- (hsmul : ∀ (r : k) (f), p f → p (r • f)) : p f := by
- 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]
-
-/-- 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. -/
-@[simps]
-def mapDomainRingHom (k : Type*) [Semiring k] {H F : Type*} [AddMonoid G] [AddMonoid H]
- [FunLike F G H] [AddMonoidHomClass F G H] (f : F) : k[G] →+* k[H] :=
- { (Finsupp.mapDomain.addMonoidHom f : MonoidAlgebra k G →+ MonoidAlgebra k H) with
- map_one' := mapDomain_one f
- map_mul' := fun x y => mapDomain_mul f x y }
-
-end MiscTheorems
-
-end AddMonoidAlgebra
-
-/-!
-#### Conversions between `AddMonoidAlgebra` and `MonoidAlgebra`
-
-We have not defined `k[G] = MonoidAlgebra k (Multiplicative G)`
-because historically this caused problems;
-since the changes that have made `nsmul` definitional, this would be possible,
-but for now we just construct the ring isomorphisms using `RingEquiv.refl _`.
--/
-
-
-/-- The equivalence between `AddMonoidAlgebra` and `MonoidAlgebra` in terms of
-`Multiplicative` -/
-protected def AddMonoidAlgebra.toMultiplicative [Semiring k] [Add G] :
- AddMonoidAlgebra k G ≃+* MonoidAlgebra k (Multiplicative G) :=
- { Finsupp.domCongr
- Multiplicative.ofAdd with
- toFun := equivMapDomain Multiplicative.ofAdd
- map_mul' := fun x y => by
- -- Porting note: added `dsimp only`; `beta_reduce` alone is not sufficient
- dsimp only
- repeat' rw [equivMapDomain_eq_mapDomain (M := k)]
- dsimp [Multiplicative.ofAdd]
- exact MonoidAlgebra.mapDomain_mul (α := Multiplicative G) (β := k)
- (MulHom.id (Multiplicative G)) x y }
-
-/-- The equivalence between `MonoidAlgebra` and `AddMonoidAlgebra` in terms of `Additive` -/
-protected def MonoidAlgebra.toAdditive [Semiring k] [Mul G] :
- MonoidAlgebra k G ≃+* AddMonoidAlgebra k (Additive G) :=
- { Finsupp.domCongr Additive.ofMul with
- toFun := equivMapDomain Additive.ofMul
- map_mul' := fun x y => by
- -- Porting note: added `dsimp only`; `beta_reduce` alone is not sufficient
- dsimp only
- repeat' rw [equivMapDomain_eq_mapDomain (M := k)]
- dsimp [Additive.ofMul]
- convert MonoidAlgebra.mapDomain_mul (β := k) (MulHom.id G) x y }
-
namespace AddMonoidAlgebra
variable {k G H}
/-! #### Non-unital, non-associative algebra structure -/
-
section NonUnitalNonAssocAlgebra
variable (k) [Semiring k] [DistribSMul R k] [Add G]
-
-instance isScalarTower_self [IsScalarTower R k k] :
- IsScalarTower R k[G] k[G] :=
- @MonoidAlgebra.isScalarTower_self k (Multiplicative G) R _ _ _ _
-
-/-- 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 k[G] k[G] :=
- @MonoidAlgebra.smulCommClass_self k (Multiplicative G) R _ _ _ _
-
-instance smulCommClass_symm_self [SMulCommClass k R k] :
- SMulCommClass k[G] R k[G] :=
- @MonoidAlgebra.smulCommClass_symm_self k (Multiplicative G) R _ _ _ _
-
variable {A : Type u₃} [NonUnitalNonAssocSemiring A]
/-- A non_unital `k`-algebra homomorphism from `k[G]` is uniquely defined by its
@@ -1680,75 +380,6 @@ end NonUnitalNonAssocAlgebra
section Algebra
--- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
-
-/-- `Finsupp.single 0` as a `RingHom` -/
-@[simps]
-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] }
-
-/-- If two ring homomorphisms from `k[G]` are equal on all `single a 1`
-and `single 0 b`, then they are equal. -/
-theorem ringHom_ext {R} [Semiring k] [AddMonoid G] [Semiring R] {f g : k[G] →+* R}
- (h₀ : ∀ b, f (single 0 b) = g (single 0 b)) (h_of : ∀ a, f (single a 1) = g (single a 1)) :
- f = g :=
- @MonoidAlgebra.ringHom_ext k (Multiplicative G) R _ _ _ _ _ h₀ h_of
-
-/-- If two ring homomorphisms from `k[G]` are equal on all `single a 1`
-and `single 0 b`, then they are equal.
-
-See note [partially-applied ext lemmas]. -/
-@[ext high]
-theorem ringHom_ext' {R} [Semiring k] [AddMonoid G] [Semiring R] {f g : k[G] →+* R}
- (h₁ : f.comp singleZeroRingHom = g.comp singleZeroRingHom)
- (h_of : (f : k[G] →* R).comp (of k G) = (g : k[G] →* R).comp (of k G)) :
- f = g :=
- ringHom_ext (RingHom.congr_fun h₁) (DFunLike.congr_fun h_of)
-
-section Opposite
-
-open Finsupp MulOpposite
-
-variable [Semiring k]
-
-/-- The opposite of an `R[I]` is ring equivalent to
-the `AddMonoidAlgebra Rᵐᵒᵖ I` over the opposite ring, taking elements to their opposite. -/
-@[simps! (config := { simpRhs := true }) apply symm_apply]
-protected noncomputable def opRingEquiv [AddCommMonoid G] :
- k[G]ᵐᵒᵖ ≃+* kᵐᵒᵖ[G] :=
- { MulOpposite.opAddEquiv.symm.trans
- (Finsupp.mapRange.addEquiv (MulOpposite.opAddEquiv : k ≃+ kᵐᵒᵖ)) with
- map_mul' := by
- -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
- 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`.
- 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.
- dsimp
- -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
- 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]
- simp only [mapRange_single, single_mul_single, ← op_mul, add_comm] }
-
--- @[simp] -- Porting note (#10618): simp can prove this
-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
-
-end Opposite
-
/-- The instance `Algebra R k[G]` whenever we have `Algebra R k`.
In particular this provides the instance `Algebra k k[G]`.
@@ -1756,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]
@@ -1771,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 }
@@ -1867,21 +496,6 @@ theorem algHom_ext_iff {φ₁ φ₂ : k[G] →ₐ[k] A} :
end lift
-section
-
--- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
-
-universe ui
-
-variable {ι : Type ui}
-
-theorem prod_single [CommSemiring k] [AddCommMonoid G] {s : Finset ι} {a : ι → G} {b : ι → k} :
- (∏ i ∈ s, single (a i) (b i)) = single (∑ i ∈ s, a i) (∏ i ∈ s, b i) :=
- Finset.cons_induction_on s rfl fun a s has ih => by
- rw [prod_cons has, ih, single_mul_single, sum_cons has, prod_cons has]
-
-end
-
theorem mapDomain_algebraMap (A : Type*) {H F : Type*} [CommSemiring k] [Semiring A] [Algebra k A]
[AddMonoid G] [AddMonoid H] [FunLike F G H] [AddMonoidHomClass F G H]
(f : F) (r : k) :
@@ -1966,5 +580,3 @@ def AddMonoidAlgebra.toMultiplicativeAlgEquiv [Semiring k] [Algebra R k] [AddMon
def MonoidAlgebra.toAdditiveAlgEquiv [Semiring k] [Algebra R k] [Monoid G] :
MonoidAlgebra k G ≃ₐ[R] AddMonoidAlgebra k (Additive G) :=
{ MonoidAlgebra.toAdditive k G with commutes' := fun r => by simp [MonoidAlgebra.toAdditive] }
-
-set_option linter.style.longFile 2100
diff --git a/Mathlib/Algebra/MonoidAlgebra/Defs.lean b/Mathlib/Algebra/MonoidAlgebra/Defs.lean
new file mode 100644
index 0000000000000..09ff3e900210d
--- /dev/null
+++ b/Mathlib/Algebra/MonoidAlgebra/Defs.lean
@@ -0,0 +1,1551 @@
+/-
+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, Kim Morrison
+-/
+import Mathlib.Algebra.BigOperators.Finsupp
+import Mathlib.Algebra.Module.BigOperators
+import Mathlib.Data.Finsupp.Basic
+import Mathlib.LinearAlgebra.Finsupp
+
+/-!
+# Monoid algebras
+
+When the domain of a `Finsupp` has a multiplicative or additive structure, we can define
+a convolution product. To mathematicians this structure is known as the "monoid algebra",
+i.e. the finite formal linear combinations over a given semiring of elements of the monoid.
+The "group ring" ℤ[G] or the "group algebra" k[G] are typical uses.
+
+In fact the construction of the "monoid algebra" makes sense when `G` is not even a monoid, but
+merely a magma, i.e., when `G` carries a multiplication which is not required to satisfy any
+conditions at all. In this case the construction yields a not-necessarily-unital,
+not-necessarily-associative algebra but it is still adjoint to the forgetful functor from such
+algebras to magmas, and we prove this as `MonoidAlgebra.liftMagma`.
+
+In this file we define `MonoidAlgebra k G := G →₀ k`, and `AddMonoidAlgebra k G`
+in the same way, and then define the convolution product on these.
+
+When the domain is additive, this is used to define polynomials:
+```
+Polynomial R := AddMonoidAlgebra R ℕ
+MvPolynomial σ α := AddMonoidAlgebra R (σ →₀ ℕ)
+```
+
+When the domain is multiplicative, e.g. a group, this will be used to define the group ring.
+
+## Notation
+
+We introduce the notation `R[A]` for `AddMonoidAlgebra R A`.
+
+## Implementation note
+Unfortunately because additive and multiplicative structures both appear in both cases,
+it doesn't appear to be possible to make much use of `to_additive`, and we just settle for
+saying everything twice.
+
+Similarly, I attempted to just define
+`k[G] := MonoidAlgebra k (Multiplicative G)`, but the definitional equality
+`Multiplicative G = G` leaks through everywhere, and seems impossible to use.
+-/
+
+assert_not_exists NonUnitalAlgHom
+assert_not_exists AlgEquiv
+
+noncomputable section
+
+open Finset
+
+open Finsupp hiding single mapDomain
+
+universe u₁ u₂ u₃ u₄
+
+variable (k : Type u₁) (G : Type u₂) (H : Type*) {R : Type*}
+
+/-! ### Multiplicative monoids -/
+
+
+section
+
+variable [Semiring k]
+
+/-- The monoid algebra over a semiring `k` generated by the monoid `G`.
+It is the type of finite formal `k`-linear combinations of terms of `G`,
+endowed with the convolution product.
+-/
+def MonoidAlgebra : Type max u₁ u₂ :=
+ G →₀ k
+
+-- Porting note: The compiler couldn't derive this.
+instance MonoidAlgebra.inhabited : Inhabited (MonoidAlgebra k G) :=
+ inferInstanceAs (Inhabited (G →₀ k))
+
+-- Porting note: The compiler couldn't derive this.
+instance MonoidAlgebra.addCommMonoid : AddCommMonoid (MonoidAlgebra k G) :=
+ inferInstanceAs (AddCommMonoid (G →₀ k))
+
+instance MonoidAlgebra.instIsCancelAdd [IsCancelAdd k] : IsCancelAdd (MonoidAlgebra k G) :=
+ inferInstanceAs (IsCancelAdd (G →₀ k))
+
+instance MonoidAlgebra.coeFun : CoeFun (MonoidAlgebra k G) fun _ => G → k :=
+ inferInstanceAs (CoeFun (G →₀ k) _)
+
+end
+
+namespace MonoidAlgebra
+
+variable {k G}
+
+section
+
+variable [Semiring k] [NonUnitalNonAssocSemiring R]
+
+-- Porting note: `reducible` cannot be `local`, so we replace some definitions and theorems with
+-- new ones which have new types.
+
+abbrev single (a : G) (b : k) : MonoidAlgebra k G := Finsupp.single a b
+
+theorem single_zero (a : G) : (single a 0 : MonoidAlgebra k G) = 0 := Finsupp.single_zero a
+
+theorem single_add (a : G) (b₁ b₂ : k) : single a (b₁ + b₂) = single a b₁ + single a b₂ :=
+ Finsupp.single_add a b₁ b₂
+
+@[simp]
+theorem sum_single_index {N} [AddCommMonoid N] {a : G} {b : k} {h : G → k → N}
+ (h_zero : h a 0 = 0) :
+ (single a b).sum h = h a b := Finsupp.sum_single_index h_zero
+
+@[simp]
+theorem sum_single (f : MonoidAlgebra k G) : f.sum single = f :=
+ Finsupp.sum_single f
+
+theorem single_apply {a a' : G} {b : k} [Decidable (a = a')] :
+ single a b a' = if a = a' then b else 0 :=
+ Finsupp.single_apply
+
+@[simp]
+theorem single_eq_zero {a : G} {b : k} : single a b = 0 ↔ b = 0 := Finsupp.single_eq_zero
+
+abbrev mapDomain {G' : Type*} (f : G → G') (v : MonoidAlgebra k G) : MonoidAlgebra k G' :=
+ Finsupp.mapDomain f v
+
+theorem mapDomain_sum {k' G' : Type*} [Semiring k'] {f : G → G'} {s : MonoidAlgebra k' G}
+ {v : G → k' → MonoidAlgebra k G} :
+ mapDomain f (s.sum v) = s.sum fun a b => mapDomain f (v a b) :=
+ Finsupp.mapDomain_sum
+
+/-- A non-commutative version of `MonoidAlgebra.lift`: given an additive homomorphism `f : k →+ R`
+and a homomorphism `g : G → R`, returns the additive homomorphism from
+`MonoidAlgebra k G` such that `liftNC f g (single a b) = f b * g a`. If `f` is a ring homomorphism
+and the range of either `f` or `g` is in center of `R`, then the result is a ring homomorphism. If
+`R` is a `k`-algebra and `f = algebraMap k R`, then the result is an algebra homomorphism called
+`MonoidAlgebra.lift`. -/
+def liftNC (f : k →+ R) (g : G → R) : MonoidAlgebra k G →+ R :=
+ liftAddHom fun x : G => (AddMonoidHom.mulRight (g x)).comp f
+
+@[simp]
+theorem liftNC_single (f : k →+ R) (g : G → R) (a : G) (b : k) :
+ liftNC f g (single a b) = f b * g a :=
+ liftAddHom_apply_single _ _ _
+
+end
+
+section Mul
+
+variable [Semiring k] [Mul G]
+
+/-- The multiplication in a monoid algebra. We make it irreducible so that Lean doesn't unfold
+it trying to unify two things that are different. -/
+@[irreducible] def mul' (f g : MonoidAlgebra k G) : MonoidAlgebra k G :=
+ f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => single (a₁ * a₂) (b₁ * b₂)
+
+/-- The product of `f g : MonoidAlgebra k G` is the finitely supported function
+ whose value at `a` is the sum of `f x * g y` over all pairs `x, y`
+ such that `x * y = a`. (Think of the group ring of a group.) -/
+instance instMul : Mul (MonoidAlgebra k G) := ⟨MonoidAlgebra.mul'⟩
+
+theorem mul_def {f g : MonoidAlgebra k G} :
+ f * g = f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => single (a₁ * a₂) (b₁ * b₂) := by
+ with_unfolding_all rfl
+
+instance nonUnitalNonAssocSemiring : NonUnitalNonAssocSemiring (MonoidAlgebra k G) :=
+ { Finsupp.instAddCommMonoid with
+ -- Porting note: `refine` & `exact` are required because `simp` behaves differently.
+ left_distrib := fun f g h => by
+ haveI := Classical.decEq G
+ simp only [mul_def]
+ refine Eq.trans (congr_arg (sum f) (funext₂ fun a₁ b₁ => sum_add_index ?_ ?_)) ?_ <;>
+ simp only [mul_add, mul_zero, single_zero, single_add, forall_true_iff, sum_add]
+ right_distrib := fun f g h => by
+ haveI := Classical.decEq G
+ simp only [mul_def]
+ refine Eq.trans (sum_add_index ?_ ?_) ?_ <;>
+ simp only [add_mul, zero_mul, single_zero, single_add, forall_true_iff, sum_zero, sum_add]
+ zero_mul := fun f => by
+ simp only [mul_def]
+ exact sum_zero_index
+ mul_zero := fun f => by
+ simp only [mul_def]
+ exact Eq.trans (congr_arg (sum f) (funext₂ fun a₁ b₁ => sum_zero_index)) sum_zero }
+
+variable [Semiring R]
+
+theorem liftNC_mul {g_hom : Type*} [FunLike g_hom G R] [MulHomClass g_hom G R]
+ (f : k →+* R) (g : g_hom) (a b : MonoidAlgebra k G)
+ (h_comm : ∀ {x y}, y ∈ a.support → Commute (f (b x)) (g y)) :
+ liftNC (f : k →+ R) g (a * b) = liftNC (f : k →+ R) g a * liftNC (f : k →+ R) g b := by
+ conv_rhs => rw [← sum_single a, ← sum_single b]
+ -- Porting note: `(liftNC _ g).map_finsupp_sum` → `map_finsupp_sum`
+ simp_rw [mul_def, map_finsupp_sum, liftNC_single, Finsupp.sum_mul, Finsupp.mul_sum]
+ refine Finset.sum_congr rfl fun y hy => Finset.sum_congr rfl fun x _hx => ?_
+ simp [mul_assoc, (h_comm hy).left_comm]
+
+end Mul
+
+section Semigroup
+
+variable [Semiring k] [Semigroup G] [Semiring R]
+
+instance nonUnitalSemiring : NonUnitalSemiring (MonoidAlgebra k G) :=
+ { MonoidAlgebra.nonUnitalNonAssocSemiring with
+ mul_assoc := fun f g h => by
+ -- Porting note: `reducible` cannot be `local` so proof gets long.
+ simp only [mul_def]
+ rw [sum_sum_index] <;> congr; on_goal 1 => ext a₁ b₁
+ rw [sum_sum_index, sum_sum_index] <;> congr; on_goal 1 => ext a₂ b₂
+ rw [sum_sum_index, sum_single_index] <;> congr; on_goal 1 => ext a₃ b₃
+ on_goal 1 => rw [sum_single_index, mul_assoc, mul_assoc]
+ all_goals simp only [single_zero, single_add, forall_true_iff, add_mul,
+ mul_add, zero_mul, mul_zero, sum_zero, sum_add] }
+
+end Semigroup
+
+section One
+
+variable [NonAssocSemiring R] [Semiring k] [One G]
+
+/-- The unit of the multiplication is `single 1 1`, i.e. the function
+ that is `1` at `1` and zero elsewhere. -/
+instance one : One (MonoidAlgebra k G) :=
+ ⟨single 1 1⟩
+
+theorem one_def : (1 : MonoidAlgebra k G) = single 1 1 :=
+ rfl
+
+@[simp]
+theorem liftNC_one {g_hom : Type*} [FunLike g_hom G R] [OneHomClass g_hom G R]
+ (f : k →+* R) (g : g_hom) :
+ liftNC (f : k →+ R) g 1 = 1 := by simp [one_def]
+
+end One
+
+section MulOneClass
+
+variable [Semiring k] [MulOneClass G]
+
+instance nonAssocSemiring : NonAssocSemiring (MonoidAlgebra k G) :=
+ { MonoidAlgebra.nonUnitalNonAssocSemiring with
+ natCast := fun n => single 1 n
+ natCast_zero := by simp
+ natCast_succ := fun _ => by simp; rfl
+ one_mul := fun f => by
+ simp only [mul_def, one_def, sum_single_index, zero_mul, single_zero, sum_zero, zero_add,
+ one_mul, sum_single]
+ mul_one := fun f => by
+ simp only [mul_def, one_def, sum_single_index, mul_zero, single_zero, sum_zero, add_zero,
+ mul_one, sum_single] }
+
+theorem natCast_def (n : ℕ) : (n : MonoidAlgebra k G) = single (1 : G) (n : k) :=
+ rfl
+
+@[deprecated (since := "2024-04-17")]
+alias nat_cast_def := natCast_def
+
+end MulOneClass
+
+/-! #### Semiring structure -/
+
+
+section Semiring
+
+variable [Semiring k] [Monoid G]
+
+instance semiring : Semiring (MonoidAlgebra k G) :=
+ { MonoidAlgebra.nonUnitalSemiring,
+ MonoidAlgebra.nonAssocSemiring with }
+
+variable [Semiring R]
+
+/-- `liftNC` as a `RingHom`, for when `f x` and `g y` commute -/
+def liftNCRingHom (f : k →+* R) (g : G →* R) (h_comm : ∀ x y, Commute (f x) (g y)) :
+ MonoidAlgebra k G →+* R :=
+ { liftNC (f : k →+ R) g with
+ map_one' := liftNC_one _ _
+ map_mul' := fun _a _b => liftNC_mul _ _ _ _ fun {_ _} _ => h_comm _ _ }
+
+end Semiring
+
+instance nonUnitalCommSemiring [CommSemiring k] [CommSemigroup G] :
+ NonUnitalCommSemiring (MonoidAlgebra k G) :=
+ { MonoidAlgebra.nonUnitalSemiring with
+ mul_comm := fun f g => by
+ simp only [mul_def, Finsupp.sum, mul_comm]
+ rw [Finset.sum_comm]
+ simp only [mul_comm] }
+
+instance nontrivial [Semiring k] [Nontrivial k] [Nonempty G] : Nontrivial (MonoidAlgebra k G) :=
+ Finsupp.instNontrivial
+
+/-! #### Derived instances -/
+
+
+section DerivedInstances
+
+instance commSemiring [CommSemiring k] [CommMonoid G] : CommSemiring (MonoidAlgebra k G) :=
+ { MonoidAlgebra.nonUnitalCommSemiring, MonoidAlgebra.semiring with }
+
+instance unique [Semiring k] [Subsingleton k] : Unique (MonoidAlgebra k G) :=
+ Finsupp.uniqueOfRight
+
+instance addCommGroup [Ring k] : AddCommGroup (MonoidAlgebra k G) :=
+ Finsupp.instAddCommGroup
+
+instance nonUnitalNonAssocRing [Ring k] [Mul G] : NonUnitalNonAssocRing (MonoidAlgebra k G) :=
+ { MonoidAlgebra.addCommGroup, MonoidAlgebra.nonUnitalNonAssocSemiring with }
+
+instance nonUnitalRing [Ring k] [Semigroup G] : NonUnitalRing (MonoidAlgebra k G) :=
+ { MonoidAlgebra.addCommGroup, MonoidAlgebra.nonUnitalSemiring with }
+
+instance nonAssocRing [Ring k] [MulOneClass G] : NonAssocRing (MonoidAlgebra k G) :=
+ { MonoidAlgebra.addCommGroup,
+ MonoidAlgebra.nonAssocSemiring with
+ intCast := fun z => single 1 (z : k)
+ -- Porting note: Both were `simpa`.
+ intCast_ofNat := fun n => by simp; rfl
+ intCast_negSucc := fun n => by simp; rfl }
+
+theorem intCast_def [Ring k] [MulOneClass G] (z : ℤ) :
+ (z : MonoidAlgebra k G) = single (1 : G) (z : k) :=
+ rfl
+
+@[deprecated (since := "2024-04-17")]
+alias int_cast_def := intCast_def
+
+instance ring [Ring k] [Monoid G] : Ring (MonoidAlgebra k G) :=
+ { MonoidAlgebra.nonAssocRing, MonoidAlgebra.semiring with }
+
+instance nonUnitalCommRing [CommRing k] [CommSemigroup G] :
+ NonUnitalCommRing (MonoidAlgebra k G) :=
+ { MonoidAlgebra.nonUnitalCommSemiring, MonoidAlgebra.nonUnitalRing with }
+
+instance commRing [CommRing k] [CommMonoid G] : CommRing (MonoidAlgebra k G) :=
+ { MonoidAlgebra.nonUnitalCommRing, MonoidAlgebra.ring with }
+
+variable {S : Type*}
+
+instance smulZeroClass [Semiring k] [SMulZeroClass R k] : SMulZeroClass R (MonoidAlgebra k G) :=
+ Finsupp.smulZeroClass
+
+instance distribSMul [Semiring k] [DistribSMul R k] : DistribSMul R (MonoidAlgebra k G) :=
+ Finsupp.distribSMul _ _
+
+instance distribMulAction [Monoid R] [Semiring k] [DistribMulAction R k] :
+ DistribMulAction R (MonoidAlgebra k G) :=
+ Finsupp.distribMulAction G k
+
+instance module [Semiring R] [Semiring k] [Module R k] : Module R (MonoidAlgebra k G) :=
+ Finsupp.module G k
+
+instance faithfulSMul [Semiring k] [SMulZeroClass R k] [FaithfulSMul R k] [Nonempty G] :
+ FaithfulSMul R (MonoidAlgebra k G) :=
+ Finsupp.faithfulSMul
+
+instance isScalarTower [Semiring k] [SMulZeroClass R k] [SMulZeroClass S k] [SMul R S]
+ [IsScalarTower R S k] : IsScalarTower R S (MonoidAlgebra k G) :=
+ Finsupp.isScalarTower G k
+
+instance smulCommClass [Semiring k] [SMulZeroClass R k] [SMulZeroClass S k] [SMulCommClass R S k] :
+ SMulCommClass R S (MonoidAlgebra k G) :=
+ Finsupp.smulCommClass G k
+
+instance isCentralScalar [Semiring k] [SMulZeroClass R k] [SMulZeroClass Rᵐᵒᵖ k]
+ [IsCentralScalar R k] : IsCentralScalar R (MonoidAlgebra k G) :=
+ Finsupp.isCentralScalar G k
+
+/-- This is not an instance as it conflicts with `MonoidAlgebra.distribMulAction` when `G = kˣ`.
+-/
+def comapDistribMulActionSelf [Group G] [Semiring k] : DistribMulAction G (MonoidAlgebra k G) :=
+ Finsupp.comapDistribMulAction
+
+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]
+
+-- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
+
+theorem mul_apply [DecidableEq G] [Mul G] (f g : MonoidAlgebra k G) (x : G) :
+ (f * g) x = f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => if a₁ * a₂ = x then b₁ * b₂ else 0 := by
+ -- Porting note: `reducible` cannot be `local` so proof gets long.
+ rw [mul_def, Finsupp.sum_apply]; congr; ext
+ rw [Finsupp.sum_apply]; congr; ext
+ apply single_apply
+
+theorem mul_apply_antidiagonal [Mul G] (f g : MonoidAlgebra k G) (x : G) (s : Finset (G × G))
+ (hs : ∀ {p : G × G}, p ∈ s ↔ p.1 * p.2 = x) : (f * g) x = ∑ p ∈ s, f p.1 * g p.2 := by
+ classical exact
+ let F : G × G → k := fun p => if p.1 * p.2 = x then f p.1 * g p.2 else 0
+ 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 with p.1 * p.2 = x, f p.1 * g p.2 :=
+ (Finset.sum_filter _ _).symm
+ _ = ∑ 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 ⊢
+ by_cases h1 : f p.1 = 0
+ · rw [h1, zero_mul]
+ · rw [hp hps h1, mul_zero]
+
+@[simp]
+theorem single_mul_single [Mul G] {a₁ a₂ : G} {b₁ b₂ : k} :
+ single a₁ b₁ * single a₂ b₂ = single (a₁ * a₂) (b₁ * b₂) := by
+ rw [mul_def]
+ exact (sum_single_index (by simp only [zero_mul, single_zero, sum_zero])).trans
+ (sum_single_index (by rw [mul_zero, single_zero]))
+
+theorem single_commute_single [Mul G] {a₁ a₂ : G} {b₁ b₂ : k}
+ (ha : Commute a₁ a₂) (hb : Commute b₁ b₂) :
+ Commute (single a₁ b₁) (single a₂ b₂) :=
+ single_mul_single.trans <| congr_arg₂ single ha hb |>.trans single_mul_single.symm
+
+theorem single_commute [Mul G] {a : G} {b : k} (ha : ∀ a', Commute a a') (hb : ∀ b', Commute b b') :
+ ∀ f : MonoidAlgebra k G, Commute (single a b) f :=
+ suffices AddMonoidHom.mulLeft (single a b) = AddMonoidHom.mulRight (single a b) from
+ DFunLike.congr_fun this
+ addHom_ext' fun a' => AddMonoidHom.ext fun b' => single_commute_single (ha a') (hb b')
+
+@[simp]
+theorem single_pow [Monoid G] {a : G} {b : k} : ∀ n : ℕ, single a b ^ n = single (a ^ n) (b ^ n)
+ | 0 => by
+ simp only [pow_zero]
+ rfl
+ | n + 1 => by simp only [pow_succ, single_pow n, single_mul_single]
+
+section
+
+/-- Like `Finsupp.mapDomain_zero`, but for the `1` we define in this file -/
+@[simp]
+theorem mapDomain_one {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [One α] [One α₂]
+ {F : Type*} [FunLike F α α₂] [OneHomClass F α α₂] (f : F) :
+ (mapDomain f (1 : MonoidAlgebra β α) : MonoidAlgebra β α₂) = (1 : MonoidAlgebra β α₂) := by
+ simp_rw [one_def, mapDomain_single, map_one]
+
+/-- Like `Finsupp.mapDomain_add`, but for the convolutive multiplication we define in this file -/
+theorem mapDomain_mul {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Mul α] [Mul α₂]
+ {F : Type*} [FunLike F α α₂] [MulHomClass F α α₂] (f : F) (x y : MonoidAlgebra β α) :
+ mapDomain f (x * y) = mapDomain f x * mapDomain f y := by
+ simp_rw [mul_def, mapDomain_sum, mapDomain_single, map_mul]
+ rw [Finsupp.sum_mapDomain_index]
+ · congr
+ ext a b
+ rw [Finsupp.sum_mapDomain_index]
+ · simp
+ · simp [mul_add]
+ · simp
+ · simp [add_mul]
+
+variable (k G)
+
+/-- The embedding of a magma into its magma algebra. -/
+@[simps]
+def ofMagma [Mul G] : G →ₙ* MonoidAlgebra k G where
+ toFun a := single a 1
+ map_mul' a b := by simp only [mul_def, mul_one, sum_single_index, single_eq_zero, mul_zero]
+
+/-- The embedding of a unital magma into its magma algebra. -/
+@[simps]
+def of [MulOneClass G] : G →* MonoidAlgebra k G :=
+ { ofMagma k G with
+ toFun := fun a => single a 1
+ map_one' := rfl }
+
+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
+ simp
+
+theorem of_injective [MulOneClass G] [Nontrivial k] :
+ Function.Injective (of k G) := fun a b h => by
+ simpa using (single_eq_single_iff _ _ _ _).mp h
+
+theorem of_commute [MulOneClass G] {a : G} (h : ∀ a', Commute a a') (f : MonoidAlgebra k G) :
+ Commute (of k G a) f :=
+ single_commute h Commute.one_left f
+
+/-- `Finsupp.single` as a `MonoidHom` from the product type into the monoid algebra.
+
+Note the order of the elements of the product are reversed compared to the arguments of
+`Finsupp.single`.
+-/
+@[simps]
+def singleHom [MulOneClass G] : k × G →* MonoidAlgebra k G where
+ toFun a := single a.2 a.1
+ map_one' := rfl
+ map_mul' _a _b := single_mul_single.symm
+
+theorem mul_single_apply_aux [Mul G] (f : MonoidAlgebra k G) {r : k} {x y z : G}
+ (H : ∀ a, a * x = z ↔ a = y) : (f * single x r) z = f y * r := by
+ classical exact
+ have A :
+ ∀ a₁ b₁,
+ ((single x r).sum fun a₂ b₂ => ite (a₁ * a₂ = z) (b₁ * b₂) 0) =
+ ite (a₁ * x = z) (b₁ * r) 0 :=
+ fun a₁ b₁ => sum_single_index <| by simp
+ calc
+ (HMul.hMul (β := MonoidAlgebra k G) f (single x r)) z =
+ sum f fun a b => if a = y then b * r else 0 := by simp only [mul_apply, A, H]
+ _ = if y ∈ f.support then f y * r else 0 := f.support.sum_ite_eq' _ _
+ _ = f y * r := by split_ifs with h <;> simp at h <;> simp [h]
+
+theorem mul_single_one_apply [MulOneClass G] (f : MonoidAlgebra k G) (r : k) (x : G) :
+ (HMul.hMul (β := MonoidAlgebra k G) f (single 1 r)) x = f x * r :=
+ f.mul_single_apply_aux fun a => by rw [mul_one]
+
+theorem mul_single_apply_of_not_exists_mul [Mul G] (r : k) {g g' : G} (x : MonoidAlgebra k G)
+ (h : ¬∃ d, g' = d * g) : (x * single g r) g' = 0 := by
+ classical
+ rw [mul_apply, Finsupp.sum_comm, Finsupp.sum_single_index]
+ swap
+ · simp_rw [Finsupp.sum, mul_zero, ite_self, Finset.sum_const_zero]
+ · apply Finset.sum_eq_zero
+ simp_rw [ite_eq_right_iff]
+ rintro g'' _hg'' rfl
+ exfalso
+ exact h ⟨_, rfl⟩
+
+theorem single_mul_apply_aux [Mul G] (f : MonoidAlgebra k G) {r : k} {x y z : G}
+ (H : ∀ a, x * a = y ↔ a = z) : (single x r * f) y = r * f z := by
+ classical exact
+ have : (f.sum fun a b => ite (x * a = y) (0 * b) 0) = 0 := by simp
+ calc
+ (HMul.hMul (α := MonoidAlgebra k G) (single x r) f) y =
+ sum f fun a b => ite (x * a = y) (r * b) 0 :=
+ (mul_apply _ _ _).trans <| sum_single_index this
+ _ = f.sum fun a b => ite (a = z) (r * b) 0 := by simp only [H]
+ _ = if z ∈ f.support then r * f z else 0 := f.support.sum_ite_eq' _ _
+ _ = _ := by split_ifs with h <;> simp at h <;> simp [h]
+
+theorem single_one_mul_apply [MulOneClass G] (f : MonoidAlgebra k G) (r : k) (x : G) :
+ (single (1 : G) r * f) x = r * f x :=
+ f.single_mul_apply_aux fun a => by rw [one_mul]
+
+theorem single_mul_apply_of_not_exists_mul [Mul G] (r : k) {g g' : G} (x : MonoidAlgebra k G)
+ (h : ¬∃ d, g' = g * d) : (single g r * x) g' = 0 := by
+ classical
+ rw [mul_apply, Finsupp.sum_single_index]
+ swap
+ · simp_rw [Finsupp.sum, zero_mul, ite_self, Finset.sum_const_zero]
+ · apply Finset.sum_eq_zero
+ simp_rw [ite_eq_right_iff]
+ rintro g'' _hg'' rfl
+ exfalso
+ exact h ⟨_, rfl⟩
+
+theorem liftNC_smul [MulOneClass G] {R : Type*} [Semiring R] (f : k →+* R) (g : G →* R) (c : k)
+ (φ : MonoidAlgebra k G) : liftNC (f : k →+ R) g (c • φ) = f c * liftNC (f : k →+ R) g φ := by
+ suffices (liftNC (↑f) g).comp (smulAddHom k (MonoidAlgebra k G) c) =
+ (AddMonoidHom.mulLeft (f c)).comp (liftNC (↑f) g) from
+ DFunLike.congr_fun this φ
+ 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, 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]
+
+end MiscTheorems
+
+/-! #### Non-unital, non-associative algebra structure -/
+
+
+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) 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]
+
+/-- 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) 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]
+
+instance smulCommClass_symm_self [SMulCommClass k R k] :
+ SMulCommClass (MonoidAlgebra k G) R (MonoidAlgebra k G) :=
+ ⟨fun t a b => by
+ haveI := SMulCommClass.symm k R k
+ rw [← smul_comm]⟩
+
+end NonUnitalNonAssocAlgebra
+
+theorem single_one_comm [CommSemiring k] [MulOneClass G] (r : k) (f : MonoidAlgebra k G) :
+ single (1 : G) r * f = f * single (1 : G) r :=
+ single_commute Commute.one_left (Commute.all _) f
+
+/-- `Finsupp.single 1` as a `RingHom` -/
+@[simps]
+def singleOneRingHom [Semiring k] [MulOneClass G] : k →+* MonoidAlgebra k G :=
+ { Finsupp.singleAddHom 1 with
+ map_one' := rfl
+ 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. -/
+@[simps]
+def mapDomainRingHom (k : Type*) {H F : Type*} [Semiring k] [Monoid G] [Monoid H]
+ [FunLike F G H] [MonoidHomClass F G H] (f : F) : MonoidAlgebra k G →+* MonoidAlgebra k H :=
+ { (Finsupp.mapDomain.addMonoidHom f : MonoidAlgebra k G →+ MonoidAlgebra k H) with
+ map_one' := mapDomain_one f
+ map_mul' := fun x y => mapDomain_mul f x y }
+
+/-- If two ring homomorphisms from `MonoidAlgebra k G` are equal on all `single a 1`
+and `single 1 b`, then they are equal. -/
+theorem ringHom_ext {R} [Semiring k] [MulOneClass G] [Semiring R] {f g : MonoidAlgebra k G →+* R}
+ (h₁ : ∀ b, f (single 1 b) = g (single 1 b)) (h_of : ∀ a, f (single a 1) = g (single a 1)) :
+ f = g :=
+ RingHom.coe_addMonoidHom_injective <|
+ addHom_ext fun a b => by
+ rw [← single, ← one_mul a, ← mul_one b, ← single_mul_single]
+ -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
+ erw [AddMonoidHom.coe_coe f, AddMonoidHom.coe_coe g]; rw [f.map_mul, g.map_mul, h₁, h_of]
+
+/-- If two ring homomorphisms from `MonoidAlgebra k G` are equal on all `single a 1`
+and `single 1 b`, then they are equal.
+
+See note [partially-applied ext lemmas]. -/
+@[ext high]
+theorem ringHom_ext' {R} [Semiring k] [MulOneClass G] [Semiring R] {f g : MonoidAlgebra k G →+* R}
+ (h₁ : f.comp singleOneRingHom = g.comp singleOneRingHom)
+ (h_of :
+ (f : MonoidAlgebra k G →* R).comp (of k G) = (g : MonoidAlgebra k G →* R).comp (of k G)) :
+ f = g :=
+ ringHom_ext (RingHom.congr_fun h₁) (DFunLike.congr_fun h_of)
+
+theorem induction_on [Semiring k] [Monoid G] {p : MonoidAlgebra k G → Prop} (f : MonoidAlgebra k G)
+ (hM : ∀ g, p (of k G g)) (hadd : ∀ f g : MonoidAlgebra k G, p f → p g → p (f + g))
+ (hsmul : ∀ (r : k) (f), p f → p (r • f)) : p f := by
+ 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)
+ simp
+
+section
+
+universe ui
+
+variable {ι : Type ui}
+
+-- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
+
+theorem prod_single [CommSemiring k] [CommMonoid G] {s : Finset ι} {a : ι → G} {b : ι → k} :
+ (∏ i ∈ s, single (a i) (b i)) = single (∏ i ∈ s, a i) (∏ i ∈ s, b i) :=
+ Finset.cons_induction_on s rfl fun a s has ih => by
+ rw [prod_cons has, ih, single_mul_single, prod_cons has, prod_cons has]
+
+end
+
+section
+
+-- We now prove some additional statements that hold for group algebras.
+variable [Semiring k] [Group G]
+
+-- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
+
+@[simp]
+theorem mul_single_apply (f : MonoidAlgebra k G) (r : k) (x y : G) :
+ (f * single x r) y = f (y * x⁻¹) * r :=
+ f.mul_single_apply_aux fun _a => eq_mul_inv_iff_mul_eq.symm
+
+@[simp]
+theorem single_mul_apply (r : k) (x : G) (f : MonoidAlgebra k G) (y : G) :
+ (single x r * f) y = r * f (x⁻¹ * y) :=
+ f.single_mul_apply_aux fun _z => eq_inv_mul_iff_mul_eq.symm
+
+theorem mul_apply_left (f g : MonoidAlgebra k G) (x : G) :
+ (f * g) x = f.sum fun a b => b * g (a⁻¹ * x) :=
+ calc
+ (f * g) x = sum f fun a b => (single a b * g) x := by
+ rw [← Finsupp.sum_apply, ← Finsupp.sum_mul g f, f.sum_single]
+ _ = _ := by simp only [single_mul_apply, Finsupp.sum]
+
+-- If we'd assumed `CommSemiring`, we could deduce this from `mul_apply_left`.
+theorem mul_apply_right (f g : MonoidAlgebra k G) (x : G) :
+ (f * g) x = g.sum fun a b => f (x * a⁻¹) * b :=
+ calc
+ (f * g) x = sum g fun a b => (f * single a b) x := by
+ rw [← Finsupp.sum_apply, ← Finsupp.mul_sum f g, g.sum_single]
+ _ = _ := by simp only [mul_single_apply, Finsupp.sum]
+
+end
+
+section Opposite
+
+open Finsupp MulOpposite
+
+variable [Semiring k]
+
+/-- The opposite of a `MonoidAlgebra R I` equivalent as a ring to
+the `MonoidAlgebra Rᵐᵒᵖ Iᵐᵒᵖ` over the opposite ring, taking elements to their opposite. -/
+@[simps! (config := { simpRhs := true }) apply symm_apply]
+protected noncomputable def opRingEquiv [Monoid G] :
+ (MonoidAlgebra k G)ᵐᵒᵖ ≃+* MonoidAlgebra kᵐᵒᵖ Gᵐᵒᵖ :=
+ { opAddEquiv.symm.trans <|
+ (Finsupp.mapRange.addEquiv (opAddEquiv : k ≃+ kᵐᵒᵖ)).trans <| Finsupp.domCongr opEquiv with
+ map_mul' := by
+ -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
+ 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 := (MonoidAlgebra k G)ᵐᵒᵖ)
+ (S := MonoidAlgebra kᵐᵒᵖ Gᵐᵒᵖ) _) ?_
+ 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,
+ AddMonoidHom.coe_mulLeft, AddMonoidHom.compl₂_apply]
+ -- 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), unop_op, unop_op, single_mul_single]
+ simp }
+
+-- @[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
+
+theorem opRingEquiv_symm_single [Monoid G] (r : kᵐᵒᵖ) (x : Gᵐᵒᵖ) :
+ MonoidAlgebra.opRingEquiv.symm (single x r) = op (single x.unop r.unop) := by simp
+
+end Opposite
+
+section Submodule
+
+variable [CommSemiring k] [Monoid G]
+variable {V : Type*} [AddCommMonoid V]
+variable [Module k V] [Module (MonoidAlgebra k G) V] [IsScalarTower k (MonoidAlgebra k G) V]
+
+/-- A submodule over `k` which is stable under scalar multiplication by elements of `G` is a
+submodule over `MonoidAlgebra k G` -/
+def submoduleOfSMulMem (W : Submodule k V) (h : ∀ (g : G) (v : V), v ∈ W → of k G g • v ∈ W) :
+ Submodule (MonoidAlgebra k G) V where
+ carrier := W
+ zero_mem' := W.zero_mem'
+ add_mem' := W.add_mem'
+ smul_mem' := by
+ intro f v hv
+ rw [← Finsupp.sum_single f, Finsupp.sum, Finset.sum_smul]
+ simp_rw [← smul_of, smul_assoc]
+ exact Submodule.sum_smul_mem W _ fun g _ => h g v hv
+
+end Submodule
+
+end MonoidAlgebra
+
+/-! ### Additive monoids -/
+
+
+section
+
+variable [Semiring k]
+
+/-- The monoid algebra over a semiring `k` generated by the additive monoid `G`.
+It is the type of finite formal `k`-linear combinations of terms of `G`,
+endowed with the convolution product.
+-/
+def AddMonoidAlgebra :=
+ G →₀ k
+
+@[inherit_doc]
+scoped[AddMonoidAlgebra] notation:9000 R:max "[" A "]" => AddMonoidAlgebra R A
+
+namespace AddMonoidAlgebra
+
+-- Porting note: The compiler couldn't derive this.
+instance inhabited : Inhabited k[G] :=
+ inferInstanceAs (Inhabited (G →₀ k))
+
+-- Porting note: The compiler couldn't derive this.
+instance addCommMonoid : AddCommMonoid k[G] :=
+ inferInstanceAs (AddCommMonoid (G →₀ k))
+
+instance instIsCancelAdd [IsCancelAdd k] : IsCancelAdd (AddMonoidAlgebra k G) :=
+ inferInstanceAs (IsCancelAdd (G →₀ k))
+
+instance coeFun : CoeFun k[G] fun _ => G → k :=
+ inferInstanceAs (CoeFun (G →₀ k) _)
+
+end AddMonoidAlgebra
+
+end
+
+namespace AddMonoidAlgebra
+
+variable {k G}
+
+section
+
+variable [Semiring k] [NonUnitalNonAssocSemiring R]
+
+-- Porting note: `reducible` cannot be `local`, so we replace some definitions and theorems with
+-- new ones which have new types.
+
+abbrev single (a : G) (b : k) : k[G] := Finsupp.single a b
+
+theorem single_zero (a : G) : (single a 0 : k[G]) = 0 := Finsupp.single_zero a
+
+theorem single_add (a : G) (b₁ b₂ : k) : single a (b₁ + b₂) = single a b₁ + single a b₂ :=
+ Finsupp.single_add a b₁ b₂
+
+@[simp]
+theorem sum_single_index {N} [AddCommMonoid N] {a : G} {b : k} {h : G → k → N}
+ (h_zero : h a 0 = 0) :
+ (single a b).sum h = h a b := Finsupp.sum_single_index h_zero
+
+@[simp]
+theorem sum_single (f : k[G]) : f.sum single = f :=
+ Finsupp.sum_single f
+
+theorem single_apply {a a' : G} {b : k} [Decidable (a = a')] :
+ single a b a' = if a = a' then b else 0 :=
+ Finsupp.single_apply
+
+@[simp]
+theorem single_eq_zero {a : G} {b : k} : single a b = 0 ↔ b = 0 := Finsupp.single_eq_zero
+
+abbrev mapDomain {G' : Type*} (f : G → G') (v : k[G]) : k[G'] :=
+ Finsupp.mapDomain f v
+
+theorem mapDomain_sum {k' G' : Type*} [Semiring k'] {f : G → G'} {s : AddMonoidAlgebra k' G}
+ {v : G → k' → k[G]} :
+ mapDomain f (s.sum v) = s.sum fun a b => mapDomain f (v a b) :=
+ Finsupp.mapDomain_sum
+
+theorem mapDomain_single {G' : Type*} {f : G → G'} {a : G} {b : k} :
+ mapDomain f (single a b) = single (f a) b :=
+ Finsupp.mapDomain_single
+
+/-- A non-commutative version of `AddMonoidAlgebra.lift`: given an additive homomorphism
+`f : k →+ R` and a map `g : Multiplicative G → R`, returns the additive
+homomorphism from `k[G]` such that `liftNC f g (single a b) = f b * g a`. If `f`
+is a ring homomorphism and the range of either `f` or `g` is in center of `R`, then the result is a
+ring homomorphism. If `R` is a `k`-algebra and `f = algebraMap k R`, then the result is an algebra
+homomorphism called `AddMonoidAlgebra.lift`. -/
+def liftNC (f : k →+ R) (g : Multiplicative G → R) : k[G] →+ R :=
+ liftAddHom fun x : G => (AddMonoidHom.mulRight (g <| Multiplicative.ofAdd x)).comp f
+
+@[simp]
+theorem liftNC_single (f : k →+ R) (g : Multiplicative G → R) (a : G) (b : k) :
+ liftNC f g (single a b) = f b * g (Multiplicative.ofAdd a) :=
+ liftAddHom_apply_single _ _ _
+
+end
+
+section Mul
+
+variable [Semiring k] [Add G]
+
+/-- The product of `f g : k[G]` is the finitely supported function
+ whose value at `a` is the sum of `f x * g y` over all pairs `x, y`
+ such that `x + y = a`. (Think of the product of multivariate
+ polynomials where `α` is the additive monoid of monomial exponents.) -/
+instance hasMul : Mul k[G] :=
+ ⟨fun f g => MonoidAlgebra.mul' (G := Multiplicative G) f g⟩
+
+theorem mul_def {f g : k[G]} :
+ f * g = f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => single (a₁ + a₂) (b₁ * b₂) :=
+ MonoidAlgebra.mul_def (G := Multiplicative G)
+
+instance nonUnitalNonAssocSemiring : NonUnitalNonAssocSemiring k[G] :=
+ { Finsupp.instAddCommMonoid with
+ -- Porting note: `refine` & `exact` are required because `simp` behaves differently.
+ left_distrib := fun f g h => by
+ haveI := Classical.decEq G
+ simp only [mul_def]
+ refine Eq.trans (congr_arg (sum f) (funext₂ fun a₁ b₁ => sum_add_index ?_ ?_)) ?_ <;>
+ simp only [mul_add, mul_zero, single_zero, single_add, forall_true_iff, sum_add]
+ right_distrib := fun f g h => by
+ haveI := Classical.decEq G
+ simp only [mul_def]
+ refine Eq.trans (sum_add_index ?_ ?_) ?_ <;>
+ simp only [add_mul, zero_mul, single_zero, single_add, forall_true_iff, sum_zero, sum_add]
+ zero_mul := fun f => by
+ simp only [mul_def]
+ exact sum_zero_index
+ mul_zero := fun f => by
+ 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 (#11041): `ext` → `refine Finsupp.ext fun _ => ?_`
+ nsmul_zero := by
+ intros
+ refine Finsupp.ext fun _ => ?_
+ simp [-nsmul_eq_mul, add_smul]
+ nsmul_succ := by
+ intros
+ refine Finsupp.ext fun _ => ?_
+ simp [-nsmul_eq_mul, add_smul] }
+
+variable [Semiring R]
+
+theorem liftNC_mul {g_hom : Type*}
+ [FunLike g_hom (Multiplicative G) R] [MulHomClass g_hom (Multiplicative G) R]
+ (f : k →+* R) (g : g_hom) (a b : k[G])
+ (h_comm : ∀ {x y}, y ∈ a.support → Commute (f (b x)) (g <| Multiplicative.ofAdd y)) :
+ liftNC (f : k →+ R) g (a * b) = liftNC (f : k →+ R) g a * liftNC (f : k →+ R) g b :=
+ (MonoidAlgebra.liftNC_mul f g _ _ @h_comm : _)
+
+end Mul
+
+section One
+
+variable [Semiring k] [Zero G] [NonAssocSemiring R]
+
+/-- The unit of the multiplication is `single 0 1`, i.e. the function
+ that is `1` at `0` and zero elsewhere. -/
+instance one : One k[G] :=
+ ⟨single 0 1⟩
+
+theorem one_def : (1 : k[G]) = single 0 1 :=
+ rfl
+
+@[simp]
+theorem liftNC_one {g_hom : Type*}
+ [FunLike g_hom (Multiplicative G) R] [OneHomClass g_hom (Multiplicative G) R]
+ (f : k →+* R) (g : g_hom) : liftNC (f : k →+ R) g 1 = 1 :=
+ (MonoidAlgebra.liftNC_one f g : _)
+
+end One
+
+section Semigroup
+
+variable [Semiring k] [AddSemigroup G]
+
+instance nonUnitalSemiring : NonUnitalSemiring k[G] :=
+ { AddMonoidAlgebra.nonUnitalNonAssocSemiring with
+ mul_assoc := fun f g h => by
+ -- Porting note: `reducible` cannot be `local` so proof gets long.
+ simp only [mul_def]
+ rw [sum_sum_index] <;> congr; on_goal 1 => ext a₁ b₁
+ rw [sum_sum_index, sum_sum_index] <;> congr; on_goal 1 => ext a₂ b₂
+ rw [sum_sum_index, sum_single_index] <;> congr; on_goal 1 => ext a₃ b₃
+ on_goal 1 => rw [sum_single_index, mul_assoc, add_assoc]
+ all_goals simp only [single_zero, single_add, forall_true_iff, add_mul,
+ mul_add, zero_mul, mul_zero, sum_zero, sum_add] }
+
+end Semigroup
+
+section MulOneClass
+
+variable [Semiring k] [AddZeroClass G]
+
+instance nonAssocSemiring : NonAssocSemiring k[G] :=
+ { AddMonoidAlgebra.nonUnitalNonAssocSemiring with
+ natCast := fun n => single 0 n
+ natCast_zero := by simp
+ natCast_succ := fun _ => by simp; rfl
+ one_mul := fun f => by
+ simp only [mul_def, one_def, sum_single_index, zero_mul, single_zero, sum_zero, zero_add,
+ one_mul, sum_single]
+ mul_one := fun f => by
+ simp only [mul_def, one_def, sum_single_index, mul_zero, single_zero, sum_zero, add_zero,
+ mul_one, sum_single] }
+
+theorem natCast_def (n : ℕ) : (n : k[G]) = single (0 : G) (n : k) :=
+ rfl
+
+@[deprecated (since := "2024-04-17")]
+alias nat_cast_def := natCast_def
+
+end MulOneClass
+
+/-! #### Semiring structure -/
+
+
+section Semiring
+
+instance smulZeroClass [Semiring k] [SMulZeroClass R k] : SMulZeroClass R k[G] :=
+ Finsupp.smulZeroClass
+
+variable [Semiring k] [AddMonoid G]
+
+instance semiring : Semiring k[G] :=
+ { AddMonoidAlgebra.nonUnitalSemiring,
+ AddMonoidAlgebra.nonAssocSemiring with }
+
+variable [Semiring R]
+
+/-- `liftNC` as a `RingHom`, for when `f` and `g` commute -/
+def liftNCRingHom (f : k →+* R) (g : Multiplicative G →* R) (h_comm : ∀ x y, Commute (f x) (g y)) :
+ k[G] →+* R :=
+ { liftNC (f : k →+ R) g with
+ map_one' := liftNC_one _ _
+ map_mul' := fun _a _b => liftNC_mul _ _ _ _ fun {_ _} _ => h_comm _ _ }
+
+end Semiring
+
+instance nonUnitalCommSemiring [CommSemiring k] [AddCommSemigroup G] :
+ NonUnitalCommSemiring k[G] :=
+ { AddMonoidAlgebra.nonUnitalSemiring with
+ mul_comm := @mul_comm (MonoidAlgebra k <| Multiplicative G) _ }
+
+instance nontrivial [Semiring k] [Nontrivial k] [Nonempty G] : Nontrivial k[G] :=
+ Finsupp.instNontrivial
+
+/-! #### Derived instances -/
+
+
+section DerivedInstances
+
+instance commSemiring [CommSemiring k] [AddCommMonoid G] : CommSemiring k[G] :=
+ { AddMonoidAlgebra.nonUnitalCommSemiring, AddMonoidAlgebra.semiring with }
+
+instance unique [Semiring k] [Subsingleton k] : Unique k[G] :=
+ Finsupp.uniqueOfRight
+
+instance addCommGroup [Ring k] : AddCommGroup k[G] :=
+ Finsupp.instAddCommGroup
+
+instance nonUnitalNonAssocRing [Ring k] [Add G] : NonUnitalNonAssocRing k[G] :=
+ { AddMonoidAlgebra.addCommGroup, AddMonoidAlgebra.nonUnitalNonAssocSemiring with }
+
+instance nonUnitalRing [Ring k] [AddSemigroup G] : NonUnitalRing k[G] :=
+ { AddMonoidAlgebra.addCommGroup, AddMonoidAlgebra.nonUnitalSemiring with }
+
+instance nonAssocRing [Ring k] [AddZeroClass G] : NonAssocRing k[G] :=
+ { AddMonoidAlgebra.addCommGroup,
+ AddMonoidAlgebra.nonAssocSemiring with
+ intCast := fun z => single 0 (z : k)
+ -- Porting note: Both were `simpa`.
+ intCast_ofNat := fun n => by simp; rfl
+ intCast_negSucc := fun n => by simp; rfl }
+
+theorem intCast_def [Ring k] [AddZeroClass G] (z : ℤ) :
+ (z : k[G]) = single (0 : G) (z : k) :=
+ rfl
+
+@[deprecated (since := "2024-04-17")]
+alias int_cast_def := intCast_def
+
+instance ring [Ring k] [AddMonoid G] : Ring k[G] :=
+ { AddMonoidAlgebra.nonAssocRing, AddMonoidAlgebra.semiring with }
+
+instance nonUnitalCommRing [CommRing k] [AddCommSemigroup G] :
+ NonUnitalCommRing k[G] :=
+ { AddMonoidAlgebra.nonUnitalCommSemiring, AddMonoidAlgebra.nonUnitalRing with }
+
+instance commRing [CommRing k] [AddCommMonoid G] : CommRing k[G] :=
+ { AddMonoidAlgebra.nonUnitalCommRing, AddMonoidAlgebra.ring with }
+
+variable {S : Type*}
+
+instance distribSMul [Semiring k] [DistribSMul R k] : DistribSMul R k[G] :=
+ Finsupp.distribSMul G k
+
+instance distribMulAction [Monoid R] [Semiring k] [DistribMulAction R k] :
+ DistribMulAction R k[G] :=
+ Finsupp.distribMulAction G k
+
+instance faithfulSMul [Semiring k] [SMulZeroClass R k] [FaithfulSMul R k] [Nonempty G] :
+ FaithfulSMul R k[G] :=
+ Finsupp.faithfulSMul
+
+instance module [Semiring R] [Semiring k] [Module R k] : Module R k[G] :=
+ Finsupp.module G k
+
+instance isScalarTower [Semiring k] [SMulZeroClass R k] [SMulZeroClass S k] [SMul R S]
+ [IsScalarTower R S k] : IsScalarTower R S k[G] :=
+ Finsupp.isScalarTower G k
+
+instance smulCommClass [Semiring k] [SMulZeroClass R k] [SMulZeroClass S k] [SMulCommClass R S k] :
+ SMulCommClass R S k[G] :=
+ Finsupp.smulCommClass G k
+
+instance isCentralScalar [Semiring k] [SMulZeroClass R k] [SMulZeroClass Rᵐᵒᵖ k]
+ [IsCentralScalar R k] : IsCentralScalar R k[G] :=
+ Finsupp.isCentralScalar G k
+
+/-! It is hard to state the equivalent of `DistribMulAction G k[G]`
+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]
+
+theorem mul_apply [DecidableEq G] [Add G] (f g : k[G]) (x : G) :
+ (f * g) x = f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => if a₁ + a₂ = x then b₁ * b₂ else 0 :=
+ @MonoidAlgebra.mul_apply k (Multiplicative G) _ _ _ _ _ _
+
+theorem mul_apply_antidiagonal [Add G] (f g : k[G]) (x : G) (s : Finset (G × G))
+ (hs : ∀ {p : G × G}, p ∈ s ↔ p.1 + p.2 = x) : (f * g) x = ∑ p ∈ s, f p.1 * g p.2 :=
+ @MonoidAlgebra.mul_apply_antidiagonal k (Multiplicative G) _ _ _ _ _ s @hs
+
+theorem single_mul_single [Add G] {a₁ a₂ : G} {b₁ b₂ : k} :
+ single a₁ b₁ * single a₂ b₂ = single (a₁ + a₂) (b₁ * b₂) :=
+ @MonoidAlgebra.single_mul_single k (Multiplicative G) _ _ _ _ _ _
+
+theorem single_commute_single [Add G] {a₁ a₂ : G} {b₁ b₂ : k}
+ (ha : AddCommute a₁ a₂) (hb : Commute b₁ b₂) :
+ Commute (single a₁ b₁) (single a₂ b₂) :=
+ @MonoidAlgebra.single_commute_single k (Multiplicative G) _ _ _ _ _ _ ha hb
+
+-- This should be a `@[simp]` lemma, but the simp_nf linter times out if we add this.
+-- Probably the correct fix is to make a `[Add]MonoidAlgebra.single` with the correct type,
+-- instead of relying on `Finsupp.single`.
+theorem single_pow [AddMonoid G] {a : G} {b : k} : ∀ n : ℕ, single a b ^ n = single (n • a) (b ^ n)
+ | 0 => by
+ simp only [pow_zero, zero_nsmul]
+ rfl
+ | n + 1 => by
+ rw [pow_succ, pow_succ, single_pow n, single_mul_single, add_nsmul, one_nsmul]
+
+/-- Like `Finsupp.mapDomain_zero`, but for the `1` we define in this file -/
+@[simp]
+theorem mapDomain_one {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Zero α] [Zero α₂]
+ {F : Type*} [FunLike F α α₂] [ZeroHomClass F α α₂] (f : F) :
+ (mapDomain f (1 : AddMonoidAlgebra β α) : AddMonoidAlgebra β α₂) =
+ (1 : AddMonoidAlgebra β α₂) := by
+ simp_rw [one_def, mapDomain_single, map_zero]
+
+/-- Like `Finsupp.mapDomain_add`, but for the convolutive multiplication we define in this file -/
+theorem mapDomain_mul {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Add α] [Add α₂]
+ {F : Type*} [FunLike F α α₂] [AddHomClass F α α₂] (f : F) (x y : AddMonoidAlgebra β α) :
+ mapDomain f (x * y) = mapDomain f x * mapDomain f y := by
+ simp_rw [mul_def, mapDomain_sum, mapDomain_single, map_add]
+ rw [Finsupp.sum_mapDomain_index]
+ · congr
+ ext a b
+ rw [Finsupp.sum_mapDomain_index]
+ · simp
+ · simp [mul_add]
+ · simp
+ · simp [add_mul]
+
+section
+
+variable (k G)
+
+/-- The embedding of an additive magma into its additive magma algebra. -/
+@[simps]
+def ofMagma [Add G] : Multiplicative G →ₙ* k[G] where
+ toFun a := single a 1
+ map_mul' a b := by simp only [mul_def, mul_one, sum_single_index, single_eq_zero, mul_zero]; rfl
+
+/-- Embedding of a magma with zero into its magma algebra. -/
+def of [AddZeroClass G] : Multiplicative G →* k[G] :=
+ { ofMagma k G with
+ toFun := fun a => single a 1
+ map_one' := rfl }
+
+/-- Embedding of a magma with zero `G`, into its magma algebra, having `G` as source. -/
+def of' : G → k[G] := fun a => single a 1
+
+end
+
+@[simp]
+theorem of_apply [AddZeroClass G] (a : Multiplicative G) :
+ of k G a = single (Multiplicative.toAdd a) 1 :=
+ rfl
+
+@[simp]
+theorem of'_apply (a : G) : of' k G a = single a 1 :=
+ rfl
+
+theorem of'_eq_of [AddZeroClass G] (a : G) : of' k G a = of k G (.ofAdd a) := rfl
+
+theorem of_injective [Nontrivial k] [AddZeroClass G] : Function.Injective (of k G) :=
+ MonoidAlgebra.of_injective
+
+theorem of'_commute [AddZeroClass G] {a : G} (h : ∀ a', AddCommute a a')
+ (f : AddMonoidAlgebra k G) :
+ Commute (of' k G a) f :=
+ MonoidAlgebra.of_commute (G := Multiplicative G) h f
+
+/-- `Finsupp.single` as a `MonoidHom` from the product type into the additive monoid algebra.
+
+Note the order of the elements of the product are reversed compared to the arguments of
+`Finsupp.single`.
+-/
+@[simps]
+def singleHom [AddZeroClass G] : k × Multiplicative G →* k[G] where
+ toFun a := single (Multiplicative.toAdd a.2) a.1
+ 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
+
+theorem mul_single_zero_apply [AddZeroClass G] (f : k[G]) (r : k) (x : G) :
+ (f * single (0 : G) r) x = f x * r :=
+ f.mul_single_apply_aux r _ _ _ fun a => by rw [add_zero]
+
+theorem mul_single_apply_of_not_exists_add [Add G] (r : k) {g g' : G} (x : k[G])
+ (h : ¬∃ d, g' = d + g) : (x * single g r) g' = 0 :=
+ @MonoidAlgebra.mul_single_apply_of_not_exists_mul k (Multiplicative G) _ _ _ _ _ _ h
+
+theorem single_mul_apply_aux [Add G] (f : k[G]) (r : k) (x y z : G)
+ (H : ∀ a, x + a = y ↔ a = z) : (single x r * f) y = r * f z :=
+ @MonoidAlgebra.single_mul_apply_aux k (Multiplicative G) _ _ _ _ _ _ _ H
+
+theorem single_zero_mul_apply [AddZeroClass G] (f : k[G]) (r : k) (x : G) :
+ (single (0 : G) r * f) x = r * f x :=
+ f.single_mul_apply_aux r _ _ _ fun a => by rw [zero_add]
+
+theorem single_mul_apply_of_not_exists_add [Add G] (r : k) {g g' : G} (x : k[G])
+ (h : ¬∃ d, g' = g + d) : (single g r * x) g' = 0 :=
+ @MonoidAlgebra.single_mul_apply_of_not_exists_mul k (Multiplicative G) _ _ _ _ _ _ h
+
+theorem mul_single_apply [AddGroup G] (f : k[G]) (r : k) (x y : G) :
+ (f * single x r) y = f (y - x) * r :=
+ (sub_eq_add_neg y x).symm ▸ @MonoidAlgebra.mul_single_apply k (Multiplicative G) _ _ _ _ _ _
+
+theorem single_mul_apply [AddGroup G] (r : k) (x : G) (f : k[G]) (y : G) :
+ (single x r * f) y = r * f (-x + y) :=
+ @MonoidAlgebra.single_mul_apply k (Multiplicative G) _ _ _ _ _ _
+
+theorem liftNC_smul {R : Type*} [AddZeroClass G] [Semiring R] (f : k →+* R)
+ (g : Multiplicative G →* R) (c : k) (φ : MonoidAlgebra k G) :
+ liftNC (f : k →+ R) g (c • φ) = f c * liftNC (f : k →+ R) g φ :=
+ @MonoidAlgebra.liftNC_smul k (Multiplicative G) _ _ _ _ f g c φ
+
+theorem induction_on [AddMonoid G] {p : k[G] → Prop} (f : k[G])
+ (hM : ∀ g, p (of k G (Multiplicative.ofAdd g)))
+ (hadd : ∀ f g : k[G], p f → p g → p (f + g))
+ (hsmul : ∀ (r : k) (f), p f → p (r • f)) : p f := by
+ 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)
+ 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. -/
+@[simps]
+def mapDomainRingHom (k : Type*) [Semiring k] {H F : Type*} [AddMonoid G] [AddMonoid H]
+ [FunLike F G H] [AddMonoidHomClass F G H] (f : F) : k[G] →+* k[H] :=
+ { (Finsupp.mapDomain.addMonoidHom f : MonoidAlgebra k G →+ MonoidAlgebra k H) with
+ map_one' := mapDomain_one f
+ map_mul' := fun x y => mapDomain_mul f x y }
+
+end MiscTheorems
+
+end AddMonoidAlgebra
+
+/-!
+#### Conversions between `AddMonoidAlgebra` and `MonoidAlgebra`
+
+We have not defined `k[G] = MonoidAlgebra k (Multiplicative G)`
+because historically this caused problems;
+since the changes that have made `nsmul` definitional, this would be possible,
+but for now we just construct the ring isomorphisms using `RingEquiv.refl _`.
+-/
+
+
+/-- The equivalence between `AddMonoidAlgebra` and `MonoidAlgebra` in terms of
+`Multiplicative` -/
+protected def AddMonoidAlgebra.toMultiplicative [Semiring k] [Add G] :
+ AddMonoidAlgebra k G ≃+* MonoidAlgebra k (Multiplicative G) :=
+ { Finsupp.domCongr
+ Multiplicative.ofAdd with
+ toFun := equivMapDomain Multiplicative.ofAdd
+ map_mul' := fun x y => by
+ -- Porting note: added `dsimp only`; `beta_reduce` alone is not sufficient
+ dsimp only
+ repeat' rw [equivMapDomain_eq_mapDomain (M := k)]
+ dsimp [Multiplicative.ofAdd]
+ exact MonoidAlgebra.mapDomain_mul (α := Multiplicative G) (β := k)
+ (MulHom.id (Multiplicative G)) x y }
+
+/-- The equivalence between `MonoidAlgebra` and `AddMonoidAlgebra` in terms of `Additive` -/
+protected def MonoidAlgebra.toAdditive [Semiring k] [Mul G] :
+ MonoidAlgebra k G ≃+* AddMonoidAlgebra k (Additive G) :=
+ { Finsupp.domCongr Additive.ofMul with
+ toFun := equivMapDomain Additive.ofMul
+ map_mul' := fun x y => by
+ -- Porting note: added `dsimp only`; `beta_reduce` alone is not sufficient
+ dsimp only
+ repeat' rw [equivMapDomain_eq_mapDomain (M := k)]
+ dsimp [Additive.ofMul]
+ convert MonoidAlgebra.mapDomain_mul (β := k) (MulHom.id G) x y }
+
+namespace AddMonoidAlgebra
+
+variable {k G H}
+
+/-! #### Non-unital, non-associative algebra structure -/
+
+
+section NonUnitalNonAssocAlgebra
+
+variable (k) [Semiring k] [DistribSMul R k] [Add G]
+
+instance isScalarTower_self [IsScalarTower R k k] :
+ IsScalarTower R k[G] k[G] :=
+ @MonoidAlgebra.isScalarTower_self k (Multiplicative G) R _ _ _ _
+
+/-- 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 k[G] k[G] :=
+ @MonoidAlgebra.smulCommClass_self k (Multiplicative G) R _ _ _ _
+
+instance smulCommClass_symm_self [SMulCommClass k R k] :
+ SMulCommClass k[G] R k[G] :=
+ @MonoidAlgebra.smulCommClass_symm_self k (Multiplicative G) R _ _ _ _
+
+end NonUnitalNonAssocAlgebra
+
+/-! #### Algebra structure -/
+
+
+section Algebra
+
+-- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
+
+/-- `Finsupp.single 0` as a `RingHom` -/
+@[simps]
+def singleZeroRingHom [Semiring k] [AddMonoid G] : k →+* k[G] :=
+ { Finsupp.singleAddHom 0 with
+ map_one' := rfl
+ 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. -/
+theorem ringHom_ext {R} [Semiring k] [AddMonoid G] [Semiring R] {f g : k[G] →+* R}
+ (h₀ : ∀ b, f (single 0 b) = g (single 0 b)) (h_of : ∀ a, f (single a 1) = g (single a 1)) :
+ f = g :=
+ @MonoidAlgebra.ringHom_ext k (Multiplicative G) R _ _ _ _ _ h₀ h_of
+
+/-- If two ring homomorphisms from `k[G]` are equal on all `single a 1`
+and `single 0 b`, then they are equal.
+
+See note [partially-applied ext lemmas]. -/
+@[ext high]
+theorem ringHom_ext' {R} [Semiring k] [AddMonoid G] [Semiring R] {f g : k[G] →+* R}
+ (h₁ : f.comp singleZeroRingHom = g.comp singleZeroRingHom)
+ (h_of : (f : k[G] →* R).comp (of k G) = (g : k[G] →* R).comp (of k G)) :
+ f = g :=
+ ringHom_ext (RingHom.congr_fun h₁) (DFunLike.congr_fun h_of)
+
+section Opposite
+
+open Finsupp MulOpposite
+
+variable [Semiring k]
+
+/-- The opposite of an `R[I]` is ring equivalent to
+the `AddMonoidAlgebra Rᵐᵒᵖ I` over the opposite ring, taking elements to their opposite. -/
+@[simps! (config := { simpRhs := true }) apply symm_apply]
+protected noncomputable def opRingEquiv [AddCommMonoid G] :
+ k[G]ᵐᵒᵖ ≃+* kᵐᵒᵖ[G] :=
+ { MulOpposite.opAddEquiv.symm.trans
+ (Finsupp.mapRange.addEquiv (MulOpposite.opAddEquiv : k ≃+ kᵐᵒᵖ)) with
+ map_mul' := by
+ -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
+ 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 (#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.
+ dsimp
+ -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
+ erw [AddEquiv.trans_apply, AddEquiv.trans_apply, AddEquiv.trans_apply,
+ MulOpposite.opAddEquiv_symm_apply]; rw [MulOpposite.unop_mul (α := k[G])]
+ dsimp
+ 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.
+-- 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
+
+theorem opRingEquiv_symm_single [AddCommMonoid G] (r : kᵐᵒᵖ) (x : Gᵐᵒᵖ) :
+ AddMonoidAlgebra.opRingEquiv.symm (single x r) = op (single x r.unop) := by simp
+
+end Opposite
+
+end Algebra
+
+section
+
+-- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`.
+
+universe ui
+
+variable {ι : Type ui}
+
+theorem prod_single [CommSemiring k] [AddCommMonoid G] {s : Finset ι} {a : ι → G} {b : ι → k} :
+ (∏ i ∈ s, single (a i) (b i)) = single (∑ i ∈ s, a i) (∏ i ∈ s, b i) :=
+ Finset.cons_induction_on s rfl fun a s has ih => by
+ rw [prod_cons has, ih, single_mul_single, sum_cons has, prod_cons has]
+
+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 b9e13bd2bac92..6ed612e48a0a5 100644
--- a/Mathlib/Algebra/MonoidAlgebra/Division.lean
+++ b/Mathlib/Algebra/MonoidAlgebra/Division.lean
@@ -3,7 +3,7 @@ Copyright (c) 2022 Eric Wieser. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Eric Wieser
-/
-import Mathlib.Algebra.MonoidAlgebra.Basic
+import Mathlib.Algebra.MonoidAlgebra.Defs
/-!
# Division of `AddMonoidAlgebra` by monomials
@@ -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 6c9381050ab49..86426ba1b8376 100644
--- a/Mathlib/Algebra/MonoidAlgebra/Grading.lean
+++ b/Mathlib/Algebra/MonoidAlgebra/Grading.lean
@@ -7,6 +7,7 @@ import Mathlib.LinearAlgebra.Finsupp
import Mathlib.Algebra.MonoidAlgebra.Support
import Mathlib.Algebra.DirectSum.Internal
import Mathlib.RingTheory.GradedAlgebra.Basic
+import Mathlib.Algebra.MonoidAlgebra.Basic
/-!
# Internal grading of an `AddMonoidAlgebra`
@@ -47,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] :=
@@ -131,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 17cab16c6913a..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.Algebra.MonoidAlgebra.Basic
-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/NoZeroDivisors.lean b/Mathlib/Algebra/MonoidAlgebra/NoZeroDivisors.lean
index 4a9ee99e15904..897769a72110a 100644
--- a/Mathlib/Algebra/MonoidAlgebra/NoZeroDivisors.lean
+++ b/Mathlib/Algebra/MonoidAlgebra/NoZeroDivisors.lean
@@ -3,8 +3,8 @@ 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.MonoidAlgebra.Basic
import Mathlib.Algebra.Group.UniqueProds.Basic
+import Mathlib.Algebra.MonoidAlgebra.Defs
/-!
# Variations on non-zero divisors in `AddMonoidAlgebra`s
diff --git a/Mathlib/Algebra/MonoidAlgebra/Support.lean b/Mathlib/Algebra/MonoidAlgebra/Support.lean
index 18069fab871f8..cfd6eaba70024 100644
--- a/Mathlib/Algebra/MonoidAlgebra/Support.lean
+++ b/Mathlib/Algebra/MonoidAlgebra/Support.lean
@@ -3,8 +3,8 @@ 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.MonoidAlgebra.Basic
-import Mathlib.Data.Finset.Pointwise.Basic
+import Mathlib.Algebra.MonoidAlgebra.Defs
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
/-!
# Lemmas about the support of a finitely supported function
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 db1846108e926..93c6613dfbc95 100644
--- a/Mathlib/Algebra/MvPolynomial/Basic.lean
+++ b/Mathlib/Algebra/MvPolynomial/Basic.lean
@@ -10,6 +10,7 @@ import Mathlib.Algebra.MonoidAlgebra.Support
import Mathlib.Data.Finsupp.Antidiagonal
import Mathlib.Order.SymmDiff
import Mathlib.RingTheory.Adjoin.Basic
+import Mathlib.Algebra.MonoidAlgebra.Basic
/-!
# Multivariate polynomials
@@ -154,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
@@ -190,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
@@ -202,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 _ _ _
@@ -302,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 _
@@ -372,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))
@@ -403,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 _
@@ -508,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
@@ -690,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
@@ -1356,6 +1355,11 @@ theorem comp_aeval {B : Type*} [CommSemiring B] [Algebra R B] (φ : S₁ →ₐ[
ext i
simp
+lemma comp_aeval_apply {B : Type*} [CommSemiring B] [Algebra R B] (φ : S₁ →ₐ[R] B)
+ (p : MvPolynomial σ R) :
+ φ (aeval f p) = aeval (fun i ↦ φ (f i)) p := by
+ rw [← comp_aeval, AlgHom.coe_comp, comp_apply]
+
@[simp]
theorem map_aeval {B : Type*} [CommSemiring B] (g : σ → S₁) (φ : S₁ →+* B) (p : MvPolynomial σ R) :
φ (aeval g p) = eval₂Hom (φ.comp (algebraMap R S₁)) (fun i => φ (g i)) p := by
@@ -1536,6 +1540,17 @@ theorem eval_mem {p : MvPolynomial σ S} {s : subS} (hs : ∀ i ∈ p.support, p
end EvalMem
+variable {S T : Type*} [CommSemiring S] [Algebra R S] [CommSemiring T] [Algebra R T] [Algebra S T]
+ [IsScalarTower R S T]
+
+lemma aeval_sum_elim {σ τ : Type*} (p : MvPolynomial (σ ⊕ τ) R) (f : τ → S) (g : σ → T) :
+ (aeval (Sum.elim g (algebraMap S T ∘ f))) p =
+ (aeval g) ((aeval (Sum.elim X (C ∘ f))) p) := by
+ induction' p using MvPolynomial.induction_on with r p q hp hq p i h
+ · simp [← IsScalarTower.algebraMap_apply]
+ · simp [hp, hq]
+ · cases i <;> simp [h]
+
end CommSemiring
end MvPolynomial
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/Division.lean b/Mathlib/Algebra/MvPolynomial/Division.lean
index 73946aa78f7a6..7d505e900d7d2 100644
--- a/Mathlib/Algebra/MvPolynomial/Division.lean
+++ b/Mathlib/Algebra/MvPolynomial/Division.lean
@@ -206,7 +206,7 @@ theorem monomial_dvd_monomial {r s : R} {i j : σ →₀ ℕ} :
theorem monomial_one_dvd_monomial_one [Nontrivial R] {i j : σ →₀ ℕ} :
monomial i (1 : R) ∣ monomial j 1 ↔ i ≤ j := by
rw [monomial_dvd_monomial]
- simp_rw [one_ne_zero, false_or_iff, dvd_rfl, and_true_iff]
+ simp_rw [one_ne_zero, false_or, dvd_rfl, and_true]
@[simp]
theorem X_dvd_X [Nontrivial R] {i j : σ} :
@@ -219,6 +219,6 @@ theorem X_dvd_X [Nontrivial R] {i j : σ} :
theorem X_dvd_monomial {i : σ} {j : σ →₀ ℕ} {r : R} :
(X i : MvPolynomial σ R) ∣ monomial j r ↔ r = 0 ∨ j i ≠ 0 := by
refine monomial_dvd_monomial.trans ?_
- simp_rw [one_dvd, and_true_iff, Finsupp.single_le_iff, Nat.one_le_iff_ne_zero]
+ simp_rw [one_dvd, and_true, Finsupp.single_le_iff, Nat.one_le_iff_ne_zero]
end MvPolynomial
diff --git a/Mathlib/Algebra/MvPolynomial/Equiv.lean b/Mathlib/Algebra/MvPolynomial/Equiv.lean
index a6350e2e62a69..6b59003105ae6 100644
--- a/Mathlib/Algebra/MvPolynomial/Equiv.lean
+++ b/Mathlib/Algebra/MvPolynomial/Equiv.lean
@@ -196,6 +196,17 @@ def isEmptyAlgEquiv [he : IsEmpty σ] : MvPolynomial σ R ≃ₐ[R] R :=
ext i m
exact IsEmpty.elim' he i)
+variable {R S₁ σ} in
+@[simp]
+lemma aeval_injective_iff_of_isEmpty [IsEmpty σ] [CommSemiring S₁] [Algebra R S₁] {f : σ → S₁} :
+ Function.Injective (aeval f : MvPolynomial σ R →ₐ[R] S₁) ↔
+ Function.Injective (algebraMap R S₁) := by
+ have : aeval f = (Algebra.ofId R S₁).comp (@isEmptyAlgEquiv R σ _ _).toAlgHom := by
+ ext i
+ exact IsEmpty.elim' ‹IsEmpty σ› i
+ rw [this, ← Injective.of_comp_iff' _ (@isEmptyAlgEquiv R σ _ _).bijective]
+ rfl
+
/-- The ring isomorphism between multivariable polynomials in no variables
and the ground ring. -/
@[simps!]
@@ -244,6 +255,18 @@ def sumAlgEquiv : MvPolynomial (S₁ ⊕ S₂) R ≃ₐ[R] MvPolynomial S₁ (Mv
simp only [sumRingEquiv, mvPolynomialEquivMvPolynomial, Equiv.toFun_as_coe,
Equiv.coe_fn_mk, B, sumToIter_C, A] }
+lemma sumAlgEquiv_comp_rename_inr :
+ (sumAlgEquiv R S₁ S₂).toAlgHom.comp (rename Sum.inr) = IsScalarTower.toAlgHom R
+ (MvPolynomial S₂ R) (MvPolynomial S₁ (MvPolynomial S₂ R)) := by
+ ext i
+ simp
+
+lemma sumAlgEquiv_comp_rename_inl :
+ (sumAlgEquiv R S₁ S₂).toAlgHom.comp (rename Sum.inl) =
+ MvPolynomial.mapAlgHom (Algebra.ofId _ _) := by
+ ext i
+ simp
+
section
-- this speeds up typeclass search in the lemma below
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 a4755788c2c2a..9c6e2c3c43e7c 100644
--- a/Mathlib/Algebra/MvPolynomial/PDeriv.lean
+++ b/Mathlib/Algebra/MvPolynomial/PDeriv.lean
@@ -65,12 +65,12 @@ theorem pderiv_def [DecidableEq σ] (i : σ) : pderiv i = mkDerivation R (Pi.sin
theorem pderiv_monomial {i : σ} :
pderiv i (monomial s a) = monomial (s - single i 1) (a * s i) := by
classical
- simp only [pderiv_def, mkDerivation_monomial, Finsupp.smul_sum, smul_eq_mul, ← smul_mul_assoc,
- ← (monomial _).map_smul]
- refine (Finset.sum_eq_single i (fun j _ hne => ?_) fun hi => ?_).trans ?_
- · simp [Pi.single_eq_of_ne hne]
- · rw [Finsupp.not_mem_support_iff] at hi; simp [hi]
- · simp
+ simp only [pderiv_def, mkDerivation_monomial, Finsupp.smul_sum, smul_eq_mul, ← smul_mul_assoc,
+ ← (monomial _).map_smul]
+ refine (Finset.sum_eq_single i (fun j _ hne => ?_) fun hi => ?_).trans ?_
+ · simp [Pi.single_eq_of_ne hne]
+ · rw [Finsupp.not_mem_support_iff] at hi; simp [hi]
+ · simp
theorem pderiv_C {i : σ} : pderiv i (C a) = 0 :=
derivation_C _ _
@@ -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']
@@ -115,6 +114,28 @@ theorem pderiv_map {S} [CommSemiring S] {φ : R →+* S} {f : MvPolynomial σ R}
· simp [eq]
· simp [eq, h]
+lemma pderiv_rename {τ : Type*} {f : σ → τ} (hf : Function.Injective f)
+ (x : σ) (p : MvPolynomial σ R) :
+ pderiv (f x) (rename f p) = rename f (pderiv x p) := by
+ classical
+ induction' p using MvPolynomial.induction_on with a p q hp hq p a h
+ · simp
+ · simp [hp, hq]
+ · simp only [map_mul, MvPolynomial.rename_X, Derivation.leibniz, MvPolynomial.pderiv_X,
+ Pi.single_apply, hf.eq_iff, smul_eq_mul, mul_ite, mul_one, mul_zero, h, map_add, add_left_inj]
+ split_ifs <;> simp
+
+lemma aeval_sum_elim_pderiv_inl {S τ : Type*} [CommRing S] [Algebra R S]
+ (p : MvPolynomial (σ ⊕ τ) R) (f : τ → S) (j : σ) :
+ aeval (Sum.elim X (C ∘ f)) ((pderiv (Sum.inl j)) p) =
+ (pderiv j) ((aeval (Sum.elim X (C ∘ f))) p) := by
+ classical
+ induction' p using MvPolynomial.induction_on with a p q hp hq p q h
+ · simp
+ · simp [hp, hq]
+ · simp only [Derivation.leibniz, pderiv_X, smul_eq_mul, map_add, map_mul, aeval_X, h]
+ cases q <;> simp [Pi.single_apply]
+
end PDeriv
end MvPolynomial
diff --git a/Mathlib/Algebra/MvPolynomial/Polynomial.lean b/Mathlib/Algebra/MvPolynomial/Polynomial.lean
index f04fac634e9f1..529c8a050c772 100644
--- a/Mathlib/Algebra/MvPolynomial/Polynomial.lean
+++ b/Mathlib/Algebra/MvPolynomial/Polynomial.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.MvPolynomial.Equiv
import Mathlib.Algebra.Polynomial.Eval
diff --git a/Mathlib/Algebra/MvPolynomial/Rename.lean b/Mathlib/Algebra/MvPolynomial/Rename.lean
index eda39a1e51a4b..48bfa47e642c2 100644
--- a/Mathlib/Algebra/MvPolynomial/Rename.lean
+++ b/Mathlib/Algebra/MvPolynomial/Rename.lean
@@ -206,15 +206,14 @@ theorem exists_finset_rename (p : MvPolynomial σ R) :
· rintro p q ⟨s, p, rfl⟩ ⟨t, q, rfl⟩
refine ⟨s ∪ t, ⟨?_, ?_⟩⟩
· refine rename (Subtype.map id ?_) p + rename (Subtype.map id ?_) q <;>
- simp (config := { contextual := true }) only [id, true_or_iff, or_true_iff,
+ simp (config := { contextual := true }) only [id, true_or, or_true,
Finset.mem_union, forall_true_iff]
· simp only [rename_rename, map_add]
rfl
· rintro p n ⟨s, p, rfl⟩
refine ⟨insert n s, ⟨?_, ?_⟩⟩
· refine rename (Subtype.map id ?_) p * X ⟨n, s.mem_insert_self n⟩
- simp (config := { contextual := true }) only [id, or_true_iff, Finset.mem_insert,
- forall_true_iff]
+ simp (config := { contextual := true }) only [id, or_true, Finset.mem_insert, forall_true_iff]
· simp only [rename_rename, rename_X, Subtype.coe_mk, map_mul]
rfl
diff --git a/Mathlib/Algebra/MvPolynomial/Variables.lean b/Mathlib/Algebra/MvPolynomial/Variables.lean
index 7f43b2f3d2866..730a6443dcfec 100644
--- a/Mathlib/Algebra/MvPolynomial/Variables.lean
+++ b/Mathlib/Algebra/MvPolynomial/Variables.lean
@@ -149,7 +149,7 @@ theorem vars_C_mul (a : A) (ha : a ≠ 0) (φ : MvPolynomial σ A) :
apply exists_congr
intro d
apply and_congr _ Iff.rfl
- rw [coeff_C_mul, mul_ne_zero_iff, eq_true ha, true_and_iff]
+ rw [coeff_C_mul, mul_ne_zero_iff, eq_true ha, true_and]
end IsDomain
diff --git a/Mathlib/Algebra/NeZero.lean b/Mathlib/Algebra/NeZero.lean
index aaa15d8a6209e..3fdf3e370cb38 100644
--- a/Mathlib/Algebra/NeZero.lean
+++ b/Mathlib/Algebra/NeZero.lean
@@ -10,32 +10,12 @@ import Mathlib.Order.Defs
/-!
# `NeZero` typeclass
-We create a typeclass `NeZero n` which carries around the fact that `(n : R) ≠ 0`.
+We give basic facts about the `NeZero n` typeclass.
-## Main declarations
-
-* `NeZero`: `n ≠ 0` as a typeclass.
-/
variable {R : Type*} [Zero R]
-/-- A type-class version of `n ≠ 0`. -/
-class NeZero (n : R) : Prop where
- /-- The proposition that `n` is not zero. -/
- out : n ≠ 0
-
-theorem NeZero.ne (n : R) [h : NeZero n] : n ≠ 0 :=
- h.out
-
-theorem NeZero.ne' (n : R) [h : NeZero n] : 0 ≠ n :=
- h.out.symm
-
-theorem neZero_iff {n : R} : NeZero n ↔ n ≠ 0 :=
- ⟨fun h ↦ h.out, NeZero.mk⟩
-
-@[simp] lemma neZero_zero_iff_false {α : Type*} [Zero α] : NeZero (0 : α) ↔ False :=
- ⟨fun h ↦ h.ne rfl, fun h ↦ h.elim⟩
-
theorem not_neZero {n : R} : ¬NeZero n ↔ n = 0 := by simp [neZero_iff]
theorem eq_zero_or_neZero (a : R) : a = 0 ∨ NeZero a :=
@@ -77,10 +57,6 @@ namespace NeZero
variable {M : Type*} {x : M}
-instance succ {n : ℕ} : NeZero (n + 1) := ⟨n.succ_ne_zero⟩
-
theorem of_pos [Preorder M] [Zero M] (h : 0 < x) : NeZero x := ⟨ne_of_gt h⟩
end NeZero
-
-lemma Nat.pos_of_neZero (n : ℕ) [NeZero n] : 0 < n := Nat.pos_of_ne_zero (NeZero.ne _)
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/Algebra.lean b/Mathlib/Algebra/Order/Algebra.lean
index 675c50fd0e04d..dc583079f431f 100644
--- a/Mathlib/Algebra/Order/Algebra.lean
+++ b/Mathlib/Algebra/Order/Algebra.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Algebra.Defs
import Mathlib.Algebra.Order.Module.OrderedSMul
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 92206333ffa94..e61fa45890bab 100644
--- a/Mathlib/Algebra/Order/Antidiag/Pi.lean
+++ b/Mathlib/Algebra/Order/Antidiag/Pi.lean
@@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Antoine Chambert-Loir, María Inés de Frutos-Fernández, Eric Wieser, Bhavik Mehta,
Yaël Dillies
-/
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
import Mathlib.Algebra.Order.BigOperators.Group.Finset
-import Mathlib.Data.Finset.Pointwise.Basic
import Mathlib.Data.Fin.Tuple.NatAntidiagonal
/-!
@@ -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 c0968b4ac7e37..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⟩
@@ -223,7 +223,7 @@ variable [LinearOrderedSemifield α] [Archimedean α] {x y ε : α}
lemma exists_nat_one_div_lt (hε : 0 < ε) : ∃ n : ℕ, 1 / (n + 1 : α) < ε := by
cases' exists_nat_gt (1 / ε) with n hn
use n
- rw [div_lt_iff, ← div_lt_iff' hε]
+ rw [div_lt_iff₀, ← div_lt_iff₀' hε]
· apply hn.trans
simp [zero_lt_one]
· exact n.cast_add_one_pos
@@ -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
@@ -299,11 +299,11 @@ theorem exists_rat_btwn {x y : α} (h : x < y) : ∃ q : ℚ, x < q ∧ (q : α)
refine ⟨(z + 1 : ℤ) / n, ?_⟩
have n0' := (inv_pos.2 (sub_pos.2 h)).trans nh
have n0 := Nat.cast_pos.1 n0'
- rw [Rat.cast_div_of_ne_zero, Rat.cast_natCast, Rat.cast_intCast, div_lt_iff n0']
- · refine ⟨(lt_div_iff n0').2 <| (lt_iff_lt_of_le_iff_le (zh _)).1 (lt_add_one _), ?_⟩
+ rw [Rat.cast_div_of_ne_zero, Rat.cast_natCast, Rat.cast_intCast, div_lt_iff₀ n0']
+ · refine ⟨(lt_div_iff₀ n0').2 <| (lt_iff_lt_of_le_iff_le (zh _)).1 (lt_add_one _), ?_⟩
rw [Int.cast_add, Int.cast_one]
refine lt_of_le_of_lt (add_le_add_right ((zh _).1 le_rfl) _) ?_
- rwa [← lt_sub_iff_add_lt', ← sub_mul, ← div_lt_iff' (sub_pos.2 h), one_div]
+ rwa [← lt_sub_iff_add_lt', ← sub_mul, ← div_lt_iff₀' (sub_pos.2 h), one_div]
· rw [Rat.den_intCast, Nat.cast_one]
exact one_ne_zero
· intro H
@@ -352,7 +352,7 @@ variable [LinearOrderedField α]
theorem archimedean_iff_nat_lt : Archimedean α ↔ ∀ x : α, ∃ n : ℕ, x < n :=
⟨@exists_nat_gt α _, fun H =>
⟨fun x y y0 =>
- (H (x / y)).imp fun n h => le_of_lt <| by rwa [div_lt_iff y0, ← nsmul_eq_mul] at h⟩⟩
+ (H (x / y)).imp fun n h => le_of_lt <| by rwa [div_lt_iff₀ y0, ← nsmul_eq_mul] at h⟩⟩
theorem archimedean_iff_nat_le : Archimedean α ↔ ∀ x : α, ∃ n : ℕ, x ≤ n :=
archimedean_iff_nat_lt.trans
@@ -427,3 +427,8 @@ instance (priority := 100) FloorRing.archimedean (α) [LinearOrderedField α] [F
Archimedean α := by
rw [archimedean_iff_int_le]
exact fun x => ⟨⌈x⌉, Int.le_ceil x⟩
+
+@[to_additive]
+instance Units.instMulArchimedean (α) [OrderedCommMonoid α] [MulArchimedean α] :
+ MulArchimedean αˣ :=
+ ⟨fun x {_} h ↦ MulArchimedean.arch x.val h⟩
diff --git a/Mathlib/Algebra/Order/Archimedean/Submonoid.lean b/Mathlib/Algebra/Order/Archimedean/Submonoid.lean
new file mode 100644
index 0000000000000..fccc02aa01ab0
--- /dev/null
+++ b/Mathlib/Algebra/Order/Archimedean/Submonoid.lean
@@ -0,0 +1,31 @@
+/-
+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.Archimedean.Basic
+import Mathlib.Algebra.Order.Monoid.Submonoid
+
+/-!
+# Submonoids of archimedean monoids
+
+This file defines the instances that show that the (mul)archimedean property is retained in a
+submonoid of the ambient group.
+
+## Main statements
+
+* `SubmonoidClass.instMulArchimedean`: the submonoid (and similar subobjects) of a mul-archimedean
+ group retains the mul-archimedean property when restricted to the submonoid.
+* `AddSubmonoidClass.instArchimedean`: the additive submonoid (and similar subobjects) of an
+ archimedean additive group retains the archimedean property when restricted to the additive
+ submonoid.
+-/
+
+@[to_additive]
+instance SubmonoidClass.instMulArchimedean {M S : Type*} [SetLike S M] [OrderedCommMonoid M]
+ [SubmonoidClass S M] [MulArchimedean M] (H : S) : MulArchimedean H := by
+ constructor
+ rintro x _
+ simp only [← Subtype.coe_lt_coe, OneMemClass.coe_one, SubmonoidClass.mk_pow, Subtype.mk_le_mk]
+ exact MulArchimedean.arch x.val
diff --git a/Mathlib/Algebra/Order/BigOperators/Expect.lean b/Mathlib/Algebra/Order/BigOperators/Expect.lean
new file mode 100644
index 0000000000000..a449b9ce36435
--- /dev/null
+++ b/Mathlib/Algebra/Order/BigOperators/Expect.lean
@@ -0,0 +1,210 @@
+/-
+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.BigOperators.Expect
+import Mathlib.Algebra.Module.Rat
+import Mathlib.Algebra.Order.BigOperators.Ring.Finset
+import Mathlib.Algebra.Order.Module.Rat
+
+/-!
+# Order properties of the average over a finset
+-/
+
+open Function
+open Fintype (card)
+open scoped BigOperators Pointwise NNRat
+
+variable {ι κ α β R : Type*}
+
+local notation a " /ℚ " q => (q : ℚ≥0)⁻¹ • a
+
+namespace Finset
+section OrderedAddCommMonoid
+variable [OrderedAddCommMonoid α] [Module ℚ≥0 α] [OrderedAddCommMonoid β] [Module ℚ≥0 β]
+ {s : Finset ι} {f g : ι → α}
+
+lemma expect_eq_zero_iff_of_nonneg (hs : s.Nonempty) (hf : ∀ i ∈ s, 0 ≤ f i) :
+ 𝔼 i ∈ s, f i = 0 ↔ ∀ i ∈ s, f i = 0 := by
+ simp [expect, sum_eq_zero_iff_of_nonneg hf, hs.ne_empty]
+
+lemma expect_eq_zero_iff_of_nonpos (hs : s.Nonempty) (hf : ∀ i ∈ s, f i ≤ 0) :
+ 𝔼 i ∈ s, f i = 0 ↔ ∀ i ∈ s, f i = 0 := by
+ simp [expect, sum_eq_zero_iff_of_nonpos hf, hs.ne_empty]
+
+section PosSMulMono
+variable [PosSMulMono ℚ≥0 α] {a : α}
+
+lemma expect_le_expect (hfg : ∀ i ∈ s, f i ≤ g i) : 𝔼 i ∈ s, f i ≤ 𝔼 i ∈ s, g i :=
+ smul_le_smul_of_nonneg_left (sum_le_sum hfg) <| by positivity
+
+/-- This is a (beta-reduced) version of the standard lemma `Finset.expect_le_expect`,
+convenient for the `gcongr` tactic. -/
+@[gcongr]
+lemma _root_.GCongr.expect_le_expect (h : ∀ i ∈ s, f i ≤ g i) : s.expect f ≤ s.expect g :=
+ Finset.expect_le_expect h
+
+lemma expect_le (hs : s.Nonempty) (h : ∀ x ∈ s, f x ≤ a) : 𝔼 i ∈ s, f i ≤ a :=
+ (inv_smul_le_iff_of_pos <| mod_cast hs.card_pos).2 <| by
+ rw [Nat.cast_smul_eq_nsmul]; exact sum_le_card_nsmul _ _ _ h
+
+lemma le_expect (hs : s.Nonempty) (h : ∀ x ∈ s, a ≤ f x) : a ≤ 𝔼 i ∈ s, f i :=
+ (le_inv_smul_iff_of_pos <| mod_cast hs.card_pos).2 <| by
+ rw [Nat.cast_smul_eq_nsmul]; exact card_nsmul_le_sum _ _ _ h
+
+lemma expect_nonneg (hf : ∀ i ∈ s, 0 ≤ f i) : 0 ≤ 𝔼 i ∈ s, f i :=
+ smul_nonneg (by positivity) <| sum_nonneg hf
+
+end PosSMulMono
+
+section PosSMulMono
+variable {M N : Type*} [AddCommMonoid M] [Module ℚ≥0 M] [OrderedAddCommMonoid N] [Module ℚ≥0 N]
+ [PosSMulMono ℚ≥0 N] {m : M → N} {p : M → Prop} {f : ι → M} {s : Finset ι}
+
+/-- Let `{a | p a}` be an additive subsemigroup of an additive commutative monoid `M`. If `m` is a
+subadditive function (`m (a + b) ≤ m a + m b`) preserved under division by a natural, `f` is a
+function valued in that subsemigroup and `s` is a nonempty set, then
+`m (𝔼 i ∈ s, f i) ≤ 𝔼 i ∈ s, m (f i)`. -/
+lemma le_expect_nonempty_of_subadditive_on_pred (h_add : ∀ a b, p a → p b → m (a + b) ≤ m a + m b)
+ (hp_add : ∀ a b, p a → p b → p (a + b)) (h_div : ∀ (n : ℕ) a, p a → m (a /ℚ n) = m a /ℚ n)
+ (hs_nonempty : s.Nonempty) (hs : ∀ i ∈ s, p (f i)) :
+ m (𝔼 i ∈ s, f i) ≤ 𝔼 i ∈ s, m (f i) := by
+ simp only [expect, h_div _ _ (sum_induction_nonempty _ _ hp_add hs_nonempty hs)]
+ exact smul_le_smul_of_nonneg_left
+ (le_sum_nonempty_of_subadditive_on_pred _ _ h_add hp_add _ _ hs_nonempty hs) <| by positivity
+
+/-- If `m : M → N` is a subadditive function (`m (a + b) ≤ m a + m b`) and `s` is a nonempty set,
+then `m (𝔼 i ∈ s, f i) ≤ 𝔼 i ∈ s, m (f i)`. -/
+lemma le_expect_nonempty_of_subadditive (m : M → N) (h_mul : ∀ a b, m (a + b) ≤ m a + m b)
+ (h_div : ∀ (n : ℕ) a, m (a /ℚ n) = m a /ℚ n) (hs : s.Nonempty) :
+ m (𝔼 i ∈ s, f i) ≤ 𝔼 i ∈ s, m (f i) :=
+ le_expect_nonempty_of_subadditive_on_pred (p := fun _ ↦ True) (by simpa) (by simp) (by simpa) hs
+ (by simp)
+
+/-- Let `{a | p a}` be a subsemigroup of a commutative monoid `M`. If `m` is a subadditive function
+(`m (x + y) ≤ m x + m y`, `m 0 = 0`) preserved under division by a natural and `f` is a function
+valued in that subsemigroup, then `m (𝔼 i ∈ s, f i) ≤ 𝔼 i ∈ s, m (f i)`. -/
+lemma le_expect_of_subadditive_on_pred (h_zero : m 0 = 0)
+ (h_add : ∀ a b, p a → p b → m (a + b) ≤ m a + m b) (hp_add : ∀ a b, p a → p b → p (a + b))
+ (h_div : ∀ (n : ℕ) a, p a → m (a /ℚ n) = m a /ℚ n)
+ (hs : ∀ i ∈ s, p (f i)) : m (𝔼 i ∈ s, f i) ≤ 𝔼 i ∈ s, m (f i) := by
+ obtain rfl | hs_nonempty := s.eq_empty_or_nonempty
+ · simp [h_zero]
+ · exact le_expect_nonempty_of_subadditive_on_pred h_add hp_add h_div hs_nonempty hs
+
+-- TODO: Contribute back better docstring to `le_prod_of_submultiplicative`
+/-- If `m` is a subadditive function (`m (x + y) ≤ m x + m y`, `m 0 = 0`) preserved under division
+by a natural, then `m (𝔼 i ∈ s, f i) ≤ 𝔼 i ∈ s, m (f i)`. -/
+lemma le_expect_of_subadditive (h_zero : m 0 = 0) (h_add : ∀ a b, m (a + b) ≤ m a + m b)
+ (h_div : ∀ (n : ℕ) a, m (a /ℚ n) = m a /ℚ n) : m (𝔼 i ∈ s, f i) ≤ 𝔼 i ∈ s, m (f i) :=
+ le_expect_of_subadditive_on_pred (p := fun _ ↦ True) h_zero (by simpa) (by simp) (by simpa)
+ (by simp)
+
+end PosSMulMono
+end OrderedAddCommMonoid
+
+section OrderedCancelAddCommMonoid
+variable [OrderedCancelAddCommMonoid α] [Module ℚ≥0 α] {s : Finset ι} {f g : ι → α}
+section PosSMulStrictMono
+variable [PosSMulStrictMono ℚ≥0 α]
+
+lemma expect_pos (hf : ∀ i ∈ s, 0 < f i) (hs : s.Nonempty) : 0 < 𝔼 i ∈ s, f i :=
+ smul_pos (inv_pos.2 <| mod_cast hs.card_pos) <| sum_pos hf hs
+
+end PosSMulStrictMono
+end OrderedCancelAddCommMonoid
+
+section LinearOrderedAddCommMonoid
+variable [LinearOrderedAddCommMonoid α] [Module ℚ≥0 α] [PosSMulMono ℚ≥0 α] {s : Finset ι}
+ {f : ι → α} {a : α}
+
+lemma exists_lt_of_lt_expect (hs : s.Nonempty) (h : a < 𝔼 i ∈ s, f i) : ∃ x ∈ s, a < f x := by
+ contrapose! h; exact expect_le hs h
+
+lemma exists_lt_of_expect_lt (hs : s.Nonempty) (h : 𝔼 i ∈ s, f i < a) : ∃ x ∈ s, f x < a := by
+ contrapose! h; exact le_expect hs h
+
+end LinearOrderedAddCommMonoid
+
+section LinearOrderedAddCommGroup
+variable [LinearOrderedAddCommGroup α] [Module ℚ≥0 α] [PosSMulMono ℚ≥0 α]
+
+lemma abs_expect_le (s : Finset ι) (f : ι → α) : |𝔼 i ∈ s, f i| ≤ 𝔼 i ∈ s, |f i| :=
+ le_expect_of_subadditive abs_zero abs_add (fun _ ↦ abs_nnqsmul _)
+
+end LinearOrderedAddCommGroup
+
+section LinearOrderedCommSemiring
+variable [LinearOrderedCommSemiring R] [ExistsAddOfLE R] [Module ℚ≥0 R] [PosSMulMono ℚ≥0 R]
+
+/-- **Cauchy-Schwarz inequality** in terms of `Finset.expect`. -/
+lemma expect_mul_sq_le_sq_mul_sq (s : Finset ι) (f g : ι → R) :
+ (𝔼 i ∈ s, f i * g i) ^ 2 ≤ (𝔼 i ∈ s, f i ^ 2) * 𝔼 i ∈ s, g i ^ 2 := by
+ simp only [expect, smul_pow, inv_pow, smul_mul_smul_comm, ← sq]
+ gcongr
+ exact sum_mul_sq_le_sq_mul_sq ..
+
+end LinearOrderedCommSemiring
+end Finset
+
+open Finset
+
+namespace Fintype
+variable [Fintype ι] [Fintype κ]
+
+section OrderedAddCommMonoid
+variable [OrderedAddCommMonoid α] [Module ℚ≥0 α] {f : ι → α}
+
+lemma expect_eq_zero_iff_of_nonneg [Nonempty ι] (hf : 0 ≤ f) : 𝔼 i, f i = 0 ↔ f = 0 := by
+ simp [expect, sum_eq_zero_iff_of_nonneg hf, univ_nonempty.ne_empty]
+
+lemma expect_eq_zero_iff_of_nonpos [Nonempty ι] (hf : f ≤ 0) : 𝔼 i, f i = 0 ↔ f = 0 := by
+ simp [expect, sum_eq_zero_iff_of_nonpos hf, univ_nonempty.ne_empty]
+
+end OrderedAddCommMonoid
+end Fintype
+
+open Finset
+
+namespace Mathlib.Meta.Positivity
+open Qq Lean Meta Finset
+open scoped BigOperators
+
+/-- Positivity extension for `Finset.expect`. -/
+@[positivity Finset.expect _ _]
+def evalFinsetExpect : PositivityExt where eval {u α} zα pα e := do
+ match e with
+ | ~q(@Finset.expect $ι _ $instα $instmod $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
+ let .some instαordsmul ← trySynthInstanceQ q(PosSMulStrictMono ℚ≥0 $α) | pure none
+ assumeInstancesCommute
+ let pr : Q(∀ i, 0 < $f i) ← mkLambdaFVars #[i] pbody
+ return some q(@expect_pos $ι $α $pα' $instmod $s $f $instαordsmul (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 instαordmon ← synthInstanceQ q(OrderedAddCommMonoid $α)
+ let instαordsmul ← synthInstanceQ q(PosSMulMono ℚ≥0 $α)
+ assumeInstancesCommute
+ return .nonnegative q(@expect_nonneg $ι $α $instαordmon $instmod $s $f $instαordsmul
+ fun i _ ↦ $pr i)
+ | _ => throwError "not Finset.expect"
+
+example (n : ℕ) (a : ℕ → ℚ) : 0 ≤ 𝔼 j ∈ range n, a j^2 := by positivity
+example (a : ULift.{2} ℕ → ℚ) (s : Finset (ULift.{2} ℕ)) : 0 ≤ 𝔼 j ∈ s, a j^2 := by positivity
+example (n : ℕ) (a : ℕ → ℚ) : 0 ≤ 𝔼 j : Fin 8, 𝔼 i ∈ range n, (a j^2 + i ^ 2) := by positivity
+example (n : ℕ) (a : ℕ → ℚ) : 0 < 𝔼 j : Fin (n + 1), (a j^2 + 1) := by positivity
+example (a : ℕ → ℚ) : 0 < 𝔼 j ∈ ({1} : Finset ℕ), (a j^2 + 1) := by positivity
+
+end Mathlib.Meta.Positivity
diff --git a/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean b/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean
index 93535400087e6..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*}
@@ -121,7 +122,7 @@ theorem one_le_prod'' (h : ∀ i : ι, 1 ≤ f i) : 1 ≤ ∏ i ∈ s, f i :=
theorem prod_le_one' (h : ∀ i ∈ s, f i ≤ 1) : ∏ i ∈ s, f i ≤ 1 :=
(prod_le_prod' h).trans_eq (by rw [prod_const_one])
-@[to_additive sum_le_sum_of_subset_of_nonneg]
+@[to_additive (attr := gcongr) sum_le_sum_of_subset_of_nonneg]
theorem prod_le_prod_of_subset_of_one_le' (h : s ⊆ t) (hf : ∀ i ∈ t, i ∉ s → 1 ≤ f i) :
∏ i ∈ s, f i ≤ ∏ i ∈ t, f i := by
classical calc
@@ -174,42 +175,50 @@ 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
+@[to_additive]
+lemma max_prod_le [LinearOrderedCommMonoid M] {f g : ι → M} {s : Finset ι} :
+ max (s.prod f) (s.prod g) ≤ s.prod (fun i ↦ max (f i) (g i)) :=
+ Multiset.max_prod_le
+
+@[to_additive]
+lemma prod_min_le [LinearOrderedCommMonoid M] {f g : ι → M} {s : Finset ι} :
+ s.prod (fun i ↦ min (f i) (g i)) ≤ min (s.prod f) (s.prod g) :=
+ Multiset.prod_min_le
+
theorem abs_sum_le_sum_abs {G : Type*} [LinearOrderedAddCommGroup G] (f : ι → G) (s : Finset ι) :
|∑ i ∈ s, f i| ≤ ∑ i ∈ s, |f i| := le_sum_of_subadditive _ abs_zero abs_add s f
@@ -221,32 +230,41 @@ theorem abs_sum_of_nonneg' {G : Type*} [LinearOrderedAddCommGroup G] {f : ι →
(hf : ∀ i, 0 ≤ f i) : |∑ i ∈ s, f i| = ∑ i ∈ s, f i := by
rw [abs_of_nonneg (Finset.sum_nonneg' hf)]
+section CommMonoid
+variable [CommMonoid α] [LE α] [MulLeftMono α] {s : Finset ι} {f : ι → α}
+
+@[to_additive (attr := simp)]
+lemma mulLECancellable_prod :
+ MulLECancellable (∏ i ∈ s, f i) ↔ ∀ ⦃i⦄, i ∈ s → MulLECancellable (f i) := by
+ induction' s using Finset.cons_induction with i s hi ih <;> simp [*]
+
+end CommMonoid
+
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
@@ -257,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
@@ -316,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) _
@@ -353,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 :=
@@ -499,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
@@ -545,7 +558,7 @@ theorem finset_sum_eq_sup_iff_disjoint [DecidableEq α] {β : Type*} {i : Finset
· simp only [Finset.not_mem_empty, IsEmpty.forall_iff, imp_true_iff, Finset.sum_empty,
Finset.sup_empty, bot_eq_zero, eq_self_iff_true]
· simp_rw [Finset.sum_cons hz, Finset.sup_cons, Finset.mem_cons, Multiset.sup_eq_union,
- forall_eq_or_imp, Ne, not_true_eq_false, IsEmpty.forall_iff, true_and_iff,
+ forall_eq_or_imp, Ne, not_true_eq_false, IsEmpty.forall_iff, true_and,
imp_and, forall_and, ← hr, @eq_comm _ z]
have := fun x (H : x ∈ i) => ne_of_mem_of_not_mem H hz
simp (config := { contextual := true }) only [this, not_false_iff, true_imp_iff]
@@ -561,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 7872ed429ca63..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 (*)) (≤)]
@@ -119,6 +119,24 @@ lemma one_le_prod_of_one_le [Preorder M] [CovariantClass M M (· * ·) (· ≤
rw [prod_cons]
exact one_le_mul (hl₁ hd (mem_cons_self hd tl)) (ih fun x h => hl₁ x (mem_cons_of_mem hd h))
+@[to_additive]
+lemma max_prod_le (l : List α) (f g : α → M) [LinearOrder M]
+ [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
+ · apply le_max_left
+ · apply le_max_right
+
+@[to_additive]
+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
+ · apply min_le_left
+ · apply min_le_right
+
end Monoid
-- TODO: develop theory of tropical rings
@@ -143,7 +161,8 @@ lemma one_lt_prod_of_one_lt [OrderedCommMonoid M] :
· exact hl₁.2.1
· exact hl₁.2.2 _ ‹_›
-@[to_additive]
+/-- See also `List.le_prod_of_mem`. -/
+@[to_additive "See also `List.le_sum_of_mem`."]
lemma single_le_prod [OrderedCommMonoid M] {l : List M} (hl₁ : ∀ x ∈ l, (1 : M) ≤ x) :
∀ x ∈ l, x ≤ l.prod := by
induction l
@@ -163,7 +182,7 @@ variable [CanonicallyOrderedCommMonoid M] {l : List M}
@[to_additive] lemma prod_eq_one_iff : l.prod = 1 ↔ ∀ x ∈ l, x = (1 : M) :=
⟨all_one_of_le_one_le_of_prod_eq_one fun _ _ => one_le _, fun h => by
- rw [List.eq_replicate.2 ⟨_, h⟩, prod_replicate, one_pow]
+ rw [List.eq_replicate_iff.2 ⟨_, h⟩, prod_replicate, one_pow]
· exact (length l)
· rfl⟩
@@ -174,5 +193,18 @@ variable [CanonicallyOrderedCommMonoid M] {l : List M}
exact le_self_mul
· simp [take_of_length_le h, take_of_length_le (le_trans h (Nat.le_succ _))]
+/-- See also `List.single_le_prod`. -/
+@[to_additive "See also `List.single_le_sum`."]
+theorem le_prod_of_mem {xs : List M} {x : M} (h₁ : x ∈ xs) : x ≤ xs.prod := by
+ induction xs with
+ | nil => simp at h₁
+ | cons y ys ih =>
+ simp only [mem_cons] at h₁
+ rcases h₁ with (rfl | h₁)
+ · simp
+ · specialize ih h₁
+ simp only [List.prod_cons]
+ exact le_mul_left ih
+
end CanonicallyOrderedCommMonoid
end List
diff --git a/Mathlib/Algebra/Order/BigOperators/Group/LocallyFinite.lean b/Mathlib/Algebra/Order/BigOperators/Group/LocallyFinite.lean
new file mode 100644
index 0000000000000..f43f25244887d
--- /dev/null
+++ b/Mathlib/Algebra/Order/BigOperators/Group/LocallyFinite.lean
@@ -0,0 +1,80 @@
+/-
+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.BigOperators.Group.Finset
+import Mathlib.Order.Interval.Finset.Basic
+
+/-!
+# Big operators indexed by intervals
+
+This file proves lemmas about `∏ x ∈ Ixx a b, f x` and `∑ x ∈ Ixx a b, f x`.
+-/
+
+variable {α β : Type*} [PartialOrder α] [CommMonoid β] {f : α → β} {a b : α}
+
+namespace Finset
+section LocallyFiniteOrder
+variable [LocallyFiniteOrder α]
+
+@[to_additive]
+lemma left_mul_prod_Ioc (h : a ≤ b) : f a * ∏ x ∈ Ioc a b, f x = ∏ x ∈ Icc a b, f x := by
+ rw [Icc_eq_cons_Ioc h, prod_cons]
+
+@[to_additive]
+lemma prod_Ioc_mul_left (h : a ≤ b) : (∏ x ∈ Ioc a b, f x) * f a = ∏ x ∈ Icc a b, f x := by
+ rw [mul_comm, left_mul_prod_Ioc h]
+
+@[to_additive]
+lemma right_mul_prod_Ico (h : a ≤ b) : f b * ∏ x ∈ Ico a b, f x = ∏ x ∈ Icc a b, f x := by
+ rw [Icc_eq_cons_Ico h, prod_cons]
+
+@[to_additive]
+lemma prod_Ico_mul_right (h : a ≤ b) : (∏ x ∈ Ico a b, f x) * f b = ∏ x ∈ Icc a b, f x := by
+ rw [mul_comm, right_mul_prod_Ico h]
+
+@[to_additive]
+lemma left_mul_prod_Ioo (h : a < b) : f a * ∏ x ∈ Ioo a b, f x = ∏ x ∈ Ico a b, f x := by
+ rw [Ico_eq_cons_Ioo h, prod_cons]
+
+@[to_additive]
+lemma prod_Ioo_mul_left (h : a < b) : (∏ x ∈ Ioo a b, f x) * f a = ∏ x ∈ Ico a b, f x := by
+ rw [mul_comm, left_mul_prod_Ioo h]
+
+@[to_additive]
+lemma right_mul_prod_Ioo (h : a < b) : f b * ∏ x ∈ Ioo a b, f x = ∏ x ∈ Ioc a b, f x := by
+ rw [Ioc_eq_cons_Ioo h, prod_cons]
+
+@[to_additive]
+lemma prod_Ioo_mul_right (h : a < b) : (∏ x ∈ Ioo a b, f x) * f b = ∏ x ∈ Ioc a b, f x := by
+ rw [mul_comm, right_mul_prod_Ioo h]
+
+end LocallyFiniteOrder
+
+section LocallyFiniteOrderTop
+variable [LocallyFiniteOrderTop α]
+
+@[to_additive]
+lemma left_mul_prod_Ioi (a : α) : f a * ∏ x ∈ Ioi a, f x = ∏ x ∈ Ici a, f x := by
+ rw [Ici_eq_cons_Ioi, prod_cons]
+
+@[to_additive]
+lemma prod_Ioi_mul_left (a : α) : (∏ x ∈ Ioi a, f x) * f a = ∏ x ∈ Ici a, f x := by
+ rw [mul_comm, left_mul_prod_Ioi]
+
+end LocallyFiniteOrderTop
+
+section LocallyFiniteOrderBot
+variable [LocallyFiniteOrderBot α]
+
+@[to_additive]
+lemma right_mul_prod_Iio (a : α) : f a * ∏ x ∈ Iio a, f x = ∏ x ∈ Iic a, f x := by
+ rw [Iic_eq_cons_Iio, prod_cons]
+
+@[to_additive]
+lemma prod_Iio_mul_right (a : α) : (∏ x ∈ Iio a, f x) * f a = ∏ x ∈ Iic a, f x := by
+ rw [mul_comm, right_mul_prod_Iio]
+
+end LocallyFiniteOrderBot
+end Finset
diff --git a/Mathlib/Algebra/Order/BigOperators/Group/Multiset.lean b/Mathlib/Algebra/Order/BigOperators/Group/Multiset.lean
index 52ae9a3e331ce..ad405fe75fb40 100644
--- a/Mathlib/Algebra/Order/BigOperators/Group/Multiset.lean
+++ b/Mathlib/Algebra/Order/BigOperators/Group/Multiset.lean
@@ -156,6 +156,20 @@ lemma max_le_of_forall_le {α : Type*} [LinearOrder α] [OrderBot α] (l : Multi
induction l using Quotient.inductionOn
simpa using List.max_le_of_forall_le _ _ h
+@[to_additive]
+lemma max_prod_le [LinearOrderedCommMonoid α] {s : Multiset ι} {f g : ι → α} :
+ max (s.map f).prod (s.map g).prod ≤ (s.map fun i ↦ max (f i) (g i)).prod := by
+ obtain ⟨l⟩ := s
+ simp_rw [Multiset.quot_mk_to_coe'', Multiset.map_coe, Multiset.prod_coe]
+ apply List.max_prod_le
+
+@[to_additive]
+lemma prod_min_le [LinearOrderedCommMonoid α] {s : Multiset ι} {f g : ι → α} :
+ (s.map fun i ↦ min (f i) (g i)).prod ≤ min (s.map f).prod (s.map g).prod := by
+ obtain ⟨l⟩ := s
+ simp_rw [Multiset.quot_mk_to_coe'', Multiset.map_coe, Multiset.prod_coe]
+ apply List.prod_min_le
+
lemma abs_sum_le_sum_abs [LinearOrderedAddCommGroup α] {s : Multiset α} :
|s.sum| ≤ (s.map abs).sum :=
le_sum_of_subadditive _ abs_zero abs_add s
diff --git a/Mathlib/Algebra/Order/BigOperators/GroupWithZero/List.lean b/Mathlib/Algebra/Order/BigOperators/GroupWithZero/List.lean
index 77f4d768aee3b..e38120c46d7ac 100644
--- a/Mathlib/Algebra/Order/BigOperators/GroupWithZero/List.lean
+++ b/Mathlib/Algebra/Order/BigOperators/GroupWithZero/List.lean
@@ -51,12 +51,12 @@ theorem prod_map_le_prod_map₀ {ι : Type*} {s : List ι} (f : ι → R) (g :
· intro i hi
apply h
simp [hi]
- apply prod_nonneg
- · simp only [mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
+ · apply prod_nonneg
+ simp only [mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
intro a ha
apply h0
simp [ha]
- apply (h0 _ _).trans (h _ _) <;> simp
+ · apply (h0 _ _).trans (h _ _) <;> simp
omit [PosMulMono R]
variable [PosMulStrictMono R] [NeZero (1 : R)]
@@ -89,11 +89,11 @@ theorem prod_map_lt_prod_map {ι : Type*} {s : List ι} (hs : s ≠ [])
apply le_of_lt
apply h
simp [hi]
- apply prod_pos
- · simp only [mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
+ · apply prod_pos
+ simp only [mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
intro a ha
apply h0
simp [ha]
- apply le_of_lt ((h0 _ _).trans (h _ _)) <;> simp
+ · apply le_of_lt ((h0 _ _).trans (h _ _)) <;> simp
end List
diff --git a/Mathlib/Algebra/Order/CauSeq/Basic.lean b/Mathlib/Algebra/Order/CauSeq/Basic.lean
index 461ef07e12d62..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
@@ -678,7 +678,7 @@ instance : Preorder (CauSeq α abs) where
| Or.inr fg, Or.inl gh => Or.inl <| lt_of_eq_of_lt fg gh
| Or.inr fg, Or.inr gh => Or.inr <| Setoid.trans fg gh
lt_iff_le_not_le _ _ :=
- ⟨fun h => ⟨Or.inl h, not_or_of_not (mt (lt_trans h) lt_irrefl) (not_limZero_of_pos h)⟩,
+ ⟨fun h => ⟨Or.inl h, not_or_intro (mt (lt_trans h) lt_irrefl) (not_limZero_of_pos h)⟩,
fun ⟨h₁, h₂⟩ => h₁.resolve_right (mt (fun h => Or.inr (Setoid.symm h)) h₂)⟩
theorem le_antisymm {f g : CauSeq α abs} (fg : f ≤ g) (gf : g ≤ f) : f ≈ g :=
@@ -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 2ac291cf0c7a6..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 _ _ _) ?_
@@ -188,7 +188,7 @@ lemma geo_series [Nontrivial β] (x : β) (hx1 : abv x < 1) :
· gcongr
exact sub_le_self _ (abv_pow abv x n ▸ abv_nonneg _ _)
refine div_nonneg (sub_nonneg.2 ?_) (sub_nonneg.2 <| le_of_lt hx1)
- exact pow_le_one _ (by positivity) hx1.le
+ exact pow_le_one₀ (by positivity) hx1.le
· intro n _
rw [← one_mul (abv x ^ n), pow_succ']
gcongr
@@ -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 ebbe5643ee00c..25c25f0275d3c 100644
--- a/Mathlib/Algebra/Order/Chebyshev.lean
+++ b/Mathlib/Algebra/Order/Chebyshev.lean
@@ -3,17 +3,19 @@ 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.Algebra.Order.Ring.Basic
import Mathlib.GroupTheory.Perm.Cycle.Basic
+import Mathlib.Tactic.GCongr
+import Mathlib.Tactic.Positivity.Basic
+import Mathlib.Tactic.Positivity.Finset
/-!
# Chebyshev's sum inequality
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.
@@ -44,28 +46,26 @@ variable {ι α β : Type*}
section SMul
-
-variable [LinearOrderedRing α] [LinearOrderedAddCommGroup β] [Module α β] [OrderedSMul α β]
- {s : Finset ι} {σ : Perm ι} {f : ι → α} {g : ι → β}
+variable [LinearOrderedSemiring α] [ExistsAddOfLE α] [LinearOrderedCancelAddCommMonoid β]
+ [Module α β] [OrderedSMul α β] {s : Finset ι} {σ : Perm ι} {f : ι → α} {g : ι → β}
/-- **Chebyshev's Sum Inequality**: When `f` and `g` monovary together (eg they are both
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σ]
- 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 _
+ obtain ⟨σ, hσ, hs⟩ := s.countable_toSet.exists_cycleOn
+ 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 _
/-- **Chebyshev's Sum Inequality**: When `f` and `g` antivary together (eg one is monotone, the
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 := by
- exact hfg.dual_right.sum_smul_sum_le_card_smul_sum
+ #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 ι]
@@ -73,15 +73,15 @@ variable [Fintype ι]
monotone/antitone), the scalar product of their sum is less than the size of the set times their
scalar product. -/
theorem Monovary.sum_smul_sum_le_card_smul_sum (hfg : Monovary f g) :
- ((∑ i, f i) • ∑ i, g i) ≤ Fintype.card ι • ∑ i, f i • g i :=
+ (∑ i, f i) • ∑ i, g i ≤ Fintype.card ι • ∑ i, f i • g i :=
(hfg.monovaryOn _).sum_smul_sum_le_card_smul_sum
/-- **Chebyshev's Sum Inequality**: When `f` and `g` antivary together (eg one is monotone, the
other is antitone), the scalar product of their sum is less than the size of the set times their
scalar product. -/
theorem Antivary.card_smul_sum_le_sum_smul_sum (hfg : Antivary f g) :
- (Fintype.card ι • ∑ i, f i • g i) ≤ (∑ i, f i) • ∑ i, g i := by
- exact (hfg.dual_right.monovaryOn _).sum_smul_sum_le_card_smul_sum
+ Fintype.card ι • ∑ i, f i • g i ≤ (∑ i, f i) • ∑ i, g i :=
+ (hfg.dual_right.monovaryOn _).sum_smul_sum_le_card_smul_sum
end SMul
@@ -93,14 +93,13 @@ Special cases of the above when scalar multiplication is actually multiplication
section Mul
-
-variable [LinearOrderedRing α] {s : Finset ι} {σ : Perm ι} {f g : ι → α}
+variable [LinearOrderedSemiring α] [ExistsAddOfLE α] {s : Finset ι} {σ : Perm ι} {f g : ι → α}
/-- **Chebyshev's Sum Inequality**: When `f` and `g` monovary together (eg they are both
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,13 +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 : α) ^ 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 ^ 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 ^ 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
@@ -124,25 +139,32 @@ variable [Fintype ι]
monotone/antitone), the product of their sum is less than the size of the set times their scalar
product. -/
theorem Monovary.sum_mul_sum_le_card_mul_sum (hfg : Monovary f g) :
- ((∑ i, f i) * ∑ i, g i) ≤ Fintype.card ι * ∑ i, f i * g i :=
+ (∑ i, f i) * ∑ i, g i ≤ Fintype.card ι * ∑ i, f i * g i :=
(hfg.monovaryOn _).sum_mul_sum_le_card_mul_sum
/-- **Chebyshev's Sum Inequality**: When `f` and `g` antivary together (eg one is monotone, the
other is antitone), the product of their sum is less than the size of the set times their scalar
product. -/
theorem Antivary.card_mul_sum_le_sum_mul_sum (hfg : Antivary f g) :
- ((Fintype.card ι : α) * ∑ i, f i * g i) ≤ (∑ i, f i) * ∑ i, g i :=
+ Fintype.card ι * ∑ i, f i * g i ≤ (∑ i, f i) * ∑ i, g i :=
(hfg.antivaryOn _).card_mul_sum_le_sum_mul_sum
end Mul
-variable [LinearOrderedField α] {s : Finset ι} {f : ι → α}
+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 ^ 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 [← card_pos, ← @Nat.cast_pos α] at hs
- rw [div_pow, div_le_div_iff (sq_pos_of_ne_zero hs.ne') hs, sq (s.card : α), mul_left_comm, ←
- mul_assoc]
- exact mul_le_mul_of_nonneg_right sq_sum_le_card_mul_sum_sq hs.le
+ 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 2c8942e53c15c..31a14a28943a9 100644
--- a/Mathlib/Algebra/Order/CompleteField.lean
+++ b/Mathlib/Algebra/Order/CompleteField.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Alex J. Best, Yaël Dillies
-/
import Mathlib.Algebra.Order.Archimedean.Hom
-import Mathlib.Algebra.Order.Pointwise
+import Mathlib.Algebra.Order.Group.Pointwise.CompleteLattice
import Mathlib.Analysis.SpecialFunctions.Pow.Real
/-!
@@ -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 10cb8d1525691..4e76076e79d17 100644
--- a/Mathlib/Algebra/Order/Field/Basic.lean
+++ b/Mathlib/Algebra/Order/Field/Basic.lean
@@ -5,9 +5,9 @@ Authors: Robert Y. Lewis, Leonardo de Moura, Mario Carneiro, Floris van Doorn
-/
import Mathlib.Algebra.CharZero.Lemmas
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
/-!
@@ -23,171 +23,143 @@ section LinearOrderedSemifield
variable [LinearOrderedSemifield α] {a b c d e : α} {m n : ℤ}
-/-- `Equiv.mulLeft₀` as an order_iso. -/
-@[simps! (config := { simpRhs := true })]
-def OrderIso.mulLeft₀ (a : α) (ha : 0 < a) : α ≃o α :=
- { Equiv.mulLeft₀ a ha.ne' with map_rel_iff' := @fun _ _ => mul_le_mul_left ha }
-
-/-- `Equiv.mulRight₀` as an order_iso. -/
-@[simps! (config := { simpRhs := true })]
-def OrderIso.mulRight₀ (a : α) (ha : 0 < a) : α ≃o α :=
- { Equiv.mulRight₀ a ha.ne' with map_rel_iff' := @fun _ _ => mul_le_mul_right ha }
-
/-!
### Relating one division with another term.
-/
-theorem lt_div_iff (hc : 0 < c) : a < b / c ↔ a * c < b :=
- lt_iff_lt_of_le_iff_le <| div_le_iff₀ hc
-
-theorem lt_div_iff' (hc : 0 < c) : a < b / c ↔ c * a < b := by rw [mul_comm, lt_div_iff hc]
+@[deprecated lt_div_iff₀ (since := "2024-10-02")]
+theorem lt_div_iff (hc : 0 < c) : a < b / c ↔ a * c < b := lt_div_iff₀ hc
-theorem div_lt_iff (hc : 0 < c) : b / c < a ↔ b < a * c :=
- lt_iff_lt_of_le_iff_le (le_div_iff₀ hc)
+@[deprecated lt_div_iff₀' (since := "2024-10-02")]
+theorem lt_div_iff' (hc : 0 < c) : a < b / c ↔ c * a < b := lt_div_iff₀' hc
-theorem div_lt_iff' (hc : 0 < c) : b / c < a ↔ b < c * a := by rw [mul_comm, div_lt_iff hc]
+@[deprecated div_lt_iff₀ (since := "2024-10-02")]
+theorem div_lt_iff (hc : 0 < c) : b / c < a ↔ b < a * c := div_lt_iff₀ hc
-lemma div_lt_comm₀ (hb : 0 < b) (hc : 0 < c) : a / b < c ↔ a / c < b := by
- rw [div_lt_iff hb, div_lt_iff' hc]
+@[deprecated div_lt_iff₀' (since := "2024-10-02")]
+theorem div_lt_iff' (hc : 0 < c) : b / c < a ↔ b < c * a := div_lt_iff₀' hc
-theorem inv_mul_le_iff (h : 0 < b) : b⁻¹ * a ≤ c ↔ a ≤ b * c := by
- rw [inv_eq_one_div, mul_comm, ← div_eq_mul_one_div]
- exact div_le_iff₀' h
+@[deprecated inv_mul_le_iff₀ (since := "2024-10-02")]
+theorem inv_mul_le_iff (h : 0 < b) : b⁻¹ * a ≤ c ↔ a ≤ b * c := inv_mul_le_iff₀ h
-theorem inv_mul_le_iff' (h : 0 < b) : b⁻¹ * a ≤ c ↔ a ≤ c * b := by rw [inv_mul_le_iff h, mul_comm]
+@[deprecated inv_mul_le_iff₀' (since := "2024-10-02")]
+theorem inv_mul_le_iff' (h : 0 < b) : b⁻¹ * a ≤ c ↔ a ≤ c * b := inv_mul_le_iff₀' h
-theorem mul_inv_le_iff (h : 0 < b) : a * b⁻¹ ≤ c ↔ a ≤ b * c := by rw [mul_comm, inv_mul_le_iff h]
+@[deprecated mul_inv_le_iff₀' (since := "2024-10-02")]
+theorem mul_inv_le_iff (h : 0 < b) : a * b⁻¹ ≤ c ↔ a ≤ b * c := mul_inv_le_iff₀' h
-theorem mul_inv_le_iff' (h : 0 < b) : a * b⁻¹ ≤ c ↔ a ≤ c * b := by rw [mul_comm, inv_mul_le_iff' h]
+@[deprecated mul_inv_le_iff₀ (since := "2024-10-02")]
+theorem mul_inv_le_iff' (h : 0 < b) : a * b⁻¹ ≤ c ↔ a ≤ c * b := mul_inv_le_iff₀ h
-theorem div_self_le_one (a : α) : a / a ≤ 1 :=
- if h : a = 0 then by simp [h] else by simp [h]
+@[deprecated inv_mul_lt_iff₀ (since := "2024-10-02")]
+theorem inv_mul_lt_iff (h : 0 < b) : b⁻¹ * a < c ↔ a < b * c := inv_mul_lt_iff₀ h
-theorem inv_mul_lt_iff (h : 0 < b) : b⁻¹ * a < c ↔ a < b * c := by
- rw [inv_eq_one_div, mul_comm, ← div_eq_mul_one_div]
- exact div_lt_iff' h
+@[deprecated inv_mul_lt_iff₀' (since := "2024-10-02")]
+theorem inv_mul_lt_iff' (h : 0 < b) : b⁻¹ * a < c ↔ a < c * b := inv_mul_lt_iff₀' h
-theorem inv_mul_lt_iff' (h : 0 < b) : b⁻¹ * a < c ↔ a < c * b := by rw [inv_mul_lt_iff h, mul_comm]
+@[deprecated mul_inv_lt_iff₀' (since := "2024-10-02")]
+theorem mul_inv_lt_iff (h : 0 < b) : a * b⁻¹ < c ↔ a < b * c := mul_inv_lt_iff₀' h
-theorem mul_inv_lt_iff (h : 0 < b) : a * b⁻¹ < c ↔ a < b * c := by rw [mul_comm, inv_mul_lt_iff h]
+@[deprecated mul_inv_lt_iff₀ (since := "2024-10-02")]
+theorem mul_inv_lt_iff' (h : 0 < b) : a * b⁻¹ < c ↔ a < c * b := mul_inv_lt_iff₀ h
-theorem mul_inv_lt_iff' (h : 0 < b) : a * b⁻¹ < c ↔ a < c * b := by rw [mul_comm, inv_mul_lt_iff' h]
+@[deprecated inv_le_iff_one_le_mul₀ (since := "2024-10-03")]
+theorem inv_pos_le_iff_one_le_mul (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ b * a := inv_le_iff_one_le_mul₀ ha
-theorem inv_pos_le_iff_one_le_mul (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ b * a := by
- rw [inv_eq_one_div]
- exact div_le_iff₀ ha
+@[deprecated inv_le_iff_one_le_mul₀' (since := "2024-10-03")]
+theorem inv_pos_le_iff_one_le_mul' (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ a * b := inv_le_iff_one_le_mul₀' ha
-theorem inv_pos_le_iff_one_le_mul' (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ a * b := by
- rw [inv_eq_one_div]
- exact div_le_iff₀' ha
+@[deprecated inv_lt_iff_one_lt_mul₀ (since := "2024-10-03")]
+theorem inv_pos_lt_iff_one_lt_mul (ha : 0 < a) : a⁻¹ < b ↔ 1 < b * a := inv_lt_iff_one_lt_mul₀ ha
-theorem inv_pos_lt_iff_one_lt_mul (ha : 0 < a) : a⁻¹ < b ↔ 1 < b * a := by
- rw [inv_eq_one_div]
- exact div_lt_iff ha
-
-theorem inv_pos_lt_iff_one_lt_mul' (ha : 0 < a) : a⁻¹ < b ↔ 1 < a * b := by
- rw [inv_eq_one_div]
- exact div_lt_iff' ha
+@[deprecated inv_lt_iff_one_lt_mul₀' (since := "2024-10-03")]
+theorem inv_pos_lt_iff_one_lt_mul' (ha : 0 < a) : a⁻¹ < b ↔ 1 < a * b := inv_lt_iff_one_lt_mul₀' ha
/-- One direction of `div_le_iff` where `b` is allowed to be `0` (but `c` must be nonnegative) -/
-theorem div_le_of_nonneg_of_le_mul (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ c * b) : a / b ≤ c := by
- rcases eq_or_lt_of_le hb with (rfl | hb')
- · simp only [div_zero, hc]
- · rwa [div_le_iff₀ hb']
+@[deprecated div_le_of_le_mul₀ (since := "2024-10-03")]
+theorem div_le_of_nonneg_of_le_mul (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ c * b) : a / b ≤ c :=
+ div_le_of_le_mul₀ hb hc h
/-- One direction of `div_le_iff` where `c` is allowed to be `0` (but `b` must be nonnegative) -/
-lemma mul_le_of_nonneg_of_le_div (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ b / c) : a * c ≤ b := by
- obtain rfl | hc := hc.eq_or_lt
- · simpa using hb
- · rwa [le_div_iff₀ hc] at h
+@[deprecated mul_le_of_le_div₀ (since := "2024-10-03")]
+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
-@[bound]
-theorem div_le_one_of_le (h : a ≤ b) (hb : 0 ≤ b) : a / b ≤ 1 :=
- div_le_of_nonneg_of_le_mul hb zero_le_one <| by rwa [one_mul]
+@[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
-@[bound]
-lemma mul_inv_le_one_of_le (h : a ≤ b) (hb : 0 ≤ b) : a * b⁻¹ ≤ 1 := by
- simpa only [← div_eq_mul_inv] using div_le_one_of_le h hb
+@[deprecated mul_inv_le_one_of_le₀ (since := "2024-10-03")]
+lemma mul_inv_le_one_of_le (h : a ≤ b) (hb : 0 ≤ b) : a * b⁻¹ ≤ 1 := mul_inv_le_one_of_le₀ h hb
-@[bound]
-lemma inv_mul_le_one_of_le (h : a ≤ b) (hb : 0 ≤ b) : b⁻¹ * a ≤ 1 := by
- simpa only [← div_eq_inv_mul] using div_le_one_of_le h hb
+@[deprecated inv_mul_le_one_of_le₀ (since := "2024-10-03")]
+lemma inv_mul_le_one_of_le (h : a ≤ b) (hb : 0 ≤ b) : b⁻¹ * a ≤ 1 := inv_mul_le_one_of_le₀ h hb
/-!
### 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_iff, 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.
@@ -208,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
@@ -231,13 +203,13 @@ 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)
theorem div_lt_div_iff (b0 : 0 < b) (d0 : 0 < d) : a / b < c / d ↔ a * d < c * b := by
- rw [lt_div_iff d0, div_mul_eq_mul_div, div_lt_iff b0]
+ rw [lt_div_iff₀ d0, div_mul_eq_mul_div, div_lt_iff₀ b0]
theorem div_le_div_iff (b0 : 0 < b) (d0 : 0 < d) : a / b ≤ c / d ↔ a * d ≤ c * b := by
rw [le_div_iff₀ d0, div_mul_eq_mul_div, div_le_iff₀ b0]
@@ -275,17 +247,21 @@ theorem one_le_div (hb : 0 < b) : 1 ≤ a / b ↔ b ≤ a := by rw [le_div_iff
theorem div_le_one (hb : 0 < b) : a / b ≤ 1 ↔ a ≤ b := by rw [div_le_iff₀ hb, one_mul]
-theorem one_lt_div (hb : 0 < b) : 1 < a / b ↔ b < a := by rw [lt_div_iff hb, one_mul]
+theorem one_lt_div (hb : 0 < b) : 1 < a / b ↔ b < a := by rw [lt_div_iff₀ hb, one_mul]
-theorem div_lt_one (hb : 0 < b) : a / b < 1 ↔ a < b := by rw [div_lt_iff hb, one_mul]
+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
@@ -297,10 +273,10 @@ 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)]
+ rwa [lt_div_iff₀' ha, ← div_eq_mul_one_div, div_lt_one (ha.trans h)]
theorem le_of_one_div_le_one_div (ha : 0 < a) (h : 1 / a ≤ 1 / b) : b ≤ a :=
le_imp_le_of_lt_imp_lt (one_div_lt_one_div_of_lt ha) h
@@ -341,7 +317,7 @@ theorem half_le_self_iff : a / 2 ≤ a ↔ 0 ≤ a := by
@[simp]
theorem half_lt_self_iff : a / 2 < a ↔ 0 < a := by
- rw [div_lt_iff (zero_lt_two' α), mul_two, lt_add_iff_pos_left]
+ rw [div_lt_iff₀ (zero_lt_two' α), mul_two, lt_add_iff_pos_left]
alias ⟨_, half_le_self⟩ := half_le_self_iff
@@ -355,9 +331,9 @@ theorem one_half_lt_one : (1 / 2 : α) < 1 :=
theorem two_inv_lt_one : (2⁻¹ : α) < 1 :=
(one_div _).symm.trans_lt one_half_lt_one
-theorem left_lt_add_div_two : a < (a + b) / 2 ↔ a < b := by simp [lt_div_iff, mul_two]
+theorem left_lt_add_div_two : a < (a + b) / 2 ↔ a < b := by simp [lt_div_iff₀, mul_two]
-theorem add_div_two_lt_right : (a + b) / 2 < b ↔ a < b := by simp [div_lt_iff, mul_two]
+theorem add_div_two_lt_right : (a + b) / 2 < b ↔ a < b := by simp [div_lt_iff₀, mul_two]
theorem add_thirds (a : α) : a / 3 + a / 3 + a / 3 = a := by
rw [div_add_div_same, div_add_div_same, ← two_mul, ← add_one_mul 2 a, two_add_one_eq_three,
@@ -385,12 +361,12 @@ theorem div_mul_le_div_mul_of_div_le_div (h : a / b ≤ c / d) (he : 0 ≤ e) :
theorem exists_pos_mul_lt {a : α} (h : 0 < a) (b : α) : ∃ c : α, 0 < c ∧ b * c < a := by
have : 0 < a / max (b + 1) 1 := div_pos h (lt_max_iff.2 (Or.inr zero_lt_one))
refine ⟨a / max (b + 1) 1, this, ?_⟩
- rw [← lt_div_iff this, div_div_cancel' h.ne']
+ rw [← lt_div_iff₀ this, div_div_cancel' h.ne']
exact lt_max_iff.2 (Or.inl <| lt_add_one _)
theorem exists_pos_lt_mul {a : α} (h : 0 < a) (b : α) : ∃ c : α, 0 < c ∧ b < c * a :=
let ⟨c, hc₀, hc⟩ := exists_pos_mul_lt h b;
- ⟨c⁻¹, inv_pos.2 hc₀, by rwa [← div_eq_inv_mul, lt_div_iff hc₀]⟩
+ ⟨c⁻¹, inv_pos.2 hc₀, by rwa [← div_eq_inv_mul, lt_div_iff₀ hc₀]⟩
lemma monotone_div_right_of_nonneg (ha : 0 ≤ a) : Monotone (· / a) :=
fun _b _c hbc ↦ div_le_div_of_nonneg_right hbc ha
@@ -429,7 +405,7 @@ theorem one_div_strictAntiOn : StrictAntiOn (fun x : α => 1 / x) (Set.Ioi 0) :=
theorem one_div_pow_le_one_div_pow_of_le (a1 : 1 ≤ a) {m n : ℕ} (mn : m ≤ n) :
1 / a ^ n ≤ 1 / a ^ m := by
- refine (one_div_le_one_div ?_ ?_).mpr (pow_le_pow_right a1 mn) <;>
+ refine (one_div_le_one_div ?_ ?_).mpr (pow_right_mono₀ a1 mn) <;>
exact pow_pos (zero_lt_one.trans_le a1) _
theorem one_div_pow_lt_one_div_pow_of_lt (a1 : 1 < a) {m n : ℕ} (mn : m < n) :
@@ -444,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
@@ -538,7 +514,7 @@ theorem lt_div_iff_of_neg' (hc : c < 0) : a < b / c ↔ b < c * a := by
rw [mul_comm, lt_div_iff_of_neg hc]
theorem div_le_one_of_ge (h : b ≤ a) (hb : b ≤ 0) : a / b ≤ 1 := by
- simpa only [neg_div_neg_eq] using div_le_one_of_le (neg_le_neg h) (neg_nonneg_of_nonpos hb)
+ simpa only [neg_div_neg_eq] using div_le_one_of_le₀ (neg_le_neg h) (neg_nonneg_of_nonpos hb)
/-! ### Bi-implications of inequalities using inversions -/
@@ -569,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) :=
@@ -723,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 5e36efa7b7f81..86284a304dde6 100644
--- a/Mathlib/Algebra/Order/Field/Defs.lean
+++ b/Mathlib/Algebra/Order/Field/Defs.lean
@@ -35,3 +35,67 @@ class LinearOrderedField (α : Type*) extends LinearOrderedCommRing α, Field α
instance (priority := 100) LinearOrderedField.toLinearOrderedSemifield [LinearOrderedField α] :
LinearOrderedSemifield α :=
{ LinearOrderedRing.toLinearOrderedSemiring, ‹LinearOrderedField α› with }
+
+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 [*]
+
+/-- Equality holds when `a ≠ 0`. See `inv_mul_cancel`. -/
+lemma inv_mul_le_one : a⁻¹ * a ≤ 1 := by obtain rfl | ha := eq_or_ne a 0 <;> simp [*]
+
+/-- Equality holds when `a ≠ 0`. See `mul_inv_cancel_left`. -/
+lemma mul_inv_left_le (hb : 0 ≤ b) : a * (a⁻¹ * b) ≤ b := by
+ obtain rfl | ha := eq_or_ne a 0 <;> simp [*]
+
+/-- Equality holds when `a ≠ 0`. See `mul_inv_cancel_left`. -/
+lemma le_mul_inv_left (hb : b ≤ 0) : b ≤ a * (a⁻¹ * b) := by
+ obtain rfl | ha := eq_or_ne a 0 <;> simp [*]
+
+/-- Equality holds when `a ≠ 0`. See `inv_mul_cancel_left`. -/
+lemma inv_mul_left_le (hb : 0 ≤ b) : a⁻¹ * (a * b) ≤ b := by
+ obtain rfl | ha := eq_or_ne a 0 <;> simp [*]
+
+/-- Equality holds when `a ≠ 0`. See `inv_mul_cancel_left`. -/
+lemma le_inv_mul_left (hb : b ≤ 0) : b ≤ a⁻¹ * (a * b) := by
+ obtain rfl | ha := eq_or_ne a 0 <;> simp [*]
+
+/-- Equality holds when `b ≠ 0`. See `mul_inv_cancel_right`. -/
+lemma mul_inv_right_le (ha : 0 ≤ a) : a * b * b⁻¹ ≤ a := by
+ obtain rfl | hb := eq_or_ne b 0 <;> simp [*]
+
+/-- Equality holds when `b ≠ 0`. See `mul_inv_cancel_right`. -/
+lemma le_mul_inv_right (ha : a ≤ 0) : a ≤ a * b * b⁻¹ := by
+ obtain rfl | hb := eq_or_ne b 0 <;> simp [*]
+
+/-- Equality holds when `b ≠ 0`. See `inv_mul_cancel_right`. -/
+lemma inv_mul_right_le (ha : 0 ≤ a) : a * b⁻¹ * b ≤ a := by
+ obtain rfl | hb := eq_or_ne b 0 <;> simp [*]
+
+/-- 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/Pointwise.lean b/Mathlib/Algebra/Order/Field/Pointwise.lean
new file mode 100644
index 0000000000000..01d4453c22523
--- /dev/null
+++ b/Mathlib/Algebra/Order/Field/Pointwise.lean
@@ -0,0 +1,126 @@
+/-
+Copyright (c) 2021 Alex J. Best. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Alex J. Best, Yaël Dillies
+-/
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
+import Mathlib.Algebra.Order.Field.Defs
+import Mathlib.Algebra.SMulWithZero
+
+/-!
+# Pointwise operations on ordered algebraic objects
+
+This file contains lemmas about the effect of pointwise operations on sets with an order structure.
+-/
+
+open Function Set
+open scoped Pointwise
+
+variable {α : Type*}
+
+namespace LinearOrderedField
+
+variable {K : Type*} [LinearOrderedField K] {a b r : K} (hr : 0 < r)
+include hr
+
+theorem smul_Ioo : r • Ioo a b = Ioo (r • a) (r • b) := by
+ ext x
+ simp only [mem_smul_set, smul_eq_mul, mem_Ioo]
+ constructor
+ · rintro ⟨a, ⟨a_h_left_left, a_h_left_right⟩, rfl⟩
+ constructor
+ · exact (mul_lt_mul_left hr).mpr a_h_left_left
+ · exact (mul_lt_mul_left hr).mpr a_h_left_right
+ · rintro ⟨a_left, a_right⟩
+ use x / r
+ refine ⟨⟨(lt_div_iff₀' hr).mpr a_left, (div_lt_iff₀' hr).mpr a_right⟩, ?_⟩
+ rw [mul_div_cancel₀ _ (ne_of_gt hr)]
+
+theorem smul_Icc : r • Icc a b = Icc (r • a) (r • b) := by
+ ext x
+ simp only [mem_smul_set, smul_eq_mul, mem_Icc]
+ constructor
+ · rintro ⟨a, ⟨a_h_left_left, a_h_left_right⟩, rfl⟩
+ constructor
+ · exact (mul_le_mul_left hr).mpr a_h_left_left
+ · exact (mul_le_mul_left hr).mpr a_h_left_right
+ · rintro ⟨a_left, a_right⟩
+ use x / r
+ refine ⟨⟨(le_div_iff₀' hr).mpr a_left, (div_le_iff₀' hr).mpr a_right⟩, ?_⟩
+ rw [mul_div_cancel₀ _ (ne_of_gt hr)]
+
+theorem smul_Ico : r • Ico a b = Ico (r • a) (r • b) := by
+ ext x
+ simp only [mem_smul_set, smul_eq_mul, mem_Ico]
+ constructor
+ · rintro ⟨a, ⟨a_h_left_left, a_h_left_right⟩, rfl⟩
+ constructor
+ · exact (mul_le_mul_left hr).mpr a_h_left_left
+ · exact (mul_lt_mul_left hr).mpr a_h_left_right
+ · rintro ⟨a_left, a_right⟩
+ use x / r
+ refine ⟨⟨(le_div_iff₀' hr).mpr a_left, (div_lt_iff₀' hr).mpr a_right⟩, ?_⟩
+ rw [mul_div_cancel₀ _ (ne_of_gt hr)]
+
+theorem smul_Ioc : r • Ioc a b = Ioc (r • a) (r • b) := by
+ ext x
+ simp only [mem_smul_set, smul_eq_mul, mem_Ioc]
+ constructor
+ · rintro ⟨a, ⟨a_h_left_left, a_h_left_right⟩, rfl⟩
+ constructor
+ · exact (mul_lt_mul_left hr).mpr a_h_left_left
+ · exact (mul_le_mul_left hr).mpr a_h_left_right
+ · rintro ⟨a_left, a_right⟩
+ use x / r
+ refine ⟨⟨(lt_div_iff₀' hr).mpr a_left, (div_le_iff₀' hr).mpr a_right⟩, ?_⟩
+ rw [mul_div_cancel₀ _ (ne_of_gt hr)]
+
+theorem smul_Ioi : r • Ioi a = Ioi (r • a) := by
+ ext x
+ simp only [mem_smul_set, smul_eq_mul, mem_Ioi]
+ constructor
+ · rintro ⟨a_w, a_h_left, rfl⟩
+ exact (mul_lt_mul_left hr).mpr a_h_left
+ · rintro h
+ use x / r
+ constructor
+ · exact (lt_div_iff₀' hr).mpr h
+ · exact mul_div_cancel₀ _ (ne_of_gt hr)
+
+theorem smul_Iio : r • Iio a = Iio (r • a) := by
+ ext x
+ simp only [mem_smul_set, smul_eq_mul, mem_Iio]
+ constructor
+ · rintro ⟨a_w, a_h_left, rfl⟩
+ exact (mul_lt_mul_left hr).mpr a_h_left
+ · rintro h
+ use x / r
+ constructor
+ · exact (div_lt_iff₀' hr).mpr h
+ · exact mul_div_cancel₀ _ (ne_of_gt hr)
+
+theorem smul_Ici : r • Ici a = Ici (r • a) := by
+ ext x
+ simp only [mem_smul_set, smul_eq_mul, mem_Ioi]
+ constructor
+ · rintro ⟨a_w, a_h_left, rfl⟩
+ exact (mul_le_mul_left hr).mpr a_h_left
+ · rintro h
+ use x / r
+ constructor
+ · exact (le_div_iff₀' hr).mpr h
+ · exact mul_div_cancel₀ _ (ne_of_gt hr)
+
+theorem smul_Iic : r • Iic a = Iic (r • a) := by
+ ext x
+ simp only [mem_smul_set, smul_eq_mul, mem_Iio]
+ constructor
+ · rintro ⟨a_w, a_h_left, rfl⟩
+ exact (mul_le_mul_left hr).mpr a_h_left
+ · rintro h
+ use x / r
+ constructor
+ · exact (div_le_iff₀' hr).mpr h
+ · exact mul_div_cancel₀ _ (ne_of_gt hr)
+
+end LinearOrderedField
diff --git a/Mathlib/Algebra/Order/Field/Power.lean b/Mathlib/Algebra/Order/Field/Power.lean
index 8dfd3676717c3..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_of_one_le 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_of_one_le hb _
+ 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 0431b57d759fd..a05e2fffee157 100644
--- a/Mathlib/Algebra/Order/Floor.lean
+++ b/Mathlib/Algebra/Order/Floor.lean
@@ -11,6 +11,7 @@ import Mathlib.Data.Nat.Cast.Order.Field
import Mathlib.Data.Set.Subsingleton
import Mathlib.Order.GaloisConnection
import Mathlib.Tactic.Abel
+import Mathlib.Tactic.FieldSimp
import Mathlib.Tactic.Linarith
import Mathlib.Tactic.Positivity
@@ -250,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]
@@ -483,7 +482,7 @@ theorem floor_div_nat (a : α) (n : ℕ) : ⌊a / n⌋₊ = ⌊a⌋₊ / n := by
· exact div_nonneg ha n.cast_nonneg
constructor
· exact cast_div_le.trans (div_le_div_of_nonneg_right (floor_le ha) n.cast_nonneg)
- rw [div_lt_iff, add_mul, one_mul, ← cast_mul, ← cast_add, ← floor_lt ha]
+ rw [div_lt_iff₀, add_mul, one_mul, ← cast_mul, ← cast_add, ← floor_lt ha]
· exact lt_div_mul_add hn
· exact cast_pos.2 hn
@@ -499,6 +498,46 @@ theorem floor_div_eq_div (m n : ℕ) : ⌊(m : α) / n⌋₊ = m / n := by
end LinearOrderedSemifield
+section LinearOrderedField
+variable [LinearOrderedField α] [FloorSemiring α] {a b : α}
+
+lemma mul_lt_floor (hb₀ : 0 < b) (hb : b < 1) (hba : ⌈b / (1 - b)⌉₊ ≤ a) : b * a < ⌊a⌋₊ := by
+ calc
+ b * a < b * (⌊a⌋₊ + 1) := by gcongr; exacts [hb₀, lt_floor_add_one _]
+ _ ≤ ⌊a⌋₊ := by
+ rw [_root_.mul_add_one, ← le_sub_iff_add_le', ← one_sub_mul, ← div_le_iff₀' (by linarith),
+ ← ceil_le]
+ exact le_floor hba
+
+lemma ceil_lt_mul (hb : 1 < b) (hba : ⌈(b - 1)⁻¹⌉₊ / b < a) : ⌈a⌉₊ < b * a := by
+ obtain hab | hba := le_total a (b - 1)⁻¹
+ · calc
+ ⌈a⌉₊ ≤ (⌈(b - 1)⁻¹⌉₊ : α) := by gcongr
+ _ < b * a := by rwa [← div_lt_iff₀']; positivity
+ · rw [← sub_pos] at hb
+ calc
+ ⌈a⌉₊ < a + 1 := ceil_lt_add_one <| hba.trans' <| by positivity
+ _ = a + (b - 1) * (b - 1)⁻¹ := by rw [mul_inv_cancel₀]; positivity
+ _ ≤ a + (b - 1) * a := by gcongr; positivity
+ _ = b * a := by rw [sub_one_mul, add_sub_cancel]
+
+lemma ceil_le_mul (hb : 1 < b) (hba : ⌈(b - 1)⁻¹⌉₊ / b ≤ a) : ⌈a⌉₊ ≤ b * a := by
+ obtain rfl | hba := hba.eq_or_lt
+ · rw [mul_div_cancel₀, cast_le, ceil_le]
+ · exact _root_.div_le_self (by positivity) hb.le
+ · positivity
+ · exact (ceil_lt_mul hb hba).le
+
+lemma div_two_lt_floor (ha : 1 ≤ a) : a / 2 < ⌊a⌋₊ := by
+ rw [div_eq_inv_mul]; refine mul_lt_floor ?_ ?_ ?_ <;> norm_num; assumption
+
+lemma ceil_lt_two_mul (ha : 2⁻¹ < a) : ⌈a⌉₊ < 2 * a :=
+ ceil_lt_mul one_lt_two (by norm_num at ha ⊢; exact ha)
+
+lemma ceil_le_two_mul (ha : 2⁻¹ ≤ a) : ⌈a⌉₊ ≤ 2 * a :=
+ ceil_le_mul one_lt_two (by norm_num at ha ⊢; exact ha)
+
+end LinearOrderedField
end Nat
/-- There exists at most one `FloorSemiring` structure on a linear ordered semiring. -/
@@ -883,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 _
@@ -936,7 +973,7 @@ theorem fract_neg {x : α} (hx : fract x ≠ 0) : fract (-x) = 1 - fract x := by
@[simp]
theorem fract_neg_eq_zero {x : α} : fract (-x) = 0 ↔ fract x = 0 := by
- simp only [fract_eq_iff, le_refl, zero_lt_one, tsub_zero, true_and_iff]
+ simp only [fract_eq_iff, le_refl, zero_lt_one, tsub_zero, true_and]
constructor <;> rintro ⟨z, hz⟩ <;> use -z <;> simp [← hz]
theorem fract_mul_nat (a : α) (b : ℕ) : ∃ z : ℤ, fract a * b - fract (a * b) = z := by
@@ -986,7 +1023,7 @@ theorem sub_floor_div_mul_nonneg (a : k) (hb : 0 < b) : 0 ≤ a - ⌊a / b⌋ *
theorem sub_floor_div_mul_lt (a : k) (hb : 0 < b) : a - ⌊a / b⌋ * b < b :=
sub_lt_iff_lt_add.2 <| by
-- Porting note: `← one_add_mul` worked in mathlib3 without the argument
- rw [← one_add_mul _ b, ← div_lt_iff hb, add_comm]
+ rw [← one_add_mul _ b, ← div_lt_iff₀ hb, add_comm]
exact lt_floor_add_one _
theorem fract_div_natCast_eq_div_natCast_mod {m n : ℕ} : fract ((m : k) / n) = ↑(m % n) / n := by
@@ -1013,7 +1050,7 @@ theorem fract_div_intCast_eq_div_intCast_mod {m : ℤ} {n : ℕ} :
obtain ⟨l₀, rfl | rfl⟩ := l.eq_nat_or_neg
· rw [cast_natCast, ← natCast_mod, cast_natCast, fract_div_natCast_eq_div_natCast_mod]
· rw [Right.nonneg_neg_iff, natCast_nonpos_iff] at hl
- simp [hl, zero_mod]
+ simp [hl]
obtain ⟨m₀, rfl | rfl⟩ := m.eq_nat_or_neg
· exact this (ofNat_nonneg m₀)
let q := ⌈↑m₀ / (n : k)⌉
@@ -1070,6 +1107,9 @@ theorem ceil_le_floor_add_one (a : α) : ⌈a⌉ ≤ ⌊a⌋ + 1 := by
theorem le_ceil (a : α) : a ≤ ⌈a⌉ :=
gc_ceil_coe.le_u_l a
+lemma le_ceil_iff : z ≤ ⌈a⌉ ↔ z - 1 < a := by rw [← sub_one_lt_iff, lt_ceil]; norm_cast
+lemma ceil_lt_iff : ⌈a⌉ < z ↔ a ≤ z - 1 := by rw [← le_sub_one_iff, ceil_le]; norm_cast
+
@[simp]
theorem ceil_intCast (z : ℤ) : ⌈(z : α)⌉ = z :=
eq_of_forall_ge_iff fun a => by rw [ceil_le, Int.cast_le]
@@ -1200,6 +1240,56 @@ theorem ceil_sub_self_eq (ha : fract a ≠ 0) : (⌈a⌉ : α) - a = 1 - fract a
rw [(or_iff_right ha).mp (fract_eq_zero_or_add_one_sub_ceil a)]
abel
+section LinearOrderedField
+variable {k : Type*} [LinearOrderedField k] [FloorRing k] {a b : k}
+
+lemma mul_lt_floor (hb₀ : 0 < b) (hb : b < 1) (hba : ⌈b / (1 - b)⌉ ≤ a) : b * a < ⌊a⌋ := by
+ calc
+ b * a < b * (⌊a⌋ + 1) := by gcongr; exacts [hb₀, lt_floor_add_one _]
+ _ ≤ ⌊a⌋ := by
+ rwa [_root_.mul_add_one, ← le_sub_iff_add_le', ← one_sub_mul, ← div_le_iff₀' (by linarith),
+ ← ceil_le, le_floor]
+
+lemma ceil_div_ceil_inv_sub_one (ha : 1 ≤ a) : ⌈⌈(a - 1)⁻¹⌉ / a⌉ = ⌈(a - 1)⁻¹⌉ := by
+ obtain rfl | ha := ha.eq_or_lt
+ · simp
+ have : 0 < a - 1 := by linarith
+ 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_of_one_lt₀ ha)]
+ convert ceil_lt_add_one _ using 1
+ field_simp
+
+lemma ceil_lt_mul (hb : 1 < b) (hba : ⌈(b - 1)⁻¹⌉ / b < a) : ⌈a⌉ < b * a := by
+ obtain hab | hba := le_total a (b - 1)⁻¹
+ · calc
+ ⌈a⌉ ≤ (⌈(b - 1)⁻¹⌉ : k) := by gcongr
+ _ < b * a := by rwa [← div_lt_iff₀']; positivity
+ · rw [← sub_pos] at hb
+ calc
+ ⌈a⌉ < a + 1 := ceil_lt_add_one _
+ _ = a + (b - 1) * (b - 1)⁻¹ := by rw [mul_inv_cancel₀]; positivity
+ _ ≤ a + (b - 1) * a := by gcongr; positivity
+ _ = b * a := by rw [sub_one_mul, add_sub_cancel]
+
+lemma ceil_le_mul (hb : 1 < b) (hba : ⌈(b - 1)⁻¹⌉ / b ≤ a) : ⌈a⌉ ≤ b * a := by
+ obtain rfl | hba := hba.eq_or_lt
+ · rw [ceil_div_ceil_inv_sub_one hb.le, mul_div_cancel₀]
+ positivity
+ · exact (ceil_lt_mul hb hba).le
+
+lemma div_two_lt_floor (ha : 1 ≤ a) : a / 2 < ⌊a⌋ := by
+ rw [div_eq_inv_mul]; refine mul_lt_floor ?_ ?_ ?_ <;> norm_num; assumption
+
+lemma ceil_lt_two_mul (ha : 2⁻¹ < a) : ⌈a⌉ < 2 * a :=
+ ceil_lt_mul one_lt_two (by norm_num at ha ⊢; exact ha)
+
+lemma ceil_le_two_mul (ha : 2⁻¹ ≤ a) : ⌈a⌉ ≤ 2 * a :=
+ ceil_le_mul one_lt_two (by norm_num at ha ⊢; exact ha)
+
+end LinearOrderedField
+
/-! #### Intervals -/
@[simp]
@@ -1359,7 +1449,7 @@ section LinearOrderedField
variable [LinearOrderedField α] [FloorRing α]
theorem round_eq (x : α) : round x = ⌊x + 1 / 2⌋ := by
- simp_rw [round, (by simp only [lt_div_iff', two_pos] : 2 * fract x < 1 ↔ fract x < 1 / 2)]
+ simp_rw [round, (by simp only [lt_div_iff₀', two_pos] : 2 * fract x < 1 ↔ fract x < 1 / 2)]
cases' lt_or_le (fract x) (1 / 2) with hx hx
· conv_rhs => rw [← fract_add_floor x, add_assoc, add_left_comm, floor_int_add]
rw [if_pos hx, self_eq_add_right, floor_eq_iff, cast_zero, zero_add]
@@ -1490,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]
@@ -1600,4 +1690,4 @@ def evalIntCeil : PositivityExt where eval {u α} _zα _pα e := do
end Mathlib.Meta.Positivity
-set_option linter.style.longFile 1700
+set_option linter.style.longFile 1800
diff --git a/Mathlib/Algebra/Order/Floor/Div.lean b/Mathlib/Algebra/Order/Floor/Div.lean
index 35d76dbf57197..20b853e6e5f94 100644
--- a/Mathlib/Algebra/Order/Floor/Div.lean
+++ b/Mathlib/Algebra/Order/Floor/Div.lean
@@ -119,7 +119,7 @@ end OrderedAddCommMonoid
section LinearOrderedAddCommMonoid
variable [LinearOrderedAddCommMonoid α] [OrderedAddCommMonoid β] [SMulZeroClass α β]
- [PosSMulReflectLE α β] [FloorDiv α β] [CeilDiv α β] {a : α} {b c : β}
+ [PosSMulReflectLE α β] [FloorDiv α β] [CeilDiv α β] {a : α} {b : β}
lemma floorDiv_le_ceilDiv : b ⌊/⌋ a ≤ b ⌈/⌉ a := by
obtain ha | ha := le_or_lt a 0
diff --git a/Mathlib/Algebra/Order/Floor/Prime.lean b/Mathlib/Algebra/Order/Floor/Prime.lean
index 6c418d3d3d34b..506029de21811 100644
--- a/Mathlib/Algebra/Order/Floor/Prime.lean
+++ b/Mathlib/Algebra/Order/Floor/Prime.lean
@@ -3,40 +3,44 @@ 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.Order.Floor
-import Mathlib.Data.Nat.Prime.Basic
+import Mathlib.Data.Nat.Prime.Infinite
+import Mathlib.Topology.Algebra.Order.Floor
/-!
# Existence of a sufficiently large prime for which `a * c ^ p / (p - 1)! < 1`
This is a technical result used in the proof of the Lindemann-Weierstrass theorem.
--/
-namespace FloorRing
+TODO: delete this file, as all its lemmas have been deprecated.
+-/
open scoped Nat
+@[deprecated eventually_mul_pow_lt_factorial_sub (since := "2024-09-25")]
+theorem Nat.exists_prime_mul_pow_lt_factorial (n a c : ℕ) :
+ ∃ p > n, p.Prime ∧ a * c ^ p < (p - 1)! :=
+ ((Filter.frequently_atTop.mpr Nat.exists_infinite_primes).and_eventually
+ (eventually_mul_pow_lt_factorial_sub a c 1)).forall_exists_of_atTop (n + 1)
+
+namespace FloorRing
+
variable {K : Type*}
+@[deprecated FloorSemiring.eventually_mul_pow_lt_factorial_sub (since := "2024-09-25")]
theorem exists_prime_mul_pow_lt_factorial [LinearOrderedRing K] [FloorRing K] (n : ℕ) (a c : K) :
- ∃ p > n, p.Prime ∧ a * c ^ p < (p - 1)! := by
- obtain ⟨p, pn, pp, h⟩ := n.exists_prime_mul_pow_lt_factorial ⌈|a|⌉.natAbs ⌈|c|⌉.natAbs
- use p, pn, pp
- calc a * c ^ p
- _ ≤ |a * c ^ p| := le_abs_self _
- _ ≤ ⌈|a|⌉ * (⌈|c|⌉ : K) ^ p := ?_
- _ = ↑(Int.natAbs ⌈|a|⌉ * Int.natAbs ⌈|c|⌉ ^ p) := ?_
- _ < ↑(p - 1)! := Nat.cast_lt.mpr h
- · rw [abs_mul, abs_pow]
- gcongr <;> try first | positivity | apply Int.le_ceil
- · simp_rw [Nat.cast_mul, Nat.cast_pow, Int.cast_natAbs,
- abs_eq_self.mpr (Int.ceil_nonneg (abs_nonneg (_ : K)))]
+ ∃ p > n, p.Prime ∧ a * c ^ p < (p - 1)! :=
+ ((Filter.frequently_atTop.mpr Nat.exists_infinite_primes).and_eventually
+ (FloorSemiring.eventually_mul_pow_lt_factorial_sub a c 1)).forall_exists_of_atTop (n + 1)
+@[deprecated FloorSemiring.tendsto_mul_pow_div_factorial_sub_atTop (since := "2024-09-25")]
theorem exists_prime_mul_pow_div_factorial_lt_one [LinearOrderedField K] [FloorRing K]
(n : ℕ) (a c : K) :
- ∃ p > n, p.Prime ∧ a * c ^ p / (p - 1)! < 1 := by
- simp_rw [div_lt_one (α := K) (Nat.cast_pos.mpr (Nat.factorial_pos _))]
- exact exists_prime_mul_pow_lt_factorial ..
+ ∃ p > n, p.Prime ∧ a * c ^ p / (p - 1)! < 1 :=
+ letI := Preorder.topology K
+ haveI : OrderTopology K := ⟨rfl⟩
+ ((Filter.frequently_atTop.mpr Nat.exists_infinite_primes).and_eventually
+ (eventually_lt_of_tendsto_lt zero_lt_one
+ (FloorSemiring.tendsto_mul_pow_div_factorial_sub_atTop a c 1))).forall_exists_of_atTop
+ (n + 1)
end FloorRing
diff --git a/Mathlib/Algebra/Order/Group/Abs.lean b/Mathlib/Algebra/Order/Group/Abs.lean
index 3d6763c037cfa..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 _)
@@ -94,7 +94,7 @@ theorem apply_abs_le_mul_of_one_le {β : Type*} [MulOneClass β] [Preorder β]
theorem abs_add (a b : α) : |a + b| ≤ |a| + |b| :=
abs_le.2
⟨(neg_add |a| |b|).symm ▸
- add_le_add ((@neg_le α ..).2 <| neg_le_abs _) ((@neg_le α ..).2 <| neg_le_abs _),
+ add_le_add (neg_le.2 <| neg_le_abs _) (neg_le.2 <| neg_le_abs _),
add_le_add (le_abs_self _) (le_abs_self _)⟩
theorem abs_add' (a b : α) : |a| ≤ |b| + |b + a| := by simpa using abs_add (-b) (b + a)
@@ -122,7 +122,7 @@ theorem sub_lt_of_abs_sub_lt_right (h : |a - b| < c) : a - c < b :=
sub_lt_of_abs_sub_lt_left (abs_sub_comm a b ▸ h)
theorem abs_sub_abs_le_abs_sub (a b : α) : |a| - |b| ≤ |a - b| :=
- (@sub_le_iff_le_add α ..).2 <|
+ sub_le_iff_le_add.2 <|
calc
|a| = |a - b + b| := by rw [sub_add_cancel]
_ ≤ |a - b| + |b| := abs_add _ _
diff --git a/Mathlib/Algebra/Order/Group/Basic.lean b/Mathlib/Algebra/Order/Group/Basic.lean
index 449dd1fe025dc..09aac4f739e3c 100644
--- a/Mathlib/Algebra/Order/Group/Basic.lean
+++ b/Mathlib/Algebra/Order/Group/Basic.lean
@@ -15,35 +15,37 @@ assert_not_exists Set.Subsingleton
open Function Int
-variable {α M R : Type*}
+variable {α : Type*}
section OrderedCommGroup
variable [OrderedCommGroup α] {m n : ℤ} {a b : α}
+@[to_additive zsmul_left_strictMono]
+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]
+ exact lt_mul_of_one_lt_right' (a ^ n) ha
+
+@[deprecated (since := "2024-09-19")] alias zsmul_strictMono_left := zsmul_left_strictMono
+
@[to_additive zsmul_pos] lemma one_lt_zpow' (ha : 1 < a) (hn : 0 < n) : 1 < a ^ n := by
- obtain ⟨n, rfl⟩ := Int.eq_ofNat_of_zero_le hn.le
- rw [zpow_natCast]
- refine one_lt_pow' ha ?_
- rintro rfl
- simp at hn
-
-@[to_additive zsmul_strictMono_left]
-lemma zpow_right_strictMono (ha : 1 < a) : StrictMono fun n : ℤ ↦ a ^ n := fun m n h ↦
- calc
- a ^ m = a ^ m * 1 := (mul_one _).symm
- _ < a ^ m * a ^ (n - m) := mul_lt_mul_left' (one_lt_zpow' ha <| Int.sub_pos_of_lt h) _
- _ = a ^ n := by simp [← zpow_add, m.add_comm]
+ simpa using zpow_right_strictMono ha hn
+
+@[to_additive zsmul_left_strictAnti]
+lemma zpow_right_strictAnti (ha : a < 1) : StrictAnti fun n : ℤ ↦ a ^ n := by
+ refine strictAnti_int_of_succ_lt fun n ↦ ?_
+ rw [zpow_add_one]
+ exact mul_lt_of_lt_one_right' (a ^ n) ha
@[to_additive zsmul_left_inj]
lemma zpow_right_inj (ha : 1 < a) {m n : ℤ} : a ^ m = a ^ n ↔ m = n :=
(zpow_right_strictMono ha).injective.eq_iff
@[to_additive zsmul_mono_left]
-lemma zpow_mono_right (ha : 1 ≤ a) : Monotone fun n : ℤ ↦ a ^ n := fun m n h ↦
- calc
- a ^ m = a ^ m * 1 := (mul_one _).symm
- _ ≤ a ^ m * a ^ (n - m) := mul_le_mul_left' (one_le_zpow ha <| Int.sub_nonneg_of_le h) _
- _ = a ^ n := by simp [← zpow_add, m.add_comm]
+lemma zpow_mono_right (ha : 1 ≤ a) : Monotone fun n : ℤ ↦ a ^ n := by
+ refine monotone_int_of_le_succ fun n ↦ ?_
+ rw [zpow_add_one]
+ exact le_mul_of_one_le_right' ha
@[to_additive (attr := gcongr)]
lemma zpow_le_zpow (ha : 1 ≤ a) (h : m ≤ n) : a ^ m ≤ a ^ n := zpow_mono_right ha h
diff --git a/Mathlib/Algebra/Order/Group/CompleteLattice.lean b/Mathlib/Algebra/Order/Group/CompleteLattice.lean
new file mode 100644
index 0000000000000..69e9649b537de
--- /dev/null
+++ b/Mathlib/Algebra/Order/Group/CompleteLattice.lean
@@ -0,0 +1,49 @@
+/-
+Copyright (c) 2021 Yury G. Kudryashov. All rights reserved.
+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.Indexed
+
+/-!
+# Distributivity of group operations over supremum/infimum
+-/
+
+open Function Set
+
+variable {ι G : Type*} [Group G] [ConditionallyCompleteLattice G] [Nonempty ι] {f : ι → G}
+
+section Right
+variable [MulRightMono G]
+
+@[to_additive]
+lemma ciSup_mul (hf : BddAbove (range f)) (a : G) : (⨆ i, f i) * a = ⨆ i, f i * a :=
+ (OrderIso.mulRight a).map_ciSup hf
+
+@[to_additive]
+lemma ciSup_div (hf : BddAbove (range f)) (a : G) : (⨆ i, f i) / a = ⨆ i, f i / a := by
+ simp only [div_eq_mul_inv, ciSup_mul hf]
+
+@[to_additive]
+lemma ciInf_mul (hf : BddBelow (range f)) (a : G) : (⨅ i, f i) * a = ⨅ i, f i * a :=
+ (OrderIso.mulRight a).map_ciInf hf
+
+@[to_additive]
+lemma ciInf_div (hf : BddBelow (range f)) (a : G) : (⨅ i, f i) / a = ⨅ i, f i / a := by
+ simp only [div_eq_mul_inv, ciInf_mul hf]
+
+end Right
+
+section Left
+variable [MulLeftMono G]
+
+@[to_additive]
+lemma mul_ciSup (hf : BddAbove (range f)) (a : G) : (a * ⨆ i, f i) = ⨆ i, a * f i :=
+ (OrderIso.mulLeft a).map_ciSup hf
+
+@[to_additive]
+lemma mul_ciInf (hf : BddBelow (range f)) (a : G) : (a * ⨅ i, f i) = ⨅ i, a * f i :=
+ (OrderIso.mulLeft a).map_ciInf hf
+
+end Left
diff --git a/Mathlib/Algebra/Order/Group/Cone.lean b/Mathlib/Algebra/Order/Group/Cone.lean
index 4cf5650b2afb0..5f110e86b0c0e 100644
--- a/Mathlib/Algebra/Order/Group/Cone.lean
+++ b/Mathlib/Algebra/Order/Group/Cone.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2017 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Scott Morrison, Artie Khovanov
+Authors: Mario Carneiro, Kim Morrison, Artie Khovanov
-/
import Mathlib.Algebra.Order.Group.Defs
import Mathlib.Algebra.Order.Monoid.Submonoid
@@ -18,13 +18,13 @@ cones in groups and the corresponding ordered groups.
-/
/-- `AddGroupConeClass S G` says that `S` is a type of cones in `G`. -/
-class AddGroupConeClass (S G : Type*) [AddCommGroup G] [SetLike S G] extends
- AddSubmonoidClass S G : Prop where
+class AddGroupConeClass (S : Type*) (G : outParam Type*) [AddCommGroup G] [SetLike S G]
+ extends AddSubmonoidClass S G : Prop where
eq_zero_of_mem_of_neg_mem {C : S} {a : G} : a ∈ C → -a ∈ C → a = 0
/-- `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 a47229cb3489f..d18bd57fc7cfe 100644
--- a/Mathlib/Algebra/Order/Group/Defs.lean
+++ b/Mathlib/Algebra/Order/Group/Defs.lean
@@ -21,9 +21,9 @@ The reason is that we did not want to change existing names in the library.
-/
/-
-`NeZero` should not be needed at this point in the ordered algebraic hierarchy.
+`NeZero` theory should not be needed at this point in the ordered algebraic hierarchy.
-/
-assert_not_exists NeZero
+assert_not_imported Mathlib.Algebra.NeZero
open Function
@@ -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 :=
@@ -175,13 +175,11 @@ variable [OrderedCommGroup α] {a b : α}
@[to_additive (attr := gcongr) neg_le_neg]
theorem inv_le_inv' : a ≤ b → b⁻¹ ≤ a⁻¹ :=
- -- Porting note: explicit type annotation was not needed before.
- (@inv_le_inv_iff α ..).mpr
+ inv_le_inv_iff.mpr
@[to_additive (attr := gcongr) neg_lt_neg]
theorem inv_lt_inv' : a < b → b⁻¹ < a⁻¹ :=
- -- Porting note: explicit type annotation was not needed before.
- (@inv_lt_inv_iff α ..).mpr
+ inv_lt_inv_iff.mpr
-- The additive version is also a `linarith` lemma.
@[to_additive]
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 6ae4c61cca65e..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
@@ -106,18 +106,25 @@ lemma mulIndicator_le_mulIndicator' (h : a ∈ s → f a ≤ g a) :
mulIndicator s f a ≤ mulIndicator s g a :=
mulIndicator_rel_mulIndicator le_rfl h
-@[to_additive]
+@[to_additive (attr := mono, gcongr)]
lemma mulIndicator_le_mulIndicator (h : f a ≤ g a) : mulIndicator s f a ≤ mulIndicator s g a :=
mulIndicator_rel_mulIndicator le_rfl fun _ ↦ h
-attribute [mono] mulIndicator_le_mulIndicator indicator_le_indicator
+@[to_additive (attr := gcongr)]
+lemma mulIndicator_mono (h : f ≤ g) : s.mulIndicator f ≤ s.mulIndicator g :=
+ fun _ ↦ mulIndicator_le_mulIndicator (h _)
@[to_additive]
-lemma mulIndicator_le_mulIndicator_of_subset (h : s ⊆ t) (hf : ∀ a, 1 ≤ f a) (a : α) :
+lemma mulIndicator_le_mulIndicator_apply_of_subset (h : s ⊆ t) (hf : 1 ≤ f a) :
mulIndicator s f a ≤ mulIndicator t f a :=
mulIndicator_apply_le'
(fun ha ↦ le_mulIndicator_apply (fun _ ↦ le_rfl) fun hat ↦ (hat <| h ha).elim) fun _ ↦
- one_le_mulIndicator_apply fun _ ↦ hf _
+ one_le_mulIndicator_apply fun _ ↦ hf
+
+@[to_additive]
+lemma mulIndicator_le_mulIndicator_of_subset (h : s ⊆ t) (hf : 1 ≤ f) :
+ mulIndicator s f ≤ mulIndicator t f :=
+ fun _ ↦ mulIndicator_le_mulIndicator_apply_of_subset h (hf _)
@[to_additive]
lemma mulIndicator_le_self' (hf : ∀ x ∉ s, 1 ≤ f x) : mulIndicator s f ≤ f :=
@@ -174,6 +181,23 @@ lemma mulIndicator_iInter_apply (h1 : (⊥ : M) = 1) (s : ι → Set α) (f : α
refine le_antisymm (by simp only [← h1, le_iInf_iff, bot_le, forall_const]) ?_
simpa [mulIndicator_of_not_mem hj] using (iInf_le (fun i ↦ (s i).mulIndicator f) j) x
+@[to_additive]
+lemma iSup_mulIndicator {ι : Type*} [Preorder ι] [IsDirected ι (· ≤ ·)] {f : ι → α → M}
+ {s : ι → Set α} (h1 : (⊥ : M) = 1) (hf : Monotone f) (hs : Monotone s) :
+ ⨆ i, (s i).mulIndicator (f i) = (⋃ i, s i).mulIndicator (⨆ i, f i) := by
+ simp only [le_antisymm_iff, iSup_le_iff]
+ refine ⟨fun i ↦ (mulIndicator_mono (le_iSup _ _)).trans (mulIndicator_le_mulIndicator_of_subset
+ (subset_iUnion _ _) (fun _ ↦ by simp [← h1])), fun a ↦ ?_⟩
+ by_cases ha : a ∈ ⋃ i, s i
+ · obtain ⟨i, hi⟩ : ∃ i, a ∈ s i := by simpa using ha
+ rw [mulIndicator_of_mem ha, iSup_apply, iSup_apply]
+ refine iSup_le fun j ↦ ?_
+ obtain ⟨k, hik, hjk⟩ := exists_ge_ge i j
+ refine le_iSup_of_le k <| (hf hjk _).trans_eq ?_
+ rw [mulIndicator_of_mem (hs hik hi)]
+ · rw [mulIndicator_of_not_mem ha, ← h1]
+ exact bot_le
+
end CompleteLattice
section CanonicallyOrderedCommMonoid
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 4e53be43c3ca4..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)]
@@ -30,19 +30,17 @@ end
section LinearOrderedCommGroup
-variable {α : Type*} [LinearOrderedCommGroup α] {a b c : α}
+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
@@ -64,7 +62,7 @@ end LinearOrderedCommGroup
section LinearOrderedAddCommGroup
-variable {α : Type*} [LinearOrderedAddCommGroup α] {a b c : α}
+variable {α : Type*} [LinearOrderedAddCommGroup α]
theorem max_sub_max_le_max (a b c d : α) : max a b - max c d ≤ max (a - c) (b - d) := by
simp only [sub_le_iff_le_add, max_le_iff]; constructor
diff --git a/Mathlib/Algebra/Order/Group/Opposite.lean b/Mathlib/Algebra/Order/Group/Opposite.lean
new file mode 100644
index 0000000000000..e145f616c4c11
--- /dev/null
+++ b/Mathlib/Algebra/Order/Group/Opposite.lean
@@ -0,0 +1,85 @@
+/-
+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.Order.Group.Defs
+import Mathlib.Algebra.Group.Opposite
+
+/-!
+# Order instances for `MulOpposite`/`AddOpposite`
+
+This files transfers order instances and ordered monoid/group instances from `α` to `αᵐᵒᵖ` and
+`αᵃᵒᵖ`.
+-/
+
+variable {α : Type*}
+
+namespace MulOpposite
+section Preorder
+variable [Preorder α]
+
+@[to_additive] instance : Preorder αᵐᵒᵖ := Preorder.lift unop
+
+@[to_additive (attr := simp)] lemma unop_le_unop {a b : αᵐᵒᵖ} : a.unop ≤ b.unop ↔ a ≤ b := .rfl
+@[to_additive (attr := simp)] lemma op_le_op {a b : α} : op a ≤ op b ↔ a ≤ b := .rfl
+
+end Preorder
+
+@[to_additive] instance [PartialOrder α] : PartialOrder αᵐᵒᵖ := PartialOrder.lift _ unop_injective
+
+section OrderedCommMonoid
+variable [OrderedCommMonoid α]
+
+@[to_additive] instance : OrderedCommMonoid αᵐᵒᵖ where
+ mul_le_mul_left a b hab c := mul_le_mul_right' (by simpa) c.unop
+
+@[to_additive (attr := simp)] lemma unop_le_one {a : αᵐᵒᵖ} : unop a ≤ 1 ↔ a ≤ 1 := .rfl
+@[to_additive (attr := simp)] lemma one_le_unop {a : αᵐᵒᵖ} : 1 ≤ unop a ↔ 1 ≤ a := .rfl
+@[to_additive (attr := simp)] lemma op_le_one {a : α} : op a ≤ 1 ↔ a ≤ 1 := .rfl
+@[to_additive (attr := simp)] lemma one_le_op {a : α} : 1 ≤ op a ↔ 1 ≤ a := .rfl
+
+end OrderedCommMonoid
+
+@[to_additive] instance [OrderedCommGroup α] : OrderedCommGroup αᵐᵒᵖ where
+ __ := instCommGroup
+ __ := instOrderedCommMonoid
+
+section OrderedAddCommMonoid
+variable [OrderedAddCommMonoid α]
+
+instance : OrderedAddCommMonoid αᵐᵒᵖ where
+ add_le_add_left a b hab c := add_le_add_left (by simpa) c.unop
+
+@[simp] lemma unop_nonneg {a : αᵐᵒᵖ} : unop a ≤ 0 ↔ a ≤ 0 := .rfl
+@[simp] lemma unop_nonpos {a : αᵐᵒᵖ} : 0 ≤ unop a ↔ 0 ≤ a := .rfl
+@[simp] lemma op_nonneg {a : α} : op a ≤ 0 ↔ a ≤ 0 := .rfl
+@[simp] lemma op_nonpos {a : α} : 0 ≤ op a ↔ 0 ≤ a := .rfl
+
+end OrderedAddCommMonoid
+
+instance [OrderedAddCommGroup α] : OrderedAddCommGroup αᵐᵒᵖ where
+ __ := instAddCommGroup
+ __ := instOrderedAddCommMonoid
+
+end MulOpposite
+
+namespace AddOpposite
+section OrderedCommMonoid
+variable [OrderedCommMonoid α]
+
+instance : OrderedCommMonoid αᵃᵒᵖ where
+ mul_le_mul_left a b hab c := mul_le_mul_left' (by simpa) c.unop
+
+@[simp] lemma unop_le_one {a : αᵃᵒᵖ} : unop a ≤ 1 ↔ a ≤ 1 := .rfl
+@[simp] lemma one_le_unop {a : αᵃᵒᵖ} : 1 ≤ unop a ↔ 1 ≤ a := .rfl
+@[simp] lemma op_le_one {a : α} : op a ≤ 1 ↔ a ≤ 1 := .rfl
+@[simp] lemma one_le_op {a : α} : 1 ≤ op a ↔ 1 ≤ a := .rfl
+
+end OrderedCommMonoid
+
+instance [OrderedCommGroup α] : OrderedCommGroup αᵃᵒᵖ where
+ __ := instCommGroup
+ __ := instOrderedCommMonoid
+
+end AddOpposite
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
new file mode 100644
index 0000000000000..d7e523a2a6595
--- /dev/null
+++ b/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean
@@ -0,0 +1,117 @@
+/-
+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.Algebra.Group.Pointwise.Set.Basic
+import Mathlib.Algebra.Order.Group.OrderIso
+import Mathlib.Algebra.Order.Monoid.Unbundled.OrderDual
+import Mathlib.Order.Bounds.OrderIso
+
+/-!
+# Upper/lower bounds in ordered monoids and groups
+
+In this file we prove a few facts like “`-s` is bounded above iff `s` is bounded below”
+(`bddAbove_neg`).
+-/
+
+open Function Set
+open scoped Pointwise
+
+variable {ι G M : Type*}
+
+section Mul
+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) :
+ a * b ∈ upperBounds (s * t) := forall_image2_iff.2 fun _ hx _ hy => mul_le_mul' (ha hx) (hb hy)
+
+@[to_additive]
+lemma subset_upperBounds_mul (s t : Set M) : upperBounds s * upperBounds t ⊆ upperBounds (s * t) :=
+ image2_subset_iff.2 fun _ hx _ hy => mul_mem_upperBounds_mul hx hy
+
+@[to_additive]
+lemma mul_mem_lowerBounds_mul (ha : a ∈ lowerBounds s) (hb : b ∈ lowerBounds t) :
+ a * b ∈ lowerBounds (s * t) := mul_mem_upperBounds_mul (M := Mᵒᵈ) ha hb
+
+@[to_additive]
+lemma subset_lowerBounds_mul (s t : Set M) : lowerBounds s * lowerBounds t ⊆ lowerBounds (s * t) :=
+ subset_upperBounds_mul (M := Mᵒᵈ) _ _
+
+@[to_additive]
+lemma BddAbove.mul (hs : BddAbove s) (ht : BddAbove t) : BddAbove (s * t) :=
+ (Nonempty.mul hs ht).mono (subset_upperBounds_mul s t)
+
+@[to_additive]
+lemma BddBelow.mul (hs : BddBelow s) (ht : BddBelow t) : BddBelow (s * t) :=
+ (Nonempty.mul hs ht).mono (subset_lowerBounds_mul s t)
+
+@[to_additive]
+lemma BddAbove.range_mul (hf : BddAbove (range f)) (hg : BddAbove (range g)) :
+ BddAbove (range fun i ↦ f i * g i) :=
+ .range_comp (f := fun i ↦ (f i, g i)) (bddAbove_range_prod.2 ⟨hf, hg⟩)
+ (monotone_fst.mul' monotone_snd)
+
+@[to_additive]
+lemma BddBelow.range_mul (hf : BddBelow (range f)) (hg : BddBelow (range g)) :
+ BddBelow (range fun i ↦ f i * g i) := BddAbove.range_mul (M := Mᵒᵈ) hf hg
+
+end Mul
+
+section InvNeg
+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 :=
+ (OrderIso.inv G).bddAbove_preimage
+
+@[to_additive (attr := simp)]
+theorem bddBelow_inv : BddBelow s⁻¹ ↔ BddAbove s :=
+ (OrderIso.inv G).bddBelow_preimage
+
+@[to_additive]
+theorem BddAbove.inv (h : BddAbove s) : BddBelow s⁻¹ :=
+ bddBelow_inv.2 h
+
+@[to_additive]
+theorem BddBelow.inv (h : BddBelow s) : BddAbove s⁻¹ :=
+ bddAbove_inv.2 h
+
+@[to_additive (attr := simp)]
+theorem isLUB_inv : IsLUB s⁻¹ a ↔ IsGLB s a⁻¹ :=
+ (OrderIso.inv G).isLUB_preimage
+
+@[to_additive]
+theorem isLUB_inv' : IsLUB s⁻¹ a⁻¹ ↔ IsGLB s a :=
+ (OrderIso.inv G).isLUB_preimage'
+
+@[to_additive]
+theorem IsGLB.inv (h : IsGLB s a) : IsLUB s⁻¹ a⁻¹ :=
+ isLUB_inv'.2 h
+
+@[to_additive (attr := simp)]
+theorem isGLB_inv : IsGLB s⁻¹ a ↔ IsLUB s a⁻¹ :=
+ (OrderIso.inv G).isGLB_preimage
+
+@[to_additive]
+theorem isGLB_inv' : IsGLB s⁻¹ a⁻¹ ↔ IsLUB s a :=
+ (OrderIso.inv G).isGLB_preimage'
+
+@[to_additive]
+theorem IsLUB.inv (h : IsLUB s a) : IsGLB s⁻¹ a⁻¹ :=
+ isGLB_inv'.2 h
+
+@[to_additive]
+lemma BddBelow.range_inv {α : Type*} {f : α → G} (hf : BddBelow (range f)) :
+ BddAbove (range (fun x => (f x)⁻¹)) :=
+ hf.range_comp (OrderIso.inv G).monotone
+
+@[to_additive]
+lemma BddAbove.range_inv {α : Type*} {f : α → G} (hf : BddAbove (range f)) :
+ BddBelow (range (fun x => (f x)⁻¹)) :=
+ BddBelow.range_inv (G := Gᵒᵈ) hf
+
+end InvNeg
diff --git a/Mathlib/Algebra/Order/Group/Pointwise/CompleteLattice.lean b/Mathlib/Algebra/Order/Group/Pointwise/CompleteLattice.lean
new file mode 100644
index 0000000000000..64ef925d173b5
--- /dev/null
+++ b/Mathlib/Algebra/Order/Group/Pointwise/CompleteLattice.lean
@@ -0,0 +1,117 @@
+/-
+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.Algebra.Order.Group.Pointwise.Bounds
+import Mathlib.Order.ConditionallyCompleteLattice.Indexed
+
+/-!
+# Infima/suprema in ordered monoids and groups
+
+In this file we prove a few facts like “The infimum of `-s` is `-` the supremum of `s`”.
+
+## TODO
+
+`sSup (s • t) = sSup s • sSup t` and `sInf (s • t) = sInf s • sInf t` hold as well but
+`CovariantClass` is currently not polymorphic enough to state it.
+-/
+
+open Function Set
+open scoped Pointwise
+
+variable {ι G M : Type*}
+
+section ConditionallyCompleteLattice
+variable [ConditionallyCompleteLattice M]
+
+section One
+variable [One M]
+
+@[to_additive (attr := simp)] lemma csSup_one : sSup (1 : Set M) = 1 := csSup_singleton _
+@[to_additive (attr := simp)] lemma csInf_one : sInf (1 : Set M) = 1 := csInf_singleton _
+
+end One
+
+section Group
+variable [Group M] [MulLeftMono M] [MulRightMono M]
+ {s t : Set M}
+
+@[to_additive]
+lemma csSup_inv (hs₀ : s.Nonempty) (hs₁ : BddBelow s) : sSup s⁻¹ = (sInf s)⁻¹ := by
+ rw [← image_inv]
+ exact ((OrderIso.inv _).map_csInf' hs₀ hs₁).symm
+
+@[to_additive]
+lemma csInf_inv (hs₀ : s.Nonempty) (hs₁ : BddAbove s) : sInf s⁻¹ = (sSup s)⁻¹ := by
+ rw [← image_inv]
+ exact ((OrderIso.inv _).map_csSup' hs₀ hs₁).symm
+
+@[to_additive]
+lemma csSup_mul (hs₀ : s.Nonempty) (hs₁ : BddAbove s) (ht₀ : t.Nonempty) (ht₁ : BddAbove t) :
+ sSup (s * t) = sSup s * sSup t :=
+ csSup_image2_eq_csSup_csSup (fun _ => (OrderIso.mulRight _).to_galoisConnection)
+ (fun _ => (OrderIso.mulLeft _).to_galoisConnection) hs₀ hs₁ ht₀ ht₁
+
+@[to_additive]
+lemma csInf_mul (hs₀ : s.Nonempty) (hs₁ : BddBelow s) (ht₀ : t.Nonempty) (ht₁ : BddBelow t) :
+ sInf (s * t) = sInf s * sInf t :=
+ csInf_image2_eq_csInf_csInf (fun _ => (OrderIso.mulRight _).symm.to_galoisConnection)
+ (fun _ => (OrderIso.mulLeft _).symm.to_galoisConnection) hs₀ hs₁ ht₀ ht₁
+
+@[to_additive]
+lemma csSup_div (hs₀ : s.Nonempty) (hs₁ : BddAbove s) (ht₀ : t.Nonempty) (ht₁ : BddBelow t) :
+ sSup (s / t) = sSup s / sInf t := by
+ rw [div_eq_mul_inv, csSup_mul hs₀ hs₁ ht₀.inv ht₁.inv, csSup_inv ht₀ ht₁, div_eq_mul_inv]
+
+@[to_additive]
+lemma csInf_div (hs₀ : s.Nonempty) (hs₁ : BddBelow s) (ht₀ : t.Nonempty) (ht₁ : BddAbove t) :
+ sInf (s / t) = sInf s / sSup t := by
+ rw [div_eq_mul_inv, csInf_mul hs₀ hs₁ ht₀.inv ht₁.inv, csInf_inv ht₀ ht₁, div_eq_mul_inv]
+
+end Group
+end ConditionallyCompleteLattice
+
+section CompleteLattice
+variable [CompleteLattice M]
+
+section One
+variable [One M]
+
+@[to_additive] lemma sSup_one : sSup (1 : Set M) = 1 := sSup_singleton
+@[to_additive] lemma sInf_one : sInf (1 : Set M) = 1 := sInf_singleton
+
+end One
+
+section Group
+variable [Group M] [MulLeftMono M] [MulRightMono M]
+ (s t : Set M)
+
+@[to_additive]
+lemma sSup_inv (s : Set M) : sSup s⁻¹ = (sInf s)⁻¹ := by
+ rw [← image_inv, sSup_image]
+ exact ((OrderIso.inv M).map_sInf _).symm
+
+@[to_additive]
+lemma sInf_inv (s : Set M) : sInf s⁻¹ = (sSup s)⁻¹ := by
+ rw [← image_inv, sInf_image]
+ exact ((OrderIso.inv M).map_sSup _).symm
+
+@[to_additive]
+lemma sSup_mul : sSup (s * t) = sSup s * sSup t :=
+ (sSup_image2_eq_sSup_sSup fun _ => (OrderIso.mulRight _).to_galoisConnection) fun _ =>
+ (OrderIso.mulLeft _).to_galoisConnection
+
+@[to_additive]
+lemma sInf_mul : sInf (s * t) = sInf s * sInf t :=
+ (sInf_image2_eq_sInf_sInf fun _ => (OrderIso.mulRight _).symm.to_galoisConnection) fun _ =>
+ (OrderIso.mulLeft _).symm.to_galoisConnection
+
+@[to_additive]
+lemma sSup_div : sSup (s / t) = sSup s / sInf t := by simp_rw [div_eq_mul_inv, sSup_mul, sSup_inv]
+
+@[to_additive]
+lemma sInf_div : sInf (s / t) = sInf s / sSup t := by simp_rw [div_eq_mul_inv, sInf_mul, sInf_inv]
+
+end Group
+end CompleteLattice
diff --git a/Mathlib/Algebra/Order/Group/PosPart.lean b/Mathlib/Algebra/Order/Group/PosPart.lean
index 078e76ef92cb4..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,34 +37,35 @@ positive part, negative part
open Function
-variable {α β : Type*}
+variable {α : Type*}
section Lattice
variable [Lattice α]
section Group
-variable [Group α] {a : α}
+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
-@[inherit_doc] postfix:max "⁺ᵐ " => oneLePart
-@[inherit_doc] postfix:max "⁻ᵐ" => leOnePart
-@[inherit_doc] postfix:max "⁺" => posPart
-@[inherit_doc] postfix:max "⁻" => negPart
+@[to_additive] lemma leOnePart_def (a : α) : a⁻ᵐ = a⁻¹ ⊔ 1 := rfl
-@[to_additive] lemma oneLePart_mono : Monotone (oneLePart : α → α) :=
+@[to_additive] lemma oneLePart_def (a : α) : a⁺ᵐ = a ⊔ 1 := rfl
+
+@[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,43 +108,56 @@ 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]
-section covariantmulop
-variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)]
+@[to_additive]
+lemma oneLePart_leOnePart_injective : Injective fun a : α ↦ (a⁺ᵐ, a⁻ᵐ) := by
+ simp only [Injective, Prod.mk.injEq, and_imp]
+ rintro a b hpos hneg
+ rw [← oneLePart_div_leOnePart a, ← oneLePart_div_leOnePart b, hpos, hneg]
+
+@[to_additive]
+lemma oneLePart_leOnePart_inj : a⁺ᵐ = b⁺ᵐ ∧ a⁻ᵐ = b⁻ᵐ ↔ a = b :=
+ Prod.mk.inj_iff.symm.trans oneLePart_leOnePart_injective.eq_iff
+
+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
@@ -157,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
@@ -200,37 +210,44 @@ end CommGroup
end Lattice
section LinearOrder
-variable [LinearOrder α] [Group α] {a : α}
+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 [MulRightMono α]
+
+@[to_additive (attr := simp)] lemma leOnePart_lt : a⁻ᵐ < b ↔ b⁻¹ < a ∧ 1 < b :=
+ sup_lt_iff.trans <| by rw [inv_lt']
+
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/Unbundled/Int.lean b/Mathlib/Algebra/Order/Group/Unbundled/Int.lean
index 773e4ce5f46eb..96c6eed502379 100644
--- a/Mathlib/Algebra/Order/Group/Unbundled/Int.lean
+++ b/Mathlib/Algebra/Order/Group/Unbundled/Int.lean
@@ -82,6 +82,15 @@ theorem abs_le_one_iff {a : ℤ} : |a| ≤ 1 ↔ a = 0 ∨ a = 1 ∨ a = -1 := b
theorem one_le_abs {z : ℤ} (h₀ : z ≠ 0) : 1 ≤ |z| :=
add_one_le_iff.mpr (abs_pos.mpr h₀)
+lemma eq_zero_of_abs_lt_dvd {m x : ℤ} (h1 : m ∣ x) (h2 : |x| < m) : x = 0 := by
+ by_contra h
+ have := Int.natAbs_le_of_dvd_ne_zero h1 h
+ rw [Int.abs_eq_natAbs] at h2
+ omega
+
+lemma abs_sub_lt_of_lt_lt {m a b : ℕ} (ha : a < m) (hb : b < m) : |(b : ℤ) - a| < m := by
+ rw [abs_lt]; omega
+
/-! #### `/` -/
theorem ediv_eq_zero_of_lt_abs {a b : ℤ} (H1 : 0 ≤ a) (H2 : a < |b|) : a / b = 0 :=
diff --git a/Mathlib/Algebra/Order/Group/Units.lean b/Mathlib/Algebra/Order/Group/Units.lean
index eaf081e0b36ab..c32449fad0ca7 100644
--- a/Mathlib/Algebra/Order/Group/Units.lean
+++ b/Mathlib/Algebra/Order/Group/Units.lean
@@ -20,8 +20,12 @@ 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 _) }
+ 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
+/-- 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
+linearly ordered commutative additive group."]
+instance Units.instLinearOrderedCommGroup [LinearOrderedCommMonoid α] :
+ LinearOrderedCommGroup αˣ where
+ __ := Units.instLinearOrder
+ __ := Units.orderedCommGroup
diff --git a/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean b/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean
index d7eab9e094013..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.
@@ -130,11 +130,6 @@ instance (priority := 100) LinearOrderedCommGroupWithZero.toMulPosStrictMono :
MulPosStrictMono α where
elim a b c hbc := by by_contra! h; exact hbc.not_le <| (mul_le_mul_right a.2).1 h
-/-- Alias of `mul_le_one'` for unification. -/
-@[deprecated mul_le_one' (since := "2024-08-21")]
-theorem mul_le_one₀ (ha : a ≤ 1) (hb : b ≤ 1) : a * b ≤ 1 :=
- mul_le_one' ha hb
-
/-- Alias of `one_le_mul'` for unification. -/
@[deprecated one_le_mul (since := "2024-08-21")]
theorem one_le_mul₀ (ha : 1 ≤ a) (hb : 1 ≤ b) : 1 ≤ a * b :=
@@ -185,25 +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_one₀ (ha : a ≠ 0) : a⁻¹ < 1 ↔ 1 < a :=
- inv_lt_one' (a := Units.mk0 a ha)
-
-theorem one_lt_inv₀ (ha : a ≠ 0) : 1 < a⁻¹ ↔ a < 1 :=
- one_lt_inv' (a := Units.mk0 a ha)
-
-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
@@ -219,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.`.
@@ -245,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
@@ -263,8 +238,6 @@ lemma pow_lt_pow_succ (ha : 1 < a) : a ^ n < a ^ n.succ := by
lemma pow_lt_pow_right₀ (ha : 1 < a) (hmn : m < n) : a ^ m < a ^ n := by
induction' hmn with n _ ih; exacts [pow_lt_pow_succ ha, lt_trans ih (pow_lt_pow_succ ha)]
-@[deprecated (since := "2023-12-23")] alias pow_lt_pow₀ := pow_lt_pow_right₀
-
end LinearOrderedCommGroupWithZero
instance instLinearOrderedCommMonoidWithZeroMultiplicativeOrderDual
@@ -313,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 _
@@ -322,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]
@@ -354,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
@@ -374,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]
@@ -400,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. -/
@@ -431,3 +402,13 @@ instance instLinearOrderedCommGroupWithZero [LinearOrderedCommGroup α] :
__ := commGroupWithZero
end WithZero
+
+section MultiplicativeNotation
+
+/-- Notation for `WithZero (Multiplicative ℕ)` -/
+scoped[Multiplicative] notation "ℕₘ₀" => WithZero (Multiplicative ℕ)
+
+/-- Notation for `WithZero (Multiplicative ℤ)` -/
+scoped[Multiplicative] notation "ℤₘ₀" => WithZero (Multiplicative ℤ)
+
+end MultiplicativeNotation
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 29e087b5c4728..d773fa40a750e 100644
--- a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean
+++ b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean
@@ -7,7 +7,8 @@ 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.GCongr.Core
+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,12 +938,16 @@ section MonoidWithZero
variable [MonoidWithZero M₀]
section Preorder
-variable [Preorder M₀] {a b c d : 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
| n + 1 => pow_succ a n ▸ mul_nonneg (pow_nonneg ha _) ha
+lemma zero_pow_le_one [ZeroLEOneClass M₀] : ∀ n : ℕ, (0 : M₀) ^ n ≤ 1
+ | 0 => (pow_zero _).le
+ | n + 1 => by rw [zero_pow n.succ_ne_zero]; exact zero_le_one
+
lemma pow_le_pow_of_le_one [ZeroLEOneClass M₀] [PosMulMono M₀] [MulPosMono M₀] (ha₀ : 0 ≤ a)
(ha₁ : a ≤ 1) : ∀ {m n : ℕ}, m ≤ n → a ^ n ≤ a ^ m
| _, _, Nat.le.refl => le_rfl
@@ -958,9 +965,6 @@ lemma sq_le [ZeroLEOneClass M₀] [PosMulMono M₀] [MulPosMono M₀] (h₀ : 0
lemma one_le_mul_of_one_le_of_one_le [ZeroLEOneClass M₀] [PosMulMono M₀] (ha : 1 ≤ a) (hb : 1 ≤ b) :
(1 : M₀) ≤ a * b := Left.one_le_mul_of_le_of_le ha hb <| zero_le_one.trans ha
-lemma mul_le_one [ZeroLEOneClass M₀] [PosMulMono M₀] [MulPosMono M₀] (ha : a ≤ 1) (hb₀ : 0 ≤ b)
- (hb : b ≤ 1) : a * b ≤ 1 := one_mul (1 : M₀) ▸ mul_le_mul ha hb hb₀ zero_le_one
-
lemma one_lt_mul_of_le_of_lt [ZeroLEOneClass M₀] [MulPosMono M₀] (ha : 1 ≤ a) (hb : 1 < b) :
1 < a * b := hb.trans_le <| le_mul_of_one_le_left (zero_le_one.trans hb.le) ha
@@ -975,6 +979,43 @@ lemma mul_lt_one_of_nonneg_of_lt_one_left [PosMulMono M₀] (ha₀ : 0 ≤ a) (h
lemma mul_lt_one_of_nonneg_of_lt_one_right [MulPosMono M₀] (ha : a ≤ 1) (hb₀ : 0 ≤ b) (hb : b < 1) :
a * b < 1 := (mul_le_of_le_one_left hb₀ ha).trans_lt hb
+section
+variable [ZeroLEOneClass M₀] [PosMulMono M₀] [MulPosMono M₀]
+
+lemma mul_le_one₀ (ha : a ≤ 1) (hb₀ : 0 ≤ b) (hb : b ≤ 1) : a * b ≤ 1 :=
+ one_mul (1 : M₀) ▸ mul_le_mul ha hb hb₀ zero_le_one
+
+lemma pow_le_one₀ : ∀ {n : ℕ}, 0 ≤ a → a ≤ 1 → a ^ n ≤ 1
+ | 0, _, _ => (pow_zero a).le
+ | n + 1, h₀, h₁ => (pow_succ a n).le.trans (mul_le_one₀ (pow_le_one₀ h₀ h₁) h₀ h₁)
+
+lemma pow_lt_one₀ (h₀ : 0 ≤ a) (h₁ : a < 1) : ∀ {n : ℕ}, n ≠ 0 → a ^ n < 1
+ | 0, h => (h rfl).elim
+ | n + 1, _ => by
+ rw [pow_succ']; exact mul_lt_one_of_nonneg_of_lt_one_left h₀ h₁ (pow_le_one₀ h₀ h₁.le)
+
+lemma one_le_pow₀ (ha : 1 ≤ a) : ∀ {n : ℕ}, 1 ≤ a ^ n
+ | 0 => by rw [pow_zero]
+ | n + 1 => by
+ simpa only [pow_succ', mul_one]
+ using mul_le_mul ha (one_le_pow₀ ha) zero_le_one (zero_le_one.trans ha)
+
+lemma one_lt_pow₀ (ha : 1 < a) : ∀ {n : ℕ}, n ≠ 0 → 1 < a ^ n
+ | 0, h => (h rfl).elim
+ | n + 1, _ => by rw [pow_succ']; exact one_lt_mul_of_lt_of_le ha (one_le_pow₀ ha.le)
+
+lemma pow_right_mono₀ (h : 1 ≤ a) : Monotone (a ^ ·) :=
+ monotone_nat_of_le_succ fun n => by
+ rw [pow_succ']; exact le_mul_of_one_le_left (pow_nonneg (zero_le_one.trans h) _) h
+
+@[gcongr]
+lemma pow_le_pow_right₀ (ha : 1 ≤ a) (hmn : m ≤ n) : a ^ m ≤ a ^ n := pow_right_mono₀ ha hmn
+
+lemma le_self_pow₀ (ha : 1 ≤ a) (hn : n ≠ 0) : a ≤ a ^ n := by
+ simpa only [pow_one] using pow_le_pow_right₀ ha <| Nat.pos_iff_ne_zero.2 hn
+
+end
+
variable [Preorder α] {f g : α → M₀}
lemma monotone_mul_left_of_nonneg [PosMulMono M₀] (ha : 0 ≤ a) : Monotone fun x ↦ a * x :=
@@ -1007,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
@@ -1113,8 +1154,16 @@ end CancelMonoidWithZero
section GroupWithZero
variable [GroupWithZero G₀]
+section Preorder
+variable [Preorder G₀] [ZeroLEOneClass G₀]
+
+/-- See `div_self` for the version with equality when `a ≠ 0`. -/
+lemma div_self_le_one (a : G₀) : a / a ≤ 1 := by obtain rfl | ha := eq_or_ne a 0 <;> simp [*]
+
+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⟩
@@ -1142,17 +1191,21 @@ 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
mp h := by simpa [hc.ne'] using mul_le_mul_of_nonneg_left h hc.le
mpr h := by simpa [hc.ne'] using mul_le_mul_of_nonneg_left h (inv_nonneg.2 hc.le)
+/-- See `inv_mul_le_iff₀'` for a version with multiplication on the other side. -/
lemma inv_mul_le_iff₀ (hc : 0 < c) : c⁻¹ * b ≤ a ↔ b ≤ c * a where
mp h := by simpa [hc.ne'] using mul_le_mul_of_nonneg_left h hc.le
mpr h := by simpa [hc.ne'] using mul_le_mul_of_nonneg_left h (inv_nonneg.2 hc.le)
@@ -1160,89 +1213,445 @@ 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]
+/-- 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
+ obtain rfl | hc := hc.eq_or_lt
+ · simpa using hb
+ · rwa [le_inv_mul_iff₀ hc] at h
+
+/-- One direction of `inv_mul_le_iff₀` where `b` is allowed to be `0` (but `c` must be nonnegative).
+-/
+lemma inv_mul_le_of_le_mul₀ (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ b * c) : b⁻¹ * a ≤ c := by
+ obtain rfl | hb := hb.eq_or_lt
+ · 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
variable [MulPosMono G₀]
+/-- See `le_mul_inv_iff₀'` for a version with multiplication on the other side. -/
lemma le_mul_inv_iff₀ (hc : 0 < c) : a ≤ b * c⁻¹ ↔ a * c ≤ b where
mp h := by simpa [hc.ne'] using mul_le_mul_of_nonneg_right h hc.le
mpr h := by simpa [hc.ne'] using mul_le_mul_of_nonneg_right h (inv_nonneg.2 hc.le)
+/-- See `mul_inv_le_iff₀'` for a version with multiplication on the other side. -/
lemma mul_inv_le_iff₀ (hc : 0 < c) : b * c⁻¹ ≤ a ↔ b ≤ a * c where
mp h := by simpa [hc.ne'] using mul_le_mul_of_nonneg_right h hc.le
mpr h := by simpa [hc.ne'] using mul_le_mul_of_nonneg_right h (inv_nonneg.2 hc.le)
+/-- See `le_div_iff₀'` for a version with multiplication on the other side. -/
lemma le_div_iff₀ (hc : 0 < c) : a ≤ b / c ↔ a * c ≤ b := by
rw [div_eq_mul_inv, le_mul_inv_iff₀ hc]
+/-- See `div_le_iff₀'` for a version with multiplication on the other side. -/
lemma div_le_iff₀ (hc : 0 < c) : b / c ≤ a ↔ b ≤ a * c := by
rw [div_eq_mul_inv, mul_inv_le_iff₀ hc]
+/-- 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
+ obtain rfl | hc := hc.eq_or_lt
+ · simpa using hb
+ · rwa [le_mul_inv_iff₀ hc] at h
+
+/-- One direction of `mul_inv_le_iff₀` where `b` is allowed to be `0` (but `c` must be nonnegative).
+-/
+lemma mul_inv_le_of_le_mul₀ (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ c * b) : a * b⁻¹ ≤ c := by
+ obtain rfl | hb := hb.eq_or_lt
+ · simp [hc]
+ · rwa [mul_inv_le_iff₀ hb]
+
+/-- One direction of `le_div_iff₀` where `c` is allowed to be `0` (but `b` must be nonnegative). -/
+lemma mul_le_of_le_div₀ (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ b / c) : a * c ≤ b :=
+ mul_le_of_le_mul_inv₀ hb hc (div_eq_mul_inv b _ ▸ h)
+
+/-- One direction of `div_le_iff₀` where `b` is allowed to be `0` (but `c` must be nonnegative). -/
+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₀] {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
+ 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_mul_lt_iff₀'` for a version with multiplication on the other side. -/
+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)
+
+@[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
+
+section MulPosStrictMono
+variable [MulPosStrictMono G₀]
+
+/-- See `lt_mul_inv_iff₀'` for a version with multiplication on the other side. -/
+lemma lt_mul_inv_iff₀ (hc : 0 < c) : a < b * c⁻¹ ↔ a * c < b where
+ mp h := by simpa [hc.ne'] using mul_lt_mul_of_pos_right h hc
+ mpr h := by simpa [hc.ne'] using mul_lt_mul_of_pos_right h (inv_pos.2 hc)
+
+/-- See `mul_inv_lt_iff₀'` for a version with multiplication on the other side. -/
+lemma mul_inv_lt_iff₀ (hc : 0 < c) : b * c⁻¹ < a ↔ b < a * c where
+ mp h := by simpa [hc.ne'] using mul_lt_mul_of_pos_right h hc
+ mpr h := by simpa [hc.ne'] using mul_lt_mul_of_pos_right h (inv_pos.2 hc)
+
+/-- See `lt_div_iff₀'` for a version with multiplication on the other side. -/
+lemma lt_div_iff₀ (hc : 0 < c) : a < b / c ↔ a * c < b := by
+ rw [div_eq_mul_inv, lt_mul_inv_iff₀ hc]
+
+/-- See `div_le_iff₀'` for a version with multiplication on the other side. -/
+lemma div_lt_iff₀ (hc : 0 < c) : b / c < a ↔ b < a * c := by
+ rw [div_eq_mul_inv, mul_inv_lt_iff₀ 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 < 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
-variable [Mul α] [IsSymmOp α α (· * ·)] [Zero α] [Preorder α]
+variable [Mul α] [@Std.Commutative α (· * ·)] [Zero α] [Preorder α]
theorem posMulStrictMono_iff_mulPosStrictMono : PosMulStrictMono α ↔ MulPosStrictMono α := by
- simp only [PosMulStrictMono, MulPosStrictMono, IsSymmOp.symm_op]
+ simp only [PosMulStrictMono, MulPosStrictMono, Std.Commutative.comm]
theorem posMulReflectLT_iff_mulPosReflectLT : PosMulReflectLT α ↔ MulPosReflectLT α := by
- simp only [PosMulReflectLT, MulPosReflectLT, IsSymmOp.symm_op]
+ simp only [PosMulReflectLT, MulPosReflectLT, Std.Commutative.comm]
theorem posMulMono_iff_mulPosMono : PosMulMono α ↔ MulPosMono α := by
- simp only [PosMulMono, MulPosMono, IsSymmOp.symm_op]
+ simp only [PosMulMono, MulPosMono, Std.Commutative.comm]
theorem posMulReflectLE_iff_mulPosReflectLE : PosMulReflectLE α ↔ MulPosReflectLE α := by
- simp only [PosMulReflectLE, MulPosReflectLE, IsSymmOp.symm_op]
+ simp only [PosMulReflectLE, MulPosReflectLE, Std.Commutative.comm]
end CommSemigroupHasZero
section CommGroupWithZero
variable [CommGroupWithZero G₀]
-variable [PartialOrder G₀] [ZeroLEOneClass G₀] [PosMulReflectLT G₀] [MulPosMono G₀] {a b c d : G₀}
+variable [PartialOrder G₀] [ZeroLEOneClass G₀] [PosMulReflectLT G₀]
+
+section PosMulMono
+variable [PosMulMono G₀] {a b c d : G₀}
+
+/-- 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 := by
+ rw [le_inv_mul_iff₀ hc, mul_comm]
+
+/-- See `inv_mul_le_iff₀` for a version with multiplication on the other side. -/
+lemma inv_mul_le_iff₀' (hc : 0 < c) : c⁻¹ * b ≤ a ↔ b ≤ a * c := by
+ rw [inv_mul_le_iff₀ hc, mul_comm]
+
+/-- See `le_mul_inv_iff₀` for a version with multiplication on the other side. -/
+lemma le_mul_inv_iff₀' (hc : 0 < c) : a ≤ b * c⁻¹ ↔ c * a ≤ b := by
+ have := posMulMono_iff_mulPosMono.1 ‹_›
+ rw [le_mul_inv_iff₀ hc, mul_comm]
+
+/-- See `mul_inv_le_iff₀` for a version with multiplication on the other side. -/
+lemma mul_inv_le_iff₀' (hc : 0 < c) : b * c⁻¹ ≤ a ↔ b ≤ c * a := by
+ have := posMulMono_iff_mulPosMono.1 ‹_›
+ rw [mul_inv_le_iff₀ hc, mul_comm]
lemma div_le_div₀ (hb : 0 < b) (hd : 0 < d) :
a / b ≤ c / d ↔ a * d ≤ c * b := by
+ have := posMulMono_iff_mulPosMono.1 ‹_›
rw [div_le_iff₀ hb, ← mul_div_right_comm, le_div_iff₀ hd]
-lemma le_div_iff₀' (hc : 0 < c) : a ≤ b / c ↔ c * a ≤ b := by rw [le_div_iff₀ hc, mul_comm]
-lemma div_le_iff₀' (hc : 0 < c) : b / c ≤ a ↔ b ≤ c * a := by rw [div_le_iff₀ hc, mul_comm]
+/-- See `le_div_iff₀` for a version with multiplication on the other side. -/
+lemma le_div_iff₀' (hc : 0 < c) : a ≤ b / c ↔ c * a ≤ b := by
+ have := posMulMono_iff_mulPosMono.1 ‹_›
+ rw [le_div_iff₀ hc, mul_comm]
+
+/-- See `div_le_iff₀` for a version with multiplication on the other side. -/
+lemma div_le_iff₀' (hc : 0 < c) : b / c ≤ a ↔ b ≤ c * a := by
+ have := posMulMono_iff_mulPosMono.1 ‹_›
+ rw [div_le_iff₀ hc, mul_comm]
lemma le_div_comm₀ (ha : 0 < a) (hc : 0 < c) : a ≤ b / c ↔ c ≤ b / a := by
+ have := posMulMono_iff_mulPosMono.1 ‹_›
rw [le_div_iff₀ ha, le_div_iff₀' hc]
lemma div_le_comm₀ (hb : 0 < b) (hc : 0 < c) : a / b ≤ c ↔ a / c ≤ b := by
+ have := posMulMono_iff_mulPosMono.1 ‹_›
rw [div_le_iff₀ hb, div_le_iff₀' hc]
@[deprecated (since := "2024-08-21")] alias le_div_iff' := le_div_iff₀'
@[deprecated (since := "2024-08-21")] alias div_le_iff' := div_le_iff₀'
+end PosMulMono
+
+section PosMulStrictMono
+variable [PosMulStrictMono G₀] {a b c : G₀}
+
+/-- 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 ↔ a * c < b := by
+ rw [lt_inv_mul_iff₀ hc, mul_comm]
+
+/-- See `inv_mul_lt_iff₀` for a version with multiplication on the other side. -/
+lemma inv_mul_lt_iff₀' (hc : 0 < c) : c⁻¹ * b < a ↔ b < a * c := by
+ rw [inv_mul_lt_iff₀ hc, mul_comm]
+
+/-- See `lt_mul_inv_iff₀` for a version with multiplication on the other side. -/
+lemma lt_mul_inv_iff₀' (hc : 0 < c) : a < b * c⁻¹ ↔ c * a < b := by
+ have := posMulStrictMono_iff_mulPosStrictMono.1 ‹_›
+ rw [lt_mul_inv_iff₀ hc, mul_comm]
+
+/-- See `mul_inv_lt_iff₀` for a version with multiplication on the other side. -/
+lemma mul_inv_lt_iff₀' (hc : 0 < c) : b * c⁻¹ < a ↔ b < c * a := by
+ have := posMulStrictMono_iff_mulPosStrictMono.1 ‹_›
+ rw [mul_inv_lt_iff₀ hc, mul_comm]
+
+/-- See `lt_div_iff₀` for a version with multiplication on the other side. -/
+lemma lt_div_iff₀' (hc : 0 < c) : a < b / c ↔ c * a < b := by
+ have := posMulStrictMono_iff_mulPosStrictMono.1 ‹_›
+ rw [lt_div_iff₀ hc, mul_comm]
+
+/-- See `div_lt_iff₀` for a version with multiplication on the other side. -/
+lemma div_lt_iff₀' (hc : 0 < c) : b / c < a ↔ b < c * a := by
+ have := posMulStrictMono_iff_mulPosStrictMono.1 ‹_›
+ rw [div_lt_iff₀ hc, mul_comm]
+
+lemma lt_div_comm₀ (ha : 0 < a) (hc : 0 < c) : a < b / c ↔ c < b / a := by
+ have := posMulStrictMono_iff_mulPosStrictMono.1 ‹_›
+ rw [lt_div_iff₀ ha, lt_div_iff₀' hc]
+
+lemma div_lt_comm₀ (hb : 0 < b) (hc : 0 < c) : a / b < c ↔ a / c < b := by
+ have := posMulStrictMono_iff_mulPosStrictMono.1 ‹_›
+ rw [div_lt_iff₀ hb, div_lt_iff₀' hc]
+
+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
new file mode 100644
index 0000000000000..0bbdd7163e56c
--- /dev/null
+++ b/Mathlib/Algebra/Order/GroupWithZero/Unbundled/Lemmas.lean
@@ -0,0 +1,27 @@
+/-
+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.Pi.Basic
+import Mathlib.Algebra.Order.GroupWithZero.Unbundled
+import Mathlib.Algebra.GroupWithZero.Units.Equiv
+import Mathlib.Order.Hom.Basic
+
+/-!
+# Multiplication by a positive element as an order isomorphism
+-/
+
+variable {G₀} [GroupWithZero G₀] [Preorder G₀] [ZeroLEOneClass G₀] {a : G₀}
+
+/-- `Equiv.mulLeft₀` as an order isomorphism. -/
+@[simps! (config := { simpRhs := true })]
+def OrderIso.mulLeft₀ [PosMulMono G₀] [PosMulReflectLE G₀] (a : G₀) (ha : 0 < a) : G₀ ≃o G₀ where
+ toEquiv := .mulLeft₀ a ha.ne'
+ map_rel_iff' := mul_le_mul_left ha
+
+/-- `Equiv.mulRight₀` as an order isomorphism. -/
+@[simps! (config := { simpRhs := true })]
+def OrderIso.mulRight₀ [MulPosMono G₀] [MulPosReflectLE G₀] (a : G₀) (ha : 0 < a) : G₀ ≃o G₀ where
+ toEquiv := .mulRight₀ a ha.ne'
+ map_rel_iff' := mul_le_mul_right ha
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 dbcb880887ff3..a90bc7fe9e004 100644
--- a/Mathlib/Algebra/Order/Hom/Basic.lean
+++ b/Mathlib/Algebra/Order/Hom/Basic.lean
@@ -73,29 +73,33 @@ variable {ι F α β γ δ : Type*}
/-! ### Basics -/
/-- `NonnegHomClass F α β` states that `F` is a type of nonnegative morphisms. -/
-class NonnegHomClass (F α β : Type*) [Zero β] [LE β] [FunLike F α β] : Prop where
+class NonnegHomClass (F : Type*) (α β : outParam Type*) [Zero β] [LE β] [FunLike F α β] : Prop where
/-- the image of any element is non negative. -/
apply_nonneg (f : F) : ∀ a, 0 ≤ f a
/-- `SubadditiveHomClass F α β` states that `F` is a type of subadditive morphisms. -/
-class SubadditiveHomClass (F α β : Type*) [Add α] [Add β] [LE β] [FunLike F α β] : Prop where
+class SubadditiveHomClass (F : Type*) (α β : outParam Type*)
+ [Add α] [Add β] [LE β] [FunLike F α β] : Prop where
/-- the image of a sum is less or equal than the sum of the images. -/
map_add_le_add (f : F) : ∀ a b, f (a + b) ≤ f a + f b
/-- `SubmultiplicativeHomClass F α β` states that `F` is a type of submultiplicative morphisms. -/
@[to_additive SubadditiveHomClass]
-class SubmultiplicativeHomClass (F α β : Type*) [Mul α] [Mul β] [LE β] [FunLike F α β] : Prop where
+class SubmultiplicativeHomClass (F : Type*) (α β : outParam (Type*)) [Mul α] [Mul β] [LE β]
+ [FunLike F α β] : Prop where
/-- the image of a product is less or equal than the product of the images. -/
map_mul_le_mul (f : F) : ∀ a b, f (a * b) ≤ f a * f b
/-- `MulLEAddHomClass F α β` states that `F` is a type of subadditive morphisms. -/
@[to_additive SubadditiveHomClass]
-class MulLEAddHomClass (F α β : Type*) [Mul α] [Add β] [LE β] [FunLike F α β] : Prop where
+class MulLEAddHomClass (F : Type*) (α β : outParam Type*) [Mul α] [Add β] [LE β] [FunLike F α β] :
+ Prop where
/-- the image of a product is less or equal than the sum of the images. -/
map_mul_le_add (f : F) : ∀ a b, f (a * b) ≤ f a + f b
/-- `NonarchimedeanHomClass F α β` states that `F` is a type of non-archimedean morphisms. -/
-class NonarchimedeanHomClass (F α β : Type*) [Add α] [LinearOrder β] [FunLike F α β] : Prop where
+class NonarchimedeanHomClass (F : Type*) (α β : outParam Type*)
+ [Add α] [LinearOrder β] [FunLike F α β] : Prop where
/-- the image of a sum is less or equal than the maximum of the images. -/
map_add_le_max (f : F) : ∀ a b, f (a + b) ≤ max (f a) (f b)
@@ -154,7 +158,8 @@ end Mathlib.Meta.Positivity
group `α`.
You should extend this class when you extend `AddGroupSeminorm`. -/
-class AddGroupSeminormClass (F α β : Type*) [AddGroup α] [OrderedAddCommMonoid β] [FunLike F α β]
+class AddGroupSeminormClass (F : Type*) (α β : outParam Type*)
+ [AddGroup α] [OrderedAddCommMonoid β] [FunLike F α β]
extends SubadditiveHomClass F α β : Prop where
/-- The image of zero is zero. -/
map_zero (f : F) : f 0 = 0
@@ -165,7 +170,8 @@ class AddGroupSeminormClass (F α β : Type*) [AddGroup α] [OrderedAddCommMonoi
You should extend this class when you extend `GroupSeminorm`. -/
@[to_additive]
-class GroupSeminormClass (F α β : Type*) [Group α] [OrderedAddCommMonoid β] [FunLike F α β]
+class GroupSeminormClass (F : Type*) (α β : outParam Type*)
+ [Group α] [OrderedAddCommMonoid β] [FunLike F α β]
extends MulLEAddHomClass F α β : Prop where
/-- The image of one is zero. -/
map_one_eq_zero (f : F) : f 1 = 0
@@ -176,7 +182,8 @@ class GroupSeminormClass (F α β : Type*) [Group α] [OrderedAddCommMonoid β]
`α`.
You should extend this class when you extend `AddGroupNorm`. -/
-class AddGroupNormClass (F α β : Type*) [AddGroup α] [OrderedAddCommMonoid β] [FunLike F α β]
+class AddGroupNormClass (F : Type*) (α β : outParam Type*)
+ [AddGroup α] [OrderedAddCommMonoid β] [FunLike F α β]
extends AddGroupSeminormClass F α β : Prop where
/-- The argument is zero if its image under the map is zero. -/
eq_zero_of_map_eq_zero (f : F) {a : α} : f a = 0 → a = 0
@@ -185,7 +192,8 @@ class AddGroupNormClass (F α β : Type*) [AddGroup α] [OrderedAddCommMonoid β
You should extend this class when you extend `GroupNorm`. -/
@[to_additive]
-class GroupNormClass (F α β : Type*) [Group α] [OrderedAddCommMonoid β] [FunLike F α β]
+class GroupNormClass (F : Type*) (α β : outParam Type*)
+ [Group α] [OrderedAddCommMonoid β] [FunLike F α β]
extends GroupSeminormClass F α β : Prop where
/-- The argument is one if its image under the map is zero. -/
eq_one_of_map_eq_zero (f : F) {a : α} : f a = 0 → a = 1
@@ -275,20 +283,23 @@ theorem map_pos_of_ne_one [Group α] [LinearOrderedAddCommMonoid β] [GroupNormC
/-- `RingSeminormClass F α` states that `F` is a type of `β`-valued seminorms on the ring `α`.
You should extend this class when you extend `RingSeminorm`. -/
-class RingSeminormClass (F α β : Type*) [NonUnitalNonAssocRing α] [OrderedSemiring β]
- [FunLike F α β] extends AddGroupSeminormClass F α β, SubmultiplicativeHomClass F α β : Prop
+class RingSeminormClass (F : Type*) (α β : outParam Type*)
+ [NonUnitalNonAssocRing α] [OrderedSemiring β] [FunLike F α β]
+ extends AddGroupSeminormClass F α β, SubmultiplicativeHomClass F α β : Prop
/-- `RingNormClass F α` states that `F` is a type of `β`-valued norms on the ring `α`.
You should extend this class when you extend `RingNorm`. -/
-class RingNormClass (F α β : Type*) [NonUnitalNonAssocRing α] [OrderedSemiring β] [FunLike F α β]
+class RingNormClass (F : Type*) (α β : outParam Type*)
+ [NonUnitalNonAssocRing α] [OrderedSemiring β] [FunLike F α β]
extends RingSeminormClass F α β, AddGroupNormClass F α β : Prop
/-- `MulRingSeminormClass F α` states that `F` is a type of `β`-valued multiplicative seminorms
on the ring `α`.
You should extend this class when you extend `MulRingSeminorm`. -/
-class MulRingSeminormClass (F α β : Type*) [NonAssocRing α] [OrderedSemiring β] [FunLike F α β]
+class MulRingSeminormClass (F : Type*) (α β : outParam Type*)
+ [NonAssocRing α] [OrderedSemiring β] [FunLike F α β]
extends AddGroupSeminormClass F α β, MonoidWithZeroHomClass F α β : Prop
-- Lower the priority of these instances since they require synthesizing an order structure.
@@ -299,7 +310,8 @@ attribute [instance 50]
ring `α`.
You should extend this class when you extend `MulRingNorm`. -/
-class MulRingNormClass (F α β : Type*) [NonAssocRing α] [OrderedSemiring β] [FunLike F α β]
+class MulRingNormClass (F : Type*) (α β : outParam Type*)
+ [NonAssocRing α] [OrderedSemiring β] [FunLike F α β]
extends MulRingSeminormClass F α β, AddGroupNormClass F α β : Prop
-- See note [out-param inheritance]
@@ -311,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 53c70afe40a7b..a8d682494ed1f 100644
--- a/Mathlib/Algebra/Order/Interval/Basic.lean
+++ b/Mathlib/Algebra/Order/Interval/Basic.lean
@@ -3,9 +3,10 @@ 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.Set
+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/Interval/Set/Instances.lean b/Mathlib/Algebra/Order/Interval/Set/Instances.lean
index ff54fbdebf8a3..4624971afef4b 100644
--- a/Mathlib/Algebra/Order/Interval/Set/Instances.lean
+++ b/Mathlib/Algebra/Order/Interval/Set/Instances.lean
@@ -1,9 +1,10 @@
/-
Copyright (c) 2022 Stuart Presnell. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stuart Presnell, Eric Wieser, Yaël Dillies, Patrick Massot, Scott Morrison
+Authors: Stuart Presnell, Eric Wieser, Yaël Dillies, Patrick Massot, Kim Morrison
-/
-import Mathlib.Algebra.Order.Ring.Basic
+import Mathlib.Algebra.GroupWithZero.InjSurj
+import Mathlib.Algebra.Order.Ring.Defs
import Mathlib.Algebra.Ring.Regular
import Mathlib.Order.Interval.Set.Basic
@@ -98,10 +99,10 @@ theorem le_one {t : Icc (0 : α) 1} : t ≤ 1 :=
t.2.2
instance mul : Mul (Icc (0 : α) 1) where
- mul p q := ⟨p * q, ⟨mul_nonneg p.2.1 q.2.1, mul_le_one p.2.2 q.2.1 q.2.2⟩⟩
+ mul p q := ⟨p * q, ⟨mul_nonneg p.2.1 q.2.1, mul_le_one₀ p.2.2 q.2.1 q.2.2⟩⟩
instance pow : Pow (Icc (0 : α) 1) ℕ where
- pow p n := ⟨p.1 ^ n, ⟨pow_nonneg p.2.1 n, pow_le_one n p.2.1 p.2.2⟩⟩
+ pow p n := ⟨p.1 ^ n, ⟨pow_nonneg p.2.1 n, pow_le_one₀ p.2.1 p.2.2⟩⟩
@[simp, norm_cast]
theorem coe_mul (x y : Icc (0 : α) 1) : ↑(x * y) = (x * y : α) :=
@@ -236,10 +237,10 @@ theorem le_one {t : Ioc (0 : α) 1} : t ≤ 1 :=
t.2.2
instance mul : Mul (Ioc (0 : α) 1) where
- mul p q := ⟨p.1 * q.1, ⟨mul_pos p.2.1 q.2.1, mul_le_one p.2.2 (le_of_lt q.2.1) q.2.2⟩⟩
+ mul p q := ⟨p.1 * q.1, ⟨mul_pos p.2.1 q.2.1, mul_le_one₀ p.2.2 (le_of_lt q.2.1) q.2.2⟩⟩
instance pow : Pow (Ioc (0 : α) 1) ℕ where
- pow p n := ⟨p.1 ^ n, ⟨pow_pos p.2.1 n, pow_le_one n (le_of_lt p.2.1) p.2.2⟩⟩
+ pow p n := ⟨p.1 ^ n, ⟨pow_pos p.2.1 n, pow_le_one₀ (le_of_lt p.2.1) p.2.2⟩⟩
@[simp, norm_cast]
theorem coe_mul (x y : Ioc (0 : α) 1) : ↑(x * y) = (x * y : α) :=
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 fbf1c3d4a4b3b..a1172e5a8524d 100644
--- a/Mathlib/Algebra/Order/Module/Defs.lean
+++ b/Mathlib/Algebra/Order/Module/Defs.lean
@@ -3,9 +3,10 @@ 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
import Mathlib.Tactic.Positivity.Core
/-!
@@ -769,7 +770,7 @@ instance instPosSMulReflectLE [PosSMulReflectLE α β] : PosSMulReflectLE α β
end Left
section Right
-variable [Preorder α] [Ring α] [OrderedAddCommGroup β] [Module α β]
+variable [Preorder α] [Monoid α] [OrderedAddCommGroup β] [DistribMulAction α β]
instance instSMulPosMono [SMulPosMono α β] : SMulPosMono α βᵒᵈ where
elim _b hb a₁ a₂ ha := by
@@ -794,6 +795,45 @@ instance instSMulPosReflectLE [SMulPosReflectLE α β] : SMulPosReflectLE α β
end Right
end OrderDual
+section OrderedAddCommMonoid
+variable [StrictOrderedSemiring α] [ExistsAddOfLE α] [OrderedCancelAddCommMonoid β]
+ [Module α β]
+
+section PosSMulMono
+variable [PosSMulMono α β] {a₁ a₂ : α} {b₁ b₂ : β}
+
+/-- Binary **rearrangement inequality**. -/
+lemma smul_add_smul_le_smul_add_smul (ha : a₁ ≤ a₂) (hb : b₁ ≤ b₂) :
+ a₁ • b₂ + a₂ • b₁ ≤ a₁ • b₁ + a₂ • b₂ := by
+ obtain ⟨a, ha₀, rfl⟩ := exists_nonneg_add_of_le ha
+ rw [add_smul, add_smul, add_left_comm]
+ gcongr
+
+/-- Binary **rearrangement inequality**. -/
+lemma smul_add_smul_le_smul_add_smul' (ha : a₂ ≤ a₁) (hb : b₂ ≤ b₁) :
+ a₁ • b₂ + a₂ • b₁ ≤ a₁ • b₁ + a₂ • b₂ := by
+ simp_rw [add_comm (a₁ • _)]; exact smul_add_smul_le_smul_add_smul ha hb
+
+end PosSMulMono
+
+section PosSMulStrictMono
+variable [PosSMulStrictMono α β] {a₁ a₂ : α} {b₁ b₂ : β}
+
+/-- Binary strict **rearrangement inequality**. -/
+lemma smul_add_smul_lt_smul_add_smul (ha : a₁ < a₂) (hb : b₁ < b₂) :
+ a₁ • b₂ + a₂ • b₁ < a₁ • b₁ + a₂ • b₂ := by
+ obtain ⟨a, ha₀, rfl⟩ := lt_iff_exists_pos_add.1 ha
+ rw [add_smul, add_smul, add_left_comm]
+ gcongr
+
+/-- Binary strict **rearrangement inequality**. -/
+lemma smul_add_smul_lt_smul_add_smul' (ha : a₂ < a₁) (hb : b₂ < b₁) :
+ a₁ • b₂ + a₂ • b₁ < a₁ • b₁ + a₂ • b₂ := by
+ simp_rw [add_comm (a₁ • _)]; exact smul_add_smul_lt_smul_add_smul ha hb
+
+end PosSMulStrictMono
+end OrderedAddCommMonoid
+
section OrderedRing
variable [OrderedRing α]
@@ -864,39 +904,6 @@ lemma smul_neg_iff_of_neg_left (ha : a < 0) : a • b < 0 ↔ 0 < b := by
simpa only [smul_zero] using smul_lt_smul_iff_of_neg_left ha (b₂ := (0 : β))
end PosSMulStrictMono
-
-/-- Binary **rearrangement inequality**. -/
-lemma smul_add_smul_le_smul_add_smul [PosSMulMono α β]
- {b₁ b₂ : α} {a d : β} (hab : b₁ ≤ b₂) (hcd : a ≤ d) : b₁ • d + b₂ • a ≤ b₁ • a + b₂ • d := by
- obtain ⟨b₂, rfl⟩ := exists_add_of_le hab
- obtain ⟨d, rfl⟩ := exists_add_of_le hcd
- rw [smul_add, add_right_comm, smul_add, ← add_assoc, add_smul _ _ d]
- rw [le_add_iff_nonneg_right] at hab hcd
- exact add_le_add_left (le_add_of_nonneg_right <| smul_nonneg hab hcd) _
-
-/-- Binary **rearrangement inequality**. -/
-lemma smul_add_smul_le_smul_add_smul' [PosSMulMono α β]
- {b₁ b₂ : α} {a d : β} (hba : b₂ ≤ b₁) (hdc : d ≤ a) : b₁ • d + b₂ • a ≤ b₁ • a + b₂ • d := by
- rw [add_comm (b₁ • d), add_comm (b₁ • a)]
- exact smul_add_smul_le_smul_add_smul hba hdc
-
-/-- Binary strict **rearrangement inequality**. -/
-lemma smul_add_smul_lt_smul_add_smul [PosSMulStrictMono α β]
- {b₁ b₂ : α} {a d : β} (hab : b₁ < b₂) (hcd : a < d) :
- b₁ • d + b₂ • a < b₁ • a + b₂ • d := by
- obtain ⟨b₂, rfl⟩ := exists_add_of_le hab.le
- obtain ⟨d, rfl⟩ := exists_add_of_le hcd.le
- rw [smul_add, add_right_comm, smul_add, ← add_assoc, add_smul _ _ d]
- rw [lt_add_iff_pos_right] at hab hcd
- exact add_lt_add_left (lt_add_of_pos_right _ <| smul_pos hab hcd) _
-
-/-- Binary strict **rearrangement inequality**. -/
-lemma smul_add_smul_lt_smul_add_smul' [PosSMulStrictMono α β]
- {b₁ b₂ : α} {a d : β} (hba : b₂ < b₁) (hdc : d < a) :
- b₁ • d + b₂ • a < b₁ • a + b₂ • d := by
- rw [add_comm (b₁ • d), add_comm (b₁ • a)]
- exact smul_add_smul_lt_smul_add_smul hba hdc
-
end OrderedAddCommGroup
section LinearOrderedAddCommGroup
@@ -1191,46 +1198,3 @@ def evalHSMul : PositivityExt where eval {_u α} zα pα (e : Q($α)) := do
| _, _ => pure .none
end Mathlib.Meta.Positivity
-
-/-!
-### Deprecated lemmas
-
-Those lemmas have been deprecated on 2023-12-23.
--/
-
-@[deprecated (since := "2023-12-23")] alias monotone_smul_left := monotone_smul_left_of_nonneg
-@[deprecated (since := "2023-12-23")] alias strict_mono_smul_left := strictMono_smul_left_of_pos
-@[deprecated (since := "2023-12-23")] alias smul_le_smul_of_nonneg := smul_le_smul_of_nonneg_left
-@[deprecated (since := "2023-12-23")] alias smul_lt_smul_of_pos := smul_lt_smul_of_pos_left
-
-@[deprecated (since := "2023-12-23")]
-alias lt_of_smul_lt_smul_of_nonneg := lt_of_smul_lt_smul_of_nonneg_left
-
-@[deprecated (since := "2023-12-23")] alias smul_le_smul_iff_of_pos := smul_le_smul_iff_of_pos_left
-@[deprecated (since := "2023-12-23")] alias smul_lt_smul_iff_of_pos := smul_lt_smul_iff_of_pos_left
-@[deprecated (since := "2023-12-23")] alias smul_max := smul_max_of_nonneg
-@[deprecated (since := "2023-12-23")] alias smul_min := smul_min_of_nonneg
-@[deprecated (since := "2023-12-23")] alias smul_pos_iff_of_pos := smul_pos_iff_of_pos_left
-@[deprecated (since := "2023-12-23")] alias inv_smul_le_iff := inv_smul_le_iff_of_pos
-@[deprecated (since := "2023-12-23")] alias le_inv_smul_iff := le_inv_smul_iff_of_pos
-@[deprecated (since := "2023-12-23")] alias inv_smul_lt_iff := inv_smul_lt_iff_of_pos
-@[deprecated (since := "2023-12-23")] alias lt_inv_smul_iff := lt_inv_smul_iff_of_pos
-@[deprecated (since := "2023-12-23")] alias OrderIso.smulLeft := OrderIso.smulRight
-
-@[deprecated (since := "2023-12-23")]
-alias OrderIso.smulLeft_symm_apply := OrderIso.smulRight_symm_apply
-
-@[deprecated (since := "2023-12-23")] alias OrderIso.smulLeft_apply := OrderIso.smulRight_apply
-@[deprecated (since := "2023-12-23")] alias smul_neg_iff_of_pos := smul_neg_iff_of_pos_left
-
-/-!
-Those lemmas have been deprecated on 2023-12-27.
--/
-
-@[deprecated (since := "2023-12-27")] alias strict_anti_smul_left := strictAnti_smul_left
-@[deprecated (since := "2023-12-27")] alias smul_le_smul_of_nonpos := smul_le_smul_of_nonpos_left
-@[deprecated (since := "2023-12-27")] alias smul_lt_smul_of_neg := smul_lt_smul_of_neg_left
-@[deprecated (since := "2023-12-27")] alias smul_pos_iff_of_neg := smul_pos_iff_of_neg_left
-@[deprecated (since := "2023-12-27")] alias smul_neg_iff_of_neg := smul_neg_iff_of_neg_left
-@[deprecated (since := "2023-12-27")] alias smul_le_smul_iff_of_neg := smul_le_smul_iff_of_neg_left
-@[deprecated (since := "2023-12-27")] alias smul_lt_smul_iff_of_neg := smul_lt_smul_iff_of_neg_left
diff --git a/Mathlib/Algebra/Order/Module/OrderedSMul.lean b/Mathlib/Algebra/Order/Module/OrderedSMul.lean
index bf1439508f708..6afca816cb005 100644
--- a/Mathlib/Algebra/Order/Module/OrderedSMul.lean
+++ b/Mathlib/Algebra/Order/Module/OrderedSMul.lean
@@ -9,7 +9,7 @@ import Mathlib.Algebra.Module.Prod
import Mathlib.Algebra.Order.Module.Defs
import Mathlib.Algebra.Order.Monoid.Prod
import Mathlib.Algebra.Order.Pi
-import Mathlib.Tactic.GCongr.Core
+import Mathlib.Tactic.GCongr.CoreAttrs
/-!
# Ordered scalar product
@@ -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/Pointwise.lean b/Mathlib/Algebra/Order/Module/Pointwise.lean
index 1214559716ed8..147291c9cdcef 100644
--- a/Mathlib/Algebra/Order/Module/Pointwise.lean
+++ b/Mathlib/Algebra/Order/Module/Pointwise.lean
@@ -3,8 +3,8 @@ 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.Group.Pointwise.Set.Basic
import Mathlib.Algebra.Order.Module.Defs
-import Mathlib.Data.Set.Pointwise.SMul
import Mathlib.Order.Bounds.OrderIso
/-!
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/Basic.lean b/Mathlib/Algebra/Order/Monoid/Canonical/Basic.lean
new file mode 100644
index 0000000000000..6005ed71ee499
--- /dev/null
+++ b/Mathlib/Algebra/Order/Monoid/Canonical/Basic.lean
@@ -0,0 +1,19 @@
+/-
+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.Order.Monoid.Canonical.Defs
+import Mathlib.Data.Finset.Lattice
+
+/-!
+# Extra lemmas about canonically ordered monoids
+-/
+
+namespace Finset
+variable {ι α : Type*} [CanonicallyLinearOrderedAddCommMonoid α] {s : Finset ι} {f : ι → α}
+
+@[simp] lemma sup_eq_zero : s.sup f = 0 ↔ ∀ i ∈ s, f i = 0 := by simp [← bot_eq_zero']
+@[simp] lemma sup'_eq_zero (hs) : s.sup' hs f = 0 ↔ ∀ i ∈ s, f i = 0 := by simp [sup'_eq_sup]
+
+end Finset
diff --git a/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean b/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean
index 6e2104c91ef78..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
@@ -58,7 +58,7 @@ instance (priority := 100) CanonicallyOrderedCommMonoid.existsMulOfLE (α : Type
section CanonicallyOrderedCommMonoid
-variable [CanonicallyOrderedCommMonoid α] {a b c d : α}
+variable [CanonicallyOrderedCommMonoid α] {a b c : α}
@[to_additive]
theorem le_self_mul : a ≤ a * c :=
@@ -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 c6998f304353c..4ed2d8ca1fa79 100644
--- a/Mathlib/Algebra/Order/Monoid/Prod.lean
+++ b/Mathlib/Algebra/Order/Monoid/Prod.lean
@@ -40,13 +40,13 @@ instance [CanonicallyOrderedCommMonoid α] [CanonicallyOrderedCommMonoid β] :
CanonicallyOrderedCommMonoid (α × β) :=
{ (inferInstance : OrderedCommMonoid _), (inferInstance : OrderBot _),
(inferInstance : ExistsMulOfLE _) with
- le_self_mul := fun _ _ ↦ ⟨le_self_mul, le_self_mul⟩ }
+ le_self_mul := fun _ _ ↦ le_def.mpr ⟨le_self_mul, le_self_mul⟩ }
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 ec0256bb10e09..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,39 +1256,39 @@ 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'
-@[to_additive]
+@[to_additive (attr := simp)]
theorem mulLECancellable_one [Monoid α] [LE α] : MulLECancellable (1 : α) := fun a b => by
simpa only [one_mul] using id
@@ -1306,12 +1305,12 @@ protected theorem inj [Mul α] [PartialOrder α] {a b c : α} (ha : MulLECancell
ha.Injective.eq_iff
@[to_additive]
-protected theorem injective_left [Mul α] [i : IsSymmOp α α (· * ·)] [PartialOrder α] {a : α}
+protected theorem injective_left [Mul α] [i : @Std.Commutative α (· * ·)] [PartialOrder α] {a : α}
(ha : MulLECancellable a) :
- Injective (· * a) := fun b c h => ha.Injective <| by dsimp; rwa [i.symm_op a, i.symm_op a]
+ Injective (· * a) := fun b c h => ha.Injective <| by dsimp; rwa [i.comm a, i.comm a]
@[to_additive]
-protected theorem inj_left [Mul α] [IsSymmOp α α (· * ·)] [PartialOrder α] {a b c : α}
+protected theorem inj_left [Mul α] [@Std.Commutative α (· * ·)] [PartialOrder α] {a b c : α}
(hc : MulLECancellable c) :
a * c = b * c ↔ a = b :=
hc.injective_left.eq_iff
@@ -1319,35 +1318,51 @@ protected theorem inj_left [Mul α] [IsSymmOp α α (· * ·)] [PartialOrder α]
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 : IsSymmOp α α (· * ·)]
- [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (ha : MulLECancellable a) :
- b * a ≤ c * a ↔ b ≤ c := by rw [i.symm_op b, i.symm_op c, ha.mul_le_mul_iff_left]
+protected theorem mul_le_mul_iff_right [Mul α] [i : @Std.Commutative α (· * ·)]
+ [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 : IsSymmOp α α (· * ·)]
- [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : MulLECancellable a) :
- a ≤ b * a ↔ 1 ≤ b := by rw [i.symm_op, ha.le_mul_iff_one_le_right]
+protected theorem le_mul_iff_one_le_left [MulOneClass α] [i : @Std.Commutative α (· * ·)]
+ [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 : IsSymmOp α α (· * ·)]
- [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : MulLECancellable a) :
- b * a ≤ a ↔ b ≤ 1 := by rw [i.symm_op, ha.mul_le_iff_le_one_right]
+protected theorem mul_le_iff_le_one_left [MulOneClass α] [i : @Std.Commutative α (· * ·)]
+ [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 α] [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 α] [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 α] [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 a86ce7532c9ee..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)) :
@@ -450,11 +450,11 @@ theorem covariant_lt_iff_contravariant_le [LinearOrder N] :
variable (mu : N → N → N)
-theorem covariant_flip_iff [IsSymmOp N N mu] :
- Covariant N N (flip mu) r ↔ Covariant N N mu r := by rw [IsSymmOp.flip_eq]
+theorem covariant_flip_iff [h : Std.Commutative mu] :
+ Covariant N N (flip mu) r ↔ Covariant N N mu r := by unfold flip; simp_rw [h.comm]
-theorem contravariant_flip_iff [IsSymmOp N N mu] :
- Contravariant N N (flip mu) r ↔ Contravariant N N mu r := by rw [IsSymmOp.flip_eq]
+theorem contravariant_flip_iff [h : Std.Commutative mu] :
+ Contravariant N N (flip mu) r ↔ Contravariant N N mu r := by unfold flip; simp_rw [h.comm]
instance contravariant_lt_of_covariant_le [LinearOrder N]
[CovariantClass N N mu (· ≤ ·)] : ContravariantClass N N mu (· < ·) where
@@ -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 877d5f5f47c07..348b449849781 100644
--- a/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean
+++ b/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean
@@ -24,103 +24,106 @@ section Preorder
variable [Preorder M]
-section Left
-
-variable [CovariantClass M M (· * ·) (· ≤ ·)] {x : M}
+namespace Left
-@[to_additive (attr := mono, gcongr) nsmul_le_nsmul_right]
-theorem pow_le_pow_left' [CovariantClass M M (swap (· * ·)) (· ≤ ·)] {a b : M} (hab : a ≤ b) :
- ∀ i : ℕ, a ^ i ≤ b ^ i
- | 0 => by simp
- | k + 1 => by
- rw [pow_succ, pow_succ]
- exact mul_le_mul' (pow_le_pow_left' hab k) hab
+variable [MulLeftMono M] {a : M}
-@[to_additive nsmul_nonneg]
-theorem one_le_pow_of_one_le' {a : M} (H : 1 ≤ a) : ∀ n : ℕ, 1 ≤ a ^ n
+@[to_additive Left.nsmul_nonneg]
+theorem one_le_pow_of_le (ha : 1 ≤ a) : ∀ n : ℕ, 1 ≤ a ^ n
| 0 => by simp
| k + 1 => by
rw [pow_succ]
- exact one_le_mul (one_le_pow_of_one_le' H k) H
+ exact one_le_mul (one_le_pow_of_le ha k) ha
+
+@[deprecated (since := "2024-09-21")] alias pow_nonneg := nsmul_nonneg
@[to_additive nsmul_nonpos]
-theorem pow_le_one' {a : M} (H : a ≤ 1) (n : ℕ) : a ^ n ≤ 1 :=
- one_le_pow_of_one_le' (M := Mᵒᵈ) H n
+theorem pow_le_one_of_le (ha : a ≤ 1) (n : ℕ) : a ^ n ≤ 1 := one_le_pow_of_le (M := Mᵒᵈ) ha n
+
+@[deprecated (since := "2024-09-21")] alias pow_nonpos := nsmul_nonpos
+
+@[to_additive nsmul_neg]
+theorem pow_lt_one_of_lt {a : M} {n : ℕ} (h : a < 1) (hn : n ≠ 0) : a ^ n < 1 := by
+ rcases Nat.exists_eq_succ_of_ne_zero hn with ⟨k, rfl⟩
+ rw [pow_succ']
+ exact mul_lt_one_of_lt_of_le h (pow_le_one_of_le h.le _)
+
+@[deprecated (since := "2024-09-21")] alias pow_neg := nsmul_neg
+
+end Left
+
+@[to_additive nsmul_nonneg] alias one_le_pow_of_one_le' := Left.one_le_pow_of_le
+@[to_additive nsmul_nonpos] alias pow_le_one' := Left.pow_le_one_of_le
+@[to_additive nsmul_neg] alias pow_lt_one' := Left.pow_lt_one_of_lt
+
+section Left
+
+variable [MulLeftMono M]
+
+@[to_additive nsmul_left_monotone]
+theorem pow_right_monotone {a : M} (ha : 1 ≤ a) : Monotone fun n : ℕ ↦ a ^ n :=
+ monotone_nat_of_le_succ fun n ↦ by rw [pow_succ]; exact le_mul_of_one_le_right' ha
@[to_additive (attr := gcongr) nsmul_le_nsmul_left]
theorem pow_le_pow_right' {a : M} {n m : ℕ} (ha : 1 ≤ a) (h : n ≤ m) : a ^ n ≤ a ^ m :=
- let ⟨k, hk⟩ := Nat.le.dest h
- calc
- a ^ n ≤ a ^ n * a ^ k := le_mul_of_one_le_right' (one_le_pow_of_one_le' ha _)
- _ = a ^ m := by rw [← hk, pow_add]
+ pow_right_monotone ha h
@[to_additive nsmul_le_nsmul_left_of_nonpos]
theorem pow_le_pow_right_of_le_one' {a : M} {n m : ℕ} (ha : a ≤ 1) (h : n ≤ m) : a ^ m ≤ a ^ n :=
pow_le_pow_right' (M := Mᵒᵈ) ha h
@[to_additive nsmul_pos]
-theorem one_lt_pow' {a : M} (ha : 1 < a) {k : ℕ} (hk : k ≠ 0) : 1 < a ^ k := by
- rcases Nat.exists_eq_succ_of_ne_zero hk with ⟨l, rfl⟩
- clear hk
- induction l with
- | zero => rw [pow_succ]; simpa using ha
- | succ l IH => rw [pow_succ]; exact one_lt_mul'' IH ha
+theorem one_lt_pow' {a : M} (ha : 1 < a) {k : ℕ} (hk : k ≠ 0) : 1 < a ^ k :=
+ pow_lt_one' (M := Mᵒᵈ) ha hk
-@[to_additive nsmul_neg]
-theorem pow_lt_one' {a : M} (ha : a < 1) {k : ℕ} (hk : k ≠ 0) : a ^ k < 1 :=
- one_lt_pow' (M := Mᵒᵈ) ha hk
+end Left
-@[to_additive (attr := gcongr) nsmul_lt_nsmul_left]
-theorem pow_lt_pow_right' [CovariantClass M M (· * ·) (· < ·)] {a : M} {n m : ℕ} (ha : 1 < a)
- (h : n < m) : a ^ n < a ^ m := by
- rcases Nat.le.dest h with ⟨k, rfl⟩; clear h
- rw [pow_add, pow_succ, mul_assoc, ← pow_succ']
- exact lt_mul_of_one_lt_right' _ (one_lt_pow' ha k.succ_ne_zero)
+section LeftLt
-@[to_additive nsmul_left_strictMono]
-theorem pow_right_strictMono' [CovariantClass M M (· * ·) (· < ·)] {a : M} (ha : 1 < a) :
- StrictMono ((a ^ ·) : ℕ → M) := fun _ _ => pow_lt_pow_right' ha
+variable [MulLeftStrictMono M] {a : M} {n m : ℕ}
-@[to_additive Left.pow_nonneg]
-theorem Left.one_le_pow_of_le (hx : 1 ≤ x) : ∀ {n : ℕ}, 1 ≤ x ^ n
- | 0 => (pow_zero x).ge
- | n + 1 => by
- rw [pow_succ]
- exact Left.one_le_mul (Left.one_le_pow_of_le hx) hx
+@[to_additive nsmul_left_strictMono]
+theorem pow_right_strictMono' (ha : 1 < a) : StrictMono ((a ^ ·) : ℕ → M) :=
+ strictMono_nat_of_lt_succ fun n ↦ by rw [pow_succ]; exact lt_mul_of_one_lt_right' (a ^ n) ha
-@[to_additive Left.pow_nonpos]
-theorem Left.pow_le_one_of_le (hx : x ≤ 1) : ∀ {n : ℕ}, x ^ n ≤ 1
- | 0 => (pow_zero _).le
- | n + 1 => by
- rw [pow_succ]
- exact Left.mul_le_one (Left.pow_le_one_of_le hx) hx
+@[to_additive (attr := gcongr) nsmul_lt_nsmul_left]
+theorem pow_lt_pow_right' (ha : 1 < a) (h : n < m) : a ^ n < a ^ m :=
+ pow_right_strictMono' ha h
-end Left
+end LeftLt
section Right
-variable [CovariantClass M M (swap (· * ·)) (· ≤ ·)] {x : M}
+variable [MulRightMono M] {x : M}
-@[to_additive Right.pow_nonneg]
+@[to_additive Right.nsmul_nonneg]
theorem Right.one_le_pow_of_le (hx : 1 ≤ x) : ∀ {n : ℕ}, 1 ≤ x ^ n
| 0 => (pow_zero _).ge
| n + 1 => by
rw [pow_succ]
exact Right.one_le_mul (Right.one_le_pow_of_le hx) hx
-@[to_additive Right.pow_nonpos]
-theorem Right.pow_le_one_of_le (hx : x ≤ 1) : ∀ {n : ℕ}, x ^ n ≤ 1
- | 0 => (pow_zero _).le
- | n + 1 => by
- rw [pow_succ]
- exact Right.mul_le_one (Right.pow_le_one_of_le hx) hx
+@[deprecated (since := "2024-09-21")] alias Right.pow_nonneg := Right.nsmul_nonneg
+
+@[to_additive Right.nsmul_nonpos]
+theorem Right.pow_le_one_of_le (hx : x ≤ 1) {n : ℕ} : x ^ n ≤ 1 :=
+ Right.one_le_pow_of_le (M := Mᵒᵈ) hx
+
+@[deprecated (since := "2024-09-21")] alias Right.pow_nonpos := Right.nsmul_nonpos
+
+@[to_additive Right.nsmul_neg]
+theorem Right.pow_lt_one_of_lt {n : ℕ} {x : M} (hn : 0 < n) (h : x < 1) : x ^ n < 1 := by
+ rcases Nat.exists_eq_succ_of_ne_zero hn.ne' with ⟨k, rfl⟩
+ rw [pow_succ]
+ exact mul_lt_one_of_le_of_lt (pow_le_one_of_le h.le) h
+
+@[deprecated (since := "2024-09-21")] alias Right.pow_neg := Right.nsmul_neg
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)
@@ -141,8 +144,14 @@ 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
+ | 0 => by simp
+ | k + 1 => by
+ rw [pow_succ, pow_succ]
+ exact mul_le_mul' (pow_le_pow_left' hab k) hab
@[to_additive Monotone.const_nsmul]
theorem Monotone.pow_const {f : β → M} (hf : Monotone f) : ∀ n : ℕ, Monotone fun a => f a ^ n
@@ -156,24 +165,6 @@ theorem pow_left_mono (n : ℕ) : Monotone fun a : M => a ^ n := monotone_id.pow
end CovariantLESwap
-@[to_additive Left.pow_neg]
-theorem Left.pow_lt_one_of_lt [CovariantClass M M (· * ·) (· < ·)] {n : ℕ} {x : M} (hn : 0 < n)
- (h : x < 1) : x ^ n < 1 :=
- Nat.le_induction ((pow_one _).trans_lt h)
- (fun n _ ih => by
- rw [pow_succ]
- exact mul_lt_one ih h)
- _ (Nat.succ_le_iff.2 hn)
-
-@[to_additive Right.pow_neg]
-theorem Right.pow_lt_one_of_lt [CovariantClass M M (swap (· * ·)) (· < ·)] {n : ℕ} {x : M}
- (hn : 0 < n) (h : x < 1) : x ^ n < 1 :=
- Nat.le_induction ((pow_one _).trans_lt h)
- (fun n _ ih => by
- rw [pow_succ]
- exact Right.mul_lt_one ih h)
- _ (Nat.succ_le_iff.2 hn)
-
end Preorder
section LinearOrder
@@ -182,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]
@@ -206,7 +197,11 @@ theorem pow_eq_one_iff {x : M} {n : ℕ} (hn : n ≠ 0) : x ^ n = 1 ↔ x = 1 :=
simp only [le_antisymm_iff]
rw [pow_le_one_iff hn, one_le_pow_iff hn]
-variable [CovariantClass M M (· * ·) (· < ·)] {a : M} {m n : ℕ}
+end CovariantLE
+
+section CovariantLT
+
+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 :=
@@ -216,11 +211,11 @@ theorem pow_le_pow_iff_right' (ha : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n :=
theorem pow_lt_pow_iff_right' (ha : 1 < a) : a ^ m < a ^ n ↔ m < n :=
(pow_right_strictMono' ha).lt_iff_lt
-end CovariantLE
+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 :=
@@ -238,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 :=
@@ -255,22 +250,19 @@ 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 :=
- ⟨fun H =>
- not_le.mp fun k =>
- haveI := covariantClass_le_of_lt M M (swap (· * ·))
- H.not_le <| Right.one_le_pow_of_le k,
- Right.pow_lt_one_of_lt hn⟩
+ 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
@@ -278,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
@@ -287,39 +279,3 @@ theorem one_le_zpow {x : G} (H : 1 ≤ x) {n : ℤ} (hn : 0 ≤ n) : 1 ≤ x ^ n
apply one_le_pow_of_one_le' H
end DivInvMonoid
-
-/-!
-### Deprecated lemmas
-
-Those lemmas have been deprecated on 2023-12-23.
--/
-
-@[deprecated (since := "2023-12-23")] alias pow_le_pow_of_le_left' := pow_le_pow_left'
-@[deprecated (since := "2023-12-23")] alias nsmul_le_nsmul_of_le_right := nsmul_le_nsmul_right
-@[deprecated (since := "2023-12-23")] alias pow_lt_pow' := pow_lt_pow_right'
-@[deprecated (since := "2023-12-23")] alias nsmul_lt_nsmul := nsmul_lt_nsmul_left
-@[deprecated (since := "2023-12-23")] alias pow_strictMono_left := pow_right_strictMono'
-@[deprecated (since := "2023-12-23")] alias nsmul_strictMono_right := nsmul_left_strictMono
-@[deprecated (since := "2023-12-23")] alias StrictMono.pow_right' := StrictMono.pow_const
-@[deprecated (since := "2023-12-23")] alias StrictMono.nsmul_left := StrictMono.const_nsmul
-@[deprecated (since := "2023-12-23")] alias pow_strictMono_right' := pow_left_strictMono
-@[deprecated (since := "2023-12-23")] alias nsmul_strictMono_left := nsmul_right_strictMono
-@[deprecated (since := "2023-12-23")] alias Monotone.pow_right := Monotone.pow_const
-@[deprecated (since := "2023-12-23")] alias Monotone.nsmul_left := Monotone.const_nsmul
-@[deprecated (since := "2023-12-23")] alias lt_of_pow_lt_pow' := lt_of_pow_lt_pow_left'
-@[deprecated (since := "2023-12-23")] alias lt_of_nsmul_lt_nsmul := lt_of_nsmul_lt_nsmul_right
-@[deprecated (since := "2023-12-23")] alias pow_le_pow' := pow_le_pow_right'
-@[deprecated (since := "2023-12-23")] alias nsmul_le_nsmul := nsmul_le_nsmul_left
-@[deprecated (since := "2023-12-23")] alias pow_le_pow_of_le_one' := pow_le_pow_right_of_le_one'
-
-@[deprecated (since := "2023-12-23")]
-alias nsmul_le_nsmul_of_nonpos := nsmul_le_nsmul_left_of_nonpos
-
-@[deprecated (since := "2023-12-23")] alias le_of_pow_le_pow' := le_of_pow_le_pow_left'
-@[deprecated (since := "2023-12-23")] alias le_of_nsmul_le_nsmul := le_of_nsmul_le_nsmul_right
-@[deprecated (since := "2023-12-23")] alias pow_le_pow_iff' := pow_le_pow_iff_right'
-@[deprecated (since := "2023-12-23")] alias nsmul_le_nsmul_iff := nsmul_le_nsmul_iff_left
-@[deprecated (since := "2023-12-23")] alias pow_lt_pow_iff' := pow_lt_pow_iff_right'
-@[deprecated (since := "2023-12-23")] alias nsmul_lt_nsmul_iff := nsmul_lt_nsmul_iff_left
-@[deprecated (since := "2023-12-23")] alias pow_mono_right := pow_left_mono
-@[deprecated (since := "2023-12-23")] alias nsmul_mono_left := nsmul_right_mono
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 be50955c5d5ae..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. -/
@@ -128,6 +125,25 @@ variable [One γ] [LE γ] {f : α → β} {g : α → γ} {e : β → γ}
end extend
end Function
+
+namespace Pi
+variable {ι : Type*} {α : ι → Type*} [DecidableEq ι] [∀ i, One (α i)] [∀ i, Preorder (α i)] {i : ι}
+ {a b : α i}
+
+@[to_additive (attr := simp)]
+lemma mulSingle_le_mulSingle : mulSingle i a ≤ mulSingle i b ↔ a ≤ b := by
+ simp [mulSingle, update_le_update_iff]
+
+@[to_additive (attr := gcongr)] alias ⟨_, GCongr.mulSingle_mono⟩ := mulSingle_le_mulSingle
+
+@[to_additive (attr := simp) single_nonneg]
+lemma one_le_mulSingle : 1 ≤ mulSingle i a ↔ 1 ≤ a := by simp [mulSingle]
+
+@[to_additive (attr := simp)]
+lemma mulSingle_le_one : mulSingle i a ≤ 1 ↔ a ≤ 1 := by simp [mulSingle]
+
+end Pi
+
-- Porting note: Tactic code not ported yet
-- namespace Tactic
diff --git a/Mathlib/Algebra/Order/Pointwise.lean b/Mathlib/Algebra/Order/Pointwise.lean
deleted file mode 100644
index 43396523eb326..0000000000000
--- a/Mathlib/Algebra/Order/Pointwise.lean
+++ /dev/null
@@ -1,250 +0,0 @@
-/-
-Copyright (c) 2021 Alex J. Best. All rights reserved.
-Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Alex J. Best, Yaël Dillies
--/
-import Mathlib.Algebra.Bounds
-import Mathlib.Algebra.Order.Field.Basic -- Porting note: `LinearOrderedField`, etc
-import Mathlib.Data.Set.Pointwise.SMul
-
-/-!
-# Pointwise operations on ordered algebraic objects
-
-This file contains lemmas about the effect of pointwise operations on sets with an order structure.
-
-## TODO
-
-`sSup (s • t) = sSup s • sSup t` and `sInf (s • t) = sInf s • sInf t` hold as well but
-`CovariantClass` is currently not polymorphic enough to state it.
--/
-
-
-open Function Set
-
-open Pointwise
-
-variable {α : Type*}
-
--- Porting note: Swapped the place of `CompleteLattice` and `ConditionallyCompleteLattice`
--- due to simpNF problem between `sSup_xx` `csSup_xx`.
-
-section CompleteLattice
-
-variable [CompleteLattice α]
-
-section One
-
-variable [One α]
-
-@[to_additive (attr := simp)]
-theorem sSup_one : sSup (1 : Set α) = 1 :=
- sSup_singleton
-
-@[to_additive (attr := simp)]
-theorem sInf_one : sInf (1 : Set α) = 1 :=
- sInf_singleton
-
-end One
-
-section Group
-
-variable [Group α] [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)]
- (s t : Set α)
-
-@[to_additive]
-theorem sSup_inv (s : Set α) : sSup s⁻¹ = (sInf s)⁻¹ := by
- rw [← image_inv, sSup_image]
- exact ((OrderIso.inv α).map_sInf _).symm
-
-@[to_additive]
-theorem sInf_inv (s : Set α) : sInf s⁻¹ = (sSup s)⁻¹ := by
- rw [← image_inv, sInf_image]
- exact ((OrderIso.inv α).map_sSup _).symm
-
-@[to_additive]
-theorem sSup_mul : sSup (s * t) = sSup s * sSup t :=
- (sSup_image2_eq_sSup_sSup fun _ => (OrderIso.mulRight _).to_galoisConnection) fun _ =>
- (OrderIso.mulLeft _).to_galoisConnection
-
-@[to_additive]
-theorem sInf_mul : sInf (s * t) = sInf s * sInf t :=
- (sInf_image2_eq_sInf_sInf fun _ => (OrderIso.mulRight _).symm.to_galoisConnection) fun _ =>
- (OrderIso.mulLeft _).symm.to_galoisConnection
-
-@[to_additive]
-theorem sSup_div : sSup (s / t) = sSup s / sInf t := by simp_rw [div_eq_mul_inv, sSup_mul, sSup_inv]
-
-@[to_additive]
-theorem sInf_div : sInf (s / t) = sInf s / sSup t := by simp_rw [div_eq_mul_inv, sInf_mul, sInf_inv]
-
-end Group
-
-end CompleteLattice
-
-section ConditionallyCompleteLattice
-
-variable [ConditionallyCompleteLattice α]
-
-section One
-
-variable [One α]
-
-@[to_additive (attr := simp)]
-theorem csSup_one : sSup (1 : Set α) = 1 :=
- csSup_singleton _
-
-@[to_additive (attr := simp)]
-theorem csInf_one : sInf (1 : Set α) = 1 :=
- csInf_singleton _
-
-end One
-
-section Group
-
-variable [Group α] [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)]
- {s t : Set α}
-
-@[to_additive]
-theorem csSup_inv (hs₀ : s.Nonempty) (hs₁ : BddBelow s) : sSup s⁻¹ = (sInf s)⁻¹ := by
- rw [← image_inv]
- exact ((OrderIso.inv α).map_csInf' hs₀ hs₁).symm
-
-@[to_additive]
-theorem csInf_inv (hs₀ : s.Nonempty) (hs₁ : BddAbove s) : sInf s⁻¹ = (sSup s)⁻¹ := by
- rw [← image_inv]
- exact ((OrderIso.inv α).map_csSup' hs₀ hs₁).symm
-
-@[to_additive]
-theorem csSup_mul (hs₀ : s.Nonempty) (hs₁ : BddAbove s) (ht₀ : t.Nonempty) (ht₁ : BddAbove t) :
- sSup (s * t) = sSup s * sSup t :=
- csSup_image2_eq_csSup_csSup (fun _ => (OrderIso.mulRight _).to_galoisConnection)
- (fun _ => (OrderIso.mulLeft _).to_galoisConnection) hs₀ hs₁ ht₀ ht₁
-
-@[to_additive]
-theorem csInf_mul (hs₀ : s.Nonempty) (hs₁ : BddBelow s) (ht₀ : t.Nonempty) (ht₁ : BddBelow t) :
- sInf (s * t) = sInf s * sInf t :=
- csInf_image2_eq_csInf_csInf (fun _ => (OrderIso.mulRight _).symm.to_galoisConnection)
- (fun _ => (OrderIso.mulLeft _).symm.to_galoisConnection) hs₀ hs₁ ht₀ ht₁
-
-@[to_additive]
-theorem csSup_div (hs₀ : s.Nonempty) (hs₁ : BddAbove s) (ht₀ : t.Nonempty) (ht₁ : BddBelow t) :
- sSup (s / t) = sSup s / sInf t := by
- rw [div_eq_mul_inv, csSup_mul hs₀ hs₁ ht₀.inv ht₁.inv, csSup_inv ht₀ ht₁, div_eq_mul_inv]
-
-@[to_additive]
-theorem csInf_div (hs₀ : s.Nonempty) (hs₁ : BddBelow s) (ht₀ : t.Nonempty) (ht₁ : BddAbove t) :
- sInf (s / t) = sInf s / sSup t := by
- rw [div_eq_mul_inv, csInf_mul hs₀ hs₁ ht₀.inv ht₁.inv, csInf_inv ht₀ ht₁, div_eq_mul_inv]
-
-end Group
-
-end ConditionallyCompleteLattice
-
-namespace LinearOrderedField
-
-variable {K : Type*} [LinearOrderedField K] {a b r : K} (hr : 0 < r)
-include hr
-
-open Set
-
-theorem smul_Ioo : r • Ioo a b = Ioo (r • a) (r • b) := by
- ext x
- simp only [mem_smul_set, smul_eq_mul, mem_Ioo]
- constructor
- · rintro ⟨a, ⟨a_h_left_left, a_h_left_right⟩, rfl⟩
- constructor
- · exact (mul_lt_mul_left hr).mpr a_h_left_left
- · exact (mul_lt_mul_left hr).mpr a_h_left_right
- · rintro ⟨a_left, a_right⟩
- use x / r
- refine ⟨⟨(lt_div_iff' hr).mpr a_left, (div_lt_iff' hr).mpr a_right⟩, ?_⟩
- rw [mul_div_cancel₀ _ (ne_of_gt hr)]
-
-theorem smul_Icc : r • Icc a b = Icc (r • a) (r • b) := by
- ext x
- simp only [mem_smul_set, smul_eq_mul, mem_Icc]
- constructor
- · rintro ⟨a, ⟨a_h_left_left, a_h_left_right⟩, rfl⟩
- constructor
- · exact (mul_le_mul_left hr).mpr a_h_left_left
- · exact (mul_le_mul_left hr).mpr a_h_left_right
- · rintro ⟨a_left, a_right⟩
- use x / r
- refine ⟨⟨(le_div_iff₀' hr).mpr a_left, (div_le_iff₀' hr).mpr a_right⟩, ?_⟩
- rw [mul_div_cancel₀ _ (ne_of_gt hr)]
-
-theorem smul_Ico : r • Ico a b = Ico (r • a) (r • b) := by
- ext x
- simp only [mem_smul_set, smul_eq_mul, mem_Ico]
- constructor
- · rintro ⟨a, ⟨a_h_left_left, a_h_left_right⟩, rfl⟩
- constructor
- · exact (mul_le_mul_left hr).mpr a_h_left_left
- · exact (mul_lt_mul_left hr).mpr a_h_left_right
- · rintro ⟨a_left, a_right⟩
- use x / r
- refine ⟨⟨(le_div_iff₀' hr).mpr a_left, (div_lt_iff' hr).mpr a_right⟩, ?_⟩
- rw [mul_div_cancel₀ _ (ne_of_gt hr)]
-
-theorem smul_Ioc : r • Ioc a b = Ioc (r • a) (r • b) := by
- ext x
- simp only [mem_smul_set, smul_eq_mul, mem_Ioc]
- constructor
- · rintro ⟨a, ⟨a_h_left_left, a_h_left_right⟩, rfl⟩
- constructor
- · exact (mul_lt_mul_left hr).mpr a_h_left_left
- · exact (mul_le_mul_left hr).mpr a_h_left_right
- · rintro ⟨a_left, a_right⟩
- use x / r
- refine ⟨⟨(lt_div_iff' hr).mpr a_left, (div_le_iff₀' hr).mpr a_right⟩, ?_⟩
- rw [mul_div_cancel₀ _ (ne_of_gt hr)]
-
-theorem smul_Ioi : r • Ioi a = Ioi (r • a) := by
- ext x
- simp only [mem_smul_set, smul_eq_mul, mem_Ioi]
- constructor
- · rintro ⟨a_w, a_h_left, rfl⟩
- exact (mul_lt_mul_left hr).mpr a_h_left
- · rintro h
- use x / r
- constructor
- · exact (lt_div_iff' hr).mpr h
- · exact mul_div_cancel₀ _ (ne_of_gt hr)
-
-theorem smul_Iio : r • Iio a = Iio (r • a) := by
- ext x
- simp only [mem_smul_set, smul_eq_mul, mem_Iio]
- constructor
- · rintro ⟨a_w, a_h_left, rfl⟩
- exact (mul_lt_mul_left hr).mpr a_h_left
- · rintro h
- use x / r
- constructor
- · exact (div_lt_iff' hr).mpr h
- · exact mul_div_cancel₀ _ (ne_of_gt hr)
-
-theorem smul_Ici : r • Ici a = Ici (r • a) := by
- ext x
- simp only [mem_smul_set, smul_eq_mul, mem_Ioi]
- constructor
- · rintro ⟨a_w, a_h_left, rfl⟩
- exact (mul_le_mul_left hr).mpr a_h_left
- · rintro h
- use x / r
- constructor
- · exact (le_div_iff₀' hr).mpr h
- · exact mul_div_cancel₀ _ (ne_of_gt hr)
-
-theorem smul_Iic : r • Iic a = Iic (r • a) := by
- ext x
- simp only [mem_smul_set, smul_eq_mul, mem_Iio]
- constructor
- · rintro ⟨a_w, a_h_left, rfl⟩
- exact (mul_le_mul_left hr).mpr a_h_left
- · rintro h
- use x / r
- constructor
- · exact (div_le_iff₀' hr).mpr h
- · exact mul_div_cancel₀ _ (ne_of_gt hr)
-
-end LinearOrderedField
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/Rearrangement.lean b/Mathlib/Algebra/Order/Rearrangement.lean
index 6643fbdac7eec..f69acca4d99d3 100644
--- a/Mathlib/Algebra/Order/Rearrangement.lean
+++ b/Mathlib/Algebra/Order/Rearrangement.lean
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mantas Bakšys
-/
import Mathlib.Algebra.BigOperators.Group.Finset
-import Mathlib.Algebra.Order.Group.Instances
import Mathlib.Algebra.Order.Module.OrderedSMul
import Mathlib.Algebra.Order.Module.Synonym
import Mathlib.Data.Prod.Lex
@@ -41,23 +40,30 @@ convenience.
The case for `Monotone`/`Antitone` pairs of functions over a `LinearOrder` is not deduced in this
file because it is easily deducible from the `Monovary` API.
+
+## TODO
+
+Add equality cases for when the permute function is injective. This comes from the following fact:
+If `Monovary f g`, `Injective g` and `σ` is a permutation, then `Monovary f (g ∘ σ) ↔ σ = 1`.
-/
open Equiv Equiv.Perm Finset Function OrderDual
-variable {ι α β : Type*}
+variable {ι α β : Type*} [LinearOrderedSemiring α] [ExistsAddOfLE α]
+ [LinearOrderedCancelAddCommMonoid β] [Module α β]
/-! ### Scalar multiplication versions -/
-
section SMul
-variable [LinearOrderedRing α] [LinearOrderedAddCommGroup β] [Module α β] [OrderedSMul α β]
- {s : Finset ι} {σ : Perm ι} {f : ι → α} {g : ι → β}
+/-! #### Weak rearrangement inequality -/
+
+section weak_inequality
+variable [PosSMulMono α β] {s : Finset ι} {σ : Perm ι} {f : ι → α} {g : ι → β}
/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is maximized when
-`f` and `g` monovary together. Stated by permuting the entries of `g`. -/
+`f` and `g` monovary together on `s`. Stated by permuting the entries of `g`. -/
theorem MonovaryOn.sum_smul_comp_perm_le_sum_smul (hfg : MonovaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f i • g (σ i) ≤ ∑ i ∈ s, f i • g i := by
classical
@@ -106,9 +112,62 @@ theorem MonovaryOn.sum_smul_comp_perm_le_sum_smul (hfg : MonovaryOn f g s)
rintro rfl
exact has hx.2
+/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is minimized when
+`f` and `g` antivary together on `s`. Stated by permuting the entries of `g`. -/
+theorem AntivaryOn.sum_smul_le_sum_smul_comp_perm (hfg : AntivaryOn f g s)
+ (hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f i • g i ≤ ∑ i ∈ s, f i • g (σ i) :=
+ hfg.dual_right.sum_smul_comp_perm_le_sum_smul hσ
+
+/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is maximized when
+`f` and `g` monovary together on `s`. Stated by permuting the entries of `f`. -/
+theorem MonovaryOn.sum_comp_perm_smul_le_sum_smul (hfg : MonovaryOn f g s)
+ (hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f (σ i) • g i ≤ ∑ i ∈ s, f i • g i := by
+ convert hfg.sum_smul_comp_perm_le_sum_smul
+ (show { x | σ⁻¹ x ≠ x } ⊆ s by simp only [set_support_inv_eq, hσ]) using 1
+ exact σ.sum_comp' s (fun i j ↦ f i • g j) hσ
+
+/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is minimized when
+`f` and `g` antivary together on `s`. Stated by permuting the entries of `f`. -/
+theorem AntivaryOn.sum_smul_le_sum_comp_perm_smul (hfg : AntivaryOn f g s)
+ (hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f i • g i ≤ ∑ i ∈ s, f (σ i) • g i :=
+ hfg.dual_right.sum_comp_perm_smul_le_sum_smul hσ
+
+variable [Fintype ι]
+
+/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is maximized when
+`f` and `g` monovary together. Stated by permuting the entries of `g`. -/
+theorem Monovary.sum_smul_comp_perm_le_sum_smul (hfg : Monovary f g) :
+ ∑ i, f i • g (σ i) ≤ ∑ i, f i • g i :=
+ (hfg.monovaryOn _).sum_smul_comp_perm_le_sum_smul fun _ _ ↦ mem_univ _
+
+/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is minimized when
+`f` and `g` antivary together. Stated by permuting the entries of `g`. -/
+theorem Antivary.sum_smul_le_sum_smul_comp_perm (hfg : Antivary f g) :
+ ∑ i, f i • g i ≤ ∑ i, f i • g (σ i) :=
+ (hfg.antivaryOn _).sum_smul_le_sum_smul_comp_perm fun _ _ ↦ mem_univ _
+
+/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is maximized when
+`f` and `g` monovary together. Stated by permuting the entries of `f`. -/
+theorem Monovary.sum_comp_perm_smul_le_sum_smul (hfg : Monovary f g) :
+ ∑ i, f (σ i) • g i ≤ ∑ i, f i • g i :=
+ (hfg.monovaryOn _).sum_comp_perm_smul_le_sum_smul fun _ _ ↦ mem_univ _
+
+/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is minimized when
+`f` and `g` antivary together. Stated by permuting the entries of `f`. -/
+theorem Antivary.sum_smul_le_sum_comp_perm_smul (hfg : Antivary f g) :
+ ∑ i, f i • g i ≤ ∑ i, f (σ i) • g i :=
+ (hfg.antivaryOn _).sum_smul_le_sum_comp_perm_smul fun _ _ ↦ mem_univ _
+
+end weak_inequality
+
+/-! #### Equality case of the rearrangement inequality -/
+
+section equality_case
+variable [PosSMulStrictMono α β] {s : Finset ι} {σ : Perm ι} {f : ι → α} {g : ι → β}
+
/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
-`g`, which monovary together, is unchanged by a permutation if and only if `f` and `g ∘ σ` monovary
-together. Stated by permuting the entries of `g`. -/
+`g`, which monovary together on `s`, is unchanged by a permutation if and only if `f` and `g ∘ σ`
+monovary together on `s`. Stated by permuting the entries of `g`. -/
theorem MonovaryOn.sum_smul_comp_perm_eq_sum_smul_iff (hfg : MonovaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f i • g (σ i) = ∑ i ∈ s, f i • g i ↔ MonovaryOn f (g ∘ σ) s := by
@@ -134,26 +193,17 @@ theorem MonovaryOn.sum_smul_comp_perm_eq_sum_smul_iff (hfg : MonovaryOn f g s)
· convert h.sum_smul_comp_perm_le_sum_smul ((set_support_inv_eq _).subset.trans hσ) using 1
simp_rw [Function.comp_apply, apply_inv_self]
-/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
-`f` and `g`, which monovary together, is strictly decreased by a permutation if and only if
-`f` and `g ∘ σ` do not monovary together. Stated by permuting the entries of `g`. -/
-theorem MonovaryOn.sum_smul_comp_perm_lt_sum_smul_iff (hfg : MonovaryOn f g s)
+/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
+`g`, which antivary together on `s`, is unchanged by a permutation if and only if `f` and `g ∘ σ`
+antivary together on `s`. Stated by permuting the entries of `g`. -/
+theorem AntivaryOn.sum_smul_comp_perm_eq_sum_smul_iff (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
- ∑ i ∈ s, f i • g (σ i) < ∑ i ∈ s, f i • g i ↔ ¬MonovaryOn f (g ∘ σ) s := by
- simp [← hfg.sum_smul_comp_perm_eq_sum_smul_iff hσ, lt_iff_le_and_ne,
- hfg.sum_smul_comp_perm_le_sum_smul hσ]
-
-/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is maximized when
-`f` and `g` monovary together. Stated by permuting the entries of `f`. -/
-theorem MonovaryOn.sum_comp_perm_smul_le_sum_smul (hfg : MonovaryOn f g s)
- (hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f (σ i) • g i ≤ ∑ i ∈ s, f i • g i := by
- convert hfg.sum_smul_comp_perm_le_sum_smul
- (show { x | σ⁻¹ x ≠ x } ⊆ s by simp only [set_support_inv_eq, hσ]) using 1
- exact σ.sum_comp' s (fun i j ↦ f i • g j) hσ
+ ∑ i ∈ s, f i • g (σ i) = ∑ i ∈ s, f i • g i ↔ AntivaryOn f (g ∘ σ) s :=
+ (hfg.dual_right.sum_smul_comp_perm_eq_sum_smul_iff hσ).trans monovaryOn_toDual_right
/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
-`g`, which monovary together, is unchanged by a permutation if and only if `f ∘ σ` and `g` monovary
-together. Stated by permuting the entries of `f`. -/
+`g`, which monovary together on `s`, is unchanged by a permutation if and only if `f ∘ σ` and `g`
+monovary together on `s`. Stated by permuting the entries of `f`. -/
theorem MonovaryOn.sum_comp_perm_smul_eq_sum_smul_iff (hfg : MonovaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f (σ i) • g i = ∑ i ∈ s, f i • g i ↔ MonovaryOn (f ∘ σ) g s := by
@@ -164,70 +214,100 @@ theorem MonovaryOn.sum_comp_perm_smul_eq_sum_smul_iff (hfg : MonovaryOn f g s)
rw [σ.sum_comp' s (fun i j ↦ f i • g j) hσ]
congr
· convert h.comp_right σ
- · rw [comp.assoc, inv_def, symm_comp_self, comp_id]
+ · rw [comp_assoc, inv_def, symm_comp_self, comp_id]
· rw [σ.eq_preimage_iff_image_eq, Set.image_perm hσ]
· convert h.comp_right σ.symm
- · rw [comp.assoc, self_comp_symm, comp_id]
+ · rw [comp_assoc, self_comp_symm, comp_id]
· rw [σ.symm.eq_preimage_iff_image_eq]
exact Set.image_perm hσinv
-/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
-`f` and `g`, which monovary together, is strictly decreased by a permutation if and only if
-`f ∘ σ` and `g` do not monovary together. Stated by permuting the entries of `f`. -/
-theorem MonovaryOn.sum_comp_perm_smul_lt_sum_smul_iff (hfg : MonovaryOn f g s)
+/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
+`g`, which antivary together on `s`, is unchanged by a permutation if and only if `f ∘ σ` and `g`
+antivary together on `s`. Stated by permuting the entries of `f`. -/
+theorem AntivaryOn.sum_comp_perm_smul_eq_sum_smul_iff (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
- ∑ i ∈ s, f (σ i) • g i < ∑ i ∈ s, f i • g i ↔ ¬MonovaryOn (f ∘ σ) g s := by
- simp [← hfg.sum_comp_perm_smul_eq_sum_smul_iff hσ, lt_iff_le_and_ne,
- hfg.sum_comp_perm_smul_le_sum_smul hσ]
+ ∑ i ∈ s, f (σ i) • g i = ∑ i ∈ s, f i • g i ↔ AntivaryOn (f ∘ σ) g s :=
+ (hfg.dual_right.sum_comp_perm_smul_eq_sum_smul_iff hσ).trans monovaryOn_toDual_right
-/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is minimized when
-`f` and `g` antivary together. Stated by permuting the entries of `g`. -/
-theorem AntivaryOn.sum_smul_le_sum_smul_comp_perm (hfg : AntivaryOn f g s)
- (hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f i • g i ≤ ∑ i ∈ s, f i • g (σ i) :=
- hfg.dual_right.sum_smul_comp_perm_le_sum_smul hσ
+@[deprecated (since := "2024-06-25")]
+alias AntivaryOn.sum_smul_eq_sum_comp_perm_smul_iff := AntivaryOn.sum_comp_perm_smul_eq_sum_smul_iff
+
+variable [Fintype ι]
+
+/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
+`g`, which monovary together, is unchanged by a permutation if and only if `f` and `g ∘ σ` monovary
+together. Stated by permuting the entries of `g`. -/
+theorem Monovary.sum_smul_comp_perm_eq_sum_smul_iff (hfg : Monovary f g) :
+ ∑ i, f i • g (σ i) = ∑ i, f i • g i ↔ Monovary f (g ∘ σ) := by
+ simp [(hfg.monovaryOn _).sum_smul_comp_perm_eq_sum_smul_iff fun _ _ ↦ mem_univ _]
+
+/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
+`g`, which monovary together, is unchanged by a permutation if and only if `f ∘ σ` and `g` monovary
+together. Stated by permuting the entries of `g`. -/
+theorem Monovary.sum_comp_perm_smul_eq_sum_smul_iff (hfg : Monovary f g) :
+ ∑ i, f (σ i) • g i = ∑ i, f i • g i ↔ Monovary (f ∘ σ) g := by
+ simp [(hfg.monovaryOn _).sum_comp_perm_smul_eq_sum_smul_iff fun _ _ ↦ mem_univ _]
/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
`g`, which antivary together, is unchanged by a permutation if and only if `f` and `g ∘ σ` antivary
together. Stated by permuting the entries of `g`. -/
-theorem AntivaryOn.sum_smul_comp_perm_eq_sum_smul_iff (hfg : AntivaryOn f g s)
- (hσ : {x | σ x ≠ x} ⊆ s) :
- ∑ i ∈ s, f i • g (σ i) = ∑ i ∈ s, f i • g i ↔ AntivaryOn f (g ∘ σ) s :=
- (hfg.dual_right.sum_smul_comp_perm_eq_sum_smul_iff hσ).trans monovaryOn_toDual_right
+theorem Antivary.sum_smul_comp_perm_eq_sum_smul_iff (hfg : Antivary f g) :
+ ∑ i, f i • g (σ i) = ∑ i, f i • g i ↔ Antivary f (g ∘ σ) := by
+ simp [(hfg.antivaryOn _).sum_smul_comp_perm_eq_sum_smul_iff fun _ _ ↦ mem_univ _]
@[deprecated (since := "2024-06-25")]
-alias AntivaryOn.sum_smul_eq_sum_smul_comp_perm_iff := AntivaryOn.sum_smul_comp_perm_eq_sum_smul_iff
+alias Antivary.sum_smul_eq_sum_smul_comp_perm_iff := Antivary.sum_smul_comp_perm_eq_sum_smul_iff
+
+/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
+`g`, which antivary together, is unchanged by a permutation if and only if `f ∘ σ` and `g` antivary
+together. Stated by permuting the entries of `f`. -/
+theorem Antivary.sum_comp_perm_smul_eq_sum_smul_iff (hfg : Antivary f g) :
+ ∑ i, f (σ i) • g i = ∑ i, f i • g i ↔ Antivary (f ∘ σ) g := by
+ simp [(hfg.antivaryOn _).sum_comp_perm_smul_eq_sum_smul_iff fun _ _ ↦ mem_univ _]
+
+@[deprecated (since := "2024-06-25")]
+alias Antivary.sum_smul_eq_sum_comp_perm_smul_iff := Antivary.sum_comp_perm_smul_eq_sum_smul_iff
+
+end equality_case
+
+/-! #### Strict rearrangement inequality -/
+
+section strict_inequality
+variable [PosSMulStrictMono α β] {s : Finset ι} {σ : Perm ι} {f : ι → α} {g : ι → β}
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
-`f` and `g`, which antivary together, is strictly decreased by a permutation if and only if
-`f` and `g ∘ σ` do not antivary together. Stated by permuting the entries of `g`. -/
+`f` and `g`, which monovary together on `s`, is strictly decreased by a permutation if and only if
+`f` and `g ∘ σ` do not monovary together on `s`. Stated by permuting the entries of `g`. -/
+theorem MonovaryOn.sum_smul_comp_perm_lt_sum_smul_iff (hfg : MonovaryOn f g s)
+ (hσ : {x | σ x ≠ x} ⊆ s) :
+ ∑ i ∈ s, f i • g (σ i) < ∑ i ∈ s, f i • g i ↔ ¬MonovaryOn f (g ∘ σ) s := by
+ simp [← hfg.sum_smul_comp_perm_eq_sum_smul_iff hσ, lt_iff_le_and_ne,
+ hfg.sum_smul_comp_perm_le_sum_smul hσ]
+
+/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
+`f` and `g`, which antivary together on `s`, is strictly decreased by a permutation if and only if
+`f` and `g ∘ σ` do not antivary together on `s`. Stated by permuting the entries of `g`. -/
theorem AntivaryOn.sum_smul_lt_sum_smul_comp_perm_iff (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f i • g i < ∑ i ∈ s, f i • g (σ i) ↔ ¬AntivaryOn f (g ∘ σ) s := by
simp [← hfg.sum_smul_comp_perm_eq_sum_smul_iff hσ, lt_iff_le_and_ne, eq_comm,
hfg.sum_smul_le_sum_smul_comp_perm hσ]
-/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is minimized when
-`f` and `g` antivary together. Stated by permuting the entries of `f`. -/
-theorem AntivaryOn.sum_smul_le_sum_comp_perm_smul (hfg : AntivaryOn f g s)
- (hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f i • g i ≤ ∑ i ∈ s, f (σ i) • g i := by
- convert hfg.sum_smul_le_sum_smul_comp_perm
- (show { x | σ⁻¹ x ≠ x } ⊆ s by simp only [set_support_inv_eq, hσ]) using 1
- exact σ.sum_comp' s (fun i j ↦ f i • g j) hσ
-
-/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
-`g`, which antivary together, is unchanged by a permutation if and only if `f ∘ σ` and `g` antivary
-together. Stated by permuting the entries of `f`. -/
-theorem AntivaryOn.sum_comp_perm_smul_eq_sum_smul_iff (hfg : AntivaryOn f g s)
+/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
+`f` and `g`, which monovary together on `s`, is strictly decreased by a permutation if and only if
+`f ∘ σ` and `g` do not monovary together on `s`. Stated by permuting the entries of `f`. -/
+theorem MonovaryOn.sum_comp_perm_smul_lt_sum_smul_iff (hfg : MonovaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
- ∑ i ∈ s, f (σ i) • g i = ∑ i ∈ s, f i • g i ↔ AntivaryOn (f ∘ σ) g s :=
- (hfg.dual_right.sum_comp_perm_smul_eq_sum_smul_iff hσ).trans monovaryOn_toDual_right
+ ∑ i ∈ s, f (σ i) • g i < ∑ i ∈ s, f i • g i ↔ ¬MonovaryOn (f ∘ σ) g s := by
+ simp [← hfg.sum_comp_perm_smul_eq_sum_smul_iff hσ, lt_iff_le_and_ne,
+ hfg.sum_comp_perm_smul_le_sum_smul hσ]
@[deprecated (since := "2024-06-25")]
-alias AntivaryOn.sum_smul_eq_sum_comp_perm_smul_iff := AntivaryOn.sum_comp_perm_smul_eq_sum_smul_iff
+alias AntivaryOn.sum_smul_eq_sum_smul_comp_perm_iff := AntivaryOn.sum_smul_comp_perm_eq_sum_smul_iff
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
-`f` and `g`, which antivary together, is strictly decreased by a permutation if and only if
-`f ∘ σ` and `g` do not antivary together. Stated by permuting the entries of `f`. -/
+`f` and `g`, which antivary together on `s`, is strictly decreased by a permutation if and only if
+`f ∘ σ` and `g` do not antivary together on `s`. Stated by permuting the entries of `f`. -/
theorem AntivaryOn.sum_smul_lt_sum_comp_perm_smul_iff (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f i • g i < ∑ i ∈ s, f (σ i) • g i ↔ ¬AntivaryOn (f ∘ σ) g s := by
@@ -236,19 +316,6 @@ theorem AntivaryOn.sum_smul_lt_sum_comp_perm_smul_iff (hfg : AntivaryOn f g s)
variable [Fintype ι]
-/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is maximized when
-`f` and `g` monovary together. Stated by permuting the entries of `g`. -/
-theorem Monovary.sum_smul_comp_perm_le_sum_smul (hfg : Monovary f g) :
- ∑ i, f i • g (σ i) ≤ ∑ i, f i • g i :=
- (hfg.monovaryOn _).sum_smul_comp_perm_le_sum_smul fun _ _ ↦ mem_univ _
-
-/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
-`g`, which monovary together, is unchanged by a permutation if and only if `f` and `g ∘ σ` monovary
-together. Stated by permuting the entries of `g`. -/
-theorem Monovary.sum_smul_comp_perm_eq_sum_smul_iff (hfg : Monovary f g) :
- ∑ i, f i • g (σ i) = ∑ i, f i • g i ↔ Monovary f (g ∘ σ) := by
- simp [(hfg.monovaryOn _).sum_smul_comp_perm_eq_sum_smul_iff fun _ _ ↦ mem_univ _]
-
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
`f` and `g`, which monovary together, is strictly decreased by a permutation if and only if
`f` and `g ∘ σ` do not monovary together. Stated by permuting the entries of `g`. -/
@@ -256,19 +323,6 @@ theorem Monovary.sum_smul_comp_perm_lt_sum_smul_iff (hfg : Monovary f g) :
∑ i, f i • g (σ i) < ∑ i, f i • g i ↔ ¬Monovary f (g ∘ σ) := by
simp [(hfg.monovaryOn _).sum_smul_comp_perm_lt_sum_smul_iff fun _ _ ↦ mem_univ _]
-/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is maximized when
-`f` and `g` monovary together. Stated by permuting the entries of `f`. -/
-theorem Monovary.sum_comp_perm_smul_le_sum_smul (hfg : Monovary f g) :
- ∑ i, f (σ i) • g i ≤ ∑ i, f i • g i :=
- (hfg.monovaryOn _).sum_comp_perm_smul_le_sum_smul fun _ _ ↦ mem_univ _
-
-/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
-`g`, which monovary together, is unchanged by a permutation if and only if `f ∘ σ` and `g` monovary
-together. Stated by permuting the entries of `g`. -/
-theorem Monovary.sum_comp_perm_smul_eq_sum_smul_iff (hfg : Monovary f g) :
- ∑ i, f (σ i) • g i = ∑ i, f i • g i ↔ Monovary (f ∘ σ) g := by
- simp [(hfg.monovaryOn _).sum_comp_perm_smul_eq_sum_smul_iff fun _ _ ↦ mem_univ _]
-
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
`f` and `g`, which monovary together, is strictly decreased by a permutation if and only if
`f` and `g ∘ σ` do not monovary together. Stated by permuting the entries of `g`. -/
@@ -276,22 +330,6 @@ theorem Monovary.sum_comp_perm_smul_lt_sum_smul_iff (hfg : Monovary f g) :
∑ i, f (σ i) • g i < ∑ i, f i • g i ↔ ¬Monovary (f ∘ σ) g := by
simp [(hfg.monovaryOn _).sum_comp_perm_smul_lt_sum_smul_iff fun _ _ ↦ mem_univ _]
-/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is minimized when
-`f` and `g` antivary together. Stated by permuting the entries of `g`. -/
-theorem Antivary.sum_smul_le_sum_smul_comp_perm (hfg : Antivary f g) :
- ∑ i, f i • g i ≤ ∑ i, f i • g (σ i) :=
- (hfg.antivaryOn _).sum_smul_le_sum_smul_comp_perm fun _ _ ↦ mem_univ _
-
-/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
-`g`, which antivary together, is unchanged by a permutation if and only if `f` and `g ∘ σ` antivary
-together. Stated by permuting the entries of `g`. -/
-theorem Antivary.sum_smul_comp_perm_eq_sum_smul_iff (hfg : Antivary f g) :
- ∑ i, f i • g (σ i) = ∑ i, f i • g i ↔ Antivary f (g ∘ σ) := by
- simp [(hfg.antivaryOn _).sum_smul_comp_perm_eq_sum_smul_iff fun _ _ ↦ mem_univ _]
-
-@[deprecated (since := "2024-06-25")]
-alias Antivary.sum_smul_eq_sum_smul_comp_perm_iff := Antivary.sum_smul_comp_perm_eq_sum_smul_iff
-
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
`f` and `g`, which antivary together, is strictly decreased by a permutation if and only if
`f` and `g ∘ σ` do not antivary together. Stated by permuting the entries of `g`. -/
@@ -299,22 +337,6 @@ theorem Antivary.sum_smul_lt_sum_smul_comp_perm_iff (hfg : Antivary f g) :
∑ i, f i • g i < ∑ i, f i • g (σ i) ↔ ¬Antivary f (g ∘ σ) := by
simp [(hfg.antivaryOn _).sum_smul_lt_sum_smul_comp_perm_iff fun _ _ ↦ mem_univ _]
-/-- **Rearrangement Inequality**: Pointwise scalar multiplication of `f` and `g` is minimized when
-`f` and `g` antivary together. Stated by permuting the entries of `f`. -/
-theorem Antivary.sum_smul_le_sum_comp_perm_smul (hfg : Antivary f g) :
- ∑ i, f i • g i ≤ ∑ i, f (σ i) • g i :=
- (hfg.antivaryOn _).sum_smul_le_sum_comp_perm_smul fun _ _ ↦ mem_univ _
-
-/-- **Equality case of the Rearrangement Inequality**: Pointwise scalar multiplication of `f` and
-`g`, which antivary together, is unchanged by a permutation if and only if `f ∘ σ` and `g` antivary
-together. Stated by permuting the entries of `f`. -/
-theorem Antivary.sum_comp_perm_smul_eq_sum_smul_iff (hfg : Antivary f g) :
- ∑ i, f (σ i) • g i = ∑ i, f i • g i ↔ Antivary (f ∘ σ) g := by
- simp [(hfg.antivaryOn _).sum_comp_perm_smul_eq_sum_smul_iff fun _ _ ↦ mem_univ _]
-
-@[deprecated (since := "2024-06-25")]
-alias Antivary.sum_smul_eq_sum_comp_perm_smul_iff := Antivary.sum_comp_perm_smul_eq_sum_smul_iff
-
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
`f` and `g`, which antivary together, is strictly decreased by a permutation if and only if
`f ∘ σ` and `g` do not antivary together. Stated by permuting the entries of `f`. -/
@@ -322,6 +344,7 @@ theorem Antivary.sum_smul_lt_sum_comp_perm_smul_iff (hfg : Antivary f g) :
∑ i, f i • g i < ∑ i, f (σ i) • g i ↔ ¬Antivary (f ∘ σ) g := by
simp [(hfg.antivaryOn _).sum_smul_lt_sum_comp_perm_smul_iff fun _ _ ↦ mem_univ _]
+end strict_inequality
end SMul
/-!
@@ -330,87 +353,84 @@ end SMul
Special cases of the above when scalar multiplication is actually multiplication.
-/
-
section Mul
-
-
-variable [LinearOrderedRing α] {s : Finset ι} {σ : Perm ι} {f g : ι → α}
+variable {s : Finset ι} {σ : Perm ι} {f g : ι → α}
/-- **Rearrangement Inequality**: Pointwise multiplication of `f` and `g` is maximized when `f` and
-`g` monovary together. Stated by permuting the entries of `g`. -/
-theorem MonovaryOn.sum_mul_comp_perm_le_sum_mul (hfg : MonovaryOn f g s)
- (hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f i * g (σ i) ≤ ∑ i ∈ s, f i * g i :=
+`g` monovary together on `s`. Stated by permuting the entries of `g`. -/
+theorem MonovaryOn.sum_mul_comp_perm_le_sum_mul (hfg : MonovaryOn f g s) (hσ : {x | σ x ≠ x} ⊆ s) :
+ ∑ i ∈ s, f i * g (σ i) ≤ ∑ i ∈ s, f i * g i :=
hfg.sum_smul_comp_perm_le_sum_smul hσ
/-- **Equality case of the Rearrangement Inequality**: Pointwise multiplication of `f` and `g`,
-which monovary together, is unchanged by a permutation if and only if `f` and `g ∘ σ` monovary
-together. Stated by permuting the entries of `g`. -/
+which monovary together on `s`, is unchanged by a permutation if and only if `f` and `g ∘ σ`
+monovary together on `s`. Stated by permuting the entries of `g`. -/
theorem MonovaryOn.sum_mul_comp_perm_eq_sum_mul_iff (hfg : MonovaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f i * g (σ i) = ∑ i ∈ s, f i * g i ↔ MonovaryOn f (g ∘ σ) s :=
hfg.sum_smul_comp_perm_eq_sum_smul_iff hσ
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise scalar multiplication of
-`f` and `g`, which monovary together, is strictly decreased by a permutation if and only if
-`f` and `g ∘ σ` do not monovary together. Stated by permuting the entries of `g`. -/
+`f` and `g`, which monovary together on `s`, is strictly decreased by a permutation if and only if
+`f` and `g ∘ σ` do not monovary together on `s`. Stated by permuting the entries of `g`. -/
theorem MonovaryOn.sum_mul_comp_perm_lt_sum_mul_iff (hfg : MonovaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f i • g (σ i) < ∑ i ∈ s, f i • g i ↔ ¬MonovaryOn f (g ∘ σ) s :=
hfg.sum_smul_comp_perm_lt_sum_smul_iff hσ
/-- **Rearrangement Inequality**: Pointwise multiplication of `f` and `g` is maximized when `f` and
-`g` monovary together. Stated by permuting the entries of `f`. -/
+`g` monovary together on `s`. Stated by permuting the entries of `f`. -/
theorem MonovaryOn.sum_comp_perm_mul_le_sum_mul (hfg : MonovaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f (σ i) * g i ≤ ∑ i ∈ s, f i * g i :=
hfg.sum_comp_perm_smul_le_sum_smul hσ
/-- **Equality case of the Rearrangement Inequality**: Pointwise multiplication of `f` and `g`,
-which monovary together, is unchanged by a permutation if and only if `f ∘ σ` and `g` monovary
-together. Stated by permuting the entries of `f`. -/
+which monovary together on `s`, is unchanged by a permutation if and only if `f ∘ σ` and `g`
+monovary together on `s`. Stated by permuting the entries of `f`. -/
theorem MonovaryOn.sum_comp_perm_mul_eq_sum_mul_iff (hfg : MonovaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f (σ i) * g i = ∑ i ∈ s, f i * g i ↔ MonovaryOn (f ∘ σ) g s :=
hfg.sum_comp_perm_smul_eq_sum_smul_iff hσ
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise multiplication of
-`f` and `g`, which monovary together, is strictly decreased by a permutation if and only if
-`f ∘ σ` and `g` do not monovary together. Stated by permuting the entries of `f`. -/
+`f` and `g`, which monovary together on `s`, is strictly decreased by a permutation if and only if
+`f ∘ σ` and `g` do not monovary together on `s`. Stated by permuting the entries of `f`. -/
theorem MonovaryOn.sum_comp_perm_mul_lt_sum_mul_iff (hfg : MonovaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f (σ i) * g i < ∑ i ∈ s, f i * g i ↔ ¬MonovaryOn (f ∘ σ) g s :=
hfg.sum_comp_perm_smul_lt_sum_smul_iff hσ
/-- **Rearrangement Inequality**: Pointwise multiplication of `f` and `g` is minimized when `f` and
-`g` antivary together. Stated by permuting the entries of `g`. -/
+`g` antivary together on `s`. Stated by permuting the entries of `g`. -/
theorem AntivaryOn.sum_mul_le_sum_mul_comp_perm (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f i * g i ≤ ∑ i ∈ s, f i * g (σ i) :=
hfg.sum_smul_le_sum_smul_comp_perm hσ
/-- **Equality case of the Rearrangement Inequality**: Pointwise multiplication of `f` and `g`,
-which antivary together, is unchanged by a permutation if and only if `f` and `g ∘ σ` antivary
-together. Stated by permuting the entries of `g`. -/
+which antivary together on `s`, is unchanged by a permutation if and only if `f` and `g ∘ σ`
+antivary together on `s`. Stated by permuting the entries of `g`. -/
theorem AntivaryOn.sum_mul_eq_sum_mul_comp_perm_iff (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f i * g (σ i) = ∑ i ∈ s, f i * g i ↔ AntivaryOn f (g ∘ σ) s :=
hfg.sum_smul_comp_perm_eq_sum_smul_iff hσ
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise multiplication of
-`f` and `g`, which antivary together, is strictly decreased by a permutation if and only if
-`f` and `g ∘ σ` do not antivary together. Stated by permuting the entries of `g`. -/
+`f` and `g`, which antivary together on `s`, is strictly decreased by a permutation if and only if
+`f` and `g ∘ σ` do not antivary together on `s`. Stated by permuting the entries of `g`. -/
theorem AntivaryOn.sum_mul_lt_sum_mul_comp_perm_iff (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f i * g i < ∑ i ∈ s, f i * g (σ i) ↔ ¬AntivaryOn f (g ∘ σ) s :=
hfg.sum_smul_lt_sum_smul_comp_perm_iff hσ
/-- **Rearrangement Inequality**: Pointwise multiplication of `f` and `g` is minimized when `f` and
-`g` antivary together. Stated by permuting the entries of `f`. -/
+`g` antivary together on `s`. Stated by permuting the entries of `f`. -/
theorem AntivaryOn.sum_mul_le_sum_comp_perm_mul (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) : ∑ i ∈ s, f i * g i ≤ ∑ i ∈ s, f (σ i) * g i :=
hfg.sum_smul_le_sum_comp_perm_smul hσ
/-- **Equality case of the Rearrangement Inequality**: Pointwise multiplication of `f` and `g`,
-which antivary together, is unchanged by a permutation if and only if `f ∘ σ` and `g` antivary
-together. Stated by permuting the entries of `f`. -/
+which antivary together on `s`, is unchanged by a permutation if and only if `f ∘ σ` and `g`
+antivary together on `s`. Stated by permuting the entries of `f`. -/
theorem AntivaryOn.sum_comp_perm_mul_eq_sum_mul_iff (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f (σ i) * g i = ∑ i ∈ s, f i * g i ↔ AntivaryOn (f ∘ σ) g s :=
@@ -420,8 +440,8 @@ theorem AntivaryOn.sum_comp_perm_mul_eq_sum_mul_iff (hfg : AntivaryOn f g s)
alias AntivaryOn.sum_mul_eq_sum_comp_perm_mul_iff := AntivaryOn.sum_comp_perm_mul_eq_sum_mul_iff
/-- **Strict inequality case of the Rearrangement Inequality**: Pointwise multiplication of
-`f` and `g`, which antivary together, is strictly decreased by a permutation if and only if
-`f ∘ σ` and `g` do not antivary together. Stated by permuting the entries of `f`. -/
+`f` and `g`, which antivary together on `s`, is strictly decreased by a permutation if and only if
+`f ∘ σ` and `g` do not antivary together on `s`. Stated by permuting the entries of `f`. -/
theorem AntivaryOn.sum_mul_lt_sum_comp_perm_mul_iff (hfg : AntivaryOn f g s)
(hσ : {x | σ x ≠ x} ⊆ s) :
∑ i ∈ s, f i * g i < ∑ i ∈ s, f (σ i) * g i ↔ ¬AntivaryOn (f ∘ σ) g s :=
diff --git a/Mathlib/Algebra/Order/Ring/Abs.lean b/Mathlib/Algebra/Order/Ring/Abs.lean
index 7d11531e4a537..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
@@ -43,7 +43,7 @@ lemma abs_two : |(2 : α)| = 2 := abs_of_pos zero_lt_two
lemma abs_mul (a b : α) : |a * b| = |a| * |b| := by
rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))]
rcases le_total a 0 with ha | ha <;> rcases le_total b 0 with hb | hb <;>
- simp only [abs_of_nonpos, abs_of_nonneg, true_or_iff, or_true_iff, eq_self_iff_true, neg_mul,
+ simp only [abs_of_nonpos, abs_of_nonneg, true_or, or_true, eq_self_iff_true, neg_mul,
mul_neg, neg_neg, *]
/-- `abs` as a `MonoidWithZeroHom`. -/
@@ -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 0d45fc5b2b588..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]
@@ -37,10 +37,6 @@ section OrderedSemiring
variable [OrderedSemiring R] {a b x y : R} {n m : ℕ}
-theorem zero_pow_le_one : ∀ n : ℕ, (0 : R) ^ n ≤ 1
- | 0 => (pow_zero _).le
- | n + 1 => by rw [zero_pow n.succ_ne_zero]; exact zero_le_one
-
theorem pow_add_pow_le (hx : 0 ≤ x) (hy : 0 ≤ y) (hn : n ≠ 0) : x ^ n + y ^ n ≤ (x + y) ^ n := by
rcases Nat.exists_eq_add_one_of_ne_zero hn with ⟨k, rfl⟩
induction k with
@@ -60,40 +56,21 @@ theorem pow_add_pow_le (hx : 0 ≤ x) (hy : 0 ≤ y) (hn : n ≠ 0) : x ^ n + y
rw [pow_succ' _ n]
exact mul_le_mul_of_nonneg_left (ih (Nat.succ_ne_zero k)) h2
-@[bound]
-theorem pow_le_one : ∀ n : ℕ, 0 ≤ a → a ≤ 1 → a ^ n ≤ 1
- | 0, _, _ => (pow_zero a).le
- | n + 1, h₀, h₁ => (pow_succ a n).le.trans (mul_le_one (pow_le_one n h₀ h₁) h₀ h₁)
-
-theorem pow_lt_one (h₀ : 0 ≤ a) (h₁ : a < 1) : ∀ {n : ℕ}, n ≠ 0 → a ^ n < 1
- | 0, h => (h rfl).elim
- | n + 1, _ => by
- rw [pow_succ']
- exact mul_lt_one_of_nonneg_of_lt_one_left h₀ h₁ (pow_le_one _ h₀ h₁.le)
-
-@[bound]
-theorem one_le_pow_of_one_le (H : 1 ≤ a) : ∀ n : ℕ, 1 ≤ a ^ n
- | 0 => by rw [pow_zero]
- | n + 1 => by
- rw [pow_succ']
- simpa only [mul_one] using
- mul_le_mul H (one_le_pow_of_one_le H n) zero_le_one (le_trans zero_le_one H)
-
-theorem pow_right_mono (h : 1 ≤ a) : Monotone (a ^ ·) :=
- monotone_nat_of_le_succ fun n => by
- rw [pow_succ']
- exact le_mul_of_one_le_left (pow_nonneg (zero_le_one.trans h) _) h
-
-@[gcongr]
-theorem pow_le_pow_right (ha : 1 ≤ a) (h : n ≤ m) : a ^ n ≤ a ^ m := pow_right_mono ha h
+attribute [bound] pow_le_one₀ one_le_pow₀
-theorem le_self_pow (ha : 1 ≤ a) (h : m ≠ 0) : a ≤ a ^ m := by
- simpa only [pow_one] using pow_le_pow_right ha <| Nat.pos_iff_ne_zero.2 h
+@[deprecated (since := "2024-09-28")] alias mul_le_one := mul_le_one₀
+@[deprecated (since := "2024-09-28")] alias pow_le_one := pow_le_one₀
+@[deprecated (since := "2024-09-28")] alias pow_lt_one := pow_lt_one₀
+@[deprecated (since := "2024-09-28")] alias one_le_pow_of_one_le := one_le_pow₀
+@[deprecated (since := "2024-09-28")] alias one_lt_pow := one_lt_pow₀
+@[deprecated (since := "2024-10-04")] alias pow_right_mono := pow_right_mono₀
+@[deprecated (since := "2024-10-04")] alias pow_le_pow_right := pow_le_pow_right₀
+@[deprecated (since := "2024-10-04")] alias le_self_pow := le_self_pow₀
/-- The `bound` tactic can't handle `m ≠ 0` goals yet, so we express as `0 < m` -/
@[bound]
lemma Bound.le_self_pow_of_pos {m : ℕ} (ha : 1 ≤ a) (h : 0 < m) : a ≤ a ^ m :=
- le_self_pow ha h.ne'
+ le_self_pow₀ ha h.ne'
@[mono, gcongr, bound]
theorem pow_le_pow_left {a b : R} (ha : 0 ≤ a) (hab : a ≤ b) : ∀ n, a ^ n ≤ b ^ n
@@ -101,12 +78,6 @@ theorem pow_le_pow_left {a b : R} (ha : 0 ≤ a) (hab : a ≤ b) : ∀ n, a ^ n
| n + 1 => by simpa only [pow_succ']
using mul_le_mul hab (pow_le_pow_left ha hab _) (pow_nonneg ha _) (ha.trans hab)
-theorem one_lt_pow (ha : 1 < a) : ∀ {n : ℕ} (_ : n ≠ 0), 1 < a ^ n
- | 0, h => (h rfl).elim
- | n + 1, _ => by
- rw [pow_succ']
- exact one_lt_mul_of_lt_of_le ha (one_le_pow_of_one_le ha.le _)
-
lemma pow_add_pow_le' (ha : 0 ≤ a) (hb : 0 ≤ b) : a ^ n + b ^ n ≤ 2 * (a + b) ^ n := by
rw [two_mul]
exact add_le_add (pow_le_pow_left ha (le_add_of_nonneg_right hb) _)
@@ -117,7 +88,7 @@ lemma pow_add_pow_le' (ha : 0 ≤ a) (hb : 0 ≤ b) : a ^ n + b ^ n ≤ 2 * (a +
lemma Bound.pow_le_pow_right_of_le_one_or_one_le (h : 1 ≤ a ∧ n ≤ m ∨ 0 ≤ a ∧ a ≤ 1 ∧ m ≤ n) :
a ^ n ≤ a ^ m := by
rcases h with ⟨a1, nm⟩ | ⟨a0, a1, mn⟩
- · exact pow_le_pow_right a1 nm
+ · exact pow_right_mono₀ a1 nm
· exact pow_le_pow_of_le_one a0 a1 mn
end OrderedSemiring
@@ -128,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
@@ -361,36 +332,3 @@ lemma pow_four_le_pow_two_of_pow_two_le (h : a ^ 2 ≤ b) : a ^ 4 ≤ b ^ 2 :=
(pow_mul a 2 2).symm ▸ pow_le_pow_left (sq_nonneg a) h 2
end LinearOrderedSemiring
-
-/-!
-### Deprecated lemmas
-
-Those lemmas have been deprecated on 2023-12-23.
--/
-
-@[deprecated (since := "2023-12-23")] alias pow_mono := pow_right_mono
-@[deprecated (since := "2023-12-23")] alias pow_le_pow := pow_le_pow_right
-@[deprecated (since := "2023-12-23")] alias pow_le_pow_of_le_left := pow_le_pow_left
-@[deprecated (since := "2023-12-23")] alias pow_lt_pow_of_lt_left := pow_lt_pow_left
-@[deprecated (since := "2023-12-23")] alias strictMonoOn_pow := pow_left_strictMonoOn
-@[deprecated (since := "2023-12-23")] alias pow_strictMono_right := pow_right_strictMono
-@[deprecated (since := "2023-12-23")] alias pow_lt_pow := pow_lt_pow_right
-@[deprecated (since := "2023-12-23")] alias pow_lt_pow_iff := pow_lt_pow_iff_right
-@[deprecated (since := "2023-12-23")] alias pow_le_pow_iff := pow_le_pow_iff_right
-@[deprecated (since := "2023-12-23")] alias self_lt_pow := lt_self_pow
-@[deprecated (since := "2023-12-23")] alias strictAnti_pow := pow_right_strictAnti
-
-@[deprecated (since := "2023-12-23")]
-alias pow_lt_pow_iff_of_lt_one := pow_lt_pow_iff_right_of_lt_one
-
-@[deprecated (since := "2023-12-23")] alias pow_lt_pow_of_lt_one := pow_lt_pow_right_of_lt_one
-@[deprecated (since := "2023-12-23")] alias lt_of_pow_lt_pow := lt_of_pow_lt_pow_left
-@[deprecated (since := "2023-12-23")] alias le_of_pow_le_pow := le_of_pow_le_pow_left
-@[deprecated (since := "2023-12-23")] alias self_le_pow := le_self_pow
-@[deprecated (since := "2023-12-23")] alias Nat.pow_lt_pow_of_lt_right := pow_lt_pow_right
-
-@[deprecated (since := "2023-12-23")]
-protected alias Nat.pow_right_strictMono := pow_right_strictMono
-
-@[deprecated (since := "2023-12-23")] alias Nat.pow_le_iff_le_right := pow_le_pow_iff_right
-@[deprecated (since := "2023-12-23")] alias Nat.pow_lt_iff_lt_right := pow_lt_pow_iff_right
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 98e9a362cfbdd..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
@@ -37,6 +37,8 @@ lemma cast_mono : Monotone (Int.cast : ℤ → R) := by
rw [← sub_nonneg, ← cast_sub, ← hk, cast_natCast]
exact k.cast_nonneg'
+@[gcongr] protected lemma GCongr.intCast_mono {m n : ℤ} (hmn : m ≤ n) : (m : R) ≤ n := cast_mono hmn
+
variable [NeZero (1 : R)] {m n : ℤ}
@[simp] lemma cast_nonneg : ∀ {n : ℤ}, (0 : R) ≤ n ↔ 0 ≤ n
@@ -53,6 +55,8 @@ lemma cast_strictMono : StrictMono (fun x : ℤ => (x : R)) :=
@[simp, norm_cast] lemma cast_lt : (m : R) < n ↔ m < n := cast_strictMono.lt_iff_lt
+@[gcongr] protected alias ⟨_, GCongr.intCast_strictMono⟩ := Int.cast_lt
+
@[simp] lemma cast_nonpos : (n : R) ≤ 0 ↔ n ≤ 0 := by rw [← cast_zero, cast_le]
@[simp] lemma cast_pos : (0 : R) < n ↔ 0 < n := by rw [← cast_zero, cast_lt]
diff --git a/Mathlib/Algebra/Order/Ring/Cone.lean b/Mathlib/Algebra/Order/Ring/Cone.lean
index 4ddd18e2f67d0..097bfc9afe3ca 100644
--- a/Mathlib/Algebra/Order/Ring/Cone.lean
+++ b/Mathlib/Algebra/Order/Ring/Cone.lean
@@ -19,7 +19,7 @@ cones in rings and the corresponding ordered rings.
-/
/-- `RingConeClass S R` says that `S` is a type of cones in `R`. -/
-class RingConeClass (S R : Type*) [Ring R] [SetLike S R]
+class RingConeClass (S : Type*) (R : outParam Type*) [Ring R] [SetLike S R]
extends AddGroupConeClass S R, SubsemiringClass S R : Prop
/-- A (positive) cone in a ring is a subsemiring that
@@ -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 7e1dda2f4617c..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 α :=
@@ -222,6 +222,22 @@ instance (priority := 100) OrderedRing.toOrderedSemiring : OrderedSemiring α :=
mul_le_mul_of_nonneg_right := fun a b c h hc => by
simpa only [sub_mul, sub_nonneg] using OrderedRing.mul_nonneg _ _ (sub_nonneg.2 h) hc }
+lemma one_add_le_one_sub_mul_one_add (h : a + b + b * c ≤ c) : 1 + a ≤ (1 - b) * (1 + c) := by
+ rw [one_sub_mul, mul_one_add, le_sub_iff_add_le, add_assoc, ← add_assoc a]
+ gcongr
+
+lemma one_add_le_one_add_mul_one_sub (h : a + c + b * c ≤ b) : 1 + a ≤ (1 + b) * (1 - c) := by
+ rw [mul_one_sub, one_add_mul, le_sub_iff_add_le, add_assoc, ← add_assoc a]
+ gcongr
+
+lemma one_sub_le_one_sub_mul_one_add (h : b + b * c ≤ a + c) : 1 - a ≤ (1 - b) * (1 + c) := by
+ rw [one_sub_mul, mul_one_add, sub_le_sub_iff, add_assoc, add_comm c]
+ gcongr
+
+lemma one_sub_le_one_add_mul_one_sub (h : c + b * c ≤ a + b) : 1 - a ≤ (1 + b) * (1 - c) := by
+ rw [mul_one_sub, one_add_mul, sub_le_sub_iff, add_assoc, add_comm b]
+ gcongr
+
end OrderedRing
section OrderedCommRing
@@ -236,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 α :=
@@ -304,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 α :=
@@ -357,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 α :=
@@ -396,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/Opposite.lean b/Mathlib/Algebra/Order/Ring/Opposite.lean
new file mode 100644
index 0000000000000..c945c5ec82242
--- /dev/null
+++ b/Mathlib/Algebra/Order/Ring/Opposite.lean
@@ -0,0 +1,50 @@
+/-
+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.Order.Group.Opposite
+import Mathlib.Algebra.Order.Ring.Defs
+import Mathlib.Algebra.Ring.Opposite
+
+/-!
+# Ordered ring instances for `MulOpposite`/`AddOpposite`
+
+This files transfers ordered (semi)ring instances from `α` to `αᵐᵒᵖ` and `αᵃᵒᵖ`.
+-/
+
+variable {α : Type*}
+
+namespace MulOpposite
+
+instance [OrderedSemiring α] : OrderedSemiring αᵐᵒᵖ where
+ __ := instSemiring
+ __ := instOrderedAddCommMonoid
+ zero_le_one := zero_le_one (α := α)
+ mul_le_mul_of_nonneg_left _ _ _ := mul_le_mul_of_nonneg_right (α := α)
+ mul_le_mul_of_nonneg_right _ _ _ := mul_le_mul_of_nonneg_left (α := α)
+
+instance [OrderedRing α] : OrderedRing αᵐᵒᵖ where
+ __ := instRing
+ __ := instOrderedAddCommGroup
+ __ := instOrderedSemiring
+ mul_nonneg _a _b ha hb := mul_nonneg (α := α) hb ha
+
+end MulOpposite
+
+namespace AddOpposite
+
+instance [OrderedSemiring α] : OrderedSemiring αᵃᵒᵖ where
+ __ := instSemiring
+ __ := instOrderedAddCommMonoid
+ zero_le_one := zero_le_one (α := α)
+ mul_le_mul_of_nonneg_left _ _ _ := mul_le_mul_of_nonneg_left (α := α)
+ mul_le_mul_of_nonneg_right _ _ _ := mul_le_mul_of_nonneg_right (α := α)
+
+instance [OrderedRing α] : OrderedRing αᵐᵒᵖ where
+ __ := instRing
+ __ := instOrderedAddCommGroup
+ __ := instOrderedSemiring
+ mul_nonneg _a _b := mul_nonneg (α := α)
+
+end AddOpposite
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 68c19b0c396c3..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,52 +784,46 @@ 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 <|
mul_le_mul h₂ h₂ (neg_nonneg.2 h) <| (neg_nonneg.2 h).trans h₂
end LinearOrderedRing
-
-@[deprecated (since := "2023-12-23")] alias zero_le_mul_left := mul_nonneg_iff_of_pos_left
-@[deprecated (since := "2023-12-23")] alias zero_le_mul_right := mul_nonneg_iff_of_pos_right
-@[deprecated (since := "2023-12-23")] alias zero_lt_mul_left := mul_pos_iff_of_pos_left
-@[deprecated (since := "2023-12-23")] alias zero_lt_mul_right := mul_pos_iff_of_pos_right
-
end OrderedCommRing
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/Ring/WithTop.lean b/Mathlib/Algebra/Order/Ring/WithTop.lean
index 3ee35faa46055..6ac933856d0ad 100644
--- a/Mathlib/Algebra/Order/Ring/WithTop.lean
+++ b/Mathlib/Algebra/Order/Ring/WithTop.lean
@@ -83,7 +83,7 @@ theorem mul_lt_top [LT α] {a b : WithTop α} (ha : a < ⊤) (hb : b < ⊤) : a
@[deprecated (since := "2024-08-25")] alias mul_lt_top' := mul_lt_top
instance instNoZeroDivisors [NoZeroDivisors α] : NoZeroDivisors (WithTop α) := by
- refine ⟨fun h₁ => Decidable.by_contradiction fun h₂ => ?_⟩
+ refine ⟨fun h₁ => Decidable.byContradiction fun h₂ => ?_⟩
rw [mul_def, if_neg h₂] at h₁
rcases Option.mem_map₂_iff.1 h₁ with ⟨a, b, (rfl : _ = _), (rfl : _ = _), hab⟩
exact h₂ ((eq_zero_or_eq_zero_of_mul_eq_zero hab).imp (congr_arg some) (congr_arg some))
diff --git a/Mathlib/Algebra/Order/Star/Basic.lean b/Mathlib/Algebra/Order/Star/Basic.lean
index 055ffe59379d4..42f4b5b776602 100644
--- a/Mathlib/Algebra/Order/Star/Basic.lean
+++ b/Mathlib/Algebra/Order/Star/Basic.lean
@@ -1,12 +1,14 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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/Conjneg.lean b/Mathlib/Algebra/Order/Star/Conjneg.lean
index 091da606b1727..e3a93e2c3e500 100644
--- a/Mathlib/Algebra/Order/Star/Conjneg.lean
+++ b/Mathlib/Algebra/Order/Star/Conjneg.lean
@@ -13,7 +13,7 @@ import Mathlib.Algebra.Star.Conjneg
open scoped ComplexConjugate
-variable {ι G R : Type*} [AddGroup G]
+variable {G R : Type*} [AddGroup G]
section OrderedCommSemiring
variable [OrderedCommSemiring R] [StarRing R] [StarOrderedRing R] {f : G → R}
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 eff553b812467..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
@@ -41,7 +41,7 @@ TODO: generalize `Nat.le_of_le_of_sub_le_sub_right`, `Nat.sub_le_sub_right_iff`,
-/
-variable {α β : Type*}
+variable {α : Type*}
/-- `OrderedSub α` means that `α` has a subtraction characterized by `a - b ≤ c ↔ a ≤ c + b`.
In other words, `a - b` is the least `c` such that `a ≤ b + c`.
@@ -60,9 +60,9 @@ theorem tsub_le_iff_right [LE α] [Add α] [Sub α] [OrderedSub α] {a b c : α}
a - b ≤ c ↔ a ≤ c + b :=
OrderedSub.tsub_le_iff_right a b c
-variable [Preorder α] [Add α] [Sub α] [OrderedSub α] {a b c d : α}
+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
@@ -83,14 +83,14 @@ variable [Preorder α]
section AddCommSemigroup
variable [AddCommSemigroup α] [Sub α] [OrderedSub α] {a b c d : α}
-/- TODO: Most results can be generalized to [Add α] [IsSymmOp α α (· + ·)] -/
+/- TODO: Most results can be generalized to [Add α] [@Std.Commutative α (· + ·)] -/
theorem tsub_le_iff_left : a - b ≤ c ↔ a ≤ b + c := by rw [tsub_le_iff_right, add_comm]
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
@@ -210,7 +210,7 @@ end Contra
end AddCommSemigroup
-variable [AddCommMonoid α] [Sub α] [OrderedSub α] {a b c d : α}
+variable [AddCommMonoid α] [Sub α] [OrderedSub α] {a b : α}
theorem tsub_nonpos : a - b ≤ 0 ↔ a ≤ b := by rw [tsub_le_iff_left, add_zero]
@@ -243,17 +243,39 @@ theorem tsub_right_comm : a - b - c = a - c - b := by
namespace AddLECancellable
+/-- See `AddLECancellable.tsub_eq_of_eq_add'` for a version assuming that `a = c + b` itself is
+cancellable rather than `b`. -/
protected theorem tsub_eq_of_eq_add (hb : AddLECancellable b) (h : a = c + b) : a - b = c :=
le_antisymm (tsub_le_iff_right.mpr h.le) <| by
rw [h]
exact hb.le_add_tsub
+/-- 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' [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
+cancellable rather than `c`. -/
protected theorem eq_tsub_of_add_eq (hc : AddLECancellable c) (h : a + c = b) : a = b - c :=
(hc.tsub_eq_of_eq_add h.symm).symm
+/-- 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' [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
+cancellable rather than `b`. -/
protected theorem tsub_eq_of_eq_add_rev (hb : AddLECancellable b) (h : a = b + c) : a - b = c :=
hb.tsub_eq_of_eq_add <| by rw [add_comm, h]
+/-- 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' [AddLeftMono α]
+ (ha : AddLECancellable a) (h : a = b + c) : a - b = c :=
+ ha.tsub_eq_of_eq_add' <| by rw [add_comm, h]
+
@[simp]
protected theorem add_tsub_cancel_right (hb : AddLECancellable b) : a + b - b = a :=
hb.tsub_eq_of_eq_add <| by rw [add_comm]
@@ -290,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
@@ -333,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 <| ?_)
@@ -353,7 +375,7 @@ end OrderedAddCommSemigroup
section LinearOrder
-variable {a b c d : α} [LinearOrder α] [AddCommSemigroup α] [Sub α] [OrderedSub α]
+variable {a b c : α} [LinearOrder α] [AddCommSemigroup α] [Sub α] [OrderedSub α]
/-- See `lt_of_tsub_lt_tsub_right_of_le` for a weaker statement in a partial order. -/
theorem lt_of_tsub_lt_tsub_right (h : a - c < b - c) : a < b :=
@@ -372,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/Prod.lean b/Mathlib/Algebra/Order/Sub/Prod.lean
index de620a351ddd8..9dcb9c7e845d2 100644
--- a/Mathlib/Algebra/Order/Sub/Prod.lean
+++ b/Mathlib/Algebra/Order/Sub/Prod.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Prod
import Mathlib.Algebra.Order.Sub.Defs
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 2bf9585fa56a6..6d9cedb09fb7c 100644
--- a/Mathlib/Algebra/Order/Sub/Unbundled/Hom.lean
+++ b/Mathlib/Algebra/Order/Sub/Unbundled/Hom.lean
@@ -16,7 +16,7 @@ variable {α β : Type*}
section Add
-variable [Preorder α] [Add α] [Sub α] [OrderedSub α] {a b c d : α}
+variable [Preorder α] [Add α] [Sub α] [OrderedSub α]
theorem AddHom.le_map_tsub [Preorder β] [Add β] [Sub β] [OrderedSub β] (f : AddHom α β)
(hf : Monotone f) (a b : α) : f a - f b ≤ f (a - b) := by
@@ -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
@@ -49,7 +49,7 @@ theorem OrderIso.map_tsub {M N : Type*} [Preorder M] [Add M] [Sub M] [OrderedSub
section Preorder
variable [Preorder α]
-variable [AddCommMonoid α] [Sub α] [OrderedSub α] {a b c d : α}
+variable [AddCommMonoid α] [Sub α] [OrderedSub α]
theorem AddMonoidHom.le_map_tsub [Preorder β] [AddCommMonoid β] [Sub β] [OrderedSub β] (f : α →+ β)
(hf : Monotone f) (a b : α) : f a - f b ≤ f (a - b) :=
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
new file mode 100644
index 0000000000000..7c69e6dc40162
--- /dev/null
+++ b/Mathlib/Algebra/Order/SuccPred/TypeTags.lean
@@ -0,0 +1,50 @@
+/-
+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.SuccPred.Archimedean
+import Mathlib.Algebra.Order.Monoid.Unbundled.TypeTags
+
+/-!
+# Successor and predecessor on type tags
+
+This file declates successor and predecessor orders on type tags.
+
+-/
+
+variable {X : Type*}
+
+instance [Preorder X] [h : SuccOrder X] : SuccOrder (Multiplicative X) := h
+instance [Preorder X] [h : SuccOrder X] : SuccOrder (Additive X) := h
+
+instance [Preorder X] [h : PredOrder X] : PredOrder (Multiplicative X) := h
+instance [Preorder X] [h : PredOrder X] : PredOrder (Additive X) := h
+
+instance [Preorder X] [SuccOrder X] [h : IsSuccArchimedean X] :
+ IsSuccArchimedean (Multiplicative X) := h
+instance [Preorder X] [SuccOrder X] [h : IsSuccArchimedean X] :
+ IsSuccArchimedean (Additive X) := h
+
+instance [Preorder X] [PredOrder X] [h : IsPredArchimedean X] :
+ IsPredArchimedean (Multiplicative X) := h
+instance [Preorder X] [PredOrder X] [h : IsPredArchimedean X] :
+ IsPredArchimedean (Additive X) := h
+
+namespace Order
+
+open Additive Multiplicative
+
+@[simp] lemma succ_ofMul [Preorder X] [SuccOrder X] (x : X) : succ (ofMul x) = ofMul (succ x) := rfl
+@[simp] lemma succ_toMul [Preorder X] [SuccOrder X] (x : X) : succ (toMul x) = toMul (succ x) := rfl
+
+@[simp] lemma succ_ofAdd [Preorder X] [SuccOrder X] (x : X) : succ (ofAdd x) = ofAdd (succ x) := rfl
+@[simp] lemma succ_toAdd [Preorder X] [SuccOrder X] (x : X) : succ (toAdd x) = toAdd (succ x) := rfl
+
+@[simp] lemma pred_ofMul [Preorder X] [PredOrder X] (x : X) : pred (ofMul x) = ofMul (pred x) := rfl
+@[simp] lemma pred_toMul [Preorder X] [PredOrder X] (x : X) : pred (toMul x) = toMul (pred x) := rfl
+
+@[simp] lemma pred_ofAdd [Preorder X] [PredOrder X] (x : X) : pred (ofAdd x) = ofAdd (pred x) := rfl
+@[simp] lemma pred_toAdd [Preorder X] [PredOrder X] (x : X) : pred (toAdd x) = toAdd (pred x) := rfl
+
+end Order
diff --git a/Mathlib/Algebra/Order/ToIntervalMod.lean b/Mathlib/Algebra/Order/ToIntervalMod.lean
index 938027eaa347f..0080b14e43fd5 100644
--- a/Mathlib/Algebra/Order/ToIntervalMod.lean
+++ b/Mathlib/Algebra/Order/ToIntervalMod.lean
@@ -517,23 +517,23 @@ theorem tfae_modEq :
[a ≡ b [PMOD p], ∀ z : ℤ, b - z • p ∉ Set.Ioo a (a + p), toIcoMod hp a b ≠ toIocMod hp a b,
toIcoMod hp a b + p = toIocMod hp a b] := by
rw [modEq_iff_toIcoMod_eq_left hp]
- tfae_have 3 → 2
- · rw [← not_exists, not_imp_not]
+ tfae_have 3 → 2 := by
+ rw [← not_exists, not_imp_not]
exact fun ⟨i, hi⟩ =>
((toIcoMod_eq_iff hp).2 ⟨Set.Ioo_subset_Ico_self hi, i, (sub_add_cancel b _).symm⟩).trans
((toIocMod_eq_iff hp).2 ⟨Set.Ioo_subset_Ioc_self hi, i, (sub_add_cancel b _).symm⟩).symm
tfae_have 4 → 3
- · intro h
+ | h => by
rw [← h, Ne, eq_comm, add_right_eq_self]
exact hp.ne'
tfae_have 1 → 4
- · intro h
+ | h => by
rw [h, eq_comm, toIocMod_eq_iff, Set.right_mem_Ioc]
refine ⟨lt_add_of_pos_right a hp, toIcoDiv hp a b - 1, ?_⟩
rw [sub_one_zsmul, add_add_add_comm, add_neg_cancel, add_zero]
conv_lhs => rw [← toIcoMod_add_toIcoDiv_zsmul hp a b, h]
- tfae_have 2 → 1
- · rw [← not_exists, not_imp_comm]
+ tfae_have 2 → 1 := by
+ rw [← not_exists, not_imp_comm]
have h' := toIcoMod_mem_Ico hp a b
exact fun h => ⟨_, h'.1.lt_of_ne' h, h'.2⟩
tfae_finish
@@ -557,12 +557,12 @@ theorem not_modEq_iff_toIcoMod_eq_toIocMod : ¬a ≡ b [PMOD p] ↔ toIcoMod hp
theorem not_modEq_iff_toIcoDiv_eq_toIocDiv :
¬a ≡ b [PMOD p] ↔ toIcoDiv hp a b = toIocDiv hp a b := by
rw [not_modEq_iff_toIcoMod_eq_toIocMod hp, toIcoMod, toIocMod, sub_right_inj,
- (zsmul_strictMono_left hp).injective.eq_iff]
+ zsmul_left_inj hp]
theorem modEq_iff_toIcoDiv_eq_toIocDiv_add_one :
a ≡ b [PMOD p] ↔ toIcoDiv hp a b = toIocDiv hp a b + 1 := by
rw [modEq_iff_toIcoMod_add_period_eq_toIocMod hp, toIcoMod, toIocMod, ← eq_sub_iff_add_eq,
- sub_sub, sub_right_inj, ← add_one_zsmul, (zsmul_strictMono_left hp).injective.eq_iff]
+ sub_sub, sub_right_inj, ← add_one_zsmul, zsmul_left_inj hp]
end AddCommGroup
@@ -595,7 +595,7 @@ theorem toIcoMod_le_toIocMod (a b : α) : toIcoMod hp a b ≤ toIocMod hp a b :=
theorem toIocMod_le_toIcoMod_add (a b : α) : toIocMod hp a b ≤ toIcoMod hp a b + p := by
rw [toIcoMod, toIocMod, sub_add, sub_le_sub_iff_left, sub_le_iff_le_add, ← add_one_zsmul,
- (zsmul_strictMono_left hp).le_iff_le]
+ (zsmul_left_strictMono hp).le_iff_le]
apply (toIocDiv_wcovBy_toIcoDiv _ _ _).le_succ
end IcoIoc
@@ -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/Order/ZeroLEOne.lean b/Mathlib/Algebra/Order/ZeroLEOne.lean
index ecd0e356d73ad..538c8f6985b42 100644
--- a/Mathlib/Algebra/Order/ZeroLEOne.lean
+++ b/Mathlib/Algebra/Order/ZeroLEOne.lean
@@ -4,7 +4,6 @@ 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.Order.Basic
-import Mathlib.Algebra.NeZero
/-!
# Typeclass expressing `0 ≤ 1`.
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 deab88e20079c..0596f27478672 100644
--- a/Mathlib/Algebra/Pointwise/Stabilizer.lean
+++ b/Mathlib/Algebra/Pointwise/Stabilizer.lean
@@ -3,8 +3,8 @@ Copyright (c) 2023 Yaël Dillies. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies
-/
-import Mathlib.Data.Finset.Pointwise.Basic
-import Mathlib.GroupTheory.QuotientGroup.Basic
+import Mathlib.Algebra.Group.Pointwise.Finset.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 9f4745493a802..8b2599a1e1c97 100644
--- a/Mathlib/Algebra/Polynomial/AlgebraMap.lean
+++ b/Mathlib/Algebra/Polynomial/AlgebraMap.lean
@@ -1,11 +1,12 @@
/-
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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.Algebra.Pi
import Mathlib.Algebra.Polynomial.Eval
import Mathlib.RingTheory.Adjoin.Basic
+import Mathlib.Algebra.MonoidAlgebra.Basic
/-!
# Theory of univariate polynomials
@@ -102,7 +103,7 @@ instance subalgebraNontrivial [Nontrivial A] : Nontrivial (Subalgebra R A[X]) :=
⟨⟨⊥, ⊤, by
rw [Ne, SetLike.ext_iff, not_forall]
refine ⟨X, ?_⟩
- simp only [Algebra.mem_bot, not_exists, Set.mem_range, iff_true_iff, Algebra.mem_top,
+ simp only [Algebra.mem_bot, not_exists, Set.mem_range, iff_true, Algebra.mem_top,
algebraMap_apply, not_forall]
intro x
rw [ext_iff, not_forall]
@@ -293,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]
@@ -526,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]
@@ -560,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 68935a4228a94..57f4bba5519be 100644
--- a/Mathlib/Algebra/Polynomial/Basic.lean
+++ b/Mathlib/Algebra/Polynomial/Basic.lean
@@ -1,11 +1,11 @@
/-
Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Chris Hughes, Johannes Hölzl, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.GroupWithZero.Divisibility
-import Mathlib.Algebra.MonoidAlgebra.Basic
import Mathlib.Data.Finset.Sort
+import Mathlib.Algebra.MonoidAlgebra.Defs
/-!
# Theory of univariate polynomials
@@ -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 ffa4e0a8e9d60..557f139b15527 100644
--- a/Mathlib/Algebra/Polynomial/BigOperators.lean
+++ b/Mathlib/Algebra/Polynomial/BigOperators.lean
@@ -47,7 +47,7 @@ theorem natDegree_list_sum_le (l : List S[X]) : natDegree l.sum ≤ (l.map natDe
List.sum_le_foldr_max natDegree (by simp) natDegree_add_le _
theorem natDegree_multiset_sum_le (l : Multiset S[X]) :
- natDegree l.sum ≤ (l.map natDegree).foldr max max_left_comm 0 :=
+ natDegree l.sum ≤ (l.map natDegree).foldr max 0 :=
Quotient.inductionOn l (by simpa using natDegree_list_sum_le)
theorem natDegree_sum_le (f : ι → S[X]) :
@@ -68,7 +68,7 @@ theorem degree_list_sum_le (l : List S[X]) : degree l.sum ≤ (l.map natDegree).
rw [← List.foldr_max_of_ne_nil]
· congr
contrapose! h
- rw [List.map_eq_nil] at h
+ rw [List.map_eq_nil_iff] at h
simp [h]
theorem natDegree_list_prod_le (l : List S[X]) : natDegree l.prod ≤ (l.map natDegree).sum := by
@@ -186,24 +186,35 @@ theorem natDegree_multiset_prod_of_monic (h : ∀ f ∈ t, Monic f) :
rw [this]
simp
convert prod_replicate (Multiset.card t) (1 : R)
- · simp only [eq_replicate, Multiset.card_map, eq_self_iff_true, true_and_iff]
+ · simp only [eq_replicate, Multiset.card_map, eq_self_iff_true, true_and]
rintro i hi
obtain ⟨i, hi, rfl⟩ := Multiset.mem_map.mp hi
apply h
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 b2747d4680f9f..383ce0d93d741 100644
--- a/Mathlib/Algebra/Polynomial/Coeff.lean
+++ b/Mathlib/Algebra/Polynomial/Coeff.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.MonoidAlgebra.Support
import Mathlib.Algebra.Polynomial.Basic
@@ -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,14 +212,14 @@ 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_of_not hkm.ne (mt mem_singleton.mp (hkm.trans hmn).ne))),
+ (mt mem_insert.mp (not_or_intro hkm.ne (mt mem_singleton.mp (hkm.trans hmn).ne))),
card_insert_of_not_mem (mt mem_singleton.mp hmn.ne), card_singleton]
end Fewnomials
@@ -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/CardPowDegree.lean b/Mathlib/Algebra/Polynomial/Degree/CardPowDegree.lean
index 1a1dd67ce6467..8b5296df327a3 100644
--- a/Mathlib/Algebra/Polynomial/Degree/CardPowDegree.lean
+++ b/Mathlib/Algebra/Polynomial/Degree/CardPowDegree.lean
@@ -50,7 +50,7 @@ noncomputable def cardPowDegree : AbsoluteValue Fq[X] ℤ :=
· rfl
exact pow_nonneg (Int.ofNat_zero_le _) _
eq_zero' := fun p =>
- ite_eq_left_iff.trans <|
+ ite_eq_left_iff.trans
⟨fun h => by
contrapose! h
exact ⟨h, (pow_pos _).ne'⟩, absurd⟩
@@ -61,7 +61,7 @@ noncomputable def cardPowDegree : AbsoluteValue Fq[X] ℤ :=
· simp only [hpq, hp, hq, eq_self_iff_true, if_true, if_false]
exact add_nonneg (pow_pos _).le (pow_pos _).le
simp only [hpq, hp, hq, if_false]
- refine le_trans (pow_le_pow_right (by omega) (Polynomial.natDegree_add_le _ _)) ?_
+ refine le_trans (pow_right_mono₀ (by omega) (Polynomial.natDegree_add_le _ _)) ?_
refine
le_trans (le_max_iff.mpr ?_)
(max_le_add_of_nonneg (pow_nonneg (by omega) _) (pow_nonneg (by omega) _))
diff --git a/Mathlib/Algebra/Polynomial/Degree/Definitions.lean b/Mathlib/Algebra/Polynomial/Degree/Definitions.lean
index c1bc0023501f9..e5cc71815055f 100644
--- a/Mathlib/Algebra/Polynomial/Degree/Definitions.lean
+++ b/Mathlib/Algebra/Polynomial/Degree/Definitions.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.MonoidAlgebra.Degree
import Mathlib.Algebra.Polynomial.Coeff
@@ -237,6 +237,12 @@ theorem natDegree_natCast (n : ℕ) : natDegree (n : R[X]) = 0 := by
@[deprecated (since := "2024-04-17")]
alias natDegree_nat_cast := natDegree_natCast
+-- See note [no_index around OfNat.ofNat]
+@[simp]
+theorem natDegree_ofNat (n : ℕ) [Nat.AtLeastTwo n] :
+ natDegree (no_index (OfNat.ofNat n : R[X])) = 0 :=
+ natDegree_natCast _
+
theorem degree_natCast_le (n : ℕ) : degree (n : R[X]) ≤ 0 := degree_le_of_natDegree_le (by simp)
@[deprecated (since := "2024-04-17")]
@@ -408,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
@@ -752,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
@@ -768,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
@@ -882,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 :=
@@ -1364,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]
@@ -1414,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
-
-@[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
+variable [IsDomain R] {p q : R[X]}
-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 d3cc2b29e0004..00c456c6a6f64 100644
--- a/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean
+++ b/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.Polynomial.Eval
@@ -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/DenomsClearable.lean b/Mathlib/Algebra/Polynomial/DenomsClearable.lean
index a9004b5762139..16046a197ca3d 100644
--- a/Mathlib/Algebra/Polynomial/DenomsClearable.lean
+++ b/Mathlib/Algebra/Polynomial/DenomsClearable.lean
@@ -5,6 +5,7 @@ Authors: Damiano Testa
-/
import Mathlib.Algebra.Polynomial.EraseLead
import Mathlib.Algebra.Polynomial.Eval
+import Mathlib.Algebra.Algebra.Basic
/-!
# Denominators of evaluation of polynomials at ratios
diff --git a/Mathlib/Algebra/Polynomial/Derivative.lean b/Mathlib/Algebra/Polynomial/Derivative.lean
index e4eb94abf7e30..899b80f020a97 100644
--- a/Mathlib/Algebra/Polynomial/Derivative.lean
+++ b/Mathlib/Algebra/Polynomial/Derivative.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.GroupPower.IterateHom
import Mathlib.Algebra.Polynomial.Eval
@@ -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
@@ -295,7 +294,7 @@ theorem mem_support_derivative [NoZeroSMulDivisors ℕ R] (p : R[X]) (n : ℕ) :
suffices ¬p.coeff (n + 1) * (n + 1 : ℕ) = 0 ↔ coeff p (n + 1) ≠ 0 by
simpa only [mem_support_iff, coeff_derivative, Ne, Nat.cast_succ]
rw [← nsmul_eq_mul', smul_eq_zero]
- simp only [Nat.succ_ne_zero, false_or_iff]
+ simp only [Nat.succ_ne_zero, false_or]
@[simp]
theorem degree_derivative_eq [NoZeroSMulDivisors ℕ R] (p : R[X]) (hp : 0 < natDegree 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 7533319d50143..804749c1a188a 100644
--- a/Mathlib/Algebra/Polynomial/Div.lean
+++ b/Mathlib/Algebra/Polynomial/Div.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.Polynomial.Inductions
import Mathlib.Algebra.Polynomial.Monic
@@ -281,7 +281,7 @@ theorem degree_divByMonic_le (p q : R[X]) : degree (p /ₘ q) ≤ degree p :=
exact WithBot.coe_le_coe.2 (Nat.le_add_left _ _)
else by
unfold divByMonic divModByMonicAux
- simp [dif_pos hq, h, false_and_iff, if_false, degree_zero, bot_le]
+ simp [dif_pos hq, h, if_false, degree_zero, bot_le]
else (divByMonic_eq_of_not_monic p hq).symm ▸ bot_le
theorem degree_divByMonic_lt (p : R[X]) {q : R[X]} (hq : Monic q) (hp0 : p ≠ 0)
@@ -486,7 +486,8 @@ def rootMultiplicity (a : R) (p : R[X]) : ℕ :=
if h0 : p = 0 then 0
else
let _ : DecidablePred fun n : ℕ => ¬(X - C a) ^ (n + 1) ∣ p := fun n =>
- @Not.decidable _ (decidableDvdMonic p ((monic_X_sub_C a).pow (n + 1)))
+ have := decidableDvdMonic p ((monic_X_sub_C a).pow (n + 1))
+ inferInstanceAs (Decidable ¬_)
Nat.find (multiplicity_X_sub_C_finite a h0)
/- Porting note: added the following due to diamond with decidableProp and
@@ -494,17 +495,24 @@ decidableDvdMonic see also [Zulip]
(https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/non-defeq.20aliased.20instance) -/
theorem rootMultiplicity_eq_nat_find_of_nonzero [DecidableEq R] {p : R[X]} (p0 : p ≠ 0) {a : R} :
letI : DecidablePred fun n : ℕ => ¬(X - C a) ^ (n + 1) ∣ p := fun n =>
- @Not.decidable _ (decidableDvdMonic p ((monic_X_sub_C a).pow (n + 1)))
+ have := decidableDvdMonic p ((monic_X_sub_C a).pow (n + 1))
+ inferInstanceAs (Decidable ¬_)
rootMultiplicity a p = Nat.find (multiplicity_X_sub_C_finite a p0) := by
dsimp [rootMultiplicity]
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 :=
@@ -519,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
@@ -540,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
@@ -549,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
@@ -616,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
@@ -638,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
@@ -653,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 13fd989d6ed3c..3c5b199f6c28d 100644
--- a/Mathlib/Algebra/Polynomial/Eval.lean
+++ b/Mathlib/Algebra/Polynomial/Eval.lean
@@ -1,10 +1,13 @@
/-
Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Chris Hughes, Johannes Hölzl, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.Polynomial.Degree.Definitions
import Mathlib.Algebra.Polynomial.Induction
+import Mathlib.Algebra.Ring.Subsemiring.Basic
+import Mathlib.Algebra.Algebra.Defs
+import Mathlib.Algebra.Ring.Subring.Basic
/-!
# Theory of univariate polynomials
@@ -1035,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
@@ -1152,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 0460864bfceb5..b0f395c366efb 100644
--- a/Mathlib/Algebra/Polynomial/FieldDivision.lean
+++ b/Mathlib/Algebra/Polynomial/FieldDivision.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.Polynomial.Derivative
import Mathlib.Algebra.Polynomial.Roots
@@ -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
@@ -334,7 +338,7 @@ theorem mod_eq_self_iff (hq0 : q ≠ 0) : p % q = p ↔ degree p < degree q :=
rw [mod_def, modByMonic, dif_pos (monic_mul_leadingCoeff_inv hq0)]
unfold divModByMonicAux
dsimp
- simp only [this, false_and_iff, if_false]⟩
+ simp only [this, false_and, if_false]⟩
theorem div_eq_zero_iff (hq0 : q ≠ 0) : p / q = 0 ↔ degree p < degree q :=
⟨fun h => by
@@ -382,6 +386,21 @@ theorem map_mod [Field k] (f : R →+* k) : (p % q).map f = p.map f % q.map f :=
· rw [mod_def, mod_def, leadingCoeff_map f, ← map_inv₀ f, ← map_C f, ← Polynomial.map_mul f,
map_modByMonic f (monic_mul_leadingCoeff_inv hq0)]
+lemma natDegree_mod_lt [Field k] (p : k[X]) {q : k[X]} (hq : q.natDegree ≠ 0) :
+ (p % q).natDegree < q.natDegree := by
+ have hq' : q.leadingCoeff ≠ 0 := by
+ rw [leadingCoeff_ne_zero]
+ contrapose! hq
+ simp [hq]
+ rw [mod_def]
+ refine (natDegree_modByMonic_lt p ?_ ?_).trans_le ?_
+ · refine monic_mul_C_of_leadingCoeff_mul_eq_one ?_
+ rw [mul_inv_eq_one₀ hq']
+ · contrapose! hq
+ rw [← natDegree_mul_C_eq_of_mul_eq_one ((inv_mul_eq_one₀ hq').mpr rfl)]
+ simp [hq]
+ · exact natDegree_mul_C_le q q.leadingCoeff⁻¹
+
section
open EuclideanDomain
@@ -509,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]
@@ -520,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 30813c8edd473..a14a7d6e696b8 100644
--- a/Mathlib/Algebra/Polynomial/GroupRingAction.lean
+++ b/Mathlib/Algebra/Polynomial/GroupRingAction.lean
@@ -95,7 +95,7 @@ theorem prodXSubSMul.eval (x : R) : (prodXSubSMul G R x).eval x = 0 :=
theorem prodXSubSMul.smul (x : R) (g : G) : g • prodXSubSMul G R x = prodXSubSMul G R x :=
letI := Classical.decEq R
- Finset.smul_prod.trans <|
+ Finset.smul_prod'.trans <|
Fintype.prod_bijective _ (MulAction.bijective g) _ _ fun g' ↦ by
rw [ofQuotientStabilizer_smul, smul_sub, Polynomial.smul_X, Polynomial.smul_C]
@@ -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/HasseDeriv.lean b/Mathlib/Algebra/Polynomial/HasseDeriv.lean
index 526b25659bb93..7f0f31d75a921 100644
--- a/Mathlib/Algebra/Polynomial/HasseDeriv.lean
+++ b/Mathlib/Algebra/Polynomial/HasseDeriv.lean
@@ -179,7 +179,7 @@ theorem natDegree_hasseDeriv_le (p : R[X]) (n : ℕ) :
refine (natDegree_sum_le _ _).trans ?_
simp_rw [Function.comp, natDegree_monomial]
rw [Finset.fold_ite, Finset.fold_const]
- · simp only [ite_self, max_eq_right, zero_le', Finset.fold_max_le, true_and_iff, and_imp,
+ · simp only [ite_self, max_eq_right, zero_le', Finset.fold_max_le, true_and, and_imp,
tsub_le_iff_right, mem_support_iff, Ne, Finset.mem_filter]
intro x hx hx'
have hxp : x ≤ p.natDegree := le_natDegree_of_ne_zero hx
diff --git a/Mathlib/Algebra/Polynomial/Identities.lean b/Mathlib/Algebra/Polynomial/Identities.lean
index 03eec7652a472..d33dfaf9c2923 100644
--- a/Mathlib/Algebra/Polynomial/Identities.lean
+++ b/Mathlib/Algebra/Polynomial/Identities.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.Polynomial.Derivative
import Mathlib.Tactic.LinearCombination
diff --git a/Mathlib/Algebra/Polynomial/Induction.lean b/Mathlib/Algebra/Polynomial/Induction.lean
index 242facc658dde..572d1091e012c 100644
--- a/Mathlib/Algebra/Polynomial/Induction.lean
+++ b/Mathlib/Algebra/Polynomial/Induction.lean
@@ -1,10 +1,10 @@
/-
Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Chris Hughes, Johannes Hölzl, Scott Morrison, Jens Wagemaker
+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
@@ -26,12 +26,11 @@ open Polynomial
universe u v w x y z
-variable {R : Type u} {S : Type v} {T : Type w} {ι : Type x} {k : Type y} {A : Type z} {a b : R}
- {m n : ℕ}
+variable {R : Type u}
section Semiring
-variable [Semiring R] {p q r : R[X]}
+variable [Semiring R]
@[elab_as_elim]
protected theorem induction_on {M : R[X] → Prop} (p : R[X]) (h_C : ∀ a, M (C a))
diff --git a/Mathlib/Algebra/Polynomial/Inductions.lean b/Mathlib/Algebra/Polynomial/Inductions.lean
index f5a98d3c5ebe0..2594bd1490eca 100644
--- a/Mathlib/Algebra/Polynomial/Inductions.lean
+++ b/Mathlib/Algebra/Polynomial/Inductions.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2021 Damiano Testa. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Chris Hughes, Johannes Hölzl, Scott Morrison, Damiano Testa, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Damiano Testa, Jens Wagemaker
-/
import Mathlib.Algebra.MonoidAlgebra.Division
import Mathlib.Algebra.Polynomial.Degree.Definitions
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 daa261800b354..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
@@ -46,7 +47,8 @@ instance instAddCommMonoid : AddCommMonoid <| AEval R M a := inferInstanceAs (Ad
instance instModuleOrig : Module R <| AEval R M a := inferInstanceAs (Module R M)
-instance instFiniteOrig [Finite R M] : Finite R <| AEval R M a := inferInstanceAs (Finite R M)
+instance instFiniteOrig [Module.Finite R M] : Module.Finite R <| AEval R M a :=
+ ‹Module.Finite R M›
instance instModulePolynomial : Module R[X] <| AEval R M a := compHom M (aeval a).toRingHom
@@ -79,7 +81,7 @@ instance instIsScalarTowerOrigPolynomial : IsScalarTower R R[X] <| AEval R M a w
apply (of R M a).symm.injective
rw [of_symm_smul, map_smul, smul_assoc, map_smul, of_symm_smul]
-instance instFinitePolynomial [Finite R M] : Finite R[X] <| AEval R M a :=
+instance instFinitePolynomial [Module.Finite R M] : Module.Finite R[X] <| AEval R M a :=
Finite.of_restrictScalars_finite R _ _
/-- Construct an `R[X]`-linear map out of `AEval R M a` from a `R`-linear map out of `M`. -/
@@ -93,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
@@ -110,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
@@ -193,6 +195,6 @@ lemma AEval'.X_smul_of (m : M) : (X : R[X]) • AEval'.of φ m = AEval'.of φ (
lemma AEval'.of_symm_X_smul (m : AEval' φ) :
(AEval'.of φ).symm ((X : R[X]) • m) = φ ((AEval'.of φ).symm m) := AEval.of_symm_X_smul _ _
-instance [Finite R M] : Finite R[X] <| AEval' φ := inferInstance
+instance [Module.Finite R M] : Module.Finite R[X] <| AEval' φ := inferInstance
end Module
diff --git a/Mathlib/Algebra/Polynomial/Module/Basic.lean b/Mathlib/Algebra/Polynomial/Module/Basic.lean
index c5e69f5e9a19f..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 _
@@ -276,8 +276,7 @@ theorem eval_smul (p : R[X]) (q : PolynomialModule R M) (r : R) :
intro i m
induction p using Polynomial.induction_on' with
| h_add _ _ e₁ e₂ => rw [add_smul, map_add, Polynomial.eval_add, e₁, e₂, add_smul]
- | h_monomial => rw [monomial_smul_single, eval_single, Polynomial.eval_monomial, eval_single,
- smul_comm, ← smul_smul, pow_add, mul_smul]
+ | h_monomial => simp only [monomial_smul_single, Polynomial.eval_monomial, eval_single]; module
@[simp]
theorem eval_map (f : M →ₗ[R] M') (q : PolynomialModule R M) (r : R) :
@@ -287,7 +286,8 @@ theorem eval_map (f : M →ₗ[R] M') (q : PolynomialModule R M) (r : R) :
· intro f g e₁ e₂
simp_rw [map_add, e₁, e₂]
· intro i m
- rw [map_single, eval_single, eval_single, f.map_smul, ← map_pow, algebraMap_smul]
+ simp only [map_single, eval_single, f.map_smul]
+ module
@[simp]
theorem eval_map' (f : M →ₗ[R] M) (q : PolynomialModule R M) (r : R) :
@@ -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) :
@@ -324,8 +323,8 @@ theorem comp_eval (p : R[X]) (q : PolynomialModule R M) (r : R) :
· intro _ _ e₁ e₂
simp_rw [map_add, e₁, e₂]
· intro i m
- rw [LinearMap.comp_apply, comp_single, eval_single, eval_smul, eval_single, pow_zero, one_smul,
- Polynomial.eval_pow]
+ rw [LinearMap.comp_apply, comp_single, eval_single, eval_smul, eval_single, eval_pow]
+ module
theorem comp_smul (p p' : R[X]) (q : PolynomialModule R M) :
comp p (p' • q) = p'.comp p • comp p q := by
diff --git a/Mathlib/Algebra/Polynomial/Monic.lean b/Mathlib/Algebra/Polynomial/Monic.lean
index 9ab637bcebdd6..9b7ed2ba528e5 100644
--- a/Mathlib/Algebra/Polynomial/Monic.lean
+++ b/Mathlib/Algebra/Polynomial/Monic.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.Polynomial.Reverse
import Mathlib.Algebra.Regular.SMul
@@ -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 e96bdc18024b0..535103330d899 100644
--- a/Mathlib/Algebra/Polynomial/Monomial.lean
+++ b/Mathlib/Algebra/Polynomial/Monomial.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.Polynomial.Basic
@@ -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 e4e14ccf3d644..c557bfff9de6c 100644
--- a/Mathlib/Algebra/Polynomial/RingDivision.lean
+++ b/Mathlib/Algebra/Polynomial/RingDivision.lean
@@ -1,10 +1,9 @@
/-
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, Scott Morrison, Jens Wagemaker, Johan Commelin
+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,106 +159,23 @@ 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)
+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]
+ calc
+ ((-1) ^ p.natDegree * p.comp (-X)).leadingCoeff =
+ (p.comp (-X) * C ((-1) ^ p.natDegree)).leadingCoeff := by
+ simp [mul_comm]
+ _ = 1 := by
+ apply monic_mul_C_of_leadingCoeff_mul_eq_one
+ simp [← pow_add, hp]
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]
@@ -667,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
@@ -716,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
@@ -731,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
@@ -770,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 93797531db5dd..3db1a24da52f9 100644
--- a/Mathlib/Algebra/Polynomial/Roots.lean
+++ b/Mathlib/Algebra/Polynomial/Roots.lean
@@ -1,9 +1,9 @@
/-
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, Scott Morrison, Jens Wagemaker, Johan Commelin
+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 :=
@@ -108,13 +108,16 @@ theorem ne_zero_of_mem_roots (h : a ∈ p.roots) : p ≠ 0 :=
theorem isRoot_of_mem_roots (h : a ∈ p.roots) : IsRoot p a :=
(mem_roots'.1 h).2
--- Porting note: added during port.
+theorem mem_roots_map_of_injective [Semiring S] {p : S[X]} {f : S →+* R}
+ (hf : Function.Injective f) {x : R} (hp : p ≠ 0) : x ∈ (p.map f).roots ↔ p.eval₂ f x = 0 := by
+ rw [mem_roots ((Polynomial.map_ne_zero_iff hf).mpr hp), IsRoot, eval_map]
+
lemma mem_roots_iff_aeval_eq_zero {x : R} (w : p ≠ 0) : x ∈ roots p ↔ aeval x p = 0 := by
- rw [mem_roots w, IsRoot.def, aeval_def, eval₂_eq_eval_map]
- simp
+ rw [aeval_def, ← mem_roots_map_of_injective (NoZeroSMulDivisors.algebraMap_injective _ _) w,
+ 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
@@ -434,6 +437,13 @@ theorem aroots_monomial [CommRing S] [IsDomain S] [Algebra T S]
(monomial n a).aroots S = n • ({0} : Multiset S) := by
rw [← C_mul_X_pow_eq_monomial, aroots_C_mul_X_pow ha]
+variable (R S) in
+@[simp]
+theorem aroots_map (p : T[X]) [CommRing S] [Algebra T S] [Algebra S R] [Algebra T R]
+ [IsScalarTower T S R] :
+ (p.map (algebraMap T S)).aroots R = p.aroots R := by
+ rw [aroots_def, aroots_def, map_map, IsScalarTower.algebraMap_eq T S R]
+
/-- The set of distinct roots of `p` in `S`.
If you have a non-separable polynomial, use `Polynomial.aroots` for the multiset
@@ -488,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
@@ -525,6 +535,12 @@ theorem rootSet_mapsTo {p : T[X]} {S S'} [CommRing S] [IsDomain S] [Algebra T S]
map_injective _ (NoZeroSMulDivisors.algebraMap_injective T S') (by rwa [Polynomial.map_zero])
exact Polynomial.map_zero _
+theorem mem_rootSet_of_injective [CommRing S] {p : S[X]} [Algebra S R]
+ (h : Function.Injective (algebraMap S R)) {x : R} (hp : p ≠ 0) :
+ x ∈ p.rootSet R ↔ aeval x p = 0 := by
+ classical
+ exact Multiset.mem_toFinset.trans (mem_roots_map_of_injective h hp)
+
end Roots
lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R]
@@ -532,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]
@@ -547,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 2eb2eecb587a6..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
@@ -180,7 +181,7 @@ the defining structures independently. For non-associative power-associative al
octonions), we replace the `[Semiring S]` with `[NonAssocSemiring S] [Pow S ℕ] [NatPowAssoc S]`.
-/
-variable (R : Type*) [Semiring R] {p : R[X]} (r : R) (p q : R[X]) {S : Type*}
+variable (R : Type*) [Semiring R] (r : R) (p q : R[X]) {S : Type*}
[NonAssocSemiring S] [Module R S] [Pow S ℕ] (x : S)
theorem smeval_C_mul : (C r * p).smeval x = r • p.smeval x := by
diff --git a/Mathlib/Algebra/Polynomial/Splits.lean b/Mathlib/Algebra/Polynomial/Splits.lean
index c30726a113d9c..db9df3da20b50 100644
--- a/Mathlib/Algebra/Polynomial/Splits.lean
+++ b/Mathlib/Algebra/Polynomial/Splits.lean
@@ -6,6 +6,7 @@ Authors: Chris Hughes
import Mathlib.Algebra.Polynomial.FieldDivision
import Mathlib.Algebra.Polynomial.Lifts
import Mathlib.Data.List.Prime
+import Mathlib.RingTheory.Polynomial.Tower
/-!
# Split polynomials
@@ -138,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
@@ -300,11 +322,33 @@ theorem eq_prod_roots_of_splits_id {p : K[X]} (hsplit : Splits (RingHom.id K) p)
p = C p.leadingCoeff * (p.roots.map fun a => X - C a).prod := by
simpa using eq_prod_roots_of_splits hsplit
+theorem aeval_eq_prod_aroots_sub_of_splits [Algebra K L] {p : K[X]}
+ (hsplit : Splits (algebraMap K L) p) (v : L) :
+ aeval v p = algebraMap K L p.leadingCoeff * ((p.aroots L).map fun a ↦ v - a).prod := by
+ rw [← eval_map_algebraMap, eq_prod_roots_of_splits hsplit]
+ simp [eval_multiset_prod]
+
+theorem eval_eq_prod_roots_sub_of_splits_id {p : K[X]}
+ (hsplit : Splits (RingHom.id K) p) (v : K) :
+ eval v p = p.leadingCoeff * (p.roots.map fun a ↦ v - a).prod := by
+ convert aeval_eq_prod_aroots_sub_of_splits hsplit v
+ rw [Algebra.id.map_eq_id, map_id]
+
theorem eq_prod_roots_of_monic_of_splits_id {p : K[X]} (m : Monic p)
(hsplit : Splits (RingHom.id K) p) : p = (p.roots.map fun a => X - C a).prod := by
convert eq_prod_roots_of_splits_id hsplit
simp [m]
+theorem aeval_eq_prod_aroots_sub_of_monic_of_splits [Algebra K L] {p : K[X]} (m : Monic p)
+ (hsplit : Splits (algebraMap K L) p) (v : L) :
+ aeval v p = ((p.aroots L).map fun a ↦ v - a).prod := by
+ simp [aeval_eq_prod_aroots_sub_of_splits hsplit, m]
+
+theorem eval_eq_prod_roots_sub_of_monic_of_splits_id {p : K[X]} (m : Monic p)
+ (hsplit : Splits (RingHom.id K) p) (v : K) :
+ eval v p = (p.roots.map fun a ↦ v - a).prod := by
+ simp [eval_eq_prod_roots_sub_of_splits_id hsplit, m]
+
theorem eq_X_sub_C_of_splits_of_single_root {x : K} {h : K[X]} (h_splits : Splits i h)
(h_roots : (h.map i).roots = {i x}) : h = C h.leadingCoeff * (X - C x) := by
apply Polynomial.map_injective _ i.injective
@@ -347,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
@@ -414,7 +458,7 @@ theorem aeval_root_derivative_of_splits [Algebra K L] [DecidableEq L] {P : K[X]}
rw [eval_multiset_prod_X_sub_C_derivative hr]
/-- If `P` is a monic polynomial that splits, then `coeff P 0` equals the product of the roots. -/
-theorem prod_roots_eq_coeff_zero_of_monic_of_split {P : K[X]} (hmo : P.Monic)
+theorem prod_roots_eq_coeff_zero_of_monic_of_splits {P : K[X]} (hmo : P.Monic)
(hP : P.Splits (RingHom.id K)) : coeff P 0 = (-1) ^ P.natDegree * P.roots.prod := by
nth_rw 1 [eq_prod_roots_of_monic_of_splits_id hmo hP]
rw [coeff_zero_eq_eval_zero, eval_multiset_prod, Multiset.map_map]
@@ -426,6 +470,9 @@ theorem prod_roots_eq_coeff_zero_of_monic_of_split {P : K[X]} (hmo : P.Monic)
rw [neg_eq_neg_one_mul]
simp only [splits_iff_card_roots.1 hP, neg_mul, one_mul, Multiset.prod_map_neg]
+@[deprecated (since := "2024-10-01")]
+alias prod_roots_eq_coeff_zero_of_monic_of_split := prod_roots_eq_coeff_zero_of_monic_of_splits
+
/-- If `P` is a monic polynomial that splits, then `P.nextCoeff` equals the sum of the roots. -/
theorem sum_roots_eq_nextCoeff_of_monic_of_split {P : K[X]} (hmo : P.Monic)
(hP : P.Splits (RingHom.id K)) : P.nextCoeff = -P.roots.sum := by
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 6f9f0e82544ef..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) :=
@@ -125,4 +125,11 @@ theorem sum_taylor_eq {R} [CommRing R] (f : R[X]) (r : R) :
rw [← comp_eq_sum_left, sub_eq_add_neg, ← C_neg, ← taylor_apply, taylor_taylor, neg_add_cancel,
taylor_zero]
+theorem eval_add_of_sq_eq_zero {A} [CommSemiring A] (p : Polynomial A) (x y : A) (hy : y ^ 2 = 0) :
+ p.eval (x + y) = p.eval x + p.derivative.eval x * y := by
+ rw [add_comm, ← Polynomial.taylor_eval,
+ Polynomial.eval_eq_sum_range' ((Nat.lt_succ_self _).trans (Nat.lt_succ_self _)),
+ Finset.sum_range_succ', Finset.sum_range_succ']
+ simp [pow_succ, mul_assoc, ← pow_two, hy, add_comm (eval x p)]
+
end Polynomial
diff --git a/Mathlib/Algebra/Polynomial/UnitTrinomial.lean b/Mathlib/Algebra/Polynomial/UnitTrinomial.lean
index f22387feb2113..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
@@ -178,7 +179,7 @@ theorem isUnitTrinomial_iff' :
refine ⟨?_, fun hp => ?_⟩
· rintro ⟨k, m, n, hkm, hmn, u, v, w, rfl⟩
rw [sum_def, trinomial_support hkm hmn u.ne_zero v.ne_zero w.ne_zero,
- sum_insert (mt mem_insert.mp (not_or_of_not hkm.ne (mt mem_singleton.mp (hkm.trans hmn).ne))),
+ sum_insert (mt mem_insert.mp (not_or_intro hkm.ne (mt mem_singleton.mp (hkm.trans hmn).ne))),
sum_insert (mt mem_singleton.mp hmn.ne), sum_singleton, trinomial_leading_coeff' hkm hmn,
trinomial_middle_coeff hkm hmn, trinomial_trailing_coeff' hkm hmn]
simp_rw [← Units.val_pow_eq_pow_val, Int.units_sq, Units.val_one]
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/QuadraticDiscriminant.lean b/Mathlib/Algebra/QuadraticDiscriminant.lean
index de6a5eb840dfd..157ac8292a0db 100644
--- a/Mathlib/Algebra/QuadraticDiscriminant.lean
+++ b/Mathlib/Algebra/QuadraticDiscriminant.lean
@@ -3,7 +3,7 @@ Copyright (c) 2019 Zhouhang Zhou. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Zhouhang Zhou
-/
-import Mathlib.Order.Filter.AtTopBot
+import Mathlib.Order.Filter.AtTopBot.Field
import Mathlib.Tactic.FieldSimp
import Mathlib.Tactic.LinearCombination
import Mathlib.Tactic.Linarith.Frontend
@@ -15,7 +15,7 @@ This file defines the discriminant of a quadratic and gives the solution to a qu
## Main definition
-- `discrim a b c`: the discriminant of a quadratic `a * x * x + b * x + c` is `b * b - 4 * a * c`.
+- `discrim a b c`: the discriminant of a quadratic `a * (x * x) + b * x + c` is `b * b - 4 * a * c`.
## Main statements
@@ -48,7 +48,7 @@ def discrim [Ring R] (a b c : R) : R :=
variable [CommRing R] {a b c : R}
-lemma discrim_eq_sq_of_quadratic_eq_zero {x : R} (h : a * x * x + b * x + c = 0) :
+lemma discrim_eq_sq_of_quadratic_eq_zero {x : R} (h : a * (x * x) + b * x + c = 0) :
discrim a b c = (2 * a * x + b) ^ 2 := by
rw [discrim]
linear_combination -4 * a * h
@@ -57,7 +57,7 @@ lemma discrim_eq_sq_of_quadratic_eq_zero {x : R} (h : a * x * x + b * x + c = 0)
-/
theorem quadratic_eq_zero_iff_discrim_eq_sq [NeZero (2 : R)] [NoZeroDivisors R]
(ha : a ≠ 0) (x : R) :
- a * x * x + b * x + c = 0 ↔ discrim a b c = (2 * a * x + b) ^ 2 := by
+ a * (x * x) + b * x + c = 0 ↔ discrim a b c = (2 * a * x + b) ^ 2 := by
refine ⟨discrim_eq_sq_of_quadratic_eq_zero, fun h ↦ ?_⟩
rw [discrim] at h
have ha : 2 * 2 * a ≠ 0 := mul_ne_zero (mul_ne_zero (NeZero.ne _) (NeZero.ne _)) ha
@@ -66,7 +66,7 @@ theorem quadratic_eq_zero_iff_discrim_eq_sq [NeZero (2 : R)] [NoZeroDivisors R]
/-- A quadratic has no root if its discriminant has no square root. -/
theorem quadratic_ne_zero_of_discrim_ne_sq (h : ∀ s : R, discrim a b c ≠ s^2) (x : R) :
- a * x * x + b * x + c ≠ 0 :=
+ a * (x * x) + b * x + c ≠ 0 :=
mt discrim_eq_sq_of_quadratic_eq_zero (h _)
end Ring
@@ -77,7 +77,7 @@ variable {K : Type*} [Field K] [NeZero (2 : K)] {a b c x : K}
/-- Roots of a quadratic equation. -/
theorem quadratic_eq_zero_iff (ha : a ≠ 0) {s : K} (h : discrim a b c = s * s) (x : K) :
- a * x * x + b * x + c = 0 ↔ x = (-b + s) / (2 * a) ∨ x = (-b - s) / (2 * a) := by
+ a * (x * x) + b * x + c = 0 ↔ x = (-b + s) / (2 * a) ∨ x = (-b - s) / (2 * a) := by
rw [quadratic_eq_zero_iff_discrim_eq_sq ha, h, sq, mul_self_eq_mul_self_iff]
field_simp
apply or_congr
@@ -86,7 +86,7 @@ theorem quadratic_eq_zero_iff (ha : a ≠ 0) {s : K} (h : discrim a b c = s * s)
/-- A quadratic has roots if its discriminant has square roots -/
theorem exists_quadratic_eq_zero (ha : a ≠ 0) (h : ∃ s, discrim a b c = s * s) :
- ∃ x, a * x * x + b * x + c = 0 := by
+ ∃ x, a * (x * x) + b * x + c = 0 := by
rcases h with ⟨s, hs⟩
use (-b + s) / (2 * a)
rw [quadratic_eq_zero_iff ha hs]
@@ -94,7 +94,7 @@ theorem exists_quadratic_eq_zero (ha : a ≠ 0) (h : ∃ s, discrim a b c = s *
/-- Root of a quadratic when its discriminant equals zero -/
theorem quadratic_eq_zero_iff_of_discrim_eq_zero (ha : a ≠ 0) (h : discrim a b c = 0) (x : K) :
- a * x * x + b * x + c = 0 ↔ x = -b / (2 * a) := by
+ a * (x * x) + b * x + c = 0 ↔ x = -b / (2 * a) := by
have : discrim a b c = 0 * 0 := by rw [h, mul_zero]
rw [quadratic_eq_zero_iff ha this, add_zero, sub_zero, or_self_iff]
@@ -105,7 +105,7 @@ section LinearOrderedField
variable {K : Type*} [LinearOrderedField K] {a b c : K}
/-- If a polynomial of degree 2 is always nonnegative, then its discriminant is nonpositive -/
-theorem discrim_le_zero (h : ∀ x : K, 0 ≤ a * x * x + b * x + c) : discrim a b c ≤ 0 := by
+theorem discrim_le_zero (h : ∀ x : K, 0 ≤ a * (x * x) + b * x + c) : discrim a b c ≤ 0 := by
rw [discrim, sq]
obtain ha | rfl | ha : a < 0 ∨ a = 0 ∨ 0 < a := lt_trichotomy a 0
-- if a < 0
@@ -114,7 +114,7 @@ theorem discrim_le_zero (h : ∀ x : K, 0 ≤ a * x * x + b * x + c) : discrim a
((tendsto_atBot_add_const_right _ b (tendsto_id.const_mul_atTop_of_neg ha)).atBot_mul_atTop
tendsto_id)
rcases (this.eventually (eventually_lt_atBot 0)).exists with ⟨x, hx⟩
- exact False.elim ((h x).not_lt <| by rwa [← add_mul])
+ exact False.elim ((h x).not_lt <| by rwa [← mul_assoc, ← add_mul])
-- if a = 0
· rcases eq_or_ne b 0 with (rfl | hb)
· simp
@@ -127,22 +127,22 @@ theorem discrim_le_zero (h : ∀ x : K, 0 ≤ a * x * x + b * x + c) : discrim a
field_simp
ring
-lemma discrim_le_zero_of_nonpos (h : ∀ x : K, a * x * x + b * x + c ≤ 0) : discrim a b c ≤ 0 :=
+lemma discrim_le_zero_of_nonpos (h : ∀ x : K, a * (x * x) + b * x + c ≤ 0) : discrim a b c ≤ 0 :=
discrim_neg a b c ▸ discrim_le_zero <| by simpa only [neg_mul, ← neg_add, neg_nonneg]
/-- If a polynomial of degree 2 is always positive, then its discriminant is negative,
at least when the coefficient of the quadratic term is nonzero.
-/
-theorem discrim_lt_zero (ha : a ≠ 0) (h : ∀ x : K, 0 < a * x * x + b * x + c) :
+theorem discrim_lt_zero (ha : a ≠ 0) (h : ∀ x : K, 0 < a * (x * x) + b * x + c) :
discrim a b c < 0 := by
- have : ∀ x : K, 0 ≤ a * x * x + b * x + c := fun x => le_of_lt (h x)
+ have : ∀ x : K, 0 ≤ a * (x * x) + b * x + c := fun x => le_of_lt (h x)
refine lt_of_le_of_ne (discrim_le_zero this) fun h' ↦ ?_
have := h (-b / (2 * a))
have : a * (-b / (2 * a)) * (-b / (2 * a)) + b * (-b / (2 * a)) + c = 0 := by
- rw [quadratic_eq_zero_iff_of_discrim_eq_zero ha h' (-b / (2 * a))]
+ rw [mul_assoc, quadratic_eq_zero_iff_of_discrim_eq_zero ha h' (-b / (2 * a))]
linarith
-lemma discrim_lt_zero_of_neg (ha : a ≠ 0) (h : ∀ x : K, a * x * x + b * x + c < 0) :
+lemma discrim_lt_zero_of_neg (ha : a ≠ 0) (h : ∀ x : K, a * (x * x) + b * x + c < 0) :
discrim a b c < 0 :=
discrim_neg a b c ▸ discrim_lt_zero (neg_ne_zero.2 ha) <| by
simpa only [neg_mul, ← neg_add, neg_pos]
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 a063ebfdef089..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
@@ -569,8 +569,8 @@ theorem rank_eq_four [StrongRankCondition R] : Module.rank R ℍ[R,c₁,c₂] =
rw [rank_eq_card_basis (basisOneIJK c₁ c₂), Fintype.card_fin]
norm_num
-theorem finrank_eq_four [StrongRankCondition R] : FiniteDimensional.finrank R ℍ[R,c₁,c₂] = 4 := by
- rw [FiniteDimensional.finrank, rank_eq_four, Cardinal.toNat_ofNat]
+theorem finrank_eq_four [StrongRankCondition R] : Module.finrank R ℍ[R,c₁,c₂] = 4 := by
+ rw [Module.finrank, rank_eq_four, Cardinal.toNat_ofNat]
/-- There is a natural equivalence when swapping the coefficients of a quaternion algebra. -/
@[simps]
@@ -1024,7 +1024,7 @@ instance : Module.Free R ℍ[R] := inferInstanceAs <| Module.Free R ℍ[R,-1,-1]
theorem rank_eq_four [StrongRankCondition R] : Module.rank R ℍ[R] = 4 :=
QuaternionAlgebra.rank_eq_four _ _
-theorem finrank_eq_four [StrongRankCondition R] : FiniteDimensional.finrank R ℍ[R] = 4 :=
+theorem finrank_eq_four [StrongRankCondition R] : Module.finrank R ℍ[R] = 4 :=
QuaternionAlgebra.finrank_eq_four _ _
@[simp] theorem star_re : (star a).re = a.re := rfl
@@ -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 25558ac78f579..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
/-!
@@ -42,11 +42,12 @@ class MulSemiringAction (M : Type u) (R : Type v) [Monoid M] [Semiring R] extend
section Semiring
-variable (M N G : Type*) [Monoid M] [Monoid N] [Group G]
-variable (A R S F : Type v) [AddMonoid A] [Semiring R] [CommSemiring S]
+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 }
@@ -92,8 +93,6 @@ end
section SimpLemmas
-variable {M G A R F}
-
attribute [simp] smul_one smul_mul' smul_zero smul_add
end SimpLemmas
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/Basic.lean b/Mathlib/Algebra/Ring/Basic.lean
index 4ae5170c85619..fd10db100aadd 100644
--- a/Mathlib/Algebra/Ring/Basic.lean
+++ b/Mathlib/Algebra/Ring/Basic.lean
@@ -40,13 +40,6 @@ def mulRight [Distrib R] (r : R) : AddHom R R where
end AddHom
-section AddHomClass
-
-variable {α β F : Type*} [NonAssocSemiring α] [NonAssocSemiring β]
- [FunLike F α β] [AddHomClass F α β]
-
-end AddHomClass
-
namespace AddMonoidHom
/-- Left multiplication by an element of a (semi)ring is an `AddMonoidHom` -/
@@ -105,7 +98,7 @@ end HasDistribNeg
section NonUnitalCommRing
-variable {α : Type*} [NonUnitalCommRing α] {a b c : α}
+variable {α : Type*} [NonUnitalCommRing α]
attribute [local simp] add_assoc add_comm add_left_comm mul_comm
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 25857d52638e5..b1b90bb34b9d1 100644
--- a/Mathlib/Algebra/Ring/CentroidHom.lean
+++ b/Mathlib/Algebra/Ring/CentroidHom.lean
@@ -61,8 +61,8 @@ attribute [nolint docBlame] CentroidHom.toAddMonoidHom
/-- `CentroidHomClass F α` states that `F` is a type of centroid homomorphisms.
You should extend this class when you extend `CentroidHom`. -/
-class CentroidHomClass (F α : Type*) [NonUnitalNonAssocSemiring α] [FunLike F α α] extends
- AddMonoidHomClass F α α : Prop where
+class CentroidHomClass (F : Type*) (α : outParam Type*)
+ [NonUnitalNonAssocSemiring α] [FunLike F α α] extends AddMonoidHomClass F α α : Prop where
/-- Commutativity of centroid homomorphims with left multiplication. -/
map_mul_left (f : F) (a b : α) : f (a * b) = a * f b
/-- Commutativity of centroid homomorphims with right multiplication. -/
@@ -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 6793e2df1e30d..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
@@ -75,15 +75,11 @@ end
section
-variable [MulOneClass R] [HasDistribNeg R] {a : R}
+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
@@ -147,7 +143,7 @@ alias neg_one_pow_two := neg_one_sq
end HasDistribNeg
section Ring
-variable [Ring R] {a b : R} {n : ℕ}
+variable [Ring R] {a : R} {n : ℕ}
@[simp] lemma neg_one_pow_mul_eq_zero_iff : (-1) ^ n * a = 0 ↔ a = 0 := by
rcases neg_one_pow_eq_or R n with h | h <;> simp [h]
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 7c35751123577..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 : α)
@@ -250,7 +222,7 @@ instance (priority := 100) CommSemiring.toCommMonoidWithZero [CommSemiring α] :
section CommSemiring
-variable [CommSemiring α] {a b c : α}
+variable [CommSemiring α]
theorem add_mul_self_eq (a b : α) : (a + b) * (a + b) = a * a + 2 * a * b + b * b := by
simp only [two_mul, add_mul, mul_add, add_assoc, mul_comm b]
@@ -371,7 +343,7 @@ end NonAssocRing
section Ring
-variable [Ring α] {a b c d e : α}
+variable [Ring α]
-- A (unital, associative) ring is a not-necessarily-unital ring
-- see Note [lower instance priority]
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 246dcd9e49330..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
@@ -126,6 +125,8 @@ section Basic
variable [Mul R] [Mul S] [Add R] [Add S] [Mul S'] [Add S']
+section coe
+
instance : EquivLike (R ≃+* S) R S where
coe f := f.toFun
inv f := f.invFun
@@ -141,30 +142,18 @@ instance : RingEquivClass (R ≃+* S) R S where
map_add f := f.map_add'
map_mul f := f.map_mul'
-@[simp]
-theorem toEquiv_eq_coe (f : R ≃+* S) : f.toEquiv = f :=
- rfl
-
--- Porting note: `toFun_eq_coe` no longer needed in Lean4
-
-@[simp]
-theorem coe_toEquiv (f : R ≃+* S) : ⇑(f : R ≃ S) = f :=
- rfl
-
-/-- A ring isomorphism preserves multiplication. -/
-protected theorem map_mul (e : R ≃+* S) (x y : R) : e (x * y) = e x * e y :=
- map_mul e x y
-
-/-- A ring isomorphism preserves addition. -/
-protected theorem map_add (e : R ≃+* S) (x y : R) : e (x + y) = e x + e y :=
- map_add e x y
-
/-- Two ring isomorphisms agree if they are defined by the
same underlying function. -/
@[ext]
theorem ext {f g : R ≃+* S} (h : ∀ x, f x = g x) : f = g :=
DFunLike.ext f g h
+protected theorem congr_arg {f : R ≃+* S} {x x' : R} : x = x' → f x = f x' :=
+ DFunLike.congr_arg f
+
+protected theorem congr_fun {f g : R ≃+* S} (h : f = g) (x : R) : f x = g x :=
+ DFunLike.congr_fun h x
+
@[simp]
theorem coe_mk (e h₃ h₄) : ⇑(⟨e, h₃, h₄⟩ : R ≃+* S) = e :=
rfl
@@ -175,11 +164,13 @@ theorem coe_mk (e h₃ h₄) : ⇑(⟨e, h₃, h₄⟩ : R ≃+* S) = e :=
theorem mk_coe (e : R ≃+* S) (e' h₁ h₂ h₃ h₄) : (⟨⟨e, e', h₁, h₂⟩, h₃, h₄⟩ : R ≃+* S) = e :=
ext fun _ => rfl
-protected theorem congr_arg {f : R ≃+* S} {x x' : R} : x = x' → f x = f x' :=
- DFunLike.congr_arg f
+@[simp]
+theorem toEquiv_eq_coe (f : R ≃+* S) : f.toEquiv = f :=
+ rfl
-protected theorem congr_fun {f g : R ≃+* S} (h : f = g) (x : R) : f x = g x :=
- DFunLike.congr_fun h x
+@[simp]
+theorem coe_toEquiv (f : R ≃+* S) : ⇑(f : R ≃ S) = f :=
+ rfl
@[simp]
theorem toAddEquiv_eq_coe (f : R ≃+* S) : f.toAddEquiv = ↑f :=
@@ -197,22 +188,45 @@ theorem coe_toMulEquiv (f : R ≃+* S) : ⇑(f : R ≃* S) = f :=
theorem coe_toAddEquiv (f : R ≃+* S) : ⇑(f : R ≃+ S) = f :=
rfl
-/-- The `RingEquiv` between two semirings with a unique element. -/
-def ringEquivOfUnique {M N} [Unique M] [Unique N] [Add M] [Mul M] [Add N] [Mul N] : M ≃+* N :=
- { AddEquiv.addEquivOfUnique, MulEquiv.mulEquivOfUnique with }
+end coe
-instance {M N} [Unique M] [Unique N] [Add M] [Mul M] [Add N] [Mul N] :
- Unique (M ≃+* N) where
- default := ringEquivOfUnique
- uniq _ := ext fun _ => Subsingleton.elim _ _
+section map
+
+/-- A ring isomorphism preserves multiplication. -/
+protected theorem map_mul (e : R ≃+* S) (x y : R) : e (x * y) = e x * e y :=
+ map_mul e x y
+
+/-- A ring isomorphism preserves addition. -/
+protected theorem map_add (e : R ≃+* S) (x y : R) : e (x + y) = e x + e y :=
+ map_add e x y
+
+end map
+
+section bijective
+
+protected theorem bijective (e : R ≃+* S) : Function.Bijective e :=
+ EquivLike.bijective e
+
+protected theorem injective (e : R ≃+* S) : Function.Injective e :=
+ EquivLike.injective e
+
+protected theorem surjective (e : R ≃+* S) : Function.Surjective e :=
+ EquivLike.surjective e
+
+end bijective
variable (R)
+section refl
+
/-- The identity map is a ring isomorphism. -/
@[refl]
def refl : R ≃+* R :=
{ MulEquiv.refl R, AddEquiv.refl R with }
+instance : Inhabited (R ≃+* R) :=
+ ⟨RingEquiv.refl R⟩
+
@[simp]
theorem refl_apply (x : R) : RingEquiv.refl R x = x :=
rfl
@@ -225,22 +239,17 @@ theorem coe_addEquiv_refl : (RingEquiv.refl R : R ≃+ R) = AddEquiv.refl R :=
theorem coe_mulEquiv_refl : (RingEquiv.refl R : R ≃* R) = MulEquiv.refl R :=
rfl
-instance : Inhabited (R ≃+* R) :=
- ⟨RingEquiv.refl R⟩
+end refl
variable {R}
+section symm
+
/-- The inverse of a ring isomorphism is a ring isomorphism. -/
@[symm]
protected def symm (e : R ≃+* S) : S ≃+* R :=
{ e.toMulEquiv.symm, e.toAddEquiv.symm with }
-/-- See Note [custom simps projection] -/
-def Simps.symm_apply (e : R ≃+* S) : S → R :=
- e.symm
-
-initialize_simps_projections RingEquiv (toFun → apply, invFun → symm_apply)
-
@[simp]
theorem invFun_eq_symm (f : R ≃+* S) : EquivLike.inv f = f.symm :=
rfl
@@ -248,14 +257,6 @@ theorem invFun_eq_symm (f : R ≃+* S) : EquivLike.inv f = f.symm :=
@[simp]
theorem symm_symm (e : R ≃+* S) : e.symm.symm = e := rfl
-@[simp]
-theorem symm_refl : (RingEquiv.refl R).symm = RingEquiv.refl R :=
- rfl
-
-@[simp]
-theorem coe_toEquiv_symm (e : R ≃+* S) : (e.symm : S ≃ R) = (e : R ≃ S).symm :=
- rfl
-
theorem symm_bijective : Function.Bijective (RingEquiv.symm : (R ≃+* S) → S ≃+* R) :=
Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩
@@ -275,35 +276,14 @@ theorem symm_mk (f : R → S) (g h₁ h₂ h₃ h₄) :
invFun := f } :=
rfl
-/-- Transitivity of `RingEquiv`. -/
-@[trans]
-protected def trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') : R ≃+* S' :=
- { e₁.toMulEquiv.trans e₂.toMulEquiv, e₁.toAddEquiv.trans e₂.toAddEquiv with }
-
-theorem trans_apply (e₁ : R ≃+* S) (e₂ : S ≃+* S') (a : R) : e₁.trans e₂ a = e₂ (e₁ a) :=
- rfl
-
@[simp]
-theorem coe_trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') : (e₁.trans e₂ : R → S') = e₂ ∘ e₁ :=
+theorem symm_refl : (RingEquiv.refl R).symm = RingEquiv.refl R :=
rfl
@[simp]
-theorem symm_trans_apply (e₁ : R ≃+* S) (e₂ : S ≃+* S') (a : S') :
- (e₁.trans e₂).symm a = e₁.symm (e₂.symm a) :=
- rfl
-
-theorem symm_trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') : (e₁.trans e₂).symm = e₂.symm.trans e₁.symm :=
+theorem coe_toEquiv_symm (e : R ≃+* S) : (e.symm : S ≃ R) = (e : R ≃ S).symm :=
rfl
-protected theorem bijective (e : R ≃+* S) : Function.Bijective e :=
- EquivLike.bijective e
-
-protected theorem injective (e : R ≃+* S) : Function.Injective e :=
- EquivLike.injective e
-
-protected theorem surjective (e : R ≃+* S) : Function.Surjective e :=
- EquivLike.surjective e
-
@[simp]
theorem apply_symm_apply (e : R ≃+* S) : ∀ x, e (e.symm x) = x :=
e.toEquiv.apply_symm_apply
@@ -315,6 +295,40 @@ theorem symm_apply_apply (e : R ≃+* S) : ∀ x, e.symm (e x) = x :=
theorem image_eq_preimage (e : R ≃+* S) (s : Set R) : e '' s = e.symm ⁻¹' s :=
e.toEquiv.image_eq_preimage s
+end symm
+
+section simps
+
+/-- See Note [custom simps projection] -/
+def Simps.symm_apply (e : R ≃+* S) : S → R :=
+ e.symm
+
+initialize_simps_projections RingEquiv (toFun → apply, invFun → symm_apply)
+
+end simps
+
+section trans
+
+/-- Transitivity of `RingEquiv`. -/
+@[trans]
+protected def trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') : R ≃+* S' :=
+ { e₁.toMulEquiv.trans e₂.toMulEquiv, e₁.toAddEquiv.trans e₂.toAddEquiv with }
+
+@[simp]
+theorem coe_trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') : (e₁.trans e₂ : R → S') = e₂ ∘ e₁ :=
+ rfl
+
+theorem trans_apply (e₁ : R ≃+* S) (e₂ : S ≃+* S') (a : R) : e₁.trans e₂ a = e₂ (e₁ a) :=
+ rfl
+
+@[simp]
+theorem symm_trans_apply (e₁ : R ≃+* S) (e₂ : S ≃+* S') (a : S') :
+ (e₁.trans e₂).symm a = e₁.symm (e₂.symm a) :=
+ rfl
+
+theorem symm_trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') : (e₁.trans e₂).symm = e₂.symm.trans e₁.symm :=
+ rfl
+
@[simp]
theorem coe_mulEquiv_trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') :
(e₁.trans e₂ : R ≃* S') = (e₁ : R ≃* S).trans ↑e₂ :=
@@ -325,6 +339,21 @@ theorem coe_addEquiv_trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') :
(e₁.trans e₂ : R ≃+ S') = (e₁ : R ≃+ S).trans ↑e₂ :=
rfl
+end trans
+
+section unique
+
+/-- The `RingEquiv` between two semirings with a unique element. -/
+def ringEquivOfUnique {M N} [Unique M] [Unique N] [Add M] [Mul M] [Add N] [Mul N] : M ≃+* N :=
+ { AddEquiv.addEquivOfUnique, MulEquiv.mulEquivOfUnique with }
+
+instance {M N} [Unique M] [Unique N] [Add M] [Mul M] [Add N] [Mul N] :
+ Unique (M ≃+* N) where
+ default := ringEquivOfUnique
+ uniq _ := ext fun _ => Subsingleton.elim _ _
+
+end unique
+
end Basic
section Opposite
@@ -379,7 +408,7 @@ end Opposite
section NonUnitalSemiring
-variable [NonUnitalNonAssocSemiring R] [NonUnitalNonAssocSemiring S] (f : R ≃+* S) (x y : R)
+variable [NonUnitalNonAssocSemiring R] [NonUnitalNonAssocSemiring S] (f : R ≃+* S) (x : R)
/-- A ring isomorphism sends zero to zero. -/
protected theorem map_zero : f 0 = 0 :=
@@ -503,7 +532,7 @@ end NonUnitalSemiring
section Semiring
-variable [NonAssocSemiring R] [NonAssocSemiring S] (f : R ≃+* S) (x y : R)
+variable [NonAssocSemiring R] [NonAssocSemiring S] (f : R ≃+* S) (x : R)
/-- A ring isomorphism sends one to one. -/
protected theorem map_one : f 1 = 1 :=
@@ -574,9 +603,9 @@ end NonUnitalRing
section Ring
-variable [NonAssocRing R] [NonAssocRing S] (f : R ≃+* S) (x y : R)
+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
@@ -704,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
@@ -719,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
@@ -775,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
@@ -814,6 +836,33 @@ theorem symm_trans_self (e : R ≃+* S) : e.symm.trans e = RingEquiv.refl S :=
end RingEquiv
+namespace RingEquiv
+
+variable [NonAssocSemiring R] [NonAssocSemiring S]
+
+/-- If a ring homomorphism has an inverse, it is a ring isomorphism. -/
+@[simps]
+def ofRingHom (f : R →+* S) (g : S →+* R) (h₁ : f.comp g = RingHom.id S)
+ (h₂ : g.comp f = RingHom.id R) : R ≃+* S :=
+ { f with
+ toFun := f
+ invFun := g
+ left_inv := RingHom.ext_iff.1 h₂
+ right_inv := RingHom.ext_iff.1 h₁ }
+
+theorem coe_ringHom_ofRingHom (f : R →+* S) (g : S →+* R) (h₁ h₂) : ofRingHom f g h₁ h₂ = f :=
+ rfl
+
+@[simp]
+theorem ofRingHom_coe_ringHom (f : R ≃+* S) (g : S →+* R) (h₁ h₂) : ofRingHom (↑f) g h₁ h₂ = f :=
+ ext fun _ ↦ rfl
+
+theorem ofRingHom_symm (f : R →+* S) (g : S →+* R) (h₁ h₂) :
+ (ofRingHom f g h₁ h₂).symm = ofRingHom g f h₂ h₁ :=
+ rfl
+
+end RingEquiv
+
namespace MulEquiv
/-- If two rings are isomorphic, and the second doesn't have zero divisors,
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 6ffa90e13d5da..c03030622109a 100644
--- a/Mathlib/Algebra/Ring/Hom/Defs.lean
+++ b/Mathlib/Algebra/Ring/Hom/Defs.lean
@@ -153,7 +153,6 @@ end coe
section
variable [NonUnitalNonAssocSemiring α] [NonUnitalNonAssocSemiring β]
-variable (f : α →ₙ+* β) {x y : α}
@[ext]
theorem ext ⦃f g : α →ₙ+* β⦄ : (∀ x, f x = g x) → f = g :=
@@ -225,7 +224,6 @@ theorem coe_comp (g : β →ₙ+* γ) (f : α →ₙ+* β) : ⇑(g.comp f) = g
@[simp]
theorem comp_apply (g : β →ₙ+* γ) (f : α →ₙ+* β) (x : α) : g.comp f x = g (f x) :=
rfl
-variable (g : β →ₙ+* γ) (f : α →ₙ+* β)
@[simp]
theorem coe_comp_addMonoidHom (g : β →ₙ+* γ) (f : α →ₙ+* β) :
@@ -260,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
@@ -331,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
@@ -441,7 +439,7 @@ end coe
section
-variable {_ : NonAssocSemiring α} {_ : NonAssocSemiring β} (f : α →+* β) {x y : α}
+variable {_ : NonAssocSemiring α} {_ : NonAssocSemiring β} (f : α →+* β)
protected theorem congr_fun {f g : α →+* β} (h : f = g) (x : α) : f x = g x :=
DFunLike.congr_fun h x
@@ -597,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
@@ -651,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/Idempotents.lean b/Mathlib/Algebra/Ring/Idempotents.lean
index 415b47517507d..80a2c2e0be568 100644
--- a/Mathlib/Algebra/Ring/Idempotents.lean
+++ b/Mathlib/Algebra/Ring/Idempotents.lean
@@ -5,6 +5,7 @@ Authors: Christopher Hoskin
-/
import Mathlib.Algebra.Group.Basic
import Mathlib.Algebra.Group.Commute.Defs
+import Mathlib.Algebra.Group.Hom.Defs
import Mathlib.Algebra.Ring.Defs
import Mathlib.Data.Subtype
import Mathlib.Order.Notation
@@ -49,6 +50,10 @@ theorem mul_of_commute {p q : S} (h : Commute p q) (h₁ : IsIdempotentElem p)
(h₂ : IsIdempotentElem q) : IsIdempotentElem (p * q) := by
rw [IsIdempotentElem, mul_assoc, ← mul_assoc q, ← h.eq, mul_assoc p, h₂.eq, ← mul_assoc, h₁.eq]
+lemma mul {M} [CommSemigroup M] {e₁ e₂ : M}
+ (he₁ : IsIdempotentElem e₁) (he₂ : IsIdempotentElem e₂) : IsIdempotentElem (e₁ * e₂) :=
+ he₁.mul_of_commute (.all e₁ e₂) he₂
+
theorem zero : IsIdempotentElem (0 : M₀) :=
mul_zero _
@@ -83,6 +88,10 @@ theorem iff_eq_zero_or_one {p : G₀} : IsIdempotentElem p ↔ p = 0 ∨ p = 1 :
h.elim (fun hp => hp.symm ▸ zero) fun hp => hp.symm ▸ one
exact mul_left_cancel₀ hp (h.trans (mul_one p).symm)
+lemma map {M N F} [Mul M] [Mul N] [FunLike F M N] [MulHomClass F M N] {e : M}
+ (he : IsIdempotentElem e) (f : F) : IsIdempotentElem (f e) := by
+ rw [IsIdempotentElem, ← map_mul, he.eq]
+
/-! ### Instances on `Subtype IsIdempotentElem` -/
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 68823fef425a9..348175c301b9b 100644
--- a/Mathlib/Algebra/Ring/Int.lean
+++ b/Mathlib/Algebra/Ring/Int.lean
@@ -97,6 +97,8 @@ lemma odd_iff : Odd n ↔ n % 2 = 1 where
lemma not_odd_iff : ¬Odd n ↔ n % 2 = 0 := by rw [odd_iff, emod_two_ne_one]
+@[simp] lemma not_odd_zero : ¬Odd (0 : ℤ) := not_odd_iff.mpr rfl
+
@[simp] lemma not_odd_iff_even : ¬Odd n ↔ Even n := by rw [not_odd_iff, even_iff]
@[simp] lemma not_even_iff_odd : ¬Even n ↔ Odd n := by rw [not_even_iff, odd_iff]
@@ -118,9 +120,9 @@ lemma even_xor'_odd (n : ℤ) : Xor' (Even n) (Odd n) := by
lemma even_xor'_odd' (n : ℤ) : ∃ k, Xor' (n = 2 * k) (n = 2 * k + 1) := by
rcases even_or_odd n with (⟨k, rfl⟩ | ⟨k, rfl⟩) <;> use k
- · simpa only [← two_mul, Xor', true_and_iff, eq_self_iff_true, not_true, or_false_iff,
- and_false_iff] using (succ_ne_self (2 * k)).symm
- · simp only [Xor', add_right_eq_self, false_or_iff, eq_self_iff_true, not_true, not_false_iff,
+ · simpa only [← two_mul, Xor', true_and, eq_self_iff_true, not_true, or_false,
+ and_false] using (succ_ne_self (2 * k)).symm
+ · simp only [Xor', add_right_eq_self, false_or, eq_self_iff_true, not_true, not_false_iff,
one_ne_zero, and_self_iff]
instance : DecidablePred (Odd : ℤ → Prop) := fun _ => decidable_of_iff _ not_even_iff_odd
@@ -164,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 94a1d21b3a889..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
@@ -214,6 +204,8 @@ lemma not_odd_iff : ¬Odd n ↔ n % 2 = 0 := by rw [odd_iff, mod_two_ne_one]
@[simp] lemma not_odd_iff_even : ¬Odd n ↔ Even n := by rw [not_odd_iff, even_iff]
@[simp] lemma not_even_iff_odd : ¬Even n ↔ Odd n := by rw [not_even_iff, odd_iff]
+@[simp] lemma not_odd_zero : ¬Odd 0 := not_odd_iff.mpr rfl
+
@[deprecated not_odd_iff_even (since := "2024-08-21")]
lemma even_iff_not_odd : Even n ↔ ¬Odd n := by rw [not_odd_iff, even_iff]
@@ -236,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)]
@@ -324,7 +319,6 @@ namespace Involutive
variable {α : Type*} {f : α → α} {n : ℕ}
-set_option linter.deprecated false in
section
lemma iterate_bit0 (hf : Involutive f) (n : ℕ) : f^[2 * n] = id := by
@@ -360,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/Pointwise/Set.lean b/Mathlib/Algebra/Ring/Pointwise/Set.lean
index 4da48ed12ad44..5ec371a33579c 100644
--- a/Mathlib/Algebra/Ring/Pointwise/Set.lean
+++ b/Mathlib/Algebra/Ring/Pointwise/Set.lean
@@ -3,7 +3,7 @@ Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Floris van Doorn
-/
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Algebra.Ring.Defs
/-!
@@ -32,8 +32,7 @@ protected noncomputable def hasDistribNeg [Mul α] [HasDistribNeg α] : HasDistr
neg_mul _ _ := by simp_rw [← image_neg]; exact image2_image_left_comm neg_mul
mul_neg _ _ := by simp_rw [← image_neg]; exact image_image2_right_comm mul_neg
-scoped[Pointwise]
- attribute [instance] Set.divisionCommMonoid Set.subtractionCommMonoid Set.hasDistribNeg
+scoped[Pointwise] attribute [instance] Set.hasDistribNeg
section Distrib
variable [Distrib α] (s t u : Set α)
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/Semiconj.lean b/Mathlib/Algebra/Ring/Semiconj.lean
index 7ca35cfbf5af9..8b20e68a71a06 100644
--- a/Mathlib/Algebra/Ring/Semiconj.lean
+++ b/Mathlib/Algebra/Ring/Semiconj.lean
@@ -19,9 +19,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
@@ -59,7 +59,7 @@ end
section
-variable [MulOneClass R] [HasDistribNeg R] {a x y : R}
+variable [MulOneClass R] [HasDistribNeg R]
-- Porting note: `simpNF` told me to remove `simp` attribute
theorem neg_one_right (a : R) : SemiconjBy a (-1) (-1) :=
diff --git a/Mathlib/Algebra/Ring/Subring/Basic.lean b/Mathlib/Algebra/Ring/Subring/Basic.lean
index c93d933e50864..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
@@ -72,7 +73,7 @@ section SubringClass
/-- `SubringClass S R` states that `S` is a type of subsets `s ⊆ R` that
are both a multiplicative submonoid and an additive subgroup. -/
-class SubringClass (S : Type*) (R : Type u) [Ring R] [SetLike S R] extends
+class SubringClass (S : Type*) (R : outParam (Type u)) [Ring R] [SetLike S R] extends
SubsemiringClass S R, NegMemClass S R : Prop
-- See note [lower instance priority]
@@ -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)
@@ -897,6 +912,14 @@ theorem map_iSup {ι : Sort*} (f : R →+* S) (s : ι → Subring R) :
(iSup s).map f = ⨆ i, (s i).map f :=
(gc_map_comap f).l_iSup
+theorem map_inf (s t : Subring R) (f : R →+* S) (hf : Function.Injective f) :
+ (s ⊓ t).map f = s.map f ⊓ t.map f := SetLike.coe_injective (Set.image_inter hf)
+
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : R →+* S) (hf : Function.Injective f)
+ (s : ι → Subring R) : (iInf s).map f = ⨅ i, (s i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ s)
+
theorem comap_inf (s t : Subring S) (f : R →+* S) : (s ⊓ t).comap f = s.comap f ⊓ t.comap f :=
(gc_map_comap f).u_inf
@@ -1075,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/IntPolynomial.lean b/Mathlib/Algebra/Ring/Subring/IntPolynomial.lean
new file mode 100644
index 0000000000000..a91e2bf11eca4
--- /dev/null
+++ b/Mathlib/Algebra/Ring/Subring/IntPolynomial.lean
@@ -0,0 +1,62 @@
+/-
+Copyright (c) 2024 María Inés de Frutos-Fernández, Filippo A. E. Nuccio. All rights reserved.
+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.Algebra.Polynomial.AlgebraMap
+
+/-!
+# Polynomials over subrings.
+
+Given a field `K` with a subring `R`, in this file we construct a map from polynomials in `K[X]`
+with coefficients in `R` to `R[X]`. We provide several lemmas to deal with
+coefficients, degree, and evaluation of `intPolynomial`.
+This is useful when dealing with integral elements in an extension of fields.
+
+# Main Definitions
+* `Polynomial.int` : given a polynomial `P`. in `K[X]` with coefficients in a field `K` with a
+ subring `R` such that all coefficients belong to `R`, `P.int R` is the corresponding polynomial
+ in `R[X]`.
+-/
+
+variable {K : Type*} [Field K] (R : Subring K)
+
+open Polynomial
+
+open scoped Polynomial
+
+/-- Given a polynomial in `K[X]` such that all coefficients belong to the subring `R`,
+ `intPolynomial` is the corresponding polynomial in `R[X]`. -/
+def Polynomial.int (P : K[X]) (hP : ∀ n : ℕ, P.coeff n ∈ R) : R[X] where
+ toFinsupp :=
+ { support := P.support
+ toFun := fun n => ⟨P.coeff n, hP n⟩
+ mem_support_toFun := fun n => by
+ rw [ne_eq, ← Subring.coe_eq_zero_iff, mem_support_iff] }
+
+namespace Polynomial
+
+variable (P : K[X]) (hP : ∀ n : ℕ, P.coeff n ∈ R)
+
+@[simp]
+theorem int_coeff_eq (n : ℕ) : ↑((P.int R hP).coeff n) = P.coeff n := rfl
+
+@[simp]
+theorem int_leadingCoeff_eq : ↑(P.int R hP).leadingCoeff = P.leadingCoeff := rfl
+
+@[simp]
+theorem int_monic_iff : (P.int R hP).Monic ↔ P.Monic := by
+ rw [Monic, Monic, ← int_leadingCoeff_eq, OneMemClass.coe_eq_one]
+
+@[simp]
+theorem int_natDegree : (P.int R hP).natDegree = P.natDegree := rfl
+
+variable {L : Type*} [Field L] [Algebra K L]
+
+@[simp]
+theorem int_eval₂_eq (x : L) :
+ eval₂ (algebraMap R L) x (P.int R hP) = aeval x P := by
+ rw [aeval_eq_sum_range, eval₂_eq_sum_range]
+ exact Finset.sum_congr rfl (fun n _ => by rw [Algebra.smul_def]; rfl)
+
+end Polynomial
diff --git a/Mathlib/Algebra/Ring/Subring/MulOpposite.lean b/Mathlib/Algebra/Ring/Subring/MulOpposite.lean
index 77448007af326..3234c63eecfab 100644
--- a/Mathlib/Algebra/Ring/Subring/MulOpposite.lean
+++ b/Mathlib/Algebra/Ring/Subring/MulOpposite.lean
@@ -141,7 +141,7 @@ theorem op_closure (s : Set R) : (closure s).op = closure (MulOpposite.unop ⁻
theorem unop_closure (s : Set Rᵐᵒᵖ) : (closure s).unop = closure (MulOpposite.op ⁻¹' s) := by
rw [← op_inj, op_unop, op_closure]
- rfl
+ simp_rw [Set.preimage_preimage, MulOpposite.op_unop, Set.preimage_id']
/-- Bijection between a subring `S` and its opposite. -/
@[simps!]
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 72f996c586990..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)
@@ -59,15 +59,20 @@ section SubsemiringClass
/-- `SubsemiringClass S R` states that `S` is a type of subsets `s ⊆ R` that
are both a multiplicative and an additive submonoid. -/
-class SubsemiringClass (S : Type*) (R : Type u) [NonAssocSemiring R]
+class SubsemiringClass (S : Type*) (R : outParam (Type u)) [NonAssocSemiring R]
[SetLike S R] extends SubmonoidClass S R, AddSubmonoidClass S R : Prop
-- See note [lower instance priority]
instance (priority := 100) SubsemiringClass.addSubmonoidWithOneClass (S : Type*)
- (R : Type u) [NonAssocSemiring R] [SetLike S R] [h : SubsemiringClass S R] :
+ (R : Type u) {_ : NonAssocSemiring R} [SetLike S R] [h : SubsemiringClass S R] :
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
@@ -500,6 +504,13 @@ theorem coe_sInf (S : Set (Subsemiring R)) : ((sInf S : Subsemiring R) : Set R)
theorem mem_sInf {S : Set (Subsemiring R)} {x : R} : x ∈ sInf S ↔ ∀ p ∈ S, x ∈ p :=
Set.mem_iInter₂
+@[simp, norm_cast]
+theorem coe_iInf {ι : Sort*} {S : ι → Subsemiring R} : (↑(⨅ i, S i) : Set R) = ⋂ i, S i := by
+ simp only [iInf, coe_sInf, Set.biInter_range]
+
+theorem mem_iInf {ι : Sort*} {S : ι → Subsemiring R} {x : R} : (x ∈ ⨅ i, S i) ↔ ∀ i, x ∈ S i := by
+ simp only [iInf, mem_sInf, Set.forall_mem_range]
+
@[simp]
theorem sInf_toSubmonoid (s : Set (Subsemiring R)) :
(sInf s).toSubmonoid = ⨅ t ∈ s, Subsemiring.toSubmonoid t :=
@@ -734,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, one_mul x⟩)
- ⟨[], 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 ▸
@@ -835,6 +853,14 @@ theorem map_iSup {ι : Sort*} (f : R →+* S) (s : ι → Subsemiring R) :
(iSup s).map f = ⨆ i, (s i).map f :=
(gc_map_comap f).l_iSup
+theorem map_inf (s t : Subsemiring R) (f : R →+* S) (hf : Function.Injective f) :
+ (s ⊓ t).map f = s.map f ⊓ t.map f := SetLike.coe_injective (Set.image_inter hf)
+
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : R →+* S) (hf : Function.Injective f)
+ (s : ι → Subsemiring R) : (iInf s).map f = ⨅ i, (s i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ s)
+
theorem comap_inf (s t : Subsemiring S) (f : R →+* S) : (s ⊓ t).comap f = s.comap f ⊓ t.comap f :=
(gc_map_comap f).u_inf
@@ -1180,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 ca90d5e223c98..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
/-!
@@ -147,7 +148,7 @@ theorem op_closure (s : Set R) : (closure s).op = closure (MulOpposite.unop ⁻
theorem unop_closure (s : Set Rᵐᵒᵖ) : (closure s).unop = closure (MulOpposite.op ⁻¹' s) := by
rw [← op_inj, op_unop, op_closure]
- rfl
+ simp_rw [Set.preimage_preimage, MulOpposite.op_unop, Set.preimage_id']
/-- Bijection between a subsemiring `S` and its opposite. -/
@[simps!]
diff --git a/Mathlib/Algebra/Ring/SumsOfSquares.lean b/Mathlib/Algebra/Ring/SumsOfSquares.lean
index 1eb9bb77744cf..6abec158dd334 100644
--- a/Mathlib/Algebra/Ring/SumsOfSquares.lean
+++ b/Mathlib/Algebra/Ring/SumsOfSquares.lean
@@ -3,9 +3,8 @@ Copyright (c) 2024 Florent Schaffhauser. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Florent Schaffhauser
-/
-import Mathlib.Algebra.Ring.Defs
+import Mathlib.Algebra.BigOperators.Group.Finset
import Mathlib.Algebra.Group.Submonoid.Basic
-import Mathlib.Algebra.Group.Even
import Mathlib.Algebra.Order.Ring.Defs
/-!
@@ -61,6 +60,15 @@ theorem IsSumSq.add [AddMonoid R] {S1 S2 : R} (p1 : IsSumSq S1)
@[deprecated (since := "2024-08-09")] alias isSumSq.add := IsSumSq.add
+/-- A finite sum of squares is a sum of squares. -/
+theorem isSumSq_sum_mul_self {ι : Type*} [AddCommMonoid R] (s : Finset ι) (f : ι → R) :
+ IsSumSq (∑ i ∈ s, f i * f i) := by
+ induction s using Finset.cons_induction with
+ | empty =>
+ simpa only [Finset.sum_empty] using IsSumSq.zero
+ | cons i s his h =>
+ exact (Finset.sum_cons (β := R) his) ▸ IsSumSq.sq_add (f i) (∑ i ∈ s, f i * f i) h
+
variable (R) in
/--
In an additive monoid with multiplication `R`, the type `sumSqIn R` is the submonoid of sums of
diff --git a/Mathlib/Algebra/Ring/ULift.lean b/Mathlib/Algebra/Ring/ULift.lean
index d22da7ec4c22e..b0d8c9a46ca7d 100644
--- a/Mathlib/Algebra/Ring/ULift.lean
+++ b/Mathlib/Algebra/Ring/ULift.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.ULift
import Mathlib.Algebra.Ring.Equiv
diff --git a/Mathlib/Algebra/Ring/Units.lean b/Mathlib/Algebra/Ring/Units.lean
index fbcb29f67829f..619def14cb01a 100644
--- a/Mathlib/Algebra/Ring/Units.lean
+++ b/Mathlib/Algebra/Ring/Units.lean
@@ -15,7 +15,7 @@ import Mathlib.Algebra.Ring.Hom.Defs
universe u v w x
-variable {α : Type u} {β : Type v} {γ : Type w} {R : Type x}
+variable {α : Type u} {β : Type v} {R : Type x}
open Function
@@ -23,7 +23,7 @@ namespace Units
section HasDistribNeg
-variable [Monoid α] [HasDistribNeg α] {a b : α}
+variable [Monoid α] [HasDistribNeg α]
/-- Each element of the group of units of a ring has an additive inverse. -/
instance : Neg αˣ :=
@@ -49,7 +49,7 @@ end HasDistribNeg
section Ring
-variable [Ring α] {a b : α}
+variable [Ring α]
-- Needs to have higher simp priority than divp_add_divp. 1000 is the default priority.
@[field_simps 1010]
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 65dc7e05fcf81..fb0556615bab7 100644
--- a/Mathlib/Algebra/RingQuot.lean
+++ b/Mathlib/Algebra/RingQuot.lean
@@ -1,10 +1,12 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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 1eba1392560bd..b897e154bd18f 100644
--- a/Mathlib/Algebra/SMulWithZero.lean
+++ b/Mathlib/Algebra/SMulWithZero.lean
@@ -7,7 +7,6 @@ import Mathlib.Algebra.Group.Action.Opposite
import Mathlib.Algebra.GroupWithZero.Action.Defs
import Mathlib.Algebra.GroupWithZero.Hom
import Mathlib.Algebra.GroupWithZero.Opposite
-import Mathlib.Algebra.Ring.Defs
/-!
# Introduce `SMulWithZero`
@@ -127,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 }
@@ -199,8 +199,3 @@ theorem smul_inv₀ [SMulCommClass α β β] [IsScalarTower α β β] (c : α) (
rw [smul_mul_smul_comm, inv_mul_cancel₀ hc, inv_mul_cancel₀ hx, one_smul]
end GroupWithZero
-
--- This instance seems a bit incongruous in this file, but `#find_home!` told me to put it here.
-instance NonUnitalNonAssocSemiring.toDistribSMul [NonUnitalNonAssocSemiring R] :
- DistribSMul R R where
- smul_add := mul_add
diff --git a/Mathlib/Algebra/Squarefree/Basic.lean b/Mathlib/Algebra/Squarefree/Basic.lean
index 4ea689f18ad28..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
@@ -153,7 +152,7 @@ theorem squarefree_iff_irreducible_sq_not_dvd_of_ne_zero {r : R} (hr : r ≠ 0)
theorem squarefree_iff_irreducible_sq_not_dvd_of_exists_irreducible {r : R}
(hr : ∃ x : R, Irreducible x) : Squarefree r ↔ ∀ x : R, Irreducible x → ¬x * x ∣ r := by
rw [irreducible_sq_not_dvd_iff_eq_zero_and_no_irreducibles_or_squarefree, ← not_exists]
- simp only [hr, not_true, false_or_iff, and_false_iff]
+ simp only [hr, not_true, false_or, and_false]
end Irreducible
@@ -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/Basic.lean b/Mathlib/Algebra/Star/Basic.lean
index 35276edb14891..99fd9d0f28098 100644
--- a/Mathlib/Algebra/Star/Basic.lean
+++ b/Mathlib/Algebra/Star/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Field.Defs
import Mathlib.Algebra.Group.Invertible.Defs
diff --git a/Mathlib/Algebra/Star/CHSH.lean b/Mathlib/Algebra/Star/CHSH.lean
index 6d92b8ca15050..eedcf9c9f9801 100644
--- a/Mathlib/Algebra/Star/CHSH.lean
+++ b/Mathlib/Algebra/Star/CHSH.lean
@@ -1,10 +1,11 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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/Conjneg.lean b/Mathlib/Algebra/Star/Conjneg.lean
index 1fb96695c6371..9b9c3b54defe4 100644
--- a/Mathlib/Algebra/Star/Conjneg.lean
+++ b/Mathlib/Algebra/Star/Conjneg.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies
-/
import Mathlib.Algebra.BigOperators.Pi
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Algebra.Star.Pi
/-!
diff --git a/Mathlib/Algebra/Star/Free.lean b/Mathlib/Algebra/Star/Free.lean
index eefbd4ba0c208..b29ed2137d81e 100644
--- a/Mathlib/Algebra/Star/Free.lean
+++ b/Mathlib/Algebra/Star/Free.lean
@@ -48,7 +48,7 @@ instance : StarRing (FreeAlgebra R X) where
unfold Star.star
simp only [Function.comp_apply]
let y := lift R (X := X) (MulOpposite.op ∘ ι R)
- apply induction (C := fun x ↦ (y (y x).unop).unop = x) _ _ _ _ x
+ refine induction (C := fun x ↦ (y (y x).unop).unop = x) _ _ ?_ ?_ ?_ ?_ x
· intros
simp only [AlgHom.commutes, MulOpposite.algebraMap_apply, MulOpposite.unop_op]
· intros
diff --git a/Mathlib/Algebra/Star/Module.lean b/Mathlib/Algebra/Star/Module.lean
index b062492e6acbd..214d513fed01a 100644
--- a/Mathlib/Algebra/Star/Module.lean
+++ b/Mathlib/Algebra/Star/Module.lean
@@ -75,11 +75,43 @@ theorem star_ratCast_smul [DivisionRing R] [AddCommGroup M] [Module R M] [StarAd
@[deprecated (since := "2024-04-17")]
alias star_rat_cast_smul := star_ratCast_smul
-@[simp]
-theorem star_rat_smul {R : Type*} [AddCommGroup R] [StarAddMonoid R] [Module ℚ R] (x : R) (n : ℚ) :
- star (n • x) = n • star x :=
+/-!
+Per the naming convention, these two lemmas call `(q • ·)` `nnrat_smul` and `rat_smul` respectively,
+rather than `nnqsmul` and `qsmul` because the latter are reserved to the actions coming from
+`DivisionSemiring` and `DivisionRing`. We provide aliases with `nnqsmul` and `qsmul` for
+discoverability.
+-/
+
+/-- Note that this lemma holds for an arbitrary `ℚ≥0`-action, rather than merely one coming from a
+`DivisionSemiring`. We keep both the `nnqsmul` and `nnrat_smul` naming conventions for
+discoverability. See `star_nnqsmul`. -/
+@[simp high]
+lemma star_nnrat_smul [AddCommMonoid R] [StarAddMonoid R] [Module ℚ≥0 R] (q : ℚ≥0) (x : R) :
+ star (q • x) = q • star x := map_nnrat_smul (starAddEquiv : R ≃+ R) _ _
+
+/-- Note that this lemma holds for an arbitrary `ℚ`-action, rather than merely one coming from a
+`DivisionRing`. We keep both the `qsmul` and `rat_smul` naming conventions for discoverability.
+See `star_qsmul`. -/
+@[simp high] lemma star_rat_smul [AddCommGroup R] [StarAddMonoid R] [Module ℚ R] (q : ℚ) (x : R) :
+ star (q • x) = q • star x :=
map_rat_smul (starAddEquiv : R ≃+ R) _ _
+/-- Note that this lemma holds for an arbitrary `ℚ≥0`-action, rather than merely one coming from a
+`DivisionSemiring`. We keep both the `nnqsmul` and `nnrat_smul` naming conventions for
+discoverability. See `star_nnrat_smul`. -/
+alias star_nnqsmul := star_nnrat_smul
+
+/-- Note that this lemma holds for an arbitrary `ℚ`-action, rather than merely one coming from a
+`DivisionRing`. We keep both the `qsmul` and `rat_smul` naming conventions for
+discoverability. See `star_rat_smul`. -/
+alias star_qsmul := star_rat_smul
+
+instance StarAddMonoid.toStarModuleNNRat [AddCommMonoid R] [Module ℚ≥0 R] [StarAddMonoid R] :
+ StarModule ℚ≥0 R where star_smul := star_nnrat_smul
+
+instance StarAddMonoid.toStarModuleRat [AddCommGroup R] [Module ℚ R] [StarAddMonoid R] :
+ StarModule ℚ R where star_smul := star_rat_smul
+
end SMulLemmas
/-- If `A` is a module over a commutative `R` with compatible actions,
@@ -184,8 +216,8 @@ def StarModule.decomposeProdAdjoint : A ≃ₗ[R] selfAdjoint A × skewAdjoint A
refine LinearEquiv.ofLinear ((selfAdjointPart R).prod (skewAdjointPart R))
(LinearMap.coprod ((selfAdjoint.submodule R A).subtype) (skewAdjoint.submodule R A).subtype)
?_ (LinearMap.ext <| StarModule.selfAdjointPart_add_skewAdjointPart R)
- -- Note: with #6965 `Submodule.coeSubtype` doesn't fire in `dsimp` or `simp`
- ext x <;> dsimp <;> erw [Submodule.coeSubtype, Submodule.coeSubtype] <;> simp
+ -- Note: with #6965 `Submodule.coe_subtype` doesn't fire in `dsimp` or `simp`
+ ext x <;> dsimp <;> erw [Submodule.coe_subtype, Submodule.coe_subtype] <;> simp
end SelfSkewAdjoint
diff --git a/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean b/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean
index b0c9fd1f0330b..558c7dbee59ad 100644
--- a/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean
+++ b/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean
@@ -97,7 +97,7 @@ variable [CommSemiring R]
variable [NonUnitalNonAssocSemiring A] [Module R A] [Star A]
variable [NonUnitalNonAssocSemiring B] [Module R B] [Star B]
variable [NonUnitalNonAssocSemiring C] [Module R C] [Star C]
-variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [NonUnitalStarAlgHomClass F R A B]
+variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [StarHomClass F A B]
instance instSetLike : SetLike (NonUnitalStarSubalgebra R A) A where
coe {s} := s.carrier
@@ -398,7 +398,7 @@ variable [CommSemiring R]
variable [NonUnitalNonAssocSemiring A] [Module R A] [Star A]
variable [NonUnitalNonAssocSemiring B] [Module R B] [Star B]
variable [NonUnitalNonAssocSemiring C] [Module R C] [Star C]
-variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [NonUnitalStarAlgHomClass F R A B]
+variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [StarHomClass F A B]
/-- Range of an `NonUnitalAlgHom` as a `NonUnitalStarSubalgebra`. -/
protected def range (φ : F) : NonUnitalStarSubalgebra R B where
@@ -471,7 +471,7 @@ variable [CommSemiring R]
variable [NonUnitalSemiring A] [Module R A] [Star A]
variable [NonUnitalSemiring B] [Module R B] [Star B]
variable [NonUnitalSemiring C] [Module R C] [Star C]
-variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [NonUnitalStarAlgHomClass F R A B]
+variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [StarHomClass F A B]
/-- Restrict a non-unital star algebra homomorphism with a left inverse to an algebra isomorphism
to its range.
@@ -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)
@@ -600,7 +600,7 @@ namespace NonUnitalStarAlgebra
variable [CommSemiring R] [StarRing R]
variable [NonUnitalSemiring A] [StarRing A] [Module R A]
variable [NonUnitalSemiring B] [StarRing B] [Module R B]
-variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [NonUnitalStarAlgHomClass F R A B]
+variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [StarHomClass F A B]
section StarSubAlgebraA
@@ -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
@@ -733,6 +737,11 @@ theorem map_sup [IsScalarTower R B B] [SMulCommClass R B B] [StarModule R B] (f
((S ⊔ T).map f : NonUnitalStarSubalgebra R B) = S.map f ⊔ T.map f :=
(NonUnitalStarSubalgebra.gc_map_comap f).l_sup
+theorem map_inf [IsScalarTower R B B] [SMulCommClass R B B] [StarModule R B] (f : F)
+ (hf : Function.Injective f) (S T : NonUnitalStarSubalgebra R A) :
+ ((S ⊓ T).map f : NonUnitalStarSubalgebra R B) = S.map f ⊓ T.map f :=
+ SetLike.coe_injective (Set.image_inter hf)
+
@[simp, norm_cast]
theorem coe_inf (S T : NonUnitalStarSubalgebra R A) : (↑(S ⊓ T) : Set A) = (S : Set A) ∩ T :=
rfl
@@ -766,6 +775,13 @@ theorem coe_iInf {ι : Sort*} {S : ι → NonUnitalStarSubalgebra R A} :
theorem mem_iInf {ι : Sort*} {S : ι → NonUnitalStarSubalgebra R A} {x : A} :
(x ∈ ⨅ i, S i) ↔ ∀ i, x ∈ S i := by simp only [iInf, mem_sInf, Set.forall_mem_range]
+theorem map_iInf {ι : Sort*} [Nonempty ι]
+ [IsScalarTower R B B] [SMulCommClass R B B] [StarModule R B] (f : F)
+ (hf : Function.Injective f) (S : ι → NonUnitalStarSubalgebra R A) :
+ ((⨅ i, S i).map f : NonUnitalStarSubalgebra R B) = ⨅ i, (S i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ S)
+
@[simp]
theorem iInf_toNonUnitalSubalgebra {ι : Sort*} (S : ι → NonUnitalStarSubalgebra R A) :
(⨅ i, S i).toNonUnitalSubalgebra = ⨅ i, (S i).toNonUnitalSubalgebra :=
@@ -786,7 +802,7 @@ theorem toNonUnitalSubalgebra_bot :
@[simp]
theorem coe_bot : ((⊥ : NonUnitalStarSubalgebra R A) : Set A) = {0} := by
simp only [Set.ext_iff, NonUnitalStarAlgebra.mem_bot, SetLike.mem_coe, Set.mem_singleton_iff,
- iff_self_iff, forall_const]
+ forall_const]
theorem eq_top_iff {S : NonUnitalStarSubalgebra R A} : S = ⊤ ↔ ∀ x : A, x ∈ S :=
⟨fun h x => by rw [h]; exact mem_top,
@@ -831,7 +847,7 @@ open NonUnitalStarAlgebra
variable [CommSemiring R]
variable [NonUnitalSemiring A] [StarRing A] [Module R A]
variable [NonUnitalSemiring B] [StarRing B] [Module R B]
-variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [NonUnitalStarAlgHomClass F R A B]
+variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [StarHomClass F A B]
variable (S : NonUnitalStarSubalgebra R A)
section StarSubalgebra
diff --git a/Mathlib/Algebra/Star/Pointwise.lean b/Mathlib/Algebra/Star/Pointwise.lean
index 58c6df130b0b7..6c37067eee6ab 100644
--- a/Mathlib/Algebra/Star/Pointwise.lean
+++ b/Mathlib/Algebra/Star/Pointwise.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.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Algebra.Star.Basic
import Mathlib.Data.Set.Finite
diff --git a/Mathlib/Algebra/Star/SelfAdjoint.lean b/Mathlib/Algebra/Star/SelfAdjoint.lean
index dffa88585c945..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
@@ -91,6 +91,7 @@ lemma commute_iff {R : Type*} [Mul R] [StarMul R] {x y : R}
· simpa only [star_mul, hx.star_eq, hy.star_eq] using h.symm
/-- Functions in a `StarHomClass` preserve self-adjoint elements. -/
+@[aesop 10% apply]
theorem map {F R S : Type*} [Star R] [Star S] [FunLike F R S] [StarHomClass F R S]
{x : R} (hx : IsSelfAdjoint x) (f : F) : IsSelfAdjoint (f x) :=
show star (f x) = f x from map_star f x ▸ congr_arg f hx
diff --git a/Mathlib/Algebra/Star/StarAlgHom.lean b/Mathlib/Algebra/Star/StarAlgHom.lean
index 53f42e18c47a9..3a2986c6d730c 100644
--- a/Mathlib/Algebra/Star/StarAlgHom.lean
+++ b/Mathlib/Algebra/Star/StarAlgHom.lean
@@ -64,6 +64,7 @@ add_decl_doc NonUnitalStarAlgHom.toNonUnitalAlgHom
/-- `NonUnitalStarAlgHomClass F R A B` asserts `F` is a type of bundled non-unital ⋆-algebra
homomorphisms from `A` to `B`. -/
+@[deprecated StarHomClass (since := "2024-09-08")]
class NonUnitalStarAlgHomClass (F : Type*) (R A B : outParam Type*)
[Monoid R] [Star A] [Star B] [NonUnitalNonAssocSemiring A] [NonUnitalNonAssocSemiring B]
[DistribMulAction R A] [DistribMulAction R B] [FunLike F A B] [NonUnitalAlgHomClass F R A B]
@@ -76,17 +77,18 @@ variable [NonUnitalNonAssocSemiring A] [DistribMulAction R A] [Star A]
variable [NonUnitalNonAssocSemiring B] [DistribMulAction R B] [Star B]
variable [FunLike F A B] [NonUnitalAlgHomClass F R A B]
-/-- Turn an element of a type `F` satisfying `NonUnitalStarAlgHomClass F R A B` into an actual
-`NonUnitalStarAlgHom`. This is declared as the default coercion from `F` to `A →⋆ₙₐ[R] B`. -/
+/-- Turn an element of a type `F` satisfying `NonUnitalAlgHomClass F R A B` and `StarHomClass F A B`
+into an actual `NonUnitalStarAlgHom`. This is declared as the default coercion from `F` to
+`A →⋆ₙₐ[R] B`. -/
@[coe]
-def toNonUnitalStarAlgHom [NonUnitalStarAlgHomClass F R A B] (f : F) : A →⋆ₙₐ[R] B :=
+def toNonUnitalStarAlgHom [StarHomClass F A B] (f : F) : A →⋆ₙₐ[R] B :=
{ (f : A →ₙₐ[R] B) with
map_star' := map_star f }
-instance [NonUnitalStarAlgHomClass F R A B] : CoeTC F (A →⋆ₙₐ[R] B) :=
+instance [StarHomClass F A B] : CoeTC F (A →⋆ₙₐ[R] B) :=
⟨toNonUnitalStarAlgHom⟩
-instance [NonUnitalStarAlgHomClass F R A B] : NonUnitalStarRingHomClass F A B :=
+instance [StarHomClass F A B] : NonUnitalStarRingHomClass F A B :=
NonUnitalStarRingHomClass.mk
end NonUnitalStarAlgHomClass
@@ -111,7 +113,7 @@ instance : NonUnitalAlgHomClass (A →⋆ₙₐ[R] B) R A B where
map_zero f := f.map_zero'
map_mul f := f.map_mul'
-instance : NonUnitalStarAlgHomClass (A →⋆ₙₐ[R] B) R A B where
+instance : StarHomClass (A →⋆ₙₐ[R] B) A B where
map_star f := f.map_star'
-- Porting note: in mathlib3 we didn't need the `Simps.apply` hint.
@@ -123,7 +125,7 @@ initialize_simps_projections NonUnitalStarAlgHom
@[simp]
protected theorem coe_coe {F : Type*} [FunLike F A B] [NonUnitalAlgHomClass F R A B]
- [NonUnitalStarAlgHomClass F R A B] (f : F) :
+ [StarHomClass F A B] (f : F) :
⇑(f : A →⋆ₙₐ[R] B) = f := rfl
@[simp]
@@ -304,34 +306,21 @@ by forgetting the interaction with the star operation. -/
add_decl_doc StarAlgHom.toAlgHom
/-- `StarAlgHomClass F R A B` states that `F` is a type of ⋆-algebra homomorphisms.
-
You should also extend this typeclass when you extend `StarAlgHom`. -/
+@[deprecated StarHomClass (since := "2024-09-08")]
class StarAlgHomClass (F : Type*) (R A B : outParam Type*)
[CommSemiring R] [Semiring A] [Algebra R A] [Star A] [Semiring B] [Algebra R B] [Star B]
[FunLike F A B] [AlgHomClass F R A B] extends StarHomClass F A B : Prop
-
--- Porting note: no longer needed
----- `R` becomes a metavariable but that's fine because it's an `outParam`
---attribute [nolint dangerousInstance] StarAlgHomClass.toStarHomClass
-
namespace StarAlgHomClass
-variable (F R A B : Type*)
-
--- See note [lower instance priority]
-instance (priority := 100) toNonUnitalStarAlgHomClass [CommSemiring R] [Semiring A] [Algebra R A]
- [Star A] [Semiring B] [Algebra R B] [Star B] [FunLike F A B] [AlgHomClass F R A B]
- [StarAlgHomClass F R A B] :
- NonUnitalStarAlgHomClass F R A B :=
- { }
+variable {F R A B : Type*}
variable [CommSemiring R] [Semiring A] [Algebra R A] [Star A]
variable [Semiring B] [Algebra R B] [Star B] [FunLike F A B] [AlgHomClass F R A B]
-variable [StarAlgHomClass F R A B]
+variable [StarHomClass F A B]
-variable {F R A B} in
-/-- Turn an element of a type `F` satisfying `StarAlgHomClass F R A B` into an actual
-`StarAlgHom`. This is declared as the default coercion from `F` to `A →⋆ₐ[R] B`. -/
+/-- Turn an element of a type `F` satisfying `AlgHomClass F R A B` and `StarHomClass F A B` into an
+actual `StarAlgHom`. This is declared as the default coercion from `F` to `A →⋆ₐ[R] B`. -/
@[coe]
def toStarAlgHom (f : F) : A →⋆ₐ[R] B :=
{ (f : A →ₐ[R] B) with
@@ -358,12 +347,12 @@ instance : AlgHomClass (A →⋆ₐ[R] B) R A B where
map_zero f := f.map_zero'
commutes f := f.commutes'
-instance : StarAlgHomClass (A →⋆ₐ[R] B) R A B where
+instance : StarHomClass (A →⋆ₐ[R] B) A B where
map_star f := f.map_star'
@[simp]
protected theorem coe_coe {F : Type*} [FunLike F A B] [AlgHomClass F R A B]
- [StarAlgHomClass F R A B] (f : F) :
+ [StarHomClass F A B] (f : F) :
⇑(f : A →⋆ₐ[R] B) = f :=
rfl
@@ -660,27 +649,16 @@ class NonUnitalAlgEquivClass (F : Type*) (R A B : outParam Type*)
/-- `StarAlgEquivClass F R A B` asserts `F` is a type of bundled ⋆-algebra equivalences between
`A` and `B`.
-
You should also extend this typeclass when you extend `StarAlgEquiv`. -/
+@[deprecated StarHomClass (since := "2024-09-08")]
class StarAlgEquivClass (F : Type*) (R A B : outParam Type*)
[Add A] [Mul A] [SMul R A] [Star A] [Add B] [Mul B] [SMul R B]
[Star B] [EquivLike F A B] [NonUnitalAlgEquivClass F R A B] : Prop where
/-- By definition, a ⋆-algebra equivalence preserves the `star` operation. -/
- map_star : ∀ (f : F) (a : A), f (star a) = star (f a)
-
--- Porting note: no longer needed
----- `R` becomes a metavariable but that's fine because it's an `outParam`
--- attribute [nolint dangerousInstance] StarAlgEquivClass.toRingEquivClass
+ protected map_star : ∀ (f : F) (a : A), f (star a) = star (f a)
namespace StarAlgEquivClass
--- See note [lower instance priority]
-instance (priority := 50) {F R A B : Type*} [Add A] [Mul A] [SMul R A] [Star A] [Add B] [Mul B]
- [SMul R B] [Star B] [EquivLike F A B] [NonUnitalAlgEquivClass F R A B]
- [hF : StarAlgEquivClass F R A B] :
- StarHomClass F A B :=
- { hF with }
-
-- See note [lower instance priority]
instance (priority := 100) {F R A B : Type*} [Monoid R] [NonUnitalNonAssocSemiring A]
[DistribMulAction R A] [NonUnitalNonAssocSemiring B] [DistribMulAction R B] [EquivLike F A B]
@@ -688,41 +666,27 @@ instance (priority := 100) {F R A B : Type*} [Monoid R] [NonUnitalNonAssocSemiri
NonUnitalAlgHomClass F R A B :=
{ }
--- See note [lower instance priority]
-instance (priority := 100) {F R A B : Type*} [Monoid R] [NonUnitalNonAssocSemiring A]
- [DistribMulAction R A] [Star A] [NonUnitalNonAssocSemiring B] [DistribMulAction R B] [Star B]
- [EquivLike F A B] [NonUnitalAlgEquivClass F R A B] [StarAlgEquivClass F R A B] :
- NonUnitalStarAlgHomClass F R A B :=
- { }
-
-- See note [lower instance priority]
instance (priority := 100) instAlgHomClass (F R A B : Type*) [CommSemiring R] [Semiring A]
[Algebra R A] [Semiring B] [Algebra R B] [EquivLike F A B] [NonUnitalAlgEquivClass F R A B] :
AlgEquivClass F R A B :=
{ commutes := fun f r => by simp only [Algebra.algebraMap_eq_smul_one, map_smul, map_one] }
--- See note [lower instance priority]
-instance (priority := 100) instStarAlgHomClass (F R A B : Type*) [CommSemiring R] [Semiring A]
- [Algebra R A] [Star A] [Semiring B] [Algebra R B] [Star B] [EquivLike F A B]
- [NonUnitalAlgEquivClass F R A B] [StarAlgEquivClass F R A B] :
- StarAlgHomClass F R A B :=
- { }
-
-/-- Turn an element of a type `F` satisfying `StarAlgEquivClass F R A B` into an actual
-`StarAlgEquiv`. This is declared as the default coercion from `F` to `A ≃⋆ₐ[R] B`. -/
+/-- Turn an element of a type `F` satisfying `AlgEquivClass F R A B` and `StarHomClass F A B` into
+an actual `StarAlgEquiv`. This is declared as the default coercion from `F` to `A ≃⋆ₐ[R] B`. -/
@[coe]
def toStarAlgEquiv {F R A B : Type*} [Add A] [Mul A] [SMul R A] [Star A] [Add B] [Mul B] [SMul R B]
- [Star B] [EquivLike F A B] [NonUnitalAlgEquivClass F R A B] [StarAlgEquivClass F R A B]
+ [Star B] [EquivLike F A B] [NonUnitalAlgEquivClass F R A B] [StarHomClass F A B]
(f : F) : A ≃⋆ₐ[R] B :=
{ (f : A ≃+* B) with
map_star' := map_star f
map_smul' := map_smul f}
-/-- Any type satisfying `StarAlgEquivClass` can be cast into `StarAlgEquiv` via
+/-- Any type satisfying `AlgEquivClass` and `StarHomClass` can be cast into `StarAlgEquiv` via
`StarAlgEquivClass.toStarAlgEquiv`. -/
instance instCoeHead {F R A B : Type*} [Add A] [Mul A] [SMul R A] [Star A] [Add B] [Mul B]
- [SMul R B] [Star B] [EquivLike F A B] [NonUnitalAlgEquivClass F R A B]
- [StarAlgEquivClass F R A B] : CoeHead F (A ≃⋆ₐ[R] B) :=
+ [SMul R B] [Star B] [EquivLike F A B] [NonUnitalAlgEquivClass F R A B] [StarHomClass F A B] :
+ CoeHead F (A ≃⋆ₐ[R] B) :=
⟨toStarAlgEquiv⟩
end StarAlgEquivClass
@@ -749,7 +713,7 @@ instance : NonUnitalAlgEquivClass (A ≃⋆ₐ[R] B) R A B where
map_add f := f.map_add'
map_smulₛₗ := map_smul'
-instance : StarAlgEquivClass (A ≃⋆ₐ[R] B) R A B where
+instance : StarHomClass (A ≃⋆ₐ[R] B) A B where
map_star := map_star'
/-- Helper instance for cases where the inference via `EquivLike` is too hard. -/
@@ -889,8 +853,8 @@ section Bijective
variable {F G R A B : Type*} [Monoid R]
variable [NonUnitalNonAssocSemiring A] [DistribMulAction R A] [Star A]
variable [NonUnitalNonAssocSemiring B] [DistribMulAction R B] [Star B]
-variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [NonUnitalStarAlgHomClass F R A B]
-variable [FunLike G B A] [NonUnitalAlgHomClass G R B A] [NonUnitalStarAlgHomClass G R B A]
+variable [FunLike F A B] [NonUnitalAlgHomClass F R A B] [StarHomClass F A B]
+variable [FunLike G B A] [NonUnitalAlgHomClass G R B A] [StarHomClass G B A]
/-- If a (unital or non-unital) star algebra morphism has an inverse, it is an isomorphism of
star algebras. -/
diff --git a/Mathlib/Algebra/Star/Subalgebra.lean b/Mathlib/Algebra/Star/Subalgebra.lean
index 380f87763c95d..b2c1cc0ea0538 100644
--- a/Mathlib/Algebra/Star/Subalgebra.lean
+++ b/Mathlib/Algebra/Star/Subalgebra.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Jireh Loreaux
+Authors: Kim Morrison, Jireh Loreaux
-/
import Mathlib.Algebra.Star.Center
import Mathlib.Algebra.Star.StarAlgHom
@@ -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)
@@ -594,6 +604,9 @@ theorem mul_mem_sup {S T : StarSubalgebra R A} {x y : A} (hx : x ∈ S) (hy : y
theorem map_sup (f : A →⋆ₐ[R] B) (S T : StarSubalgebra R A) : map f (S ⊔ T) = map f S ⊔ map f T :=
(StarSubalgebra.gc_map_comap f).l_sup
+theorem map_inf (f : A →⋆ₐ[R] B) (hf : Function.Injective f) (S T : StarSubalgebra R A) :
+ map f (S ⊓ T) = map f S ⊓ map f T := SetLike.coe_injective (Set.image_inter hf)
+
@[simp, norm_cast]
theorem coe_inf (S T : StarSubalgebra R A) : (↑(S ⊓ T) : Set A) = (S : Set A) ∩ T :=
rfl
@@ -627,6 +640,11 @@ theorem coe_iInf {ι : Sort*} {S : ι → StarSubalgebra R A} : (↑(⨅ i, S i)
theorem mem_iInf {ι : Sort*} {S : ι → StarSubalgebra R A} {x : A} :
(x ∈ ⨅ i, S i) ↔ ∀ i, x ∈ S i := by simp only [iInf, mem_sInf, Set.forall_mem_range]
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : A →⋆ₐ[R] B) (hf : Function.Injective f)
+ (s : ι → StarSubalgebra R A) : map f (iInf s) = ⨅ (i : ι), map f (s i) := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ s)
+
@[simp]
theorem iInf_toSubalgebra {ι : Sort*} (S : ι → StarSubalgebra R A) :
(⨅ i, S i).toSubalgebra = ⨅ i, (S i).toSubalgebra :=
@@ -657,10 +675,10 @@ section
variable [StarModule R A]
theorem ext_adjoin {s : Set A} [FunLike F (adjoin R s) B]
- [AlgHomClass F R (adjoin R s) B] [StarAlgHomClass F R (adjoin R s) B] {f g : F}
+ [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]
@@ -669,7 +687,7 @@ theorem ext_adjoin {s : Set A} [FunLike F (adjoin R s) B]
· simp only [map_star, hx]
theorem ext_adjoin_singleton {a : A} [FunLike F (adjoin R ({a} : Set A)) B]
- [AlgHomClass F R (adjoin R ({a} : Set A)) B] [StarAlgHomClass F R (adjoin R ({a} : Set A)) B]
+ [AlgHomClass F R (adjoin R ({a} : Set A)) B] [StarHomClass F (adjoin R ({a} : Set A)) B]
{f g : F} (h : f ⟨a, self_mem_adjoin_singleton R a⟩ = g ⟨a, self_mem_adjoin_singleton R a⟩) :
f = g :=
ext_adjoin fun x hx =>
@@ -677,13 +695,12 @@ theorem ext_adjoin_singleton {a : A} [FunLike F (adjoin R ({a} : Set A)) B]
Subtype.ext <| Set.mem_singleton_iff.mp hx).symm ▸
h
-variable [FunLike F A B] [AlgHomClass F R A B] [StarAlgHomClass F R A B] (f g : F)
+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 0e976107f9917..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
@@ -690,7 +706,9 @@ section Inv
variable {R : Type u} {M : Type v}
variable [Neg M] [Inv R] [SMul Rᵐᵒᵖ M] [SMul R M]
-/-- Inversion of the trivial-square-zero extension, sending $r + m$ to $r^{-1} - r^{-1}mr^{-1}$. -/
+/-- Inversion of the trivial-square-zero extension, sending $r + m$ to $r^{-1} - r^{-1}mr^{-1}$.
+
+Strictly this is only a _two_-sided inverse when the left and right actions associate. -/
instance instInv : Inv (tsze R M) :=
⟨fun b => (b.1⁻¹, -(b.1⁻¹ •> b.2 <• b.1⁻¹))⟩
@@ -702,6 +720,75 @@ instance instInv : Inv (tsze R M) :=
end Inv
+/-! This section is heavily inspired by analogous results about matrices. -/
+section Invertible
+variable {R : Type u} {M : Type v}
+variable [AddCommGroup M] [Semiring R] [Module Rᵐᵒᵖ M] [Module R M]
+
+/-- `x.fst : R` is invertible when `x : tzre R M` is. -/
+abbrev invertibleFstOfInvertible (x : tsze R M) [Invertible x] : Invertible x.fst where
+ invOf := (⅟x).fst
+ invOf_mul_self := by rw [← fst_mul, invOf_mul_self, fst_one]
+ mul_invOf_self := by rw [← fst_mul, mul_invOf_self, fst_one]
+
+theorem fst_invOf (x : tsze R M) [Invertible x] [Invertible x.fst] : (⅟x).fst = ⅟(x.fst) := by
+ letI := invertibleFstOfInvertible x
+ convert (rfl : _ = ⅟ x.fst)
+
+theorem mul_left_eq_one (r : R) (x : tsze R M) (h : r * x.fst = 1) :
+ (inl r + inr (-((r •> x.snd) <• r))) * x = 1 := by
+ ext <;> dsimp
+ · rw [add_zero, h]
+ · rw [add_zero, zero_add, smul_neg, op_smul_op_smul, h, op_one, one_smul,
+ add_neg_cancel]
+
+theorem mul_right_eq_one (x : tsze R M) (r : R) (h : x.fst * r = 1) :
+ x * (inl r + inr (-(r •> (x.snd <• r)))) = 1 := by
+ ext <;> dsimp
+ · rw [add_zero, h]
+ · rw [add_zero, zero_add, smul_neg, smul_smul, h, one_smul, neg_add_cancel]
+
+variable [SMulCommClass R Rᵐᵒᵖ M]
+
+/-- `x : tzre R M` is invertible when `x.fst : R` is. -/
+abbrev invertibleOfInvertibleFst (x : tsze R M) [Invertible x.fst] : Invertible x where
+ invOf := (⅟x.fst, -(⅟x.fst •> x.snd <• ⅟x.fst))
+ invOf_mul_self := by
+ convert mul_left_eq_one _ _ (invOf_mul_self x.fst)
+ ext <;> simp
+ mul_invOf_self := by
+ convert mul_right_eq_one _ _ (mul_invOf_self x.fst)
+ ext <;> simp [smul_comm]
+
+theorem snd_invOf (x : tsze R M) [Invertible x] [Invertible x.fst] :
+ (⅟x).snd = -(⅟x.fst •> x.snd <• ⅟x.fst) := by
+ letI := invertibleOfInvertibleFst x
+ convert congr_arg (TrivSqZeroExt.snd (R := R) (M := M)) (_ : _ = ⅟ x)
+ convert rfl
+
+/-- Together `TrivSqZeroExt.detInvertibleOfInvertible` and `TrivSqZeroExt.invertibleOfDetInvertible`
+form an equivalence, although both sides of the equiv are subsingleton anyway. -/
+@[simps]
+def invertibleEquivInvertibleFst (x : tsze R M) : Invertible x ≃ Invertible x.fst where
+ toFun _ := invertibleFstOfInvertible x
+ invFun _ := invertibleOfInvertibleFst x
+ left_inv _ := Subsingleton.elim _ _
+ right_inv _ := Subsingleton.elim _ _
+
+/-- When lowered to a prop, `Matrix.invertibleEquivInvertibleFst` forms an `iff`. -/
+theorem isUnit_iff_isUnit_fst {x : tsze R M} : IsUnit x ↔ IsUnit x.fst := by
+ simp only [← nonempty_invertible_iff_isUnit, (invertibleEquivInvertibleFst x).nonempty_congr]
+
+@[simp]
+theorem isUnit_inl_iff {r : R} : IsUnit (inl r : tsze R M) ↔ IsUnit r := by
+ rw [isUnit_iff_isUnit_fst, fst_inl]
+
+@[simp]
+theorem isUnit_inr_iff {m : M} : IsUnit (inr m : tsze R M) ↔ Subsingleton R := by
+ simp_rw [isUnit_iff_isUnit_fst, fst_inr, isUnit_zero_iff, subsingleton_iff_zero_eq_one]
+
+end Invertible
+
section DivisionSemiring
variable {R : Type u} {M : Type v}
variable [DivisionSemiring R] [AddCommGroup M] [Module Rᵐᵒᵖ M] [Module R M]
@@ -727,18 +814,19 @@ protected theorem inv_one : (1 : tsze R M)⁻¹ = (1 : tsze R M) := by
rw [← inl_one, TrivSqZeroExt.inv_inl, inv_one]
protected theorem inv_mul_cancel {x : tsze R M} (hx : fst x ≠ 0) : x⁻¹ * x = 1 := by
- ext
- · rw [fst_mul, fst_inv, inv_mul_cancel₀ hx, fst_one]
- · rw [snd_mul, snd_inv, snd_one, smul_neg, op_smul_op_smul, inv_mul_cancel₀ hx, op_one, one_smul,
- fst_inv, add_neg_cancel]
+ convert mul_left_eq_one _ _ (_root_.inv_mul_cancel₀ hx) using 2
+ ext <;> simp
variable [SMulCommClass R Rᵐᵒᵖ M]
+@[simp] theorem invOf_eq_inv (x : tsze R M) [Invertible x] : ⅟x = x⁻¹ := by
+ letI := invertibleFstOfInvertible x
+ ext <;> simp [fst_invOf, snd_invOf]
+
protected theorem mul_inv_cancel {x : tsze R M} (hx : fst x ≠ 0) : x * x⁻¹ = 1 := by
- ext
- · rw [fst_mul, fst_inv, fst_one, mul_inv_cancel₀ hx]
- · rw [snd_mul, snd_inv, snd_one, smul_neg, smul_comm, smul_smul, mul_inv_cancel₀ hx, one_smul,
- fst_inv, neg_add_cancel]
+ have : Invertible x.fst := Units.invertible (.mk0 _ hx)
+ have := invertibleOfInvertibleFst x
+ rw [← invOf_eq_inv, mul_invOf_self]
protected theorem mul_inv_rev (a b : tsze R M) :
(a * b)⁻¹ = b⁻¹ * a⁻¹ := by
@@ -763,6 +851,10 @@ protected theorem inv_inv {x : tsze R M} (hx : fst x ≠ 0) : x⁻¹⁻¹ = x :=
rw [fst_inv]
apply inv_ne_zero hx
+@[simp]
+theorem isUnit_inv_iff {x : tsze R M} : IsUnit x⁻¹ ↔ IsUnit x := by
+ simp_rw [isUnit_iff_isUnit_fst, fst_inv, isUnit_iff_ne_zero, ne_eq, inv_eq_zero]
+
end DivisionSemiring
section DivisionRing
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 8945030d7edd1..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
@@ -52,24 +53,26 @@ deriving Category
/-- A Scheme is affine if the canonical map `X ⟶ Spec Γ(X)` is an isomorphism. -/
class IsAffine (X : Scheme) : Prop where
- affine : IsIso (ΓSpec.adjunction.unit.app X)
+ affine : IsIso X.toSpecΓ
attribute [instance] IsAffine.affine
+instance (X : Scheme.{u}) [IsAffine X] : IsIso (ΓSpec.adjunction.unit.app X) := @IsAffine.affine X _
+
/-- The canonical isomorphism `X ≅ Spec Γ(X)` for an affine scheme. -/
@[simps! (config := .lemmasOnly) hom]
def Scheme.isoSpec (X : Scheme) [IsAffine X] : X ≅ Spec Γ(X, ⊤) :=
- asIso (ΓSpec.adjunction.unit.app X)
+ asIso X.toSpecΓ
@[reassoc]
theorem Scheme.isoSpec_hom_naturality {X Y : Scheme} [IsAffine X] [IsAffine Y] (f : X ⟶ Y) :
X.isoSpec.hom ≫ Spec.map (f.app ⊤) = f ≫ Y.isoSpec.hom := by
- simp only [isoSpec, asIso_hom, ΓSpec.adjunction_unit_naturality]
+ simp only [isoSpec, asIso_hom, Scheme.toSpecΓ_naturality]
@[reassoc]
theorem Scheme.isoSpec_inv_naturality {X Y : Scheme} [IsAffine X] [IsAffine Y] (f : X ⟶ Y) :
Spec.map (f.app ⊤) ≫ Y.isoSpec.inv = X.isoSpec.inv ≫ f := by
- rw [Iso.eq_inv_comp, isoSpec, asIso_hom, ← ΓSpec.adjunction_unit_naturality_assoc, isoSpec,
+ rw [Iso.eq_inv_comp, isoSpec, asIso_hom, ← Scheme.toSpecΓ_naturality_assoc, isoSpec,
asIso_inv, IsIso.hom_inv_id, Category.comp_id]
/-- Construct an affine scheme from a scheme and the information that it is affine.
@@ -111,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. -/
@@ -226,68 +248,141 @@ 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 :=
- ΓSpec.adjunction_unit_map_basicOpen _ _
+ 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
· rintro ⟨_, ⟨x, rfl⟩, rfl⟩
refine ⟨_, ⟨_, ⟨x, rfl⟩, rfl⟩, ?_⟩
- exact congr_arg Opens.carrier (ΓSpec.adjunction_unit_map_basicOpen _ _)
+ exact congr_arg Opens.carrier (Scheme.toSpecΓ_preimage_basicOpen _ _)
· rintro ⟨_, ⟨_, ⟨x, rfl⟩, rfl⟩, rfl⟩
refine ⟨_, ⟨x, rfl⟩, ?_⟩
- exact congr_arg Opens.carrier (ΓSpec.adjunction_unit_map_basicOpen _ _).symm
+ 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
@@ -309,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
@@ -352,23 +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, Functor.id_obj, Functor.comp_obj,
- Functor.rightOp_obj, Scheme.Γ_obj, unop_op, Scheme.Spec_obj, Scheme.Opens.topIso_hom,
- Scheme.comp_app, Scheme.Opens.ι_app_self, 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
@@ -383,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 _ _
@@ -408,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 _
@@ -421,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⟩
@@ -435,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 :
@@ -490,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)) :
@@ -523,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`.
@@ -555,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
@@ -564,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
@@ -584,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
@@ -619,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.
@@ -683,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, ⊤)) :
- (ΓSpec.adjunction.unit.app X).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
@@ -692,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. -/
@@ -706,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 8e25ace403b09..5a23dde317010 100644
--- a/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean
+++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean
@@ -5,6 +5,7 @@ Authors: David Kurniadi Angdinata
-/
import Mathlib.Algebra.Polynomial.Bivariate
import Mathlib.AlgebraicGeometry.EllipticCurve.Weierstrass
+import Mathlib.AlgebraicGeometry.EllipticCurve.VariableChange
/-!
# Affine coordinates for Weierstrass curves
@@ -163,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]
@@ -182,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]
@@ -209,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]
@@ -225,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]
@@ -255,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)]
@@ -313,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
@@ -608,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
@@ -624,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
@@ -655,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
@@ -816,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 cbb5edf60ed85..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
@@ -545,7 +538,7 @@ lemma toClass_eq_zero (P : W.Point) : toClass P = 0 ↔ P = 0 := by
rw [← finrank_quotient_span_eq_natDegree_norm (CoordinateRing.basis W) h0,
← (quotientEquivAlgOfEq F hp).toLinearEquiv.finrank_eq,
(CoordinateRing.quotientXYIdealEquiv W h).toLinearEquiv.finrank_eq,
- FiniteDimensional.finrank_self]
+ Module.finrank_self]
· exact congr_arg toClass
lemma toClass_injective : Function.Injective <| @toClass _ _ W := by
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 b3f2eea5ac125..e4838de2f5dd0 100644
--- a/Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean
+++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean
@@ -7,6 +7,7 @@ import Mathlib.Algebra.MvPolynomial.CommRing
import Mathlib.Algebra.MvPolynomial.PDeriv
import Mathlib.AlgebraicGeometry.EllipticCurve.Affine
import Mathlib.Data.Fin.Tuple.Reflection
+import Mathlib.Tactic.LinearCombination'
/-!
# Jacobian coordinates for Weierstrass curves
@@ -498,7 +499,7 @@ lemma negY_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) :
lemma Y_sub_Y_mul_Y_sub_negY {P Q : Fin 3 → R} (hP : W'.Equation P) (hQ : W'.Equation Q)
(hx : P x * Q z ^ 2 = Q x * P z ^ 2) :
(P y * Q z ^ 3 - Q y * P z ^ 3) * (P y * Q z ^ 3 - W'.negY Q * P z ^ 3) = 0 := by
- linear_combination (norm := (rw [negY]; ring1)) Q z ^ 6 * (equation_iff P).mp hP
+ linear_combination' (norm := (rw [negY]; ring1)) Q z ^ 6 * (equation_iff P).mp hP
- P z ^ 6 * (equation_iff Q).mp hQ + hx * hx * hx + W'.a₂ * P z ^ 2 * Q z ^ 2 * hx * hx
+ (W'.a₄ * P z ^ 4 * Q z ^ 4 - W'.a₁ * P y * P z * Q z ^ 4) * hx
@@ -678,7 +679,7 @@ lemma negDblY_smul (P : Fin 3 → R) (u : R) : W'.negDblY (u • P) = (u ^ 4) ^
lemma negDblY_of_Z_eq_zero {P : Fin 3 → R} (hP : W'.Equation P) (hPz : P z = 0) :
W'.negDblY P = -(P x ^ 2) ^ 3 := by
- linear_combination (norm :=
+ linear_combination' (norm :=
(rw [negDblY, dblU_of_Z_eq_zero hPz, dblX_of_Z_eq_zero hP hPz, negY_of_Z_eq_zero hPz]; ring1))
(8 * (equation_of_Z_eq_zero hPz).mp hP - 12 * P x ^ 3) * (equation_of_Z_eq_zero hPz).mp hP
@@ -1168,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]
@@ -1184,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
new file mode 100644
index 0000000000000..23a9a69744985
--- /dev/null
+++ b/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean
@@ -0,0 +1,758 @@
+/-
+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.VariableChange
+import Mathlib.Algebra.CharP.Defs
+
+/-!
+
+# Some normal forms of elliptic curves
+
+This file defines some normal forms of Weierstrass equations of elliptic curves.
+
+## Main definitions and results
+
+The following normal forms are in [silverman2009], section III.1, page 42.
+
+- `WeierstrassCurve.IsCharNeTwoNF` is a type class which asserts that a `WeierstrassCurve` is
+ of form $Y^2 = X^3 + a_2X^2 + a_4X + a_6$. It is the normal form of characteristic ≠ 2.
+
+ If 2 is invertible in the ring (for example, if it is a field of characteristic ≠ 2),
+ then for any `WeierstrassCurve` there exists a change of variables which will change
+ it into such normal form (`WeierstrassCurve.exists_variableChange_isCharNeTwoNF`).
+ See also `WeierstrassCurve.toCharNeTwoNF` and `WeierstrassCurve.toCharNeTwoNF_spec`.
+
+The following normal forms are in [silverman2009], Appendix A, Proposition 1.1.
+
+- `WeierstrassCurve.IsShortNF` is a type class which asserts that a `WeierstrassCurve` is
+ of form $Y^2 = X^3 + a_4X + a_6$. It is the normal form of characteristic ≠ 2 or 3, and
+ also the normal form of characteristic = 3 and j = 0.
+
+ If 2 and 3 are invertible in the ring (for example, if it is a field of characteristic ≠ 2 or 3),
+ then for any `WeierstrassCurve` there exists a change of variables which will change
+ it into such normal form (`WeierstrassCurve.exists_variableChange_isShortNF`).
+ See also `WeierstrassCurve.toShortNF` and `WeierstrassCurve.toShortNF_spec`.
+
+ If the ring is of characteristic = 3, then for any `WeierstrassCurve` with $b_2 = 0$ (for an
+ elliptic curve, this is equivalent to j = 0), there exists a change of variables which will
+ change it into such normal form (see `WeierstrassCurve.toShortNFOfCharThree`
+ and `WeierstrassCurve.toShortNFOfCharThree_spec`).
+
+- `WeierstrassCurve.IsCharThreeJNeZeroNF` is a type class which asserts that a `WeierstrassCurve` is
+ of form $Y^2 = X^3 + a_2X^2 + a_6$. It is the normal form of characteristic = 3 and j ≠ 0.
+
+ If the field is of characteristic = 3, then for any `WeierstrassCurve` with $b_2 \neq 0$ (for an
+ elliptic curve, this is equivalent to j ≠ 0), there exists a change of variables which will
+ change it into such normal form (see `WeierstrassCurve.toCharThreeNF`
+ and `WeierstrassCurve.toCharThreeNF_spec_of_b₂_ne_zero`).
+
+- `WeierstrassCurve.IsCharThreeNF` is the combination of the above two, that is, asserts that
+ a `WeierstrassCurve` is of form $Y^2 = X^3 + a_2X^2 + a_6$ or $Y^2 = X^3 + a_4X + a_6$.
+ It is the normal form of characteristic = 3.
+
+ If the field is of characteristic = 3, then for any `WeierstrassCurve` there exists a change of
+ variables which will change it into such normal form
+ (`WeierstrassCurve.exists_variableChange_isCharThreeNF`).
+ See also `WeierstrassCurve.toCharThreeNF` and `WeierstrassCurve.toCharThreeNF_spec`.
+
+- `WeierstrassCurve.IsCharTwoJEqZeroNF` is a type class which asserts that a `WeierstrassCurve` is
+ of form $Y^2 + a_3Y = X^3 + a_4X + a_6$. It is the normal form of characteristic = 2 and j = 0.
+
+ If the ring is of characteristic = 2, then for any `WeierstrassCurve` with $a_1 = 0$ (for an
+ elliptic curve, this is equivalent to j = 0), there exists a change of variables which will
+ change it into such normal form (see `WeierstrassCurve.toCharTwoJEqZeroNF`
+ and `WeierstrassCurve.toCharTwoJEqZeroNF_spec`).
+
+- `WeierstrassCurve.IsCharTwoJNeZeroNF` is a type class which asserts that a `WeierstrassCurve` is
+ of form $Y^2 + XY = X^3 + a_2X^2 + a_6$. It is the normal form of characteristic = 2 and j ≠ 0.
+
+ If the field is of characteristic = 2, then for any `WeierstrassCurve` with $a_1 \neq 0$ (for an
+ elliptic curve, this is equivalent to j ≠ 0), there exists a change of variables which will
+ change it into such normal form (see `WeierstrassCurve.toCharTwoJNeZeroNF`
+ and `WeierstrassCurve.toCharTwoJNeZeroNF_spec`).
+
+- `WeierstrassCurve.IsCharTwoNF` is the combination of the above two, that is, asserts that
+ a `WeierstrassCurve` is of form $Y^2 + XY = X^3 + a_2X^2 + a_6$ or
+ $Y^2 + a_3Y = X^3 + a_4X + a_6$. It is the normal form of characteristic = 2.
+
+ If the field is of characteristic = 2, then for any `WeierstrassCurve` there exists a change of
+ variables which will change it into such normal form
+ (`WeierstrassCurve.exists_variableChange_isCharTwoNF`).
+ See also `WeierstrassCurve.toCharTwoNF` and `WeierstrassCurve.toCharTwoNF_spec`.
+
+## References
+
+* [J Silverman, *The Arithmetic of Elliptic Curves*][silverman2009]
+
+## Tags
+
+elliptic curve, weierstrass equation, normal form
+
+-/
+
+variable {R : Type*} [CommRing R] (W : WeierstrassCurve R)
+variable {F : Type*} [Field F] (E : EllipticCurve F)
+
+namespace WeierstrassCurve
+
+/-! ### Normal forms of characteristic ≠ 2 -/
+
+/-- A `WeierstrassCurve` is in normal form of characteristic ≠ 2, if its $a_1, a_3 = 0$.
+In other words it is $Y^2 = X^3 + a_2X^2 + a_4X + a_6$. -/
+@[mk_iff]
+class IsCharNeTwoNF : Prop where
+ a₁ : W.a₁ = 0
+ a₃ : W.a₃ = 0
+
+section Quantity
+
+variable [W.IsCharNeTwoNF]
+
+@[simp]
+theorem a₁_of_isCharNeTwoNF : W.a₁ = 0 := IsCharNeTwoNF.a₁
+
+@[simp]
+theorem a₃_of_isCharNeTwoNF : W.a₃ = 0 := IsCharNeTwoNF.a₃
+
+@[simp]
+theorem b₂_of_isCharNeTwoNF : W.b₂ = 4 * W.a₂ := by
+ rw [b₂, a₁_of_isCharNeTwoNF]
+ ring1
+
+@[simp]
+theorem b₄_of_isCharNeTwoNF : W.b₄ = 2 * W.a₄ := by
+ rw [b₄, a₃_of_isCharNeTwoNF]
+ ring1
+
+@[simp]
+theorem b₆_of_isCharNeTwoNF : W.b₆ = 4 * W.a₆ := by
+ rw [b₆, a₃_of_isCharNeTwoNF]
+ ring1
+
+@[simp]
+theorem b₈_of_isCharNeTwoNF : W.b₈ = 4 * W.a₂ * W.a₆ - W.a₄ ^ 2 := by
+ rw [b₈, a₁_of_isCharNeTwoNF, a₃_of_isCharNeTwoNF]
+ ring1
+
+@[simp]
+theorem c₄_of_isCharNeTwoNF : W.c₄ = 16 * W.a₂ ^ 2 - 48 * W.a₄ := by
+ rw [c₄, b₂_of_isCharNeTwoNF, b₄_of_isCharNeTwoNF]
+ ring1
+
+@[simp]
+theorem c₆_of_isCharNeTwoNF : W.c₆ = -64 * W.a₂ ^ 3 + 288 * W.a₂ * W.a₄ - 864 * W.a₆ := by
+ rw [c₆, b₂_of_isCharNeTwoNF, b₄_of_isCharNeTwoNF, b₆_of_isCharNeTwoNF]
+ ring1
+
+@[simp]
+theorem Δ_of_isCharNeTwoNF : W.Δ = -64 * W.a₂ ^ 3 * W.a₆ + 16 * W.a₂ ^ 2 * W.a₄ ^ 2 - 64 * W.a₄ ^ 3
+ - 432 * W.a₆ ^ 2 + 288 * W.a₂ * W.a₄ * W.a₆ := by
+ rw [Δ, b₂_of_isCharNeTwoNF, b₄_of_isCharNeTwoNF, b₆_of_isCharNeTwoNF, b₈_of_isCharNeTwoNF]
+ ring1
+
+end Quantity
+
+section VariableChange
+
+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. -/
+@[simps]
+def toCharNeTwoNF : VariableChange R := ⟨1, 0, ⅟2 * -W.a₁, ⅟2 * -W.a₃⟩
+
+instance toCharNeTwoNF_spec : (W.variableChange W.toCharNeTwoNF).IsCharNeTwoNF := by
+ constructor <;> simp
+
+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 -/
+
+/-- A `WeierstrassCurve` is in short normal form, if its $a_1, a_2, a_3 = 0$.
+In other words it is $Y^2 = X^3 + a_4X + a_6$.
+
+This is the normal form of characteristic ≠ 2 or 3, and
+also the normal form of characteristic = 3 and j = 0. -/
+@[mk_iff]
+class IsShortNF : Prop where
+ a₁ : W.a₁ = 0
+ a₂ : W.a₂ = 0
+ a₃ : W.a₃ = 0
+
+section Quantity
+
+variable [W.IsShortNF]
+
+instance isCharNeTwoNF_of_isShortNF : W.IsCharNeTwoNF := ⟨IsShortNF.a₁, IsShortNF.a₃⟩
+
+theorem a₁_of_isShortNF : W.a₁ = 0 := IsShortNF.a₁
+
+@[simp]
+theorem a₂_of_isShortNF : W.a₂ = 0 := IsShortNF.a₂
+
+theorem a₃_of_isShortNF : W.a₃ = 0 := IsShortNF.a₃
+
+theorem b₂_of_isShortNF : W.b₂ = 0 := by
+ simp
+
+theorem b₄_of_isShortNF : W.b₄ = 2 * W.a₄ := W.b₄_of_isCharNeTwoNF
+
+theorem b₆_of_isShortNF : W.b₆ = 4 * W.a₆ := W.b₆_of_isCharNeTwoNF
+
+theorem b₈_of_isShortNF : W.b₈ = -W.a₄ ^ 2 := by
+ simp
+
+theorem c₄_of_isShortNF : W.c₄ = -48 * W.a₄ := by
+ simp
+
+theorem c₆_of_isShortNF : W.c₆ = -864 * W.a₆ := by
+ simp
+
+theorem Δ_of_isShortNF : W.Δ = -16 * (4 * W.a₄ ^ 3 + 27 * W.a₆ ^ 2) := by
+ rw [Δ_of_isCharNeTwoNF, a₂_of_isShortNF]
+ ring1
+
+variable [CharP R 3]
+
+theorem b₄_of_isShortNF_of_char_three : W.b₄ = -W.a₄ := by
+ rw [b₄_of_isShortNF]
+ linear_combination W.a₄ * CharP.cast_eq_zero R 3
+
+theorem b₆_of_isShortNF_of_char_three : W.b₆ = W.a₆ := by
+ rw [b₆_of_isShortNF]
+ linear_combination W.a₆ * CharP.cast_eq_zero R 3
+
+theorem c₄_of_isShortNF_of_char_three : W.c₄ = 0 := by
+ rw [c₄_of_isShortNF]
+ linear_combination -16 * W.a₄ * CharP.cast_eq_zero R 3
+
+theorem c₆_of_isShortNF_of_char_three : W.c₆ = 0 := by
+ rw [c₆_of_isShortNF]
+ linear_combination -288 * W.a₆ * CharP.cast_eq_zero R 3
+
+theorem Δ_of_isShortNF_of_char_three : W.Δ = -W.a₄ ^ 3 := by
+ rw [Δ_of_isShortNF]
+ linear_combination (-21 * W.a₄ ^ 3 - 144 * W.a₆ ^ 2) * CharP.cast_eq_zero R 3
+
+variable [E.IsShortNF]
+
+theorem _root_.EllipticCurve.j_of_isShortNF :
+ E.j = 6912 * E.a₄ ^ 3 / (4 * E.a₄ ^ 3 + 27 * E.a₆ ^ 2) := by
+ have h := E.Δ'.ne_zero
+ rw [E.coe_Δ', Δ_of_isShortNF] at h
+ rw [EllipticCurve.j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, E.coe_Δ',
+ c₄_of_isShortNF, Δ_of_isShortNF, div_eq_div_iff h (right_ne_zero_of_mul h)]
+ ring1
+
+@[simp]
+theorem _root_.EllipticCurve.j_of_isShortNF_of_char_three [CharP F 3] : E.j = 0 := by
+ rw [EllipticCurve.j, c₄_of_isShortNF_of_char_three]; simp
+
+end Quantity
+
+section VariableChange
+
+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.
+It is the composition of an explicit change of variables with `WeierstrassCurve.toCharNeTwoNF`. -/
+def toShortNF : VariableChange R :=
+ .comp ⟨1, ⅟3 * -(W.variableChange W.toCharNeTwoNF).a₂, 0, 0⟩ W.toCharNeTwoNF
+
+instance toShortNF_spec : (W.variableChange W.toShortNF).IsShortNF := by
+ rw [toShortNF, variableChange_comp]
+ constructor <;> simp
+
+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 -/
+
+/-- A `WeierstrassCurve` is in normal form of characteristic = 3 and j ≠ 0, if its
+$a_1, a_3, a_4 = 0$. In other words it is $Y^2 = X^3 + a_2X^2 + a_6$. -/
+@[mk_iff]
+class IsCharThreeJNeZeroNF : Prop where
+ a₁ : W.a₁ = 0
+ a₃ : W.a₃ = 0
+ a₄ : W.a₄ = 0
+
+section Quantity
+
+variable [W.IsCharThreeJNeZeroNF]
+
+instance isCharNeTwoNF_of_isCharThreeJNeZeroNF : W.IsCharNeTwoNF :=
+ ⟨IsCharThreeJNeZeroNF.a₁, IsCharThreeJNeZeroNF.a₃⟩
+
+theorem a₁_of_isCharThreeJNeZeroNF : W.a₁ = 0 := IsCharThreeJNeZeroNF.a₁
+
+theorem a₃_of_isCharThreeJNeZeroNF : W.a₃ = 0 := IsCharThreeJNeZeroNF.a₃
+
+@[simp]
+theorem a₄_of_isCharThreeJNeZeroNF : W.a₄ = 0 := IsCharThreeJNeZeroNF.a₄
+
+theorem b₂_of_isCharThreeJNeZeroNF : W.b₂ = 4 * W.a₂ := W.b₂_of_isCharNeTwoNF
+
+theorem b₄_of_isCharThreeJNeZeroNF : W.b₄ = 0 := by
+ simp
+
+theorem b₆_of_isCharThreeJNeZeroNF : W.b₆ = 4 * W.a₆ := W.b₆_of_isCharNeTwoNF
+
+theorem b₈_of_isCharThreeJNeZeroNF : W.b₈ = 4 * W.a₂ * W.a₆ := by
+ simp
+
+theorem c₄_of_isCharThreeJNeZeroNF : W.c₄ = 16 * W.a₂ ^ 2 := by
+ simp
+
+theorem c₆_of_isCharThreeJNeZeroNF : W.c₆ = -64 * W.a₂ ^ 3 - 864 * W.a₆ := by
+ simp
+
+theorem Δ_of_isCharThreeJNeZeroNF : W.Δ = -64 * W.a₂ ^ 3 * W.a₆ - 432 * W.a₆ ^ 2 := by
+ simp
+
+variable [CharP R 3]
+
+theorem b₂_of_isCharThreeJNeZeroNF_of_char_three : W.b₂ = W.a₂ := by
+ rw [b₂_of_isCharThreeJNeZeroNF]
+ linear_combination W.a₂ * CharP.cast_eq_zero R 3
+
+theorem b₆_of_isCharThreeJNeZeroNF_of_char_three : W.b₆ = W.a₆ := by
+ rw [b₆_of_isCharThreeJNeZeroNF]
+ linear_combination W.a₆ * CharP.cast_eq_zero R 3
+
+theorem b₈_of_isCharThreeJNeZeroNF_of_char_three : W.b₈ = W.a₂ * W.a₆ := by
+ rw [b₈_of_isCharThreeJNeZeroNF]
+ linear_combination W.a₂ * W.a₆ * CharP.cast_eq_zero R 3
+
+theorem c₄_of_isCharThreeJNeZeroNF_of_char_three : W.c₄ = W.a₂ ^ 2 := by
+ rw [c₄_of_isCharThreeJNeZeroNF]
+ linear_combination 5 * W.a₂ ^ 2 * CharP.cast_eq_zero R 3
+
+theorem c₆_of_isCharThreeJNeZeroNF_of_char_three : W.c₆ = -W.a₂ ^ 3 := by
+ rw [c₆_of_isCharThreeJNeZeroNF]
+ linear_combination (-21 * W.a₂ ^ 3 - 288 * W.a₆) * CharP.cast_eq_zero R 3
+
+theorem Δ_of_isCharThreeJNeZeroNF_of_char_three : W.Δ = -W.a₂ ^ 3 * W.a₆ := by
+ rw [Δ_of_isCharThreeJNeZeroNF]
+ linear_combination (-21 * W.a₂ ^ 3 * W.a₆ - 144 * W.a₆ ^ 2) * CharP.cast_eq_zero R 3
+
+variable [E.IsCharThreeJNeZeroNF] [CharP F 3]
+
+@[simp]
+theorem _root_.EllipticCurve.j_of_isCharThreeJNeZeroNF_of_char_three : E.j = -E.a₂ ^ 3 / E.a₆ := by
+ have h := E.Δ'.ne_zero
+ rw [E.coe_Δ', Δ_of_isCharThreeJNeZeroNF_of_char_three] at h
+ rw [EllipticCurve.j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, E.coe_Δ',
+ c₄_of_isCharThreeJNeZeroNF_of_char_three, Δ_of_isCharThreeJNeZeroNF_of_char_three,
+ div_eq_div_iff h (right_ne_zero_of_mul h)]
+ ring1
+
+theorem _root_.EllipticCurve.j_ne_zero_of_isCharThreeJNeZeroNF_of_char_three : E.j ≠ 0 := by
+ rw [E.j_of_isCharThreeJNeZeroNF_of_char_three, div_ne_zero_iff]
+ have h := E.Δ'.ne_zero
+ rwa [E.coe_Δ', Δ_of_isCharThreeJNeZeroNF_of_char_three, mul_ne_zero_iff] at h
+
+end Quantity
+
+/-! ### Normal forms of characteristic = 3 -/
+
+/-- A `WeierstrassCurve` is in normal form of characteristic = 3, if it is
+$Y^2 = X^3 + a_2X^2 + a_6$ (`WeierstrassCurve.IsCharThreeJNeZeroNF`) or
+$Y^2 = X^3 + a_4X + a_6$ (`WeierstrassCurve.IsShortNF`). -/
+class inductive IsCharThreeNF : Prop
+| of_j_ne_zero [W.IsCharThreeJNeZeroNF] : IsCharThreeNF
+| of_j_eq_zero [W.IsShortNF] : IsCharThreeNF
+
+instance isCharThreeNF_of_isCharThreeJNeZeroNF [W.IsCharThreeJNeZeroNF] : W.IsCharThreeNF :=
+ IsCharThreeNF.of_j_ne_zero
+
+instance isCharThreeNF_of_isShortNF [W.IsShortNF] : W.IsCharThreeNF :=
+ IsCharThreeNF.of_j_eq_zero
+
+instance isCharNeTwoNF_of_isCharThreeNF [W.IsCharThreeNF] : W.IsCharNeTwoNF := by
+ cases ‹W.IsCharThreeNF› <;> infer_instance
+
+section VariableChange
+
+variable [CharP R 3] [CharP F 3]
+
+/-- For a `WeierstrassCurve` defined over a ring of characteristic = 3,
+there is an explicit change of variables of it to $Y^2 = X^3 + a_4X + a_6$
+(`WeierstrassCurve.IsShortNF`) if its j = 0.
+This is in fact given by `WeierstrassCurve.toCharNeTwoNF`. -/
+def toShortNFOfCharThree : VariableChange R :=
+ have h : (2 : R) * 2 = 1 := by linear_combination CharP.cast_eq_zero R 3
+ letI : Invertible (2 : R) := ⟨2, h, h⟩
+ W.toCharNeTwoNF
+
+lemma toShortNFOfCharThree_a₂ : (W.variableChange W.toShortNFOfCharThree).a₂ = W.b₂ := by
+ simp_rw [toShortNFOfCharThree, toCharNeTwoNF, variableChange_a₂, inv_one, Units.val_one, b₂]
+ linear_combination (-W.a₂ - W.a₁ ^ 2) * CharP.cast_eq_zero R 3
+
+theorem toShortNFOfCharThree_spec (hb₂ : W.b₂ = 0) :
+ (W.variableChange W.toShortNFOfCharThree).IsShortNF := by
+ have h : (2 : R) * 2 = 1 := by linear_combination CharP.cast_eq_zero R 3
+ letI : Invertible (2 : R) := ⟨2, h, h⟩
+ 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,
+there is an explicit change of variables of it to `WeierstrassCurve.IsCharThreeNF`, that is,
+$Y^2 = X^3 + a_2X^2 + a_6$ (`WeierstrassCurve.IsCharThreeJNeZeroNF`) or
+$Y^2 = X^3 + a_4X + a_6$ (`WeierstrassCurve.IsShortNF`).
+It is the composition of an explicit change of variables with
+`WeierstrassCurve.toShortNFOfCharThree`. -/
+def toCharThreeNF : VariableChange F :=
+ .comp ⟨1, (W.variableChange W.toShortNFOfCharThree).a₄ /
+ (W.variableChange W.toShortNFOfCharThree).a₂, 0, 0⟩ W.toShortNFOfCharThree
+
+theorem toCharThreeNF_spec_of_b₂_ne_zero (hb₂ : W.b₂ ≠ 0) :
+ (W.variableChange W.toCharThreeNF).IsCharThreeJNeZeroNF := by
+ have h : (2 : F) * 2 = 1 := by linear_combination CharP.cast_eq_zero F 3
+ letI : Invertible (2 : F) := ⟨2, h, h⟩
+ rw [toCharThreeNF, variableChange_comp]
+ set W' := W.variableChange W.toShortNFOfCharThree
+ haveI : W'.IsCharNeTwoNF := W.toCharNeTwoNF_spec
+ constructor
+ · simp
+ · simp
+ · field_simp [W.toShortNFOfCharThree_a₂ ▸ hb₂]
+ linear_combination (W'.a₄ * W'.a₂ ^ 2 + W'.a₄ ^ 2) * CharP.cast_eq_zero F 3
+
+theorem toCharThreeNF_spec_of_b₂_eq_zero (hb₂ : W.b₂ = 0) :
+ (W.variableChange W.toCharThreeNF).IsShortNF := by
+ rw [toCharThreeNF, toShortNFOfCharThree_a₂, hb₂, div_zero, ← VariableChange.id,
+ 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₂
+ infer_instance
+ · haveI := W.toCharThreeNF_spec_of_b₂_ne_zero hb₂
+ infer_instance
+
+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 -/
+
+/-- A `WeierstrassCurve` is in normal form of characteristic = 2 and j ≠ 0, if its $a_1 = 1$ and
+$a_3, a_4 = 0$. In other words it is $Y^2 + XY = X^3 + a_2X^2 + a_6$. -/
+@[mk_iff]
+class IsCharTwoJNeZeroNF : Prop where
+ a₁ : W.a₁ = 1
+ a₃ : W.a₃ = 0
+ a₄ : W.a₄ = 0
+
+section Quantity
+
+variable [W.IsCharTwoJNeZeroNF]
+
+@[simp]
+theorem a₁_of_isCharTwoJNeZeroNF : W.a₁ = 1 := IsCharTwoJNeZeroNF.a₁
+
+@[simp]
+theorem a₃_of_isCharTwoJNeZeroNF : W.a₃ = 0 := IsCharTwoJNeZeroNF.a₃
+
+@[simp]
+theorem a₄_of_isCharTwoJNeZeroNF : W.a₄ = 0 := IsCharTwoJNeZeroNF.a₄
+
+@[simp]
+theorem b₂_of_isCharTwoJNeZeroNF : W.b₂ = 1 + 4 * W.a₂ := by
+ rw [b₂, a₁_of_isCharTwoJNeZeroNF]
+ ring1
+
+@[simp]
+theorem b₄_of_isCharTwoJNeZeroNF : W.b₄ = 0 := by
+ rw [b₄, a₃_of_isCharTwoJNeZeroNF, a₄_of_isCharTwoJNeZeroNF]
+ ring1
+
+@[simp]
+theorem b₆_of_isCharTwoJNeZeroNF : W.b₆ = 4 * W.a₆ := by
+ rw [b₆, a₃_of_isCharTwoJNeZeroNF]
+ ring1
+
+@[simp]
+theorem b₈_of_isCharTwoJNeZeroNF : W.b₈ = W.a₆ + 4 * W.a₂ * W.a₆ := by
+ rw [b₈, a₁_of_isCharTwoJNeZeroNF, a₃_of_isCharTwoJNeZeroNF, a₄_of_isCharTwoJNeZeroNF]
+ ring1
+
+@[simp]
+theorem c₄_of_isCharTwoJNeZeroNF : W.c₄ = W.b₂ ^ 2 := by
+ rw [c₄, b₄_of_isCharTwoJNeZeroNF]
+ ring1
+
+@[simp]
+theorem c₆_of_isCharTwoJNeZeroNF : W.c₆ = -W.b₂ ^ 3 - 864 * W.a₆ := by
+ rw [c₆, b₄_of_isCharTwoJNeZeroNF, b₆_of_isCharTwoJNeZeroNF]
+ ring1
+
+variable [CharP R 2]
+
+theorem b₂_of_isCharTwoJNeZeroNF_of_char_two : W.b₂ = 1 := by
+ rw [b₂_of_isCharTwoJNeZeroNF]
+ linear_combination 2 * W.a₂ * CharP.cast_eq_zero R 2
+
+theorem b₆_of_isCharTwoJNeZeroNF_of_char_two : W.b₆ = 0 := by
+ rw [b₆_of_isCharTwoJNeZeroNF]
+ linear_combination 2 * W.a₆ * CharP.cast_eq_zero R 2
+
+theorem b₈_of_isCharTwoJNeZeroNF_of_char_two : W.b₈ = W.a₆ := by
+ rw [b₈_of_isCharTwoJNeZeroNF]
+ linear_combination 2 * W.a₂ * W.a₆ * CharP.cast_eq_zero R 2
+
+theorem c₄_of_isCharTwoJNeZeroNF_of_char_two : W.c₄ = 1 := by
+ rw [c₄_of_isCharTwoJNeZeroNF, b₂_of_isCharTwoJNeZeroNF_of_char_two]
+ ring1
+
+theorem c₆_of_isCharTwoJNeZeroNF_of_char_two : W.c₆ = 1 := by
+ rw [c₆_of_isCharTwoJNeZeroNF, b₂_of_isCharTwoJNeZeroNF_of_char_two]
+ linear_combination (-1 - 432 * W.a₆) * CharP.cast_eq_zero R 2
+
+@[simp]
+theorem Δ_of_isCharTwoJNeZeroNF_of_char_two : W.Δ = W.a₆ := by
+ rw [Δ, b₂_of_isCharTwoJNeZeroNF_of_char_two, b₄_of_isCharTwoJNeZeroNF,
+ b₆_of_isCharTwoJNeZeroNF_of_char_two, b₈_of_isCharTwoJNeZeroNF_of_char_two]
+ linear_combination -W.a₆ * CharP.cast_eq_zero R 2
+
+variable [E.IsCharTwoJNeZeroNF] [CharP F 2]
+
+@[simp]
+theorem _root_.EllipticCurve.j_of_isCharTwoJNeZeroNF_of_char_two : E.j = 1 / E.a₆ := by
+ rw [EllipticCurve.j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, E.coe_Δ',
+ c₄_of_isCharTwoJNeZeroNF_of_char_two, Δ_of_isCharTwoJNeZeroNF_of_char_two, one_pow]
+
+theorem _root_.EllipticCurve.j_ne_zero_of_isCharTwoJNeZeroNF_of_char_two : E.j ≠ 0 := by
+ rw [E.j_of_isCharTwoJNeZeroNF_of_char_two, div_ne_zero_iff]
+ have h := E.Δ'.ne_zero
+ rw [E.coe_Δ', Δ_of_isCharTwoJNeZeroNF_of_char_two] at h
+ exact ⟨one_ne_zero, h⟩
+
+end Quantity
+
+/-! ### Normal forms of characteristic = 2 and j = 0 -/
+
+/-- A `WeierstrassCurve` is in normal form of characteristic = 2 and j = 0, if its $a_1, a_2 = 0$.
+In other words it is $Y^2 + a_3Y = X^3 + a_4X + a_6$. -/
+@[mk_iff]
+class IsCharTwoJEqZeroNF : Prop where
+ a₁ : W.a₁ = 0
+ a₂ : W.a₂ = 0
+
+section Quantity
+
+variable [W.IsCharTwoJEqZeroNF]
+
+@[simp]
+theorem a₁_of_isCharTwoJEqZeroNF : W.a₁ = 0 := IsCharTwoJEqZeroNF.a₁
+
+@[simp]
+theorem a₂_of_isCharTwoJEqZeroNF : W.a₂ = 0 := IsCharTwoJEqZeroNF.a₂
+
+@[simp]
+theorem b₂_of_isCharTwoJEqZeroNF : W.b₂ = 0 := by
+ rw [b₂, a₁_of_isCharTwoJEqZeroNF, a₂_of_isCharTwoJEqZeroNF]
+ ring1
+
+@[simp]
+theorem b₄_of_isCharTwoJEqZeroNF : W.b₄ = 2 * W.a₄ := by
+ rw [b₄, a₁_of_isCharTwoJEqZeroNF]
+ ring1
+
+@[simp]
+theorem b₈_of_isCharTwoJEqZeroNF : W.b₈ = -W.a₄ ^ 2 := by
+ rw [b₈, a₁_of_isCharTwoJEqZeroNF, a₂_of_isCharTwoJEqZeroNF]
+ ring1
+
+@[simp]
+theorem c₄_of_isCharTwoJEqZeroNF : W.c₄ = -48 * W.a₄ := by
+ rw [c₄, b₂_of_isCharTwoJEqZeroNF, b₄_of_isCharTwoJEqZeroNF]
+ ring1
+
+@[simp]
+theorem c₆_of_isCharTwoJEqZeroNF : W.c₆ = -216 * W.b₆ := by
+ rw [c₆, b₂_of_isCharTwoJEqZeroNF, b₄_of_isCharTwoJEqZeroNF]
+ ring1
+
+@[simp]
+theorem Δ_of_isCharTwoJEqZeroNF : W.Δ = -(64 * W.a₄ ^ 3 + 27 * W.b₆ ^ 2) := by
+ rw [Δ, b₂_of_isCharTwoJEqZeroNF, b₄_of_isCharTwoJEqZeroNF]
+ ring1
+
+variable [CharP R 2]
+
+theorem b₄_of_isCharTwoJEqZeroNF_of_char_two : W.b₄ = 0 := by
+ rw [b₄_of_isCharTwoJEqZeroNF]
+ linear_combination W.a₄ * CharP.cast_eq_zero R 2
+
+theorem b₈_of_isCharTwoJEqZeroNF_of_char_two : W.b₈ = W.a₄ ^ 2 := by
+ rw [b₈_of_isCharTwoJEqZeroNF]
+ linear_combination -W.a₄ ^ 2 * CharP.cast_eq_zero R 2
+
+theorem c₄_of_isCharTwoJEqZeroNF_of_char_two : W.c₄ = 0 := by
+ rw [c₄_of_isCharTwoJEqZeroNF]
+ linear_combination -24 * W.a₄ * CharP.cast_eq_zero R 2
+
+theorem c₆_of_isCharTwoJEqZeroNF_of_char_two : W.c₆ = 0 := by
+ rw [c₆_of_isCharTwoJEqZeroNF]
+ linear_combination -108 * W.b₆ * CharP.cast_eq_zero R 2
+
+theorem Δ_of_isCharTwoJEqZeroNF_of_char_two : W.Δ = W.a₃ ^ 4 := by
+ rw [Δ_of_isCharTwoJEqZeroNF, b₆_of_char_two]
+ linear_combination (-32 * W.a₄ ^ 3 - 14 * W.a₃ ^ 4) * CharP.cast_eq_zero R 2
+
+variable [E.IsCharTwoJEqZeroNF]
+
+theorem _root_.EllipticCurve.j_of_isCharTwoJEqZeroNF :
+ E.j = 110592 * E.a₄ ^ 3 / (64 * E.a₄ ^ 3 + 27 * E.b₆ ^ 2) := by
+ have h := E.Δ'.ne_zero
+ rw [E.coe_Δ', Δ_of_isCharTwoJEqZeroNF] at h
+ rw [EllipticCurve.j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, E.coe_Δ',
+ c₄_of_isCharTwoJEqZeroNF, Δ_of_isCharTwoJEqZeroNF, div_eq_div_iff h (neg_ne_zero.1 h)]
+ ring1
+
+@[simp]
+theorem _root_.EllipticCurve.j_of_isCharTwoJEqZeroNF_of_char_two [CharP F 2] : E.j = 0 := by
+ rw [EllipticCurve.j, c₄_of_isCharTwoJEqZeroNF_of_char_two]; simp
+
+end Quantity
+
+/-! ### Normal forms of characteristic = 2 -/
+
+/-- A `WeierstrassCurve` is in normal form of characteristic = 2, if it 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`). -/
+class inductive IsCharTwoNF : Prop
+| of_j_ne_zero [W.IsCharTwoJNeZeroNF] : IsCharTwoNF
+| of_j_eq_zero [W.IsCharTwoJEqZeroNF] : IsCharTwoNF
+
+instance isCharTwoNF_of_isCharTwoJNeZeroNF [W.IsCharTwoJNeZeroNF] : W.IsCharTwoNF :=
+ IsCharTwoNF.of_j_ne_zero
+
+instance isCharTwoNF_of_isCharTwoJEqZeroNF [W.IsCharTwoJEqZeroNF] : W.IsCharTwoNF :=
+ IsCharTwoNF.of_j_eq_zero
+
+section VariableChange
+
+variable [CharP R 2] [CharP F 2]
+
+/-- For a `WeierstrassCurve` defined over a ring of characteristic = 2,
+there is an explicit change of variables of it to $Y^2 + a_3Y = X^3 + a_4X + a_6$
+(`WeierstrassCurve.IsCharTwoJEqZeroNF`) if its j = 0. -/
+def toCharTwoJEqZeroNF : VariableChange R := ⟨1, W.a₂, 0, 0⟩
+
+theorem toCharTwoJEqZeroNF_spec (ha₁ : W.a₁ = 0) :
+ (W.variableChange W.toCharTwoJEqZeroNF).IsCharTwoJEqZeroNF := by
+ constructor
+ · simp [toCharTwoJEqZeroNF, ha₁]
+ · 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,
+there is an explicit change of variables of it to $Y^2 + XY = X^3 + a_2X^2 + a_6$
+(`WeierstrassCurve.IsCharTwoJNeZeroNF`) if its j ≠ 0. -/
+def toCharTwoJNeZeroNF (W : WeierstrassCurve F) (ha₁ : W.a₁ ≠ 0) : VariableChange F :=
+ ⟨Units.mk0 _ ha₁, W.a₃ / W.a₁, 0, (W.a₁ ^ 2 * W.a₄ + W.a₃ ^ 2) / W.a₁ ^ 3⟩
+
+theorem toCharTwoJNeZeroNF_spec (ha₁ : W.a₁ ≠ 0) :
+ (W.variableChange (W.toCharTwoJNeZeroNF ha₁)).IsCharTwoJNeZeroNF := by
+ constructor
+ · simp [toCharTwoJNeZeroNF, ha₁]
+ · field_simp [toCharTwoJNeZeroNF]
+ linear_combination (W.a₃ * W.a₁ ^ 3 + W.a₁ ^ 2 * W.a₄ + W.a₃ ^ 2) * CharP.cast_eq_zero F 2
+ · field_simp [toCharTwoJNeZeroNF]
+ linear_combination (W.a₁ ^ 4 * W.a₃ ^ 2 + W.a₁ ^ 5 * W.a₃ * W.a₂) * CharP.cast_eq_zero F 2
+
+theorem _root_.EllipticCurve.toCharTwoJNeZeroNF_spec (ha₁ : E.a₁ ≠ 0) :
+ (E.variableChange (E.toCharTwoJNeZeroNF ha₁)).IsCharTwoJNeZeroNF :=
+ E.toWeierstrassCurve.toCharTwoJNeZeroNF_spec ha₁
+
+/-- For a `WeierstrassCurve` defined over a field of characteristic = 2,
+there is an explicit change of variables of it to `WeierstrassCurve.IsCharTwoNF`, that is,
+$Y^2 + XY = X^3 + a_2X^2 + a_6$ (`WeierstrassCurve.IsCharTwoJNeZeroNF`) or
+$Y^2 + a_3Y = X^3 + a_4X + a_6$ (`WeierstrassCurve.IsCharTwoJEqZeroNF`). -/
+def toCharTwoNF [DecidableEq F] : VariableChange F :=
+ if ha₁ : W.a₁ = 0 then W.toCharTwoJEqZeroNF else W.toCharTwoJNeZeroNF ha₁
+
+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₁
+ infer_instance
+ · rw [toCharTwoNF, dif_neg ha₁]
+ haveI := W.toCharTwoJNeZeroNF_spec ha₁
+ infer_instance
+
+theorem exists_variableChange_isCharTwoNF :
+ ∃ 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
+
+end WeierstrassCurve
diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean
index e010653a6a29e..00a1a91f99235 100644
--- a/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean
+++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean
@@ -7,13 +7,15 @@ import Mathlib.Algebra.MvPolynomial.CommRing
import Mathlib.Algebra.MvPolynomial.PDeriv
import Mathlib.AlgebraicGeometry.EllipticCurve.Affine
import Mathlib.Data.Fin.Tuple.Reflection
+import Mathlib.Tactic.LinearCombination'
/-!
# Projective coordinates for Weierstrass curves
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
@@ -28,16 +30,27 @@ derivatives are independent of the representative for $[x:y:z]$, and the nonsing
already implies that $(x, y, z) \ne (0, 0, 0)$, so a nonsingular rational point on `W` can simply be
given by a tuple consisting of $[x:y:z]$ and the nonsingular condition on any representative.
+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
* `WeierstrassCurve.Projective.PointClass`: the equivalence class of a point representative.
* `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
@@ -105,13 +118,13 @@ lemma fin3_def (P : Fin 3 → R) : ![P x, P y, P z] = P := by
lemma fin3_def_ext (X Y Z : R) : ![X, Y, Z] x = X ∧ ![X, Y, Z] y = Y ∧ ![X, Y, Z] z = Z :=
⟨rfl, rfl, rfl⟩
-lemma comp_fin3 {S} (f : R → S) (X Y Z : R) : f ∘ ![X, Y, Z] = ![f X, f Y, f Z] :=
- (FinVec.map_eq _ _).symm
+lemma comp_fin3 {S : Type v} (f : R → S) (X Y Z : R) : f ∘ ![X, Y, Z] = ![f X, f Y, f Z] :=
+ (FinVec.map_eq ..).symm
variable [CommRing R]
-lemma smul_fin3 (P : Fin 3 → R) (u : R) : u • P = ![u * P x, u * P y, u * P z] :=
- List.ofFn_inj.mp rfl
+lemma smul_fin3 (P : Fin 3 → R) (u : R) : u • P = ![u * P x, u * P y, u * P z] := by
+ simp [← List.ofFn_inj]
lemma smul_fin3_ext (P : Fin 3 → R) (u : R) :
(u • P) x = u * P x ∧ (u • P) y = u * P y ∧ (u • P) z = u * P z :=
@@ -133,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 :=
@@ -235,10 +253,10 @@ lemma equation_iff (P : Fin 3 → R) : W'.Equation P ↔
rw [Equation, eval_polynomial, sub_eq_zero]
lemma equation_smul (P : Fin 3 → R) {u : R} (hu : IsUnit u) : W'.Equation (u • P) ↔ W'.Equation P :=
- have (u : R) {P : Fin 3 → R} (hP : W'.Equation P) : W'.Equation <| u • P := by
+ have hP (u : R) {P : Fin 3 → R} (hP : W'.Equation P) : W'.Equation <| u • P := by
rw [equation_iff] at hP ⊢
linear_combination (norm := (simp only [smul_fin3_ext]; ring1)) u ^ 3 * hP
- ⟨fun h => by convert this hu.unit.inv h; erw [smul_smul, hu.val_inv_mul, one_smul], this u⟩
+ ⟨fun h => by convert hP hu.unit.inv h; erw [smul_smul, hu.val_inv_mul, one_smul], hP u⟩
lemma equation_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : W'.Equation P ↔ W'.Equation Q := by
rcases h with ⟨u, rfl⟩
@@ -355,7 +373,7 @@ lemma nonsingular_iff (P : Fin 3 → R) : W'.Nonsingular P ↔ W'.Equation P ∧
lemma nonsingular_smul (P : Fin 3 → R) {u : R} (hu : IsUnit u) :
W'.Nonsingular (u • P) ↔ W'.Nonsingular P :=
- have {u : R} (hu : IsUnit u) {P : Fin 3 → R} (hP : W'.Nonsingular <| u • P) :
+ have hP {u : R} (hu : IsUnit u) {P : Fin 3 → R} (hP : W'.Nonsingular <| u • P) :
W'.Nonsingular P := by
rcases (nonsingular_iff _).mp hP with ⟨hP, hP'⟩
refine (nonsingular_iff P).mpr ⟨(equation_smul P hu).mp hP, ?_⟩
@@ -364,7 +382,7 @@ lemma nonsingular_smul (P : Fin 3 → R) {u : R} (hu : IsUnit u) :
exact ⟨by linear_combination (norm := ring1) u ^ 2 * hP'.left,
by linear_combination (norm := ring1) u ^ 2 * hP'.right.left,
by linear_combination (norm := ring1) u ^ 2 * hP'.right.right⟩
- ⟨this hu, fun h => this hu.unit⁻¹.isUnit <| by rwa [smul_smul, hu.val_inv_mul, one_smul]⟩
+ ⟨hP hu, fun h => hP hu.unit⁻¹.isUnit <| by rwa [smul_smul, hu.val_inv_mul, one_smul]⟩
lemma nonsingular_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : W'.Nonsingular P ↔ W'.Nonsingular Q := by
rcases h with ⟨u, rfl⟩
@@ -446,4 +464,983 @@ alias nonsingular_of_affine_of_Z_ne_zero := nonsingular_of_Z_ne_zero
@[deprecated (since := "2024-08-27")] alias nonsingular_smul_iff := nonsingular_smul
@[deprecated (since := "2024-08-27")] alias nonsingular_zero' := nonsingular_zero
+section Negation
+
+/-! ### Negation formulae -/
+
+variable (W') in
+/-- The $Y$-coordinate of a representative of `-P` for a point `P`. -/
+def negY (P : Fin 3 → R) : R :=
+ -P y - W'.a₁ * P x - W'.a₃ * P z
+
+lemma negY_eq (X Y Z : R) : W'.negY ![X, Y, Z] = -Y - W'.a₁ * X - W'.a₃ * Z :=
+ rfl
+
+lemma negY_smul (P : Fin 3 → R) (u : R) : W'.negY (u • P) = u * W'.negY P := by
+ simp only [negY, smul_fin3_ext]
+ ring1
+
+lemma negY_of_Z_eq_zero [NoZeroDivisors R] {P : Fin 3 → R} (hP : W'.Equation P) (hPz : P z = 0) :
+ W'.negY P = -P y := by
+ rw [negY, hPz, X_eq_zero_of_Z_eq_zero hP hPz, mul_zero, sub_zero, mul_zero, sub_zero]
+
+lemma negY_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) :
+ W.negY P / P z = W.toAffine.negY (P x / P z) (P y / P z) := by
+ linear_combination (norm := (rw [negY, Affine.negY]; ring1)) -W.a₃ * div_self hPz
+
+lemma Y_sub_Y_mul_Y_sub_negY {P Q : Fin 3 → R} (hP : W'.Equation P) (hQ : W'.Equation Q)
+ (hx : P x * Q z = Q x * P z) :
+ P z * Q z * (P y * Q z - Q y * P z) * (P y * Q z - W'.negY Q * P z) = 0 := by
+ linear_combination' (norm := (rw [negY]; ring1)) Q z ^ 3 * (equation_iff P).mp hP
+ - P z ^ 3 * (equation_iff Q).mp hQ + hx * hx * hx + W'.a₂ * P z * Q z * hx * hx
+ + (W'.a₄ * P z ^ 2 * Q z ^ 2 - W'.a₁ * P y * P z * Q z ^ 2) * hx
+
+lemma Y_eq_of_Y_ne [NoZeroDivisors R] {P Q : Fin 3 → R} (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) :
+ P y * Q z = W'.negY Q * P z :=
+ sub_eq_zero.mp <| (mul_eq_zero.mp <| Y_sub_Y_mul_Y_sub_negY hP hQ hx).resolve_left <|
+ mul_ne_zero (mul_ne_zero hPz hQz) <| sub_ne_zero.mpr hy
+
+lemma Y_eq_of_Y_ne' [NoZeroDivisors R] {P Q : Fin 3 → R} (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) : P y * Q z = Q y * P z :=
+ sub_eq_zero.mp <| (mul_eq_zero.mp <| (mul_eq_zero.mp <| Y_sub_Y_mul_Y_sub_negY hP hQ hx
+ ).resolve_right <| sub_ne_zero.mpr hy).resolve_left <| mul_ne_zero hPz hQz
+
+lemma Y_eq_iff' {P Q : Fin 3 → F} (hPz : P z ≠ 0) (hQz : Q z ≠ 0) :
+ P y * Q z = W.negY Q * P z ↔ P y / P z = W.toAffine.negY (Q x / Q z) (Q y / Q z) :=
+ negY_of_Z_ne_zero hQz ▸ (div_eq_div_iff hPz hQz).symm
+
+lemma Y_sub_Y_add_Y_sub_negY {P Q : Fin 3 → R} (hx : P x * Q z = Q x * P z) :
+ (P y * Q z - Q y * P z) + (P y * Q z - W'.negY Q * P z) = (P y - W'.negY P) * Q z := by
+ linear_combination (norm := (rw [negY, negY]; ring1)) -W'.a₁ * hx
+
+lemma Y_ne_negY_of_Y_ne [NoZeroDivisors R] {P Q : Fin 3 → R} (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) : P y ≠ W'.negY P := by
+ have hy' : P y * Q z - W'.negY Q * P z = 0 := sub_eq_zero.mpr <| Y_eq_of_Y_ne hP hQ hPz hQz hx hy
+ contrapose! hy
+ linear_combination (norm := ring1) Y_sub_Y_add_Y_sub_negY hx + Q z * hy - hy'
+
+lemma Y_ne_negY_of_Y_ne' [NoZeroDivisors R] {P Q : Fin 3 → R} (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) : P y ≠ W'.negY P := by
+ have hy' : P y * Q z - Q y * P z = 0 := sub_eq_zero.mpr <| Y_eq_of_Y_ne' hP hQ hPz hQz hx hy
+ contrapose! hy
+ linear_combination (norm := ring1) Y_sub_Y_add_Y_sub_negY hx + Q z * hy - hy'
+
+lemma Y_eq_negY_of_Y_eq [NoZeroDivisors R] {P Q : Fin 3 → R} (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) :
+ P y = W'.negY P :=
+ mul_left_injective₀ hQz <| by
+ linear_combination (norm := ring1) -Y_sub_Y_add_Y_sub_negY hx + hy + hy'
+
+lemma nonsingular_iff_of_Y_eq_negY {P : Fin 3 → F} (hPz : P z ≠ 0) (hy : P y = W.negY P) :
+ W.Nonsingular P ↔ W.Equation P ∧ eval P W.polynomialX ≠ 0 := by
+ have hy' : eval P W.polynomialY = (P y - W.negY P) * P z := by rw [negY, eval_polynomialY]; ring1
+ rw [nonsingular_iff_of_Z_ne_zero hPz, hy', hy, sub_self, zero_mul, ne_self_iff_false, or_false]
+
+end Negation
+
+section Doubling
+
+/-! ### Doubling formulae -/
+
+variable (W) in
+/-- The unit associated to the doubling of a 2-torsion point `P`.
+More specifically, the unit `u` such that `W.add P P = u • ![0, 1, 0]` where `P = W.neg P`. -/
+noncomputable def dblU (P : Fin 3 → F) : F :=
+ eval P W.polynomialX ^ 3 / P z ^ 2
+
+lemma dblU_eq (P : Fin 3 → F) : W.dblU P =
+ (W.a₁ * P y * P z - (3 * P x ^ 2 + 2 * W.a₂ * P x * P z + W.a₄ * P z ^ 2)) ^ 3 / P z ^ 2 := by
+ rw [dblU, eval_polynomialX]
+
+lemma dblU_smul {P : Fin 3 → F} (hPz : P z ≠ 0) {u : F} (hu : u ≠ 0) :
+ W.dblU (u • P) = u ^ 4 * W.dblU P := by
+ field_simp [dblU_eq, smul_fin3_ext]
+ ring1
+
+lemma dblU_of_Z_eq_zero {P : Fin 3 → F} (hPz : P z = 0) : W.dblU P = 0 := by
+ rw [dblU_eq, hPz, zero_pow two_ne_zero, div_zero]
+
+lemma dblU_ne_zero_of_Y_eq {P Q : Fin 3 → F} (hP : W.Nonsingular 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.dblU P ≠ 0 :=
+ div_ne_zero (pow_ne_zero 3
+ ((nonsingular_iff_of_Y_eq_negY hPz <| Y_eq_negY_of_Y_eq hQz hx hy hy').mp hP).right) <|
+ pow_ne_zero 2 hPz
+
+lemma isUnit_dblU_of_Y_eq {P Q : Fin 3 → F} (hP : W.Nonsingular 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) :
+ IsUnit (W.dblU P) :=
+ (dblU_ne_zero_of_Y_eq hP hPz hQz hx hy hy').isUnit
+
+variable (W') in
+/-- The $Z$-coordinate of a representative of `2 • P` for a point `P`. -/
+def dblZ (P : Fin 3 → R) : R :=
+ P z * (P y - W'.negY P) ^ 3
+
+lemma dblZ_smul (P : Fin 3 → R) (u : R) : W'.dblZ (u • P) = u ^ 4 * W'.dblZ P := by
+ simp only [dblZ, negY_smul, smul_fin3_ext]
+ ring1
+
+lemma dblZ_of_Z_eq_zero {P : Fin 3 → R} (hPz : P z = 0) : W'.dblZ P = 0 := by
+ rw [dblZ, hPz, zero_mul]
+
+lemma dblZ_of_Y_eq [NoZeroDivisors R] {P Q : Fin 3 → R} (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'.dblZ P = 0 := by
+ rw [dblZ, Y_eq_negY_of_Y_eq hQz hx hy hy', sub_self, zero_pow three_ne_zero, mul_zero]
+
+lemma dblZ_ne_zero_of_Y_ne [NoZeroDivisors R] {P Q : Fin 3 → R} (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'.dblZ P ≠ 0 :=
+ mul_ne_zero hPz <| pow_ne_zero 3 <| sub_ne_zero.mpr <| Y_ne_negY_of_Y_ne hP hQ hPz hQz hx hy
+
+lemma isUnit_dblZ_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) : IsUnit (W.dblZ P) :=
+ (dblZ_ne_zero_of_Y_ne hP hQ hPz hQz hx hy).isUnit
+
+lemma dblZ_ne_zero_of_Y_ne' [NoZeroDivisors R] {P Q : Fin 3 → R} (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'.dblZ P ≠ 0 :=
+ mul_ne_zero hPz <| pow_ne_zero 3 <| sub_ne_zero.mpr <| Y_ne_negY_of_Y_ne' hP hQ hPz hQz hx hy
+
+lemma isUnit_dblZ_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) :
+ IsUnit (W.dblZ P) :=
+ (dblZ_ne_zero_of_Y_ne' hP hQ hPz hQz hx hy).isUnit
+
+private lemma toAffine_slope_of_eq {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.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z) =
+ -eval P W.polynomialX / P z / (P y - W.negY P) := by
+ have hPy : P y - W.negY P ≠ 0 := sub_ne_zero.mpr <| Y_ne_negY_of_Y_ne' hP hQ hPz hQz hx hy
+ simp only [X_eq_iff hPz hQz, ne_eq, Y_eq_iff' hPz hQz] at hx hy
+ rw [Affine.slope_of_Y_ne hx <| negY_of_Z_ne_zero hQz ▸ hy, ← negY_of_Z_ne_zero hPz]
+ field_simp [eval_polynomialX, hPz]
+ ring1
+
+variable (W') in
+/-- The $X$-coordinate of a representative of `2 • P` for a point `P`. -/
+noncomputable def dblX (P : Fin 3 → R) : R :=
+ 2 * P x * P y ^ 3 + 3 * W'.a₁ * P x ^ 2 * P y ^ 2 + 6 * W'.a₂ * P x ^ 3 * P y
+ - 8 * W'.a₂ * P y ^ 3 * P z + 9 * W'.a₃ * P x ^ 4 - 6 * W'.a₃ * P x * P y ^ 2 * P z
+ - 6 * W'.a₄ * P x ^ 2 * P y * P z - 18 * W'.a₆ * P x * P y * P z ^ 2
+ + 3 * W'.a₁ ^ 2 * P x ^ 3 * P y - 2 * W'.a₁ ^ 2 * P y ^ 3 * P z + 3 * W'.a₁ * W'.a₂ * P x ^ 4
+ - 12 * W'.a₁ * W'.a₂ * P x * P y ^ 2 * P z - 9 * W'.a₁ * W'.a₃ * P x ^ 2 * P y * P z
+ - 3 * W'.a₁ * W'.a₄ * P x ^ 3 * P z - 9 * W'.a₁ * W'.a₆ * P x ^ 2 * P z ^ 2
+ + 8 * W'.a₂ ^ 2 * P x ^ 2 * P y * P z + 12 * W'.a₂ * W'.a₃ * P x ^ 3 * P z
+ - 12 * W'.a₂ * W'.a₃ * P y ^ 2 * P z ^ 2 + 8 * W'.a₂ * W'.a₄ * P x * P y * P z ^ 2
+ - 12 * W'.a₃ ^ 2 * P x * P y * P z ^ 2 + 6 * W'.a₃ * W'.a₄ * P x ^ 2 * P z ^ 2
+ + 2 * W'.a₄ ^ 2 * P y * P z ^ 3 + W'.a₁ ^ 3 * P x ^ 4 - 3 * W'.a₁ ^ 3 * P x * P y ^ 2 * P z
+ - 2 * W'.a₁ ^ 2 * W'.a₂ * P x ^ 2 * P y * P z - 3 * W'.a₁ ^ 2 * W'.a₃ * P y ^ 2 * P z ^ 2
+ + 2 * W'.a₁ ^ 2 * W'.a₄ * P x * P y * P z ^ 2 + 4 * W'.a₁ * W'.a₂ ^ 2 * P x ^ 3 * P z
+ - 8 * W'.a₁ * W'.a₂ * W'.a₃ * P x * P y * P z ^ 2
+ + 4 * W'.a₁ * W'.a₂ * W'.a₄ * P x ^ 2 * P z ^ 2 - 3 * W'.a₁ * W'.a₃ ^ 2 * P x ^ 2 * P z ^ 2
+ + 2 * W'.a₁ * W'.a₃ * W'.a₄ * P y * P z ^ 3 + W'.a₁ * W'.a₄ ^ 2 * P x * P z ^ 3
+ + 4 * W'.a₂ ^ 2 * W'.a₃ * P x ^ 2 * P z ^ 2 - 6 * W'.a₂ * W'.a₃ ^ 2 * P y * P z ^ 3
+ + 4 * W'.a₂ * W'.a₃ * W'.a₄ * P x * P z ^ 3 - 2 * W'.a₃ ^ 3 * P x * P z ^ 3
+ + W'.a₃ * W'.a₄ ^ 2 * P z ^ 4 - W'.a₁ ^ 4 * P x ^ 2 * P y * P z
+ + W'.a₁ ^ 3 * W'.a₂ * P x ^ 3 * P z - 2 * W'.a₁ ^ 3 * W'.a₃ * P x * P y * P z ^ 2
+ + W'.a₁ ^ 3 * W'.a₄ * P x ^ 2 * P z ^ 2 + W'.a₁ ^ 2 * W'.a₂ * W'.a₃ * P x ^ 2 * P z ^ 2
+ - W'.a₁ ^ 2 * W'.a₃ ^ 2 * P y * P z ^ 3 + 2 * W'.a₁ ^ 2 * W'.a₃ * W'.a₄ * P x * P z ^ 3
+ - W'.a₁ * W'.a₂ * W'.a₃ ^ 2 * P x * P z ^ 3 - W'.a₂ * W'.a₃ ^ 3 * P z ^ 4
+ + W'.a₁ * W'.a₃ ^ 2 * W'.a₄ * P z ^ 4
+
+lemma dblX_eq' {P : Fin 3 → R} (hP : W'.Equation P) : W'.dblX P * P z =
+ (eval P W'.polynomialX ^ 2 - W'.a₁ * eval P W'.polynomialX * P z * (P y - W'.negY P)
+ - W'.a₂ * P z ^ 2 * (P y - W'.negY P) ^ 2 - 2 * P x * P z * (P y - W'.negY P) ^ 2)
+ * (P y - W'.negY P) := by
+ linear_combination (norm := (rw [dblX, eval_polynomialX, negY]; ring1))
+ 9 * (W'.a₁ * P x ^ 2 + 2 * P x * P y) * (equation_iff _).mp hP
+
+lemma dblX_eq {P : Fin 3 → F} (hP : W.Equation P) (hPz : P z ≠ 0) : W.dblX P =
+ ((eval P W.polynomialX ^ 2 - W.a₁ * eval P W.polynomialX * P z * (P y - W.negY P)
+ - W.a₂ * P z ^ 2 * (P y - W.negY P) ^ 2 - 2 * P x * P z * (P y - W.negY P) ^ 2)
+ * (P y - W.negY P)) / P z := by
+ rw [← dblX_eq' hP, mul_div_cancel_right₀ _ hPz]
+
+lemma dblX_smul (P : Fin 3 → R) (u : R) : W'.dblX (u • P) = u ^ 4 * W'.dblX P := by
+ simp only [dblX, smul_fin3_ext]
+ ring1
+
+lemma dblX_of_Z_eq_zero [NoZeroDivisors R] {P : Fin 3 → R} (hP : W'.Equation P) (hPz : P z = 0) :
+ W'.dblX P = 0 := by
+ rw [dblX, hPz, X_eq_zero_of_Z_eq_zero hP hPz]
+ ring1
+
+lemma dblX_of_Y_eq [NoZeroDivisors R] {P Q : Fin 3 → R} (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'.dblX P = 0 := by
+ apply eq_zero_of_ne_zero_of_mul_right_eq_zero hPz
+ rw [dblX_eq' hP, Y_eq_negY_of_Y_eq hQz hx hy hy']
+ ring1
+
+private lemma toAffine_addX_of_eq {P : Fin 3 → F} (hPz : P z ≠ 0) {n d : F} (hd : d ≠ 0) :
+ W.toAffine.addX (P x / P z) (P x / P z) (-n / P z / d) =
+ (n ^ 2 - W.a₁ * n * P z * d - W.a₂ * P z ^ 2 * d ^ 2 - 2 * P x * P z * d ^ 2) * d / P z
+ / (P z * d ^ 3) := by
+ field_simp [mul_ne_zero hPz hd]
+ ring1
+
+lemma dblX_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) (hx : P x * Q z = Q x * P z) (hy : P y * Q z ≠ W.negY Q * P z) :
+ W.dblX P / 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)) := by
+ rw [dblX_eq hP hPz, dblZ, toAffine_slope_of_eq hP hQ hPz hQz hx hy, ← (X_eq_iff hPz hQz).mp hx,
+ toAffine_addX_of_eq hPz <| sub_ne_zero.mpr <| Y_ne_negY_of_Y_ne' hP hQ hPz hQz hx hy]
+
+variable (W') in
+/-- The $Y$-coordinate of a representative of `-(2 • P)` for a point `P`. -/
+noncomputable def negDblY (P : Fin 3 → R) : R :=
+ -P y ^ 4 - 3 * W'.a₁ * P x * P y ^ 3 - 9 * W'.a₃ * P x ^ 3 * P y + 3 * W'.a₃ * P y ^ 3 * P z
+ - 3 * W'.a₄ * P x * P y ^ 2 * P z - 27 * W'.a₆ * P x ^ 3 * P z + 9 * W'.a₆ * P y ^ 2 * P z ^ 2
+ - 3 * W'.a₁ ^ 2 * P x ^ 2 * P y ^ 2 + 4 * W'.a₁ * W'.a₂ * P y ^ 3 * P z
+ - 3 * W'.a₁ * W'.a₂ * P x ^ 3 * P y - 9 * W'.a₁ * W'.a₃ * P x ^ 4
+ + 6 * W'.a₁ * W'.a₃ * P x * P y ^ 2 * P z + 18 * W'.a₁ * W'.a₆ * P x * P y * P z ^ 2
+ + 9 * W'.a₂ ^ 2 * P x ^ 4 - 8 * W'.a₂ ^ 2 * P x * P y ^ 2 * P z
+ - 9 * W'.a₂ * W'.a₃ * P x ^ 2 * P y * P z + 9 * W'.a₂ * W'.a₄ * P x ^ 3 * P z
+ - 4 * W'.a₂ * W'.a₄ * P y ^ 2 * P z ^ 2 - 27 * W'.a₂ * W'.a₆ * P x ^ 2 * P z ^ 2
+ - 9 * W'.a₃ ^ 2 * P x ^ 3 * P z + 6 * W'.a₃ ^ 2 * P y ^ 2 * P z ^ 2
+ - 12 * W'.a₃ * W'.a₄ * P x * P y * P z ^ 2 + 9 * W'.a₄ ^ 2 * P x ^ 2 * P z ^ 2
+ - 2 * W'.a₁ ^ 3 * P x ^ 3 * P y + W'.a₁ ^ 3 * P y ^ 3 * P z + 3 * W'.a₁ ^ 2 * W'.a₂ * P x ^ 4
+ + 2 * W'.a₁ ^ 2 * W'.a₂ * P x * P y ^ 2 * P z + 3 * W'.a₁ ^ 2 * W'.a₃ * P x ^ 2 * P y * P z
+ + 3 * W'.a₁ ^ 2 * W'.a₄ * P x ^ 3 * P z - W'.a₁ ^ 2 * W'.a₄ * P y ^ 2 * P z ^ 2
+ - 12 * W'.a₁ * W'.a₂ ^ 2 * P x ^ 2 * P y * P z - 6 * W'.a₁ * W'.a₂ * W'.a₃ * P x ^ 3 * P z
+ + 4 * W'.a₁ * W'.a₂ * W'.a₃ * P y ^ 2 * P z ^ 2
+ - 8 * W'.a₁ * W'.a₂ * W'.a₄ * P x * P y * P z ^ 2 + 6 * W'.a₁ * W'.a₃ ^ 2 * P x * P y * P z ^ 2
+ - W'.a₁ * W'.a₄ ^ 2 * P y * P z ^ 3 + 8 * W'.a₂ ^ 3 * P x ^ 3 * P z
+ - 8 * W'.a₂ ^ 2 * W'.a₃ * P x * P y * P z ^ 2 + 12 * W'.a₂ ^ 2 * W'.a₄ * P x ^ 2 * P z ^ 2
+ - 9 * W'.a₂ * W'.a₃ ^ 2 * P x ^ 2 * P z ^ 2 - 4 * W'.a₂ * W'.a₃ * W'.a₄ * P y * P z ^ 3
+ + 6 * W'.a₂ * W'.a₄ ^ 2 * P x * P z ^ 3 + W'.a₃ ^ 3 * P y * P z ^ 3
+ - 3 * W'.a₃ ^ 2 * W'.a₄ * P x * P z ^ 3 + W'.a₄ ^ 3 * P z ^ 4 + W'.a₁ ^ 4 * P x * P y ^ 2 * P z
+ - 3 * W'.a₁ ^ 3 * W'.a₂ * P x ^ 2 * P y * P z + W'.a₁ ^ 3 * W'.a₃ * P y ^ 2 * P z ^ 2
+ - 2 * W'.a₁ ^ 3 * W'.a₄ * P x * P y * P z ^ 2 + 2 * W'.a₁ ^ 2 * W'.a₂ ^ 2 * P x ^ 3 * P z
+ - 2 * W'.a₁ ^ 2 * W'.a₂ * W'.a₃ * P x * P y * P z ^ 2
+ + 3 * W'.a₁ ^ 2 * W'.a₂ * W'.a₄ * P x ^ 2 * P z ^ 2
+ - 2 * W'.a₁ ^ 2 * W'.a₃ * W'.a₄ * P y * P z ^ 3 + W'.a₁ ^ 2 * W'.a₄ ^ 2 * P x * P z ^ 3
+ + W'.a₁ * W'.a₂ * W'.a₃ ^ 2 * P y * P z ^ 3 + 2 * W'.a₁ * W'.a₂ * W'.a₃ * W'.a₄ * P x * P z ^ 3
+ + W'.a₁ * W'.a₃ * W'.a₄ ^ 2 * P z ^ 4 - 2 * W'.a₂ ^ 2 * W'.a₃ ^ 2 * P x * P z ^ 3
+ - W'.a₂ * W'.a₃ ^ 2 * W'.a₄ * P z ^ 4
+
+lemma negDblY_eq' {P : Fin 3 → R} (hP : W'.Equation P) : W'.negDblY P * P z ^ 2 =
+ -eval P W'.polynomialX * (eval P W'.polynomialX ^ 2
+ - W'.a₁ * eval P W'.polynomialX * P z * (P y - W'.negY P)
+ - W'.a₂ * P z ^ 2 * (P y - W'.negY P) ^ 2 - 2 * P x * P z * (P y - W'.negY P) ^ 2
+ - P x * P z * (P y - W'.negY P) ^ 2) + P y * P z ^ 2 * (P y - W'.negY P) ^ 3 := by
+ linear_combination (norm := (rw [negDblY, eval_polynomialX, negY]; ring1))
+ -9 * (P y ^ 2 * P z + 2 * W'.a₁ * P x * P y * P z - 3 * P x ^ 3 - 3 * W'.a₂ * P x ^ 2 * P z)
+ * (equation_iff _).mp hP
+
+lemma negDblY_eq {P : Fin 3 → F} (hP : W.Equation P) (hPz : P z ≠ 0) : W.negDblY P =
+ (-eval P W.polynomialX * (eval P W.polynomialX ^ 2
+ - W.a₁ * eval P W.polynomialX * P z * (P y - W.negY P)
+ - W.a₂ * P z ^ 2 * (P y - W.negY P) ^ 2 - 2 * P x * P z * (P y - W.negY P) ^ 2
+ - P x * P z * (P y - W.negY P) ^ 2) + P y * P z ^ 2 * (P y - W.negY P) ^ 3) / P z ^ 2 := by
+ rw [← negDblY_eq' hP, mul_div_cancel_right₀ _ <| pow_ne_zero 2 hPz]
+
+lemma negDblY_smul (P : Fin 3 → R) (u : R) : W'.negDblY (u • P) = u ^ 4 * W'.negDblY P := by
+ simp only [negDblY, smul_fin3_ext]
+ ring1
+
+lemma negDblY_of_Z_eq_zero [NoZeroDivisors R] {P : Fin 3 → R} (hP : W'.Equation P) (hPz : P z = 0) :
+ W'.negDblY P = -P y ^ 4 := by
+ rw [negDblY, hPz, X_eq_zero_of_Z_eq_zero hP hPz]
+ ring1
+
+lemma negDblY_of_Y_eq' [NoZeroDivisors R] {P Q : Fin 3 → R} (hP : W'.Equation P) (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'.negDblY P * P z ^ 2 = -eval P W'.polynomialX ^ 3 := by
+ rw [negDblY_eq' hP, Y_eq_negY_of_Y_eq hQz hx hy hy']
+ ring1
+
+lemma negDblY_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.negDblY P = -W.dblU P := by
+ rw [dblU, ← neg_div, ← negDblY_of_Y_eq' hP hQz hx hy hy',
+ mul_div_cancel_right₀ _ <| pow_ne_zero 2 hPz]
+
+private lemma toAffine_negAddY_of_eq {P : Fin 3 → F} (hPz : P z ≠ 0) {n d : F} (hd : d ≠ 0) :
+ W.toAffine.negAddY (P x / P z) (P x / P z) (P y / P z) (-n / P z / d) =
+ (-n * (n ^ 2 - W.a₁ * n * P z * d - W.a₂ * P z ^ 2 * d ^ 2 - 2 * P x * P z * d ^ 2
+ - P x * P z * d ^ 2) + P y * P z ^ 2 * d ^ 3) / P z ^ 2 / (P z * d ^ 3) := by
+ rw [Affine.negAddY, toAffine_addX_of_eq hPz hd]
+ field_simp [mul_ne_zero hPz <| mul_ne_zero hPz <| pow_ne_zero 3 hd]
+ ring1
+
+lemma negDblY_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) (hx : P x * Q z = Q x * P z) (hy : P y * Q z ≠ W.negY Q * P z) :
+ W.negDblY P / W.dblZ P = W.toAffine.negAddY (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)) := by
+ rw [negDblY_eq hP hPz, dblZ, toAffine_slope_of_eq hP hQ hPz hQz hx hy, ← (X_eq_iff hPz hQz).mp hx,
+ toAffine_negAddY_of_eq hPz <| sub_ne_zero.mpr <| Y_ne_negY_of_Y_ne' hP hQ hPz hQz hx hy]
+
+variable (W') in
+/-- The $Y$-coordinate of a representative of `2 • P` for a point `P`. -/
+noncomputable def dblY (P : Fin 3 → R) : R :=
+ W'.negY ![W'.dblX P, W'.negDblY P, W'.dblZ P]
+
+lemma dblY_smul (P : Fin 3 → R) (u : R) : W'.dblY (u • P) = u ^ 4 * W'.dblY P := by
+ simp only [dblY, negY_eq, negDblY_smul, dblX_smul, dblZ_smul]
+ ring1
+
+lemma dblY_of_Z_eq_zero [NoZeroDivisors R] {P : Fin 3 → R} (hP : W'.Equation P) (hPz : P z = 0) :
+ W'.dblY P = P y ^ 4 := by
+ rw [dblY, negY_eq, negDblY_of_Z_eq_zero hP hPz, dblX_of_Z_eq_zero hP hPz, dblZ_of_Z_eq_zero hPz]
+ ring1
+
+lemma dblY_of_Y_eq' [NoZeroDivisors R] {P Q : Fin 3 → R} (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'.dblY P * P z ^ 2 = eval P W'.polynomialX ^ 3 := by
+ linear_combination (norm := (rw [dblY, negY_eq, dblX_of_Y_eq hP hPz hQz hx hy hy',
+ dblZ_of_Y_eq hQz hx hy hy']; ring1)) -negDblY_of_Y_eq' hP hQz hx hy hy'
+
+lemma dblY_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.dblY P = W.dblU P := by
+ rw [dblU, ← dblY_of_Y_eq' hP hPz hQz hx hy hy', mul_div_cancel_right₀ _ <| pow_ne_zero 2 hPz]
+
+lemma dblY_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) (hx : P x * Q z = Q x * P z) (hy : P y * Q z ≠ W.negY Q * P z) :
+ W.dblY P / W.dblZ P = 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)) := by
+ erw [dblY, negY_of_Z_ne_zero <| dblZ_ne_zero_of_Y_ne' hP hQ hPz hQz hx hy,
+ dblX_of_Z_ne_zero hP hQ hPz hQz hx hy, negDblY_of_Z_ne_zero hP hQ hPz hQz hx hy, Affine.addY]
+
+variable (W') in
+/-- The coordinates of a representative of `2 • P` for a point `P`. -/
+noncomputable def dblXYZ (P : Fin 3 → R) : Fin 3 → R :=
+ ![W'.dblX P, W'.dblY P, W'.dblZ P]
+
+lemma dblXYZ_X (P : Fin 3 → R) : W'.dblXYZ P x = W'.dblX P :=
+ rfl
+
+lemma dblXYZ_Y (P : Fin 3 → R) : W'.dblXYZ P y = W'.dblY P :=
+ rfl
+
+lemma dblXYZ_Z (P : Fin 3 → R) : W'.dblXYZ P z = W'.dblZ P :=
+ rfl
+
+lemma dblXYZ_smul (P : Fin 3 → R) (u : R) : W'.dblXYZ (u • P) = u ^ 4 • W'.dblXYZ P := by
+ rw [dblXYZ, dblX_smul, dblY_smul, dblZ_smul, smul_fin3, dblXYZ_X, dblXYZ_Y, dblXYZ_Z]
+
+lemma dblXYZ_of_Z_eq_zero [NoZeroDivisors R] {P : Fin 3 → R} (hP : W'.Equation P) (hPz : P z = 0) :
+ W'.dblXYZ P = P y ^ 4 • ![0, 1, 0] := by
+ erw [dblXYZ, dblX_of_Z_eq_zero hP hPz, dblY_of_Z_eq_zero hP hPz, dblZ_of_Z_eq_zero hPz, smul_fin3,
+ mul_zero, mul_one]
+
+lemma dblXYZ_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.dblXYZ P = W.dblU P • ![0, 1, 0] := by
+ erw [dblXYZ, dblX_of_Y_eq hP hPz hQz hx hy hy', dblY_of_Y_eq hP hPz hQz hx hy hy',
+ dblZ_of_Y_eq hQz hx hy hy', smul_fin3, mul_zero, mul_one]
+
+lemma dblXYZ_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) (hx : P x * Q z = Q x * P z) (hy : P y * Q z ≠ W.negY Q * P z) :
+ W.dblXYZ P = 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
+ have hZ : IsUnit <| W.dblZ P := isUnit_dblZ_of_Y_ne' hP hQ hPz hQz hx hy
+ erw [dblXYZ, smul_fin3, ← dblX_of_Z_ne_zero hP hQ hPz hQz hx hy, hZ.mul_div_cancel,
+ ← dblY_of_Z_ne_zero hP hQ hPz hQz hx hy, hZ.mul_div_cancel, mul_one]
+
+end Doubling
+
+section Addition
+
+/-! ### Addition formulae -/
+
+/-- The unit associated to the addition of a non-2-torsion point `P` with its negation.
+More specifically, the unit `u` such that `W.add P Q = u • ![0, 1, 0]` where `P x / P z = Q x / Q z`
+but `P ≠ W.neg P`. -/
+def addU (P Q : Fin 3 → F) : F :=
+ -(P y * Q z - Q y * P z) ^ 3 / (P z * Q z)
+
+lemma addU_smul {P Q : Fin 3 → F} (hPz : P z ≠ 0) (hQz : Q z ≠ 0) {u v : F} (hu : u ≠ 0)
+ (hv : v ≠ 0) : addU (u • P) (v • Q) = (u * v) ^ 2 * addU P Q := by
+ field_simp [addU, smul_fin3_ext]
+ ring1
+
+lemma addU_of_Z_eq_zero_left {P Q : Fin 3 → F} (hPz : P z = 0) : addU P Q = 0 := by
+ rw [addU, hPz, zero_mul, div_zero]
+
+lemma addU_of_Z_eq_zero_right {P Q : Fin 3 → F} (hQz : Q z = 0) : addU P Q = 0 := by
+ rw [addU, hQz, mul_zero <| P z, div_zero]
+
+lemma addU_ne_zero_of_Y_ne {P Q : Fin 3 → F} (hPz : P z ≠ 0) (hQz : Q z ≠ 0)
+ (hy : P y * Q z ≠ Q y * P z) : addU P Q ≠ 0 :=
+ div_ne_zero (neg_ne_zero.mpr <| pow_ne_zero 3 <| sub_ne_zero.mpr hy) <| mul_ne_zero hPz hQz
+
+lemma isUnit_addU_of_Y_ne {P Q : Fin 3 → F} (hPz : P z ≠ 0) (hQz : Q z ≠ 0)
+ (hy : P y * Q z ≠ Q y * P z) : IsUnit (addU P Q) :=
+ (addU_ne_zero_of_Y_ne hPz hQz hy).isUnit
+
+variable (W') in
+/-- The $Z$-coordinate of a representative of `P + Q` for two distinct points `P` and `Q`.
+Note that this returns the value 0 if the representatives of `P` and `Q` are equal. -/
+def addZ (P Q : Fin 3 → R) : R :=
+ -3 * P x ^ 2 * Q x * Q z + 3 * P x * Q x ^ 2 * P z + P y ^ 2 * Q z ^ 2 - Q y ^ 2 * P z ^ 2
+ + W'.a₁ * P x * P y * Q z ^ 2 - W'.a₁ * Q x * Q y * P z ^ 2 - W'.a₂ * P x ^ 2 * Q z ^ 2
+ + W'.a₂ * Q x ^ 2 * P z ^ 2 + W'.a₃ * P y * P z * Q z ^ 2 - W'.a₃ * Q y * P z ^ 2 * Q z
+ - W'.a₄ * P x * P z * Q z ^ 2 + W'.a₄ * Q x * P z ^ 2 * Q z
+
+lemma addZ_eq' {P Q : Fin 3 → R} (hP : W'.Equation P) (hQ : W'.Equation Q) :
+ W'.addZ P Q * (P z * Q z) = (P x * Q z - Q x * P z) ^ 3 := by
+ linear_combination (norm := (rw [addZ]; ring1))
+ Q z ^ 3 * (equation_iff _).mp hP - P z ^ 3 * (equation_iff _).mp hQ
+
+lemma addZ_eq {P Q : Fin 3 → F} (hP : W.Equation P) (hQ : W.Equation Q) (hPz : P z ≠ 0)
+ (hQz : Q z ≠ 0) : W.addZ P Q = (P x * Q z - Q x * P z) ^ 3 / (P z * Q z) := by
+ rw [← addZ_eq' hP hQ, mul_div_cancel_right₀ _ <| mul_ne_zero hPz hQz]
+
+lemma addZ_smul (P Q : Fin 3 → R) (u v : R) :
+ W'.addZ (u • P) (v • Q) = (u * v) ^ 2 * W'.addZ P Q := by
+ simp only [addZ, smul_fin3_ext]
+ ring1
+
+lemma addZ_self (P : Fin 3 → R) : W'.addZ P P = 0 := by
+ rw [addZ]
+ ring1
+
+lemma addZ_of_Z_eq_zero_left [NoZeroDivisors R] {P Q : Fin 3 → R} (hP : W'.Equation P)
+ (hPz : P z = 0) : W'.addZ P Q = P y ^ 2 * Q z * Q z := by
+ rw [addZ, hPz, X_eq_zero_of_Z_eq_zero hP hPz]
+ ring1
+
+lemma addZ_of_Z_eq_zero_right [NoZeroDivisors R] {P Q : Fin 3 → R} (hQ : W'.Equation Q)
+ (hQz : Q z = 0) : W'.addZ P Q = -(Q y ^ 2 * P z) * P z := by
+ rw [addZ, hQz, X_eq_zero_of_Z_eq_zero hQ hQz]
+ ring1
+
+lemma addZ_of_X_eq [NoZeroDivisors R] {P Q : Fin 3 → R} (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'.addZ P Q = 0 := by
+ apply eq_zero_of_ne_zero_of_mul_right_eq_zero <| mul_ne_zero hPz hQz
+ rw [addZ_eq' hP hQ, hx, sub_self, zero_pow three_ne_zero]
+
+lemma addZ_ne_zero_of_X_ne [NoZeroDivisors R] {P Q : Fin 3 → R} (hP : W'.Equation P)
+ (hQ : W'.Equation Q) (hx : P x * Q z ≠ Q x * P z) : W'.addZ P Q ≠ 0 :=
+ addZ_eq' hP hQ ▸ left_ne_zero_of_mul <| pow_ne_zero 3 <| sub_ne_zero.mpr hx
+
+lemma isUnit_addZ_of_X_ne {P Q : Fin 3 → F} (hP : W.Equation P) (hQ : W.Equation Q)
+ (hx : P x * Q z ≠ Q x * P z) : IsUnit <| W.addZ P Q :=
+ (addZ_ne_zero_of_X_ne hP hQ hx).isUnit
+
+private lemma toAffine_slope_of_ne {P Q : Fin 3 → F} (hPz : P z ≠ 0) (hQz : Q z ≠ 0)
+ (hx : P x * Q z ≠ Q x * P z) :
+ W.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z) =
+ (P y * Q z - Q y * P z) / (P x * Q z - Q x * P z) := by
+ field_simp [Affine.slope_of_X_ne <| by rwa [ne_eq, ← X_eq_iff hPz hQz]]
+ ring1
+
+variable (W') in
+/-- The $X$-coordinate of a representative of `P + Q` for two distinct points `P` and `Q`.
+Note that this returns the value 0 if the representatives of `P` and `Q` are equal. -/
+def addX (P Q : Fin 3 → R) : R :=
+ -P x * Q y ^ 2 * P z + Q x * P y ^ 2 * Q z - 2 * P x * P y * Q y * Q z + 2 * Q x * P y * Q y * P z
+ - W'.a₁ * P x ^ 2 * Q y * Q z + W'.a₁ * Q x ^ 2 * P y * P z + W'.a₂ * P x ^ 2 * Q x * Q z
+ - W'.a₂ * P x * Q x ^ 2 * P z - W'.a₃ * P x * P y * Q z ^ 2 + W'.a₃ * Q x * Q y * P z ^ 2
+ - 2 * W'.a₃ * P x * Q y * P z * Q z + 2 * W'.a₃ * Q x * P y * P z * Q z
+ + W'.a₄ * P x ^ 2 * Q z ^ 2 - W'.a₄ * Q x ^ 2 * P z ^ 2 + 3 * W'.a₆ * P x * P z * Q z ^ 2
+ - 3 * W'.a₆ * Q x * P z ^ 2 * Q z
+
+lemma addX_eq' {P Q : Fin 3 → R} (hP : W'.Equation P) (hQ : W'.Equation Q) :
+ W'.addX P Q * (P z * Q z) ^ 2 =
+ ((P y * Q z - Q y * P z) ^ 2 * P z * Q z
+ + W'.a₁ * (P y * Q z - Q y * P z) * P z * Q z * (P x * Q z - Q x * P z)
+ - W'.a₂ * P z * Q z * (P x * Q z - Q x * P z) ^ 2 - P x * Q z * (P x * Q z - Q x * P z) ^ 2
+ - Q x * P z * (P x * Q z - Q x * P z) ^ 2) * (P x * Q z - Q x * P z) := by
+ linear_combination (norm := (rw [addX]; ring1))
+ (2 * Q x * P z * Q z ^ 3 - P x * Q z ^ 4) * (equation_iff _).mp hP
+ + (Q x * P z ^ 4 - 2 * P x * P z ^ 3 * Q z) * (equation_iff _).mp hQ
+
+lemma addX_eq {P Q : Fin 3 → F} (hP : W.Equation P) (hQ : W.Equation Q) (hPz : P z ≠ 0)
+ (hQz : Q z ≠ 0) : W.addX P Q =
+ ((P y * Q z - Q y * P z) ^ 2 * P z * Q z
+ + W.a₁ * (P y * Q z - Q y * P z) * P z * Q z * (P x * Q z - Q x * P z)
+ - W.a₂ * P z * Q z * (P x * Q z - Q x * P z) ^ 2 - P x * Q z * (P x * Q z - Q x * P z) ^ 2
+ - Q x * P z * (P x * Q z - Q x * P z) ^ 2) * (P x * Q z - Q x * P z) / (P z * Q z) ^ 2 := by
+ rw [← addX_eq' hP hQ, mul_div_cancel_right₀ _ <| pow_ne_zero 2 <| mul_ne_zero hPz hQz]
+
+lemma addX_smul (P Q : Fin 3 → R) (u v : R) :
+ W'.addX (u • P) (v • Q) = (u * v) ^ 2 * W'.addX P Q := by
+ simp only [addX, smul_fin3_ext]
+ ring1
+
+lemma addX_self (P : Fin 3 → R) : W'.addX P P = 0 := by
+ rw [addX]
+ ring1
+
+lemma addX_of_Z_eq_zero_left [NoZeroDivisors R] {P Q : Fin 3 → R} (hP : W'.Equation P)
+ (hPz : P z = 0) : W'.addX P Q = P y ^ 2 * Q z * Q x := by
+ rw [addX, hPz, X_eq_zero_of_Z_eq_zero hP hPz]
+ ring1
+
+lemma addX_of_Z_eq_zero_right [NoZeroDivisors R] {P Q : Fin 3 → R} (hQ : W'.Equation Q)
+ (hQz : Q z = 0) : W'.addX P Q = -(Q y ^ 2 * P z) * P x := by
+ rw [addX, hQz, X_eq_zero_of_Z_eq_zero hQ hQz]
+ ring1
+
+lemma addX_of_X_eq [NoZeroDivisors R] {P Q : Fin 3 → R} (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'.addX P Q = 0 := by
+ apply eq_zero_of_ne_zero_of_mul_right_eq_zero <| pow_ne_zero 2 <| mul_ne_zero hPz hQz
+ rw [addX_eq' hP hQ, hx]
+ ring1
+
+private lemma toAffine_addX_of_ne {P Q : Fin 3 → F} (hPz : P z ≠ 0) (hQz : Q z ≠ 0) {n d : F}
+ (hd : d ≠ 0) : W.toAffine.addX (P x / P z) (Q x / Q z) (n / d) =
+ (n ^ 2 * P z * Q z + W.a₁ * n * P z * Q z * d - W.a₂ * P z * Q z * d ^ 2 - P x * Q z * d ^ 2
+ - Q x * P z * d ^ 2) * d / (P z * Q z) ^ 2 / (d ^ 3 / (P z * Q z)) := by
+ field_simp [hd]
+ ring1
+
+lemma addX_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) (hx : P x * Q z ≠ Q x * P z) : W.addX 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)) := by
+ rw [addX_eq hP hQ hPz hQz, addZ_eq hP hQ hPz hQz, toAffine_slope_of_ne hPz hQz hx,
+ toAffine_addX_of_ne hPz hQz <| sub_ne_zero.mpr hx]
+
+variable (W') in
+/-- The $Y$-coordinate of a representative of `-(P + Q)` for two distinct points `P` and `Q`.
+Note that this returns the value 0 if the representatives of `P` and `Q` are equal. -/
+def negAddY (P Q : Fin 3 → R) : R :=
+ -3 * P x ^ 2 * Q x * Q y + 3 * P x * Q x ^ 2 * P y - P y ^ 2 * Q y * Q z + P y * Q y ^ 2 * P z
+ + W'.a₁ * P x * Q y ^ 2 * P z - W'.a₁ * Q x * P y ^ 2 * Q z - W'.a₂ * P x ^ 2 * Q y * Q z
+ + W'.a₂ * Q x ^ 2 * P y * P z + 2 * W'.a₂ * P x * Q x * P y * Q z
+ - 2 * W'.a₂ * P x * Q x * Q y * P z - W'.a₃ * P y ^ 2 * Q z ^ 2 + W'.a₃ * Q y ^ 2 * P z ^ 2
+ + W'.a₄ * P x * P y * Q z ^ 2 - 2 * W'.a₄ * P x * Q y * P z * Q z
+ + 2 * W'.a₄ * Q x * P y * P z * Q z - W'.a₄ * Q x * Q y * P z ^ 2
+ + 3 * W'.a₆ * P y * P z * Q z ^ 2 - 3 * W'.a₆ * Q y * P z ^ 2 * Q z
+
+lemma negAddY_eq' {P Q : Fin 3 → R} (hP : W'.Equation P) (hQ : W'.Equation Q) :
+ W'.negAddY P Q * (P z * Q z) ^ 2 =
+ (P y * Q z - Q y * P z) * ((P y * Q z - Q y * P z) ^ 2 * P z * Q z
+ + W'.a₁ * (P y * Q z - Q y * P z) * P z * Q z * (P x * Q z - Q x * P z)
+ - W'.a₂ * P z * Q z * (P x * Q z - Q x * P z) ^ 2 - P x * Q z * (P x * Q z - Q x * P z) ^ 2
+ - Q x * P z * (P x * Q z - Q x * P z) ^ 2 - P x * Q z * (P x * Q z - Q x * P z) ^ 2)
+ + P y * Q z * (P x * Q z - Q x * P z) ^ 3 := by
+ linear_combination (norm := (rw [negAddY]; ring1))
+ (2 * Q y * P z * Q z ^ 3 - P y * Q z ^ 4) * (equation_iff _).mp hP
+ + (Q y * P z ^ 4 - 2 * P y * P z ^ 3 * Q z) * (equation_iff _).mp hQ
+
+lemma negAddY_eq {P Q : Fin 3 → F} (hP : W.Equation P) (hQ : W.Equation Q) (hPz : P z ≠ 0)
+ (hQz : Q z ≠ 0) : W.negAddY P Q =
+ ((P y * Q z - Q y * P z) * ((P y * Q z - Q y * P z) ^ 2 * P z * Q z
+ + W.a₁ * (P y * Q z - Q y * P z) * P z * Q z * (P x * Q z - Q x * P z)
+ - W.a₂ * P z * Q z * (P x * Q z - Q x * P z) ^ 2 - P x * Q z * (P x * Q z - Q x * P z) ^ 2
+ - Q x * P z * (P x * Q z - Q x * P z) ^ 2 - P x * Q z * (P x * Q z - Q x * P z) ^ 2)
+ + P y * Q z * (P x * Q z - Q x * P z) ^ 3) / (P z * Q z) ^ 2 := by
+ rw [← negAddY_eq' hP hQ, mul_div_cancel_right₀ _ <| pow_ne_zero 2 <| mul_ne_zero hPz hQz]
+
+lemma negAddY_smul (P Q : Fin 3 → R) (u v : R) :
+ W'.negAddY (u • P) (v • Q) = (u * v) ^ 2 * W'.negAddY P Q := by
+ simp only [negAddY, smul_fin3_ext]
+ ring1
+
+lemma negAddY_self (P : Fin 3 → R) : W'.negAddY P P = 0 := by
+ rw [negAddY]
+ ring1
+
+lemma negAddY_of_Z_eq_zero_left [NoZeroDivisors R] {P Q : Fin 3 → R} (hP : W'.Equation P)
+ (hPz : P z = 0) : W'.negAddY P Q = P y ^ 2 * Q z * W'.negY Q := by
+ rw [negAddY, hPz, X_eq_zero_of_Z_eq_zero hP hPz, negY]
+ ring1
+
+lemma negAddY_of_Z_eq_zero_right [NoZeroDivisors R] {P Q : Fin 3 → R} (hQ : W'.Equation Q)
+ (hQz : Q z = 0) : W'.negAddY P Q = -(Q y ^ 2 * P z) * W'.negY P := by
+ rw [negAddY, hQz, X_eq_zero_of_Z_eq_zero hQ hQz, negY]
+ ring1
+
+lemma negAddY_of_X_eq' {P Q : Fin 3 → R} (hP : W'.Equation P) (hQ : W'.Equation Q)
+ (hx : P x * Q z = Q x * P z) :
+ W'.negAddY P Q * (P z * Q z) ^ 2 = (P y * Q z - Q y * P z) ^ 3 * (P z * Q z) := by
+ rw [negAddY_eq' hP hQ, hx]
+ ring1
+
+lemma negAddY_of_X_eq {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.negAddY P Q = -addU P Q := by
+ rw [addU, neg_div, neg_neg, ← mul_div_mul_right _ _ <| mul_ne_zero hPz hQz,
+ ← negAddY_of_X_eq' hP hQ hx, ← sq,
+ mul_div_cancel_right₀ _ <| pow_ne_zero 2 <| mul_ne_zero hPz hQz]
+
+private lemma toAffine_negAddY_of_ne {P Q : Fin 3 → F} (hPz : P z ≠ 0) (hQz : Q z ≠ 0) {n d : F}
+ (hd : d ≠ 0) : W.toAffine.negAddY (P x / P z) (Q x / Q z) (P y / P z) (n / d) =
+ (n * (n ^ 2 * P z * Q z + W.a₁ * n * P z * Q z * d - W.a₂ * P z * Q z * d ^ 2
+ - P x * Q z * d ^ 2 - Q x * P z * d ^ 2 - P x * Q z * d ^ 2) + P y * Q z * d ^ 3)
+ / (P z * Q z) ^ 2 / (d ^ 3 / (P z * Q z)) := by
+ rw [Affine.negAddY, toAffine_addX_of_ne hPz hQz hd]
+ field_simp [mul_ne_zero (pow_ne_zero 2 <| mul_ne_zero hPz hQz) <| pow_ne_zero 3 hd]
+ ring1
+
+lemma negAddY_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) (hx : P x * Q z ≠ Q x * P z) : W.negAddY P Q / W.addZ P Q =
+ W.toAffine.negAddY (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)) := by
+ rw [negAddY_eq hP hQ hPz hQz, addZ_eq hP hQ hPz hQz, toAffine_slope_of_ne hPz hQz hx,
+ toAffine_negAddY_of_ne hPz hQz <| sub_ne_zero.mpr hx]
+
+variable (W') in
+/-- The $Y$-coordinate of a representative of `P + Q` for two distinct points `P` and `Q`.
+Note that this returns the value 0 if the representatives of `P` and `Q` are equal. -/
+def addY (P Q : Fin 3 → R) : R :=
+ W'.negY ![W'.addX P Q, W'.negAddY P Q, W'.addZ P Q]
+
+lemma addY_smul (P Q : Fin 3 → R) (u v : R) :
+ W'.addY (u • P) (v • Q) = (u * v) ^ 2 * W'.addY P Q := by
+ simp only [addY, negY_eq, negAddY_smul, addX_smul, addZ_smul]
+ ring1
+
+lemma addY_self (P : Fin 3 → R) : W'.addY P P = 0 := by
+ simp only [addY, negY_eq, negAddY_self, addX_self, addZ_self, neg_zero, mul_zero, sub_zero]
+
+lemma addY_of_Z_eq_zero_left [NoZeroDivisors R] {P Q : Fin 3 → R} (hP : W'.Equation P)
+ (hPz : P z = 0) : W'.addY P Q = P y ^ 2 * Q z * Q y := by
+ rw [addY, negY_eq, negAddY_of_Z_eq_zero_left hP hPz, negY, addX_of_Z_eq_zero_left hP hPz,
+ addZ_of_Z_eq_zero_left hP hPz]
+ ring1
+
+lemma addY_of_Z_eq_zero_right [NoZeroDivisors R] {P Q : Fin 3 → R} (hQ : W'.Equation Q)
+ (hQz : Q z = 0) : W'.addY P Q = -(Q y ^ 2 * P z) * P y := by
+ rw [addY, negY_eq, negAddY_of_Z_eq_zero_right hQ hQz, negY, addX_of_Z_eq_zero_right hQ hQz,
+ addZ_of_Z_eq_zero_right hQ hQz]
+ ring1
+
+lemma addY_of_X_eq' [NoZeroDivisors R] {P Q : Fin 3 → R} (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'.addY P Q * (P z * Q z) ^ 3 = -(P y * Q z - Q y * P z) ^ 3 * (P z * Q z) ^ 2 := by
+ linear_combination (norm := (rw [addY, negY_eq, addX_of_X_eq hP hQ hPz hQz hx,
+ addZ_of_X_eq hP hQ hPz hQz hx]; ring1)) -(P z * Q z) * negAddY_of_X_eq' hP hQ hx
+
+lemma addY_of_X_eq {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.addY P Q = addU P Q := by
+ rw [addU, ← mul_div_mul_right _ _ <| pow_ne_zero 2 <| mul_ne_zero hPz hQz,
+ ← addY_of_X_eq' hP hQ hPz hQz hx, ← pow_succ',
+ mul_div_cancel_right₀ _ <| pow_ne_zero 3 <| mul_ne_zero hPz hQz]
+
+lemma addY_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) (hx : P x * Q z ≠ Q x * P z) : W.addY P Q / W.addZ P Q =
+ 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)) := by
+ erw [addY, negY_of_Z_ne_zero <| addZ_ne_zero_of_X_ne hP hQ hx, addX_of_Z_ne_zero hP hQ hPz hQz hx,
+ negAddY_of_Z_ne_zero hP hQ hPz hQz hx, Affine.addY]
+
+variable (W') in
+/-- The coordinates of a representative of `P + Q` for two distinct points `P` and `Q`.
+Note that this returns the value `![0, 0, 0]` if the representatives of `P` and `Q` are equal. -/
+noncomputable def addXYZ (P Q : Fin 3 → R) : Fin 3 → R :=
+ ![W'.addX P Q, W'.addY P Q, W'.addZ P Q]
+
+lemma addXYZ_X (P Q : Fin 3 → R) : W'.addXYZ P Q x = W'.addX P Q :=
+ rfl
+
+lemma addXYZ_Y (P Q : Fin 3 → R) : W'.addXYZ P Q y = W'.addY P Q :=
+ rfl
+
+lemma addXYZ_Z (P Q : Fin 3 → R) : W'.addXYZ P Q z = W'.addZ P Q :=
+ rfl
+
+lemma addXYZ_smul (P Q : Fin 3 → R) (u v : R) :
+ W'.addXYZ (u • P) (v • Q) = (u * v) ^ 2 • W'.addXYZ P Q := by
+ rw [addXYZ, addX_smul, addY_smul, addZ_smul, smul_fin3, addXYZ_X, addXYZ_Y, addXYZ_Z]
+
+lemma addXYZ_self (P : Fin 3 → R) : W'.addXYZ P P = ![0, 0, 0] := by
+ rw [addXYZ, addX_self, addY_self, addZ_self]
+
+lemma addXYZ_of_Z_eq_zero_left [NoZeroDivisors R] {P Q : Fin 3 → R} (hP : W'.Equation P)
+ (hPz : P z = 0) : W'.addXYZ P Q = (P y ^ 2 * Q z) • Q := by
+ rw [addXYZ, addX_of_Z_eq_zero_left hP hPz, addY_of_Z_eq_zero_left hP hPz,
+ addZ_of_Z_eq_zero_left hP hPz, smul_fin3]
+
+lemma addXYZ_of_Z_eq_zero_right [NoZeroDivisors R] {P Q : Fin 3 → R} (hQ : W'.Equation Q)
+ (hQz : Q z = 0) : W'.addXYZ P Q = -(Q y ^ 2 * P z) • P := by
+ rw [addXYZ, addX_of_Z_eq_zero_right hQ hQz, addY_of_Z_eq_zero_right hQ hQz,
+ addZ_of_Z_eq_zero_right hQ hQz, smul_fin3]
+
+lemma addXYZ_of_X_eq {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.addXYZ P Q = addU P Q • ![0, 1, 0] := by
+ erw [addXYZ, addX_of_X_eq hP hQ hPz hQz hx, addY_of_X_eq hP hQ hPz hQz hx,
+ addZ_of_X_eq hP hQ hPz hQz hx, smul_fin3, mul_zero, mul_one]
+
+lemma addXYZ_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) (hx : P x * Q z ≠ Q x * P z) : W.addXYZ 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
+ have hZ : IsUnit <| W.addZ P Q := isUnit_addZ_of_X_ne hP hQ hx
+ erw [addXYZ, smul_fin3, ← addX_of_Z_ne_zero hP hQ hPz hQz hx, hZ.mul_div_cancel,
+ ← addY_of_Z_ne_zero hP hQ hPz hQz hx, hZ.mul_div_cancel, mul_one]
+
+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
new file mode 100644
index 0000000000000..77ea4968688e9
--- /dev/null
+++ b/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean
@@ -0,0 +1,325 @@
+/-
+Copyright (c) 2024 Jz Pan. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Kevin Buzzard, David Kurniadi Angdinata, Jz Pan
+-/
+import Mathlib.AlgebraicGeometry.EllipticCurve.Weierstrass
+
+/-!
+# Change of variables of Weierstrass curves
+
+This file defines admissible linear change of variables of Weierstrass curves.
+
+## Main definitions
+
+ * `WeierstrassCurve.VariableChange`: a change of variables of Weierstrass curves.
+ * `WeierstrassCurve.variableChange`: the Weierstrass curve induced by a change of variables.
+ * `WeierstrassCurve.instMulActionVariableChange`: change of variables act on Weierstrass curves.
+ * `EllipticCurve.variableChange`: the elliptic curve induced by a change of variables.
+ * `EllipticCurve.instMulActionVariableChange`: change of variables act on elliptic curves.
+
+## Main statements
+
+ * `EllipticCurve.variableChange_j`: the j-invariant of an elliptic curve is invariant under an
+ admissible linear change of variables.
+
+## References
+
+ * [J Silverman, *The Arithmetic of Elliptic Curves*][silverman2009]
+
+## Tags
+
+elliptic curve, weierstrass equation, change of variables
+-/
+
+local macro "map_simp" : tactic =>
+ `(tactic| simp only [map_ofNat, map_neg, map_add, map_sub, map_mul, map_pow])
+
+universe s u v w
+
+namespace WeierstrassCurve
+
+variable {R : Type u} [CommRing R] (W : WeierstrassCurve R)
+
+section VariableChange
+
+/-! ### Variable changes -/
+
+/-- An admissible linear change of variables of Weierstrass curves defined over a ring `R` given by
+a tuple $(u, r, s, t)$ for some $u \in R^\times$ and some $r, s, t \in R$. As a matrix, it is
+$\begin{pmatrix} u^2 & 0 & r \cr u^2s & u^3 & t \cr 0 & 0 & 1 \end{pmatrix}$. -/
+@[ext]
+structure VariableChange (R : Type u) [CommRing R] where
+ /-- The `u` coefficient of an admissible linear change of variables, which must be a unit. -/
+ u : Rˣ
+ /-- The `r` coefficient of an admissible linear change of variables. -/
+ r : R
+ /-- The `s` coefficient of an admissible linear change of variables. -/
+ s : R
+ /-- The `t` coefficient of an admissible linear change of variables. -/
+ t : R
+
+namespace VariableChange
+
+variable (C C' : VariableChange R)
+
+/-- The identity linear change of variables given by the identity matrix. -/
+def id : VariableChange R :=
+ ⟨1, 0, 0, 0⟩
+
+/-- The composition of two linear changes of variables given by matrix multiplication. -/
+def comp : VariableChange R where
+ u := C.u * C'.u
+ r := C.r * C'.u ^ 2 + C'.r
+ s := C'.u * C.s + C'.s
+ t := C.t * C'.u ^ 3 + C.r * C'.s * C'.u ^ 2 + C'.t
+
+/-- The inverse of a linear change of variables given by matrix inversion. -/
+def inv : VariableChange R where
+ u := C.u⁻¹
+ r := -C.r * C.u⁻¹ ^ 2
+ s := -C.s * C.u⁻¹
+ t := (C.r * C.s - C.t) * C.u⁻¹ ^ 3
+
+lemma id_comp (C : VariableChange R) : comp id C = C := by
+ simp only [comp, id, zero_add, zero_mul, mul_zero, one_mul]
+
+lemma comp_id (C : VariableChange R) : comp C id = C := by
+ simp only [comp, id, add_zero, mul_zero, one_mul, mul_one, one_pow, Units.val_one]
+
+lemma comp_left_inv (C : VariableChange R) : comp (inv C) C = id := by
+ rw [comp, id, inv]
+ ext <;> dsimp only
+ · exact C.u.inv_mul
+ · linear_combination (norm := ring1) -C.r * pow_mul_pow_eq_one 2 C.u.inv_mul
+ · linear_combination (norm := ring1) -C.s * C.u.inv_mul
+ · linear_combination (norm := ring1) (C.r * C.s - C.t) * pow_mul_pow_eq_one 3 C.u.inv_mul
+ + -C.r * C.s * pow_mul_pow_eq_one 2 C.u.inv_mul
+
+lemma comp_assoc (C C' C'' : VariableChange R) : comp (comp C C') C'' = comp C (comp C' C'') := by
+ ext <;> simp only [comp, Units.val_mul] <;> ring1
+
+instance instGroup : Group (VariableChange R) where
+ one := id
+ inv := inv
+ mul := comp
+ one_mul := id_comp
+ mul_one := comp_id
+ inv_mul_cancel := comp_left_inv
+ mul_assoc := comp_assoc
+
+end VariableChange
+
+variable (C : VariableChange R)
+
+/-- The Weierstrass curve over `R` induced by an admissible linear change of variables
+$(X, Y) \mapsto (u^2X + r, u^3Y + u^2sX + t)$ for some $u \in R^\times$ and some $r, s, t \in R$. -/
+@[simps]
+def variableChange : WeierstrassCurve R where
+ a₁ := C.u⁻¹ * (W.a₁ + 2 * C.s)
+ a₂ := C.u⁻¹ ^ 2 * (W.a₂ - C.s * W.a₁ + 3 * C.r - C.s ^ 2)
+ a₃ := C.u⁻¹ ^ 3 * (W.a₃ + C.r * W.a₁ + 2 * C.t)
+ a₄ := C.u⁻¹ ^ 4 * (W.a₄ - C.s * W.a₃ + 2 * C.r * W.a₂ - (C.t + C.r * C.s) * W.a₁ + 3 * C.r ^ 2
+ - 2 * C.s * C.t)
+ a₆ := C.u⁻¹ ^ 6 * (W.a₆ + C.r * W.a₄ + C.r ^ 2 * W.a₂ + C.r ^ 3 - C.t * W.a₃ - C.t ^ 2
+ - C.r * C.t * W.a₁)
+
+lemma variableChange_id : W.variableChange VariableChange.id = W := by
+ rw [VariableChange.id, variableChange, inv_one, Units.val_one]
+ ext <;> (dsimp only; ring1)
+
+lemma variableChange_comp (C C' : VariableChange R) (W : WeierstrassCurve R) :
+ W.variableChange (C.comp C') = (W.variableChange C').variableChange C := by
+ simp only [VariableChange.comp, variableChange]
+ ext <;> simp only [mul_inv, Units.val_mul]
+ · linear_combination (norm := ring1) ↑C.u⁻¹ * C.s * 2 * C'.u.inv_mul
+ · linear_combination (norm := ring1)
+ C.s * (-C'.s * 2 - W.a₁) * C.u⁻¹ ^ 2 * ↑C'.u⁻¹ * C'.u.inv_mul
+ + (C.r * 3 - C.s ^ 2) * C.u⁻¹ ^ 2 * pow_mul_pow_eq_one 2 C'.u.inv_mul
+ · linear_combination (norm := ring1)
+ C.r * (C'.s * 2 + W.a₁) * C.u⁻¹ ^ 3 * ↑C'.u⁻¹ * pow_mul_pow_eq_one 2 C'.u.inv_mul
+ + C.t * 2 * C.u⁻¹ ^ 3 * pow_mul_pow_eq_one 3 C'.u.inv_mul
+ · linear_combination (norm := ring1)
+ C.s * (-W.a₃ - C'.r * W.a₁ - C'.t * 2) * C.u⁻¹ ^ 4 * C'.u⁻¹ ^ 3 * C'.u.inv_mul
+ + C.u⁻¹ ^ 4 * C'.u⁻¹ ^ 2 * (C.r * C'.r * 6 + C.r * W.a₂ * 2 - C'.s * C.r * W.a₁ * 2
+ - C'.s ^ 2 * C.r * 2) * pow_mul_pow_eq_one 2 C'.u.inv_mul
+ - C.u⁻¹ ^ 4 * ↑C'.u⁻¹ * (C.s * C'.s * C.r * 2 + C.s * C.r * W.a₁ + C'.s * C.t * 2
+ + C.t * W.a₁) * pow_mul_pow_eq_one 3 C'.u.inv_mul
+ + C.u⁻¹ ^ 4 * (C.r ^ 2 * 3 - C.s * C.t * 2) * pow_mul_pow_eq_one 4 C'.u.inv_mul
+ · linear_combination (norm := ring1)
+ C.r * C.u⁻¹ ^ 6 * C'.u⁻¹ ^ 4 * (C'.r * W.a₂ * 2 - C'.r * C'.s * W.a₁ + C'.r ^ 2 * 3 + W.a₄
+ - C'.s * C'.t * 2 - C'.s * W.a₃ - C'.t * W.a₁) * pow_mul_pow_eq_one 2 C'.u.inv_mul
+ - C.u⁻¹ ^ 6 * C'.u⁻¹ ^ 3 * C.t * (C'.r * W.a₁ + C'.t * 2 + W.a₃)
+ * pow_mul_pow_eq_one 3 C'.u.inv_mul
+ + C.r ^ 2 * C.u⁻¹ ^ 6 * C'.u⁻¹ ^ 2 * (C'.r * 3 + W.a₂ - C'.s * W.a₁ - C'.s ^ 2)
+ * pow_mul_pow_eq_one 4 C'.u.inv_mul
+ - C.r * C.t * C.u⁻¹ ^ 6 * ↑C'.u⁻¹ * (C'.s * 2 + W.a₁) * pow_mul_pow_eq_one 5 C'.u.inv_mul
+ + C.u⁻¹ ^ 6 * (C.r ^ 3 - C.t ^ 2) * pow_mul_pow_eq_one 6 C'.u.inv_mul
+
+instance instMulActionVariableChange : MulAction (VariableChange R) (WeierstrassCurve R) where
+ smul := fun C W => W.variableChange C
+ one_smul := variableChange_id
+ mul_smul := variableChange_comp
+
+@[simp]
+lemma variableChange_b₂ : (W.variableChange C).b₂ = C.u⁻¹ ^ 2 * (W.b₂ + 12 * C.r) := by
+ simp only [b₂, variableChange_a₁, variableChange_a₂]
+ ring1
+
+@[simp]
+lemma variableChange_b₄ :
+ (W.variableChange C).b₄ = C.u⁻¹ ^ 4 * (W.b₄ + C.r * W.b₂ + 6 * C.r ^ 2) := by
+ simp only [b₂, b₄, variableChange_a₁, variableChange_a₃, variableChange_a₄]
+ ring1
+
+@[simp]
+lemma variableChange_b₆ : (W.variableChange C).b₆ =
+ C.u⁻¹ ^ 6 * (W.b₆ + 2 * C.r * W.b₄ + C.r ^ 2 * W.b₂ + 4 * C.r ^ 3) := by
+ simp only [b₂, b₄, b₆, variableChange_a₃, variableChange_a₆]
+ ring1
+
+@[simp]
+lemma variableChange_b₈ : (W.variableChange C).b₈ = C.u⁻¹ ^ 8 *
+ (W.b₈ + 3 * C.r * W.b₆ + 3 * C.r ^ 2 * W.b₄ + C.r ^ 3 * W.b₂ + 3 * C.r ^ 4) := by
+ simp only [b₂, b₄, b₆, b₈, variableChange_a₁, variableChange_a₂, variableChange_a₃,
+ variableChange_a₄, variableChange_a₆]
+ ring1
+
+@[simp]
+lemma variableChange_c₄ : (W.variableChange C).c₄ = C.u⁻¹ ^ 4 * W.c₄ := by
+ simp only [c₄, variableChange_b₂, variableChange_b₄]
+ ring1
+
+@[simp]
+lemma variableChange_c₆ : (W.variableChange C).c₆ = C.u⁻¹ ^ 6 * W.c₆ := by
+ simp only [c₆, variableChange_b₂, variableChange_b₄, variableChange_b₆]
+ ring1
+
+@[simp]
+lemma variableChange_Δ : (W.variableChange C).Δ = C.u⁻¹ ^ 12 * W.Δ := by
+ simp only [b₂, b₄, b₆, b₈, Δ, variableChange_a₁, variableChange_a₂, variableChange_a₃,
+ variableChange_a₄, variableChange_a₆]
+ ring1
+
+end VariableChange
+
+section BaseChange
+
+/-! ### Maps and base changes of variable changes -/
+
+variable {A : Type v} [CommRing A] (φ : R →+* A)
+
+namespace VariableChange
+
+variable (C : VariableChange R)
+
+/-- The change of variables mapped over a ring homomorphism `φ : R →+* A`. -/
+@[simps]
+def map : VariableChange A :=
+ ⟨Units.map φ C.u, φ C.r, φ C.s, φ C.t⟩
+
+variable (A)
+
+/-- The change of variables base changed to an algebra `A` over `R`. -/
+abbrev baseChange [Algebra R A] : VariableChange A :=
+ C.map <| algebraMap R A
+
+variable {A}
+
+@[simp]
+lemma map_id : C.map (RingHom.id R) = C :=
+ rfl
+
+lemma map_map {A : Type v} [CommRing A] (φ : R →+* A) {B : Type w} [CommRing B] (ψ : A →+* B) :
+ (C.map φ).map ψ = C.map (ψ.comp φ) :=
+ rfl
+
+@[simp]
+lemma map_baseChange {S : Type s} [CommRing S] [Algebra R S] {A : Type v} [CommRing A] [Algebra R A]
+ [Algebra S A] [IsScalarTower R S A] {B : Type w} [CommRing B] [Algebra R B] [Algebra S B]
+ [IsScalarTower R S B] (ψ : A →ₐ[S] B) : (C.baseChange A).map ψ = C.baseChange B :=
+ congr_arg C.map <| ψ.comp_algebraMap_of_tower R
+
+lemma map_injective {φ : R →+* A} (hφ : Function.Injective φ) :
+ Function.Injective <| map (φ := φ) := fun _ _ h => by
+ rcases mk.inj h with ⟨h, _, _, _⟩
+ replace h := (Units.mk.inj h).left
+ ext <;> apply_fun _ using hφ <;> assumption
+
+private lemma id_map : (id : VariableChange R).map φ = id := by
+ simp only [id, map]
+ ext <;> simp only [map_one, Units.val_one, map_zero]
+
+private lemma comp_map (C' : VariableChange R) : (C.comp C').map φ = (C.map φ).comp (C'.map φ) := by
+ simp only [comp, map]
+ ext <;> map_simp <;> simp only [Units.coe_map, Units.coe_map_inv, MonoidHom.coe_coe]
+
+/-- The map over a ring homomorphism of a change of variables is a group homomorphism. -/
+def mapHom : VariableChange R →* VariableChange A where
+ toFun := map φ
+ map_one' := id_map φ
+ map_mul' := comp_map φ
+
+end VariableChange
+
+lemma map_variableChange (C : VariableChange R) :
+ (W.map φ).variableChange (C.map φ) = (W.variableChange C).map φ := by
+ simp only [map, variableChange, VariableChange.map]
+ ext <;> map_simp <;> simp only [Units.coe_map, Units.coe_map_inv, MonoidHom.coe_coe]
+
+end BaseChange
+
+end WeierstrassCurve
+
+/-! ## Variable changes of elliptic curves -/
+
+namespace EllipticCurve
+
+variable {R : Type u} [CommRing R]
+
+variable (E : EllipticCurve R)
+
+section VariableChange
+
+variable (C : WeierstrassCurve.VariableChange R)
+
+-- Porting note: was just `@[simps]`
+/-- The elliptic curve over `R` induced by an admissible linear change of variables
+$(X, Y) \mapsto (u^2X + r, u^3Y + u^2sX + t)$ for some $u \in R^\times$ and some $r, s, t \in R$.
+When `R` is a field, any two Weierstrass equations isomorphic to `E` are related by this. -/
+@[simps (config := { rhsMd := .default }) a₁ a₂ a₃ a₄ a₆ Δ' toWeierstrassCurve]
+def variableChange : EllipticCurve R :=
+ ⟨E.toWeierstrassCurve.variableChange C, C.u⁻¹ ^ 12 * E.Δ', by
+ rw [Units.val_mul, Units.val_pow_eq_pow_val, coe_Δ', E.variableChange_Δ]⟩
+
+lemma variableChange_id : E.variableChange WeierstrassCurve.VariableChange.id = E := by
+ simp only [variableChange, WeierstrassCurve.variableChange_id]
+ simp only [WeierstrassCurve.VariableChange.id, inv_one, one_pow, one_mul]
+
+lemma variableChange_comp (C C' : WeierstrassCurve.VariableChange R) (E : EllipticCurve R) :
+ E.variableChange (C.comp C') = (E.variableChange C').variableChange C := by
+ simp only [variableChange, WeierstrassCurve.variableChange_comp]
+ simp only [WeierstrassCurve.VariableChange.comp, mul_inv, mul_pow, ← mul_assoc]
+
+instance instMulActionVariableChange :
+ MulAction (WeierstrassCurve.VariableChange R) (EllipticCurve R) where
+ smul := fun C E => E.variableChange C
+ one_smul := variableChange_id
+ mul_smul := variableChange_comp
+
+lemma coe_variableChange_Δ' : (E.variableChange C).Δ' = C.u⁻¹ ^ 12 * E.Δ' :=
+ rfl
+
+lemma coe_inv_variableChange_Δ' : (E.variableChange C).Δ'⁻¹ = C.u ^ 12 * E.Δ'⁻¹ := by
+ rw [variableChange_Δ', mul_inv, inv_pow, inv_inv]
+
+@[simp]
+lemma variableChange_j : (E.variableChange C).j = E.j := by
+ rw [j, coe_inv_variableChange_Δ', Units.val_mul, Units.val_pow_eq_pow_val,
+ variableChange_toWeierstrassCurve, WeierstrassCurve.variableChange_c₄]
+ have hu : (C.u * C.u⁻¹ : R) ^ 12 = 1 := by rw [C.u.mul_inv, one_pow]
+ linear_combination (norm := (rw [j]; ring1)) E.j * hu
+
+end VariableChange
+
+end EllipticCurve
diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean
index 5bb09227528a8..9d730cf3c9239 100644
--- a/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean
+++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean
@@ -3,6 +3,7 @@ Copyright (c) 2021 Kevin Buzzard. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kevin Buzzard, David Kurniadi Angdinata
-/
+import Mathlib.Algebra.CharP.Defs
import Mathlib.Algebra.CubicDiscriminant
import Mathlib.Tactic.FieldSimp
import Mathlib.Tactic.LinearCombination
@@ -33,8 +34,6 @@ splitting field of `R` are precisely the $X$-coordinates of the non-zero 2-torsi
* `WeierstrassCurve.ofJ0`: a Weierstrass curve whose j-invariant is 0.
* `WeierstrassCurve.ofJ1728`: a Weierstrass curve whose j-invariant is 1728.
* `WeierstrassCurve.ofJ`: a Weierstrass curve whose j-invariant is neither 0 nor 1728.
- * `WeierstrassCurve.VariableChange`: a change of variables of Weierstrass curves.
- * `WeierstrassCurve.variableChange`: the Weierstrass curve induced by a change of variables.
* `WeierstrassCurve.map`: the Weierstrass curve mapped over a ring homomorphism.
* `WeierstrassCurve.twoTorsionPolynomial`: the 2-torsion polynomial of a Weierstrass curve.
* `EllipticCurve`: an elliptic curve over a commutative ring.
@@ -48,8 +47,6 @@ splitting field of `R` are precisely the $X$-coordinates of the non-zero 2-torsi
* `WeierstrassCurve.twoTorsionPolynomial_disc`: the discriminant of a Weierstrass curve is a
constant factor of the cubic discriminant of its 2-torsion polynomial.
- * `EllipticCurve.variableChange_j`: the j-invariant of an elliptic curve is invariant under an
- admissible linear change of variables.
* `EllipticCurve.ofJ_j`: the j-invariant of `EllipticCurve.ofJ` is equal to j.
## Implementation notes
@@ -106,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
@@ -130,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
@@ -152,169 +142,89 @@ lemma c_relation : 1728 * W.Δ = W.c₄ ^ 3 - W.c₆ ^ 2 := by
simp only [b₂, b₄, b₆, b₈, c₄, c₆, Δ]
ring1
-end Quantity
+section CharTwo
-section VariableChange
+variable [CharP R 2]
-/-! ### Variable changes -/
+lemma b₂_of_char_two : W.b₂ = W.a₁ ^ 2 := by
+ rw [b₂]
+ linear_combination 2 * W.a₂ * CharP.cast_eq_zero R 2
-/-- An admissible linear change of variables of Weierstrass curves defined over a ring `R` given by
-a tuple $(u, r, s, t)$ for some $u \in R^\times$ and some $r, s, t \in R$. As a matrix, it is
-$\begin{pmatrix} u^2 & 0 & r \cr u^2s & u^3 & t \cr 0 & 0 & 1 \end{pmatrix}$. -/
-@[ext]
-structure VariableChange (R : Type u) [CommRing R] where
- /-- The `u` coefficient of an admissible linear change of variables, which must be a unit. -/
- u : Rˣ
- /-- The `r` coefficient of an admissible linear change of variables. -/
- r : R
- /-- The `s` coefficient of an admissible linear change of variables. -/
- s : R
- /-- The `t` coefficient of an admissible linear change of variables. -/
- t : R
-
-namespace VariableChange
-
-variable (C C' C'' : VariableChange R)
-
-/-- The identity linear change of variables given by the identity matrix. -/
-def id : VariableChange R :=
- ⟨1, 0, 0, 0⟩
-
-/-- The composition of two linear changes of variables given by matrix multiplication. -/
-def comp : VariableChange R where
- u := C.u * C'.u
- r := C.r * C'.u ^ 2 + C'.r
- s := C'.u * C.s + C'.s
- t := C.t * C'.u ^ 3 + C.r * C'.s * C'.u ^ 2 + C'.t
-
-/-- The inverse of a linear change of variables given by matrix inversion. -/
-def inv : VariableChange R where
- u := C.u⁻¹
- r := -C.r * C.u⁻¹ ^ 2
- s := -C.s * C.u⁻¹
- t := (C.r * C.s - C.t) * C.u⁻¹ ^ 3
-
-lemma id_comp (C : VariableChange R) : comp id C = C := by
- simp only [comp, id, zero_add, zero_mul, mul_zero, one_mul]
-
-lemma comp_id (C : VariableChange R) : comp C id = C := by
- simp only [comp, id, add_zero, mul_zero, one_mul, mul_one, one_pow, Units.val_one]
-
-lemma comp_left_inv (C : VariableChange R) : comp (inv C) C = id := by
- rw [comp, id, inv]
- ext <;> dsimp only
- · exact C.u.inv_mul
- · linear_combination (norm := ring1) -C.r * pow_mul_pow_eq_one 2 C.u.inv_mul
- · linear_combination (norm := ring1) -C.s * C.u.inv_mul
- · linear_combination (norm := ring1) (C.r * C.s - C.t) * pow_mul_pow_eq_one 3 C.u.inv_mul
- + -C.r * C.s * pow_mul_pow_eq_one 2 C.u.inv_mul
-
-lemma comp_assoc (C C' C'' : VariableChange R) : comp (comp C C') C'' = comp C (comp C' C'') := by
- ext <;> simp only [comp, Units.val_mul] <;> ring1
-
-instance instGroup : Group (VariableChange R) where
- one := id
- inv := inv
- mul := comp
- one_mul := id_comp
- mul_one := comp_id
- inv_mul_cancel := comp_left_inv
- mul_assoc := comp_assoc
-
-end VariableChange
-
-variable (C : VariableChange R)
-
-/-- The Weierstrass curve over `R` induced by an admissible linear change of variables
-$(X, Y) \mapsto (u^2X + r, u^3Y + u^2sX + t)$ for some $u \in R^\times$ and some $r, s, t \in R$. -/
-@[simps]
-def variableChange : WeierstrassCurve R where
- a₁ := C.u⁻¹ * (W.a₁ + 2 * C.s)
- a₂ := C.u⁻¹ ^ 2 * (W.a₂ - C.s * W.a₁ + 3 * C.r - C.s ^ 2)
- a₃ := C.u⁻¹ ^ 3 * (W.a₃ + C.r * W.a₁ + 2 * C.t)
- a₄ := C.u⁻¹ ^ 4 * (W.a₄ - C.s * W.a₃ + 2 * C.r * W.a₂ - (C.t + C.r * C.s) * W.a₁ + 3 * C.r ^ 2
- - 2 * C.s * C.t)
- a₆ := C.u⁻¹ ^ 6 * (W.a₆ + C.r * W.a₄ + C.r ^ 2 * W.a₂ + C.r ^ 3 - C.t * W.a₃ - C.t ^ 2
- - C.r * C.t * W.a₁)
-
-lemma variableChange_id : W.variableChange VariableChange.id = W := by
- rw [VariableChange.id, variableChange, inv_one, Units.val_one]
- ext <;> (dsimp only; ring1)
-
-lemma variableChange_comp (C C' : VariableChange R) (W : WeierstrassCurve R) :
- W.variableChange (C.comp C') = (W.variableChange C').variableChange C := by
- simp only [VariableChange.comp, variableChange]
- ext <;> simp only [mul_inv, Units.val_mul]
- · linear_combination (norm := ring1) C.u⁻¹ * C.s * 2 * C'.u.inv_mul
- · linear_combination (norm := ring1)
- C.s * (-C'.s * 2 - W.a₁) * C.u⁻¹ ^ 2 * C'.u⁻¹ * C'.u.inv_mul
- + (C.r * 3 - C.s ^ 2) * C.u⁻¹ ^ 2 * pow_mul_pow_eq_one 2 C'.u.inv_mul
- · linear_combination (norm := ring1)
- C.r * (C'.s * 2 + W.a₁) * C.u⁻¹ ^ 3 * C'.u⁻¹ * pow_mul_pow_eq_one 2 C'.u.inv_mul
- + C.t * 2 * C.u⁻¹ ^ 3 * pow_mul_pow_eq_one 3 C'.u.inv_mul
- · linear_combination (norm := ring1)
- C.s * (-W.a₃ - C'.r * W.a₁ - C'.t * 2) * C.u⁻¹ ^ 4 * C'.u⁻¹ ^ 3 * C'.u.inv_mul
- + C.u⁻¹ ^ 4 * C'.u⁻¹ ^ 2 * (C.r * C'.r * 6 + C.r * W.a₂ * 2 - C'.s * C.r * W.a₁ * 2
- - C'.s ^ 2 * C.r * 2) * pow_mul_pow_eq_one 2 C'.u.inv_mul
- - C.u⁻¹ ^ 4 * C'.u⁻¹ * (C.s * C'.s * C.r * 2 + C.s * C.r * W.a₁ + C'.s * C.t * 2
- + C.t * W.a₁) * pow_mul_pow_eq_one 3 C'.u.inv_mul
- + C.u⁻¹ ^ 4 * (C.r ^ 2 * 3 - C.s * C.t * 2) * pow_mul_pow_eq_one 4 C'.u.inv_mul
- · linear_combination (norm := ring1)
- C.r * C.u⁻¹ ^ 6 * C'.u⁻¹ ^ 4 * (C'.r * W.a₂ * 2 - C'.r * C'.s * W.a₁ + C'.r ^ 2 * 3 + W.a₄
- - C'.s * C'.t * 2 - C'.s * W.a₃ - C'.t * W.a₁) * pow_mul_pow_eq_one 2 C'.u.inv_mul
- - C.u⁻¹ ^ 6 * C'.u⁻¹ ^ 3 * C.t * (C'.r * W.a₁ + C'.t * 2 + W.a₃)
- * pow_mul_pow_eq_one 3 C'.u.inv_mul
- + C.r ^ 2 * C.u⁻¹ ^ 6 * C'.u⁻¹ ^ 2 * (C'.r * 3 + W.a₂ - C'.s * W.a₁ - C'.s ^ 2)
- * pow_mul_pow_eq_one 4 C'.u.inv_mul
- - C.r * C.t * C.u⁻¹ ^ 6 * C'.u⁻¹ * (C'.s * 2 + W.a₁) * pow_mul_pow_eq_one 5 C'.u.inv_mul
- + C.u⁻¹ ^ 6 * (C.r ^ 3 - C.t ^ 2) * pow_mul_pow_eq_one 6 C'.u.inv_mul
-
-instance instMulActionVariableChange : MulAction (VariableChange R) (WeierstrassCurve R) where
- smul := fun C W => W.variableChange C
- one_smul := variableChange_id
- mul_smul := variableChange_comp
+lemma b₄_of_char_two : W.b₄ = W.a₁ * W.a₃ := by
+ rw [b₄]
+ linear_combination W.a₄ * CharP.cast_eq_zero R 2
-@[simp]
-lemma variableChange_b₂ : (W.variableChange C).b₂ = C.u⁻¹ ^ 2 * (W.b₂ + 12 * C.r) := by
- simp only [b₂, variableChange_a₁, variableChange_a₂]
- ring1
+lemma b₆_of_char_two : W.b₆ = W.a₃ ^ 2 := by
+ rw [b₆]
+ linear_combination 2 * W.a₆ * CharP.cast_eq_zero R 2
-@[simp]
-lemma variableChange_b₄ :
- (W.variableChange C).b₄ = C.u⁻¹ ^ 4 * (W.b₄ + C.r * W.b₂ + 6 * C.r ^ 2) := by
- simp only [b₂, b₄, variableChange_a₁, variableChange_a₃, variableChange_a₄]
- ring1
+lemma b₈_of_char_two :
+ W.b₈ = W.a₁ ^ 2 * W.a₆ + W.a₁ * W.a₃ * W.a₄ + W.a₂ * W.a₃ ^ 2 + W.a₄ ^ 2 := by
+ rw [b₈]
+ linear_combination (2 * W.a₂ * W.a₆ - W.a₁ * W.a₃ * W.a₄ - W.a₄ ^ 2) * CharP.cast_eq_zero R 2
-@[simp]
-lemma variableChange_b₆ : (W.variableChange C).b₆ =
- C.u⁻¹ ^ 6 * (W.b₆ + 2 * C.r * W.b₄ + C.r ^ 2 * W.b₂ + 4 * C.r ^ 3) := by
- simp only [b₂, b₄, b₆, variableChange_a₃, variableChange_a₆]
- ring1
+lemma c₄_of_char_two : W.c₄ = W.a₁ ^ 4 := by
+ rw [c₄, b₂_of_char_two]
+ linear_combination -12 * W.b₄ * CharP.cast_eq_zero R 2
-@[simp]
-lemma variableChange_b₈ : (W.variableChange C).b₈ = C.u⁻¹ ^ 8 *
- (W.b₈ + 3 * C.r * W.b₆ + 3 * C.r ^ 2 * W.b₄ + C.r ^ 3 * W.b₂ + 3 * C.r ^ 4) := by
- simp only [b₂, b₄, b₆, b₈, variableChange_a₁, variableChange_a₂, variableChange_a₃,
- variableChange_a₄, variableChange_a₆]
- ring1
+lemma c₆_of_char_two : W.c₆ = W.a₁ ^ 6 := by
+ rw [c₆, b₂_of_char_two]
+ linear_combination (18 * W.a₁ ^ 2 * W.b₄ - 108 * W.b₆ - W.a₁ ^ 6) * CharP.cast_eq_zero R 2
-@[simp]
-lemma variableChange_c₄ : (W.variableChange C).c₄ = C.u⁻¹ ^ 4 * W.c₄ := by
- simp only [c₄, variableChange_b₂, variableChange_b₄]
- ring1
+lemma Δ_of_char_two : W.Δ = W.a₁ ^ 4 * W.b₈ + W.a₃ ^ 4 + W.a₁ ^ 3 * W.a₃ ^ 3 := by
+ rw [Δ, b₂_of_char_two, b₄_of_char_two, b₆_of_char_two]
+ linear_combination (-W.a₁ ^ 4 * W.b₈ - 14 * W.a₃ ^ 4) * CharP.cast_eq_zero R 2
-@[simp]
-lemma variableChange_c₆ : (W.variableChange C).c₆ = C.u⁻¹ ^ 6 * W.c₆ := by
- simp only [c₆, variableChange_b₂, variableChange_b₄, variableChange_b₆]
- ring1
+lemma b_relation_of_char_two : W.b₂ * W.b₆ = W.b₄ ^ 2 := by
+ linear_combination -W.b_relation + 2 * W.b₈ * CharP.cast_eq_zero R 2
-@[simp]
-lemma variableChange_Δ : (W.variableChange C).Δ = C.u⁻¹ ^ 12 * W.Δ := by
- simp only [b₂, b₄, b₆, b₈, Δ, variableChange_a₁, variableChange_a₂, variableChange_a₃,
- variableChange_a₄, variableChange_a₆]
- ring1
+lemma c_relation_of_char_two : W.c₄ ^ 3 = W.c₆ ^ 2 := by
+ linear_combination -W.c_relation + 864 * W.Δ * CharP.cast_eq_zero R 2
+
+end CharTwo
+
+section CharThree
+
+variable [CharP R 3]
+
+lemma b₂_of_char_three : W.b₂ = W.a₁ ^ 2 + W.a₂ := by
+ rw [b₂]
+ linear_combination W.a₂ * CharP.cast_eq_zero R 3
+
+lemma b₄_of_char_three : W.b₄ = -W.a₄ + W.a₁ * W.a₃ := by
+ rw [b₄]
+ linear_combination W.a₄ * CharP.cast_eq_zero R 3
+
+lemma b₆_of_char_three : W.b₆ = W.a₃ ^ 2 + W.a₆ := by
+ rw [b₆]
+ linear_combination W.a₆ * CharP.cast_eq_zero R 3
+
+lemma b₈_of_char_three :
+ W.b₈ = W.a₁ ^ 2 * W.a₆ + W.a₂ * W.a₆ - W.a₁ * W.a₃ * W.a₄ + W.a₂ * W.a₃ ^ 2 - W.a₄ ^ 2 := by
+ rw [b₈]
+ linear_combination W.a₂ * W.a₆ * CharP.cast_eq_zero R 3
-end VariableChange
+lemma c₄_of_char_three : W.c₄ = W.b₂ ^ 2 := by
+ rw [c₄]
+ linear_combination -8 * W.b₄ * CharP.cast_eq_zero R 3
+
+lemma c₆_of_char_three : W.c₆ = -W.b₂ ^ 3 := by
+ rw [c₆]
+ linear_combination (12 * W.b₂ * W.b₄ - 72 * W.b₆) * CharP.cast_eq_zero R 3
+
+lemma Δ_of_char_three : W.Δ = -W.b₂ ^ 2 * W.b₈ - 8 * W.b₄ ^ 3 := by
+ rw [Δ]
+ linear_combination (-9 * W.b₆ ^ 2 + 3 * W.b₂ * W.b₄ * W.b₆) * CharP.cast_eq_zero R 3
+
+lemma b_relation_of_char_three : W.b₈ = W.b₂ * W.b₆ - W.b₄ ^ 2 := by
+ linear_combination W.b_relation - W.b₈ * CharP.cast_eq_zero R 3
+
+lemma c_relation_of_char_three : W.c₄ ^ 3 = W.c₆ ^ 2 := by
+ linear_combination -W.c_relation + 576 * W.Δ * CharP.cast_eq_zero R 3
+
+end CharThree
+
+end Quantity
section BaseChange
@@ -388,64 +298,6 @@ lemma map_injective {φ : R →+* A} (hφ : Function.Injective φ) :
rcases mk.inj h with ⟨_, _, _, _, _⟩
ext <;> apply_fun _ using hφ <;> assumption
-namespace VariableChange
-
-variable (C : VariableChange R)
-
-/-- The change of variables mapped over a ring homomorphism `φ : R →+* A`. -/
-@[simps]
-def map : VariableChange A :=
- ⟨Units.map φ C.u, φ C.r, φ C.s, φ C.t⟩
-
-variable (A)
-
-/-- The change of variables base changed to an algebra `A` over `R`. -/
-abbrev baseChange [Algebra R A] : VariableChange A :=
- C.map <| algebraMap R A
-
-variable {A}
-
-@[simp]
-lemma map_id : C.map (RingHom.id R) = C :=
- rfl
-
-lemma map_map {A : Type v} [CommRing A] (φ : R →+* A) {B : Type w} [CommRing B] (ψ : A →+* B) :
- (C.map φ).map ψ = C.map (ψ.comp φ) :=
- rfl
-
-@[simp]
-lemma map_baseChange {S : Type s} [CommRing S] [Algebra R S] {A : Type v} [CommRing A] [Algebra R A]
- [Algebra S A] [IsScalarTower R S A] {B : Type w} [CommRing B] [Algebra R B] [Algebra S B]
- [IsScalarTower R S B] (ψ : A →ₐ[S] B) : (C.baseChange A).map ψ = C.baseChange B :=
- congr_arg C.map <| ψ.comp_algebraMap_of_tower R
-
-lemma map_injective {φ : R →+* A} (hφ : Function.Injective φ) :
- Function.Injective <| map (φ := φ) := fun _ _ h => by
- rcases mk.inj h with ⟨h, _, _, _⟩
- replace h := (Units.mk.inj h).left
- ext <;> apply_fun _ using hφ <;> assumption
-
-private lemma id_map : (id : VariableChange R).map φ = id := by
- simp only [id, map]
- ext <;> simp only [map_one, Units.val_one, map_zero]
-
-private lemma comp_map (C' : VariableChange R) : (C.comp C').map φ = (C.map φ).comp (C'.map φ) := by
- simp only [comp, map]
- ext <;> map_simp <;> simp only [Units.coe_map, Units.coe_map_inv, MonoidHom.coe_coe]
-
-/-- The map over a ring homomorphism of a change of variables is a group homomorphism. -/
-def mapHom : VariableChange R →* VariableChange A where
- toFun := map φ
- map_one' := id_map φ
- map_mul' := comp_map φ
-
-end VariableChange
-
-lemma map_variableChange (C : VariableChange R) :
- (W.map φ).variableChange (C.map φ) = (W.variableChange C).map φ := by
- simp only [map, variableChange, VariableChange.map]
- ext <;> map_simp <;> simp only [Units.coe_map, Units.coe_map_inv, MonoidHom.coe_coe]
-
end BaseChange
section TorsionPolynomial
@@ -462,6 +314,36 @@ lemma twoTorsionPolynomial_disc : W.twoTorsionPolynomial.disc = 16 * W.Δ := by
simp only [b₂, b₄, b₆, b₈, Δ, twoTorsionPolynomial, Cubic.disc]
ring1
+section CharTwo
+
+variable [CharP R 2]
+
+lemma twoTorsionPolynomial_of_char_two : W.twoTorsionPolynomial = ⟨0, W.b₂, 0, W.b₆⟩ := by
+ rw [twoTorsionPolynomial]
+ ext <;> dsimp
+ · linear_combination 2 * CharP.cast_eq_zero R 2
+ · linear_combination W.b₄ * CharP.cast_eq_zero R 2
+
+lemma twoTorsionPolynomial_disc_of_char_two : W.twoTorsionPolynomial.disc = 0 := by
+ linear_combination W.twoTorsionPolynomial_disc + 8 * W.Δ * CharP.cast_eq_zero R 2
+
+end CharTwo
+
+section CharThree
+
+variable [CharP R 3]
+
+lemma twoTorsionPolynomial_of_char_three : W.twoTorsionPolynomial = ⟨1, W.b₂, -W.b₄, W.b₆⟩ := by
+ rw [twoTorsionPolynomial]
+ ext <;> dsimp
+ · linear_combination CharP.cast_eq_zero R 3
+ · linear_combination W.b₄ * CharP.cast_eq_zero R 3
+
+lemma twoTorsionPolynomial_disc_of_char_three : W.twoTorsionPolynomial.disc = W.Δ := by
+ linear_combination W.twoTorsionPolynomial_disc + 5 * W.Δ * CharP.cast_eq_zero R 3
+
+end CharThree
+
lemma twoTorsionPolynomial_disc_isUnit [Invertible (2 : R)] :
IsUnit W.twoTorsionPolynomial.disc ↔ IsUnit W.Δ := by
rw [twoTorsionPolynomial_disc, IsUnit.mul_iff, show (16 : R) = 2 ^ 4 by norm_num1]
@@ -526,7 +408,6 @@ end WeierstrassCurve
/-- An elliptic curve over a commutative ring. Note that this definition is only mathematically
accurate for certain rings whose Picard group has trivial 12-torsion, such as a field or a PID. -/
-@[ext]
structure EllipticCurve (R : Type u) [CommRing R] extends WeierstrassCurve R where
/-- The discriminant `Δ'` of an elliptic curve over `R`, which is given as a unit in `R`. -/
Δ' : Rˣ
@@ -535,61 +416,76 @@ structure EllipticCurve (R : Type u) [CommRing R] extends WeierstrassCurve R whe
namespace EllipticCurve
-variable {R : Type u} [CommRing R] (E : EllipticCurve R)
+variable {R : Type u} [CommRing R]
+
+theorem toWeierstrassCurve_injective : Function.Injective (toWeierstrassCurve (R := R))
+ | ⟨x1, _, x3⟩, ⟨y1, _, y3⟩, h => by
+ change x1 = y1 at h
+ congr
+ exact Units.ext (by rw [x3, y3, h])
+
+@[ext]
+theorem ext {x y : EllipticCurve R} (h₁ : x.a₁ = y.a₁) (h₂ : x.a₂ = y.a₂) (h₃ : x.a₃ = y.a₃)
+ (h₄ : x.a₄ = y.a₄) (h₆ : x.a₆ = y.a₆) : x = y :=
+ toWeierstrassCurve_injective (WeierstrassCurve.ext h₁ h₂ h₃ h₄ h₆)
+
+variable (E : EllipticCurve R)
--- 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
-lemma twoTorsionPolynomial_disc_ne_zero [Nontrivial R] [Invertible (2 : R)] :
- E.twoTorsionPolynomial.disc ≠ 0 :=
- E.toWeierstrassCurve.twoTorsionPolynomial_disc_ne_zero <| E.coe_Δ' ▸ E.Δ'.isUnit
+/-- A variant of `EllipticCurve.j_eq_zero_iff` without assuming a reduced ring. -/
+lemma j_eq_zero_iff' : E.j = 0 ↔ E.c₄ ^ 3 = 0 := by
+ rw [j, Units.mul_right_eq_zero]
-section VariableChange
+lemma j_eq_zero (h : E.c₄ = 0) : E.j = 0 := by
+ rw [j_eq_zero_iff', h, zero_pow three_ne_zero]
-/-! ### Variable changes -/
+lemma j_eq_zero_iff [IsReduced R] : E.j = 0 ↔ E.c₄ = 0 := by
+ rw [j_eq_zero_iff', IsReduced.pow_eq_zero_iff three_ne_zero]
-variable (C : WeierstrassCurve.VariableChange R)
+section CharTwo
--- Porting note: was just `@[simps]`
-/-- The elliptic curve over `R` induced by an admissible linear change of variables
-$(X, Y) \mapsto (u^2X + r, u^3Y + u^2sX + t)$ for some $u \in R^\times$ and some $r, s, t \in R$.
-When `R` is a field, any two Weierstrass equations isomorphic to `E` are related by this. -/
-@[simps (config := { rhsMd := .default }) a₁ a₂ a₃ a₄ a₆ Δ' toWeierstrassCurve]
-def variableChange : EllipticCurve R :=
- ⟨E.toWeierstrassCurve.variableChange C, C.u⁻¹ ^ 12 * E.Δ', by
- rw [Units.val_mul, Units.val_pow_eq_pow_val, coe_Δ', E.variableChange_Δ]⟩
-
-lemma variableChange_id : E.variableChange WeierstrassCurve.VariableChange.id = E := by
- simp only [variableChange, WeierstrassCurve.variableChange_id]
- simp only [WeierstrassCurve.VariableChange.id, inv_one, one_pow, one_mul]
-
-lemma variableChange_comp (C C' : WeierstrassCurve.VariableChange R) (E : EllipticCurve R) :
- E.variableChange (C.comp C') = (E.variableChange C').variableChange C := by
- simp only [variableChange, WeierstrassCurve.variableChange_comp]
- simp only [WeierstrassCurve.VariableChange.comp, mul_inv, mul_pow, ← mul_assoc]
-
-instance instMulActionVariableChange :
- MulAction (WeierstrassCurve.VariableChange R) (EllipticCurve R) where
- smul := fun C E => E.variableChange C
- one_smul := variableChange_id
- mul_smul := variableChange_comp
-
-lemma coe_variableChange_Δ' : (E.variableChange C).Δ' = C.u⁻¹ ^ 12 * E.Δ' :=
- rfl
+variable [CharP R 2]
-lemma coe_inv_variableChange_Δ' : (E.variableChange C).Δ'⁻¹ = C.u ^ 12 * E.Δ'⁻¹ := by
- rw [variableChange_Δ', mul_inv, inv_pow, inv_inv]
+lemma j_of_char_two : E.j = E.Δ'⁻¹ * E.a₁ ^ 12 := by
+ rw [j, E.c₄_of_char_two, ← pow_mul]
-@[simp]
-lemma variableChange_j : (E.variableChange C).j = E.j := by
- rw [j, coe_inv_variableChange_Δ', Units.val_mul, Units.val_pow_eq_pow_val,
- variableChange_toWeierstrassCurve, WeierstrassCurve.variableChange_c₄]
- have hu : (C.u * C.u⁻¹ : R) ^ 12 = 1 := by rw [C.u.mul_inv, one_pow]
- linear_combination (norm := (rw [j]; ring1)) E.j * hu
+/-- A variant of `EllipticCurve.j_eq_zero_iff_of_char_two` without assuming a reduced ring. -/
+lemma j_eq_zero_iff_of_char_two' : E.j = 0 ↔ E.a₁ ^ 12 = 0 := by
+ rw [j_of_char_two, Units.mul_right_eq_zero]
+
+lemma j_eq_zero_of_char_two (h : E.a₁ = 0) : E.j = 0 := by
+ rw [j_eq_zero_iff_of_char_two', h, zero_pow (Nat.succ_ne_zero _)]
+
+lemma j_eq_zero_iff_of_char_two [IsReduced R] : E.j = 0 ↔ E.a₁ = 0 := by
+ rw [j_eq_zero_iff_of_char_two', IsReduced.pow_eq_zero_iff (Nat.succ_ne_zero _)]
-end VariableChange
+end CharTwo
+
+section CharThree
+
+variable [CharP R 3]
+
+lemma j_of_char_three : E.j = E.Δ'⁻¹ * E.b₂ ^ 6 := by
+ rw [j, E.c₄_of_char_three, ← pow_mul]
+
+/-- A variant of `EllipticCurve.j_eq_zero_iff_of_char_three` without assuming a reduced ring. -/
+lemma j_eq_zero_iff_of_char_three' : E.j = 0 ↔ E.b₂ ^ 6 = 0 := by
+ rw [j_of_char_three, Units.mul_right_eq_zero]
+
+lemma j_eq_zero_of_char_three (h : E.b₂ = 0) : E.j = 0 := by
+ rw [j_eq_zero_iff_of_char_three', h, zero_pow (Nat.succ_ne_zero _)]
+
+lemma j_eq_zero_iff_of_char_three [IsReduced R] : E.j = 0 ↔ E.b₂ = 0 := by
+ rw [j_eq_zero_iff_of_char_three', IsReduced.pow_eq_zero_iff (Nat.succ_ne_zero _)]
+
+end CharThree
+
+lemma twoTorsionPolynomial_disc_ne_zero [Nontrivial R] [Invertible (2 : R)] :
+ E.twoTorsionPolynomial.disc ≠ 0 :=
+ E.toWeierstrassCurve.twoTorsionPolynomial_disc_ne_zero <| E.coe_Δ' ▸ E.Δ'.isUnit
section BaseChange
@@ -623,8 +519,7 @@ lemma map_j : (E.map φ).j = φ E.j := by
lemma map_injective {φ : R →+* A} (hφ : Function.Injective φ) :
Function.Injective <| map (φ := φ) := fun _ _ h => by
- rcases mk.inj h with ⟨h1, h2⟩
- replace h2 := (Units.mk.inj h2).left
+ rcases mk.inj h with ⟨h1, _⟩
rcases WeierstrassCurve.mk.inj h1 with ⟨_, _, _, _, _⟩
ext <;> apply_fun _ using hφ <;> assumption
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 807cd5593bbde..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. -/
@@ -314,22 +302,21 @@ theorem right_triangle (R : CommRingCat) :
/-- The adjunction `Γ ⊣ Spec` from `CommRingᵒᵖ` to `LocallyRingedSpace`. -/
-- Porting note: `simps` cause a time out, so `Unit` and `counit` will be added manually
-def locallyRingedSpaceAdjunction : Γ.rightOp ⊣ Spec.toLocallyRingedSpace.{u} :=
- Adjunction.mkOfUnitCounit
- { unit := identityToΓSpec
- counit := (NatIso.op SpecΓIdentity).inv
- left_triangle := by
- ext X; erw [Category.id_comp]
- exact congr_arg Quiver.Hom.op (left_triangle X)
- right_triangle := by
- ext R : 2
- -- Porting note: a little bit hand holding
- change identityToΓSpec.app _ ≫ 𝟙 _ ≫ Spec.toLocallyRingedSpace.map _ =
- 𝟙 _
- simp_rw [Category.id_comp, show (NatIso.op SpecΓIdentity).inv.app R =
- (SpecΓIdentity.inv.app R.unop).op from rfl]
- exact right_triangle R.unop
- }
+def locallyRingedSpaceAdjunction : Γ.rightOp ⊣ Spec.toLocallyRingedSpace.{u} where
+ unit := identityToΓSpec
+ counit := (NatIso.op SpecΓIdentity).inv
+ left_triangle_components X := by
+ simp only [Functor.id_obj, Functor.rightOp_obj, Γ_obj, Functor.comp_obj,
+ Spec.toLocallyRingedSpace_obj, Spec.locallyRingedSpaceObj_toSheafedSpace,
+ Spec.sheafedSpaceObj_carrier, Spec.sheafedSpaceObj_presheaf, Functor.rightOp_map, Γ_map,
+ Quiver.Hom.unop_op, NatIso.op_inv, NatTrans.op_app, SpecΓIdentity_inv_app]
+ exact congr_arg Quiver.Hom.op (left_triangle X)
+ right_triangle_components R := by
+ simp only [Spec.toLocallyRingedSpace_obj, Functor.id_obj, Functor.comp_obj, Functor.rightOp_obj,
+ Γ_obj, Spec.locallyRingedSpaceObj_toSheafedSpace, Spec.sheafedSpaceObj_carrier,
+ Spec.sheafedSpaceObj_presheaf, NatIso.op_inv, NatTrans.op_app, op_unop, SpecΓIdentity_inv_app,
+ Spec.toLocallyRingedSpace_map, Quiver.Hom.unop_op]
+ exact right_triangle R.unop
lemma locallyRingedSpaceAdjunction_unit :
locallyRingedSpaceAdjunction.unit = identityToΓSpec := rfl
@@ -363,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,
@@ -376,25 +363,24 @@ lemma toOpen_comp_locallyRingedSpaceAdjunction_homEquiv_app
/-- The adjunction `Γ ⊣ Spec` from `CommRingᵒᵖ` to `Scheme`. -/
def adjunction : Scheme.Γ.rightOp ⊣ Scheme.Spec.{u} where
- homEquiv 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 }
+ { 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
- homEquiv_unit := rfl
- homEquiv_counit := rfl
+ 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
@@ -403,14 +389,13 @@ theorem adjunction_counit_app' {R : CommRingCatᵒᵖ} :
theorem adjunction_counit_app {R : CommRingCatᵒᵖ} :
ΓSpec.adjunction.counit.app R = (Scheme.ΓSpecIso (unop R)).inv.op := rfl
--- This is not a simp lemma to respect the abstraction
-theorem adjunction_unit_app {X : Scheme} :
- ΓSpec.adjunction.unit.app X = locallyRingedSpaceAdjunction.unit.app X.1 := rfl
+/-- The canonical map `X ⟶ Spec Γ(X, ⊤)`. This is the unit of the `Γ-Spec` adjunction. -/
+def _root_.AlgebraicGeometry.Scheme.toSpecΓ (X : Scheme.{u}) : X ⟶ Spec Γ(X, ⊤) :=
+ ΓSpec.adjunction.unit.app X
-@[reassoc (attr := simp)]
-theorem adjunction_unit_naturality {X Y : Scheme.{u}} (f : X ⟶ Y) :
- f ≫ ΓSpec.adjunction.unit.app Y = ΓSpec.adjunction.unit.app X ≫ Spec.map (f.app ⊤) :=
- ΓSpec.adjunction.unit.naturality f
+@[simp]
+theorem adjunction_unit_app {X : Scheme} :
+ ΓSpec.adjunction.unit.app X = X.toSpecΓ := rfl
instance isIso_locallyRingedSpaceAdjunction_counit :
IsIso.{u + 1, u + 1} locallyRingedSpaceAdjunction.counit :=
@@ -422,56 +407,76 @@ instance isIso_adjunction_counit : IsIso ΓSpec.adjunction.counit := by
rw [adjunction_counit_app]
infer_instance
+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 ⊤) :=
+ ΓSpec.adjunction.unit.naturality f
+
@[simp]
-theorem adjunction_unit_app_app_top (X : Scheme.{u}) :
- (ΓSpec.adjunction.unit.app X).app ⊤ = (Scheme.ΓSpecIso Γ(X, ⊤)).hom := by
+theorem Scheme.toSpecΓ_app_top (X : Scheme.{u}) :
+ X.toSpecΓ.app ⊤ = (Scheme.ΓSpecIso Γ(X, ⊤)).hom := by
have := ΓSpec.adjunction.left_triangle_components X
dsimp at this
rw [← IsIso.eq_comp_inv] at this
- simp only [adjunction_counit_app, Functor.id_obj, Functor.comp_obj, Functor.rightOp_obj,
+ simp only [ΓSpec.adjunction_counit_app, Functor.id_obj, Functor.comp_obj, Functor.rightOp_obj,
Scheme.Γ_obj, Category.id_comp] at this
rw [← Quiver.Hom.op_inj.eq_iff, this, ← op_inv, IsIso.Iso.inv_inv]
@[simp]
theorem SpecMap_ΓSpecIso_hom (R : CommRingCat.{u}) :
- Spec.map ((Scheme.ΓSpecIso R).hom) = adjunction.unit.app (Spec R) := by
+ Spec.map ((Scheme.ΓSpecIso R).hom) = (Spec R).toSpecΓ := by
have := ΓSpec.adjunction.right_triangle_components (op R)
dsimp at this
rwa [← IsIso.eq_comp_inv, Category.id_comp, ← Spec.map_inv, IsIso.Iso.inv_inv, eq_comm] at this
-lemma adjunction_unit_map_basicOpen (X : Scheme.{u}) (r : Γ(X, ⊤)) :
- (ΓSpec.adjunction.unit.app X ⁻¹ᵁ (PrimeSpectrum.basicOpen r)) = X.basicOpen r := by
- rw [← basicOpen_eq_of_affine]
- erw [Scheme.preimage_basicOpen]
+lemma Scheme.toSpecΓ_preimage_basicOpen (X : Scheme.{u}) (r : Γ(X, ⊤)) :
+ X.toSpecΓ ⁻¹ᵁ (PrimeSpectrum.basicOpen r) = X.basicOpen r := by
+ rw [← basicOpen_eq_of_affine, Scheme.preimage_basicOpen]
congr
- rw [ΓSpec.adjunction_unit_app_app_top]
+ rw [Scheme.toSpecΓ_app_top]
exact Iso.inv_hom_id_apply _ _
-theorem toOpen_unit_app_val_c_app {X : Scheme.{u}} (U) :
- StructureSheaf.toOpen _ _ ≫ (ΓSpec.adjunction.unit.app X).val.c.app U =
+-- Warning: this LHS of this lemma breaks the structure-sheaf abstraction.
+@[reassoc (attr := simp)]
+theorem toOpen_toSpecΓ_app {X : Scheme.{u}} (U) :
+ StructureSheaf.toOpen _ _ ≫ X.toSpecΓ.app U =
X.presheaf.map (homOfLE (by exact le_top)).op := by
rw [← StructureSheaf.toOpen_res _ _ _ (homOfLE le_top), Category.assoc,
- NatTrans.naturality _ (homOfLE (le_top (a := U.unop))).op]
+ NatTrans.naturality _ (homOfLE (le_top (a := U))).op]
show (ΓSpec.adjunction.counit.app (Scheme.Γ.rightOp.obj X)).unop ≫
(Scheme.Γ.rightOp.map (ΓSpec.adjunction.unit.app X)).unop ≫ _ = _
rw [← Category.assoc, ← unop_comp, ΓSpec.adjunction.left_triangle_components]
dsimp
exact Category.id_comp _
--- Warning: this LHS of this lemma breaks the structure-sheaf abstraction.
-@[reassoc (attr := simp)]
-theorem toOpen_unit_app_val_c_app' {X : Scheme.{u}} (U : Opens (PrimeSpectrum Γ(X, ⊤))) :
- toOpen Γ(X, ⊤) U ≫ (adjunction.unit.app X).app U =
- X.presheaf.map (homOfLE (by exact le_top)).op :=
- ΓSpec.toOpen_unit_app_val_c_app (op U)
+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
-end ΓSpec
+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 ⊤ ≫
- (ΓSpec.adjunction.unit.app U).app ⊤ ≫ U.topIso.hom := by
- rw [ΓSpec.adjunction_unit_app_app_top] -- why can't simp find this
- simp
+ U.toScheme.toSpecΓ.app ⊤ ≫ U.topIso.hom := by simp
+
+@[deprecated (since := "2024-07-24")]
+alias ΓSpec.adjunction_unit_naturality := Scheme.toSpecΓ_naturality
+@[deprecated (since := "2024-07-24")]
+alias ΓSpec.adjunction_unit_naturality_assoc := Scheme.toSpecΓ_naturality_assoc
+@[deprecated (since := "2024-07-24")]
+alias ΓSpec.adjunction_unit_app_app_top := Scheme.toSpecΓ_app_top
+@[deprecated (since := "2024-07-24")]
+alias ΓSpec.adjunction_unit_map_basicOpen := Scheme.toSpecΓ_preimage_basicOpen
/-! Immediate consequences of the adjunction. -/
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 6233014ed00a7..d14b580db3d1a 100644
--- a/Mathlib/AlgebraicGeometry/Modules/Tilde.lean
+++ b/Mathlib/AlgebraicGeometry/Modules/Tilde.lean
@@ -1,13 +1,15 @@
/-
Copyright (c) 2024 Weihong Xu. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Weihong Xu
+Authors: Kevin Buzzard, Johan Commelin, Amelia Livingston, Sophie Morel, Jujian Zhang, Weihong Xu
-/
import Mathlib.Algebra.Module.LocalizedModule
import Mathlib.AlgebraicGeometry.StructureSheaf
import Mathlib.AlgebraicGeometry.Modules.Sheaf
import Mathlib.Algebra.Category.ModuleCat.Sheaf
+import Mathlib.Algebra.Category.ModuleCat.FilteredColimits
+import Mathlib.CategoryTheory.Limits.ConcreteCategory.WithAlgebraicStructures
/-!
@@ -18,8 +20,16 @@ such that `M^~(U)` is the set of dependent functions that are locally fractions.
## Main definitions
-* `ModuleCat.tildeInAddCommGrp` : `M^~` as a sheaf of abelian groups.
+* `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
+
+To get the `R`-module structure on the stalks on `M^~`, we had to define
+`ModuleCat.tildeInModuleCat`, which is `M^~` seen as sheaf of `R`-modules. We get it by
+applying a forgetful functor to `ModuleCat.tilde M`.
-/
@@ -49,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)⟩
/--
@@ -138,37 +148,250 @@ instance (U : (Opens (PrimeSpectrum.Top R))ᵒᵖ) :
AddCommGroup (M.tildeInType.1.obj U) :=
inferInstanceAs <| AddCommGroup (Tilde.sectionsSubmodule M U)
+noncomputable instance (U : (Opens (PrimeSpectrum.Top R))ᵒᵖ) :
+ Module ((Spec (.of R)).ringCatSheaf.1.obj U) (M.tildeInType.1.obj U) :=
+ inferInstanceAs <| Module _ (Tilde.sectionsSubmodule M U)
+
/--
-`M^~` as a presheaf of abelian groups over `Spec R`
+`M^~` as a sheaf of `𝒪_{Spec R}`-modules
-/
-def preTildeInAddCommGrp : Presheaf AddCommGrp (PrimeSpectrum.Top R) where
- obj U := .of ((M.tildeInType).1.obj U)
- map {U V} i :=
- { toFun := M.tildeInType.1.map i
- map_zero' := rfl
- map_add' := fun x y => rfl}
+noncomputable def tilde : (Spec (CommRingCat.of R)).Modules where
+ val :=
+ { obj := fun U ↦ ModuleCat.of _ (M.tildeInType.val.obj U)
+ map := fun {U V} i ↦
+ { toFun := M.tildeInType.val.map i
+ map_smul' := by intros; rfl
+ map_add' := by intros; rfl } }
+ isSheaf := (TopCat.Presheaf.isSheaf_iff_isSheaf_comp (forget AddCommGrp) _ ).2
+ M.tildeInType.2
/--
-`M^~` as a sheaf of abelian groups over `Spec R`
+This is `M^~` as a sheaf of `R`-modules.
-/
-def tildeInAddCommGrp : Sheaf AddCommGrp (PrimeSpectrum.Top R) :=
- ⟨M.preTildeInAddCommGrp,
- TopCat.Presheaf.isSheaf_iff_isSheaf_comp (forget AddCommGrp) _ |>.mpr
- (TopCat.Presheaf.isSheaf_of_iso (NatIso.ofComponents (fun _ => Iso.refl _) fun _ => rfl)
- M.tildeInType.2)⟩
+noncomputable def tildeInModuleCat :
+ TopCat.Presheaf (ModuleCat R) (PrimeSpectrum.Top R) :=
+ (PresheafOfModules.forgetToPresheafModuleCat (op ⊤) <|
+ Limits.initialOpOfTerminal Limits.isTerminalTop).obj (tilde M).1 ⋙
+ ModuleCat.restrictScalars (StructureSheaf.globalSectionsIso R).hom
-noncomputable instance (U : (Opens (PrimeSpectrum.Top R))ᵒᵖ) :
- Module ((Spec (.of R)).ringCatSheaf.1.obj U) (M.tildeInAddCommGrp.1.obj U) :=
- inferInstanceAs <| Module _ (Tilde.sectionsSubmodule M U)
+namespace Tilde
+
+@[simp]
+theorem res_apply (U V : Opens (PrimeSpectrum.Top R)) (i : V ⟶ U)
+ (s : (tildeInModuleCat M).obj (op U)) (x : V) :
+ ((tildeInModuleCat M).map i.op s).1 x = (s.1 (i x) : _) :=
+ rfl
+
+lemma smul_section_apply (r : R) (U : Opens (PrimeSpectrum.Top R))
+ (s : (tildeInModuleCat M).1.obj (op U)) (x : U) :
+ (r • s).1 x = r • (s.1 x) := rfl
+
+lemma smul_stalk_no_nonzero_divisor {x : PrimeSpectrum R}
+ (r : x.asIdeal.primeCompl) (st : (tildeInModuleCat M).stalk x) (hst : r.1 • st = 0) :
+ st = 0 := by
+ refine Limits.Concrete.colimit_no_zero_smul_divisor
+ _ _ _ ⟨op ⟨PrimeSpectrum.basicOpen r.1, r.2⟩, fun U i s hs ↦ Subtype.eq <| funext fun pt ↦ ?_⟩
+ _ hst
+ apply LocalizedModule.eq_zero_of_smul_eq_zero _ (i.unop pt).2 _
+ (congr_fun (Subtype.ext_iff.1 hs) pt)
/--
-`M^~` as a sheaf of `𝒪_{Spec R}`-modules
+If `U` is an open subset of `Spec R`, this is the morphism of `R`-modules from `M` to
+`M^~(U)`.
-/
-noncomputable def tilde : (Spec (CommRingCat.of R)).Modules where
- val :=
- { presheaf := M.tildeInAddCommGrp.1
- module := inferInstance
- map_smul := fun _ _ _ => rfl }
- isSheaf := M.tildeInAddCommGrp.2
+def toOpen (U : Opens (PrimeSpectrum.Top R)) :
+ ModuleCat.of R M ⟶ (tildeInModuleCat M).1.obj (op U) where
+ toFun f :=
+ ⟨fun x ↦ LocalizedModule.mkLinearMap _ _ f, fun x ↦
+ ⟨U, x.2, 𝟙 _, f, 1, fun y ↦ ⟨(Ideal.ne_top_iff_one _).1 y.1.2.1, by simp⟩⟩⟩
+ map_add' f g := Subtype.eq <| funext fun x ↦ LinearMap.map_add _ _ _
+ map_smul' r m := by
+ simp only [isLocallyFraction_pred, LocalizedModule.mkLinearMap_apply, LinearMapClass.map_smul,
+ RingHom.id_apply]
+ rfl
+
+@[simp]
+theorem toOpen_res (U V : Opens (PrimeSpectrum.Top R)) (i : V ⟶ U) :
+ toOpen M U ≫ (tildeInModuleCat M).map i.op = toOpen M V :=
+ rfl
+
+/--
+If `x` is a point of `Spec R`, this is the morphism of `R`-modules from `M` to the stalk of
+`M^~` at `x`.
+-/
+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))
+
+open LocalizedModule TopCat.Presheaf in
+lemma isUnit_toStalk (x : PrimeSpectrum.Top R) (r : x.asIdeal.primeCompl) :
+ IsUnit ((algebraMap R (Module.End R ((tildeInModuleCat M).stalk x))) r) := by
+ rw [Module.End_isUnit_iff]
+ refine ⟨LinearMap.ker_eq_bot.1 <| eq_bot_iff.2 fun st (h : r.1 • st = 0) ↦
+ 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 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
+ germ_ext (W := O) (hxW := ⟨mem, r.2⟩) (iWU := 𝟙 _) (iWV := homOfLE inf_le_left) _ <|
+ Subtype.eq <| funext fun y ↦ smul_eq_iff_of_mem (S := y.1.1.primeCompl) r _ _ _ |>.2 rfl⟩
+ obtain ⟨V, mem_V, iV, num, den, hV⟩ := s.2 ⟨q.1, q.2.1⟩
+ refine ⟨V ⊓ O, ⟨mem_V, q.2⟩, homOfLE inf_le_right, num, r * den, fun y ↦ ?_⟩
+ obtain ⟨h1, h2⟩ := hV ⟨y, y.2.1⟩
+ refine ⟨y.1.asIdeal.primeCompl.mul_mem y.2.2.2 h1, ?_⟩
+ simp only [Opens.coe_inf, isLocallyFraction_pred, mkLinearMap_apply,
+ smul_eq_iff_of_mem (S := y.1.1.primeCompl) (hr := h1), mk_smul_mk, one_smul, mul_one] at h2 ⊢
+ simpa only [h2, mk_smul_mk, one_smul, smul'_mk, mk_eq] using ⟨1, by simp only [one_smul]; rfl⟩
+
+/--
+The morphism of `R`-modules from the localization of `M` at the prime ideal corresponding to `x`
+to the stalk of `M^~` at `x`.
+-/
+noncomputable def localizationToStalk (x : PrimeSpectrum.Top R) :
+ ModuleCat.of R (LocalizedModule x.asIdeal.primeCompl M) ⟶
+ (TopCat.Presheaf.stalk (tildeInModuleCat M) x) :=
+ LocalizedModule.lift _ (toStalk M x) <| isUnit_toStalk M x
+
+
+/-- 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 9cf21c35955ab..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
@@ -122,15 +122,14 @@ lemma isAffine_of_isAffineOpen_basicOpen (s : Set Γ(X, ⊤))
simp only [← basicOpen_eq_of_affine]
exact (isAffineOpen_top (Scheme.Spec.obj (op _))).basicOpen _
· rw [PrimeSpectrum.iSup_basicOpen_eq_top_iff, Subtype.range_coe_subtype, Set.setOf_mem_eq, hs]
- · show IsAffineOpen (ΓSpec.adjunction.unit.app X ⁻¹ᵁ PrimeSpectrum.basicOpen i.1)
- rw [ΓSpec.adjunction_unit_map_basicOpen]
+ · rw [Scheme.toSpecΓ_preimage_basicOpen]
exact hs₂ _ i.2
· simp only [Functor.comp_obj, Functor.rightOp_obj, Scheme.Γ_obj, Scheme.Spec_obj, id_eq,
eq_mpr_eq_cast, Functor.id_obj, Opens.map_top, morphismRestrict_app]
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
@@ -159,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 7d7bc17702e37..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,10 +354,10 @@ 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
- constructor
+ apply MorphismProperty.RespectsIso.mk
· rintro X Y Z e f ⟨a, h⟩; exact ⟨a, h₁ e f h⟩
· rintro X Y Z e f ⟨a, h⟩; exact ⟨isAffine_of_isIso e.inv, h₂ e f h⟩
@@ -398,7 +429,7 @@ theorem of_targetAffineLocally_of_isPullback
instance (P : AffineTargetMorphismProperty) [P.toProperty.RespectsIso] :
(targetAffineLocally P).RespectsIso := by
- constructor
+ apply MorphismProperty.RespectsIso.mk
· introv H U
rw [morphismRestrict_comp, P.cancel_left_of_respectsIso]
exact H U
@@ -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 4affb2c6194ba..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]
@@ -84,22 +91,22 @@ instance comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsClosedImmersion f]
/-- Composition with an isomorphism preserves closed immersions. -/
instance respectsIso : MorphismProperty.RespectsIso @IsClosedImmersion := by
- constructor <;> intro X Y Z e f hf <;> infer_instance
+ apply MorphismProperty.RespectsIso.mk <;> intro X Y Z e f hf <;> infer_instance
/-- Given two commutative rings `R S : CommRingCat` and a surjective morphism
`f : R ⟶ S`, the induced scheme morphism `specObj S ⟶ specObj R` is a
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]
- exact surjective_respectsIso
+ exact RingHom.surjective_respectsIso
apply (MorphismProperty.arrow_mk_iso_iff
(RingHom.toMorphismProperty (fun f ↦ Function.Surjective f))
(Scheme.arrowStalkMapSpecIso f x)).mpr
- exact surjective_localRingHom_of_surjective f h x.asIdeal
+ exact RingHom.surjective_localRingHom_of_surjective f h x.asIdeal
/-- For any ideal `I` in a commutative ring `R`, the quotient map `specObj R ⟶ specObj (R ⧸ I)`
is a closed immersion. -/
@@ -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 91b9cb9c05db1..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`. -/
@@ -251,12 +263,12 @@ variable {P : ∀ {R S : Type u} [CommRing R] [CommRing S], (R →+* S) → Prop
/-- If `P` respects isos, then `stalkwise P` respects isos. -/
lemma stalkwise_respectsIso (hP : RingHom.RespectsIso P) :
(stalkwise P).RespectsIso where
- precomp {X Y Z} e f hf := by
+ precomp {X Y Z} e (he : IsIso e) f hf := by
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.hom.val.base x)
- postcomp {X Y Z} 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/FinitePresentation.lean b/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.lean
index 384a722407c6d..d6dee82946a83 100644
--- a/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.lean
+++ b/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.lean
@@ -49,6 +49,10 @@ instance : HasRingHomProperty @LocallyOfFinitePresentation RingHom.FinitePresent
instance (priority := 900) locallyOfFinitePresentation_of_isOpenImmersion [IsOpenImmersion f] :
LocallyOfFinitePresentation f :=
HasRingHomProperty.of_isOpenImmersion
+ RingHom.finitePresentation_holdsForLocalizationAway.containsIdentities
+
+instance : MorphismProperty.IsStableUnderComposition @LocallyOfFinitePresentation :=
+ HasRingHomProperty.stableUnderComposition RingHom.finitePresentation_stableUnderComposition
instance locallyOfFinitePresentation_comp {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z)
[hf : LocallyOfFinitePresentation f] [hg : LocallyOfFinitePresentation g] :
diff --git a/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean b/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean
index ffc351acd412a..a5bbcc0abb5f2 100644
--- a/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean
+++ b/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean
@@ -46,6 +46,10 @@ instance : HasRingHomProperty @LocallyOfFiniteType RingHom.FiniteType where
instance (priority := 900) locallyOfFiniteType_of_isOpenImmersion [IsOpenImmersion f] :
LocallyOfFiniteType f :=
HasRingHomProperty.of_isOpenImmersion
+ RingHom.finiteType_holdsForLocalizationAway.containsIdentities
+
+instance : MorphismProperty.IsStableUnderComposition @LocallyOfFiniteType :=
+ HasRingHomProperty.stableUnderComposition RingHom.finiteType_stableUnderComposition
instance locallyOfFiniteType_comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z)
[hf : LocallyOfFiniteType f] [hg : LocallyOfFiniteType g] : LocallyOfFiniteType (f ≫ g) :=
@@ -53,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 25d3e57f11b98..1cf0aeb9c2a52 100644
--- a/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean
+++ b/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean
@@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andrew Yang
-/
import Mathlib.AlgebraicGeometry.Morphisms.UnderlyingMap
-import Mathlib.RingTheory.LocalProperties
+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
@@ -52,7 +56,7 @@ lemma isPreimmersion_eq_inf :
/-- Being surjective on stalks is local at the target. -/
instance isSurjectiveOnStalks_isLocalAtTarget : IsLocalAtTarget
(stalkwise (Function.Surjective ·)) :=
- stalkwiseIsLocalAtTarget_of_respectsIso surjective_respectsIso
+ stalkwiseIsLocalAtTarget_of_respectsIso RingHom.surjective_respectsIso
namespace IsPreimmersion
@@ -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 211a07cc5edf0..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]
@@ -198,7 +198,15 @@ theorem exists_pow_mul_eq_zero_of_res_basicOpen_eq_zero_of_isAffineOpen (X : Sch
{U : X.Opens} (hU : IsAffineOpen U) (x f : Γ(X, U))
(H : x |_ X.basicOpen f = 0) : ∃ n : ℕ, f ^ n * x = 0 := by
rw [← map_zero (X.presheaf.map (homOfLE <| X.basicOpen_le f : X.basicOpen f ⟶ U).op)] at H
- obtain ⟨⟨_, n, rfl⟩, e⟩ := (hU.isLocalization_basicOpen f).exists_of_eq H
+ #adaptation_note
+ /--
+ Prior to nightly-2024-09-29, we could use dot notation here:
+ `(hU.isLocalization_basicOpen f).exists_of_eq H`
+ This is no longer possible;
+ likely changing the signature of `IsLocalization.Away.exists_of_eq` is in order.
+ -/
+ obtain ⟨n, e⟩ :=
+ @IsLocalization.Away.exists_of_eq _ _ _ _ _ _ (hU.isLocalization_basicOpen f) _ _ H
exact ⟨n, by simpa [mul_comm x] using e⟩
/-- If `x : Γ(X, U)` is zero on `D(f)` for some `f : Γ(X, U)`, and `U` is quasi-compact, then
@@ -264,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}
@@ -272,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 83373737cbce2..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,13 +347,39 @@ 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 (ΓSpec.adjunction_unit_map_basicOpen _ _).symm).op) _ ?_
+ (eqToHom (Scheme.toSpecΓ_preimage_basicOpen _ _).symm).op) _ ?_
rw [ConcreteCategory.isIso_iff_bijective, CommRingCat.forget_map]
apply (config := { allowSynthFailures := true }) IsLocalization.bijective
· exact StructureSheaf.IsLocalization.to_basicOpen _ _
@@ -361,8 +387,6 @@ theorem isIso_ΓSpec_adjunction_unit_app_basicOpen {X : Scheme} [CompactSpace X]
· exact isCompact_univ
· exact isQuasiSeparated_univ
· rw [← CommRingCat.comp_eq_ring_hom_comp]
- simp [RingHom.algebraMap_toAlgebra]
- rw [ΓSpec.toOpen_unit_app_val_c_app'_assoc, ← Functor.map_comp]
- rfl
+ simp [RingHom.algebraMap_toAlgebra, ← Functor.map_comp]
end AlgebraicGeometry
diff --git a/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean b/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean
index 3ed0b2cf6b132..06f83cb90fe8a 100644
--- a/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean
+++ b/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean
@@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andrew Yang
-/
import Mathlib.AlgebraicGeometry.Morphisms.Basic
-import Mathlib.RingTheory.LocalProperties
+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 _ _ _
@@ -228,9 +300,8 @@ theorem of_source_openCover [IsAffine Y]
| basicOpen U r H =>
simp_rw [Scheme.affineBasicOpen_coe,
← f.appLE_map (U := ⊤) le_top (homOfLE (X.basicOpen_le r)).op]
- apply (isLocal_ringHomProperty P).StableUnderComposition _ _ H
have := U.2.isLocalization_basicOpen r
- apply (isLocal_ringHomProperty P).HoldsForLocalizationAway _ r
+ exact (isLocal_ringHomProperty P).StableUnderCompositionWithLocalizationAway.left _ r _ H
| openCover U s hs H =>
apply (isLocal_ringHomProperty P).OfLocalizationSpanTarget.ofIsLocalization
(isLocal_ringHomProperty P).respectsIso _ _ hs
@@ -283,16 +354,16 @@ instance : IsLocalAtSource P := by
fun i ↦ iff_of_source_openCover (P := P) (f := 𝒰.map i ≫ f) (𝒰.obj i).affineCover]
simp [Scheme.OpenCover.affineRefinement, Sigma.forall]
-instance : P.ContainsIdentities where
+lemma containsIdentities (hP : RingHom.ContainsIdentities Q) : P.ContainsIdentities where
id_mem X := by
rw [IsLocalAtTarget.iff_of_iSup_eq_top (P := P) _ (iSup_affineOpens_eq_top _)]
intro U
have : IsAffine (𝟙 X ⁻¹ᵁ U.1) := U.2
rw [morphismRestrict_id, iff_of_isAffine (P := P), Scheme.id_app]
- exact (isLocal_ringHomProperty P).HoldsForLocalizationAway.of_bijective _ _
- Function.bijective_id
+ apply hP
-instance : P.IsStableUnderComposition where
+lemma stableUnderComposition (hP : RingHom.StableUnderComposition Q) :
+ P.IsStableUnderComposition where
comp_mem {X Y Z} f g hf hg := by
wlog hZ : IsAffine Z generalizing X Y Z
· rw [IsLocalAtTarget.iff_of_iSup_eq_top (P := P) _ (iSup_affineOpens_eq_top _)]
@@ -311,7 +382,7 @@ instance : P.IsStableUnderComposition where
rw [← Category.assoc]
exact this _ (comp_of_isOpenImmersion _ _ _ hf) inferInstance
rw [iff_of_isAffine (P := P)] at hf hg ⊢
- exact (isLocal_ringHomProperty P).StableUnderComposition _ _ hg hf
+ exact hP _ _ hg hf
theorem of_comp
(H : ∀ {R S T : Type u} [CommRing R] [CommRing S] [CommRing T],
@@ -339,10 +410,16 @@ theorem of_comp
rw [iff_of_isAffine (P := P)] at h ⊢
exact H _ _ h
-instance : P.IsMultiplicative where
+lemma isMultiplicative (hPc : RingHom.StableUnderComposition Q)
+ (hPi : RingHom.ContainsIdentities Q) :
+ P.IsMultiplicative where
+ comp_mem := (stableUnderComposition hPc).comp_mem
+ id_mem := (containsIdentities hPi).id_mem
include Q in
-lemma of_isOpenImmersion [IsOpenImmersion f] : P f := IsLocalAtSource.of_isOpenImmersion f
+lemma of_isOpenImmersion (hP : RingHom.ContainsIdentities Q) [IsOpenImmersion f] : P f :=
+ haveI : P.ContainsIdentities := containsIdentities hP
+ IsLocalAtSource.of_isOpenImmersion f
lemma stableUnderBaseChange (hP : RingHom.StableUnderBaseChange Q) : P.StableUnderBaseChange := by
apply HasAffineProperty.stableUnderBaseChange
@@ -360,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 c65f7aa086fbc..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,15 +106,35 @@ 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
+ refine ⟨fun h ↦ ?_, image_le_image_of_le f⟩
+ rw [← preimage_image_eq f U, ← preimage_image_eq f U']
+ apply preimage_le_preimage_of_le f h
lemma image_preimage_eq_opensRange_inter (U : Y.Opens) : f ''ᵁ f ⁻¹ᵁ U = f.opensRange ⊓ U := by
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) :
@@ -122,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 :=
@@ -131,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`. -/
@@ -174,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
@@ -182,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
@@ -207,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
@@ -249,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) :=
@@ -263,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
@@ -273,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]
@@ -285,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
@@ -324,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₂⟩
@@ -363,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⟩
@@ -400,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 :=
@@ -423,15 +456,15 @@ 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
rw [← pullbackSymmetry_hom_comp_snd]
-- Porting note: was just `infer_instance`, it is a bit weird that no explicit class instance is
-- provided but still class inference fail to find this
- exact LocallyRingedSpace.IsOpenImmersion.comp (H := inferInstance) _
+ exact LocallyRingedSpace.IsOpenImmersion.comp (H := inferInstance) _ _
instance pullback_to_base [IsOpenImmersion g] :
IsOpenImmersion (limit.π (cospan f g) WalkingCospan.one) := by
@@ -439,14 +472,14 @@ instance pullback_to_base [IsOpenImmersion g] :
change IsOpenImmersion (_ ≫ f)
-- Porting note: was just `infer_instance`, it is a bit weird that no explicit class instance is
-- provided but still class inference fail to find this
- exact LocallyRingedSpace.IsOpenImmersion.comp (H := inferInstance) _
+ exact LocallyRingedSpace.IsOpenImmersion.comp (H := inferInstance) _ _
instance forgetToTopPreservesOfLeft : PreservesLimit (cospan f g) Scheme.forgetToTop := by
delta Scheme.forgetToTop
- apply @Limits.compPreservesLimit (K := cospan f g) (F := forget)
+ refine @Limits.compPreservesLimit _ _ _ _ _ _ (K := cospan f g) _ _ (F := forget)
(G := LocallyRingedSpace.forgetToTop) ?_ ?_
· infer_instance
- apply @preservesLimitOfIsoDiagram (F := _) _ _ _ _ _ _ (diagramIsoCospan.{u} _).symm ?_
+ refine @preservesLimitOfIsoDiagram _ _ _ _ _ _ _ _ _ (diagramIsoCospan.{u} _).symm ?_
dsimp [LocallyRingedSpace.forgetToTop]
infer_instance
@@ -454,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
@@ -470,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
@@ -487,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]
@@ -505,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
@@ -525,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)
@@ -539,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
@@ -594,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 34df4b8d2c4b9..73be6978660ac 100644
--- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean
+++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean
@@ -3,14 +3,14 @@ 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.RingTheory.PrimeSpectrum
-import Mathlib.Topology.Irreducible
-import Mathlib.Topology.Sets.Closeds
+import Mathlib.RingTheory.KrullDimension.Basic
+import Mathlib.Topology.KrullDimension
import Mathlib.Topology.Sober
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
@@ -106,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
@@ -207,21 +213,14 @@ section Comap
variable {S' : Type*} [CommSemiring S']
-theorem preimage_comap_zeroLocus_aux (f : R →+* S) (s : Set R) :
- (fun y => ⟨Ideal.comap f y.asIdeal, inferInstance⟩ : PrimeSpectrum S → PrimeSpectrum R) ⁻¹'
- zeroLocus s =
- zeroLocus (f '' s) := by
- ext x
- simp only [mem_zeroLocus, Set.image_subset_iff, Set.mem_preimage, mem_zeroLocus, Ideal.coe_comap]
-
-/-- The function between prime spectra of commutative (semi)rings induced by a ring homomorphism.
-This function is continuous. -/
+/-- The continuous function between prime spectra of commutative (semi)rings induced by a ring
+homomorphism. -/
def comap (f : R →+* S) : C(PrimeSpectrum S, PrimeSpectrum R) where
- toFun y := ⟨Ideal.comap f y.asIdeal, inferInstance⟩
+ toFun := f.specComap
continuous_toFun := by
simp only [continuous_iff_isClosed, isClosed_iff_zeroLocus]
rintro _ ⟨s, rfl⟩
- exact ⟨_, preimage_comap_zeroLocus_aux f s⟩
+ exact ⟨_, preimage_specComap_zeroLocus_aux f s⟩
variable (f : R →+* S)
@@ -244,17 +243,15 @@ theorem comap_comp_apply (f : R →+* S) (g : S →+* S') (x : PrimeSpectrum S')
@[simp]
theorem preimage_comap_zeroLocus (s : Set R) : comap f ⁻¹' zeroLocus s = zeroLocus (f '' s) :=
- preimage_comap_zeroLocus_aux f s
+ preimage_specComap_zeroLocus_aux f s
theorem comap_injective_of_surjective (f : R →+* S) (hf : Function.Surjective f) :
- Function.Injective (comap f) := fun x y h =>
- PrimeSpectrum.ext (Ideal.comap_injective_of_surjective f hf
- (congr_arg PrimeSpectrum.asIdeal h : (comap f x).asIdeal = (comap f y).asIdeal))
+ Function.Injective (comap f) := fun _ _ h => specComap_injective_of_surjective _ hf h
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]
@@ -265,40 +262,30 @@ 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)) := by
- intro p q h
- replace h := congr_arg (fun x : PrimeSpectrum R => Ideal.map (algebraMap R S) x.asIdeal) h
- dsimp only [comap, ContinuousMap.coe_mk] at h
- rw [IsLocalization.map_comap M S, IsLocalization.map_comap M S] at h
- ext1
- exact h
+ Function.Injective (comap (algebraMap R S)) :=
+ fun _ _ h => localization_specComap_injective S M h
+
+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⟩
-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⟩
+@[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 } := by
- ext x
- constructor
- · simp_rw [disjoint_iff_inf_le]
- rintro ⟨p, rfl⟩ x ⟨hx₁, hx₂⟩
- exact (p.2.1 : ¬_) (p.asIdeal.eq_top_of_isUnit_mem hx₂ (IsLocalization.map_units S ⟨x, hx₁⟩))
- · intro h
- use ⟨x.asIdeal.map (algebraMap R S), IsLocalization.isPrime_of_isPrime_disjoint M S _ x.2 h⟩
- ext1
- exact IsLocalization.comap_map_of_isPrime_disjoint M S _ x.2 h
+ Set.range (comap (algebraMap R S)) = { p | Disjoint (M : Set R) p.asIdeal } :=
+ localization_specComap_range ..
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
@@ -307,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
@@ -336,38 +326,25 @@ theorem comap_singleton_isClosed_of_isIntegral (f : R →+* S) (hf : f.IsIntegra
(Ideal.isMaximal_comap_of_isIntegral_of_isMaximal' f hf x.asIdeal)
theorem image_comap_zeroLocus_eq_zeroLocus_comap (hf : Surjective f) (I : Ideal S) :
- comap f '' zeroLocus I = zeroLocus (I.comap f) := by
- simp only [Set.ext_iff, Set.mem_image, mem_zeroLocus, SetLike.coe_subset_coe]
- refine fun p => ⟨?_, fun h_I_p => ?_⟩
- · rintro ⟨p, hp, rfl⟩ a ha
- exact hp ha
- · have hp : ker f ≤ p.asIdeal := (Ideal.comap_mono bot_le).trans h_I_p
- refine ⟨⟨p.asIdeal.map f, Ideal.map_isPrime_of_surjective hf hp⟩, fun x hx => ?_, ?_⟩
- · obtain ⟨x', rfl⟩ := hf x
- exact Ideal.mem_map_of_mem f (h_I_p hx)
- · ext x
- rw [comap_asIdeal, Ideal.mem_comap, Ideal.mem_map_iff_of_surjective f hf]
- refine ⟨?_, fun hx => ⟨x, hx, rfl⟩⟩
- rintro ⟨x', hx', heq⟩
- rw [← sub_sub_cancel x' x]
- refine p.asIdeal.sub_mem hx' (hp ?_)
- rwa [mem_ker, map_sub, sub_eq_zero]
+ comap f '' zeroLocus I = zeroLocus (I.comap f) :=
+ image_specComap_zeroLocus_eq_zeroLocus_comap _ f hf I
theorem range_comap_of_surjective (hf : Surjective f) :
- Set.range (comap f) = zeroLocus (ker f) := by
- rw [← Set.image_univ]
- convert image_comap_zeroLocus_eq_zeroLocus_comap _ _ hf _
- rw [zeroLocus_bot]
+ Set.range (comap f) = zeroLocus (ker f) :=
+ range_specComap_of_surjective _ f hf
theorem isClosed_range_comap_of_surjective (hf : Surjective f) :
IsClosed (Set.range (comap f)) := by
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
@@ -388,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
@@ -495,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))]
@@ -576,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]
@@ -662,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)
@@ -685,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
@@ -693,3 +760,50 @@ theorem PrimeSpectrum.comap_residue (T : Type u) [CommRing T] [LocalRing T]
exact Ideal.mk_ker
end LocalRing
+
+section KrullDimension
+
+theorem PrimeSpectrum.topologicalKrullDim_eq_ringKrullDim [CommRing R] :
+ topologicalKrullDim (PrimeSpectrum R) = ringKrullDim R :=
+ Order.krullDim_orderDual.symm.trans <| Order.krullDim_eq_of_orderIso
+ (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 139077e8ace13..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
@@ -402,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
@@ -454,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
@@ -594,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
@@ -610,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]
@@ -635,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
@@ -656,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)
@@ -676,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
@@ -685,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
/--
@@ -697,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) :=
@@ -755,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
@@ -806,7 +807,7 @@ If `f ∈ A` is a homogeneous element of positive degree, then the projective sp
-/
def projIsoSpec (f) {m} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) :
(Proj| pbo f) ≅ (Spec (A⁰_ f)) :=
- @asIso (f := toSpec 𝒜 f) (isIso_toSpec 𝒜 f f_deg hm)
+ @asIso _ _ _ _ (f := toSpec 𝒜 f) (isIso_toSpec 𝒜 f f_deg hm)
/--
This is the scheme `Proj(A)` for any `ℕ`-graded ring `A`.
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 d4cb9d574a2c2..4fb6a8f489f90 100644
--- a/Mathlib/AlgebraicGeometry/Properties.lean
+++ b/Mathlib/AlgebraicGeometry/Properties.lean
@@ -4,10 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andrew Yang
-/
import Mathlib.AlgebraicGeometry.AffineScheme
-import Mathlib.RingTheory.Nilpotent.Lemmas
-import Mathlib.Topology.Sheaves.SheafCondition.Sites
-import Mathlib.Algebra.Category.Ring.Constructions
-import Mathlib.RingTheory.LocalProperties
+import Mathlib.RingTheory.LocalProperties.Reduced
/-!
# Basic properties of schemes
@@ -32,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⟩
@@ -59,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) :
@@ -69,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
@@ -117,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
@@ -133,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
@@ -144,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
@@ -242,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 36ae5c042ab8c..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
@@ -453,8 +453,8 @@ instance isAffine_of_isAffine_isAffine_isAffine {X Y Z : Scheme}
IsAffine (pullback f g) :=
isAffine_of_isIso
(pullback.map f g (Spec.map (Γ.map f.op)) (Spec.map (Γ.map g.op))
- (ΓSpec.adjunction.unit.app X) (ΓSpec.adjunction.unit.app Y) (ΓSpec.adjunction.unit.app Z)
- (ΓSpec.adjunction.unit.naturality f) (ΓSpec.adjunction.unit.naturality g) ≫
+ X.toSpecΓ Y.toSpecΓ Z.toSpecΓ
+ (Scheme.toSpecΓ_naturality f) (Scheme.toSpecΓ_naturality g) ≫
(PreservesPullback.iso Scheme.Spec _ _).inv)
/-- Given an open cover `{ Xᵢ }` of `X`, then `X ×[Z] Y` is covered by `Xᵢ ×[Z] Y`. -/
@@ -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 ≫
+ @openCoverOfIsIso _ _
+ (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
@@ -583,8 +585,10 @@ the morphism `Spec (S ⊗[R] T) ⟶ Spec T` obtained by applying `Spec.map` to t
-/
@[reassoc (attr := simp)]
lemma pullbackSpecIso_inv_snd :
- (pullbackSpecIso R S T).inv ≫ pullback.snd _ _ = Spec.map (ofHom (toRingHom includeRight)) :=
+ (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
@@ -595,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
@@ -606,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
new file mode 100644
index 0000000000000..4b64608218fcd
--- /dev/null
+++ b/Mathlib/AlgebraicGeometry/ResidueField.lean
@@ -0,0 +1,296 @@
+/-
+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.Stalk
+import Mathlib.Geometry.RingedSpace.LocallyRingedSpace.ResidueField
+
+/-!
+
+# Residue fields of points
+
+## Main definitions
+
+The following are in the `AlgebraicGeometry.Scheme` namespace:
+
+- `AlgebraicGeometry.Scheme.residueField`: The residue field of the stalk at `x`.
+- `AlgebraicGeometry.Scheme.evaluation`: For open subsets `U` of `X` containing `x`,
+ the evaluation map from sections over `U` to the residue field at `x`.
+- `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 LocalRing
+
+noncomputable section
+
+namespace AlgebraicGeometry.Scheme
+
+variable (X : Scheme.{u}) {U : X.Opens}
+
+/-- The residue field of `X` at a point `x` is the residue field of the stalk of `X`
+at `x`. -/
+def residueField (x : X) : CommRingCat :=
+ CommRingCat.of <| LocalRing.ResidueField (X.presheaf.stalk x)
+
+instance (x : X) : Field (X.residueField x) :=
+ inferInstanceAs <| Field (LocalRing.ResidueField (X.presheaf.stalk x))
+
+/-- The residue map from the stalk to the residue field. -/
+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`.
+
+If we interpret sections over `U` as functions of `X` defined on `U`, then this ring map
+corresponds to evaluation at `x`.
+-/
+def evaluation (U : X.Opens) (x : X) (hx : x ∈ U) : Γ(X, U) ⟶ X.residueField x :=
+ X.presheaf.germ U x hx ≫ X.residue _
+
+@[reassoc]
+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 :=
+ X.evaluation ⊤ x trivial
+
+@[simp]
+lemma evaluation_eq_zero_iff_not_mem_basicOpen (x : X) (hx : x ∈ U) (f : Γ(X, U)) :
+ X.evaluation U x hx f = 0 ↔ x ∉ X.basicOpen f :=
+ X.toLocallyRingedSpace.evaluation_eq_zero_iff_not_mem_basicOpen ⟨x, hx⟩ f
+
+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
+
+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
+
+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.base x) ⟶ X.residueField x :=
+ LocalRing.ResidueField.map (f.stalkMap x)
+
+@[reassoc]
+lemma residue_residueFieldMap (x : X) :
+ Y.residue (f.base x) ≫ f.residueFieldMap x = f.stalkMap x ≫ X.residue x := by
+ simp [Hom.residueFieldMap]
+ rfl
+
+@[simp]
+lemma residueFieldMap_id (x : X) :
+ Hom.residueFieldMap (𝟙 X) x = 𝟙 (X.residueField x) :=
+ LocallyRingedSpace.residueFieldMap_id _
+
+@[simp]
+lemma residueFieldMap_comp {Z : Scheme.{u}} (g : Y ⟶ Z) (x : 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.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.1 ⟨x, hx⟩
+
+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.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
+ (asIso (f.stalkMap x)).commRingCatIsoToRingEquiv).toCommRingCatIso.isIso_hom
+
+section congr
+
+-- replace this def if hard to work with
+/-- The isomorphism between residue fields of equal points. -/
+def residueFieldCongr {x y : X} (h : x = y) :
+ X.residueField x ≅ X.residueField y :=
+ eqToIso (by subst h; rfl)
+
+@[simp]
+lemma residueFieldCongr_refl {x : X} :
+ X.residueFieldCongr (refl x) = Iso.refl _ := rfl
+
+@[simp]
+lemma residueFieldCongr_symm {x y : X} (e : x = y) :
+ (X.residueFieldCongr e).symm = X.residueFieldCongr e.symm := rfl
+
+@[simp]
+lemma residueFieldCongr_inv {x y : X} (e : x = y) :
+ (X.residueFieldCongr e).inv = (X.residueFieldCongr e.symm).hom := rfl
+
+@[simp]
+lemma residueFieldCongr_trans {x y z : X} (e : x = y) (e' : y = z) :
+ X.residueFieldCongr e ≪≫ X.residueFieldCongr e' = X.residueFieldCongr (e.trans e') := by
+ subst e e'
+ rfl
+
+@[reassoc (attr := simp)]
+lemma residueFieldCongr_trans_hom (X : Scheme) {x y z : X} (e : x = y) (e' : y = z) :
+ (X.residueFieldCongr e).hom ≫ (X.residueFieldCongr e').hom =
+ (X.residueFieldCongr (e.trans e')).hom := by
+ subst e e'
+ rfl
+
+@[reassoc]
+lemma residue_residueFieldCongr (X : Scheme) {x y : X} (h : x = y) :
+ X.residue x ≫ (X.residueFieldCongr h).hom =
+ (X.presheaf.stalkCongr (.of_eq h)).hom ≫ X.residue y := by
+ 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
+
+/-- The canonical map `Spec κ(x) ⟶ X`. -/
+def fromSpecResidueField (X : Scheme) (x : X) :
+ Spec (X.residueField x) ⟶ 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) :
+ Spec.map (X.residueFieldCongr h).hom ≫ X.fromSpecResidueField _ =
+ 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 3c13ad4164037..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,15 @@ 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]
+ exact U.ι.image_le_image_of_le le_top
@[simp]
lemma ι_preimage_self : U.ι ⁻¹ᵁ U = ⊤ :=
@@ -101,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
@@ -117,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 _ _ _
-
-@[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 _ _ _
+ {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 _ _ _
-@[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
@@ -169,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
@@ -216,50 +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
-@[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
-
--- 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))
+@[simp]
+lemma Scheme.restrictFunctor_map_left {U V : X.Opens} (i : U ⟶ V) :
+ (X.restrictFunctor.map i).left = (X.homOfLE i.le) := rfl
-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 [-Scheme.restrictFunctor_map_left]
- rw [X.restrictFunctor_map_app, ← Functor.map_comp, ← Functor.map_comp]
+ dsimp
+ rw [X.homOfLE_app, ← Functor.map_comp, ← Functor.map_comp]
congr 1)
/-- `X ∣_ U ∣_ V` is isomorphic to `X ∣_ V ∣_ U` -/
@@ -269,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
@@ -316,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 _ _
@@ -328,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
@@ -345,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]
@@ -371,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) :
@@ -384,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⟩
@@ -431,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
@@ -452,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. -/
@@ -463,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
@@ -502,19 +592,91 @@ 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
delta morphismRestrict
exact PresheafedSpace.IsOpenImmersion.comp _ _
+variable {X Y : Scheme.{u}}
+
+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.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 [resLE]
+
+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]
+
+@[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.base).map (homOfLE e')).le) := by
+ simp [← cancel_mono W.ι]
+
+@[reassoc (attr := simp)]
+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.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}) :
+ P (f.resLE U V e) ↔ P (f.resLE U' V' (e₁ ▸ e₂ ▸ e)) := by
+ subst e₁; subst e₂; rfl
+
+lemma resLE_preimage (f : X ⟶ Y) {U : Y.Opens} {V : X.Opens} (e : V ≤ f ⁻¹ᵁ U)
+ (O : U.toScheme.Opens) :
+ f.resLE U V e ⁻¹ᵁ O = V.ι ⁻¹ᵁ (f ⁻¹ᵁ U.ι ''ᵁ O) := by
+ rw [← preimage_comp, ← resLE_comp_ι f e, preimage_comp, preimage_image_eq]
+
+lemma le_preimage_resLE_iff {U : Y.Opens} {V : X.Opens} (e : V ≤ f ⁻¹ᵁ U)
+ (O : U.toScheme.Opens) (W : V.toScheme.Opens) :
+ W ≤ (f.resLE U V e) ⁻¹ᵁ O ↔ V.ι ''ᵁ W ≤ f ⁻¹ᵁ U.ι ''ᵁ O := by
+ simp [resLE_preimage, ← image_le_image_iff V.ι, image_preimage_eq_opensRange_inter, V.ι_image_le]
+
+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 [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]
+ rfl
+
+end Scheme.Hom
+
+/-- `f.resLE U V` induces `f.appLE U V` on global sections. -/
+noncomputable def arrowResLEAppIso (f : X ⟶ Y) (U : Y.Opens) (V : X.Opens) (e : V ≤ f ⁻¹ᵁ U) :
+ Arrow.mk ((f.resLE U V e).app ⊤) ≅ Arrow.mk (f.appLE U V e) :=
+ Arrow.isoMk U.topIso V.topIso <| by
+ simp only [Opens.map_top, Arrow.mk_left, Arrow.mk_right, Functor.id_obj, Scheme.Opens.topIso_hom,
+ eqToHom_op, Arrow.mk_hom, Scheme.Hom.map_appLE]
+ rw [← Scheme.Hom.appLE_eq_app, Scheme.Hom.resLE_appLE, Scheme.Hom.appLE_map]
+
end MorphismRestrict
/-- The restriction of an open cover to an open subset. -/
@@ -531,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 fab17a4f32795..18cc563e90561 100644
--- a/Mathlib/AlgebraicGeometry/Scheme.lean
+++ b/Mathlib/AlgebraicGeometry/Scheme.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.AlgebraicGeometry.Spec
import Mathlib.Algebra.Category.Ring.Constructions
@@ -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,28 +154,33 @@ 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)
lemma preimage_iSup_eq_top {ι} {U : ι → Opens Y} (hU : iSup U = ⊤) :
⨆ i, f ⁻¹ᵁ U i = ⊤ := f.preimage_iSup U ▸ hU ▸ rfl
+lemma preimage_le_preimage_of_le {U U' : Y.Opens} (hUU' : U ≤ U') :
+ f ⁻¹ᵁ U ≤ f ⁻¹ᵁ U' :=
+ fun _ ha ↦ hUU' ha
+
end Hom
@[simp]
@@ -173,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
@@ -204,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]
@@ -212,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`
@@ -240,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
@@ -258,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
@@ -272,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) :
@@ -314,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]
@@ -354,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
@@ -384,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]
@@ -446,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 :=
@@ -485,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
@@ -554,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))
@@ -575,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
@@ -603,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
@@ -627,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 b60cff5c8de99..4d4595fade0bd 100644
--- a/Mathlib/AlgebraicGeometry/Spec.lean
+++ b/Mathlib/AlgebraicGeometry/Spec.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Justus Springer
+Authors: Kim Morrison, Justus Springer
-/
import Mathlib.Geometry.RingedSpace.LocallyRingedSpace
import Mathlib.AlgebraicGeometry.StructureSheaf
@@ -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 692b54e2ecf76..6d0abf3ae594a 100644
--- a/Mathlib/AlgebraicGeometry/StructureSheaf.lean
+++ b/Mathlib/AlgebraicGeometry/StructureSheaf.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison
+Authors: Johan Commelin, Kim Morrison
-/
import Mathlib.AlgebraicGeometry.PrimeSpectrum.Basic
import Mathlib.Algebra.Category.Ring.Colimits
@@ -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 4a3ffcf186da8..25c2c3588b0e9 100644
--- a/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean
+++ b/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean
@@ -80,7 +80,7 @@ theorem d_squared (n : ℕ) : objD X (n + 1) ≫ objD X n = 0 := by
apply Finset.sum_bij φ
· -- φ(S) is contained in Sᶜ
intro ij hij
- simp only [S, Finset.mem_univ, Finset.compl_filter, Finset.mem_filter, true_and_iff,
+ simp only [S, Finset.mem_univ, Finset.compl_filter, Finset.mem_filter, true_and,
Fin.val_succ, Fin.coe_castLT] at hij ⊢
linarith
· -- φ : S → Sᶜ is injective
@@ -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/Degeneracies.lean b/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean
index ac8cbcf733f76..dde1b3dea55c9 100644
--- a/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean
+++ b/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean
@@ -95,7 +95,7 @@ theorem σ_comp_P_eq_zero (X : SimplicialObject C) {n q : ℕ} (i : Fin (n + 1))
comp_id, v.comp_Hσ_eq hi, assoc, SimplicialObject.δ_comp_σ_succ_assoc, Fin.eta,
decomposition_Q n q, sum_comp, sum_comp, Finset.sum_eq_zero, add_zero, add_neg_eq_zero]
intro j hj
- simp only [true_and_iff, Finset.mem_univ, Finset.mem_filter] at hj
+ simp only [Finset.mem_univ, Finset.mem_filter] at hj
obtain ⟨k, hk⟩ := Nat.le.dest (Nat.lt_succ_iff.mp (Fin.is_lt j))
rw [add_comm] at hk
have hi' : i = Fin.castSucc ⟨i, by omega⟩ := by
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 84980eaca3178..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
@@ -59,7 +59,7 @@ theorem reflTransSymmAux_mem_I (x : I × I) : reflTransSymmAux x ∈ I := by
· norm_num
· unit_interval
· rw [mul_assoc]
- apply mul_le_one
+ apply mul_le_one₀
· unit_interval
· apply mul_nonneg
· norm_num
@@ -69,7 +69,7 @@ theorem reflTransSymmAux_mem_I (x : I × I) : reflTransSymmAux x ∈ I := by
· apply mul_nonneg
· unit_interval
linarith [unitInterval.nonneg x.2, unitInterval.le_one x.2]
- · apply mul_le_one
+ · apply mul_le_one₀
· unit_interval
· linarith [unitInterval.nonneg x.2, unitInterval.le_one x.2]
· linarith [unitInterval.nonneg x.2, unitInterval.le_one x.2]
@@ -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/InducedMaps.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean
index c47f77c73c988..d00c54679772a 100644
--- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean
+++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean
@@ -96,7 +96,7 @@ private theorem end_path : f x₁ = g x₃ := by convert hfg 1 <;> simp only [Pa
theorem eq_path_of_eq_image :
(πₘ f).map ⟦p⟧ = hcast (start_path hfg) ≫ (πₘ g).map ⟦q⟧ ≫ hcast (end_path hfg).symm := by
- rw [Functor.conj_eqToHom_iff_heq
+ rw [conj_eqToHom_iff_heq
((πₘ f).map ⟦p⟧) ((πₘ g).map ⟦q⟧)
(FundamentalGroupoid.ext <| start_path hfg)
(FundamentalGroupoid.ext <| end_path hfg)]
@@ -178,7 +178,7 @@ theorem evalAt_eq (x : X) : ⟦H.evalAt x⟧ = hcast (H.apply_zero x).symm ≫
(πₘ H.uliftMap).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫
hcast (H.apply_one x).symm.symm := by
dsimp only [prodToProdTopI, uhpath01, hcast]
- refine (@Functor.conj_eqToHom_iff_heq (πₓ Y) _ _ _ _ _ _ _ _
+ refine (@conj_eqToHom_iff_heq (πₓ Y) _ _ _ _ _ _ _ _
(FundamentalGroupoid.ext <| H.apply_one x).symm).mpr ?_
simp only [id_eq_path_refl, prodToProdTop_map, Path.Homotopic.prod_lift, map_eq, ←
Path.Homotopic.map_lift]
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 62e4f9ca124ea..0ce1710a542c8 100644
--- a/Mathlib/AlgebraicTopology/MooreComplex.lean
+++ b/Mathlib/AlgebraicTopology/MooreComplex.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Homology.HomologicalComplex
import Mathlib.AlgebraicTopology.SimplicialObject
@@ -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 1f52cf7037c0b..72bc3cc192913 100644
--- a/Mathlib/AlgebraicTopology/SimplexCategory.lean
+++ b/Mathlib/AlgebraicTopology/SimplexCategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison, Adam Topaz
+Authors: Johan Commelin, Kim Morrison, Adam Topaz
-/
import Mathlib.Tactic.Linarith
import Mathlib.CategoryTheory.Skeletal
@@ -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,9 +209,41 @@ 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)
+
theorem hom_zero_zero (f : ([0] : SimplexCategory) ⟶ [0]) : f = 𝟙 _ := by
- ext : 3
- apply @Subsingleton.elim (Fin 1)
+ apply Subsingleton.elim
end
@@ -398,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
@@ -488,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
@@ -628,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'
@@ -643,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
@@ -691,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 _)
@@ -725,7 +834,7 @@ theorem eq_id_of_mono {x : SimplexCategory} (i : x ⟶ x) [Mono i] : i = 𝟙 _
apply isIso_of_bijective
dsimp
rw [Fintype.bijective_iff_injective_and_card i.toOrderHom, ← mono_iff_injective,
- eq_self_iff_true, and_true_iff]
+ eq_self_iff_true, and_true]
infer_instance
theorem eq_id_of_epi {x : SimplexCategory} (i : x ⟶ x) [Epi i] : i = 𝟙 _ := by
@@ -735,7 +844,7 @@ theorem eq_id_of_epi {x : SimplexCategory} (i : x ⟶ x) [Epi i] : i = 𝟙 _ :=
apply isIso_of_bijective
dsimp
rw [Fintype.bijective_iff_surjective_and_card i.toOrderHom, ← epi_iff_surjective,
- eq_self_iff_true, and_true_iff]
+ eq_self_iff_true, and_true]
infer_instance
theorem eq_σ_of_epi {n : ℕ} (θ : mk (n + 1) ⟶ mk n) [Epi θ] : ∃ i : Fin (n + 1), θ = σ i := by
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
new file mode 100644
index 0000000000000..2dde40d7ea1e5
--- /dev/null
+++ b/Mathlib/AlgebraicTopology/SimplicialCategory/SimplicialObject.lean
@@ -0,0 +1,41 @@
+/-
+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.AlgebraicTopology.SimplicialCategory.Basic
+import Mathlib.CategoryTheory.Functor.FunctorHom
+
+/-!
+# The category of simplicial objects is simplicial
+
+In `CategoryTheory.Functor.FunctorHom`, it was shown that a category of functors
+`C ⥤ D` is enriched over a suitable category `C ⥤ Type _` of functors to types.
+
+In this file, we deduce that `SimplicialObject D` is enriched over `SSet.{v} D`
+(when `D : Type u` and `[Category.{v} D]`) and that `SimplicialObject D`
+is actually a simplicial category. In particular, the category of simplicial
+sets is a simplicial category.
+
+-/
+
+universe v u
+
+namespace CategoryTheory
+
+variable {D : Type u} [Category.{v} D]
+
+namespace SimplicialObject
+
+noncomputable instance : EnrichedCategory SSet.{v} (SimplicialObject D) :=
+ inferInstanceAs (EnrichedCategory (_ ⥤ Type v) (_ ⥤ D))
+
+noncomputable instance : SimplicialCategory (SimplicialObject D) where
+ homEquiv := Functor.natTransEquiv.symm
+
+noncomputable instance : SimplicialCategory SSet.{v} :=
+ inferInstanceAs (SimplicialCategory (SimplicialObject (Type v)))
+
+end SimplicialObject
+
+end CategoryTheory
diff --git a/Mathlib/AlgebraicTopology/SimplicialObject.lean b/Mathlib/AlgebraicTopology/SimplicialObject.lean
index 4d65c1b5fcf57..d99137665f53d 100644
--- a/Mathlib/AlgebraicTopology/SimplicialObject.lean
+++ b/Mathlib/AlgebraicTopology/SimplicialObject.lean
@@ -1,10 +1,12 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison, Adam Topaz
+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 79%
rename from Mathlib/AlgebraicTopology/SimplicialSet.lean
rename to Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean
index e20ccf4e006ff..814de7455bce4 100644
--- a/Mathlib/AlgebraicTopology/SimplicialSet.lean
+++ b/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison, Adam Topaz
+Authors: Johan Commelin, Kim Morrison, Adam Topaz
-/
import Mathlib.AlgebraicTopology.SimplicialObject
import Mathlib.CategoryTheory.Limits.Shapes.Types
@@ -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 21364f30fc245..d97397b1c6019 100644
--- a/Mathlib/AlgebraicTopology/SingularSet.lean
+++ b/Mathlib/AlgebraicTopology/SingularSet.lean
@@ -1,9 +1,9 @@
/-
Copyright (c) 2023 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison, Adam Topaz
+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 9caab40add1e5..b04809638446e 100644
--- a/Mathlib/Analysis/Analytic/Basic.lean
+++ b/Mathlib/Analysis/Analytic/Basic.lean
@@ -49,14 +49,13 @@ Additionally, let `f` be a function from `E` to `F`.
* `HasFPowerSeriesAt f p x`: on some ball of center `x` with positive radius, holds
`HasFPowerSeriesOnBall f p x r`.
* `AnalyticAt 𝕜 f x`: there exists a power series `p` such that holds `HasFPowerSeriesAt f p x`.
-* `AnalyticOn 𝕜 f s`: the function `f` is analytic at every point of `s`.
+* `AnalyticOnNhd 𝕜 f s`: the function `f` is analytic at every point of `s`.
-We also define versions of `HasFPowerSeriesOnBall`, `AnalyticAt`, and `AnalyticOn` restricted to a
-set, similar to `ContinuousWithinAt`. See `Mathlib.Analysis.Analytic.Within` for basic properties.
+We also define versions of `HasFPowerSeriesOnBall`, `AnalyticAt`, and `AnalyticOnNhd` restricted to
+a set, similar to `ContinuousWithinAt`. See `Mathlib.Analysis.Analytic.Within` for basic properties.
-* `AnalyticWithinAt 𝕜 f s x` means a power series at `x` converges to `f` on `𝓝[s] x`, and
- `f` is continuous within `s` at `x`.
-* `AnalyticWithinOn 𝕜 f s t` means `∀ x ∈ t, AnalyticWithinAt 𝕜 f s x`.
+* `AnalyticWithinAt 𝕜 f s x` means a power series at `x` converges to `f` on `𝓝[s ∪ {x}] x`.
+* `AnalyticOn 𝕜 f s t` means `∀ x ∈ t, AnalyticWithinAt 𝕜 f s x`.
We develop the basic properties of these notions, notably:
* If a function admits a power series, it is continuous (see
@@ -64,10 +63,6 @@ We develop the basic properties of these notions, notably:
`AnalyticAt.continuousAt`).
* In a complete space, the sum of a formal power series with positive radius is well defined on the
disk of convergence, see `FormalMultilinearSeries.hasFPowerSeriesOnBall`.
-* If a function admits a power series in a ball, then it is analytic at any point `y` of this ball,
- and the power series there can be expressed in terms of the initial power series `p` as
- `p.changeOrigin y`. See `HasFPowerSeriesOnBall.changeOrigin`. It follows in particular that
- the set of points at which a given function is analytic is open, see `isOpen_analyticAt`.
## Implementation details
@@ -230,7 +225,7 @@ theorem lt_radius_of_isBigO (h₀ : r ≠ 0) {a : ℝ} (ha : a ∈ Ioo (-1 : ℝ
theorem norm_mul_pow_le_of_lt_radius (p : FormalMultilinearSeries 𝕜 E F) {r : ℝ≥0}
(h : (r : ℝ≥0∞) < p.radius) : ∃ C > 0, ∀ n, ‖p n‖ * (r : ℝ) ^ n ≤ C :=
let ⟨_, ha, C, hC, h⟩ := p.norm_mul_pow_le_mul_pow_of_lt_radius h
- ⟨C, hC, fun n => (h n).trans <| mul_le_of_le_one_right hC.lt.le (pow_le_one _ ha.1.le ha.2.le)⟩
+ ⟨C, hC, fun n => (h n).trans <| mul_le_of_le_one_right hC.lt.le (pow_le_one₀ ha.1.le ha.2.le)⟩
/-- For `r` strictly smaller than the radius of `p`, then `‖pₙ‖ rⁿ` is bounded. -/
theorem norm_le_div_pow_of_pos_of_lt_radius (p : FormalMultilinearSeries 𝕜 E F) {r : ℝ≥0}
@@ -297,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⟩
@@ -306,6 +301,18 @@ theorem le_mul_pow_of_radius_pos (p : FormalMultilinearSeries 𝕜 E F) (h : 0 <
rw [inv_pow, ← div_eq_mul_inv]
exact hCp n
+lemma radius_le_of_le {𝕜' E' F' : Type*}
+ [NontriviallyNormedField 𝕜'] [NormedAddCommGroup E'] [NormedSpace 𝕜' E']
+ [NormedAddCommGroup F'] [NormedSpace 𝕜' F']
+ {p : FormalMultilinearSeries 𝕜 E F} {q : FormalMultilinearSeries 𝕜' E' F'}
+ (h : ∀ n, ‖p n‖ ≤ ‖q n‖) : q.radius ≤ p.radius := by
+ apply le_of_forall_nnreal_lt (fun r hr ↦ ?_)
+ rcases norm_mul_pow_le_of_lt_radius _ hr with ⟨C, -, hC⟩
+ apply le_radius_of_bound _ C (fun n ↦ ?_)
+ apply le_trans _ (hC n)
+ gcongr
+ exact h n
+
/-- The radius of the sum of two formal series is at least the minimum of their two radii. -/
theorem min_radius_le_radius_add (p q : FormalMultilinearSeries 𝕜 E F) :
min p.radius q.radius ≤ (p + q).radius := by
@@ -340,7 +347,7 @@ end FormalMultilinearSeries
section
-variable {f g : E → F} {p pf pg : FormalMultilinearSeries 𝕜 E F} {x : E} {r r' : ℝ≥0∞}
+variable {f g : E → F} {p pf pg : FormalMultilinearSeries 𝕜 E F} {s t : Set E} {x : E} {r r' : ℝ≥0∞}
/-- Given a function `f : E → F` and a formal multilinear series `p`, we say that `f` has `p` as
a power series on the ball of radius `r > 0` around `x` if `f (x + y) = ∑' pₙ yⁿ` for all `‖y‖ < r`.
@@ -352,7 +359,8 @@ structure HasFPowerSeriesOnBall (f : E → F) (p : FormalMultilinearSeries 𝕜
hasSum :
∀ {y}, y ∈ EMetric.ball (0 : E) r → HasSum (fun n : ℕ => p n fun _ : Fin n => y) (f (x + y))
-/-- Analogue of `HasFPowerSeriesOnBall` where convergence is required only on a set `s`. -/
+/-- Analogue of `HasFPowerSeriesOnBall` where convergence is required only on a set `s`. We also
+require convergence at `x` as the behavior of this notion is very bad otherwise. -/
structure HasFPowerSeriesWithinOnBall (f : E → F) (p : FormalMultilinearSeries 𝕜 E F) (s : Set E)
(x : E) (r : ℝ≥0∞) : Prop where
/-- `p` converges on `ball 0 r` -/
@@ -360,10 +368,8 @@ structure HasFPowerSeriesWithinOnBall (f : E → F) (p : FormalMultilinearSeries
/-- The radius of convergence is positive -/
r_pos : 0 < r
/-- `p converges to f` within `s` -/
- hasSum : ∀ {y}, x + y ∈ s → y ∈ EMetric.ball (0 : E) r →
+ hasSum : ∀ {y}, x + y ∈ insert x s → y ∈ EMetric.ball (0 : E) r →
HasSum (fun n : ℕ => p n fun _ : Fin n => y) (f (x + y))
- /-- We require `ContinuousWithinAt f s x` to ensure `f x` is nice -/
- continuousWithinAt : ContinuousWithinAt f s x
/-- Given a function `f : E → F` and a formal multilinear series `p`, we say that `f` has `p` as
a power series around `x` if `f (x + y) = ∑' pₙ yⁿ` for all `y` in a neighborhood of `0`. -/
@@ -390,14 +396,21 @@ def AnalyticWithinAt (f : E → F) (s : Set E) (x : E) : Prop :=
/-- Given a function `f : E → F`, we say that `f` is analytic on a set `s` if it is analytic around
every point of `s`. -/
-def AnalyticOn (f : E → F) (s : Set E) :=
+def AnalyticOnNhd (f : E → F) (s : Set E) :=
∀ x, x ∈ s → AnalyticAt 𝕜 f x
-/-- `f` is analytic within `s` if it is analytic within `s` at each point of `t`. Note that
-this is weaker than `AnalyticOn 𝕜 f s`, as `f` is allowed to be arbitrary outside `s`. -/
-def AnalyticWithinOn (f : E → F) (s : Set E) : Prop :=
+/-- `f` is analytic within `s` if it is analytic within `s` at each point of `s`. Note that
+this is weaker than `AnalyticOnNhd 𝕜 f s`, as `f` is allowed to be arbitrary outside `s`. -/
+def AnalyticOn (f : E → F) (s : Set E) : Prop :=
∀ x ∈ s, AnalyticWithinAt 𝕜 f s x
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn := AnalyticOn
+
+/-!
+### `HasFPowerSeriesOnBall` and `HasFPowerSeriesWithinOnBall`
+-/
+
variable {𝕜}
theorem HasFPowerSeriesOnBall.hasFPowerSeriesAt (hf : HasFPowerSeriesOnBall f p x r) :
@@ -410,14 +423,16 @@ theorem HasFPowerSeriesAt.analyticAt (hf : HasFPowerSeriesAt f p x) : AnalyticAt
theorem HasFPowerSeriesOnBall.analyticAt (hf : HasFPowerSeriesOnBall f p x r) : AnalyticAt 𝕜 f x :=
hf.hasFPowerSeriesAt.analyticAt
-theorem HasFPowerSeriesOnBall.congr (hf : HasFPowerSeriesOnBall f p x r)
- (hg : EqOn f g (EMetric.ball x r)) : HasFPowerSeriesOnBall g p x r :=
- { r_le := hf.r_le
- r_pos := hf.r_pos
- hasSum := fun {y} hy => by
- convert hf.hasSum hy using 1
- apply hg.symm
- simpa [edist_eq_coe_nnnorm_sub] using hy }
+theorem HasFPowerSeriesWithinOnBall.hasFPowerSeriesWithinAt
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) : HasFPowerSeriesWithinAt f p s x :=
+ ⟨r, hf⟩
+
+theorem HasFPowerSeriesWithinAt.analyticWithinAt (hf : HasFPowerSeriesWithinAt f p s x) :
+ AnalyticWithinAt 𝕜 f s x := ⟨p, hf⟩
+
+theorem HasFPowerSeriesWithinOnBall.analyticWithinAt (hf : HasFPowerSeriesWithinOnBall f p s x r) :
+ AnalyticWithinAt 𝕜 f s x :=
+ hf.hasFPowerSeriesWithinAt.analyticWithinAt
/-- If a function `f` has a power series `p` around `x`, then the function `z ↦ f (z - y)` has the
same power series around `x + y`. -/
@@ -429,6 +444,13 @@ theorem HasFPowerSeriesOnBall.comp_sub (hf : HasFPowerSeriesOnBall f p x r) (y :
convert hf.hasSum hz using 2
abel }
+theorem HasFPowerSeriesWithinOnBall.hasSum_sub (hf : HasFPowerSeriesWithinOnBall f p s x r) {y : E}
+ (hy : y ∈ (insert x s) ∩ EMetric.ball x r) :
+ HasSum (fun n : ℕ => p n fun _ => y - x) (f y) := by
+ have : y - x ∈ EMetric.ball (0 : E) r := by simpa [edist_eq_coe_nnnorm_sub] using hy.2
+ have := hf.hasSum (by simpa only [add_sub_cancel] using hy.1) this
+ simpa only [add_sub_cancel]
+
theorem HasFPowerSeriesOnBall.hasSum_sub (hf : HasFPowerSeriesOnBall f p x r) {y : E}
(hy : y ∈ EMetric.ball x r) : HasSum (fun n : ℕ => p n fun _ => y - x) (f y) := by
have : y - x ∈ EMetric.ball (0 : E) r := by simpa [edist_eq_coe_nnnorm_sub] using hy
@@ -437,14 +459,69 @@ theorem HasFPowerSeriesOnBall.hasSum_sub (hf : HasFPowerSeriesOnBall f p x r) {y
theorem HasFPowerSeriesOnBall.radius_pos (hf : HasFPowerSeriesOnBall f p x r) : 0 < p.radius :=
lt_of_lt_of_le hf.r_pos hf.r_le
+theorem HasFPowerSeriesWithinOnBall.radius_pos (hf : HasFPowerSeriesWithinOnBall f p s x r) :
+ 0 < p.radius :=
+ lt_of_lt_of_le hf.r_pos hf.r_le
+
theorem HasFPowerSeriesAt.radius_pos (hf : HasFPowerSeriesAt f p x) : 0 < p.radius :=
let ⟨_, hr⟩ := hf
hr.radius_pos
+theorem HasFPowerSeriesWithinOnBall.of_le
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) (r'_pos : 0 < r') (hr : r' ≤ r) :
+ HasFPowerSeriesWithinOnBall f p s x r' :=
+ ⟨le_trans hr hf.1, r'_pos, fun hy h'y => hf.hasSum hy (EMetric.ball_subset_ball hr h'y)⟩
+
theorem HasFPowerSeriesOnBall.mono (hf : HasFPowerSeriesOnBall f p x r) (r'_pos : 0 < r')
(hr : r' ≤ r) : HasFPowerSeriesOnBall f p x r' :=
⟨le_trans hr hf.1, r'_pos, fun hy => hf.hasSum (EMetric.ball_subset_ball hr hy)⟩
+lemma HasFPowerSeriesWithinOnBall.congr {f g : E → F} {p : FormalMultilinearSeries 𝕜 E F}
+ {s : Set E} {x : E} {r : ℝ≥0∞} (h : HasFPowerSeriesWithinOnBall f p s x r)
+ (h' : EqOn g f (s ∩ EMetric.ball x r)) (h'' : g x = f x) :
+ HasFPowerSeriesWithinOnBall g p s x r := by
+ refine ⟨h.r_le, h.r_pos, ?_⟩
+ intro y hy h'y
+ convert h.hasSum hy h'y using 1
+ simp only [mem_insert_iff, add_right_eq_self] at hy
+ rcases hy with rfl | hy
+ · simpa using h''
+ · apply h'
+ refine ⟨hy, ?_⟩
+ simpa [edist_eq_coe_nnnorm_sub] using h'y
+
+/-- Variant of `HasFPowerSeriesWithinOnBall.congr` in which one requests equality on `insert x s`
+instead of separating `x` and `s`. -/
+lemma HasFPowerSeriesWithinOnBall.congr' {f g : E → F} {p : FormalMultilinearSeries 𝕜 E F}
+ {s : Set E} {x : E} {r : ℝ≥0∞} (h : HasFPowerSeriesWithinOnBall f p s x r)
+ (h' : EqOn g f (insert x s ∩ EMetric.ball x r)) :
+ HasFPowerSeriesWithinOnBall g p s x r := by
+ refine ⟨h.r_le, h.r_pos, fun {y} hy h'y ↦ ?_⟩
+ convert h.hasSum hy h'y using 1
+ exact h' ⟨hy, by simpa [edist_eq_coe_nnnorm_sub] using h'y⟩
+
+lemma HasFPowerSeriesWithinAt.congr {f g : E → F} {p : FormalMultilinearSeries 𝕜 E F} {s : Set E}
+ {x : E} (h : HasFPowerSeriesWithinAt f p s x) (h' : g =ᶠ[𝓝[s] x] f) (h'' : g x = f x) :
+ HasFPowerSeriesWithinAt g p s x := by
+ rcases h with ⟨r, hr⟩
+ obtain ⟨ε, εpos, hε⟩ : ∃ ε > 0, EMetric.ball x ε ∩ s ⊆ {y | g y = f y} :=
+ EMetric.mem_nhdsWithin_iff.1 h'
+ let r' := min r ε
+ refine ⟨r', ?_⟩
+ have := hr.of_le (r' := r') (by simp [r', εpos, hr.r_pos]) (min_le_left _ _)
+ apply this.congr _ h''
+ intro z hz
+ exact hε ⟨EMetric.ball_subset_ball (min_le_right _ _) hz.2, hz.1⟩
+
+theorem HasFPowerSeriesOnBall.congr (hf : HasFPowerSeriesOnBall f p x r)
+ (hg : EqOn f g (EMetric.ball x r)) : HasFPowerSeriesOnBall g p x r :=
+ { r_le := hf.r_le
+ r_pos := hf.r_pos
+ hasSum := fun {y} hy => by
+ convert hf.hasSum hy using 1
+ apply hg.symm
+ simpa [edist_eq_coe_nnnorm_sub] using hy }
+
theorem HasFPowerSeriesAt.congr (hf : HasFPowerSeriesAt f p x) (hg : f =ᶠ[𝓝 x] g) :
HasFPowerSeriesAt g p x := by
rcases hf with ⟨r₁, h₁⟩
@@ -453,6 +530,12 @@ theorem HasFPowerSeriesAt.congr (hf : HasFPowerSeriesAt f p x) (hg : f =ᶠ[𝓝
(h₁.mono (lt_min h₁.r_pos h₂pos) inf_le_left).congr
fun y hy => h₂ (EMetric.ball_subset_ball inf_le_right hy)⟩
+protected theorem HasFPowerSeriesWithinAt.eventually (hf : HasFPowerSeriesWithinAt f p s x) :
+ ∀ᶠ r : ℝ≥0∞ in 𝓝[>] 0, HasFPowerSeriesWithinOnBall f p s x r :=
+ let ⟨_, hr⟩ := hf
+ mem_of_superset (Ioo_mem_nhdsWithin_Ioi (left_mem_Ico.2 hr.r_pos)) fun _ hr' =>
+ hr.of_le hr'.1 hr'.2.le
+
protected theorem HasFPowerSeriesAt.eventually (hf : HasFPowerSeriesAt f p x) :
∀ᶠ r : ℝ≥0∞ in 𝓝[>] 0, HasFPowerSeriesOnBall f p x r :=
let ⟨_, hr⟩ := hf
@@ -487,149 +570,352 @@ theorem HasFPowerSeriesAt.eventually_eq_zero
let ⟨_, hr⟩ := hf
hr.eventually_eq_zero
-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 => ?_⟩
- simp [constFormalMultilinearSeries_apply hn]
+@[simp] lemma hasFPowerSeriesWithinOnBall_univ :
+ HasFPowerSeriesWithinOnBall f p univ x r ↔ HasFPowerSeriesOnBall f p x r := by
+ constructor
+ · intro h
+ refine ⟨h.r_le, h.r_pos, fun {y} m ↦ h.hasSum (by simp) m⟩
+ · intro h
+ exact ⟨h.r_le, h.r_pos, fun {y} _ m => h.hasSum m⟩
+
+@[simp] lemma hasFPowerSeriesWithinAt_univ :
+ HasFPowerSeriesWithinAt f p univ x ↔ HasFPowerSeriesAt f p x := by
+ simp only [HasFPowerSeriesWithinAt, hasFPowerSeriesWithinOnBall_univ, HasFPowerSeriesAt]
+
+lemma HasFPowerSeriesWithinOnBall.mono (hf : HasFPowerSeriesWithinOnBall f p s x r) (h : t ⊆ s) :
+ HasFPowerSeriesWithinOnBall f p t x r where
+ r_le := hf.r_le
+ r_pos := hf.r_pos
+ hasSum hy h'y := hf.hasSum (insert_subset_insert h hy) h'y
+
+lemma HasFPowerSeriesOnBall.hasFPowerSeriesWithinOnBall (hf : HasFPowerSeriesOnBall f p x r) :
+ HasFPowerSeriesWithinOnBall f p s x r := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ exact hf.mono (subset_univ _)
+
+lemma HasFPowerSeriesWithinAt.mono (hf : HasFPowerSeriesWithinAt f p s x) (h : t ⊆ s) :
+ HasFPowerSeriesWithinAt f p t x := by
+ obtain ⟨r, hp⟩ := hf
+ exact ⟨r, hp.mono h⟩
+
+lemma HasFPowerSeriesAt.hasFPowerSeriesWithinAt (hf : HasFPowerSeriesAt f p x) :
+ HasFPowerSeriesWithinAt f p s x := by
+ rw [← hasFPowerSeriesWithinAt_univ] at hf
+ apply hf.mono (subset_univ _)
+
+theorem HasFPowerSeriesWithinAt.mono_of_mem
+ (h : HasFPowerSeriesWithinAt f p s x) (hst : s ∈ 𝓝[t] x) :
+ HasFPowerSeriesWithinAt f p t x := by
+ rcases h with ⟨r, hr⟩
+ rcases EMetric.mem_nhdsWithin_iff.1 hst with ⟨r', r'_pos, hr'⟩
+ refine ⟨min r r', ?_⟩
+ have Z := hr.of_le (by simp [r'_pos, hr.r_pos]) (min_le_left r r')
+ refine ⟨Z.r_le, Z.r_pos, fun {y} hy h'y ↦ ?_⟩
+ apply Z.hasSum ?_ h'y
+ simp only [mem_insert_iff, add_right_eq_self] at hy
+ rcases hy with rfl | hy
+ · simp
+ apply mem_insert_of_mem _ (hr' ?_)
+ simp only [EMetric.mem_ball, edist_eq_coe_nnnorm_sub, sub_zero, lt_min_iff, mem_inter_iff,
+ add_sub_cancel_left, hy, and_true] at h'y ⊢
+ exact h'y.2
+
+@[simp] lemma hasFPowerSeriesWithinOnBall_insert_self :
+ HasFPowerSeriesWithinOnBall f p (insert x s) x r ↔ HasFPowerSeriesWithinOnBall f p s x r := by
+ refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ <;>
+ exact ⟨h.r_le, h.r_pos, fun {y} ↦ by simpa only [insert_idem] using h.hasSum (y := y)⟩
+
+@[simp] theorem hasFPowerSeriesWithinAt_insert {y : E} :
+ HasFPowerSeriesWithinAt f p (insert y s) x ↔ HasFPowerSeriesWithinAt f p s x := by
+ rcases eq_or_ne x y with rfl | hy
+ · simp [HasFPowerSeriesWithinAt]
+ · refine ⟨fun h ↦ h.mono (subset_insert _ _), fun h ↦ ?_⟩
+ apply HasFPowerSeriesWithinAt.mono_of_mem h
+ rw [nhdsWithin_insert_of_ne hy]
+ exact self_mem_nhdsWithin
+
+theorem HasFPowerSeriesWithinOnBall.coeff_zero (hf : HasFPowerSeriesWithinOnBall f pf s x r)
+ (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 _ => 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
+ have A := (hf.hasSum (by simp) zero_mem).unique (hasSum_single _ this)
+ simpa [v_eq] using A.symm
-theorem hasFPowerSeriesAt_const {c : F} {e : E} :
- HasFPowerSeriesAt (fun _ => c) (constFormalMultilinearSeries 𝕜 E c) e :=
- ⟨⊤, hasFPowerSeriesOnBall_const⟩
+theorem HasFPowerSeriesOnBall.coeff_zero (hf : HasFPowerSeriesOnBall f pf x r)
+ (v : Fin 0 → E) : pf 0 v = f x := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ exact hf.coeff_zero v
-theorem analyticAt_const {v : F} : AnalyticAt 𝕜 (fun _ => v) x :=
- ⟨constFormalMultilinearSeries 𝕜 E v, hasFPowerSeriesAt_const⟩
+theorem HasFPowerSeriesWithinAt.coeff_zero (hf : HasFPowerSeriesWithinAt f pf s x) (v : Fin 0 → E) :
+ pf 0 v = f x :=
+ let ⟨_, hrf⟩ := hf
+ hrf.coeff_zero v
-theorem analyticOn_const {v : F} {s : Set E} : AnalyticOn 𝕜 (fun _ => v) s :=
- fun _ _ => analyticAt_const
+theorem HasFPowerSeriesAt.coeff_zero (hf : HasFPowerSeriesAt f pf x) (v : Fin 0 → E) :
+ pf 0 v = f x :=
+ let ⟨_, hrf⟩ := hf
+ hrf.coeff_zero v
-theorem HasFPowerSeriesOnBall.add (hf : HasFPowerSeriesOnBall f pf x r)
- (hg : HasFPowerSeriesOnBall g pg x r) : HasFPowerSeriesOnBall (f + g) (pf + pg) x r :=
- { r_le := le_trans (le_min_iff.2 ⟨hf.r_le, hg.r_le⟩) (pf.min_radius_le_radius_add pg)
- r_pos := hf.r_pos
- hasSum := fun hy => (hf.hasSum hy).add (hg.hasSum hy) }
+/-!
+### Analytic functions
+-/
-theorem HasFPowerSeriesAt.add (hf : HasFPowerSeriesAt f pf x) (hg : HasFPowerSeriesAt g pg x) :
- HasFPowerSeriesAt (f + g) (pf + pg) x := by
- rcases (hf.eventually.and hg.eventually).exists with ⟨r, hr⟩
- exact ⟨r, hr.1.add hr.2⟩
+@[simp] lemma analyticWithinAt_univ :
+ AnalyticWithinAt 𝕜 f univ x ↔ AnalyticAt 𝕜 f x := by
+ simp [AnalyticWithinAt, AnalyticAt]
-theorem AnalyticAt.congr (hf : AnalyticAt 𝕜 f x) (hg : f =ᶠ[𝓝 x] g) : AnalyticAt 𝕜 g x :=
- let ⟨_, hpf⟩ := hf
- (hpf.congr hg).analyticAt
+@[simp] lemma analyticOn_univ {f : E → F} :
+ AnalyticOn 𝕜 f univ ↔ AnalyticOnNhd 𝕜 f univ := by
+ simp only [AnalyticOn, analyticWithinAt_univ, AnalyticOnNhd]
-theorem analyticAt_congr (h : f =ᶠ[𝓝 x] g) : AnalyticAt 𝕜 f x ↔ AnalyticAt 𝕜 g x :=
- ⟨fun hf ↦ hf.congr h, fun hg ↦ hg.congr h.symm⟩
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn_univ := analyticOn_univ
-theorem AnalyticAt.add (hf : AnalyticAt 𝕜 f x) (hg : AnalyticAt 𝕜 g x) : AnalyticAt 𝕜 (f + g) x :=
- let ⟨_, hpf⟩ := hf
- let ⟨_, hqf⟩ := hg
- (hpf.add hqf).analyticAt
-
-theorem HasFPowerSeriesOnBall.neg (hf : HasFPowerSeriesOnBall f pf x r) :
- HasFPowerSeriesOnBall (-f) (-pf) x r :=
- { r_le := by
- rw [pf.radius_neg]
- exact hf.r_le
- r_pos := hf.r_pos
- hasSum := fun hy => (hf.hasSum hy).neg }
+lemma AnalyticWithinAt.mono (hf : AnalyticWithinAt 𝕜 f s x) (h : t ⊆ s) :
+ AnalyticWithinAt 𝕜 f t x := by
+ obtain ⟨p, hp⟩ := hf
+ exact ⟨p, hp.mono h⟩
-theorem HasFPowerSeriesAt.neg (hf : HasFPowerSeriesAt f pf x) : HasFPowerSeriesAt (-f) (-pf) x :=
- let ⟨_, hrf⟩ := hf
- hrf.neg.hasFPowerSeriesAt
+lemma AnalyticAt.analyticWithinAt (hf : AnalyticAt 𝕜 f x) : AnalyticWithinAt 𝕜 f s x := by
+ rw [← analyticWithinAt_univ] at hf
+ apply hf.mono (subset_univ _)
-theorem AnalyticAt.neg (hf : AnalyticAt 𝕜 f x) : AnalyticAt 𝕜 (-f) x :=
- let ⟨_, hpf⟩ := hf
- hpf.neg.analyticAt
+lemma AnalyticOnNhd.analyticOn (hf : AnalyticOnNhd 𝕜 f s) : AnalyticOn 𝕜 f s :=
+ fun x hx ↦ (hf x hx).analyticWithinAt
-theorem HasFPowerSeriesOnBall.sub (hf : HasFPowerSeriesOnBall f pf x r)
- (hg : HasFPowerSeriesOnBall g pg x r) : HasFPowerSeriesOnBall (f - g) (pf - pg) x r := by
- simpa only [sub_eq_add_neg] using hf.add hg.neg
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.analyticWithinOn := AnalyticOnNhd.analyticOn
-theorem HasFPowerSeriesAt.sub (hf : HasFPowerSeriesAt f pf x) (hg : HasFPowerSeriesAt g pg x) :
- HasFPowerSeriesAt (f - g) (pf - pg) x := by
- simpa only [sub_eq_add_neg] using hf.add hg.neg
+lemma AnalyticWithinAt.congr_of_eventuallyEq {f g : E → F} {s : Set E} {x : E}
+ (hf : AnalyticWithinAt 𝕜 f s x) (hs : g =ᶠ[𝓝[s] x] f) (hx : g x = f x) :
+ AnalyticWithinAt 𝕜 g s x := by
+ rcases hf with ⟨p, hp⟩
+ exact ⟨p, hp.congr hs hx⟩
-theorem AnalyticAt.sub (hf : AnalyticAt 𝕜 f x) (hg : AnalyticAt 𝕜 g x) :
- AnalyticAt 𝕜 (f - g) x := by
- simpa only [sub_eq_add_neg] using hf.add hg.neg
+lemma AnalyticWithinAt.congr_of_eventuallyEq_insert {f g : E → F} {s : Set E} {x : E}
+ (hf : AnalyticWithinAt 𝕜 f s x) (hs : g =ᶠ[𝓝[insert x s] x] f) :
+ AnalyticWithinAt 𝕜 g s x := by
+ apply hf.congr_of_eventuallyEq (nhdsWithin_mono x (subset_insert x s) hs)
+ apply mem_of_mem_nhdsWithin (mem_insert x s) hs
-theorem AnalyticOn.mono {s t : Set E} (hf : AnalyticOn 𝕜 f t) (hst : s ⊆ t) : AnalyticOn 𝕜 f s :=
- fun z hz => hf z (hst hz)
+lemma AnalyticWithinAt.congr {f g : E → F} {s : Set E} {x : E}
+ (hf : AnalyticWithinAt 𝕜 f s x) (hs : EqOn g f s) (hx : g x = f x) :
+ AnalyticWithinAt 𝕜 g s x :=
+ hf.congr_of_eventuallyEq hs.eventuallyEq_nhdsWithin hx
-theorem AnalyticOn.congr' {s : Set E} (hf : AnalyticOn 𝕜 f s) (hg : f =ᶠ[𝓝ˢ s] g) :
+lemma AnalyticOn.congr {f g : E → F} {s : Set E}
+ (hf : AnalyticOn 𝕜 f s) (hs : EqOn g f s) :
AnalyticOn 𝕜 g s :=
+ fun x m ↦ (hf x m).congr hs (hs m)
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.congr := AnalyticOn.congr
+
+theorem AnalyticAt.congr (hf : AnalyticAt 𝕜 f x) (hg : f =ᶠ[𝓝 x] g) : AnalyticAt 𝕜 g x :=
+ let ⟨_, hpf⟩ := hf
+ (hpf.congr hg).analyticAt
+
+theorem analyticAt_congr (h : f =ᶠ[𝓝 x] g) : AnalyticAt 𝕜 f x ↔ AnalyticAt 𝕜 g x :=
+ ⟨fun hf ↦ hf.congr h, fun hg ↦ hg.congr h.symm⟩
+
+theorem AnalyticOnNhd.mono {s t : Set E} (hf : AnalyticOnNhd 𝕜 f t) (hst : s ⊆ t) :
+ AnalyticOnNhd 𝕜 f s :=
+ fun z hz => hf z (hst hz)
+
+theorem AnalyticOnNhd.congr' (hf : AnalyticOnNhd 𝕜 f s) (hg : f =ᶠ[𝓝ˢ s] g) :
+ AnalyticOnNhd 𝕜 g s :=
fun z hz => (hf z hz).congr (mem_nhdsSet_iff_forall.mp hg z hz)
-theorem analyticOn_congr' {s : Set E} (h : f =ᶠ[𝓝ˢ s] g) : AnalyticOn 𝕜 f s ↔ AnalyticOn 𝕜 g s :=
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.congr' := AnalyticOnNhd.congr'
+
+theorem analyticOnNhd_congr' (h : f =ᶠ[𝓝ˢ s] g) : AnalyticOnNhd 𝕜 f s ↔ AnalyticOnNhd 𝕜 g s :=
⟨fun hf => hf.congr' h, fun hg => hg.congr' h.symm⟩
-theorem AnalyticOn.congr {s : Set E} (hs : IsOpen s) (hf : AnalyticOn 𝕜 f s) (hg : s.EqOn f g) :
- AnalyticOn 𝕜 g s :=
+@[deprecated (since := "2024-09-26")]
+alias analyticOn_congr' := analyticOnNhd_congr'
+
+theorem AnalyticOnNhd.congr (hs : IsOpen s) (hf : AnalyticOnNhd 𝕜 f s) (hg : s.EqOn f g) :
+ AnalyticOnNhd 𝕜 g s :=
hf.congr' <| mem_nhdsSet_iff_forall.mpr
(fun _ hz => eventuallyEq_iff_exists_mem.mpr ⟨s, hs.mem_nhds hz, hg⟩)
-theorem analyticOn_congr {s : Set E} (hs : IsOpen s) (h : s.EqOn f g) : AnalyticOn 𝕜 f s ↔
- AnalyticOn 𝕜 g s := ⟨fun hf => hf.congr hs h, fun hg => hg.congr hs h.symm⟩
+theorem analyticOnNhd_congr (hs : IsOpen s) (h : s.EqOn f g) : AnalyticOnNhd 𝕜 f s ↔
+ AnalyticOnNhd 𝕜 g s := ⟨fun hf => hf.congr hs h, fun hg => hg.congr hs h.symm⟩
-theorem AnalyticOn.add {s : Set E} (hf : AnalyticOn 𝕜 f s) (hg : AnalyticOn 𝕜 g s) :
- AnalyticOn 𝕜 (f + g) s :=
- fun z hz => (hf z hz).add (hg z hz)
+@[deprecated (since := "2024-09-26")]
+alias analyticOn_congr := analyticOnNhd_congr
-theorem AnalyticOn.neg {s : Set E} (hf : AnalyticOn 𝕜 f s) : AnalyticOn 𝕜 (-f) s :=
- fun z hz ↦ (hf z hz).neg
+theorem AnalyticWithinAt.mono_of_mem
+ (h : AnalyticWithinAt 𝕜 f s x) (hst : s ∈ 𝓝[t] x) : AnalyticWithinAt 𝕜 f t x := by
+ rcases h with ⟨p, hp⟩
+ exact ⟨p, hp.mono_of_mem hst⟩
-theorem AnalyticOn.sub {s : Set E} (hf : AnalyticOn 𝕜 f s) (hg : AnalyticOn 𝕜 g s) :
- AnalyticOn 𝕜 (f - g) s :=
- fun z hz => (hf z hz).sub (hg z hz)
+lemma AnalyticOn.mono {f : E → F} {s t : Set E} (h : AnalyticOn 𝕜 f t)
+ (hs : s ⊆ t) : AnalyticOn 𝕜 f s :=
+ fun _ m ↦ (h _ (hs m)).mono hs
-theorem HasFPowerSeriesOnBall.coeff_zero (hf : HasFPowerSeriesOnBall f pf x r) (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
- intro i hi
- have : 0 < i := pos_iff_ne_zero.2 hi
- exact ContinuousMultilinearMap.map_coord_zero _ (⟨0, this⟩ : Fin i) rfl
- have A := (hf.hasSum zero_mem).unique (hasSum_single _ this)
- simpa [v_eq] using A.symm
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.mono := AnalyticOn.mono
-theorem HasFPowerSeriesAt.coeff_zero (hf : HasFPowerSeriesAt f pf x) (v : Fin 0 → E) :
- pf 0 v = f x :=
- let ⟨_, hrf⟩ := hf
- hrf.coeff_zero v
+@[simp] theorem analyticWithinAt_insert {f : E → F} {s : Set E} {x y : E} :
+ AnalyticWithinAt 𝕜 f (insert y s) x ↔ AnalyticWithinAt 𝕜 f s x := by
+ simp [AnalyticWithinAt]
+
+/-!
+### Composition with linear maps
+-/
+
+/-- If a function `f` has a power series `p` on a ball within a set and `g` is linear,
+then `g ∘ f` has the power series `g ∘ p` on the same ball. -/
+theorem ContinuousLinearMap.comp_hasFPowerSeriesWithinOnBall (g : F →L[𝕜] G)
+ (h : HasFPowerSeriesWithinOnBall f p s x r) :
+ HasFPowerSeriesWithinOnBall (g ∘ f) (g.compFormalMultilinearSeries p) s x r where
+ r_le := h.r_le.trans (p.radius_le_radius_continuousLinearMap_comp _)
+ r_pos := h.r_pos
+ hasSum hy h'y := by
+ simpa only [ContinuousLinearMap.compFormalMultilinearSeries_apply,
+ ContinuousLinearMap.compContinuousMultilinearMap_coe, Function.comp_apply] using
+ g.hasSum (h.hasSum hy h'y)
/-- If a function `f` has a power series `p` on a ball and `g` is linear, then `g ∘ f` has the
power series `g ∘ p` on the same ball. -/
theorem ContinuousLinearMap.comp_hasFPowerSeriesOnBall (g : F →L[𝕜] G)
(h : HasFPowerSeriesOnBall f p x r) :
- HasFPowerSeriesOnBall (g ∘ f) (g.compFormalMultilinearSeries p) x r :=
- { r_le := h.r_le.trans (p.radius_le_radius_continuousLinearMap_comp _)
- r_pos := h.r_pos
- hasSum := fun hy => by
- simpa only [ContinuousLinearMap.compFormalMultilinearSeries_apply,
- ContinuousLinearMap.compContinuousMultilinearMap_coe, Function.comp_apply] using
- g.hasSum (h.hasSum hy) }
+ HasFPowerSeriesOnBall (g ∘ f) (g.compFormalMultilinearSeries p) x r := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at h ⊢
+ exact g.comp_hasFPowerSeriesWithinOnBall h
/-- If a function `f` is analytic on a set `s` and `g` is linear, then `g ∘ f` is analytic
on `s`. -/
-theorem ContinuousLinearMap.comp_analyticOn {s : Set E} (g : F →L[𝕜] G) (h : AnalyticOn 𝕜 f s) :
+theorem ContinuousLinearMap.comp_analyticOn (g : F →L[𝕜] G) (h : AnalyticOn 𝕜 f s) :
AnalyticOn 𝕜 (g ∘ f) s := by
rintro x hx
rcases h x hx with ⟨p, r, hp⟩
+ exact ⟨g.compFormalMultilinearSeries p, r, g.comp_hasFPowerSeriesWithinOnBall hp⟩
+
+/-- If a function `f` is analytic on a set `s` and `g` is linear, then `g ∘ f` is analytic
+on `s`. -/
+theorem ContinuousLinearMap.comp_analyticOnNhd
+ {s : Set E} (g : F →L[𝕜] G) (h : AnalyticOnNhd 𝕜 f s) :
+ AnalyticOnNhd 𝕜 (g ∘ f) s := by
+ rintro x hx
+ rcases h x hx with ⟨p, r, hp⟩
exact ⟨g.compFormalMultilinearSeries p, r, g.comp_hasFPowerSeriesOnBall hp⟩
+/-!
+### Relation between analytic function and the partial sums of its power series
+-/
+
+theorem HasFPowerSeriesWithinOnBall.tendsto_partialSum
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) {y : E} (hy : y ∈ EMetric.ball (0 : E) r)
+ (h'y : x + y ∈ insert x s) :
+ Tendsto (fun n => p.partialSum n y) atTop (𝓝 (f (x + y))) :=
+ (hf.hasSum h'y hy).tendsto_sum_nat
+
+theorem HasFPowerSeriesOnBall.tendsto_partialSum
+ (hf : HasFPowerSeriesOnBall f p x r) {y : E} (hy : y ∈ EMetric.ball (0 : E) r) :
+ Tendsto (fun n => p.partialSum n y) atTop (𝓝 (f (x + y))) :=
+ (hf.hasSum hy).tendsto_sum_nat
+
+theorem HasFPowerSeriesAt.tendsto_partialSum
+ (hf : HasFPowerSeriesAt f p x) :
+ ∀ᶠ y in 𝓝 0, Tendsto (fun n => p.partialSum n y) atTop (𝓝 (f (x + y))) := by
+ rcases hf with ⟨r, hr⟩
+ filter_upwards [EMetric.ball_mem_nhds (0 : E) hr.r_pos] with y hy
+ exact hr.tendsto_partialSum hy
+
+open Finset in
+/-- If a function admits a power series expansion within a ball, then the partial sums
+`p.partialSum n z` converge to `f (x + y)` as `n → ∞` and `z → y`. Note that `x + z` doesn't need
+to belong to the set where the power series expansion holds. -/
+theorem HasFPowerSeriesWithinOnBall.tendsto_partialSum_prod {y : E}
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) (hy : y ∈ EMetric.ball (0 : E) r)
+ (h'y : x + y ∈ insert x s) :
+ Tendsto (fun (z : ℕ × E) ↦ p.partialSum z.1 z.2) (atTop ×ˢ 𝓝 y) (𝓝 (f (x + y))) := by
+ have A : Tendsto (fun (z : ℕ × E) ↦ p.partialSum z.1 y) (atTop ×ˢ 𝓝 y) (𝓝 (f (x + y))) := by
+ apply (hf.tendsto_partialSum hy h'y).comp tendsto_fst
+ suffices Tendsto (fun (z : ℕ × E) ↦ p.partialSum z.1 z.2 - p.partialSum z.1 y)
+ (atTop ×ˢ 𝓝 y) (𝓝 0) by simpa using A.add this
+ apply Metric.tendsto_nhds.2 (fun ε εpos ↦ ?_)
+ obtain ⟨r', yr', r'r⟩ : ∃ (r' : ℝ≥0), ‖y‖₊ < r' ∧ r' < r := by
+ simp [edist_eq_coe_nnnorm] at hy
+ simpa using ENNReal.lt_iff_exists_nnreal_btwn.1 hy
+ have yr'_2 : ‖y‖ < r' := by simpa [← coe_nnnorm] using yr'
+ have S : Summable fun n ↦ ‖p n‖ * ↑r' ^ n := p.summable_norm_mul_pow (r'r.trans_le hf.r_le)
+ obtain ⟨k, hk⟩ : ∃ k, ∑' (n : ℕ), ‖p (n + k)‖ * ↑r' ^ (n + k) < ε / 4 := by
+ have : Tendsto (fun k ↦ ∑' n, ‖p (n + k)‖ * ↑r' ^ (n + k)) atTop (𝓝 0) := by
+ apply _root_.tendsto_sum_nat_add (f := fun n ↦ ‖p n‖ * ↑r' ^ n)
+ exact ((tendsto_order.1 this).2 _ (by linarith)).exists
+ have A : ∀ᶠ (z : ℕ × E) in atTop ×ˢ 𝓝 y,
+ dist (p.partialSum k z.2) (p.partialSum k y) < ε / 4 := by
+ have : ContinuousAt (fun z ↦ p.partialSum k z) y := (p.partialSum_continuous k).continuousAt
+ exact tendsto_snd (Metric.tendsto_nhds.1 this.tendsto (ε / 4) (by linarith))
+ have B : ∀ᶠ (z : ℕ × E) in atTop ×ˢ 𝓝 y, ‖z.2‖₊ < r' := by
+ suffices ∀ᶠ (z : E) in 𝓝 y, ‖z‖₊ < r' from tendsto_snd this
+ have : Metric.ball 0 r' ∈ 𝓝 y := Metric.isOpen_ball.mem_nhds (by simpa using yr'_2)
+ filter_upwards [this] with a ha using by simpa [← coe_nnnorm] using ha
+ have C : ∀ᶠ (z : ℕ × E) in atTop ×ˢ 𝓝 y, k ≤ z.1 := tendsto_fst (Ici_mem_atTop _)
+ filter_upwards [A, B, C]
+ rintro ⟨n, z⟩ hz h'z hkn
+ simp only [dist_eq_norm, sub_zero] at hz ⊢
+ have I (w : E) (hw : ‖w‖₊ < r') : ‖∑ i ∈ Ico k n, p i (fun _ ↦ w)‖ ≤ ε / 4 := calc
+ ‖∑ i ∈ Ico k n, p i (fun _ ↦ w)‖
+ _ = ‖∑ i ∈ range (n - k), p (i + k) (fun _ ↦ w)‖ := by
+ rw [sum_Ico_eq_sum_range]
+ congr with i
+ rw [add_comm k]
+ _ ≤ ∑ i ∈ range (n - k), ‖p (i + k) (fun _ ↦ w)‖ := norm_sum_le _ _
+ _ ≤ ∑ i ∈ range (n - k), ‖p (i + k)‖ * ‖w‖ ^ (i + k) := by
+ gcongr with i _hi; exact ((p (i + k)).le_opNorm _).trans_eq (by simp)
+ _ ≤ ∑ i ∈ range (n - k), ‖p (i + k)‖ * ↑r' ^ (i + k) := by
+ gcongr with i _hi; simpa [← coe_nnnorm] using hw.le
+ _ ≤ ∑' i, ‖p (i + k)‖ * ↑r' ^ (i + k) := by
+ apply sum_le_tsum _ (fun i _hi ↦ by positivity)
+ apply ((_root_.summable_nat_add_iff k).2 S)
+ _ ≤ ε / 4 := hk.le
+ calc
+ ‖p.partialSum n z - p.partialSum n y‖
+ _ = ‖∑ i ∈ range n, p i (fun _ ↦ z) - ∑ i ∈ range n, p i (fun _ ↦ y)‖ := rfl
+ _ = ‖(∑ i ∈ range k, p i (fun _ ↦ z) + ∑ i ∈ Ico k n, p i (fun _ ↦ z))
+ - (∑ i ∈ range k, p i (fun _ ↦ y) + ∑ i ∈ Ico k n, p i (fun _ ↦ y))‖ := by
+ simp [sum_range_add_sum_Ico _ hkn]
+ _ = ‖(p.partialSum k z - p.partialSum k y) + (∑ i ∈ Ico k n, p i (fun _ ↦ z))
+ + (- ∑ i ∈ Ico k n, p i (fun _ ↦ y))‖ := by
+ congr 1
+ 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
+ _ ≤ ε / 4 + ε / 4 + ε / 4 := by
+ gcongr
+ · exact I _ h'z
+ · simp only [norm_neg]; exact I _ yr'
+ _ < ε := by linarith
+
+/-- If a function admits a power series on a ball, then the partial sums
+`p.partialSum n z` converges to `f (x + y)` as `n → ∞` and `z → y`. -/
+theorem HasFPowerSeriesOnBall.tendsto_partialSum_prod {y : E}
+ (hf : HasFPowerSeriesOnBall f p x r) (hy : y ∈ EMetric.ball (0 : E) r) :
+ Tendsto (fun (z : ℕ × E) ↦ p.partialSum z.1 z.2) (atTop ×ˢ 𝓝 y) (𝓝 (f (x + y))) :=
+ (hf.hasFPowerSeriesWithinOnBall (s := univ)).tendsto_partialSum_prod hy (by simp)
+
/-- If a function admits a power series expansion, then it is exponentially close to the partial
sums of this power series on strict subdisks of the disk of convergence.
This version provides an upper estimate that decreases both in `‖y‖` and `n`. See also
-`HasFPowerSeriesOnBall.uniform_geometric_approx` for a weaker version. -/
-theorem HasFPowerSeriesOnBall.uniform_geometric_approx' {r' : ℝ≥0}
- (hf : HasFPowerSeriesOnBall f p x r) (h : (r' : ℝ≥0∞) < r) :
- ∃ a ∈ Ioo (0 : ℝ) 1, ∃ C > 0, ∀ y ∈ Metric.ball (0 : E) r', ∀ n,
+`HasFPowerSeriesWithinOnBall.uniform_geometric_approx` for a weaker version. -/
+theorem HasFPowerSeriesWithinOnBall.uniform_geometric_approx' {r' : ℝ≥0}
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) (h : (r' : ℝ≥0∞) < r) :
+ ∃ a ∈ Ioo (0 : ℝ) 1, ∃ C > 0, ∀ y ∈ Metric.ball (0 : E) r', ∀ n, x + y ∈ insert x s →
‖f (x + y) - p.partialSum n y‖ ≤ C * (a * (‖y‖ / r')) ^ n := by
obtain ⟨a, ha, C, hC, hp⟩ : ∃ a ∈ Ioo (0 : ℝ) 1, ∃ C > 0, ∀ n, ‖p n‖ * (r' : ℝ) ^ n ≤ C * a ^ n :=
p.norm_mul_pow_le_mul_pow_of_lt_radius (h.trans_le hf.r_le)
- refine ⟨a, ha, C / (1 - a), div_pos hC (sub_pos.2 ha.2), fun y hy n => ?_⟩
+ refine ⟨a, ha, C / (1 - a), div_pos hC (sub_pos.2 ha.2), fun y hy n ys => ?_⟩
have yr' : ‖y‖ < r' := by
rw [ball_zero_eq] at hy
exact hy
@@ -639,13 +925,13 @@ theorem HasFPowerSeriesOnBall.uniform_geometric_approx' {r' : ℝ≥0}
exact mod_cast yr'
rw [norm_sub_rev, ← mul_div_right_comm]
have ya : a * (‖y‖ / ↑r') ≤ a :=
- mul_le_of_le_one_right ha.1.le (div_le_one_of_le yr'.le r'.coe_nonneg)
+ mul_le_of_le_one_right ha.1.le (div_le_one_of_le₀ yr'.le r'.coe_nonneg)
suffices ‖p.partialSum n y - f (x + y)‖ ≤ C * (a * (‖y‖ / r')) ^ n / (1 - a * (‖y‖ / r')) by
refine this.trans ?_
have : 0 < a := ha.1
gcongr
apply_rules [sub_pos.2, ha.2]
- apply norm_sub_le_of_geometric_bound_of_hasSum (ya.trans_lt ha.2) _ (hf.hasSum this)
+ apply norm_sub_le_of_geometric_bound_of_hasSum (ya.trans_lt ha.2) _ (hf.hasSum ys this)
intro n
calc
‖(p n) fun _ : Fin n => y‖
@@ -655,58 +941,94 @@ theorem HasFPowerSeriesOnBall.uniform_geometric_approx' {r' : ℝ≥0}
_ ≤ C * (a * (‖y‖ / r')) ^ n := by rw [mul_pow, mul_assoc]
/-- If a function admits a power series expansion, then it is exponentially close to the partial
-sums of this power series on strict subdisks of the disk of convergence. -/
-theorem HasFPowerSeriesOnBall.uniform_geometric_approx {r' : ℝ≥0}
+sums of this power series on strict subdisks of the disk of convergence.
+
+This version provides an upper estimate that decreases both in `‖y‖` and `n`. See also
+`HasFPowerSeriesOnBall.uniform_geometric_approx` for a weaker version. -/
+theorem HasFPowerSeriesOnBall.uniform_geometric_approx' {r' : ℝ≥0}
(hf : HasFPowerSeriesOnBall f p x r) (h : (r' : ℝ≥0∞) < r) :
+ ∃ a ∈ Ioo (0 : ℝ) 1, ∃ C > 0, ∀ y ∈ Metric.ball (0 : E) r', ∀ n,
+ ‖f (x + y) - p.partialSum n y‖ ≤ C * (a * (‖y‖ / r')) ^ n := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ simpa using hf.uniform_geometric_approx' h
+
+/-- If a function admits a power series expansion within a set in a ball, then it is exponentially
+close to the partial sums of this power series on strict subdisks of the disk of convergence. -/
+theorem HasFPowerSeriesWithinOnBall.uniform_geometric_approx {r' : ℝ≥0}
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) (h : (r' : ℝ≥0∞) < r) :
∃ a ∈ Ioo (0 : ℝ) 1,
- ∃ C > 0, ∀ y ∈ Metric.ball (0 : E) r', ∀ n, ‖f (x + y) - p.partialSum n y‖ ≤ C * a ^ n := by
+ ∃ C > 0, ∀ y ∈ Metric.ball (0 : E) r', ∀ n, x + y ∈ insert x s →
+ ‖f (x + y) - p.partialSum n y‖ ≤ C * a ^ n := by
obtain ⟨a, ha, C, hC, hp⟩ : ∃ a ∈ Ioo (0 : ℝ) 1, ∃ C > 0, ∀ y ∈ Metric.ball (0 : E) r', ∀ n,
- ‖f (x + y) - p.partialSum n y‖ ≤ C * (a * (‖y‖ / r')) ^ n :=
+ x + y ∈ insert x s → ‖f (x + y) - p.partialSum n y‖ ≤ C * (a * (‖y‖ / r')) ^ n :=
hf.uniform_geometric_approx' h
- refine ⟨a, ha, C, hC, fun y hy n => (hp y hy n).trans ?_⟩
+ refine ⟨a, ha, C, hC, fun y hy n ys => (hp y hy n ys).trans ?_⟩
have yr' : ‖y‖ < r' := by rwa [ball_zero_eq] at hy
have := ha.1.le -- needed to discharge a side goal on the next line
gcongr
- exact mul_le_of_le_one_right ha.1.le (div_le_one_of_le yr'.le r'.coe_nonneg)
+ exact mul_le_of_le_one_right ha.1.le (div_le_one_of_le₀ yr'.le r'.coe_nonneg)
-/-- Taylor formula for an analytic function, `IsBigO` version. -/
-theorem HasFPowerSeriesAt.isBigO_sub_partialSum_pow (hf : HasFPowerSeriesAt f p x) (n : ℕ) :
- (fun y : E => f (x + y) - p.partialSum n y) =O[𝓝 0] fun y => ‖y‖ ^ n := by
+/-- If a function admits a power series expansion, then it is exponentially close to the partial
+sums of this power series on strict subdisks of the disk of convergence. -/
+theorem HasFPowerSeriesOnBall.uniform_geometric_approx {r' : ℝ≥0}
+ (hf : HasFPowerSeriesOnBall f p x r) (h : (r' : ℝ≥0∞) < r) :
+ ∃ a ∈ Ioo (0 : ℝ) 1,
+ ∃ C > 0, ∀ y ∈ Metric.ball (0 : E) r', ∀ n,
+ ‖f (x + y) - p.partialSum n y‖ ≤ C * a ^ n := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ simpa using hf.uniform_geometric_approx h
+
+/-- Taylor formula for an analytic function within a set, `IsBigO` version. -/
+theorem HasFPowerSeriesWithinAt.isBigO_sub_partialSum_pow
+ (hf : HasFPowerSeriesWithinAt f p s x) (n : ℕ) :
+ (fun y : E => f (x + y) - p.partialSum n y)
+ =O[𝓝[(x + ·)⁻¹' insert x s] 0] fun y => ‖y‖ ^ n := by
rcases hf with ⟨r, hf⟩
rcases ENNReal.lt_iff_exists_nnreal_btwn.1 hf.r_pos with ⟨r', r'0, h⟩
obtain ⟨a, -, C, -, hp⟩ : ∃ a ∈ Ioo (0 : ℝ) 1, ∃ C > 0, ∀ y ∈ Metric.ball (0 : E) r', ∀ n,
- ‖f (x + y) - p.partialSum n y‖ ≤ C * (a * (‖y‖ / r')) ^ n :=
+ x + y ∈ insert x s → ‖f (x + y) - p.partialSum n y‖ ≤ C * (a * (‖y‖ / r')) ^ n :=
hf.uniform_geometric_approx' h
refine isBigO_iff.2 ⟨C * (a / r') ^ n, ?_⟩
replace r'0 : 0 < (r' : ℝ) := mod_cast r'0
- filter_upwards [Metric.ball_mem_nhds (0 : E) r'0] with y hy
- simpa [mul_pow, mul_div_assoc, mul_assoc, div_mul_eq_mul_div] using hp y hy n
+ filter_upwards [inter_mem_nhdsWithin _ (Metric.ball_mem_nhds (0 : E) r'0)] with y hy
+ simpa [mul_pow, mul_div_assoc, mul_assoc, div_mul_eq_mul_div, div_pow]
+ using hp y hy.2 n (by simpa using hy.1)
-/-- If `f` has formal power series `∑ n, pₙ` on a ball of radius `r`, then for `y, z` in any smaller
-ball, the norm of the difference `f y - f z - p 1 (fun _ ↦ y - z)` is bounded above by
-`C * (max ‖y - x‖ ‖z - x‖) * ‖y - z‖`. This lemma formulates this property using `IsBigO` and
-`Filter.principal` on `E × E`. -/
-theorem HasFPowerSeriesOnBall.isBigO_image_sub_image_sub_deriv_principal
- (hf : HasFPowerSeriesOnBall f p x r) (hr : r' < r) :
- (fun y : E × E => f y.1 - f y.2 - p 1 fun _ => y.1 - y.2) =O[𝓟 (EMetric.ball (x, x) r')]
+/-- Taylor formula for an analytic function, `IsBigO` version. -/
+theorem HasFPowerSeriesAt.isBigO_sub_partialSum_pow
+ (hf : HasFPowerSeriesAt f p x) (n : ℕ) :
+ (fun y : E => f (x + y) - p.partialSum n y) =O[𝓝 0] fun y => ‖y‖ ^ n := by
+ rw [← hasFPowerSeriesWithinAt_univ] at hf
+ simpa using hf.isBigO_sub_partialSum_pow n
+
+/-- If `f` has formal power series `∑ n, pₙ` in a set, within a ball of radius `r`, then
+for `y, z` in any smaller ball, the norm of the difference `f y - f z - p 1 (fun _ ↦ y - z)` is
+bounded above by `C * (max ‖y - x‖ ‖z - x‖) * ‖y - z‖`. This lemma formulates this property
+using `IsBigO` and `Filter.principal` on `E × E`. -/
+theorem HasFPowerSeriesWithinOnBall.isBigO_image_sub_image_sub_deriv_principal
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) (hr : r' < r) :
+ (fun y : E × E => f y.1 - f y.2 - p 1 fun _ => y.1 - y.2)
+ =O[𝓟 (EMetric.ball (x, x) r' ∩ ((insert x s) ×ˢ (insert x s)))]
fun y => ‖y - (x, x)‖ * ‖y.1 - y.2‖ := by
lift r' to ℝ≥0 using ne_top_of_lt hr
rcases (zero_le r').eq_or_lt with (rfl | hr'0)
- · simp only [isBigO_bot, EMetric.ball_zero, principal_empty, ENNReal.coe_zero]
+ · simp only [ENNReal.coe_zero, EMetric.ball_zero, empty_inter, principal_empty, isBigO_bot]
obtain ⟨a, ha, C, hC : 0 < C, hp⟩ :
∃ a ∈ Ioo (0 : ℝ) 1, ∃ C > 0, ∀ n : ℕ, ‖p n‖ * (r' : ℝ) ^ n ≤ C * a ^ n :=
p.norm_mul_pow_le_mul_pow_of_lt_radius (hr.trans_le hf.r_le)
simp only [← le_div_iff₀ (pow_pos (NNReal.coe_pos.2 hr'0) _)] at hp
set L : E × E → ℝ := fun y =>
C * (a / r') ^ 2 * (‖y - (x, x)‖ * ‖y.1 - y.2‖) * (a / (1 - a) ^ 2 + 2 / (1 - a))
- have hL : ∀ y ∈ EMetric.ball (x, x) r', ‖f y.1 - f y.2 - p 1 fun _ => y.1 - y.2‖ ≤ L y := by
- intro y hy'
+ have hL : ∀ y ∈ EMetric.ball (x, x) r' ∩ ((insert x s) ×ˢ (insert x s)),
+ ‖f y.1 - f y.2 - p 1 fun _ => y.1 - y.2‖ ≤ L y := by
+ intro y ⟨hy', ys⟩
have hy : y ∈ EMetric.ball x r ×ˢ EMetric.ball x r := by
rw [EMetric.ball_prod_same]
exact EMetric.ball_subset_ball hr.le hy'
set A : ℕ → F := fun n => (p n fun _ => y.1 - x) - p n fun _ => y.2 - x
have hA : HasSum (fun n => A (n + 2)) (f y.1 - f y.2 - p 1 fun _ => y.1 - y.2) := by
- convert (hasSum_nat_add_iff' 2).2 ((hf.hasSum_sub hy.1).sub (hf.hasSum_sub hy.2)) using 1
+ convert (hasSum_nat_add_iff' 2).2
+ ((hf.hasSum_sub ⟨ys.1, hy.1⟩).sub (hf.hasSum_sub ⟨ys.2, hy.2⟩)) using 1
rw [Finset.sum_range_succ, Finset.sum_range_one, hf.coeff_zero, hf.coeff_zero, sub_self,
zero_add, ← Subsingleton.pi_single_eq (0 : Fin 1) (y.1 - x), Pi.single,
← Subsingleton.pi_single_eq (0 : Fin 1) (y.2 - x), Pi.single, ← (p 1).map_sub, ← Pi.single,
@@ -742,23 +1064,60 @@ theorem HasFPowerSeriesOnBall.isBigO_image_sub_image_sub_deriv_principal
exact (hasSum_coe_mul_geometric_of_norm_lt_one this).add -- Porting note: was `convert`!
((hasSum_geometric_of_norm_lt_one this).mul_left 2)
exact hA.norm_le_of_bounded hBL hAB
- suffices L =O[𝓟 (EMetric.ball (x, x) r')] fun y => ‖y - (x, x)‖ * ‖y.1 - y.2‖ by
+ suffices L =O[𝓟 (EMetric.ball (x, x) r' ∩ ((insert x s) ×ˢ (insert x s)))]
+ fun y => ‖y - (x, x)‖ * ‖y.1 - y.2‖ by
refine (IsBigO.of_bound 1 (eventually_principal.2 fun y hy => ?_)).trans this
rw [one_mul]
exact (hL y hy).trans (le_abs_self _)
simp_rw [L, mul_right_comm _ (_ * _)]
exact (isBigO_refl _ _).const_mul_left _
+/-- If `f` has formal power series `∑ n, pₙ` on a ball of radius `r`, then for `y, z` in any smaller
+ball, the norm of the difference `f y - f z - p 1 (fun _ ↦ y - z)` is bounded above by
+`C * (max ‖y - x‖ ‖z - x‖) * ‖y - z‖`. This lemma formulates this property using `IsBigO` and
+`Filter.principal` on `E × E`. -/
+theorem HasFPowerSeriesOnBall.isBigO_image_sub_image_sub_deriv_principal
+ (hf : HasFPowerSeriesOnBall f p x r) (hr : r' < r) :
+ (fun y : E × E => f y.1 - f y.2 - p 1 fun _ => y.1 - y.2)
+ =O[𝓟 (EMetric.ball (x, x) r')] fun y => ‖y - (x, x)‖ * ‖y.1 - y.2‖ := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ simpa using hf.isBigO_image_sub_image_sub_deriv_principal hr
+
+/-- If `f` has formal power series `∑ n, pₙ` within a set, on a ball of radius `r`, then for `y, z`
+in any smaller ball, the norm of the difference `f y - f z - p 1 (fun _ ↦ y - z)` is bounded above
+by `C * (max ‖y - x‖ ‖z - x‖) * ‖y - z‖`. -/
+theorem HasFPowerSeriesWithinOnBall.image_sub_sub_deriv_le
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) (hr : r' < r) :
+ ∃ C, ∀ᵉ (y ∈ insert x s ∩ EMetric.ball x r') (z ∈ insert x s ∩ EMetric.ball x r'),
+ ‖f y - f z - p 1 fun _ => y - z‖ ≤ C * max ‖y - x‖ ‖z - x‖ * ‖y - z‖ := by
+ have := hf.isBigO_image_sub_image_sub_deriv_principal hr
+ simp only [isBigO_principal, mem_inter_iff, EMetric.mem_ball, Prod.edist_eq, max_lt_iff, mem_prod,
+ norm_mul, Real.norm_eq_abs, abs_norm, and_imp, Prod.forall, mul_assoc] at this ⊢
+ rcases this with ⟨C, hC⟩
+ exact ⟨C, fun y ys hy z zs hz ↦ hC y z hy hz ys zs⟩
+
/-- If `f` has formal power series `∑ n, pₙ` on a ball of radius `r`, then for `y, z` in any smaller
ball, the norm of the difference `f y - f z - p 1 (fun _ ↦ y - z)` is bounded above by
`C * (max ‖y - x‖ ‖z - x‖) * ‖y - z‖`. -/
-theorem HasFPowerSeriesOnBall.image_sub_sub_deriv_le (hf : HasFPowerSeriesOnBall f p x r)
- (hr : r' < r) :
+theorem HasFPowerSeriesOnBall.image_sub_sub_deriv_le
+ (hf : HasFPowerSeriesOnBall f p x r) (hr : r' < r) :
∃ C, ∀ᵉ (y ∈ EMetric.ball x r') (z ∈ EMetric.ball x r'),
‖f y - f z - p 1 fun _ => y - z‖ ≤ C * max ‖y - x‖ ‖z - x‖ * ‖y - z‖ := by
- simpa only [isBigO_principal, mul_assoc, norm_mul, norm_norm, Prod.forall, EMetric.mem_ball,
- Prod.edist_eq, max_lt_iff, and_imp, @forall_swap (_ < _) E] using
- hf.isBigO_image_sub_image_sub_deriv_principal hr
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ simpa only [mem_univ, insert_eq_of_mem, univ_inter] using hf.image_sub_sub_deriv_le hr
+
+/-- If `f` has formal power series `∑ n, pₙ` at `x` within a set `s`, then
+`f y - f z - p 1 (fun _ ↦ y - z) = O(‖(y, z) - (x, x)‖ * ‖y - z‖)` as `(y, z) → (x, x)`
+within `s × s`. -/
+theorem HasFPowerSeriesWithinAt.isBigO_image_sub_norm_mul_norm_sub
+ (hf : HasFPowerSeriesWithinAt f p s x) :
+ (fun y : E × E => f y.1 - f y.2 - p 1 fun _ => y.1 - y.2)
+ =O[𝓝[(insert x s) ×ˢ (insert x s)] (x, x)] fun y => ‖y - (x, x)‖ * ‖y.1 - y.2‖ := by
+ rcases hf with ⟨r, hf⟩
+ rcases ENNReal.lt_iff_exists_nnreal_btwn.1 hf.r_pos with ⟨r', r'0, h⟩
+ refine (hf.isBigO_image_sub_image_sub_deriv_principal h).mono ?_
+ rw [inter_comm]
+ exact le_principal_iff.2 (inter_mem_nhdsWithin _ (EMetric.ball_mem_nhds _ r'0))
/-- If `f` has formal power series `∑ n, pₙ` at `x`, then
`f y - f z - p 1 (fun _ ↦ y - z) = O(‖(y, z) - (x, x)‖ * ‖y - z‖)` as `(y, z) → (x, x)`.
@@ -766,27 +1125,52 @@ In particular, `f` is strictly differentiable at `x`. -/
theorem HasFPowerSeriesAt.isBigO_image_sub_norm_mul_norm_sub (hf : HasFPowerSeriesAt f p x) :
(fun y : E × E => f y.1 - f y.2 - p 1 fun _ => y.1 - y.2) =O[𝓝 (x, x)] fun y =>
‖y - (x, x)‖ * ‖y.1 - y.2‖ := by
- rcases hf with ⟨r, hf⟩
- rcases ENNReal.lt_iff_exists_nnreal_btwn.1 hf.r_pos with ⟨r', r'0, h⟩
- refine (hf.isBigO_image_sub_image_sub_deriv_principal h).mono ?_
- exact le_principal_iff.2 (EMetric.ball_mem_nhds _ r'0)
-
-/-- If a function admits a power series expansion at `x`, then it is the uniform limit of the
-partial sums of this power series on strict subdisks of the disk of convergence, i.e., `f (x + y)`
-is the uniform limit of `p.partialSum n y` there. -/
-theorem HasFPowerSeriesOnBall.tendstoUniformlyOn {r' : ℝ≥0} (hf : HasFPowerSeriesOnBall f p x r)
- (h : (r' : ℝ≥0∞) < r) :
+ rw [← hasFPowerSeriesWithinAt_univ] at hf
+ simpa using hf.isBigO_image_sub_norm_mul_norm_sub
+
+/-- If a function admits a power series expansion within a set at `x`, then it is the uniform limit
+of the partial sums of this power series on strict subdisks of the disk of convergence, i.e.,
+`f (x + y)` is the uniform limit of `p.partialSum n y` there. -/
+theorem HasFPowerSeriesWithinOnBall.tendstoUniformlyOn {r' : ℝ≥0}
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) (h : (r' : ℝ≥0∞) < r) :
TendstoUniformlyOn (fun n y => p.partialSum n y) (fun y => f (x + y)) atTop
- (Metric.ball (0 : E) r') := by
+ ((x + ·)⁻¹' (insert x s) ∩ Metric.ball (0 : E) r') := by
obtain ⟨a, ha, C, -, hp⟩ : ∃ a ∈ Ioo (0 : ℝ) 1, ∃ C > 0, ∀ y ∈ Metric.ball (0 : E) r', ∀ n,
- ‖f (x + y) - p.partialSum n y‖ ≤ C * a ^ n := hf.uniform_geometric_approx h
+ x + y ∈ insert x s → ‖f (x + y) - p.partialSum n y‖ ≤ C * a ^ n := hf.uniform_geometric_approx h
refine Metric.tendstoUniformlyOn_iff.2 fun ε εpos => ?_
have L : Tendsto (fun n => (C : ℝ) * a ^ n) atTop (𝓝 ((C : ℝ) * 0)) :=
tendsto_const_nhds.mul (tendsto_pow_atTop_nhds_zero_of_lt_one ha.1.le ha.2)
rw [mul_zero] at L
refine (L.eventually (gt_mem_nhds εpos)).mono fun n hn y hy => ?_
rw [dist_eq_norm]
- exact (hp y hy n).trans_lt hn
+ exact (hp y hy.2 n hy.1).trans_lt hn
+
+/-- If a function admits a power series expansion at `x`, then it is the uniform limit of the
+partial sums of this power series on strict subdisks of the disk of convergence, i.e., `f (x + y)`
+is the uniform limit of `p.partialSum n y` there. -/
+theorem HasFPowerSeriesOnBall.tendstoUniformlyOn {r' : ℝ≥0} (hf : HasFPowerSeriesOnBall f p x r)
+ (h : (r' : ℝ≥0∞) < r) :
+ TendstoUniformlyOn (fun n y => p.partialSum n y) (fun y => f (x + y)) atTop
+ (Metric.ball (0 : E) r') := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ simpa using hf.tendstoUniformlyOn h
+
+/-- If a function admits a power series expansion within a set at `x`, then it is the locally
+uniform limit of the partial sums of this power series on the disk of convergence, i.e., `f (x + y)`
+is the locally uniform limit of `p.partialSum n y` there. -/
+theorem HasFPowerSeriesWithinOnBall.tendstoLocallyUniformlyOn
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) :
+ TendstoLocallyUniformlyOn (fun n y => p.partialSum n y) (fun y => f (x + y)) atTop
+ ((x + ·)⁻¹' (insert x s) ∩ EMetric.ball (0 : E) r) := by
+ intro u hu y hy
+ rcases ENNReal.lt_iff_exists_nnreal_btwn.1 hy.2 with ⟨r', yr', hr'⟩
+ have : EMetric.ball (0 : E) r' ∈ 𝓝 y := IsOpen.mem_nhds EMetric.isOpen_ball yr'
+ refine ⟨(x + ·)⁻¹' (insert x s) ∩ EMetric.ball (0 : E) r', ?_, ?_⟩
+ · rw [nhdsWithin_inter_of_mem']
+ · exact inter_mem_nhdsWithin _ this
+ · apply mem_nhdsWithin_of_mem_nhds
+ apply Filter.mem_of_superset this (EMetric.ball_subset_ball hr'.le)
+ · simpa [Metric.emetric_ball_nnreal] using hf.tendstoUniformlyOn hr' u hu
/-- If a function admits a power series expansion at `x`, then it is the locally uniform limit of
the partial sums of this power series on the disk of convergence, i.e., `f (x + y)`
@@ -794,11 +1178,20 @@ is the locally uniform limit of `p.partialSum n y` there. -/
theorem HasFPowerSeriesOnBall.tendstoLocallyUniformlyOn (hf : HasFPowerSeriesOnBall f p x r) :
TendstoLocallyUniformlyOn (fun n y => p.partialSum n y) (fun y => f (x + y)) atTop
(EMetric.ball (0 : E) r) := by
- intro u hu x hx
- rcases ENNReal.lt_iff_exists_nnreal_btwn.1 hx with ⟨r', xr', hr'⟩
- have : EMetric.ball (0 : E) r' ∈ 𝓝 x := IsOpen.mem_nhds EMetric.isOpen_ball xr'
- refine ⟨EMetric.ball (0 : E) r', mem_nhdsWithin_of_mem_nhds this, ?_⟩
- simpa [Metric.emetric_ball_nnreal] using hf.tendstoUniformlyOn hr' u hu
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ simpa using hf.tendstoLocallyUniformlyOn
+
+/-- If a function admits a power series expansion within a set at `x`, then it is the uniform limit
+of the partial sums of this power series on strict subdisks of the disk of convergence, i.e., `f y`
+is the uniform limit of `p.partialSum n (y - x)` there. -/
+theorem HasFPowerSeriesWithinOnBall.tendstoUniformlyOn' {r' : ℝ≥0}
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) (h : (r' : ℝ≥0∞) < r) :
+ TendstoUniformlyOn (fun n y => p.partialSum n (y - x)) f atTop
+ (insert x s ∩ Metric.ball (x : E) r') := by
+ convert (hf.tendstoUniformlyOn h).comp fun y => y - x using 1
+ · simp [Function.comp_def]
+ · ext z
+ simp [dist_eq_norm]
/-- If a function admits a power series expansion at `x`, then it is the uniform limit of the
partial sums of this power series on strict subdisks of the disk of convergence, i.e., `f y`
@@ -806,18 +1199,17 @@ is the uniform limit of `p.partialSum n (y - x)` there. -/
theorem HasFPowerSeriesOnBall.tendstoUniformlyOn' {r' : ℝ≥0} (hf : HasFPowerSeriesOnBall f p x r)
(h : (r' : ℝ≥0∞) < r) :
TendstoUniformlyOn (fun n y => p.partialSum n (y - x)) f atTop (Metric.ball (x : E) r') := by
- convert (hf.tendstoUniformlyOn h).comp fun y => y - x using 1
- · simp [Function.comp_def]
- · ext z
- simp [dist_eq_norm]
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ simpa using hf.tendstoUniformlyOn' h
-/-- If a function admits a power series expansion at `x`, then it is the locally uniform limit of
-the partial sums of this power series on the disk of convergence, i.e., `f y`
+/-- If a function admits a power series expansion within a set at `x`, then it is the locally
+uniform limit of the partial sums of this power series on the disk of convergence, i.e., `f y`
is the locally uniform limit of `p.partialSum n (y - x)` there. -/
-theorem HasFPowerSeriesOnBall.tendstoLocallyUniformlyOn' (hf : HasFPowerSeriesOnBall f p x r) :
+theorem HasFPowerSeriesWithinOnBall.tendstoLocallyUniformlyOn'
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) :
TendstoLocallyUniformlyOn (fun n y => p.partialSum n (y - x)) f atTop
- (EMetric.ball (x : E) r) := by
- have A : ContinuousOn (fun y : E => y - x) (EMetric.ball (x : E) r) :=
+ (insert x s ∩ EMetric.ball (x : E) r) := by
+ have A : ContinuousOn (fun y : E => y - x) (insert x s ∩ EMetric.ball (x : E) r) :=
(continuous_id.sub continuous_const).continuousOn
convert hf.tendstoLocallyUniformlyOn.comp (fun y : E => y - x) _ A using 1
· ext z
@@ -825,29 +1217,88 @@ theorem HasFPowerSeriesOnBall.tendstoLocallyUniformlyOn' (hf : HasFPowerSeriesOn
· intro z
simp [edist_eq_coe_nnnorm, edist_eq_coe_nnnorm_sub]
-/-- If a function admits a power series expansion on a disk, then it is continuous there. -/
-protected theorem HasFPowerSeriesOnBall.continuousOn (hf : HasFPowerSeriesOnBall f p x r) :
- ContinuousOn f (EMetric.ball x r) :=
+/-- If a function admits a power series expansion at `x`, then it is the locally uniform limit of
+the partial sums of this power series on the disk of convergence, i.e., `f y`
+is the locally uniform limit of `p.partialSum n (y - x)` there. -/
+theorem HasFPowerSeriesOnBall.tendstoLocallyUniformlyOn' (hf : HasFPowerSeriesOnBall f p x r) :
+ TendstoLocallyUniformlyOn (fun n y => p.partialSum n (y - x)) f atTop
+ (EMetric.ball (x : E) r) := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ simpa using hf.tendstoLocallyUniformlyOn'
+
+/-- If a function admits a power series expansion within a set on a ball, then it is
+continuous there. -/
+protected theorem HasFPowerSeriesWithinOnBall.continuousOn
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) :
+ ContinuousOn f (insert x s ∩ EMetric.ball x r) :=
hf.tendstoLocallyUniformlyOn'.continuousOn <|
Eventually.of_forall fun n =>
((p.partialSum_continuous n).comp (continuous_id.sub continuous_const)).continuousOn
+/-- If a function admits a power series expansion on a ball, then it is continuous there. -/
+protected theorem HasFPowerSeriesOnBall.continuousOn (hf : HasFPowerSeriesOnBall f p x r) :
+ ContinuousOn f (EMetric.ball x r) := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ simpa using hf.continuousOn
+
+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_nhdsWithin
+ exact inter_mem_nhdsWithin _ (EMetric.ball_mem_nhds x hf.r_pos)
+
+protected theorem HasFPowerSeriesWithinOnBall.continuousWithinAt
+ (hf : HasFPowerSeriesWithinOnBall f p s x r) :
+ ContinuousWithinAt f s x :=
+ hf.continuousWithinAt_insert.mono (subset_insert x s)
+
+protected theorem HasFPowerSeriesWithinAt.continuousWithinAt_insert
+ (hf : HasFPowerSeriesWithinAt f p s x) :
+ ContinuousWithinAt f (insert x s) x := by
+ rcases hf with ⟨r, hr⟩
+ apply hr.continuousWithinAt_insert
+
+protected theorem HasFPowerSeriesWithinAt.continuousWithinAt
+ (hf : HasFPowerSeriesWithinAt f p s x) :
+ ContinuousWithinAt f s x :=
+ hf.continuousWithinAt_insert.mono (subset_insert x s)
+
protected theorem HasFPowerSeriesAt.continuousAt (hf : HasFPowerSeriesAt f p x) :
ContinuousAt f x :=
let ⟨_, hr⟩ := hf
hr.continuousOn.continuousAt (EMetric.ball_mem_nhds x hr.r_pos)
+protected theorem AnalyticWithinAt.continuousWithinAt_insert (hf : AnalyticWithinAt 𝕜 f s x) :
+ ContinuousWithinAt f (insert x s) x :=
+ let ⟨_, hp⟩ := hf
+ hp.continuousWithinAt_insert
+
+protected theorem AnalyticWithinAt.continuousWithinAt (hf : AnalyticWithinAt 𝕜 f s x) :
+ ContinuousWithinAt f s x :=
+ hf.continuousWithinAt_insert.mono (subset_insert x s)
+
protected theorem AnalyticAt.continuousAt (hf : AnalyticAt 𝕜 f x) : ContinuousAt f x :=
let ⟨_, hp⟩ := hf
hp.continuousAt
-protected theorem AnalyticOn.continuousOn {s : Set E} (hf : AnalyticOn 𝕜 f s) : ContinuousOn f s :=
+protected theorem AnalyticOnNhd.continuousOn {s : Set E} (hf : AnalyticOnNhd 𝕜 f s) :
+ ContinuousOn f s :=
fun x hx => (hf x hx).continuousAt.continuousWithinAt
+protected lemma AnalyticOn.continuousOn {f : E → F} {s : Set E} (h : AnalyticOn 𝕜 f s) :
+ ContinuousOn f s :=
+ fun x m ↦ (h x m).continuousWithinAt
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.continuousOn := AnalyticOn.continuousOn
+
/-- Analytic everywhere implies continuous -/
-theorem AnalyticOn.continuous {f : E → F} (fa : AnalyticOn 𝕜 f univ) : Continuous f := by
+theorem AnalyticOnNhd.continuous {f : E → F} (fa : AnalyticOnNhd 𝕜 f univ) : Continuous f := by
rw [continuous_iff_continuousOn_univ]; exact fa.continuousOn
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.continuous := AnalyticOnNhd.continuous
+
/-- In a complete space, the sum of a converging power series `p` admits `p` as a power series.
This is not totally obvious as we need to check the convergence of the series. -/
protected theorem FormalMultilinearSeries.hasFPowerSeriesOnBall [CompleteSpace F]
@@ -859,6 +1310,10 @@ protected theorem FormalMultilinearSeries.hasFPowerSeriesOnBall [CompleteSpace F
rw [zero_add]
exact p.hasSum hy }
+theorem HasFPowerSeriesWithinOnBall.sum (h : HasFPowerSeriesWithinOnBall f p s x r) {y : E}
+ (h'y : x + y ∈ insert x s) (hy : y ∈ EMetric.ball (0 : E) r) : f (x + y) = p.sum y :=
+ (h.hasSum h'y hy).tsum_eq.symm
+
theorem HasFPowerSeriesOnBall.sum (h : HasFPowerSeriesOnBall f p x r) {y : E}
(hy : y ∈ EMetric.ball (0 : E) r) : f (x + y) = p.sum y :=
(h.hasSum hy).tsum_eq.symm
@@ -872,465 +1327,6 @@ protected theorem FormalMultilinearSeries.continuousOn [CompleteSpace F] :
end
-/-!
-### Uniqueness of power series
-If a function `f : E → F` has two representations as power series at a point `x : E`, corresponding
-to formal multilinear series `p₁` and `p₂`, then these representations agree term-by-term. That is,
-for any `n : ℕ` and `y : E`, `p₁ n (fun i ↦ y) = p₂ n (fun i ↦ y)`. In the one-dimensional case,
-when `f : 𝕜 → E`, the continuous multilinear maps `p₁ n` and `p₂ n` are given by
-`ContinuousMultilinearMap.mkPiRing`, and hence are determined completely by the value of
-`p₁ n (fun i ↦ 1)`, so `p₁ = p₂`. Consequently, the radius of convergence for one series can be
-transferred to the other.
--/
-
-
-section Uniqueness
-
-open ContinuousMultilinearMap
-
-theorem Asymptotics.IsBigO.continuousMultilinearMap_apply_eq_zero {n : ℕ} {p : E[×n]→L[𝕜] F}
- (h : (fun y => p fun _ => y) =O[𝓝 0] fun y => ‖y‖ ^ (n + 1)) (y : E) : (p fun _ => y) = 0 := by
- obtain ⟨c, c_pos, hc⟩ := h.exists_pos
- obtain ⟨t, ht, t_open, z_mem⟩ := eventually_nhds_iff.mp (isBigOWith_iff.mp hc)
- obtain ⟨δ, δ_pos, δε⟩ := (Metric.isOpen_iff.mp t_open) 0 z_mem
- clear h hc z_mem
- cases' n with n
- · exact norm_eq_zero.mp (by
- -- Porting note: the symmetric difference of the `simpa only` sets:
- -- added `zero_add, pow_one`
- -- removed `zero_pow, Ne.def, Nat.one_ne_zero, not_false_iff`
- simpa only [fin0_apply_norm, norm_eq_zero, norm_zero, zero_add, pow_one,
- mul_zero, norm_le_zero_iff] using ht 0 (δε (Metric.mem_ball_self δ_pos)))
- · refine Or.elim (Classical.em (y = 0))
- (fun hy => by simpa only [hy] using p.map_zero) fun hy => ?_
- replace hy := norm_pos_iff.mpr hy
- refine norm_eq_zero.mp (le_antisymm (le_of_forall_pos_le_add fun ε ε_pos => ?_) (norm_nonneg _))
- have h₀ := _root_.mul_pos c_pos (pow_pos hy (n.succ + 1))
- obtain ⟨k, k_pos, k_norm⟩ := NormedField.exists_norm_lt 𝕜
- (lt_min (mul_pos δ_pos (inv_pos.mpr hy)) (mul_pos ε_pos (inv_pos.mpr h₀)))
- have h₁ : ‖k • y‖ < δ := by
- rw [norm_smul]
- exact inv_mul_cancel_right₀ hy.ne.symm δ ▸
- mul_lt_mul_of_pos_right (lt_of_lt_of_le k_norm (min_le_left _ _)) hy
- have h₂ :=
- calc
- ‖p fun _ => k • y‖ ≤ c * ‖k • y‖ ^ (n.succ + 1) := by
- -- Porting note: now Lean wants `_root_.`
- simpa only [norm_pow, _root_.norm_norm] using ht (k • y) (δε (mem_ball_zero_iff.mpr h₁))
- --simpa only [norm_pow, norm_norm] using ht (k • y) (δε (mem_ball_zero_iff.mpr h₁))
- _ = ‖k‖ ^ n.succ * (‖k‖ * (c * ‖y‖ ^ (n.succ + 1))) := by
- -- Porting note: added `Nat.succ_eq_add_one` since otherwise `ring` does not conclude.
- simp only [norm_smul, mul_pow, Nat.succ_eq_add_one]
- -- Porting note: removed `rw [pow_succ]`, since it now becomes superfluous.
- ring
- have h₃ : ‖k‖ * (c * ‖y‖ ^ (n.succ + 1)) < ε :=
- inv_mul_cancel_right₀ h₀.ne.symm ε ▸
- mul_lt_mul_of_pos_right (lt_of_lt_of_le k_norm (min_le_right _ _)) h₀
- calc
- ‖p fun _ => y‖ = ‖k⁻¹ ^ n.succ‖ * ‖p fun _ => k • y‖ := by
- simpa only [inv_smul_smul₀ (norm_pos_iff.mp k_pos), norm_smul, Finset.prod_const,
- Finset.card_fin] using
- congr_arg norm (p.map_smul_univ (fun _ : Fin n.succ => k⁻¹) fun _ : Fin n.succ => k • y)
- _ ≤ ‖k⁻¹ ^ n.succ‖ * (‖k‖ ^ n.succ * (‖k‖ * (c * ‖y‖ ^ (n.succ + 1)))) := by gcongr
- _ = ‖(k⁻¹ * k) ^ n.succ‖ * (‖k‖ * (c * ‖y‖ ^ (n.succ + 1))) := by
- rw [← mul_assoc]
- simp [norm_mul, mul_pow]
- _ ≤ 0 + ε := by
- rw [inv_mul_cancel₀ (norm_pos_iff.mp k_pos)]
- simpa using h₃.le
-
-/-- If a formal multilinear series `p` represents the zero function at `x : E`, then the
-terms `p n (fun i ↦ y)` appearing in the sum are zero for any `n : ℕ`, `y : E`. -/
-theorem HasFPowerSeriesAt.apply_eq_zero {p : FormalMultilinearSeries 𝕜 E F} {x : E}
- (h : HasFPowerSeriesAt 0 p x) (n : ℕ) : ∀ y : E, (p n fun _ => y) = 0 := by
- refine Nat.strong_induction_on n fun k hk => ?_
- have psum_eq : p.partialSum (k + 1) = fun y => p k fun _ => y := by
- funext z
- refine Finset.sum_eq_single _ (fun b hb hnb => ?_) fun hn => ?_
- · have := Finset.mem_range_succ_iff.mp hb
- simp only [hk b (this.lt_of_ne hnb), Pi.zero_apply]
- · exact False.elim (hn (Finset.mem_range.mpr (lt_add_one k)))
- replace h := h.isBigO_sub_partialSum_pow k.succ
- simp only [psum_eq, zero_sub, Pi.zero_apply, Asymptotics.isBigO_neg_left] at h
- exact h.continuousMultilinearMap_apply_eq_zero
-
-/-- A one-dimensional formal multilinear series representing the zero function is zero. -/
-theorem HasFPowerSeriesAt.eq_zero {p : FormalMultilinearSeries 𝕜 𝕜 E} {x : 𝕜}
- (h : HasFPowerSeriesAt 0 p x) : p = 0 := by
- ext n x
- rw [← mkPiRing_apply_one_eq_self (p n)]
- simp [h.apply_eq_zero n 1]
-
-/-- One-dimensional formal multilinear series representing the same function are equal. -/
-theorem HasFPowerSeriesAt.eq_formalMultilinearSeries {p₁ p₂ : FormalMultilinearSeries 𝕜 𝕜 E}
- {f : 𝕜 → E} {x : 𝕜} (h₁ : HasFPowerSeriesAt f p₁ x) (h₂ : HasFPowerSeriesAt f p₂ x) : p₁ = p₂ :=
- sub_eq_zero.mp (HasFPowerSeriesAt.eq_zero (x := x) (by simpa only [sub_self] using h₁.sub h₂))
-
-theorem HasFPowerSeriesAt.eq_formalMultilinearSeries_of_eventually
- {p q : FormalMultilinearSeries 𝕜 𝕜 E} {f g : 𝕜 → E} {x : 𝕜} (hp : HasFPowerSeriesAt f p x)
- (hq : HasFPowerSeriesAt g q x) (heq : ∀ᶠ z in 𝓝 x, f z = g z) : p = q :=
- (hp.congr heq).eq_formalMultilinearSeries hq
-
-/-- A one-dimensional formal multilinear series representing a locally zero function is zero. -/
-theorem HasFPowerSeriesAt.eq_zero_of_eventually {p : FormalMultilinearSeries 𝕜 𝕜 E} {f : 𝕜 → E}
- {x : 𝕜} (hp : HasFPowerSeriesAt f p x) (hf : f =ᶠ[𝓝 x] 0) : p = 0 :=
- (hp.congr hf).eq_zero
-
-/-- If a function `f : 𝕜 → E` has two power series representations at `x`, then the given radii in
-which convergence is guaranteed may be interchanged. This can be useful when the formal multilinear
-series in one representation has a particularly nice form, but the other has a larger radius. -/
-theorem HasFPowerSeriesOnBall.exchange_radius {p₁ p₂ : FormalMultilinearSeries 𝕜 𝕜 E} {f : 𝕜 → E}
- {r₁ r₂ : ℝ≥0∞} {x : 𝕜} (h₁ : HasFPowerSeriesOnBall f p₁ x r₁)
- (h₂ : HasFPowerSeriesOnBall f p₂ x r₂) : HasFPowerSeriesOnBall f p₁ x r₂ :=
- h₂.hasFPowerSeriesAt.eq_formalMultilinearSeries h₁.hasFPowerSeriesAt ▸ h₂
-
-/-- If a function `f : 𝕜 → E` has power series representation `p` on a ball of some radius and for
-each positive radius it has some power series representation, then `p` converges to `f` on the whole
-`𝕜`. -/
-theorem HasFPowerSeriesOnBall.r_eq_top_of_exists {f : 𝕜 → E} {r : ℝ≥0∞} {x : 𝕜}
- {p : FormalMultilinearSeries 𝕜 𝕜 E} (h : HasFPowerSeriesOnBall f p x r)
- (h' : ∀ (r' : ℝ≥0) (_ : 0 < r'), ∃ p' : FormalMultilinearSeries 𝕜 𝕜 E,
- HasFPowerSeriesOnBall f p' x r') :
- HasFPowerSeriesOnBall f p x ∞ :=
- { r_le := ENNReal.le_of_forall_pos_nnreal_lt fun r hr _ =>
- let ⟨_, hp'⟩ := h' r hr
- (h.exchange_radius hp').r_le
- r_pos := ENNReal.coe_lt_top
- hasSum := fun {y} _ =>
- let ⟨r', hr'⟩ := exists_gt ‖y‖₊
- let ⟨_, hp'⟩ := h' r' hr'.ne_bot.bot_lt
- (h.exchange_radius hp').hasSum <| mem_emetric_ball_zero_iff.mpr (ENNReal.coe_lt_coe.2 hr') }
-
-end Uniqueness
-
-/-!
-### Changing origin in a power series
-
-If a function is analytic in a disk `D(x, R)`, then it is analytic in any disk contained in that
-one. Indeed, one can write
-$$
-f (x + y + z) = \sum_{n} p_n (y + z)^n = \sum_{n, k} \binom{n}{k} p_n y^{n-k} z^k
-= \sum_{k} \Bigl(\sum_{n} \binom{n}{k} p_n y^{n-k}\Bigr) z^k.
-$$
-The corresponding power series has thus a `k`-th coefficient equal to
-$\sum_{n} \binom{n}{k} p_n y^{n-k}$. In the general case where `pₙ` is a multilinear map, this has
-to be interpreted suitably: instead of having a binomial coefficient, one should sum over all
-possible subsets `s` of `Fin n` of cardinality `k`, and attribute `z` to the indices in `s` and
-`y` to the indices outside of `s`.
-
-In this paragraph, we implement this. The new power series is called `p.changeOrigin y`. Then, we
-check its convergence and the fact that its sum coincides with the original sum. The outcome of this
-discussion is that the set of points where a function is analytic is open.
--/
-
-
-namespace FormalMultilinearSeries
-
-section
-
-variable (p : FormalMultilinearSeries 𝕜 E F) {x y : E} {r R : ℝ≥0}
-
-/-- A term of `FormalMultilinearSeries.changeOriginSeries`.
-
-Given a formal multilinear series `p` and a point `x` in its ball of convergence,
-`p.changeOrigin x` is a formal multilinear series such that
-`p.sum (x+y) = (p.changeOrigin x).sum y` when this makes sense. Each term of `p.changeOrigin x`
-is itself an analytic function of `x` given by the series `p.changeOriginSeries`. Each term in
-`changeOriginSeries` is the sum of `changeOriginSeriesTerm`'s over all `s` of cardinality `l`.
-The definition is such that `p.changeOriginSeriesTerm k l s hs (fun _ ↦ x) (fun _ ↦ y) =
-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])
- a (p (k + l))
-
-theorem changeOriginSeriesTerm_apply (k l : ℕ) (s : Finset (Fin (k + l))) (hs : s.card = l)
- (x y : E) :
- (p.changeOriginSeriesTerm k l s hs (fun _ => x) fun _ => y) =
- p (k + l) (s.piecewise (fun _ => x) fun _ => y) :=
- ContinuousMultilinearMap.curryFinFinset_apply_const _ _ _ _ _
-
-@[simp]
-theorem norm_changeOriginSeriesTerm (k l : ℕ) (s : Finset (Fin (k + l))) (hs : s.card = l) :
- ‖p.changeOriginSeriesTerm k l s hs‖ = ‖p (k + l)‖ := by
- simp only [changeOriginSeriesTerm, LinearIsometryEquiv.norm_map]
-
-@[simp]
-theorem nnnorm_changeOriginSeriesTerm (k l : ℕ) (s : Finset (Fin (k + l))) (hs : s.card = l) :
- ‖p.changeOriginSeriesTerm k l s hs‖₊ = ‖p (k + l)‖₊ := by
- simp only [changeOriginSeriesTerm, LinearIsometryEquiv.nnnorm_map]
-
-theorem nnnorm_changeOriginSeriesTerm_apply_le (k l : ℕ) (s : Finset (Fin (k + l)))
- (hs : s.card = l) (x y : E) :
- ‖p.changeOriginSeriesTerm k l s hs (fun _ => x) fun _ => y‖₊ ≤
- ‖p (k + l)‖₊ * ‖x‖₊ ^ l * ‖y‖₊ ^ k := by
- rw [← p.nnnorm_changeOriginSeriesTerm k l s hs, ← Fin.prod_const, ← Fin.prod_const]
- apply ContinuousMultilinearMap.le_of_opNNNorm_le
- apply ContinuousMultilinearMap.le_opNNNorm
-
-/-- The power series for `f.changeOrigin k`.
-
-Given a formal multilinear series `p` and a point `x` in its ball of convergence,
-`p.changeOrigin x` is a formal multilinear series such that
-`p.sum (x+y) = (p.changeOrigin x).sum y` when this makes sense. Its `k`-th term is the sum of
-the series `p.changeOriginSeries k`. -/
-def changeOriginSeries (k : ℕ) : FormalMultilinearSeries 𝕜 E (E[×k]→L[𝕜] F) := fun l =>
- ∑ s : { s : Finset (Fin (k + l)) // Finset.card s = l }, p.changeOriginSeriesTerm k l s s.2
-
-theorem nnnorm_changeOriginSeries_le_tsum (k l : ℕ) :
- ‖p.changeOriginSeries k l‖₊ ≤
- ∑' _ : { s : Finset (Fin (k + l)) // s.card = l }, ‖p (k + l)‖₊ :=
- (nnnorm_sum_le _ (fun t => changeOriginSeriesTerm p k l (Subtype.val t) t.prop)).trans_eq <| by
- simp_rw [tsum_fintype, nnnorm_changeOriginSeriesTerm (p := p) (k := k) (l := l)]
-
-theorem nnnorm_changeOriginSeries_apply_le_tsum (k l : ℕ) (x : E) :
- ‖p.changeOriginSeries k l fun _ => x‖₊ ≤
- ∑' _ : { s : Finset (Fin (k + l)) // s.card = l }, ‖p (k + l)‖₊ * ‖x‖₊ ^ l := by
- rw [NNReal.tsum_mul_right, ← Fin.prod_const]
- exact (p.changeOriginSeries k l).le_of_opNNNorm_le _ (p.nnnorm_changeOriginSeries_le_tsum _ _)
-
-/-- Changing the origin of a formal multilinear series `p`, so that
-`p.sum (x+y) = (p.changeOrigin x).sum y` when this makes sense.
--/
-def changeOrigin (x : E) : FormalMultilinearSeries 𝕜 E F :=
- fun k => (p.changeOriginSeries k).sum x
-
-/-- An auxiliary equivalence useful in the proofs about
-`FormalMultilinearSeries.changeOriginSeries`: the set of triples `(k, l, s)`, where `s` is a
-`Finset (Fin (k + l))` of cardinality `l` is equivalent to the set of pairs `(n, s)`, where `s` is a
-`Finset (Fin n)`.
-
-The forward map sends `(k, l, s)` to `(k + l, s)` and the inverse map sends `(n, s)` to
-`(n - Finset.card s, Finset.card s, s)`. The actual definition is less readable because of problems
-with non-definitional equalities. -/
-@[simps]
-def changeOriginIndexEquiv :
- (Σ k l : ℕ, { s : Finset (Fin (k + l)) // s.card = l }) ≃ Σ n : ℕ, Finset (Fin n) where
- toFun s := ⟨s.1 + s.2.1, s.2.2⟩
- invFun s :=
- ⟨s.1 - s.2.card, s.2.card,
- ⟨s.2.map
- (finCongr <| (tsub_add_cancel_of_le <| card_finset_fin_le s.2).symm).toEmbedding,
- Finset.card_map _⟩⟩
- left_inv := by
- rintro ⟨k, l, ⟨s : Finset (Fin <| k + l), hs : s.card = l⟩⟩
- dsimp only [Subtype.coe_mk]
- -- Lean can't automatically generalize `k' = k + l - s.card`, `l' = s.card`, so we explicitly
- -- formulate the generalized goal
- suffices ∀ k' l', k' = k → l' = l → ∀ (hkl : k + l = k' + l') (hs'),
- (⟨k', l', ⟨s.map (finCongr hkl).toEmbedding, hs'⟩⟩ :
- Σk l : ℕ, { s : Finset (Fin (k + l)) // s.card = l }) = ⟨k, l, ⟨s, hs⟩⟩ by
- apply this <;> simp only [hs, add_tsub_cancel_right]
- rintro _ _ rfl rfl hkl hs'
- simp only [Equiv.refl_toEmbedding, finCongr_refl, Finset.map_refl, eq_self_iff_true,
- OrderIso.refl_toEquiv, and_self_iff, heq_iff_eq]
- right_inv := by
- rintro ⟨n, s⟩
- simp [tsub_add_cancel_of_le (card_finset_fin_le s), finCongr_eq_equivCast]
-
-lemma changeOriginSeriesTerm_changeOriginIndexEquiv_symm (n t) :
- let s := changeOriginIndexEquiv.symm ⟨n, t⟩
- p.changeOriginSeriesTerm s.1 s.2.1 s.2.2 s.2.2.2 (fun _ ↦ x) (fun _ ↦ y) =
- p n (t.piecewise (fun _ ↦ x) fun _ ↦ y) := by
- have : ∀ (m) (hm : n = m), p n (t.piecewise (fun _ ↦ x) fun _ ↦ y) =
- p m ((t.map (finCongr hm).toEmbedding).piecewise (fun _ ↦ x) fun _ ↦ y) := by
- rintro m rfl
- simp (config := { unfoldPartialApp := true }) [Finset.piecewise]
- simp_rw [changeOriginSeriesTerm_apply, eq_comm]; apply this
-
-theorem changeOriginSeries_summable_aux₁ {r r' : ℝ≥0} (hr : (r + r' : ℝ≥0∞) < p.radius) :
- Summable fun s : Σk l : ℕ, { s : Finset (Fin (k + l)) // s.card = l } =>
- ‖p (s.1 + s.2.1)‖₊ * r ^ s.2.1 * r' ^ s.1 := by
- rw [← changeOriginIndexEquiv.symm.summable_iff]
- dsimp only [Function.comp_def, changeOriginIndexEquiv_symm_apply_fst,
- changeOriginIndexEquiv_symm_apply_snd_fst]
- have : ∀ n : ℕ,
- HasSum (fun s : Finset (Fin n) => ‖p (n - s.card + s.card)‖₊ * r ^ s.card * r' ^ (n - s.card))
- (‖p n‖₊ * (r + r') ^ n) := by
- intro n
- -- TODO: why `simp only [tsub_add_cancel_of_le (card_finset_fin_le _)]` fails?
- convert_to HasSum (fun s : Finset (Fin n) => ‖p n‖₊ * (r ^ s.card * r' ^ (n - s.card))) _
- · ext1 s
- rw [tsub_add_cancel_of_le (card_finset_fin_le _), mul_assoc]
- rw [← Fin.sum_pow_mul_eq_add_pow]
- exact (hasSum_fintype _).mul_left _
- refine NNReal.summable_sigma.2 ⟨fun n => (this n).summable, ?_⟩
- simp only [(this _).tsum_eq]
- exact p.summable_nnnorm_mul_pow hr
-
-theorem changeOriginSeries_summable_aux₂ (hr : (r : ℝ≥0∞) < p.radius) (k : ℕ) :
- Summable fun s : Σl : ℕ, { s : Finset (Fin (k + l)) // s.card = l } =>
- ‖p (k + s.1)‖₊ * r ^ s.1 := by
- rcases ENNReal.lt_iff_exists_add_pos_lt.1 hr with ⟨r', h0, hr'⟩
- simpa only [mul_inv_cancel_right₀ (pow_pos h0 _).ne'] using
- ((NNReal.summable_sigma.1 (p.changeOriginSeries_summable_aux₁ hr')).1 k).mul_right (r' ^ k)⁻¹
-
-theorem changeOriginSeries_summable_aux₃ {r : ℝ≥0} (hr : ↑r < p.radius) (k : ℕ) :
- Summable fun l : ℕ => ‖p.changeOriginSeries k l‖₊ * r ^ l := by
- refine NNReal.summable_of_le
- (fun n => ?_) (NNReal.summable_sigma.1 <| p.changeOriginSeries_summable_aux₂ hr k).2
- simp only [NNReal.tsum_mul_right]
- exact mul_le_mul' (p.nnnorm_changeOriginSeries_le_tsum _ _) le_rfl
-
-theorem le_changeOriginSeries_radius (k : ℕ) : p.radius ≤ (p.changeOriginSeries k).radius :=
- ENNReal.le_of_forall_nnreal_lt fun _r hr =>
- le_radius_of_summable_nnnorm _ (p.changeOriginSeries_summable_aux₃ hr k)
-
-theorem nnnorm_changeOrigin_le (k : ℕ) (h : (‖x‖₊ : ℝ≥0∞) < p.radius) :
- ‖p.changeOrigin x k‖₊ ≤
- ∑' s : Σl : ℕ, { s : Finset (Fin (k + l)) // s.card = l }, ‖p (k + s.1)‖₊ * ‖x‖₊ ^ s.1 := by
- refine tsum_of_nnnorm_bounded ?_ fun l => p.nnnorm_changeOriginSeries_apply_le_tsum k l x
- have := p.changeOriginSeries_summable_aux₂ h k
- refine HasSum.sigma this.hasSum fun l => ?_
- exact ((NNReal.summable_sigma.1 this).1 l).hasSum
-
-/-- The radius of convergence of `p.changeOrigin x` is at least `p.radius - ‖x‖`. In other words,
-`p.changeOrigin x` is well defined on the largest ball contained in the original ball of
-convergence. -/
-theorem changeOrigin_radius : p.radius - ‖x‖₊ ≤ (p.changeOrigin x).radius := by
- refine ENNReal.le_of_forall_pos_nnreal_lt fun r _h0 hr => ?_
- rw [lt_tsub_iff_right, add_comm] at hr
- have hr' : (‖x‖₊ : ℝ≥0∞) < p.radius := (le_add_right le_rfl).trans_lt hr
- apply le_radius_of_summable_nnnorm
- have : ∀ k : ℕ,
- ‖p.changeOrigin x k‖₊ * r ^ k ≤
- (∑' s : Σl : ℕ, { s : Finset (Fin (k + l)) // s.card = l }, ‖p (k + s.1)‖₊ * ‖x‖₊ ^ s.1) *
- r ^ k :=
- fun k => mul_le_mul_right' (p.nnnorm_changeOrigin_le k hr') (r ^ k)
- refine NNReal.summable_of_le this ?_
- simpa only [← NNReal.tsum_mul_right] using
- (NNReal.summable_sigma.1 (p.changeOriginSeries_summable_aux₁ hr)).2
-
-/-- `derivSeries p` is a power series for `fderiv 𝕜 f` if `p` is a power series for `f`,
-see `HasFPowerSeriesOnBall.fderiv`. -/
-def derivSeries : FormalMultilinearSeries 𝕜 E (E →L[𝕜] F) :=
- (continuousMultilinearCurryFin1 𝕜 E F : (E[×1]→L[𝕜] F) →L[𝕜] E →L[𝕜] F)
- |>.compFormalMultilinearSeries (p.changeOriginSeries 1)
-
-end
-
--- From this point on, assume that the space is complete, to make sure that series that converge
--- in norm also converge in `F`.
-variable [CompleteSpace F] (p : FormalMultilinearSeries 𝕜 E F) {x y : E} {r R : ℝ≥0}
-
-theorem hasFPowerSeriesOnBall_changeOrigin (k : ℕ) (hr : 0 < p.radius) :
- HasFPowerSeriesOnBall (fun x => p.changeOrigin x k) (p.changeOriginSeries k) 0 p.radius :=
- have := p.le_changeOriginSeries_radius k
- ((p.changeOriginSeries k).hasFPowerSeriesOnBall (hr.trans_le this)).mono hr this
-
-/-- Summing the series `p.changeOrigin x` at a point `y` gives back `p (x + y)`. -/
-theorem changeOrigin_eval (h : (‖x‖₊ + ‖y‖₊ : ℝ≥0∞) < p.radius) :
- (p.changeOrigin x).sum y = p.sum (x + y) := by
- have radius_pos : 0 < p.radius := lt_of_le_of_lt (zero_le _) h
- have x_mem_ball : x ∈ EMetric.ball (0 : E) p.radius :=
- mem_emetric_ball_zero_iff.2 ((le_add_right le_rfl).trans_lt h)
- have y_mem_ball : y ∈ EMetric.ball (0 : E) (p.changeOrigin x).radius := by
- refine mem_emetric_ball_zero_iff.2 (lt_of_lt_of_le ?_ p.changeOrigin_radius)
- rwa [lt_tsub_iff_right, add_comm]
- have x_add_y_mem_ball : x + y ∈ EMetric.ball (0 : E) p.radius := by
- refine mem_emetric_ball_zero_iff.2 (lt_of_le_of_lt ?_ h)
- exact mod_cast nnnorm_add_le x y
- set f : (Σ k l : ℕ, { s : Finset (Fin (k + l)) // s.card = l }) → F := fun s =>
- p.changeOriginSeriesTerm s.1 s.2.1 s.2.2 s.2.2.2 (fun _ => x) fun _ => y
- have hsf : Summable f := by
- refine .of_nnnorm_bounded _ (p.changeOriginSeries_summable_aux₁ h) ?_
- rintro ⟨k, l, s, hs⟩
- dsimp only [Subtype.coe_mk]
- exact p.nnnorm_changeOriginSeriesTerm_apply_le _ _ _ _ _ _
- have hf : HasSum f ((p.changeOrigin x).sum y) := by
- refine HasSum.sigma_of_hasSum ((p.changeOrigin x).summable y_mem_ball).hasSum (fun k => ?_) hsf
- · dsimp only [f]
- refine ContinuousMultilinearMap.hasSum_eval ?_ _
- have := (p.hasFPowerSeriesOnBall_changeOrigin k radius_pos).hasSum x_mem_ball
- rw [zero_add] at this
- refine HasSum.sigma_of_hasSum this (fun l => ?_) ?_
- · simp only [changeOriginSeries, ContinuousMultilinearMap.sum_apply]
- apply hasSum_fintype
- · refine .of_nnnorm_bounded _
- (p.changeOriginSeries_summable_aux₂ (mem_emetric_ball_zero_iff.1 x_mem_ball) k)
- fun s => ?_
- refine (ContinuousMultilinearMap.le_opNNNorm _ _).trans_eq ?_
- simp
- refine hf.unique (changeOriginIndexEquiv.symm.hasSum_iff.1 ?_)
- refine HasSum.sigma_of_hasSum
- (p.hasSum x_add_y_mem_ball) (fun n => ?_) (changeOriginIndexEquiv.symm.summable_iff.2 hsf)
- erw [(p n).map_add_univ (fun _ => x) fun _ => y]
- simp_rw [← changeOriginSeriesTerm_changeOriginIndexEquiv_symm]
- exact hasSum_fintype (fun c => f (changeOriginIndexEquiv.symm ⟨n, c⟩))
-
-/-- Power series terms are analytic as we vary the origin -/
-theorem analyticAt_changeOrigin (p : FormalMultilinearSeries 𝕜 E F) (rp : p.radius > 0) (n : ℕ) :
- AnalyticAt 𝕜 (fun x ↦ p.changeOrigin x n) 0 :=
- (FormalMultilinearSeries.hasFPowerSeriesOnBall_changeOrigin p n rp).analyticAt
-
-end FormalMultilinearSeries
-
-section
-
-variable [CompleteSpace F] {f : E → F} {p : FormalMultilinearSeries 𝕜 E F} {x y : E} {r : ℝ≥0∞}
-
-/-- If a function admits a power series expansion `p` on a ball `B (x, r)`, then it also admits a
-power series on any subball of this ball (even with a different center), given by `p.changeOrigin`.
--/
-theorem HasFPowerSeriesOnBall.changeOrigin (hf : HasFPowerSeriesOnBall f p x r)
- (h : (‖y‖₊ : ℝ≥0∞) < r) : HasFPowerSeriesOnBall f (p.changeOrigin y) (x + y) (r - ‖y‖₊) :=
- { r_le := by
- apply le_trans _ p.changeOrigin_radius
- exact tsub_le_tsub hf.r_le le_rfl
- r_pos := by simp [h]
- hasSum := fun {z} hz => by
- have : f (x + y + z) =
- FormalMultilinearSeries.sum (FormalMultilinearSeries.changeOrigin p y) z := by
- rw [mem_emetric_ball_zero_iff, lt_tsub_iff_right, add_comm] at hz
- rw [p.changeOrigin_eval (hz.trans_le hf.r_le), add_assoc, hf.sum]
- refine mem_emetric_ball_zero_iff.2 (lt_of_le_of_lt ?_ hz)
- exact mod_cast nnnorm_add_le y z
- rw [this]
- apply (p.changeOrigin y).hasSum
- refine EMetric.ball_subset_ball (le_trans ?_ p.changeOrigin_radius) hz
- exact tsub_le_tsub hf.r_le le_rfl }
-
-/-- If a function admits a power series expansion `p` on an open ball `B (x, r)`, then
-it is analytic at every point of this ball. -/
-theorem HasFPowerSeriesOnBall.analyticAt_of_mem (hf : HasFPowerSeriesOnBall f p x r)
- (h : y ∈ EMetric.ball x r) : AnalyticAt 𝕜 f y := by
- have : (‖y - x‖₊ : ℝ≥0∞) < r := by simpa [edist_eq_coe_nnnorm_sub] using h
- have := hf.changeOrigin this
- rw [add_sub_cancel] at this
- exact this.analyticAt
-
-theorem HasFPowerSeriesOnBall.analyticOn (hf : HasFPowerSeriesOnBall f p x r) :
- AnalyticOn 𝕜 f (EMetric.ball x r) :=
- fun _y hy => hf.analyticAt_of_mem hy
-
-variable (𝕜 f)
-
-/-- For any function `f` from a normed vector space to a Banach space, the set of points `x` such
-that `f` is analytic at `x` is open. -/
-theorem isOpen_analyticAt : IsOpen { x | AnalyticAt 𝕜 f x } := by
- rw [isOpen_iff_mem_nhds]
- rintro x ⟨p, r, hr⟩
- exact mem_of_superset (EMetric.ball_mem_nhds _ hr.r_pos) fun y hy => hr.analyticAt_of_mem hy
-
-variable {𝕜}
-
-theorem AnalyticAt.eventually_analyticAt {f : E → F} {x : E} (h : AnalyticAt 𝕜 f x) :
- ∀ᶠ y in 𝓝 x, AnalyticAt 𝕜 f y :=
-(isOpen_analyticAt 𝕜 f).mem_nhds h
-
-theorem AnalyticAt.exists_mem_nhds_analyticOn {f : E → F} {x : E} (h : AnalyticAt 𝕜 f x) :
- ∃ s ∈ 𝓝 x, AnalyticOn 𝕜 f s :=
-h.eventually_analyticAt.exists_mem
-
-/-- If we're analytic at a point, we're analytic in a nonempty ball -/
-theorem AnalyticAt.exists_ball_analyticOn {f : E → F} {x : E} (h : AnalyticAt 𝕜 f x) :
- ∃ r : ℝ, 0 < r ∧ AnalyticOn 𝕜 f (Metric.ball x r) :=
- Metric.isOpen_iff.mp (isOpen_analyticAt _ _) _ h
-
-end
-
section
open FormalMultilinearSeries
@@ -1347,7 +1343,7 @@ theorem hasFPowerSeriesAt_iff :
simp only [Metric.eventually_nhds_iff]
rintro ⟨r, r_pos, h⟩
refine ⟨p.radius ⊓ r.toNNReal, by simp, ?_, ?_⟩
- · simp only [r_pos.lt, lt_inf_iff, ENNReal.coe_pos, Real.toNNReal_pos, and_true_iff]
+ · simp only [r_pos.lt, lt_inf_iff, ENNReal.coe_pos, Real.toNNReal_pos, and_true]
obtain ⟨z, z_pos, le_z⟩ := NormedField.exists_norm_lt 𝕜 r_pos.lt
have : (‖z‖₊ : ENNReal) ≤ p.radius := by
simp only [dist_zero_right] at h
diff --git a/Mathlib/Analysis/Analytic/CPolynomial.lean b/Mathlib/Analysis/Analytic/CPolynomial.lean
index 355c4baaf830d..263a5246c148b 100644
--- a/Mathlib/Analysis/Analytic/CPolynomial.lean
+++ b/Mathlib/Analysis/Analytic/CPolynomial.lean
@@ -3,7 +3,8 @@ Copyright (c) 2023 Sophie Morel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sophie Morel
-/
-import Mathlib.Analysis.Analytic.Basic
+import Mathlib.Analysis.Analytic.ChangeOrigin
+import Mathlib.Analysis.Analytic.Constructions
/-! We specialize the theory fo analytic functions to the case of functions that admit a
development given by a *finite* formal multilinear series. We call them "continuously polynomial",
@@ -28,15 +29,19 @@ for `n : ℕ`, and let `f` be a function from `E` to `F`.
We develop the basic properties of these notions, notably:
* If a function is continuously polynomial, then it is analytic, see
`HasFiniteFPowerSeriesOnBall.hasFPowerSeriesOnBall`, `HasFiniteFPowerSeriesAt.hasFPowerSeriesAt`,
- `CPolynomialAt.analyticAt` and `CPolynomialOn.analyticOn`.
+ `CPolynomialAt.analyticAt` and `CPolynomialOn.analyticOnNhd`.
* The sum of a finite formal power series with positive radius is well defined on the whole space,
see `FormalMultilinearSeries.hasFiniteFPowerSeriesOnBall_of_finite`.
* If a function admits a finite power series in a ball, then it is continuously polynomial at
any point `y` of this ball, and the power series there can be expressed in terms of the initial
power series `p` as `p.changeOrigin y`, which is finite (with the same bound as `p`) by
- `changeOrigin_finite_of_finite`. See `HasFiniteFPowerSeriesOnBall.changeOrigin `. It follows in
+ `changeOrigin_finite_of_finite`. See `HasFiniteFPowerSeriesOnBall.changeOrigin`. It follows in
particular that the set of points at which a given function is continuously polynomial is open,
see `isOpen_cPolynomialAt`.
+
+We prove in particular that continuous multilinear maps are continuously polynomial, and so
+are continuous linear maps into continuous multilinear maps. In particular, such maps are
+analytic.
-/
variable {𝕜 E F G : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E]
@@ -111,9 +116,16 @@ theorem CPolynomialAt.analyticAt (hf : CPolynomialAt 𝕜 f x) : AnalyticAt 𝕜
let ⟨p, _, hp⟩ := hf
⟨p, hp.toHasFPowerSeriesAt⟩
-theorem CPolynomialOn.analyticOn {s : Set E} (hf : CPolynomialOn 𝕜 f s) : AnalyticOn 𝕜 f s :=
+theorem CPolynomialAt.analyticWithinAt {s : Set E} (hf : CPolynomialAt 𝕜 f x) :
+ AnalyticWithinAt 𝕜 f s x :=
+ hf.analyticAt.analyticWithinAt
+
+theorem CPolynomialOn.analyticOnNhd {s : Set E} (hf : CPolynomialOn 𝕜 f s) : AnalyticOnNhd 𝕜 f s :=
fun x hx ↦ (hf x hx).analyticAt
+theorem CPolynomialOn.analyticOn {s : Set E} (hf : CPolynomialOn 𝕜 f s) : AnalyticOn 𝕜 f s :=
+ hf.analyticOnNhd.analyticOn
+
theorem HasFiniteFPowerSeriesOnBall.congr (hf : HasFiniteFPowerSeriesOnBall f p x n r)
(hg : EqOn f g (EMetric.ball x r)) : HasFiniteFPowerSeriesOnBall g p x n r :=
⟨hf.1.congr hg, hf.finite⟩
@@ -330,7 +342,7 @@ protected theorem CPolynomialAt.continuousAt (hf : CPolynomialAt 𝕜 f x) : Con
protected theorem CPolynomialOn.continuousOn {s : Set E} (hf : CPolynomialOn 𝕜 f s) :
ContinuousOn f s :=
- hf.analyticOn.continuousOn
+ hf.analyticOnNhd.continuousOn
/-- Continuously polynomial everywhere implies continuous -/
theorem CPolynomialOn.continuous {f : E → F} (fa : CPolynomialOn 𝕜 f univ) : Continuous f := by
@@ -539,3 +551,104 @@ theorem CPolynomialAt.exists_ball_cPolynomialOn {f : E → F} {x : E} (h : CPoly
Metric.isOpen_iff.mp (isOpen_cPolynomialAt _ _) _ h
end
+
+/-!
+### Continuous multilinear maps
+
+We show that continuous multilinear maps are continuously polynomial, and therefore analytic.
+-/
+
+namespace ContinuousMultilinearMap
+
+variable {ι : Type*} {Em : ι → Type*} [∀ i, NormedAddCommGroup (Em i)] [∀ i, NormedSpace 𝕜 (Em i)]
+ [Fintype ι] (f : ContinuousMultilinearMap 𝕜 Em F) {x : Π i, Em i} {s : Set (Π i, Em i)}
+
+open FormalMultilinearSeries
+
+protected theorem hasFiniteFPowerSeriesOnBall :
+ HasFiniteFPowerSeriesOnBall f f.toFormalMultilinearSeries 0 (Fintype.card ι + 1) ⊤ :=
+ .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
+
+lemma cpolynomialAt : CPolynomialAt 𝕜 f x :=
+ f.hasFiniteFPowerSeriesOnBall.cPolynomialAt_of_mem
+ (by simp only [Metric.emetric_ball_top, Set.mem_univ])
+
+lemma cpolyomialOn : CPolynomialOn 𝕜 f s := fun _ _ ↦ f.cpolynomialAt
+
+lemma analyticOnNhd : AnalyticOnNhd 𝕜 f s := f.cpolyomialOn.analyticOnNhd
+
+lemma analyticOn : AnalyticOn 𝕜 f s := f.analyticOnNhd.analyticOn
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn := analyticOn
+
+lemma analyticAt : AnalyticAt 𝕜 f x := f.cpolynomialAt.analyticAt
+
+lemma analyticWithinAt : AnalyticWithinAt 𝕜 f s x := f.analyticAt.analyticWithinAt
+
+end ContinuousMultilinearMap
+
+
+/-!
+### Continuous linear maps into continuous multilinear maps
+
+We show that a continuous linear map into continuous multilinear maps is continuously polynomial
+(as a function of two variables, i.e., uncurried). Therefore, it is also analytic.
+-/
+
+namespace ContinuousLinearMap
+
+variable {ι : Type*} {Em : ι → Type*} [∀ i, NormedAddCommGroup (Em i)] [∀ i, NormedSpace 𝕜 (Em i)]
+ [Fintype ι] (f : G →L[𝕜] ContinuousMultilinearMap 𝕜 Em F)
+ {s : Set (G × (Π i, Em i))} {x : G × (Π i, Em i)}
+
+/-- Formal multilinear series associated to a linear map into multilinear maps. -/
+noncomputable def toFormalMultilinearSeriesOfMultilinear :
+ FormalMultilinearSeries 𝕜 (G × (Π i, Em i)) F :=
+ fun n ↦ if h : Fintype.card (Option ι) = n then
+ (f.continuousMultilinearMapOption).domDomCongr (Fintype.equivFinOfCardEq h)
+ else 0
+
+protected theorem hasFiniteFPowerSeriesOnBall_uncurry_of_multilinear :
+ HasFiniteFPowerSeriesOnBall (fun (p : G × (Π i, Em i)) ↦ f p.1 p.2)
+ f.toFormalMultilinearSeriesOfMultilinear 0 (Fintype.card (Option ι) + 1) ⊤ := by
+ apply HasFiniteFPowerSeriesOnBall.mk' ?_ ENNReal.zero_lt_top ?_
+ · intro m hm
+ apply dif_neg
+ exact Nat.ne_of_lt hm
+ · intro y _
+ rw [Finset.sum_eq_single_of_mem _ (Finset.self_mem_range_succ _), zero_add]
+ · rw [toFormalMultilinearSeriesOfMultilinear, dif_pos rfl]; rfl
+ · intro m _ ne; rw [toFormalMultilinearSeriesOfMultilinear, dif_neg ne.symm]; rfl
+
+lemma cpolynomialAt_uncurry_of_multilinear :
+ CPolynomialAt 𝕜 (fun (p : G × (Π i, Em i)) ↦ f p.1 p.2) x :=
+ f.hasFiniteFPowerSeriesOnBall_uncurry_of_multilinear.cPolynomialAt_of_mem
+ (by simp only [Metric.emetric_ball_top, Set.mem_univ])
+
+lemma cpolyomialOn_uncurry_of_multilinear :
+ CPolynomialOn 𝕜 (fun (p : G × (Π i, Em i)) ↦ f p.1 p.2) s :=
+ fun _ _ ↦ f.cpolynomialAt_uncurry_of_multilinear
+
+lemma analyticOnNhd_uncurry_of_multilinear :
+ AnalyticOnNhd 𝕜 (fun (p : G × (Π i, Em i)) ↦ f p.1 p.2) s :=
+ f.cpolyomialOn_uncurry_of_multilinear.analyticOnNhd
+
+lemma analyticOn_uncurry_of_multilinear :
+ AnalyticOn 𝕜 (fun (p : G × (Π i, Em i)) ↦ f p.1 p.2) s :=
+ f.analyticOnNhd_uncurry_of_multilinear.analyticOn
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn_uncurry_of_multilinear := analyticOn_uncurry_of_multilinear
+
+lemma analyticAt_uncurry_of_multilinear : AnalyticAt 𝕜 (fun (p : G × (Π i, Em i)) ↦ f p.1 p.2) x :=
+ f.cpolynomialAt_uncurry_of_multilinear.analyticAt
+
+lemma analyticWithinAt_uncurry_of_multilinear :
+ AnalyticWithinAt 𝕜 (fun (p : G × (Π i, Em i)) ↦ f p.1 p.2) s x :=
+ f.analyticAt_uncurry_of_multilinear.analyticWithinAt
+
+end ContinuousLinearMap
diff --git a/Mathlib/Analysis/Analytic/ChangeOrigin.lean b/Mathlib/Analysis/Analytic/ChangeOrigin.lean
new file mode 100644
index 0000000000000..ff6fdee77e8d2
--- /dev/null
+++ b/Mathlib/Analysis/Analytic/ChangeOrigin.lean
@@ -0,0 +1,391 @@
+/-
+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, Yury Kudryashov
+-/
+import Mathlib.Analysis.Analytic.Basic
+
+/-!
+# Changing origin in a power series
+
+If a function is analytic in a disk `D(x, R)`, then it is analytic in any disk contained in that
+one. Indeed, one can write
+$$
+f (x + y + z) = \sum_{n} p_n (y + z)^n = \sum_{n, k} \binom{n}{k} p_n y^{n-k} z^k
+= \sum_{k} \Bigl(\sum_{n} \binom{n}{k} p_n y^{n-k}\Bigr) z^k.
+$$
+The corresponding power series has thus a `k`-th coefficient equal to
+$\sum_{n} \binom{n}{k} p_n y^{n-k}$. In the general case where `pₙ` is a multilinear map, this has
+to be interpreted suitably: instead of having a binomial coefficient, one should sum over all
+possible subsets `s` of `Fin n` of cardinality `k`, and attribute `z` to the indices in `s` and
+`y` to the indices outside of `s`.
+
+In this file, we implement this. The new power series is called `p.changeOrigin y`. Then, we
+check its convergence and the fact that its sum coincides with the original sum. The outcome of this
+discussion is that the set of points where a function is analytic is open. All these arguments
+require the target space to be complete, as otherwise the series might not converge.
+
+### Main results
+
+In a complete space, if a function admits a power series in a ball, then it is analytic at any
+point `y` of this ball, and the power series there can be expressed in terms of the initial power
+series `p` as `p.changeOrigin y`. See `HasFPowerSeriesOnBall.changeOrigin`. It follows in particular
+that the set of points at which a given function is analytic is open, see `isOpen_analyticAt`.
+-/
+
+noncomputable section
+
+open scoped NNReal ENNReal Topology
+open Filter Set
+
+variable {𝕜 E F : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E]
+[NormedAddCommGroup F] [NormedSpace 𝕜 F]
+
+namespace FormalMultilinearSeries
+
+section
+
+variable (p : FormalMultilinearSeries 𝕜 E F) {x y : E} {r R : ℝ≥0}
+
+/-- A term of `FormalMultilinearSeries.changeOriginSeries`.
+
+Given a formal multilinear series `p` and a point `x` in its ball of convergence,
+`p.changeOrigin x` is a formal multilinear series such that
+`p.sum (x+y) = (p.changeOrigin x).sum y` when this makes sense. Each term of `p.changeOrigin x`
+is itself an analytic function of `x` given by the series `p.changeOriginSeries`. Each term in
+`changeOriginSeries` is the sum of `changeOriginSeriesTerm`'s over all `s` of cardinality `l`.
+The definition is such that `p.changeOriginSeriesTerm k l s hs (fun _ ↦ x) (fun _ ↦ y) =
+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 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)
+ (x y : E) :
+ (p.changeOriginSeriesTerm k l s hs (fun _ => x) fun _ => y) =
+ p (k + l) (s.piecewise (fun _ => x) fun _ => y) :=
+ ContinuousMultilinearMap.curryFinFinset_apply_const _ _ _ _ _
+
+@[simp]
+theorem norm_changeOriginSeriesTerm (k l : ℕ) (s : Finset (Fin (k + l))) (hs : s.card = l) :
+ ‖p.changeOriginSeriesTerm k l s hs‖ = ‖p (k + l)‖ := by
+ simp only [changeOriginSeriesTerm, LinearIsometryEquiv.norm_map]
+
+@[simp]
+theorem nnnorm_changeOriginSeriesTerm (k l : ℕ) (s : Finset (Fin (k + l))) (hs : s.card = l) :
+ ‖p.changeOriginSeriesTerm k l s hs‖₊ = ‖p (k + l)‖₊ := by
+ simp only [changeOriginSeriesTerm, LinearIsometryEquiv.nnnorm_map]
+
+theorem nnnorm_changeOriginSeriesTerm_apply_le (k l : ℕ) (s : Finset (Fin (k + l)))
+ (hs : s.card = l) (x y : E) :
+ ‖p.changeOriginSeriesTerm k l s hs (fun _ => x) fun _ => y‖₊ ≤
+ ‖p (k + l)‖₊ * ‖x‖₊ ^ l * ‖y‖₊ ^ k := by
+ rw [← p.nnnorm_changeOriginSeriesTerm k l s hs, ← Fin.prod_const, ← Fin.prod_const]
+ apply ContinuousMultilinearMap.le_of_opNNNorm_le
+ apply ContinuousMultilinearMap.le_opNNNorm
+
+/-- The power series for `f.changeOrigin k`.
+
+Given a formal multilinear series `p` and a point `x` in its ball of convergence,
+`p.changeOrigin x` is a formal multilinear series such that
+`p.sum (x+y) = (p.changeOrigin x).sum y` when this makes sense. Its `k`-th term is the sum of
+the series `p.changeOriginSeries k`. -/
+def changeOriginSeries (k : ℕ) : FormalMultilinearSeries 𝕜 E (E[×k]→L[𝕜] F) := fun l =>
+ ∑ s : { s : Finset (Fin (k + l)) // Finset.card s = l }, p.changeOriginSeriesTerm k l s s.2
+
+theorem nnnorm_changeOriginSeries_le_tsum (k l : ℕ) :
+ ‖p.changeOriginSeries k l‖₊ ≤
+ ∑' _ : { s : Finset (Fin (k + l)) // s.card = l }, ‖p (k + l)‖₊ :=
+ (nnnorm_sum_le _ (fun t => changeOriginSeriesTerm p k l (Subtype.val t) t.prop)).trans_eq <| by
+ simp_rw [tsum_fintype, nnnorm_changeOriginSeriesTerm (p := p) (k := k) (l := l)]
+
+theorem nnnorm_changeOriginSeries_apply_le_tsum (k l : ℕ) (x : E) :
+ ‖p.changeOriginSeries k l fun _ => x‖₊ ≤
+ ∑' _ : { s : Finset (Fin (k + l)) // s.card = l }, ‖p (k + l)‖₊ * ‖x‖₊ ^ l := by
+ rw [NNReal.tsum_mul_right, ← Fin.prod_const]
+ exact (p.changeOriginSeries k l).le_of_opNNNorm_le _ (p.nnnorm_changeOriginSeries_le_tsum _ _)
+
+/-- Changing the origin of a formal multilinear series `p`, so that
+`p.sum (x+y) = (p.changeOrigin x).sum y` when this makes sense.
+-/
+def changeOrigin (x : E) : FormalMultilinearSeries 𝕜 E F :=
+ fun k => (p.changeOriginSeries k).sum x
+
+/-- An auxiliary equivalence useful in the proofs about
+`FormalMultilinearSeries.changeOriginSeries`: the set of triples `(k, l, s)`, where `s` is a
+`Finset (Fin (k + l))` of cardinality `l` is equivalent to the set of pairs `(n, s)`, where `s` is a
+`Finset (Fin n)`.
+
+The forward map sends `(k, l, s)` to `(k + l, s)` and the inverse map sends `(n, s)` to
+`(n - Finset.card s, Finset.card s, s)`. The actual definition is less readable because of problems
+with non-definitional equalities. -/
+@[simps]
+def changeOriginIndexEquiv :
+ (Σ k l : ℕ, { s : Finset (Fin (k + l)) // s.card = l }) ≃ Σ n : ℕ, Finset (Fin n) where
+ toFun s := ⟨s.1 + s.2.1, s.2.2⟩
+ invFun s :=
+ ⟨s.1 - s.2.card, s.2.card,
+ ⟨s.2.map
+ (finCongr <| (tsub_add_cancel_of_le <| card_finset_fin_le s.2).symm).toEmbedding,
+ Finset.card_map _⟩⟩
+ left_inv := by
+ rintro ⟨k, l, ⟨s : Finset (Fin <| k + l), hs : s.card = l⟩⟩
+ dsimp only [Subtype.coe_mk]
+ -- Lean can't automatically generalize `k' = k + l - s.card`, `l' = s.card`, so we explicitly
+ -- formulate the generalized goal
+ suffices ∀ k' l', k' = k → l' = l → ∀ (hkl : k + l = k' + l') (hs'),
+ (⟨k', l', ⟨s.map (finCongr hkl).toEmbedding, hs'⟩⟩ :
+ Σk l : ℕ, { s : Finset (Fin (k + l)) // s.card = l }) = ⟨k, l, ⟨s, hs⟩⟩ by
+ apply this <;> simp only [hs, add_tsub_cancel_right]
+ rintro _ _ rfl rfl hkl hs'
+ simp only [Equiv.refl_toEmbedding, finCongr_refl, Finset.map_refl, eq_self_iff_true,
+ OrderIso.refl_toEquiv, and_self_iff, heq_iff_eq]
+ right_inv := by
+ rintro ⟨n, s⟩
+ simp [tsub_add_cancel_of_le (card_finset_fin_le s), finCongr_eq_equivCast]
+
+lemma changeOriginSeriesTerm_changeOriginIndexEquiv_symm (n t) :
+ let s := changeOriginIndexEquiv.symm ⟨n, t⟩
+ p.changeOriginSeriesTerm s.1 s.2.1 s.2.2 s.2.2.2 (fun _ ↦ x) (fun _ ↦ y) =
+ p n (t.piecewise (fun _ ↦ x) fun _ ↦ y) := by
+ have : ∀ (m) (hm : n = m), p n (t.piecewise (fun _ ↦ x) fun _ ↦ y) =
+ p m ((t.map (finCongr hm).toEmbedding).piecewise (fun _ ↦ x) fun _ ↦ y) := by
+ rintro m rfl
+ simp (config := { unfoldPartialApp := true }) [Finset.piecewise]
+ simp_rw [changeOriginSeriesTerm_apply, eq_comm]; apply this
+
+theorem changeOriginSeries_summable_aux₁ {r r' : ℝ≥0} (hr : (r + r' : ℝ≥0∞) < p.radius) :
+ Summable fun s : Σk l : ℕ, { s : Finset (Fin (k + l)) // s.card = l } =>
+ ‖p (s.1 + s.2.1)‖₊ * r ^ s.2.1 * r' ^ s.1 := by
+ rw [← changeOriginIndexEquiv.symm.summable_iff]
+ dsimp only [Function.comp_def, changeOriginIndexEquiv_symm_apply_fst,
+ changeOriginIndexEquiv_symm_apply_snd_fst]
+ have : ∀ n : ℕ,
+ HasSum (fun s : Finset (Fin n) => ‖p (n - s.card + s.card)‖₊ * r ^ s.card * r' ^ (n - s.card))
+ (‖p n‖₊ * (r + r') ^ n) := by
+ intro n
+ -- TODO: why `simp only [tsub_add_cancel_of_le (card_finset_fin_le _)]` fails?
+ convert_to HasSum (fun s : Finset (Fin n) => ‖p n‖₊ * (r ^ s.card * r' ^ (n - s.card))) _
+ · ext1 s
+ rw [tsub_add_cancel_of_le (card_finset_fin_le _), mul_assoc]
+ rw [← Fin.sum_pow_mul_eq_add_pow]
+ exact (hasSum_fintype _).mul_left _
+ refine NNReal.summable_sigma.2 ⟨fun n => (this n).summable, ?_⟩
+ simp only [(this _).tsum_eq]
+ exact p.summable_nnnorm_mul_pow hr
+
+theorem changeOriginSeries_summable_aux₂ (hr : (r : ℝ≥0∞) < p.radius) (k : ℕ) :
+ Summable fun s : Σl : ℕ, { s : Finset (Fin (k + l)) // s.card = l } =>
+ ‖p (k + s.1)‖₊ * r ^ s.1 := by
+ rcases ENNReal.lt_iff_exists_add_pos_lt.1 hr with ⟨r', h0, hr'⟩
+ simpa only [mul_inv_cancel_right₀ (pow_pos h0 _).ne'] using
+ ((NNReal.summable_sigma.1 (p.changeOriginSeries_summable_aux₁ hr')).1 k).mul_right (r' ^ k)⁻¹
+
+theorem changeOriginSeries_summable_aux₃ {r : ℝ≥0} (hr : ↑r < p.radius) (k : ℕ) :
+ Summable fun l : ℕ => ‖p.changeOriginSeries k l‖₊ * r ^ l := by
+ refine NNReal.summable_of_le
+ (fun n => ?_) (NNReal.summable_sigma.1 <| p.changeOriginSeries_summable_aux₂ hr k).2
+ simp only [NNReal.tsum_mul_right]
+ exact mul_le_mul' (p.nnnorm_changeOriginSeries_le_tsum _ _) le_rfl
+
+theorem le_changeOriginSeries_radius (k : ℕ) : p.radius ≤ (p.changeOriginSeries k).radius :=
+ ENNReal.le_of_forall_nnreal_lt fun _r hr =>
+ le_radius_of_summable_nnnorm _ (p.changeOriginSeries_summable_aux₃ hr k)
+
+theorem nnnorm_changeOrigin_le (k : ℕ) (h : (‖x‖₊ : ℝ≥0∞) < p.radius) :
+ ‖p.changeOrigin x k‖₊ ≤
+ ∑' s : Σl : ℕ, { s : Finset (Fin (k + l)) // s.card = l }, ‖p (k + s.1)‖₊ * ‖x‖₊ ^ s.1 := by
+ refine tsum_of_nnnorm_bounded ?_ fun l => p.nnnorm_changeOriginSeries_apply_le_tsum k l x
+ have := p.changeOriginSeries_summable_aux₂ h k
+ refine HasSum.sigma this.hasSum fun l => ?_
+ exact ((NNReal.summable_sigma.1 this).1 l).hasSum
+
+/-- The radius of convergence of `p.changeOrigin x` is at least `p.radius - ‖x‖`. In other words,
+`p.changeOrigin x` is well defined on the largest ball contained in the original ball of
+convergence. -/
+theorem changeOrigin_radius : p.radius - ‖x‖₊ ≤ (p.changeOrigin x).radius := by
+ refine ENNReal.le_of_forall_pos_nnreal_lt fun r _h0 hr => ?_
+ rw [lt_tsub_iff_right, add_comm] at hr
+ have hr' : (‖x‖₊ : ℝ≥0∞) < p.radius := (le_add_right le_rfl).trans_lt hr
+ apply le_radius_of_summable_nnnorm
+ have : ∀ k : ℕ,
+ ‖p.changeOrigin x k‖₊ * r ^ k ≤
+ (∑' s : Σl : ℕ, { s : Finset (Fin (k + l)) // s.card = l }, ‖p (k + s.1)‖₊ * ‖x‖₊ ^ s.1) *
+ r ^ k :=
+ fun k => mul_le_mul_right' (p.nnnorm_changeOrigin_le k hr') (r ^ k)
+ refine NNReal.summable_of_le this ?_
+ simpa only [← NNReal.tsum_mul_right] using
+ (NNReal.summable_sigma.1 (p.changeOriginSeries_summable_aux₁ hr)).2
+
+/-- `derivSeries p` is a power series for `fderiv 𝕜 f` if `p` is a power series for `f`,
+see `HasFPowerSeriesOnBall.fderiv`. -/
+def derivSeries : FormalMultilinearSeries 𝕜 E (E →L[𝕜] F) :=
+ (continuousMultilinearCurryFin1 𝕜 E F : (E[×1]→L[𝕜] F) →L[𝕜] E →L[𝕜] F)
+ |>.compFormalMultilinearSeries (p.changeOriginSeries 1)
+
+theorem radius_le_radius_derivSeries : p.radius ≤ p.derivSeries.radius := by
+ apply (p.le_changeOriginSeries_radius 1).trans (radius_le_of_le (fun n ↦ ?_))
+ apply (ContinuousLinearMap.norm_compContinuousMultilinearMap_le _ _).trans
+ apply mul_le_of_le_one_left (norm_nonneg _)
+ exact ContinuousLinearMap.opNorm_le_bound _ zero_le_one (by simp)
+
+end
+
+-- From this point on, assume that the space is complete, to make sure that series that converge
+-- in norm also converge in `F`.
+variable [CompleteSpace F] (p : FormalMultilinearSeries 𝕜 E F) {x y : E} {r R : ℝ≥0}
+
+theorem hasFPowerSeriesOnBall_changeOrigin (k : ℕ) (hr : 0 < p.radius) :
+ HasFPowerSeriesOnBall (fun x => p.changeOrigin x k) (p.changeOriginSeries k) 0 p.radius :=
+ have := p.le_changeOriginSeries_radius k
+ ((p.changeOriginSeries k).hasFPowerSeriesOnBall (hr.trans_le this)).mono hr this
+
+/-- Summing the series `p.changeOrigin x` at a point `y` gives back `p (x + y)`. -/
+theorem changeOrigin_eval (h : (‖x‖₊ + ‖y‖₊ : ℝ≥0∞) < p.radius) :
+ (p.changeOrigin x).sum y = p.sum (x + y) := by
+ have radius_pos : 0 < p.radius := lt_of_le_of_lt (zero_le _) h
+ have x_mem_ball : x ∈ EMetric.ball (0 : E) p.radius :=
+ mem_emetric_ball_zero_iff.2 ((le_add_right le_rfl).trans_lt h)
+ have y_mem_ball : y ∈ EMetric.ball (0 : E) (p.changeOrigin x).radius := by
+ refine mem_emetric_ball_zero_iff.2 (lt_of_lt_of_le ?_ p.changeOrigin_radius)
+ rwa [lt_tsub_iff_right, add_comm]
+ have x_add_y_mem_ball : x + y ∈ EMetric.ball (0 : E) p.radius := by
+ refine mem_emetric_ball_zero_iff.2 (lt_of_le_of_lt ?_ h)
+ exact mod_cast nnnorm_add_le x y
+ set f : (Σ k l : ℕ, { s : Finset (Fin (k + l)) // s.card = l }) → F := fun s =>
+ p.changeOriginSeriesTerm s.1 s.2.1 s.2.2 s.2.2.2 (fun _ => x) fun _ => y
+ have hsf : Summable f := by
+ refine .of_nnnorm_bounded _ (p.changeOriginSeries_summable_aux₁ h) ?_
+ rintro ⟨k, l, s, hs⟩
+ dsimp only [Subtype.coe_mk]
+ exact p.nnnorm_changeOriginSeriesTerm_apply_le _ _ _ _ _ _
+ have hf : HasSum f ((p.changeOrigin x).sum y) := by
+ refine HasSum.sigma_of_hasSum ((p.changeOrigin x).summable y_mem_ball).hasSum (fun k => ?_) hsf
+ · dsimp only [f]
+ refine ContinuousMultilinearMap.hasSum_eval ?_ _
+ have := (p.hasFPowerSeriesOnBall_changeOrigin k radius_pos).hasSum x_mem_ball
+ rw [zero_add] at this
+ refine HasSum.sigma_of_hasSum this (fun l => ?_) ?_
+ · simp only [changeOriginSeries, ContinuousMultilinearMap.sum_apply]
+ apply hasSum_fintype
+ · refine .of_nnnorm_bounded _
+ (p.changeOriginSeries_summable_aux₂ (mem_emetric_ball_zero_iff.1 x_mem_ball) k)
+ fun s => ?_
+ refine (ContinuousMultilinearMap.le_opNNNorm _ _).trans_eq ?_
+ simp
+ refine hf.unique (changeOriginIndexEquiv.symm.hasSum_iff.1 ?_)
+ refine HasSum.sigma_of_hasSum
+ (p.hasSum x_add_y_mem_ball) (fun n => ?_) (changeOriginIndexEquiv.symm.summable_iff.2 hsf)
+ erw [(p n).map_add_univ (fun _ => x) fun _ => y]
+ simp_rw [← changeOriginSeriesTerm_changeOriginIndexEquiv_symm]
+ exact hasSum_fintype (fun c => f (changeOriginIndexEquiv.symm ⟨n, c⟩))
+
+/-- Power series terms are analytic as we vary the origin -/
+theorem analyticAt_changeOrigin (p : FormalMultilinearSeries 𝕜 E F) (rp : p.radius > 0) (n : ℕ) :
+ AnalyticAt 𝕜 (fun x ↦ p.changeOrigin x n) 0 :=
+ (FormalMultilinearSeries.hasFPowerSeriesOnBall_changeOrigin p n rp).analyticAt
+
+end FormalMultilinearSeries
+
+
+section
+
+variable [CompleteSpace F] {f : E → F} {p : FormalMultilinearSeries 𝕜 E F} {s : Set E}
+ {x y : E} {r : ℝ≥0∞}
+
+/-- If a function admits a power series expansion `p` within a set `s` on a ball `B (x, r)`, then
+it also admits a power series on any subball of this ball (even with a different center provided
+it belongs to `s`), given by `p.changeOrigin`. -/
+theorem HasFPowerSeriesWithinOnBall.changeOrigin (hf : HasFPowerSeriesWithinOnBall f p s x r)
+ (h : (‖y‖₊ : ℝ≥0∞) < r) (hy : x + y ∈ insert x s) :
+ HasFPowerSeriesWithinOnBall f (p.changeOrigin y) s (x + y) (r - ‖y‖₊) where
+ r_le := by
+ apply le_trans _ p.changeOrigin_radius
+ exact tsub_le_tsub hf.r_le le_rfl
+ r_pos := by simp [h]
+ hasSum {z} h'z hz := by
+ have : f (x + y + z) =
+ FormalMultilinearSeries.sum (FormalMultilinearSeries.changeOrigin p y) z := by
+ rw [mem_emetric_ball_zero_iff, lt_tsub_iff_right, add_comm] at hz
+ rw [p.changeOrigin_eval (hz.trans_le hf.r_le), add_assoc, hf.sum]
+ · have : insert (x + y) s ⊆ insert (x + y) (insert x s) := by
+ apply insert_subset_insert (subset_insert _ _)
+ rw [insert_eq_of_mem hy] at this
+ apply this
+ simpa [add_assoc] using h'z
+ refine mem_emetric_ball_zero_iff.2 (lt_of_le_of_lt ?_ hz)
+ exact mod_cast nnnorm_add_le y z
+ rw [this]
+ apply (p.changeOrigin y).hasSum
+ refine EMetric.ball_subset_ball (le_trans ?_ p.changeOrigin_radius) hz
+ exact tsub_le_tsub hf.r_le le_rfl
+
+/-- If a function admits a power series expansion `p` on a ball `B (x, r)`, then it also admits a
+power series on any subball of this ball (even with a different center), given by `p.changeOrigin`.
+-/
+theorem HasFPowerSeriesOnBall.changeOrigin (hf : HasFPowerSeriesOnBall f p x r)
+ (h : (‖y‖₊ : ℝ≥0∞) < r) : HasFPowerSeriesOnBall f (p.changeOrigin y) (x + y) (r - ‖y‖₊) := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf ⊢
+ exact hf.changeOrigin h (by simp)
+
+/-- If a function admits a power series expansion `p` on an open ball `B (x, r)`, then
+it is analytic at every point of this ball. -/
+theorem HasFPowerSeriesWithinOnBall.analyticWithinAt_of_mem
+ (hf : HasFPowerSeriesWithinOnBall f p s x r)
+ (h : y ∈ insert x s ∩ EMetric.ball x r) : AnalyticWithinAt 𝕜 f s y := by
+ have : (‖y - x‖₊ : ℝ≥0∞) < r := by simpa [edist_eq_coe_nnnorm_sub] using h.2
+ have := hf.changeOrigin this (by simpa using h.1)
+ rw [add_sub_cancel] at this
+ exact this.analyticWithinAt
+
+/-- If a function admits a power series expansion `p` on an open ball `B (x, r)`, then
+it is analytic at every point of this ball. -/
+theorem HasFPowerSeriesOnBall.analyticAt_of_mem (hf : HasFPowerSeriesOnBall f p x r)
+ (h : y ∈ EMetric.ball x r) : AnalyticAt 𝕜 f y := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf
+ rw [← analyticWithinAt_univ]
+ exact hf.analyticWithinAt_of_mem (by simpa using h)
+
+theorem HasFPowerSeriesWithinOnBall.analyticOn (hf : HasFPowerSeriesWithinOnBall f p s x r) :
+ AnalyticOn 𝕜 f (insert x s ∩ EMetric.ball x r) :=
+ fun _ hy ↦ ((analyticWithinAt_insert (y := x)).2 (hf.analyticWithinAt_of_mem hy)).mono
+ inter_subset_left
+
+theorem HasFPowerSeriesOnBall.analyticOnNhd (hf : HasFPowerSeriesOnBall f p x r) :
+ AnalyticOnNhd 𝕜 f (EMetric.ball x r) :=
+ fun _y hy => hf.analyticAt_of_mem hy
+
+@[deprecated (since := "2024-09-26")]
+alias HasFPowerSeriesOnBall.analyticOn := HasFPowerSeriesOnBall.analyticOnNhd
+
+variable (𝕜 f) in
+/-- For any function `f` from a normed vector space to a Banach space, the set of points `x` such
+that `f` is analytic at `x` is open. -/
+theorem isOpen_analyticAt : IsOpen { x | AnalyticAt 𝕜 f x } := by
+ rw [isOpen_iff_mem_nhds]
+ rintro x ⟨p, r, hr⟩
+ exact mem_of_superset (EMetric.ball_mem_nhds _ hr.r_pos) fun y hy => hr.analyticAt_of_mem hy
+
+theorem AnalyticAt.eventually_analyticAt (h : AnalyticAt 𝕜 f x) :
+ ∀ᶠ y in 𝓝 x, AnalyticAt 𝕜 f y :=
+ (isOpen_analyticAt 𝕜 f).mem_nhds h
+
+theorem AnalyticAt.exists_mem_nhds_analyticOnNhd (h : AnalyticAt 𝕜 f x) :
+ ∃ s ∈ 𝓝 x, AnalyticOnNhd 𝕜 f s :=
+ h.eventually_analyticAt.exists_mem
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticAt.exists_mem_nhds_analyticOn := AnalyticAt.exists_mem_nhds_analyticOnNhd
+
+/-- If we're analytic at a point, we're analytic in a nonempty ball -/
+theorem AnalyticAt.exists_ball_analyticOnNhd (h : AnalyticAt 𝕜 f x) :
+ ∃ r : ℝ, 0 < r ∧ AnalyticOnNhd 𝕜 f (Metric.ball x r) :=
+ Metric.isOpen_iff.mp (isOpen_analyticAt _ _) _ h
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticAt.exists_ball_analyticOn := AnalyticAt.exists_ball_analyticOnNhd
+
+end
diff --git a/Mathlib/Analysis/Analytic/Composition.lean b/Mathlib/Analysis/Analytic/Composition.lean
index 2267a001aa658..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)
@@ -331,29 +331,34 @@ section
variable (𝕜 E)
/-- The identity formal multilinear series, with all coefficients equal to `0` except for `n = 1`
-where it is (the continuous multilinear version of) the identity. -/
-def id : FormalMultilinearSeries 𝕜 E E
- | 0 => 0
+where it is (the continuous multilinear version of) the identity. We allow an arbitrary
+constant coefficient `x`. -/
+def id (x : E) : FormalMultilinearSeries 𝕜 E E
+ | 0 => ContinuousMultilinearMap.uncurry0 𝕜 _ x
| 1 => (continuousMultilinearCurryFin1 𝕜 E E).symm (ContinuousLinearMap.id 𝕜 E)
| _ => 0
+@[simp] theorem id_apply_zero (x : E) (v : Fin 0 → E) :
+ (FormalMultilinearSeries.id 𝕜 E x) 0 v = x := rfl
+
/-- The first coefficient of `id 𝕜 E` is the identity. -/
@[simp]
-theorem id_apply_one (v : Fin 1 → E) : (FormalMultilinearSeries.id 𝕜 E) 1 v = v 0 :=
+theorem id_apply_one (x : E) (v : Fin 1 → E) : (FormalMultilinearSeries.id 𝕜 E x) 1 v = v 0 :=
rfl
/-- The `n`th coefficient of `id 𝕜 E` is the identity when `n = 1`. We state this in a dependent
way, as it will often appear in this form. -/
-theorem id_apply_one' {n : ℕ} (h : n = 1) (v : Fin n → E) :
- (id 𝕜 E) n v = v ⟨0, h.symm ▸ zero_lt_one⟩ := by
+theorem id_apply_one' (x : E) {n : ℕ} (h : n = 1) (v : Fin n → E) :
+ (id 𝕜 E x) n v = v ⟨0, h.symm ▸ zero_lt_one⟩ := by
subst n
apply id_apply_one
/-- For `n ≠ 1`, the `n`-th coefficient of `id 𝕜 E` is zero, by definition. -/
@[simp]
-theorem id_apply_ne_one {n : ℕ} (h : n ≠ 1) : (FormalMultilinearSeries.id 𝕜 E) n = 0 := by
+theorem id_apply_of_one_lt (x : E) {n : ℕ} (h : 1 < n) :
+ (FormalMultilinearSeries.id 𝕜 E x) n = 0 := by
cases' n with n
- · rfl
+ · contradiction
· cases n
· contradiction
· rfl
@@ -361,11 +366,11 @@ theorem id_apply_ne_one {n : ℕ} (h : n ≠ 1) : (FormalMultilinearSeries.id
end
@[simp]
-theorem comp_id (p : FormalMultilinearSeries 𝕜 E F) : p.comp (id 𝕜 E) = p := by
+theorem comp_id (p : FormalMultilinearSeries 𝕜 E F) (x : E) : p.comp (id 𝕜 E x) = p := by
ext1 n
dsimp [FormalMultilinearSeries.comp]
rw [Finset.sum_eq_single (Composition.ones n)]
- · show compAlongComposition p (id 𝕜 E) (Composition.ones n) = p n
+ · show compAlongComposition p (id 𝕜 E x) (Composition.ones n) = p n
ext v
rw [compAlongComposition_apply]
apply p.congr (Composition.ones_length n)
@@ -375,50 +380,60 @@ theorem comp_id (p : FormalMultilinearSeries 𝕜 E F) : p.comp (id 𝕜 E) = p
rw [Fin.ext_iff, Fin.coe_castLE, Fin.val_mk]
· show
∀ b : Composition n,
- b ∈ Finset.univ → b ≠ Composition.ones n → compAlongComposition p (id 𝕜 E) b = 0
+ b ∈ Finset.univ → b ≠ Composition.ones n → compAlongComposition p (id 𝕜 E x) b = 0
intro b _ hb
obtain ⟨k, hk, lt_k⟩ : ∃ (k : ℕ), k ∈ Composition.blocks b ∧ 1 < k :=
Composition.ne_ones_iff.1 hb
obtain ⟨i, hi⟩ : ∃ (i : Fin b.blocks.length), b.blocks[i] = k :=
List.get_of_mem hk
-
let j : Fin b.length := ⟨i.val, b.blocks_length ▸ i.prop⟩
have A : 1 < b.blocksFun j := by convert lt_k
ext v
rw [compAlongComposition_apply, ContinuousMultilinearMap.zero_apply]
apply ContinuousMultilinearMap.map_coord_zero _ j
dsimp [applyComposition]
- rw [id_apply_ne_one _ _ (ne_of_gt A)]
+ rw [id_apply_of_one_lt _ _ _ A]
rfl
· simp
@[simp]
-theorem id_comp (p : FormalMultilinearSeries 𝕜 E F) (h : p 0 = 0) : (id 𝕜 F).comp p = p := by
+theorem id_comp (p : FormalMultilinearSeries 𝕜 E F) (v0 : Fin 0 → E) :
+ (id 𝕜 F (p 0 v0)).comp p = p := by
ext1 n
by_cases hn : n = 0
- · rw [hn, h]
+ · rw [hn]
ext v
- rw [comp_coeff_zero', id_apply_ne_one _ _ zero_ne_one]
- rfl
+ simp only [comp_coeff_zero', id_apply_zero]
+ congr with i
+ exact i.elim0
· dsimp [FormalMultilinearSeries.comp]
have n_pos : 0 < n := bot_lt_iff_ne_bot.mpr hn
rw [Finset.sum_eq_single (Composition.single n n_pos)]
- · show compAlongComposition (id 𝕜 F) p (Composition.single n n_pos) = p n
+ · show compAlongComposition (id 𝕜 F (p 0 v0)) p (Composition.single n n_pos) = p n
ext v
- rw [compAlongComposition_apply, id_apply_one' _ _ (Composition.single_length n_pos)]
+ rw [compAlongComposition_apply, id_apply_one' _ _ _ (Composition.single_length n_pos)]
dsimp [applyComposition]
refine p.congr rfl fun i him hin => congr_arg v <| ?_
ext; simp
· show
- ∀ b : Composition n,
- b ∈ Finset.univ → b ≠ Composition.single n n_pos → compAlongComposition (id 𝕜 F) p b = 0
+ ∀ b : Composition n, b ∈ Finset.univ → b ≠ Composition.single n n_pos →
+ compAlongComposition (id 𝕜 F (p 0 v0)) p b = 0
intro b _ hb
- have A : b.length ≠ 1 := by simpa [Composition.eq_single_iff_length] using hb
+ have A : 1 < b.length := by
+ have : b.length ≠ 1 := by simpa [Composition.eq_single_iff_length] using hb
+ have : 0 < b.length := Composition.length_pos_of_pos b n_pos
+ omega
ext v
- rw [compAlongComposition_apply, id_apply_ne_one _ _ A]
+ rw [compAlongComposition_apply, id_apply_of_one_lt _ _ _ A]
rfl
· simp
+/-- Variant of `id_comp` in which the zero coefficient is given by an equality hypothesis instead
+of a definitional equality. Useful for rewriting or simplifying out in some situations. -/
+theorem id_comp' (p : FormalMultilinearSeries 𝕜 E F) (x : F) (v0 : Fin 0 → E) (h : x = p 0 v0) :
+ (id 𝕜 F x).comp p = p := by
+ simp [h]
+
/-! ### Summability properties of the composition of formal power series -/
@@ -458,7 +473,7 @@ theorem comp_summable_nnreal (q : FormalMultilinearSeries 𝕜 F G) (p : FormalM
simp only [Finset.prod_mul_distrib, Finset.prod_pow_eq_pow_sum, c.sum_blocksFun]
_ ≤ ∏ _i : Fin c.length, Cp := Finset.prod_le_prod' fun i _ => hCp _
_ = Cp ^ c.length := by simp
- _ ≤ Cp ^ n := pow_le_pow_right hCp1 c.length_le
+ _ ≤ Cp ^ n := pow_right_mono₀ hCp1 c.length_le
calc
‖q.compAlongComposition p c‖₊ * r ^ n ≤
(‖q c.length‖₊ * ∏ i, ‖p (c.blocksFun i)‖₊) * r ^ n :=
@@ -527,8 +542,7 @@ def compPartialSumSource (m M N : ℕ) : Finset (Σ n, Fin n → ℕ) :=
theorem mem_compPartialSumSource_iff (m M N : ℕ) (i : Σ n, Fin n → ℕ) :
i ∈ compPartialSumSource m M N ↔
(m ≤ i.1 ∧ i.1 < M) ∧ ∀ a : Fin i.1, 1 ≤ i.2 a ∧ i.2 a < N := by
- simp only [compPartialSumSource, Finset.mem_Ico, Fintype.mem_piFinset, Finset.mem_sigma,
- iff_self_iff]
+ simp only [compPartialSumSource, Finset.mem_Ico, Fintype.mem_piFinset, Finset.mem_sigma]
/-- Change of variables appearing to compute the composition of partial sums of formal
power series -/
@@ -569,7 +583,7 @@ theorem compPartialSumTargetSet_image_compPartialSumSource (m M N : ℕ)
rcases i with ⟨n, c⟩
refine ⟨⟨c.length, c.blocksFun⟩, ?_, ?_⟩
· simp only [compPartialSumTargetSet, Set.mem_setOf_eq] at hi
- simp only [mem_compPartialSumSource_iff, hi.left, hi.right, true_and_iff, and_true_iff]
+ simp only [mem_compPartialSumSource_iff, hi.left, hi.right, true_and, and_true]
exact fun a => c.one_le_blocks' _
· dsimp [compChangeOfVariables]
rw [Composition.sigma_eq_iff_blocks_eq]
@@ -608,7 +622,7 @@ theorem compChangeOfVariables_sum {α : Type*} [AddCommMonoid α] (m M N : ℕ)
-- Porting note: added
simp only at H
simp only [mem_compPartialSumTarget_iff, Composition.length, Composition.blocks, H.left,
- map_ofFn, length_ofFn, true_and_iff, compChangeOfVariables]
+ map_ofFn, length_ofFn, true_and, compChangeOfVariables]
intro j
simp only [Composition.blocksFun, (H.right _).right, List.get_ofFn]
-- 2 - show that the map is injective
@@ -635,11 +649,12 @@ theorem compChangeOfVariables_sum {α : Type*} [AddCommMonoid α] (m M N : ℕ)
/-- The auxiliary set corresponding to the composition of partial sums asymptotically contains
all possible compositions. -/
-theorem compPartialSumTarget_tendsto_atTop :
- Tendsto (fun N => compPartialSumTarget 0 N N) atTop atTop := by
+theorem compPartialSumTarget_tendsto_prod_atTop :
+ Tendsto (fun (p : ℕ × ℕ) => compPartialSumTarget 0 p.1 p.2) atTop atTop := by
apply Monotone.tendsto_atTop_finset
· intro m n hmn a ha
- have : ∀ i, i < m → i < n := fun i hi => lt_of_lt_of_le hi hmn
+ have : ∀ i, i < m.1 → i < n.1 := fun i hi => lt_of_lt_of_le hi hmn.1
+ have : ∀ i, i < m.2 → i < n.2 := fun i hi => lt_of_lt_of_le hi hmn.2
aesop
· rintro ⟨n, c⟩
simp only [mem_compPartialSumTarget_iff]
@@ -651,40 +666,48 @@ theorem compPartialSumTarget_tendsto_atTop :
apply hn
simp only [Finset.mem_image_of_mem, Finset.mem_coe, Finset.mem_univ]
+/-- The auxiliary set corresponding to the composition of partial sums asymptotically contains
+all possible compositions. -/
+theorem compPartialSumTarget_tendsto_atTop :
+ Tendsto (fun N => compPartialSumTarget 0 N N) atTop atTop := by
+ apply Tendsto.comp compPartialSumTarget_tendsto_prod_atTop tendsto_atTop_diagonal
+
/-- Composing the partial sums of two multilinear series coincides with the sum over all
compositions in `compPartialSumTarget 0 N N`. This is precisely the motivation for the
definition of `compPartialSumTarget`. -/
theorem comp_partialSum (q : FormalMultilinearSeries 𝕜 F G) (p : FormalMultilinearSeries 𝕜 E F)
- (N : ℕ) (z : E) :
- q.partialSum N (∑ i ∈ Finset.Ico 1 N, p i fun _j => z) =
- ∑ i ∈ compPartialSumTarget 0 N N, q.compAlongComposition p i.2 fun _j => z := by
+ (M N : ℕ) (z : E) :
+ q.partialSum M (∑ i ∈ Finset.Ico 1 N, p i fun _j => z) =
+ ∑ i ∈ compPartialSumTarget 0 M N, q.compAlongComposition p i.2 fun _j => z := by
-- we expand the composition, using the multilinearity of `q` to expand along each coordinate.
suffices H :
- (∑ n ∈ Finset.range N,
+ (∑ n ∈ Finset.range M,
∑ r ∈ Fintype.piFinset fun i : Fin n => Finset.Ico 1 N,
q n fun i : Fin n => p (r i) fun _j => z) =
- ∑ i ∈ compPartialSumTarget 0 N N, q.compAlongComposition p i.2 fun _j => z by
+ ∑ i ∈ compPartialSumTarget 0 M N, q.compAlongComposition p i.2 fun _j => z by
simpa only [FormalMultilinearSeries.partialSum, ContinuousMultilinearMap.map_sum_finset] using H
-- rewrite the first sum as a big sum over a sigma type, in the finset
-- `compPartialSumTarget 0 N N`
rw [Finset.range_eq_Ico, Finset.sum_sigma']
-- use `compChangeOfVariables_sum`, saying that this change of variables respects sums
- apply compChangeOfVariables_sum 0 N N
+ apply compChangeOfVariables_sum 0 M N
rintro ⟨k, blocks_fun⟩ H
- apply congr _ (compChangeOfVariables_length 0 N N H).symm
+ apply congr _ (compChangeOfVariables_length 0 M N H).symm
intros
- rw [← compChangeOfVariables_blocksFun 0 N N H]
+ rw [← compChangeOfVariables_blocksFun 0 M N H]
rfl
end FormalMultilinearSeries
open FormalMultilinearSeries
-/-- If two functions `g` and `f` have power series `q` and `p` respectively at `f x` and `x`, then
-`g ∘ f` admits the power series `q.comp p` at `x`. -/
-theorem HasFPowerSeriesAt.comp {g : F → G} {f : E → F} {q : FormalMultilinearSeries 𝕜 F G}
- {p : FormalMultilinearSeries 𝕜 E F} {x : E} (hg : HasFPowerSeriesAt g q (f x))
- (hf : HasFPowerSeriesAt f p x) : HasFPowerSeriesAt (g ∘ f) (q.comp p) x := by
+/-- If two functions `g` and `f` have power series `q` and `p` respectively at `f x` and `x`, within
+two sets `s` and `t` such that `f` maps `s` to `t`, then `g ∘ f` admits the power
+series `q.comp p` at `x` within `s`. -/
+theorem HasFPowerSeriesWithinAt.comp {g : F → G} {f : E → F} {q : FormalMultilinearSeries 𝕜 F G}
+ {p : FormalMultilinearSeries 𝕜 E F} {x : E} {t : Set F} {s : Set E}
+ (hg : HasFPowerSeriesWithinAt g q t (f x)) (hf : HasFPowerSeriesWithinAt f p s x)
+ (hs : Set.MapsTo f s t) : HasFPowerSeriesWithinAt (g ∘ f) (q.comp p) s x := by
/- Consider `rf` and `rg` such that `f` and `g` have power series expansion on the disks
of radius `rf` and `rg`. -/
rcases hg with ⟨rg, Hg⟩
@@ -695,10 +718,14 @@ theorem HasFPowerSeriesAt.comp {g : F → G} {f : E → F} {q : FormalMultilinea
`f (x + y)` is close enough to `f x` to be in the disk where `g` is well behaved. Let
`min (r, rf, δ)` be this new radius. -/
obtain ⟨δ, δpos, hδ⟩ :
- ∃ δ : ℝ≥0∞, 0 < δ ∧ ∀ {z : E}, z ∈ EMetric.ball x δ → f z ∈ EMetric.ball (f x) rg := by
- have : EMetric.ball (f x) rg ∈ 𝓝 (f x) := EMetric.ball_mem_nhds _ Hg.r_pos
- rcases EMetric.mem_nhds_iff.1 (Hf.analyticAt.continuousAt this) with ⟨δ, δpos, Hδ⟩
- exact ⟨δ, δpos, fun hz => Hδ hz⟩
+ ∃ δ : ℝ≥0∞, 0 < δ ∧ ∀ {z : E}, z ∈ insert x s ∩ EMetric.ball x δ
+ → f z ∈ insert (f x) t ∩ EMetric.ball (f x) rg := by
+ have : insert (f x) t ∩ EMetric.ball (f x) rg ∈ 𝓝[insert (f x) t] (f x) := by
+ apply inter_mem_nhdsWithin
+ exact EMetric.ball_mem_nhds _ Hg.r_pos
+ have := Hf.analyticWithinAt.continuousWithinAt_insert.tendsto_nhdsWithin (hs.insert x) this
+ rcases EMetric.mem_nhdsWithin_iff.1 this with ⟨δ, δpos, Hδ⟩
+ exact ⟨δ, δpos, fun {z} hz => Hδ (by rwa [Set.inter_comm])⟩
let rf' := min rf δ
have min_pos : 0 < min rf' r := by
simp only [rf', r_pos, Hf.r_pos, δpos, lt_min_iff, ENNReal.coe_pos, and_self_iff]
@@ -707,17 +734,17 @@ theorem HasFPowerSeriesAt.comp {g : F → G} {f : E → F} {q : FormalMultilinea
refine ⟨min rf' r, ?_⟩
refine
⟨le_trans (min_le_right rf' r) (FormalMultilinearSeries.le_comp_radius_of_summable q p r hr),
- min_pos, @fun y hy => ?_⟩
+ min_pos, fun {y} h'y hy ↦ ?_⟩
/- Let `y` satisfy `‖y‖ < min (r, rf', δ)`. We want to show that `g (f (x + y))` is the sum of
`q.comp p` applied to `y`. -/
-- First, check that `y` is small enough so that estimates for `f` and `g` apply.
have y_mem : y ∈ EMetric.ball (0 : E) rf :=
(EMetric.ball_subset_ball (le_trans (min_le_left _ _) (min_le_left _ _))) hy
- have fy_mem : f (x + y) ∈ EMetric.ball (f x) rg := by
+ have fy_mem : f (x + y) ∈ insert (f x) t ∩ EMetric.ball (f x) rg := by
apply hδ
have : y ∈ EMetric.ball (0 : E) δ :=
(EMetric.ball_subset_ball (le_trans (min_le_left _ _) (min_le_right _ _))) hy
- simpa [edist_eq_coe_nnnorm_sub, edist_eq_coe_nnnorm]
+ simpa [-Set.mem_insert_iff, edist_eq_coe_nnnorm_sub, h'y]
/- Now the proof starts. To show that the sum of `q.comp p` at `y` is `g (f (x + y))`,
we will write `q.comp p` applied to `y` as a big sum over all compositions.
Since the sum is summable, to get its convergence it suffices to get
@@ -727,11 +754,11 @@ theorem HasFPowerSeriesAt.comp {g : F → G} {f : E → F} {q : FormalMultilinea
To show that it converges to `g (f (x + y))`, pointwise convergence would not be enough,
but we have uniform convergence to save the day. -/
-- First step: the partial sum of `p` converges to `f (x + y)`.
- have A : Tendsto (fun n => ∑ a ∈ Finset.Ico 1 n, p a fun _b => y)
- atTop (𝓝 (f (x + y) - f x)) := by
- have L :
- ∀ᶠ n in atTop, (∑ a ∈ Finset.range n, p a fun _b => y) - f x
- = ∑ a ∈ Finset.Ico 1 n, p a fun _b => y := by
+ have A : Tendsto (fun n ↦ (n, ∑ a ∈ Finset.Ico 1 n, p a fun _ ↦ y))
+ atTop (atTop ×ˢ 𝓝 (f (x + y) - f x)) := by
+ apply Tendsto.prod_mk tendsto_id
+ have L : ∀ᶠ n in atTop, (∑ a ∈ Finset.range n, p a fun _b ↦ y) - f x
+ = ∑ a ∈ Finset.Ico 1 n, p a fun _b ↦ y := by
rw [eventually_atTop]
refine ⟨1, fun n hn => ?_⟩
symm
@@ -740,23 +767,19 @@ theorem HasFPowerSeriesAt.comp {g : F → G} {f : E → F} {q : FormalMultilinea
have :
Tendsto (fun n => (∑ a ∈ Finset.range n, p a fun _b => y) - f x) atTop
(𝓝 (f (x + y) - f x)) :=
- (Hf.hasSum y_mem).tendsto_sum_nat.sub tendsto_const_nhds
+ (Hf.hasSum h'y y_mem).tendsto_sum_nat.sub tendsto_const_nhds
exact Tendsto.congr' L this
-- Second step: the composition of the partial sums of `q` and `p` converges to `g (f (x + y))`.
- have B :
- Tendsto (fun n => q.partialSum n (∑ a ∈ Finset.Ico 1 n, p a fun _b => y)) atTop
+ have B : Tendsto (fun n => q.partialSum n (∑ a ∈ Finset.Ico 1 n, p a fun _b ↦ y)) atTop
(𝓝 (g (f (x + y)))) := by
- -- we use the fact that the partial sums of `q` converge locally uniformly to `g`, and that
- -- composition passes to the limit under locally uniform convergence.
- have B₁ : ContinuousAt (fun z : F => g (f x + z)) (f (x + y) - f x) := by
- refine ContinuousAt.comp ?_ (continuous_const.add continuous_id).continuousAt
- simp only [add_sub_cancel, _root_.id]
- exact Hg.continuousOn.continuousAt (IsOpen.mem_nhds EMetric.isOpen_ball fy_mem)
- have B₂ : f (x + y) - f x ∈ EMetric.ball (0 : F) rg := by
- simpa [edist_eq_coe_nnnorm, edist_eq_coe_nnnorm_sub] using fy_mem
- rw [← EMetric.isOpen_ball.nhdsWithin_eq B₂] at A
- convert Hg.tendstoLocallyUniformlyOn.tendsto_comp B₁.continuousWithinAt B₂ A
- simp only [add_sub_cancel]
+ -- we use the fact that the partial sums of `q` converge to `g (f (x + y))`, uniformly on a
+ -- neighborhood of `f (x + y)`.
+ have : Tendsto (fun (z : ℕ × F) ↦ q.partialSum z.1 z.2)
+ (atTop ×ˢ 𝓝 (f (x + y) - f x)) (𝓝 (g (f x + (f (x + y) - f x)))) := by
+ apply Hg.tendsto_partialSum_prod (y := f (x + y) - f x)
+ · simpa [edist_eq_coe_nnnorm_sub] using fy_mem.2
+ · simpa using fy_mem.1
+ simpa using this.comp A
-- Third step: the sum over all compositions in `compPartialSumTarget 0 n n` converges to
-- `g (f (x + y))`. As this sum is exactly the composition of the partial sum, this is a direct
-- consequence of the second step
@@ -803,13 +826,46 @@ theorem HasFPowerSeriesAt.comp {g : F → G} {f : E → F} {q : FormalMultilinea
rw [Function.comp_apply]
exact E
+/-- If two functions `g` and `f` have power series `q` and `p` respectively at `f x` and `x`,
+then `g ∘ f` admits the power series `q.comp p` at `x` within `s`. -/
+theorem HasFPowerSeriesAt.comp {g : F → G} {f : E → F} {q : FormalMultilinearSeries 𝕜 F G}
+ {p : FormalMultilinearSeries 𝕜 E F} {x : E}
+ (hg : HasFPowerSeriesAt g q (f x)) (hf : HasFPowerSeriesAt f p x) :
+ HasFPowerSeriesAt (g ∘ f) (q.comp p) x := by
+ rw [← hasFPowerSeriesWithinAt_univ] at hf hg ⊢
+ apply hg.comp hf (by simp)
+
+/-- If two functions `g` and `f` are analytic respectively at `f x` and `x`, within
+two sets `s` and `t` such that `f` maps `s` to `t`, then `g ∘ f` is analytic at `x` within `s`. -/
+theorem AnalyticWithinAt.comp {g : F → G} {f : E → F} {x : E} {t : Set F} {s : Set E}
+ (hg : AnalyticWithinAt 𝕜 g t (f x)) (hf : AnalyticWithinAt 𝕜 f s x) (h : Set.MapsTo f s t) :
+ AnalyticWithinAt 𝕜 (g ∘ f) s x := by
+ let ⟨_q, hq⟩ := hg
+ let ⟨_p, hp⟩ := hf
+ exact (hq.comp hp h).analyticWithinAt
+
+/-- Version of `AnalyticWithinAt.comp` where point equality is a separate hypothesis. -/
+theorem AnalyticWithinAt.comp_of_eq {g : F → G} {f : E → F} {y : F} {x : E} {t : Set F} {s : Set E}
+ (hg : AnalyticWithinAt 𝕜 g t y) (hf : AnalyticWithinAt 𝕜 f s x) (h : Set.MapsTo f s t)
+ (hy : f x = y) :
+ AnalyticWithinAt 𝕜 (g ∘ f) s x := by
+ rw [← hy] at hg
+ exact hg.comp hf h
+
+lemma AnalyticOn.comp {f : F → G} {g : E → F} {s : Set F}
+ {t : Set E} (hf : AnalyticOn 𝕜 f s) (hg : AnalyticOn 𝕜 g t) (h : Set.MapsTo g t s) :
+ AnalyticOn 𝕜 (f ∘ g) t :=
+ fun x m ↦ (hf _ (h m)).comp (hg x m) h
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.comp := AnalyticOn.comp
+
/-- If two functions `g` and `f` are analytic respectively at `f x` and `x`, then `g ∘ f` is
analytic at `x`. -/
theorem AnalyticAt.comp {g : F → G} {f : E → F} {x : E} (hg : AnalyticAt 𝕜 g (f x))
- (hf : AnalyticAt 𝕜 f x) : AnalyticAt 𝕜 (g ∘ f) x :=
- let ⟨_q, hq⟩ := hg
- let ⟨_p, hp⟩ := hf
- (hq.comp hp).analyticAt
+ (hf : AnalyticAt 𝕜 f x) : AnalyticAt 𝕜 (g ∘ f) x := by
+ rw [← analyticWithinAt_univ] at hg hf ⊢
+ apply hg.comp hf (by simp)
/-- Version of `AnalyticAt.comp` where point equality is a separate hypothesis. -/
theorem AnalyticAt.comp_of_eq {g : F → G} {f : E → F} {y : F} {x : E} (hg : AnalyticAt 𝕜 g y)
@@ -817,16 +873,40 @@ theorem AnalyticAt.comp_of_eq {g : F → G} {f : E → F} {y : F} {x : E} (hg :
rw [← hy] at hg
exact hg.comp hf
+theorem AnalyticAt.comp_analyticWithinAt {g : F → G} {f : E → F} {x : E} {s : Set E}
+ (hg : AnalyticAt 𝕜 g (f x)) (hf : AnalyticWithinAt 𝕜 f s x) :
+ AnalyticWithinAt 𝕜 (g ∘ f) s x := by
+ rw [← analyticWithinAt_univ] at hg
+ exact hg.comp hf (Set.mapsTo_univ _ _)
+
+theorem AnalyticAt.comp_analyticWithinAt_of_eq {g : F → G} {f : E → F} {x : E} {y : F} {s : Set E}
+ (hg : AnalyticAt 𝕜 g y) (hf : AnalyticWithinAt 𝕜 f s x) (h : f x = y) :
+ AnalyticWithinAt 𝕜 (g ∘ f) s x := by
+ rw [← h] at hg
+ exact hg.comp_analyticWithinAt hf
+
/-- If two functions `g` and `f` are analytic respectively on `s.image f` and `s`, then `g ∘ f` is
analytic on `s`. -/
-theorem AnalyticOn.comp' {s : Set E} {g : F → G} {f : E → F} (hg : AnalyticOn 𝕜 g (s.image f))
- (hf : AnalyticOn 𝕜 f s) : AnalyticOn 𝕜 (g ∘ f) s :=
+theorem AnalyticOnNhd.comp' {s : Set E} {g : F → G} {f : E → F} (hg : AnalyticOnNhd 𝕜 g (s.image f))
+ (hf : AnalyticOnNhd 𝕜 f s) : AnalyticOnNhd 𝕜 (g ∘ f) s :=
fun z hz => (hg (f z) (Set.mem_image_of_mem f hz)).comp (hf z hz)
-theorem AnalyticOn.comp {s : Set E} {t : Set F} {g : F → G} {f : E → F} (hg : AnalyticOn 𝕜 g t)
- (hf : AnalyticOn 𝕜 f s) (st : Set.MapsTo f s t) : AnalyticOn 𝕜 (g ∘ f) s :=
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.comp' := AnalyticOnNhd.comp'
+
+theorem AnalyticOnNhd.comp {s : Set E} {t : Set F} {g : F → G} {f : E → F}
+ (hg : AnalyticOnNhd 𝕜 g t) (hf : AnalyticOnNhd 𝕜 f s) (st : Set.MapsTo f s t) :
+ AnalyticOnNhd 𝕜 (g ∘ f) s :=
comp' (mono hg (Set.mapsTo'.mp st)) hf
+lemma AnalyticOnNhd.comp_analyticOn {f : F → G} {g : E → F} {s : Set F}
+ {t : Set E} (hf : AnalyticOnNhd 𝕜 f s) (hg : AnalyticOn 𝕜 g t) (h : Set.MapsTo g t s) :
+ AnalyticOn 𝕜 (f ∘ g) t :=
+ fun x m ↦ (hf _ (h m)).comp_analyticWithinAt (hg x m)
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.comp_analyticWithinOn := AnalyticOnNhd.comp_analyticOn
+
/-!
### Associativity of the composition of formal multilinear series
@@ -963,7 +1043,7 @@ def sigmaCompositionAux (a : Composition n) (b : Composition a.length)
a.blocks_pos
(by
rw [← a.blocks.join_splitWrtComposition b]
- exact mem_join_of_mem (List.getElem_mem _ _ _) hi)
+ exact mem_join_of_mem (List.getElem_mem _) hi)
blocks_sum := by simp [Composition.blocksFun, getElem_map, Composition.gather]
theorem length_sigmaCompositionAux (a : Composition n) (b : Composition a.length)
@@ -1029,7 +1109,7 @@ theorem sizeUpTo_sizeUpTo_add (a : Composition n) (b : Composition a.length) {i
have : sizeUpTo b i + Nat.succ j = (sizeUpTo b i + j).succ := rfl
rw [this, sizeUpTo_succ _ D, IHj A, sizeUpTo_succ _ B]
simp only [sigmaCompositionAux, add_assoc, add_left_inj, Fin.val_mk]
- rw [getElem_of_eq (getElem_splitWrtComposition _ _ _ _), getElem_drop, getElem_take _ _ C]
+ rw [getElem_of_eq (getElem_splitWrtComposition _ _ _ _), getElem_drop, getElem_take' _ _ C]
/-- Natural equivalence between `(Σ (a : Composition n), Composition a.length)` and
`(Σ (c : Composition n), Π (i : Fin c.length), Composition (c.blocksFun i))`, that shows up as a
@@ -1100,7 +1180,7 @@ def sigmaEquivSigmaPi (n : ℕ) :
· intro i
dsimp [Composition.sigmaCompositionAux]
rw [getElem_of_eq (splitWrtComposition_join _ _ _)]
- · simp only [getElem_ofFn]
+ · simp only [List.getElem_ofFn]
· simp only [map_ofFn]
rfl
· congr
diff --git a/Mathlib/Analysis/Analytic/Constructions.lean b/Mathlib/Analysis/Analytic/Constructions.lean
index b66134ef40759..c3c7fe59dc3a5 100644
--- a/Mathlib/Analysis/Analytic/Constructions.lean
+++ b/Mathlib/Analysis/Analytic/Constructions.lean
@@ -6,6 +6,7 @@ Authors: David Loeffler, Geoffrey Irving
import Mathlib.Analysis.Analytic.Composition
import Mathlib.Analysis.Analytic.Linear
import Mathlib.Analysis.NormedSpace.OperatorNorm.Mul
+import Mathlib.Analysis.Normed.Ring.Units
/-!
# Various ways to combine analytic functions
@@ -31,6 +32,169 @@ variable {E F G H : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedAd
variable {𝕝 : Type*} [NontriviallyNormedField 𝕝] [NormedAlgebra 𝕜 𝕝]
variable {A : Type*} [NormedRing A] [NormedAlgebra 𝕜 A]
+/-!
+### Constants are analytic
+-/
+
+theorem hasFPowerSeriesOnBall_const {c : F} {e : E} :
+ HasFPowerSeriesOnBall (fun _ => c) (constFormalMultilinearSeries 𝕜 E c) e ⊤ := by
+ refine ⟨by simp, WithTop.top_pos, fun _ => hasSum_single 0 fun n hn => ?_⟩
+ simp [constFormalMultilinearSeries_apply hn]
+
+theorem hasFPowerSeriesAt_const {c : F} {e : E} :
+ HasFPowerSeriesAt (fun _ => c) (constFormalMultilinearSeries 𝕜 E c) e :=
+ ⟨⊤, hasFPowerSeriesOnBall_const⟩
+
+theorem analyticAt_const {v : F} {x : E} : AnalyticAt 𝕜 (fun _ => v) x :=
+ ⟨constFormalMultilinearSeries 𝕜 E v, hasFPowerSeriesAt_const⟩
+
+theorem analyticOnNhd_const {v : F} {s : Set E} : AnalyticOnNhd 𝕜 (fun _ => v) s :=
+ fun _ _ => analyticAt_const
+
+theorem analyticWithinAt_const {v : F} {s : Set E} {x : E} : AnalyticWithinAt 𝕜 (fun _ => v) s x :=
+ analyticAt_const.analyticWithinAt
+
+theorem analyticOn_const {v : F} {s : Set E} : AnalyticOn 𝕜 (fun _ => v) s :=
+ analyticOnNhd_const.analyticOn
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn_const := analyticOn_const
+
+/-!
+### Addition, negation, subtraction
+-/
+
+section
+
+variable {f g : E → F} {pf pg : FormalMultilinearSeries 𝕜 E F} {s : Set E} {x : E} {r : ℝ≥0∞}
+
+theorem HasFPowerSeriesWithinOnBall.add (hf : HasFPowerSeriesWithinOnBall f pf s x r)
+ (hg : HasFPowerSeriesWithinOnBall g pg s x r) :
+ HasFPowerSeriesWithinOnBall (f + g) (pf + pg) s x r :=
+ { r_le := le_trans (le_min_iff.2 ⟨hf.r_le, hg.r_le⟩) (pf.min_radius_le_radius_add pg)
+ r_pos := hf.r_pos
+ hasSum := fun hy h'y => (hf.hasSum hy h'y).add (hg.hasSum hy h'y) }
+
+theorem HasFPowerSeriesOnBall.add (hf : HasFPowerSeriesOnBall f pf x r)
+ (hg : HasFPowerSeriesOnBall g pg x r) : HasFPowerSeriesOnBall (f + g) (pf + pg) x r :=
+ { r_le := le_trans (le_min_iff.2 ⟨hf.r_le, hg.r_le⟩) (pf.min_radius_le_radius_add pg)
+ r_pos := hf.r_pos
+ hasSum := fun hy => (hf.hasSum hy).add (hg.hasSum hy) }
+
+theorem HasFPowerSeriesWithinAt.add
+ (hf : HasFPowerSeriesWithinAt f pf s x) (hg : HasFPowerSeriesWithinAt g pg s x) :
+ HasFPowerSeriesWithinAt (f + g) (pf + pg) s x := by
+ rcases (hf.eventually.and hg.eventually).exists with ⟨r, hr⟩
+ exact ⟨r, hr.1.add hr.2⟩
+
+theorem HasFPowerSeriesAt.add (hf : HasFPowerSeriesAt f pf x) (hg : HasFPowerSeriesAt g pg x) :
+ HasFPowerSeriesAt (f + g) (pf + pg) x := by
+ rcases (hf.eventually.and hg.eventually).exists with ⟨r, hr⟩
+ exact ⟨r, hr.1.add hr.2⟩
+
+theorem AnalyticWithinAt.add (hf : AnalyticWithinAt 𝕜 f s x) (hg : AnalyticWithinAt 𝕜 g s x) :
+ AnalyticWithinAt 𝕜 (f + g) s x :=
+ let ⟨_, hpf⟩ := hf
+ let ⟨_, hqf⟩ := hg
+ (hpf.add hqf).analyticWithinAt
+
+theorem AnalyticAt.add (hf : AnalyticAt 𝕜 f x) (hg : AnalyticAt 𝕜 g x) : AnalyticAt 𝕜 (f + g) x :=
+ let ⟨_, hpf⟩ := hf
+ let ⟨_, hqf⟩ := hg
+ (hpf.add hqf).analyticAt
+
+theorem HasFPowerSeriesWithinOnBall.neg (hf : HasFPowerSeriesWithinOnBall f pf s x r) :
+ HasFPowerSeriesWithinOnBall (-f) (-pf) s x r :=
+ { r_le := by
+ rw [pf.radius_neg]
+ exact hf.r_le
+ r_pos := hf.r_pos
+ hasSum := fun hy h'y => (hf.hasSum hy h'y).neg }
+
+theorem HasFPowerSeriesOnBall.neg (hf : HasFPowerSeriesOnBall f pf x r) :
+ HasFPowerSeriesOnBall (-f) (-pf) x r :=
+ { r_le := by
+ rw [pf.radius_neg]
+ exact hf.r_le
+ r_pos := hf.r_pos
+ hasSum := fun hy => (hf.hasSum hy).neg }
+
+theorem HasFPowerSeriesWithinAt.neg (hf : HasFPowerSeriesWithinAt f pf s x) :
+ HasFPowerSeriesWithinAt (-f) (-pf) s x :=
+ let ⟨_, hrf⟩ := hf
+ hrf.neg.hasFPowerSeriesWithinAt
+
+theorem HasFPowerSeriesAt.neg (hf : HasFPowerSeriesAt f pf x) : HasFPowerSeriesAt (-f) (-pf) x :=
+ let ⟨_, hrf⟩ := hf
+ hrf.neg.hasFPowerSeriesAt
+
+theorem AnalyticWithinAt.neg (hf : AnalyticWithinAt 𝕜 f s x) : AnalyticWithinAt 𝕜 (-f) s x :=
+ let ⟨_, hpf⟩ := hf
+ hpf.neg.analyticWithinAt
+
+theorem AnalyticAt.neg (hf : AnalyticAt 𝕜 f x) : AnalyticAt 𝕜 (-f) x :=
+ let ⟨_, hpf⟩ := hf
+ hpf.neg.analyticAt
+
+theorem HasFPowerSeriesWithinOnBall.sub (hf : HasFPowerSeriesWithinOnBall f pf s x r)
+ (hg : HasFPowerSeriesWithinOnBall g pg s x r) :
+ HasFPowerSeriesWithinOnBall (f - g) (pf - pg) s x r := by
+ simpa only [sub_eq_add_neg] using hf.add hg.neg
+
+theorem HasFPowerSeriesOnBall.sub (hf : HasFPowerSeriesOnBall f pf x r)
+ (hg : HasFPowerSeriesOnBall g pg x r) : HasFPowerSeriesOnBall (f - g) (pf - pg) x r := by
+ simpa only [sub_eq_add_neg] using hf.add hg.neg
+
+theorem HasFPowerSeriesWithinAt.sub
+ (hf : HasFPowerSeriesWithinAt f pf s x) (hg : HasFPowerSeriesWithinAt g pg s x) :
+ HasFPowerSeriesWithinAt (f - g) (pf - pg) s x := by
+ simpa only [sub_eq_add_neg] using hf.add hg.neg
+
+theorem HasFPowerSeriesAt.sub (hf : HasFPowerSeriesAt f pf x) (hg : HasFPowerSeriesAt g pg x) :
+ HasFPowerSeriesAt (f - g) (pf - pg) x := by
+ simpa only [sub_eq_add_neg] using hf.add hg.neg
+
+theorem AnalyticWithinAt.sub (hf : AnalyticWithinAt 𝕜 f s x) (hg : AnalyticWithinAt 𝕜 g s x) :
+ AnalyticWithinAt 𝕜 (f - g) s x := by
+ simpa only [sub_eq_add_neg] using hf.add hg.neg
+
+theorem AnalyticAt.sub (hf : AnalyticAt 𝕜 f x) (hg : AnalyticAt 𝕜 g x) :
+ AnalyticAt 𝕜 (f - g) x := by
+ simpa only [sub_eq_add_neg] using hf.add hg.neg
+
+theorem AnalyticOn.add (hf : AnalyticOn 𝕜 f s) (hg : AnalyticOn 𝕜 g s) :
+ AnalyticOn 𝕜 (f + g) s :=
+ fun z hz => (hf z hz).add (hg z hz)
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.add := AnalyticOn.add
+
+theorem AnalyticOnNhd.add (hf : AnalyticOnNhd 𝕜 f s) (hg : AnalyticOnNhd 𝕜 g s) :
+ AnalyticOnNhd 𝕜 (f + g) s :=
+ fun z hz => (hf z hz).add (hg z hz)
+
+theorem AnalyticOn.neg (hf : AnalyticOn 𝕜 f s) : AnalyticOn 𝕜 (-f) s :=
+ fun z hz ↦ (hf z hz).neg
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.neg := AnalyticOn.neg
+
+theorem AnalyticOnNhd.neg (hf : AnalyticOnNhd 𝕜 f s) : AnalyticOnNhd 𝕜 (-f) s :=
+ fun z hz ↦ (hf z hz).neg
+
+theorem AnalyticOn.sub (hf : AnalyticOn 𝕜 f s) (hg : AnalyticOn 𝕜 g s) :
+ AnalyticOn 𝕜 (f - g) s :=
+ fun z hz => (hf z hz).sub (hg z hz)
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.sub := AnalyticOn.sub
+
+theorem AnalyticOnNhd.sub (hf : AnalyticOnNhd 𝕜 f s) (hg : AnalyticOnNhd 𝕜 g s) :
+ AnalyticOnNhd 𝕜 (f - g) s :=
+ fun z hz => (hf z hz).sub (hg z hz)
+
+end
+
/-!
### Cartesian products are analytic
-/
@@ -63,21 +227,36 @@ lemma FormalMultilinearSeries.radius_prod_eq_min
refine (max_le_add_of_nonneg (norm_nonneg _) (norm_nonneg _)).trans ?_
apply Real.le_norm_self
-lemma HasFPowerSeriesOnBall.prod {e : E} {f : E → F} {g : E → G} {r s : ℝ≥0∞}
+lemma HasFPowerSeriesWithinOnBall.prod {e : E} {f : E → F} {g : E → G} {r s : ℝ≥0∞} {t : Set E}
{p : FormalMultilinearSeries 𝕜 E F} {q : FormalMultilinearSeries 𝕜 E G}
- (hf : HasFPowerSeriesOnBall f p e r) (hg : HasFPowerSeriesOnBall g q e s) :
- HasFPowerSeriesOnBall (fun x ↦ (f x, g x)) (p.prod q) e (min r s) where
+ (hf : HasFPowerSeriesWithinOnBall f p t e r) (hg : HasFPowerSeriesWithinOnBall g q t e s) :
+ HasFPowerSeriesWithinOnBall (fun x ↦ (f x, g x)) (p.prod q) t e (min r s) where
r_le := by
rw [p.radius_prod_eq_min]
exact min_le_min hf.r_le hg.r_le
r_pos := lt_min hf.r_pos hg.r_pos
hasSum := by
- intro y hy
+ intro y h'y hy
simp_rw [FormalMultilinearSeries.prod, ContinuousMultilinearMap.prod_apply]
- refine (hf.hasSum ?_).prod_mk (hg.hasSum ?_)
+ refine (hf.hasSum h'y ?_).prod_mk (hg.hasSum h'y ?_)
· exact EMetric.mem_ball.mpr (lt_of_lt_of_le hy (min_le_left _ _))
· exact EMetric.mem_ball.mpr (lt_of_lt_of_le hy (min_le_right _ _))
+lemma HasFPowerSeriesOnBall.prod {e : E} {f : E → F} {g : E → G} {r s : ℝ≥0∞}
+ {p : FormalMultilinearSeries 𝕜 E F} {q : FormalMultilinearSeries 𝕜 E G}
+ (hf : HasFPowerSeriesOnBall f p e r) (hg : HasFPowerSeriesOnBall g q e s) :
+ HasFPowerSeriesOnBall (fun x ↦ (f x, g x)) (p.prod q) e (min r s) := by
+ rw [← hasFPowerSeriesWithinOnBall_univ] at hf hg ⊢
+ exact hf.prod hg
+
+lemma HasFPowerSeriesWithinAt.prod {e : E} {f : E → F} {g : E → G} {s : Set E}
+ {p : FormalMultilinearSeries 𝕜 E F} {q : FormalMultilinearSeries 𝕜 E G}
+ (hf : HasFPowerSeriesWithinAt f p s e) (hg : HasFPowerSeriesWithinAt g q s e) :
+ HasFPowerSeriesWithinAt (fun x ↦ (f x, g x)) (p.prod q) s e := by
+ rcases hf with ⟨_, hf⟩
+ rcases hg with ⟨_, hg⟩
+ exact ⟨_, hf.prod hg⟩
+
lemma HasFPowerSeriesAt.prod {e : E} {f : E → F} {g : E → G}
{p : FormalMultilinearSeries 𝕜 E F} {q : FormalMultilinearSeries 𝕜 E G}
(hf : HasFPowerSeriesAt f p e) (hg : HasFPowerSeriesAt g q e) :
@@ -86,6 +265,14 @@ lemma HasFPowerSeriesAt.prod {e : E} {f : E → F} {g : E → G}
rcases hg with ⟨_, hg⟩
exact ⟨_, hf.prod hg⟩
+/-- The Cartesian product of analytic functions is analytic. -/
+lemma AnalyticWithinAt.prod {e : E} {f : E → F} {g : E → G} {s : Set E}
+ (hf : AnalyticWithinAt 𝕜 f s e) (hg : AnalyticWithinAt 𝕜 g s e) :
+ AnalyticWithinAt 𝕜 (fun x ↦ (f x, g x)) s e := by
+ rcases hf with ⟨_, hf⟩
+ rcases hg with ⟨_, hg⟩
+ exact ⟨_, hf.prod hg⟩
+
/-- The Cartesian product of analytic functions is analytic. -/
lemma AnalyticAt.prod {e : E} {f : E → F} {g : E → G}
(hf : AnalyticAt 𝕜 f e) (hg : AnalyticAt 𝕜 g e) :
@@ -94,12 +281,21 @@ lemma AnalyticAt.prod {e : E} {f : E → F} {g : E → G}
rcases hg with ⟨_, hg⟩
exact ⟨_, hf.prod hg⟩
-/-- The Cartesian product of analytic functions is analytic. -/
+/-- The Cartesian product of analytic functions within a set is analytic. -/
lemma AnalyticOn.prod {f : E → F} {g : E → G} {s : Set E}
(hf : AnalyticOn 𝕜 f s) (hg : AnalyticOn 𝕜 g s) :
AnalyticOn 𝕜 (fun x ↦ (f x, g x)) s :=
fun x hx ↦ (hf x hx).prod (hg x hx)
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.prod := AnalyticOn.prod
+
+/-- The Cartesian product of analytic functions is analytic. -/
+lemma AnalyticOnNhd.prod {f : E → F} {g : E → G} {s : Set E}
+ (hf : AnalyticOnNhd 𝕜 f s) (hg : AnalyticOnNhd 𝕜 g s) :
+ AnalyticOnNhd 𝕜 (fun x ↦ (f x, g x)) s :=
+ fun x hx ↦ (hf x hx).prod (hg x hx)
+
/-- `AnalyticAt.comp` for functions on product spaces -/
theorem AnalyticAt.comp₂ {h : F × G → H} {f : E → F} {g : E → G} {x : E}
(ha : AnalyticAt 𝕜 h (f x, g x)) (fa : AnalyticAt 𝕜 f x)
@@ -107,35 +303,249 @@ theorem AnalyticAt.comp₂ {h : F × G → H} {f : E → F} {g : E → G} {x : E
AnalyticAt 𝕜 (fun x ↦ h (f x, g x)) x :=
AnalyticAt.comp ha (fa.prod ga)
-/-- `AnalyticOn.comp` for functions on product spaces -/
-theorem AnalyticOn.comp₂ {h : F × G → H} {f : E → F} {g : E → G} {s : Set (F × G)} {t : Set E}
- (ha : AnalyticOn 𝕜 h s) (fa : AnalyticOn 𝕜 f t) (ga : AnalyticOn 𝕜 g t)
- (m : ∀ x, x ∈ t → (f x, g x) ∈ s) : AnalyticOn 𝕜 (fun x ↦ h (f x, g x)) t :=
+/-- `AnalyticWithinAt.comp` for functions on product spaces -/
+theorem AnalyticWithinAt.comp₂ {h : F × G → H} {f : E → F} {g : E → G} {s : Set (F × G)}
+ {t : Set E} {x : E}
+ (ha : AnalyticWithinAt 𝕜 h s (f x, g x)) (fa : AnalyticWithinAt 𝕜 f t x)
+ (ga : AnalyticWithinAt 𝕜 g t x) (hf : Set.MapsTo (fun y ↦ (f y, g y)) t s) :
+ AnalyticWithinAt 𝕜 (fun x ↦ h (f x, g x)) t x :=
+ AnalyticWithinAt.comp ha (fa.prod ga) hf
+
+/-- `AnalyticAt.comp_analyticWithinAt` for functions on product spaces -/
+theorem AnalyticAt.comp₂_analyticWithinAt
+ {h : F × G → H} {f : E → F} {g : E → G} {x : E} {s : Set E}
+ (ha : AnalyticAt 𝕜 h (f x, g x)) (fa : AnalyticWithinAt 𝕜 f s x)
+ (ga : AnalyticWithinAt 𝕜 g s x) :
+ AnalyticWithinAt 𝕜 (fun x ↦ h (f x, g x)) s x :=
+ AnalyticAt.comp_analyticWithinAt ha (fa.prod ga)
+
+/-- `AnalyticOnNhd.comp` for functions on product spaces -/
+theorem AnalyticOnNhd.comp₂ {h : F × G → H} {f : E → F} {g : E → G} {s : Set (F × G)} {t : Set E}
+ (ha : AnalyticOnNhd 𝕜 h s) (fa : AnalyticOnNhd 𝕜 f t) (ga : AnalyticOnNhd 𝕜 g t)
+ (m : ∀ x, x ∈ t → (f x, g x) ∈ s) : AnalyticOnNhd 𝕜 (fun x ↦ h (f x, g x)) t :=
fun _ xt ↦ (ha _ (m _ xt)).comp₂ (fa _ xt) (ga _ xt)
+/-- `AnalyticOn.comp` for functions on product spaces -/
+theorem AnalyticOn.comp₂ {h : F × G → H} {f : E → F} {g : E → G} {s : Set (F × G)}
+ {t : Set E}
+ (ha : AnalyticOn 𝕜 h s) (fa : AnalyticOn 𝕜 f t)
+ (ga : AnalyticOn 𝕜 g t) (m : Set.MapsTo (fun y ↦ (f y, g y)) t s) :
+ AnalyticOn 𝕜 (fun x ↦ h (f x, g x)) t :=
+ fun x hx ↦ (ha _ (m hx)).comp₂ (fa x hx) (ga x hx) m
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.comp₂ := AnalyticOn.comp₂
+
/-- Analytic functions on products are analytic in the first coordinate -/
theorem AnalyticAt.curry_left {f : E × F → G} {p : E × F} (fa : AnalyticAt 𝕜 f p) :
AnalyticAt 𝕜 (fun x ↦ f (x, p.2)) p.1 :=
- AnalyticAt.comp₂ fa (analyticAt_id _ _) analyticAt_const
+ AnalyticAt.comp₂ fa analyticAt_id analyticAt_const
alias AnalyticAt.along_fst := AnalyticAt.curry_left
+theorem AnalyticWithinAt.curry_left
+ {f : E × F → G} {s : Set (E × F)} {p : E × F} (fa : AnalyticWithinAt 𝕜 f s p) :
+ AnalyticWithinAt 𝕜 (fun x ↦ f (x, p.2)) {x | (x, p.2) ∈ s} p.1 :=
+ AnalyticWithinAt.comp₂ fa analyticWithinAt_id analyticWithinAt_const (fun _ hx ↦ hx)
+
/-- Analytic functions on products are analytic in the second coordinate -/
theorem AnalyticAt.curry_right {f : E × F → G} {p : E × F} (fa : AnalyticAt 𝕜 f p) :
AnalyticAt 𝕜 (fun y ↦ f (p.1, y)) p.2 :=
- AnalyticAt.comp₂ fa analyticAt_const (analyticAt_id _ _)
+ AnalyticAt.comp₂ fa analyticAt_const analyticAt_id
alias AnalyticAt.along_snd := AnalyticAt.curry_right
+theorem AnalyticWithinAt.curry_right
+ {f : E × F → G} {s : Set (E × F)} {p : E × F} (fa : AnalyticWithinAt 𝕜 f s p) :
+ AnalyticWithinAt 𝕜 (fun y ↦ f (p.1, y)) {y | (p.1, y) ∈ s} p.2 :=
+ AnalyticWithinAt.comp₂ fa analyticWithinAt_const analyticWithinAt_id (fun _ hx ↦ hx)
+
/-- Analytic functions on products are analytic in the first coordinate -/
-theorem AnalyticOn.curry_left {f : E × F → G} {s : Set (E × F)} {y : F} (fa : AnalyticOn 𝕜 f s) :
+theorem AnalyticOnNhd.curry_left {f : E × F → G} {s : Set (E × F)} {y : F}
+ (fa : AnalyticOnNhd 𝕜 f s) :
+ AnalyticOnNhd 𝕜 (fun x ↦ f (x, y)) {x | (x, y) ∈ s} :=
+ fun x m ↦ (fa (x, y) m).curry_left
+alias AnalyticOnNhd.along_fst := AnalyticOnNhd.curry_left
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.along_fst := AnalyticOnNhd.curry_left
+
+theorem AnalyticOn.curry_left
+ {f : E × F → G} {s : Set (E × F)} {y : F} (fa : AnalyticOn 𝕜 f s) :
AnalyticOn 𝕜 (fun x ↦ f (x, y)) {x | (x, y) ∈ s} :=
- fun x m ↦ (fa (x, y) m).along_fst
-alias AnalyticOn.along_fst := AnalyticOn.curry_left
+ fun x m ↦ (fa (x, y) m).curry_left
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.curry_left := AnalyticOn.curry_left
/-- Analytic functions on products are analytic in the second coordinate -/
-theorem AnalyticOn.curry_right {f : E × F → G} {x : E} {s : Set (E × F)} (fa : AnalyticOn 𝕜 f s) :
+theorem AnalyticOnNhd.curry_right {f : E × F → G} {x : E} {s : Set (E × F)}
+ (fa : AnalyticOnNhd 𝕜 f s) :
+ AnalyticOnNhd 𝕜 (fun y ↦ f (x, y)) {y | (x, y) ∈ s} :=
+ fun y m ↦ (fa (x, y) m).curry_right
+alias AnalyticOnNhd.along_snd := AnalyticOnNhd.curry_right
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.along_snd := AnalyticOnNhd.curry_right
+
+theorem AnalyticOn.curry_right
+ {f : E × F → G} {x : E} {s : Set (E × F)} (fa : AnalyticOn 𝕜 f s) :
AnalyticOn 𝕜 (fun y ↦ f (x, y)) {y | (x, y) ∈ s} :=
- fun y m ↦ (fa (x, y) m).along_snd
-alias AnalyticOn.along_snd := AnalyticOn.curry_right
+ fun y m ↦ (fa (x, y) m).curry_right
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.curry_right := AnalyticOn.curry_right
+
+/-!
+### Analyticity in Pi spaces
+
+In this section, `f : Π i, E → Fm i` is a family of functions, i.e., each `f i` is a function,
+from `E` to a space `Fm i`. We discuss whether the family as a whole is analytic as a function
+of `x : E`, i.e., whether `x ↦ (f 1 x, ..., f n x)` is analytic from `E` to the product space
+`Π i, Fm i`. This function is denoted either by `fun x ↦ (fun i ↦ f i x)`, or `fun x i ↦ f i x`,
+or `fun x ↦ (f ⬝ x)`. We use the latter spelling in the statements, for readability purposes.
+-/
+
+section
+
+variable {ι : Type*} [Fintype ι] {e : E} {Fm : ι → Type*}
+ [∀ i, NormedAddCommGroup (Fm i)] [∀ i, NormedSpace 𝕜 (Fm i)]
+ {f : Π i, E → Fm i} {s : Set E} {r : ℝ≥0∞}
+ {p : Π i, FormalMultilinearSeries 𝕜 E (Fm i)}
+
+lemma FormalMultilinearSeries.radius_pi_le (p : Π i, FormalMultilinearSeries 𝕜 E (Fm i)) (i : ι) :
+ (FormalMultilinearSeries.pi p).radius ≤ (p i).radius := by
+ apply le_of_forall_nnreal_lt (fun r' hr' ↦ ?_)
+ obtain ⟨C, -, hC⟩ : ∃ C > 0, ∀ (n : ℕ),
+ ‖pi p n‖ * ↑r' ^ n ≤ C := norm_mul_pow_le_of_lt_radius _ hr'
+ apply le_radius_of_bound _ C (fun n ↦ ?_)
+ apply le_trans _ (hC n)
+ gcongr
+ rw [pi, ContinuousMultilinearMap.opNorm_pi]
+ exact norm_le_pi_norm (fun i ↦ p i n) i
+
+lemma FormalMultilinearSeries.le_radius_pi (h : ∀ i, r ≤ (p i).radius) :
+ r ≤ (FormalMultilinearSeries.pi p).radius := by
+ apply le_of_forall_nnreal_lt (fun r' hr' ↦ ?_)
+ have I i : ∃ C > 0, ∀ n, ‖p i n‖ * (r' : ℝ) ^ n ≤ C :=
+ norm_mul_pow_le_of_lt_radius _ (hr'.trans_le (h i))
+ choose C C_pos hC using I
+ obtain ⟨D, D_nonneg, hD⟩ : ∃ D ≥ 0, ∀ i, C i ≤ D :=
+ ⟨∑ i, C i, Finset.sum_nonneg (fun i _ ↦ (C_pos i).le),
+ fun i ↦ Finset.single_le_sum (fun j _ ↦ (C_pos j).le) (Finset.mem_univ _)⟩
+ apply le_radius_of_bound _ D (fun n ↦ ?_)
+ rcases le_or_lt ((r' : ℝ)^n) 0 with hr' | hr'
+ · exact le_trans (mul_nonpos_of_nonneg_of_nonpos (by positivity) hr') D_nonneg
+ · simp only [pi]
+ rw [← le_div_iff₀ hr', ContinuousMultilinearMap.opNorm_pi,
+ pi_norm_le_iff_of_nonneg (by positivity)]
+ intro i
+ exact (le_div_iff₀ hr').2 ((hC i n).trans (hD i))
+
+lemma FormalMultilinearSeries.radius_pi_eq_iInf :
+ (FormalMultilinearSeries.pi p).radius = ⨅ i, (p i).radius := by
+ refine le_antisymm (by simp [radius_pi_le]) ?_
+ apply le_of_forall_nnreal_lt (fun r' hr' ↦ ?_)
+ exact le_radius_pi (fun i ↦ le_iInf_iff.1 hr'.le i)
+
+/-- If each function in a finite family has a power series within a ball, then so does the
+family as a whole. Note that the positivity assumption on the radius is only needed when
+the family is empty. -/
+lemma HasFPowerSeriesWithinOnBall.pi
+ (hf : ∀ i, HasFPowerSeriesWithinOnBall (f i) (p i) s e r) (hr : 0 < r) :
+ HasFPowerSeriesWithinOnBall (fun x ↦ (f · x)) (FormalMultilinearSeries.pi p) s e r where
+ r_le := by
+ apply FormalMultilinearSeries.le_radius_pi (fun i ↦ ?_)
+ exact (hf i).r_le
+ r_pos := hr
+ 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
+ ↔ ∀ i, HasFPowerSeriesWithinOnBall (f i) (p i) s e r :=
+ ⟨fun h i ↦ ⟨h.r_le.trans (FormalMultilinearSeries.radius_pi_le _ _), hr,
+ fun m hy ↦ Pi.hasSum.1 (h.hasSum m hy) i⟩, fun h ↦ .pi h hr⟩
+
+lemma HasFPowerSeriesOnBall.pi
+ (hf : ∀ i, HasFPowerSeriesOnBall (f i) (p i) e r) (hr : 0 < r) :
+ HasFPowerSeriesOnBall (fun x ↦ (f · x)) (FormalMultilinearSeries.pi p) e r := by
+ simp_rw [← hasFPowerSeriesWithinOnBall_univ] at hf ⊢
+ exact HasFPowerSeriesWithinOnBall.pi hf hr
+
+lemma hasFPowerSeriesOnBall_pi_iff (hr : 0 < r) :
+ HasFPowerSeriesOnBall (fun x ↦ (f · x)) (FormalMultilinearSeries.pi p) e r
+ ↔ ∀ i, HasFPowerSeriesOnBall (f i) (p i) e r := by
+ simp_rw [← hasFPowerSeriesWithinOnBall_univ]
+ exact hasFPowerSeriesWithinOnBall_pi_iff hr
+
+lemma HasFPowerSeriesWithinAt.pi
+ (hf : ∀ i, HasFPowerSeriesWithinAt (f i) (p i) s e) :
+ HasFPowerSeriesWithinAt (fun x ↦ (f · x)) (FormalMultilinearSeries.pi p) s e := by
+ have : ∀ᶠ r in 𝓝[>] 0, ∀ i, HasFPowerSeriesWithinOnBall (f i) (p i) s e r :=
+ eventually_all.mpr (fun i ↦ (hf i).eventually)
+ obtain ⟨r, hr, r_pos⟩ := (this.and self_mem_nhdsWithin).exists
+ exact ⟨r, HasFPowerSeriesWithinOnBall.pi hr r_pos⟩
+
+lemma hasFPowerSeriesWithinAt_pi_iff :
+ HasFPowerSeriesWithinAt (fun x ↦ (f · x)) (FormalMultilinearSeries.pi p) s e
+ ↔ ∀ i, HasFPowerSeriesWithinAt (f i) (p i) s e := by
+ refine ⟨fun h i ↦ ?_, fun h ↦ .pi h⟩
+ obtain ⟨r, hr⟩ := h
+ exact ⟨r, (hasFPowerSeriesWithinOnBall_pi_iff hr.r_pos).1 hr i⟩
+
+lemma HasFPowerSeriesAt.pi
+ (hf : ∀ i, HasFPowerSeriesAt (f i) (p i) e) :
+ HasFPowerSeriesAt (fun x ↦ (f · x)) (FormalMultilinearSeries.pi p) e := by
+ simp_rw [← hasFPowerSeriesWithinAt_univ] at hf ⊢
+ exact HasFPowerSeriesWithinAt.pi hf
+
+lemma hasFPowerSeriesAt_pi_iff :
+ HasFPowerSeriesAt (fun x ↦ (f · x)) (FormalMultilinearSeries.pi p) e
+ ↔ ∀ i, HasFPowerSeriesAt (f i) (p i) e := by
+ simp_rw [← hasFPowerSeriesWithinAt_univ]
+ exact hasFPowerSeriesWithinAt_pi_iff
+
+lemma AnalyticWithinAt.pi (hf : ∀ i, AnalyticWithinAt 𝕜 (f i) s e) :
+ AnalyticWithinAt 𝕜 (fun x ↦ (f · x)) s e := by
+ choose p hp using hf
+ exact ⟨FormalMultilinearSeries.pi p, HasFPowerSeriesWithinAt.pi hp⟩
+
+lemma analyticWithinAt_pi_iff :
+ AnalyticWithinAt 𝕜 (fun x ↦ (f · x)) s e ↔ ∀ i, AnalyticWithinAt 𝕜 (f i) s e := by
+ refine ⟨fun h i ↦ ?_, fun h ↦ .pi h⟩
+ exact ((ContinuousLinearMap.proj (R := 𝕜) i).analyticAt _).comp_analyticWithinAt h
+
+lemma AnalyticAt.pi (hf : ∀ i, AnalyticAt 𝕜 (f i) e) :
+ AnalyticAt 𝕜 (fun x ↦ (f · x)) e := by
+ simp_rw [← analyticWithinAt_univ] at hf ⊢
+ exact AnalyticWithinAt.pi hf
+
+lemma analyticAt_pi_iff :
+ AnalyticAt 𝕜 (fun x ↦ (f · x)) e ↔ ∀ i, AnalyticAt 𝕜 (f i) e := by
+ simp_rw [← analyticWithinAt_univ]
+ exact analyticWithinAt_pi_iff
+
+lemma AnalyticOn.pi (hf : ∀ i, AnalyticOn 𝕜 (f i) s) :
+ AnalyticOn 𝕜 (fun x ↦ (f · x)) s :=
+ fun x hx ↦ AnalyticWithinAt.pi (fun i ↦ hf i x hx)
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.pi := AnalyticOn.pi
+
+lemma analyticOn_pi_iff :
+ AnalyticOn 𝕜 (fun x ↦ (f · x)) s ↔ ∀ i, AnalyticOn 𝕜 (f i) s :=
+ ⟨fun h i x hx ↦ analyticWithinAt_pi_iff.1 (h x hx) i, fun h ↦ .pi h⟩
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn_pi_iff := analyticOn_pi_iff
+
+lemma AnalyticOnNhd.pi (hf : ∀ i, AnalyticOnNhd 𝕜 (f i) s) :
+ AnalyticOnNhd 𝕜 (fun x ↦ (f · x)) s :=
+ fun x hx ↦ AnalyticAt.pi (fun i ↦ hf i x hx)
+
+lemma analyticOnNhd_pi_iff :
+ AnalyticOnNhd 𝕜 (fun x ↦ (f · x)) s ↔ ∀ i, AnalyticOnNhd 𝕜 (f i) s :=
+ ⟨fun h i x hx ↦ analyticAt_pi_iff.1 (h x hx) i, fun h ↦ .pi h⟩
+
+end
/-!
### Arithmetic on analytic functions
@@ -154,6 +564,13 @@ lemma analyticAt_smul [NormedSpace 𝕝 E] [IsScalarTower 𝕜 𝕝 E] (z : 𝕝
lemma analyticAt_mul (z : A × A) : AnalyticAt 𝕜 (fun x : A × A ↦ x.1 * x.2) z :=
(ContinuousLinearMap.mul 𝕜 A).analyticAt_bilinear z
+/-- Scalar multiplication of one analytic function by another. -/
+lemma AnalyticWithinAt.smul [NormedSpace 𝕝 F] [IsScalarTower 𝕜 𝕝 F]
+ {f : E → 𝕝} {g : E → F} {s : Set E} {z : E}
+ (hf : AnalyticWithinAt 𝕜 f s z) (hg : AnalyticWithinAt 𝕜 g s z) :
+ AnalyticWithinAt 𝕜 (fun x ↦ f x • g x) s z :=
+ (analyticAt_smul _).comp₂_analyticWithinAt hf hg
+
/-- Scalar multiplication of one analytic function by another. -/
lemma AnalyticAt.smul [NormedSpace 𝕝 F] [IsScalarTower 𝕜 𝕝 F] {f : E → 𝕝} {g : E → F} {z : E}
(hf : AnalyticAt 𝕜 f z) (hg : AnalyticAt 𝕜 g z) :
@@ -161,53 +578,165 @@ lemma AnalyticAt.smul [NormedSpace 𝕝 F] [IsScalarTower 𝕜 𝕝 F] {f : E
(analyticAt_smul _).comp₂ hf hg
/-- Scalar multiplication of one analytic function by another. -/
-lemma AnalyticOn.smul [NormedSpace 𝕝 F] [IsScalarTower 𝕜 𝕝 F] {f : E → 𝕝} {g : E → F} {s : Set E}
+lemma AnalyticOn.smul [NormedSpace 𝕝 F] [IsScalarTower 𝕜 𝕝 F]
+ {f : E → 𝕝} {g : E → F} {s : Set E}
(hf : AnalyticOn 𝕜 f s) (hg : AnalyticOn 𝕜 g s) :
AnalyticOn 𝕜 (fun x ↦ f x • g x) s :=
fun _ m ↦ (hf _ m).smul (hg _ m)
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.smul := AnalyticOn.smul
+
+/-- Scalar multiplication of one analytic function by another. -/
+lemma AnalyticOnNhd.smul [NormedSpace 𝕝 F] [IsScalarTower 𝕜 𝕝 F] {f : E → 𝕝} {g : E → F} {s : Set E}
+ (hf : AnalyticOnNhd 𝕜 f s) (hg : AnalyticOnNhd 𝕜 g s) :
+ AnalyticOnNhd 𝕜 (fun x ↦ f x • g x) s :=
+ fun _ m ↦ (hf _ m).smul (hg _ m)
+
+/-- Multiplication of analytic functions (valued in a normed `𝕜`-algebra) is analytic. -/
+lemma AnalyticWithinAt.mul {f g : E → A} {s : Set E} {z : E}
+ (hf : AnalyticWithinAt 𝕜 f s z) (hg : AnalyticWithinAt 𝕜 g s z) :
+ AnalyticWithinAt 𝕜 (fun x ↦ f x * g x) s z :=
+ (analyticAt_mul _).comp₂_analyticWithinAt hf hg
+
/-- Multiplication of analytic functions (valued in a normed `𝕜`-algebra) is analytic. -/
lemma AnalyticAt.mul {f g : E → A} {z : E} (hf : AnalyticAt 𝕜 f z) (hg : AnalyticAt 𝕜 g z) :
AnalyticAt 𝕜 (fun x ↦ f x * g x) z :=
(analyticAt_mul _).comp₂ hf hg
/-- Multiplication of analytic functions (valued in a normed `𝕜`-algebra) is analytic. -/
-lemma AnalyticOn.mul {f g : E → A} {s : Set E} (hf : AnalyticOn 𝕜 f s) (hg : AnalyticOn 𝕜 g s) :
+lemma AnalyticOn.mul {f g : E → A} {s : Set E}
+ (hf : AnalyticOn 𝕜 f s) (hg : AnalyticOn 𝕜 g s) :
AnalyticOn 𝕜 (fun x ↦ f x * g x) s :=
fun _ m ↦ (hf _ m).mul (hg _ m)
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.mul := AnalyticOn.mul
+
+/-- Multiplication of analytic functions (valued in a normed `𝕜`-algebra) is analytic. -/
+lemma AnalyticOnNhd.mul {f g : E → A} {s : Set E}
+ (hf : AnalyticOnNhd 𝕜 f s) (hg : AnalyticOnNhd 𝕜 g s) :
+ AnalyticOnNhd 𝕜 (fun x ↦ f x * g x) s :=
+ fun _ m ↦ (hf _ m).mul (hg _ m)
+
/-- Powers of analytic functions (into a normed `𝕜`-algebra) are analytic. -/
-lemma AnalyticAt.pow {f : E → A} {z : E} (hf : AnalyticAt 𝕜 f z) (n : ℕ) :
- AnalyticAt 𝕜 (fun x ↦ f x ^ n) z := by
+lemma AnalyticWithinAt.pow {f : E → A} {z : E} {s : Set E} (hf : AnalyticWithinAt 𝕜 f s z) (n : ℕ) :
+ AnalyticWithinAt 𝕜 (fun x ↦ f x ^ n) s z := by
induction n with
| zero =>
simp only [pow_zero]
- apply analyticAt_const
+ apply analyticWithinAt_const
| succ m hm =>
simp only [pow_succ]
exact hm.mul hf
+/-- Powers of analytic functions (into a normed `𝕜`-algebra) are analytic. -/
+lemma AnalyticAt.pow {f : E → A} {z : E} (hf : AnalyticAt 𝕜 f z) (n : ℕ) :
+ AnalyticAt 𝕜 (fun x ↦ f x ^ n) z := by
+ rw [← analyticWithinAt_univ] at hf ⊢
+ exact hf.pow n
+
/-- Powers of analytic functions (into a normed `𝕜`-algebra) are analytic. -/
lemma AnalyticOn.pow {f : E → A} {s : Set E} (hf : AnalyticOn 𝕜 f s) (n : ℕ) :
AnalyticOn 𝕜 (fun x ↦ f x ^ n) s :=
fun _ m ↦ (hf _ m).pow n
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.pow := AnalyticOn.pow
+
+/-- Powers of analytic functions (into a normed `𝕜`-algebra) are analytic. -/
+lemma AnalyticOnNhd.pow {f : E → A} {s : Set E} (hf : AnalyticOnNhd 𝕜 f s) (n : ℕ) :
+ AnalyticOnNhd 𝕜 (fun x ↦ f x ^ n) s :=
+ fun _ m ↦ (hf _ m).pow n
+
+
+/-!
+### Restriction of scalars
+-/
+
+section
+
+variable {𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜 𝕜']
+ [NormedSpace 𝕜' E] [IsScalarTower 𝕜 𝕜' E]
+ [NormedSpace 𝕜' F] [IsScalarTower 𝕜 𝕜' F]
+ {f : E → F} {p : FormalMultilinearSeries 𝕜' E F} {x : E} {s : Set E} {r : ℝ≥0∞}
+
+lemma HasFPowerSeriesWithinOnBall.restrictScalars (hf : HasFPowerSeriesWithinOnBall f p s x r) :
+ HasFPowerSeriesWithinOnBall f (p.restrictScalars 𝕜) s x r :=
+ ⟨hf.r_le.trans (FormalMultilinearSeries.radius_le_of_le (fun n ↦ by simp)), hf.r_pos, hf.hasSum⟩
+
+lemma HasFPowerSeriesOnBall.restrictScalars (hf : HasFPowerSeriesOnBall f p x r) :
+ HasFPowerSeriesOnBall f (p.restrictScalars 𝕜) x r :=
+ ⟨hf.r_le.trans (FormalMultilinearSeries.radius_le_of_le (fun n ↦ by simp)), hf.r_pos, hf.hasSum⟩
+
+lemma HasFPowerSeriesWithinAt.restrictScalars (hf : HasFPowerSeriesWithinAt f p s x) :
+ HasFPowerSeriesWithinAt f (p.restrictScalars 𝕜) s x := by
+ rcases hf with ⟨r, hr⟩
+ exact ⟨r, hr.restrictScalars⟩
+
+lemma HasFPowerSeriesAt.restrictScalars (hf : HasFPowerSeriesAt f p x) :
+ HasFPowerSeriesAt f (p.restrictScalars 𝕜) x := by
+ rcases hf with ⟨r, hr⟩
+ exact ⟨r, hr.restrictScalars⟩
+
+lemma AnalyticWithinAt.restrictScalars (hf : AnalyticWithinAt 𝕜' f s x) :
+ AnalyticWithinAt 𝕜 f s x := by
+ rcases hf with ⟨p, hp⟩
+ exact ⟨p.restrictScalars 𝕜, hp.restrictScalars⟩
+
+lemma AnalyticAt.restrictScalars (hf : AnalyticAt 𝕜' f x) :
+ AnalyticAt 𝕜 f x := by
+ rcases hf with ⟨p, hp⟩
+ exact ⟨p.restrictScalars 𝕜, hp.restrictScalars⟩
+
+lemma AnalyticOn.restrictScalars (hf : AnalyticOn 𝕜' f s) :
+ AnalyticOn 𝕜 f s :=
+ fun x hx ↦ (hf x hx).restrictScalars
+
+lemma AnalyticOnNhd.restrictScalars (hf : AnalyticOnNhd 𝕜' f s) :
+ AnalyticOnNhd 𝕜 f s :=
+ fun x hx ↦ (hf x hx).restrictScalars
+
+end
+
+
+/-!
+### Inversion is analytic
+-/
+
section Geometric
variable (𝕜 A : Type*) [NontriviallyNormedField 𝕜] [NormedRing A] [NormedAlgebra 𝕜 A]
- [NormOneClass A]
/-- The geometric series `1 + x + x ^ 2 + ...` as a `FormalMultilinearSeries`. -/
def formalMultilinearSeries_geometric : FormalMultilinearSeries 𝕜 A A :=
fun n ↦ ContinuousMultilinearMap.mkPiAlgebraFin 𝕜 n A
-lemma formalMultilinearSeries_geometric_apply_norm (n : ℕ) :
+lemma formalMultilinearSeries_geometric_apply_norm_le (n : ℕ) :
+ ‖formalMultilinearSeries_geometric 𝕜 A n‖ ≤ max 1 ‖(1 : A)‖ :=
+ ContinuousMultilinearMap.norm_mkPiAlgebraFin_le
+
+lemma formalMultilinearSeries_geometric_apply_norm [NormOneClass A] (n : ℕ) :
‖formalMultilinearSeries_geometric 𝕜 A n‖ = 1 :=
ContinuousMultilinearMap.norm_mkPiAlgebraFin
end Geometric
-lemma formalMultilinearSeries_geometric_radius (𝕜) [NontriviallyNormedField 𝕜]
+lemma one_le_formalMultilinearSeries_geometric_radius (𝕜 : Type*) [NontriviallyNormedField 𝕜]
+ (A : Type*) [NormedRing A] [NormedAlgebra 𝕜 A] :
+ 1 ≤ (formalMultilinearSeries_geometric 𝕜 A).radius := by
+ refine le_of_forall_nnreal_lt (fun r hr ↦ ?_)
+ rw [← Nat.cast_one, ENNReal.coe_lt_natCast, Nat.cast_one] at hr
+ apply FormalMultilinearSeries.le_radius_of_isBigO
+ apply isBigO_of_le' (c := max 1 ‖(1 : A)‖) atTop (fun n ↦ ?_)
+ simp only [norm_mul, norm_norm, norm_pow, Real.norm_eq_abs, NNReal.abs_eq, norm_one, mul_one,
+ abs_norm]
+ apply le_trans ?_ (formalMultilinearSeries_geometric_apply_norm_le 𝕜 A n)
+ conv_rhs => rw [← mul_one (‖formalMultilinearSeries_geometric 𝕜 A n‖)]
+ gcongr
+ exact pow_le_one₀ (coe_nonneg r) hr.le
+
+lemma formalMultilinearSeries_geometric_radius (𝕜 : Type*) [NontriviallyNormedField 𝕜]
(A : Type*) [NormedRing A] [NormOneClass A] [NormedAlgebra 𝕜 A] :
(formalMultilinearSeries_geometric 𝕜 A).radius = 1 := by
apply le_antisymm
@@ -231,22 +760,68 @@ lemma formalMultilinearSeries_geometric_radius (𝕜) [NontriviallyNormedField
simp_rw [formalMultilinearSeries_geometric_apply_norm, one_mul]
refine isBigO_of_le atTop (fun n ↦ ?_)
rw [norm_one, Real.norm_of_nonneg (pow_nonneg (coe_nonneg r) _)]
- exact pow_le_one _ (coe_nonneg r) hr.le
+ exact pow_le_one₀ (coe_nonneg r) hr.le
-lemma hasFPowerSeriesOnBall_inv_one_sub
- (𝕜 𝕝 : Type*) [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕝] [NormedAlgebra 𝕜 𝕝] :
- HasFPowerSeriesOnBall (fun x : 𝕝 ↦ (1 - x)⁻¹) (formalMultilinearSeries_geometric 𝕜 𝕝) 0 1 := by
+lemma hasFPowerSeriesOnBall_inverse_one_sub
+ (𝕜 : Type*) [NontriviallyNormedField 𝕜]
+ (A : Type*) [NormedRing A] [NormedAlgebra 𝕜 A] [HasSummableGeomSeries A] :
+ HasFPowerSeriesOnBall (fun x : A ↦ Ring.inverse (1 - x))
+ (formalMultilinearSeries_geometric 𝕜 A) 0 1 := by
constructor
- · exact le_of_eq (formalMultilinearSeries_geometric_radius 𝕜 𝕝).symm
+ · exact one_le_formalMultilinearSeries_geometric_radius 𝕜 A
· exact one_pos
· intro y hy
- simp_rw [zero_add, formalMultilinearSeries_geometric,
- ContinuousMultilinearMap.mkPiAlgebraFin_apply,
- List.prod_ofFn, Finset.prod_const,
- Finset.card_univ, Fintype.card_fin]
- apply hasSum_geometric_of_norm_lt_one
- simpa only [← ofReal_one, Metric.emetric_ball, Metric.ball,
- dist_eq_norm, sub_zero] using hy
+ simp only [EMetric.mem_ball, edist_dist, dist_zero_right, ofReal_lt_one] at hy
+ simp only [zero_add, NormedRing.inverse_one_sub _ hy, Units.oneSub, Units.inv_mk,
+ formalMultilinearSeries_geometric, ContinuousMultilinearMap.mkPiAlgebraFin_apply,
+ List.ofFn_const, List.prod_replicate]
+ exact (summable_geometric_of_norm_lt_one hy).hasSum
+
+lemma analyticAt_inverse_one_sub (𝕜 : Type*) [NontriviallyNormedField 𝕜]
+ (A : Type*) [NormedRing A] [NormedAlgebra 𝕜 A] [HasSummableGeomSeries A] :
+ AnalyticAt 𝕜 (fun x : A ↦ Ring.inverse (1 - x)) 0 :=
+ ⟨_, ⟨_, hasFPowerSeriesOnBall_inverse_one_sub 𝕜 A⟩⟩
+
+/-- If `A` is a normed algebra over `𝕜` with summable geometric series, then inversion on `A` is
+analytic at any unit. -/
+lemma analyticAt_inverse {𝕜 : Type*} [NontriviallyNormedField 𝕜]
+ {A : Type*} [NormedRing A] [NormedAlgebra 𝕜 A] [HasSummableGeomSeries A] (z : Aˣ) :
+ AnalyticAt 𝕜 Ring.inverse (z : A) := by
+ rcases subsingleton_or_nontrivial A with hA|hA
+ · convert analyticAt_const (v := (0 : A))
+ · let f1 : A → A := fun a ↦ a * z.inv
+ let f2 : A → A := fun b ↦ Ring.inverse (1 - b)
+ let f3 : A → A := fun c ↦ 1 - z.inv * c
+ have feq : ∀ᶠ y in 𝓝 (z : A), (f1 ∘ f2 ∘ f3) y = Ring.inverse y := by
+ have : Metric.ball (z : A) (‖(↑z⁻¹ : A)‖⁻¹) ∈ 𝓝 (z : A) := by
+ apply Metric.ball_mem_nhds
+ simp
+ filter_upwards [this] with y hy
+ simp only [Metric.mem_ball, dist_eq_norm] at hy
+ have : y = Units.ofNearby z y hy := rfl
+ rw [this, Eq.comm]
+ simp only [Ring.inverse_unit, Function.comp_apply]
+ simp [Units.ofNearby, f1, f2, f3, Units.add, _root_.mul_sub]
+ rw [← Ring.inverse_unit]
+ congr
+ simp
+ apply AnalyticAt.congr _ feq
+ apply (analyticAt_id.mul analyticAt_const).comp
+ apply AnalyticAt.comp
+ · simp only [Units.inv_eq_val_inv, Units.inv_mul, sub_self, f2, f3]
+ exact analyticAt_inverse_one_sub 𝕜 A
+ · exact analyticAt_const.sub (analyticAt_const.mul analyticAt_id)
+
+lemma analyticOnNhd_inverse {𝕜 : Type*} [NontriviallyNormedField 𝕜]
+ {A : Type*} [NormedRing A] [NormedAlgebra 𝕜 A] [HasSummableGeomSeries A] :
+ AnalyticOnNhd 𝕜 Ring.inverse {x : A | IsUnit x} :=
+ fun _ hx ↦ analyticAt_inverse (IsUnit.unit hx)
+
+lemma hasFPowerSeriesOnBall_inv_one_sub
+ (𝕜 𝕝 : Type*) [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕝] [NormedAlgebra 𝕜 𝕝] :
+ HasFPowerSeriesOnBall (fun x : 𝕝 ↦ (1 - x)⁻¹) (formalMultilinearSeries_geometric 𝕜 𝕝) 0 1 := by
+ convert hasFPowerSeriesOnBall_inverse_one_sub 𝕜 𝕝
+ exact Ring.inverse_eq_inv'.symm
lemma analyticAt_inv_one_sub (𝕝 : Type*) [NontriviallyNormedField 𝕝] [NormedAlgebra 𝕜 𝕝] :
AnalyticAt 𝕜 (fun x : 𝕝 ↦ (1 - x)⁻¹) 0 :=
@@ -255,34 +830,48 @@ lemma analyticAt_inv_one_sub (𝕝 : Type*) [NontriviallyNormedField 𝕝] [Norm
/-- If `𝕝` is a normed field extension of `𝕜`, then the inverse map `𝕝 → 𝕝` is `𝕜`-analytic
away from 0. -/
lemma analyticAt_inv {z : 𝕝} (hz : z ≠ 0) : AnalyticAt 𝕜 Inv.inv z := by
- let f1 : 𝕝 → 𝕝 := fun a ↦ 1 / z * a
- let f2 : 𝕝 → 𝕝 := fun b ↦ (1 - b)⁻¹
- let f3 : 𝕝 → 𝕝 := fun c ↦ 1 - c / z
- have feq : f1 ∘ f2 ∘ f3 = Inv.inv := by
- ext1 x
- dsimp only [f1, f2, f3, Function.comp_apply]
- field_simp
- have f3val : f3 z = 0 := by simp only [f3, div_self hz, sub_self]
- have f3an : AnalyticAt 𝕜 f3 z := by
- apply analyticAt_const.sub
- simpa only [div_eq_inv_mul] using analyticAt_const.mul (analyticAt_id 𝕜 z)
- exact feq ▸ (analyticAt_const.mul (analyticAt_id _ _)).comp
- ((f3val.symm ▸ analyticAt_inv_one_sub 𝕝).comp f3an)
+ convert analyticAt_inverse (𝕜 := 𝕜) (Units.mk0 _ hz)
+ exact Ring.inverse_eq_inv'.symm
/-- `x⁻¹` is analytic away from zero -/
-lemma analyticOn_inv : AnalyticOn 𝕜 (fun z ↦ z⁻¹) {z : 𝕝 | z ≠ 0} := by
+lemma analyticOnNhd_inv : AnalyticOnNhd 𝕜 (fun z ↦ z⁻¹) {z : 𝕝 | z ≠ 0} := by
intro z m; exact analyticAt_inv m
+lemma analyticOn_inv : AnalyticOn 𝕜 (fun z ↦ z⁻¹) {z : 𝕝 | z ≠ 0} :=
+ analyticOnNhd_inv.analyticOn
+
+/-- `(f x)⁻¹` is analytic away from `f x = 0` -/
+theorem AnalyticWithinAt.inv {f : E → 𝕝} {x : E} {s : Set E}
+ (fa : AnalyticWithinAt 𝕜 f s x) (f0 : f x ≠ 0) :
+ AnalyticWithinAt 𝕜 (fun x ↦ (f x)⁻¹) s x :=
+ (analyticAt_inv f0).comp_analyticWithinAt fa
+
/-- `(f x)⁻¹` is analytic away from `f x = 0` -/
theorem AnalyticAt.inv {f : E → 𝕝} {x : E} (fa : AnalyticAt 𝕜 f x) (f0 : f x ≠ 0) :
AnalyticAt 𝕜 (fun x ↦ (f x)⁻¹) x :=
(analyticAt_inv f0).comp fa
-/-- `x⁻¹` is analytic away from zero -/
-theorem AnalyticOn.inv {f : E → 𝕝} {s : Set E} (fa : AnalyticOn 𝕜 f s) (f0 : ∀ x ∈ s, f x ≠ 0) :
+/-- `(f x)⁻¹` is analytic away from `f x = 0` -/
+theorem AnalyticOn.inv {f : E → 𝕝} {s : Set E}
+ (fa : AnalyticOn 𝕜 f s) (f0 : ∀ x ∈ s, f x ≠ 0) :
AnalyticOn 𝕜 (fun x ↦ (f x)⁻¹) s :=
fun x m ↦ (fa x m).inv (f0 x m)
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.inv := AnalyticOn.inv
+
+/-- `(f x)⁻¹` is analytic away from `f x = 0` -/
+theorem AnalyticOnNhd.inv {f : E → 𝕝} {s : Set E}
+ (fa : AnalyticOnNhd 𝕜 f s) (f0 : ∀ x ∈ s, f x ≠ 0) :
+ AnalyticOnNhd 𝕜 (fun x ↦ (f x)⁻¹) s :=
+ fun x m ↦ (fa x m).inv (f0 x m)
+
+/-- `f x / g x` is analytic away from `g x = 0` -/
+theorem AnalyticWithinAt.div {f g : E → 𝕝} {s : Set E} {x : E}
+ (fa : AnalyticWithinAt 𝕜 f s x) (ga : AnalyticWithinAt 𝕜 g s x) (g0 : g x ≠ 0) :
+ AnalyticWithinAt 𝕜 (fun x ↦ f x / g x) s x := by
+ simp_rw [div_eq_mul_inv]; exact fa.mul (ga.inv g0)
+
/-- `f x / g x` is analytic away from `g x = 0` -/
theorem AnalyticAt.div {f g : E → 𝕝} {x : E}
(fa : AnalyticAt 𝕜 f x) (ga : AnalyticAt 𝕜 g x) (g0 : g x ≠ 0) :
@@ -295,40 +884,81 @@ theorem AnalyticOn.div {f g : E → 𝕝} {s : Set E}
AnalyticOn 𝕜 (fun x ↦ f x / g x) s := fun x m ↦
(fa x m).div (ga x m) (g0 x m)
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.div := AnalyticOn.div
+
+/-- `f x / g x` is analytic away from `g x = 0` -/
+theorem AnalyticOnNhd.div {f g : E → 𝕝} {s : Set E}
+ (fa : AnalyticOnNhd 𝕜 f s) (ga : AnalyticOnNhd 𝕜 g s) (g0 : ∀ x ∈ s, g x ≠ 0) :
+ AnalyticOnNhd 𝕜 (fun x ↦ f x / g x) s := fun x m ↦
+ (fa x m).div (ga x m) (g0 x m)
+
/-!
### Finite sums and products of analytic functions
-/
/-- Finite sums of analytic functions are analytic -/
-theorem Finset.analyticAt_sum {f : α → E → F} {c : E}
- (N : Finset α) (h : ∀ n ∈ N, AnalyticAt 𝕜 (f n) c) :
- AnalyticAt 𝕜 (fun z ↦ ∑ n ∈ N, f n z) c := by
+theorem Finset.analyticWithinAt_sum {f : α → E → F} {c : E} {s : Set E}
+ (N : Finset α) (h : ∀ n ∈ N, AnalyticWithinAt 𝕜 (f n) s c) :
+ AnalyticWithinAt 𝕜 (fun z ↦ ∑ n ∈ N, f n z) s c := by
induction' N using Finset.induction with a B aB hB
· simp only [Finset.sum_empty]
- exact analyticAt_const
+ exact analyticWithinAt_const
· simp_rw [Finset.sum_insert aB]
simp only [Finset.mem_insert] at h
exact (h a (Or.inl rfl)).add (hB fun b m ↦ h b (Or.inr m))
+/-- Finite sums of analytic functions are analytic -/
+theorem Finset.analyticAt_sum {f : α → E → F} {c : E}
+ (N : Finset α) (h : ∀ n ∈ N, AnalyticAt 𝕜 (f n) c) :
+ AnalyticAt 𝕜 (fun z ↦ ∑ n ∈ N, f n z) c := by
+ simp_rw [← analyticWithinAt_univ] at h ⊢
+ exact N.analyticWithinAt_sum h
+
/-- Finite sums of analytic functions are analytic -/
theorem Finset.analyticOn_sum {f : α → E → F} {s : Set E}
(N : Finset α) (h : ∀ n ∈ N, AnalyticOn 𝕜 (f n) s) :
AnalyticOn 𝕜 (fun z ↦ ∑ n ∈ N, f n z) s :=
+ fun z zs ↦ N.analyticWithinAt_sum (fun n m ↦ h n m z zs)
+
+@[deprecated (since := "2024-09-26")]
+alias Finset.analyticWithinOn_sum := Finset.analyticOn_sum
+
+/-- Finite sums of analytic functions are analytic -/
+theorem Finset.analyticOnNhd_sum {f : α → E → F} {s : Set E}
+ (N : Finset α) (h : ∀ n ∈ N, AnalyticOnNhd 𝕜 (f n) s) :
+ AnalyticOnNhd 𝕜 (fun z ↦ ∑ n ∈ N, f n z) s :=
fun z zs ↦ N.analyticAt_sum (fun n m ↦ h n m z zs)
/-- Finite products of analytic functions are analytic -/
-theorem Finset.analyticAt_prod {A : Type*} [NormedCommRing A] [NormedAlgebra 𝕜 A]
- {f : α → E → A} {c : E} (N : Finset α) (h : ∀ n ∈ N, AnalyticAt 𝕜 (f n) c) :
- AnalyticAt 𝕜 (fun z ↦ ∏ n ∈ N, f n z) c := by
+theorem Finset.analyticWithinAt_prod {A : Type*} [NormedCommRing A] [NormedAlgebra 𝕜 A]
+ {f : α → E → A} {c : E} {s : Set E} (N : Finset α) (h : ∀ n ∈ N, AnalyticWithinAt 𝕜 (f n) s c) :
+ AnalyticWithinAt 𝕜 (fun z ↦ ∏ n ∈ N, f n z) s c := by
induction' N using Finset.induction with a B aB hB
· simp only [Finset.prod_empty]
- exact analyticAt_const
+ exact analyticWithinAt_const
· simp_rw [Finset.prod_insert aB]
simp only [Finset.mem_insert] at h
exact (h a (Or.inl rfl)).mul (hB fun b m ↦ h b (Or.inr m))
+/-- Finite products of analytic functions are analytic -/
+theorem Finset.analyticAt_prod {A : Type*} [NormedCommRing A] [NormedAlgebra 𝕜 A]
+ {f : α → E → A} {c : E} (N : Finset α) (h : ∀ n ∈ N, AnalyticAt 𝕜 (f n) c) :
+ AnalyticAt 𝕜 (fun z ↦ ∏ n ∈ N, f n z) c := by
+ simp_rw [← analyticWithinAt_univ] at h ⊢
+ exact N.analyticWithinAt_prod h
+
/-- Finite products of analytic functions are analytic -/
theorem Finset.analyticOn_prod {A : Type*} [NormedCommRing A] [NormedAlgebra 𝕜 A]
{f : α → E → A} {s : Set E} (N : Finset α) (h : ∀ n ∈ N, AnalyticOn 𝕜 (f n) s) :
AnalyticOn 𝕜 (fun z ↦ ∏ n ∈ N, f n z) s :=
+ fun z zs ↦ N.analyticWithinAt_prod (fun n m ↦ h n m z zs)
+
+@[deprecated (since := "2024-09-26")]
+alias Finset.analyticWithinOn_prod := Finset.analyticOn_prod
+
+/-- Finite products of analytic functions are analytic -/
+theorem Finset.analyticOnNhd_prod {A : Type*} [NormedCommRing A] [NormedAlgebra 𝕜 A]
+ {f : α → E → A} {s : Set E} (N : Finset α) (h : ∀ n ∈ N, AnalyticOnNhd 𝕜 (f n) s) :
+ AnalyticOnNhd 𝕜 (fun z ↦ ∏ n ∈ N, f n z) s :=
fun z zs ↦ N.analyticAt_prod (fun n m ↦ h n m z zs)
diff --git a/Mathlib/Analysis/Analytic/Inverse.lean b/Mathlib/Analysis/Analytic/Inverse.lean
index ccd47d8263a54..4b94111adff37 100644
--- a/Mathlib/Analysis/Analytic/Inverse.lean
+++ b/Mathlib/Analysis/Analytic/Inverse.lean
@@ -4,36 +4,44 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel
-/
import Mathlib.Analysis.Analytic.Composition
+import Mathlib.Analysis.Analytic.Linear
+import Mathlib.Tactic.Positivity.Finset
/-!
# Inverse of analytic functions
We construct the left and right inverse of a formal multilinear series with invertible linear term,
-we prove that they coincide and study their properties (notably convergence).
+we prove that they coincide and study their properties (notably convergence). We deduce that the
+inverse of an analytic partial homeomorphism is analytic.
## Main statements
-* `p.leftInv i`: the formal left inverse of the formal multilinear series `p`,
- for `i : E ≃L[𝕜] F` which coincides with `p₁`.
-* `p.rightInv i`: the formal right inverse of the formal multilinear series `p`,
- for `i : E ≃L[𝕜] F` which coincides with `p₁`.
-* `p.leftInv_comp` says that `p.leftInv i` is indeed a left inverse to `p` when `p₁ = i`.
-* `p.rightInv_comp` says that `p.rightInv i` is indeed a right inverse to `p` when `p₁ = i`.
+* `p.leftInv i x`: the formal left inverse of the formal multilinear series `p`, with constant
+ coefficient `x`, for `i : E ≃L[𝕜] F` which coincides with `p₁`.
+* `p.rightInv i x`: the formal right inverse of the formal multilinear series `p`, with constant
+ coefficient `x`, for `i : E ≃L[𝕜] F` which coincides with `p₁`.
+* `p.leftInv_comp` says that `p.leftInv i x` is indeed a left inverse to `p` when `p₁ = i`.
+* `p.rightInv_comp` says that `p.rightInv i x` is indeed a right inverse to `p` when `p₁ = i`.
* `p.leftInv_eq_rightInv`: the two inverses coincide.
* `p.radius_rightInv_pos_of_radius_pos`: if a power series has a positive radius of convergence,
then so does its inverse.
+* `PartialHomeomorph.hasFPowerSeriesAt_symm` shows that, if a partial homeomorph has a power series
+ `p` at a point, with invertible linear part, then the inverse also has a power series at the
+ image point, given by `p.leftInv`.
-/
-open scoped Topology
+open scoped Topology ENNReal
open Finset Filter
-namespace FormalMultilinearSeries
+variable {𝕜 : Type*} [NontriviallyNormedField 𝕜]
+ {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E]
+ {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
+ {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G]
-variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E]
- [NormedSpace 𝕜 E] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
+namespace FormalMultilinearSeries
/-! ### The left inverse of a formal multilinear series -/
@@ -51,27 +59,27 @@ term compensates the rest of the sum, using `i⁻¹` as an inverse to `p₁`.
These formulas only make sense when the constant term `p₀` vanishes. The definition we give is
general, but it ignores the value of `p₀`.
-/
-noncomputable def leftInv (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) :
+noncomputable def leftInv (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E) :
FormalMultilinearSeries 𝕜 F E
- | 0 => 0
+ | 0 => ContinuousMultilinearMap.uncurry0 𝕜 _ x
| 1 => (continuousMultilinearCurryFin1 𝕜 F E).symm i.symm
| n + 2 =>
-∑ c : { c : Composition (n + 2) // c.length < n + 2 },
- (leftInv p i (c : Composition (n + 2)).length).compAlongComposition
+ (leftInv p i x (c : Composition (n + 2)).length).compAlongComposition
(p.compContinuousLinearMap i.symm) c
@[simp]
-theorem leftInv_coeff_zero (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) :
- p.leftInv i 0 = 0 := by rw [leftInv]
+theorem leftInv_coeff_zero (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E) :
+ p.leftInv i x 0 = ContinuousMultilinearMap.uncurry0 𝕜 _ x := by rw [leftInv]
@[simp]
-theorem leftInv_coeff_one (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) :
- p.leftInv i 1 = (continuousMultilinearCurryFin1 𝕜 F E).symm i.symm := by rw [leftInv]
+theorem leftInv_coeff_one (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E) :
+ p.leftInv i x 1 = (continuousMultilinearCurryFin1 𝕜 F E).symm i.symm := by rw [leftInv]
/-- The left inverse does not depend on the zeroth coefficient of a formal multilinear
series. -/
-theorem leftInv_removeZero (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) :
- p.removeZero.leftInv i = p.leftInv i := by
+theorem leftInv_removeZero (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E) :
+ p.removeZero.leftInv i x = p.leftInv i x := by
ext1 n
induction' n using Nat.strongRec' with n IH
match n with
@@ -87,14 +95,15 @@ theorem leftInv_removeZero (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[
/-- The left inverse to a formal multilinear series is indeed a left inverse, provided its linear
term is invertible. -/
-theorem leftInv_comp (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F)
- (h : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i) : (leftInv p i).comp p = id 𝕜 E := by
- ext (n v)
+theorem leftInv_comp (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E)
+ (h : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i) :
+ (leftInv p i x).comp p = id 𝕜 E x := by
+ ext n v
classical
match n with
| 0 =>
- simp only [leftInv_coeff_zero, ContinuousMultilinearMap.zero_apply, id_apply_ne_one, Ne,
- not_false_iff, zero_ne_one, comp_coeff_zero']
+ simp only [comp_coeff_zero', leftInv_coeff_zero, ContinuousMultilinearMap.uncurry0_apply,
+ id_apply_zero]
| 1 =>
simp only [leftInv_coeff_one, comp_coeff_one, h, id_apply_one, ContinuousLinearEquiv.coe_apply,
ContinuousLinearEquiv.symm_apply_apply, continuousMultilinearCurryFin1_symm_apply]
@@ -111,16 +120,16 @@ theorem leftInv_comp (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F)
{Composition.ones (n + 2)} := by
simp [Set.mem_toFinset (s := {c | Composition.length c < n + 2})]
have C :
- ((p.leftInv i (Composition.ones (n + 2)).length)
+ ((p.leftInv i x (Composition.ones (n + 2)).length)
fun j : Fin (Composition.ones n.succ.succ).length =>
p 1 fun _ => v ((Fin.castLE (Composition.length_le _)) j)) =
- p.leftInv i (n + 2) fun j : Fin (n + 2) => p 1 fun _ => v j := by
+ p.leftInv i x (n + 2) fun j : Fin (n + 2) => p 1 fun _ => v j := by
apply FormalMultilinearSeries.congr _ (Composition.ones_length _) fun j hj1 hj2 => ?_
exact FormalMultilinearSeries.congr _ rfl fun k _ _ => by congr
have D :
- (p.leftInv i (n + 2) fun j : Fin (n + 2) => p 1 fun _ => v j) =
+ (p.leftInv i x (n + 2) fun j : Fin (n + 2) => p 1 fun _ => v j) =
-∑ c ∈ {c : Composition (n + 2) | c.length < n + 2}.toFinset,
- (p.leftInv i c.length) (p.applyComposition c v) := by
+ (p.leftInv i x c.length) (p.applyComposition c v) := by
simp only [leftInv, ContinuousMultilinearMap.neg_apply, neg_inj,
ContinuousMultilinearMap.sum_apply]
convert
@@ -128,7 +137,7 @@ theorem leftInv_comp (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F)
(fun c : Composition (n + 2) => c.length < n + 2)
(fun c : Composition (n + 2) =>
(ContinuousMultilinearMap.compAlongComposition
- (p.compContinuousLinearMap (i.symm : F →L[𝕜] E)) c (p.leftInv i c.length))
+ (p.compContinuousLinearMap (i.symm : F →L[𝕜] E)) c (p.leftInv i x c.length))
fun j : Fin (n + 2) => p 1 fun _ : Fin 1 => v j)).symm.trans
_
simp only [compContinuousLinearMap_applyComposition,
@@ -157,26 +166,26 @@ term compensates the rest of the sum, using `i⁻¹` as an inverse to `p₁`.
These formulas only make sense when the constant term `p₀` vanishes. The definition we give is
general, but it ignores the value of `p₀`.
-/
-noncomputable def rightInv (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) :
+noncomputable def rightInv (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E) :
FormalMultilinearSeries 𝕜 F E
- | 0 => 0
+ | 0 => ContinuousMultilinearMap.uncurry0 𝕜 _ x
| 1 => (continuousMultilinearCurryFin1 𝕜 F E).symm i.symm
| n + 2 =>
- let q : FormalMultilinearSeries 𝕜 F E := fun k => if k < n + 2 then rightInv p i k else 0;
+ let q : FormalMultilinearSeries 𝕜 F E := fun k => if k < n + 2 then rightInv p i x k else 0;
-(i.symm : F →L[𝕜] E).compContinuousMultilinearMap ((p.comp q) (n + 2))
@[simp]
-theorem rightInv_coeff_zero (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) :
- p.rightInv i 0 = 0 := by rw [rightInv]
+theorem rightInv_coeff_zero (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E) :
+ p.rightInv i x 0 = ContinuousMultilinearMap.uncurry0 𝕜 _ x := by rw [rightInv]
@[simp]
-theorem rightInv_coeff_one (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) :
- p.rightInv i 1 = (continuousMultilinearCurryFin1 𝕜 F E).symm i.symm := by rw [rightInv]
+theorem rightInv_coeff_one (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E) :
+ p.rightInv i x 1 = (continuousMultilinearCurryFin1 𝕜 F E).symm i.symm := by rw [rightInv]
/-- The right inverse does not depend on the zeroth coefficient of a formal multilinear
series. -/
-theorem rightInv_removeZero (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) :
- p.removeZero.rightInv i = p.rightInv i := by
+theorem rightInv_removeZero (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E) :
+ p.removeZero.rightInv i x = p.rightInv i x := by
ext1 n
induction' n using Nat.strongRec' with n IH
match n with
@@ -216,12 +225,12 @@ theorem comp_rightInv_aux1 {n : ℕ} (hn : 0 < n) (p : FormalMultilinearSeries
simp [FormalMultilinearSeries.comp, A, Finset.sum_union B, C, -Set.toFinset_setOf,
-add_right_inj, -Composition.single_length]
-theorem comp_rightInv_aux2 (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (n : ℕ)
+theorem comp_rightInv_aux2 (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E) (n : ℕ)
(v : Fin (n + 2) → F) :
∑ c ∈ {c : Composition (n + 2) | 1 < c.length}.toFinset,
- p c.length (applyComposition (fun k : ℕ => ite (k < n + 2) (p.rightInv i k) 0) c v) =
+ p c.length (applyComposition (fun k : ℕ => ite (k < n + 2) (p.rightInv i x k) 0) c v) =
∑ c ∈ {c : Composition (n + 2) | 1 < c.length}.toFinset,
- p c.length ((p.rightInv i).applyComposition c v) := by
+ p c.length ((p.rightInv i x).applyComposition c v) := by
have N : 0 < n + 2 := by norm_num
refine sum_congr rfl fun c hc => p.congr rfl fun j hj1 hj2 => ?_
have : ∀ k, c.blocksFun k < n + 2 := by
@@ -232,14 +241,16 @@ theorem comp_rightInv_aux2 (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[
/-- The right inverse to a formal multilinear series is indeed a right inverse, provided its linear
term is invertible and its constant term vanishes. -/
-theorem comp_rightInv (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F)
- (h : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i) (h0 : p 0 = 0) :
- p.comp (rightInv p i) = id 𝕜 F := by
+theorem comp_rightInv (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E)
+ (h : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i) :
+ p.comp (rightInv p i x) = id 𝕜 F (p 0 0) := by
ext (n v)
match n with
| 0 =>
- simp only [h0, ContinuousMultilinearMap.zero_apply, id_apply_ne_one, Ne, not_false_iff,
- zero_ne_one, comp_coeff_zero']
+ simp only [comp_coeff_zero', Matrix.zero_empty, id_apply_zero]
+ congr
+ ext i
+ exact i.elim0
| 1 =>
simp only [comp_coeff_one, h, rightInv_coeff_one, ContinuousLinearEquiv.apply_symm_apply,
id_apply_one, ContinuousLinearEquiv.coe_apply, continuousMultilinearCurryFin1_symm_apply]
@@ -248,11 +259,12 @@ theorem comp_rightInv (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F
simp [comp_rightInv_aux1 N, h, rightInv, lt_irrefl n, show n + 2 ≠ 1 by omega,
← sub_eq_add_neg, sub_eq_zero, comp_rightInv_aux2, -Set.toFinset_setOf]
-theorem rightInv_coeff (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (n : ℕ) (hn : 2 ≤ n) :
- p.rightInv i n =
+theorem rightInv_coeff (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E)
+ (n : ℕ) (hn : 2 ≤ n) :
+ p.rightInv i x n =
-(i.symm : F →L[𝕜] E).compContinuousMultilinearMap
(∑ c ∈ ({c | 1 < Composition.length c}.toFinset : Finset (Composition n)),
- p.compAlongComposition (p.rightInv i) c) := by
+ p.compAlongComposition (p.rightInv i x) c) := by
match n with
| 0 => exact False.elim (zero_lt_two.not_le hn)
| 1 => exact False.elim (one_lt_two.not_le hn)
@@ -261,32 +273,21 @@ 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 -/
-private theorem leftInv_eq_rightInv_aux (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F)
- (h : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i) (h0 : p 0 = 0) :
- leftInv p i = rightInv p i :=
- calc
- leftInv p i = (leftInv p i).comp (id 𝕜 F) := by simp
- _ = (leftInv p i).comp (p.comp (rightInv p i)) := by rw [comp_rightInv p i h h0]
- _ = ((leftInv p i).comp p).comp (rightInv p i) := by rw [comp_assoc]
- _ = (id 𝕜 E).comp (rightInv p i) := by rw [leftInv_comp p i h]
- _ = rightInv p i := by simp
-
-/-- The left inverse and the right inverse of a formal multilinear series coincide. This is not at
-all obvious from their definition, but it follows from uniqueness of inverses (which comes from the
-fact that composition is associative on formal multilinear series). -/
-theorem leftInv_eq_rightInv (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F)
- (h : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i) : leftInv p i = rightInv p i :=
+theorem leftInv_eq_rightInv (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) (x : E)
+ (h : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i) :
+ leftInv p i x = rightInv p i x :=
calc
- leftInv p i = leftInv p.removeZero i := by rw [leftInv_removeZero]
- _ = rightInv p.removeZero i := by
- apply leftInv_eq_rightInv_aux _ _ (by simpa using h) (by simp)
- _ = rightInv p i := by rw [rightInv_removeZero]
+ leftInv p i x = (leftInv p i x).comp (id 𝕜 F (p 0 0)) := by simp
+ _ = (leftInv p i x).comp (p.comp (rightInv p i x)) := by rw [comp_rightInv p i _ h]
+ _ = ((leftInv p i x).comp p).comp (rightInv p i x) := by rw [comp_assoc]
+ _ = (id 𝕜 E x).comp (rightInv p i x) := by rw [leftInv_comp p i _ h]
+ _ = rightInv p i x := by simp [id_comp' _ _ 0]
/-!
### Convergence of the inverse of a power series
@@ -423,17 +424,17 @@ theorem radius_right_inv_pos_of_radius_pos_aux1 (n : ℕ) (p : ℕ → ℝ) (hp
expression for `∑_{k ‖p.rightInv i k‖)
+ radius_right_inv_pos_of_radius_pos_aux1 n (fun k => ‖p.rightInv i x k‖)
(fun k => norm_nonneg _) hr ha
/-- If a a formal multilinear series has a positive radius of convergence, then its right inverse
also has a positive radius of convergence. -/
-theorem radius_rightInv_pos_of_radius_pos (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F)
- (hp : 0 < p.radius) : 0 < (p.rightInv i).radius := by
+theorem radius_rightInv_pos_of_radius_pos
+ {p : FormalMultilinearSeries 𝕜 E F} {i : E ≃L[𝕜] F} {x : E}
+ (hp : 0 < p.radius) : 0 < (p.rightInv i x).radius := by
obtain ⟨C, r, Cpos, rpos, ple⟩ :
∃ (C r : _) (_ : 0 < C) (_ : 0 < r), ∀ n : ℕ, ‖p n‖ ≤ C * r ^ n :=
le_mul_pow_of_radius_pos p hp
@@ -508,7 +506,7 @@ theorem radius_rightInv_pos_of_radius_pos (p : FormalMultilinearSeries 𝕜 E F)
exact ⟨a, ha.1, ha.2.1.le, ha.2.2.le⟩
-- check by induction that the partial sums are suitably bounded, using the choice of `a` and the
-- inductive control from Lemma `radius_rightInv_pos_of_radius_pos_aux2`.
- let S n := ∑ k ∈ Ico 1 n, a ^ k * ‖p.rightInv i k‖
+ let S n := ∑ k ∈ Ico 1 n, a ^ k * ‖p.rightInv i x k‖
have IRec : ∀ n, 1 ≤ n → S n ≤ (I + 1) * a := by
apply Nat.le_induction
· simp only [S]
@@ -536,21 +534,159 @@ theorem radius_rightInv_pos_of_radius_pos (p : FormalMultilinearSeries 𝕜 E F)
_ ≤ (I + 1) * a := by gcongr
-- conclude that all coefficients satisfy `aⁿ Qₙ ≤ (I + 1) a`.
let a' : NNReal := ⟨a, apos.le⟩
- suffices H : (a' : ENNReal) ≤ (p.rightInv i).radius by
+ suffices H : (a' : ENNReal) ≤ (p.rightInv i x).radius by
apply lt_of_lt_of_le _ H
-- Prior to leanprover/lean4#2734, this was `exact_mod_cast apos`.
simpa only [ENNReal.coe_pos]
- apply le_radius_of_bound _ ((I + 1) * a) fun n => ?_
- by_cases hn : n = 0
- · have : ‖p.rightInv i n‖ = ‖p.rightInv i 0‖ := by congr <;> try rw [hn]
- simp only [this, norm_zero, zero_mul, rightInv_coeff_zero]
- positivity
- · have one_le_n : 1 ≤ n := bot_lt_iff_ne_bot.2 hn
- calc
- ‖p.rightInv i n‖ * (a' : ℝ) ^ n = a ^ n * ‖p.rightInv i n‖ := mul_comm _ _
- _ ≤ ∑ k ∈ Ico 1 (n + 1), a ^ k * ‖p.rightInv i k‖ :=
- (haveI : ∀ k ∈ Ico 1 (n + 1), 0 ≤ a ^ k * ‖p.rightInv i k‖ := fun k _ => by positivity
- single_le_sum this (by simp [one_le_n]))
- _ ≤ (I + 1) * a := IRec (n + 1) (by norm_num)
+ apply le_radius_of_eventually_le _ ((I + 1) * a)
+ filter_upwards [Ici_mem_atTop 1] with n (hn : 1 ≤ n)
+ calc
+ ‖p.rightInv i x n‖ * (a' : ℝ) ^ n = a ^ n * ‖p.rightInv i x n‖ := mul_comm _ _
+ _ ≤ ∑ k ∈ Ico 1 (n + 1), a ^ k * ‖p.rightInv i x k‖ :=
+ (haveI : ∀ k ∈ Ico 1 (n + 1), 0 ≤ a ^ k * ‖p.rightInv i x k‖ := fun k _ => by positivity
+ single_le_sum this (by simp [hn]))
+ _ ≤ (I + 1) * a := IRec (n + 1) (by norm_num)
+
+/-- If a a formal multilinear series has a positive radius of convergence, then its left inverse
+also has a positive radius of convergence. -/
+theorem radius_leftInv_pos_of_radius_pos
+ {p : FormalMultilinearSeries 𝕜 E F} {i : E ≃L[𝕜] F} {x : E}
+ (hp : 0 < p.radius) (h : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i) :
+ 0 < (p.leftInv i x).radius := by
+ rw [leftInv_eq_rightInv _ _ _ h]
+ exact radius_rightInv_pos_of_radius_pos hp
end FormalMultilinearSeries
+
+/-!
+### The inverse of an analytic partial homeomorphism is analytic
+-/
+
+open FormalMultilinearSeries List
+
+lemma HasFPowerSeriesAt.tendsto_partialSum_prod_of_comp
+ {f : E → G} {q : FormalMultilinearSeries 𝕜 F G}
+ {p : FormalMultilinearSeries 𝕜 E F} {x : E}
+ (hf : HasFPowerSeriesAt f (q.comp p) x) (hq : 0 < q.radius) (hp : 0 < p.radius) :
+ ∀ᶠ y in 𝓝 0, Tendsto (fun (a : ℕ × ℕ) ↦ q.partialSum a.1 (p.partialSum a.2 y
+ - p 0 (fun _ ↦ 0))) atTop (𝓝 (f (x + y))) := by
+ rcases hf with ⟨r0, h0⟩
+ rcases q.comp_summable_nnreal p hq hp with ⟨r1, r1_pos : 0 < r1, hr1⟩
+ let r : ℝ≥0∞ := min r0 r1
+ have : EMetric.ball (0 : E) r ∈ 𝓝 0 :=
+ EMetric.ball_mem_nhds 0 (lt_min h0.r_pos (by exact_mod_cast r1_pos))
+ filter_upwards [this] with y hy
+ have hy0 : y ∈ EMetric.ball 0 r0 := EMetric.ball_subset_ball (min_le_left _ _) hy
+ have A : HasSum (fun i : Σ n, Composition n => q.compAlongComposition p i.2 fun _j => y)
+ (f (x + y)) := by
+ have cau : CauchySeq fun s : Finset (Σ n, Composition n) =>
+ ∑ i ∈ s, q.compAlongComposition p i.2 fun _j => y := by
+ apply cauchySeq_finset_of_norm_bounded _ (NNReal.summable_coe.2 hr1) _
+ simp only [coe_nnnorm, NNReal.coe_mul, NNReal.coe_pow]
+ rintro ⟨n, c⟩
+ calc
+ ‖(compAlongComposition q p c) fun _j : Fin n => y‖ ≤
+ ‖compAlongComposition q p c‖ * ∏ _j : Fin n, ‖y‖ := by
+ apply ContinuousMultilinearMap.le_opNorm
+ _ ≤ ‖compAlongComposition q p c‖ * (r1 : ℝ) ^ n := by
+ apply mul_le_mul_of_nonneg_left _ (norm_nonneg _)
+ rw [Finset.prod_const, Finset.card_fin]
+ apply pow_le_pow_left (norm_nonneg _)
+ rw [EMetric.mem_ball, edist_eq_coe_nnnorm] at hy
+ have := le_trans (le_of_lt hy) (min_le_right _ _)
+ rwa [ENNReal.coe_le_coe, ← NNReal.coe_le_coe, coe_nnnorm] at this
+ apply HasSum.of_sigma (fun b ↦ hasSum_fintype _) ?_ cau
+ simpa [FormalMultilinearSeries.comp] using h0.hasSum hy0
+ have B : Tendsto (fun (n : ℕ × ℕ) => ∑ i ∈ compPartialSumTarget 0 n.1 n.2,
+ q.compAlongComposition p i.2 fun _j => y) atTop (𝓝 (f (x + y))) := by
+ apply Tendsto.comp A compPartialSumTarget_tendsto_prod_atTop
+ have C : Tendsto (fun (n : ℕ × ℕ) => q.partialSum n.1 (∑ a ∈ Finset.Ico 1 n.2, p a fun _b ↦ y))
+ atTop (𝓝 (f (x + y))) := by simpa [comp_partialSum] using B
+ apply C.congr'
+ filter_upwards [Ici_mem_atTop (0, 1)]
+ rintro ⟨-, n⟩ ⟨-, (hn : 1 ≤ n)⟩
+ congr
+ rw [partialSum, eq_sub_iff_add_eq', Finset.range_eq_Ico,
+ Finset.sum_eq_sum_Ico_succ_bot hn]
+ congr with i
+ exact i.elim0
+
+lemma HasFPowerSeriesAt.eventually_hasSum_of_comp {f : E → F} {g : F → G}
+ {q : FormalMultilinearSeries 𝕜 F G} {p : FormalMultilinearSeries 𝕜 E F} {x : E}
+ (hgf : HasFPowerSeriesAt (g ∘ f) (q.comp p) x) (hf : HasFPowerSeriesAt f p x)
+ (hq : 0 < q.radius) :
+ ∀ᶠ y in 𝓝 0, HasSum (fun n : ℕ => q n fun _ : Fin n => (f (x + y) - f x)) (g (f (x + y))) := by
+ have : ∀ᶠ y in 𝓝 (0 : E), f (x + y) - f x ∈ EMetric.ball 0 q.radius := by
+ have A : ContinuousAt (fun y ↦ f (x + y) - f x) 0 := by
+ apply ContinuousAt.sub _ continuousAt_const
+ exact hf.continuousAt.comp_of_eq (continuous_add_left x).continuousAt (by simp)
+ have B : EMetric.ball 0 q.radius ∈ 𝓝 (f (x + 0) - f x) := by
+ simpa using EMetric.ball_mem_nhds _ hq
+ exact A.preimage_mem_nhds B
+ filter_upwards [hgf.tendsto_partialSum_prod_of_comp hq (hf.radius_pos),
+ hf.tendsto_partialSum, this] with y hy h'y h''y
+ have L : Tendsto (fun n ↦ q.partialSum n (f (x + y) - f x)) atTop (𝓝 (g (f (x + y)))) := by
+ apply (closed_nhds_basis (g (f (x + y)))).tendsto_right_iff.2
+ rintro u ⟨hu, u_closed⟩
+ 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 _ ↦ 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 _ ↦ 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
+ apply this.tendsto.comp
+ apply Tendsto.sub h'y
+ convert tendsto_const_nhds
+ exact (HasFPowerSeriesAt.coeff_zero hf fun _ ↦ 0).symm
+ apply u_closed.mem_of_tendsto this
+ filter_upwards [Ici_mem_atTop b₀] with b hb using vu (hab _ _ ha hb)
+ have C : CauchySeq (fun (s : Finset ℕ) ↦ ∑ n ∈ s, q n fun _ : Fin n => (f (x + y) - f x)) := by
+ have Z := q.summable_norm_apply (x := f (x + y) - f x) h''y
+ exact cauchySeq_finset_of_norm_bounded _ Z (fun i ↦ le_rfl)
+ exact tendsto_nhds_of_cauchySeq_of_subseq C tendsto_finset_range L
+
+/-- If a partial homeomorphism `f` is defined at `a` and has a power series expansion there with
+invertible linear term, then `f.symm` has a power series expansion at `f a`, given by the inverse
+of the initial power series. -/
+theorem PartialHomeomorph.hasFPowerSeriesAt_symm (f : PartialHomeomorph E F) {a : E}
+ {i : E ≃L[𝕜] F} (h0 : a ∈ f.source) {p : FormalMultilinearSeries 𝕜 E F}
+ (h : HasFPowerSeriesAt f p a) (hp : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i) :
+ HasFPowerSeriesAt f.symm (p.leftInv i a) (f a) := by
+ have A : HasFPowerSeriesAt (f.symm ∘ f) ((p.leftInv i a).comp p) a := by
+ have : HasFPowerSeriesAt (ContinuousLinearMap.id 𝕜 E) ((p.leftInv i a).comp p) a := by
+ rw [leftInv_comp _ _ _ hp]
+ exact (ContinuousLinearMap.id 𝕜 E).hasFPowerSeriesAt a
+ apply this.congr
+ filter_upwards [f.open_source.mem_nhds h0] with x hx using by simp [hx]
+ have B : ∀ᶠ (y : E) in 𝓝 0, HasSum (fun n ↦ (p.leftInv i a n) fun _ ↦ f (a + y) - f a)
+ (f.symm (f (a + y))) := by
+ simpa using A.eventually_hasSum_of_comp h (radius_leftInv_pos_of_radius_pos h.radius_pos hp)
+ have C : ∀ᶠ (y : E) in 𝓝 a, HasSum (fun n ↦ (p.leftInv i a n) fun _ ↦ f y - f a)
+ (f.symm (f y)) := by
+ rw [← sub_eq_zero_of_eq (a := a) rfl] at B
+ have : ContinuousAt (fun x ↦ x - a) a := by fun_prop
+ simpa using this.preimage_mem_nhds B
+ have D : ∀ᶠ (y : E) in 𝓝 (f.symm (f a)),
+ HasSum (fun n ↦ (p.leftInv i a n) fun _ ↦ f y - f a) y := by
+ simp only [h0, PartialHomeomorph.left_inv]
+ filter_upwards [C, f.open_source.mem_nhds h0] with x hx h'x
+ simpa [h'x] using hx
+ have E : ∀ᶠ z in 𝓝 (f a), HasSum (fun n ↦ (p.leftInv i a n) fun _ ↦ f (f.symm z) - f a)
+ (f.symm z) := by
+ have : ContinuousAt f.symm (f a) := f.continuousAt_symm (f.map_source h0)
+ exact this D
+ have F : ∀ᶠ z in 𝓝 (f a), HasSum (fun n ↦ (p.leftInv i a n) fun _ ↦ z - f a) (f.symm z) := by
+ filter_upwards [f.open_target.mem_nhds (f.map_source h0), E] with z hz h'z
+ simpa [hz] using h'z
+ rcases EMetric.mem_nhds_iff.1 F with ⟨r, r_pos, hr⟩
+ refine ⟨min r (p.leftInv i a).radius, min_le_right _ _,
+ lt_min r_pos (radius_leftInv_pos_of_radius_pos h.radius_pos hp), fun {y} hy ↦ ?_⟩
+ have : y + f a ∈ EMetric.ball (f a) r := by
+ simp only [EMetric.mem_ball, edist_eq_coe_nnnorm_sub, sub_zero, lt_min_iff,
+ add_sub_cancel_right] at hy ⊢
+ exact hy.1
+ simpa [add_comm] using hr this
diff --git a/Mathlib/Analysis/Analytic/IsolatedZeros.lean b/Mathlib/Analysis/Analytic/IsolatedZeros.lean
index 5646e3721fa72..18aad9fb34b3e 100644
--- a/Mathlib/Analysis/Analytic/IsolatedZeros.lean
+++ b/Mathlib/Analysis/Analytic/IsolatedZeros.lean
@@ -20,7 +20,7 @@ useful in this setup.
* `AnalyticAt.eventually_eq_zero_or_eventually_ne_zero` is the main statement that if a function is
analytic at `z₀`, then either it is identically zero in a neighborhood of `z₀`, or it does not
vanish in a punctured neighborhood of `z₀`.
-* `AnalyticOn.eqOn_of_preconnected_of_frequently_eq` is the identity theorem for analytic
+* `AnalyticOnNhd.eqOn_of_preconnected_of_frequently_eq` is the identity theorem for analytic
functions: if a function `f` is analytic on a connected set `U` and is zero on a set with an
accumulation point in `U` then `f` is identically `0` on `U`.
-/
@@ -157,7 +157,7 @@ lemma unique_eventuallyEq_zpow_smul_nonzero {m n : ℤ}
rw [frequently_eq_iff_eventually_eq hj_an] at this
· rw [EventuallyEq.eq_of_nhds this, sub_self, zero_zpow _ (sub_ne_zero.mpr hj_ne), zero_smul]
conv => enter [2, z, 1]; rw [← Int.toNat_sub_of_le h_le, zpow_natCast]
- exact (((analyticAt_id _ _).sub analyticAt_const).pow _).smul hg_an
+ exact ((analyticAt_id.sub analyticAt_const).pow _).smul hg_an
/-- For a function `f` on `𝕜`, and `z₀ ∈ 𝕜`, there exists at most one `n` such that on a
neighbourhood of `z₀` we have `f z = (z - z₀) ^ n • g z`, with `g` analytic and nonvanishing at
@@ -221,7 +221,7 @@ lemma order_eq_nat_iff (hf : AnalyticAt 𝕜 f z₀) (n : ℕ) : hf.order = ↑n
end AnalyticAt
-namespace AnalyticOn
+namespace AnalyticOnNhd
variable {U : Set 𝕜}
@@ -229,13 +229,22 @@ variable {U : Set 𝕜}
analytic on a connected set `U` and vanishes in arbitrary neighborhoods of a point `z₀ ∈ U`, then
it is identically zero in `U`.
For higher-dimensional versions requiring that the function vanishes in a neighborhood of `z₀`,
-see `AnalyticOn.eqOn_zero_of_preconnected_of_eventuallyEq_zero`. -/
-theorem eqOn_zero_of_preconnected_of_frequently_eq_zero (hf : AnalyticOn 𝕜 f U)
+see `AnalyticOnNhd.eqOn_zero_of_preconnected_of_eventuallyEq_zero`. -/
+theorem eqOn_zero_of_preconnected_of_frequently_eq_zero (hf : AnalyticOnNhd 𝕜 f U)
(hU : IsPreconnected U) (h₀ : z₀ ∈ U) (hfw : ∃ᶠ z in 𝓝[≠] z₀, f z = 0) : EqOn f 0 U :=
hf.eqOn_zero_of_preconnected_of_eventuallyEq_zero hU h₀
((hf z₀ h₀).frequently_zero_iff_eventually_zero.1 hfw)
-theorem eqOn_zero_of_preconnected_of_mem_closure (hf : AnalyticOn 𝕜 f U) (hU : IsPreconnected U)
+theorem eqOn_zero_or_eventually_ne_zero_of_preconnected (hf : AnalyticOnNhd 𝕜 f U)
+ (hU : IsPreconnected U) : EqOn f 0 U ∨ ∀ᶠ x in codiscreteWithin U, f x ≠ 0 := by
+ simp only [or_iff_not_imp_right, ne_eq, eventually_iff, mem_codiscreteWithin,
+ disjoint_principal_right, not_forall]
+ rintro ⟨x, hx, hx2⟩
+ refine hf.eqOn_zero_of_preconnected_of_frequently_eq_zero hU hx fun nh ↦ hx2 ?_
+ filter_upwards [nh] with a ha
+ simp_all
+
+theorem eqOn_zero_of_preconnected_of_mem_closure (hf : AnalyticOnNhd 𝕜 f U) (hU : IsPreconnected U)
(h₀ : z₀ ∈ U) (hfz₀ : z₀ ∈ closure ({z | f z = 0} \ {z₀})) : EqOn f 0 U :=
hf.eqOn_zero_of_preconnected_of_frequently_eq_zero hU h₀
(mem_closure_ne_iff_frequently_within.mp hfz₀)
@@ -244,15 +253,21 @@ theorem eqOn_zero_of_preconnected_of_mem_closure (hf : AnalyticOn 𝕜 f U) (hU
analytic on a connected set `U` and coincide at points which accumulate to a point `z₀ ∈ U`, then
they coincide globally in `U`.
For higher-dimensional versions requiring that the functions coincide in a neighborhood of `z₀`,
-see `AnalyticOn.eqOn_of_preconnected_of_eventuallyEq`. -/
-theorem eqOn_of_preconnected_of_frequently_eq (hf : AnalyticOn 𝕜 f U) (hg : AnalyticOn 𝕜 g U)
+see `AnalyticOnNhd.eqOn_of_preconnected_of_eventuallyEq`. -/
+theorem eqOn_of_preconnected_of_frequently_eq (hf : AnalyticOnNhd 𝕜 f U) (hg : AnalyticOnNhd 𝕜 g U)
(hU : IsPreconnected U) (h₀ : z₀ ∈ U) (hfg : ∃ᶠ z in 𝓝[≠] z₀, f z = g z) : EqOn f g U := by
have hfg' : ∃ᶠ z in 𝓝[≠] z₀, (f - g) z = 0 :=
hfg.mono fun z h => by rw [Pi.sub_apply, h, sub_self]
simpa [sub_eq_zero] using fun z hz =>
(hf.sub hg).eqOn_zero_of_preconnected_of_frequently_eq_zero hU h₀ hfg' hz
-theorem eqOn_of_preconnected_of_mem_closure (hf : AnalyticOn 𝕜 f U) (hg : AnalyticOn 𝕜 g U)
+theorem eqOn_or_eventually_ne_of_preconnected (hf : AnalyticOnNhd 𝕜 f U) (hg : AnalyticOnNhd 𝕜 g U)
+ (hU : IsPreconnected U) : EqOn f g U ∨ ∀ᶠ x in codiscreteWithin U, f x ≠ g x :=
+ (eqOn_zero_or_eventually_ne_zero_of_preconnected (hf.sub hg) hU).imp
+ (fun h _ hx ↦ eq_of_sub_eq_zero (h hx))
+ (by simp only [Pi.sub_apply, ne_eq, sub_eq_zero, imp_self])
+
+theorem eqOn_of_preconnected_of_mem_closure (hf : AnalyticOnNhd 𝕜 f U) (hg : AnalyticOnNhd 𝕜 g U)
(hU : IsPreconnected U) (h₀ : z₀ ∈ U) (hfg : z₀ ∈ closure ({z | f z = g z} \ {z₀})) :
EqOn f g U :=
hf.eqOn_of_preconnected_of_frequently_eq hg hU h₀ (mem_closure_ne_iff_frequently_within.mp hfg)
@@ -261,10 +276,13 @@ theorem eqOn_of_preconnected_of_mem_closure (hf : AnalyticOn 𝕜 f U) (hg : Ana
field `𝕜` are analytic everywhere and coincide at points which accumulate to a point `z₀`, then
they coincide globally.
For higher-dimensional versions requiring that the functions coincide in a neighborhood of `z₀`,
-see `AnalyticOn.eq_of_eventuallyEq`. -/
-theorem eq_of_frequently_eq [ConnectedSpace 𝕜] (hf : AnalyticOn 𝕜 f univ) (hg : AnalyticOn 𝕜 g univ)
- (hfg : ∃ᶠ z in 𝓝[≠] z₀, f z = g z) : f = g :=
+see `AnalyticOnNhd.eq_of_eventuallyEq`. -/
+theorem eq_of_frequently_eq [ConnectedSpace 𝕜] (hf : AnalyticOnNhd 𝕜 f univ)
+ (hg : AnalyticOnNhd 𝕜 g univ) (hfg : ∃ᶠ z in 𝓝[≠] z₀, f z = g z) : f = g :=
funext fun x =>
eqOn_of_preconnected_of_frequently_eq hf hg isPreconnected_univ (mem_univ z₀) hfg (mem_univ x)
-end AnalyticOn
+@[deprecated (since := "2024-09-26")]
+alias _root_.AnalyticOn.eq_of_frequently_eq := eq_of_frequently_eq
+
+end AnalyticOnNhd
diff --git a/Mathlib/Analysis/Analytic/Linear.lean b/Mathlib/Analysis/Analytic/Linear.lean
index 6bd87d9e23035..bd405daef5895 100644
--- a/Mathlib/Analysis/Analytic/Linear.lean
+++ b/Mathlib/Analysis/Analytic/Linear.lean
@@ -9,7 +9,10 @@ import Mathlib.Analysis.Analytic.Basic
# Linear functions are analytic
In this file we prove that a `ContinuousLinearMap` defines an analytic function with
-the formal power series `f x = f a + f (x - a)`. We also prove similar results for multilinear maps.
+the formal power series `f x = f a + f (x - a)`. We also prove similar results for bilinear maps.
+
+TODO: port to use `CPolynomial`, and prove the stronger result that continuous linear maps are
+continuously polynomial
-/
variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E]
@@ -41,6 +44,18 @@ protected theorem hasFPowerSeriesAt (f : E →L[𝕜] F) (x : E) :
protected theorem analyticAt (f : E →L[𝕜] F) (x : E) : AnalyticAt 𝕜 f x :=
(f.hasFPowerSeriesAt x).analyticAt
+protected theorem analyticOnNhd (f : E →L[𝕜] F) (s : Set E) : AnalyticOnNhd 𝕜 f s :=
+ fun x _ ↦ f.analyticAt x
+
+protected theorem analyticWithinAt (f : E →L[𝕜] F) (s : Set E) (x : E) : AnalyticWithinAt 𝕜 f s x :=
+ (f.analyticAt x).analyticWithinAt
+
+protected theorem analyticOn (f : E →L[𝕜] F) (s : Set E) : AnalyticOn 𝕜 f s :=
+ fun x _ ↦ f.analyticWithinAt _ x
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn := ContinuousLinearMap.analyticOn
+
/-- Reinterpret a bilinear map `f : E →L[𝕜] F →L[𝕜] G` as a multilinear map
`(E × F) [×2]→L[𝕜] G`. This multilinear map is the second term in the formal
multilinear series expansion of `uncurry f`. It is given by
@@ -57,35 +72,31 @@ theorem uncurryBilinear_apply (f : E →L[𝕜] F →L[𝕜] G) (m : Fin 2 → E
/-- Formal multilinear series expansion of a bilinear function `f : E →L[𝕜] F →L[𝕜] G`. -/
def fpowerSeriesBilinear (f : E →L[𝕜] F →L[𝕜] G) (x : E × F) : FormalMultilinearSeries 𝕜 (E × F) G
- | 0 => ContinuousMultilinearMap.curry0 𝕜 _ (f x.1 x.2)
+ | 0 => ContinuousMultilinearMap.uncurry0 𝕜 _ (f x.1 x.2)
| 1 => (continuousMultilinearCurryFin1 𝕜 (E × F) G).symm (f.deriv₂ x)
| 2 => f.uncurryBilinear
| _ => 0
+@[simp]
theorem fpowerSeriesBilinear_apply_zero (f : E →L[𝕜] F →L[𝕜] G) (x : E × F) :
- fpowerSeriesBilinear f x 0 = ContinuousMultilinearMap.curry0 𝕜 _ (f x.1 x.2) :=
+ 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 = ∞ :=
@@ -109,29 +120,110 @@ protected theorem analyticAt_bilinear (f : E →L[𝕜] F →L[𝕜] G) (x : E
AnalyticAt 𝕜 (fun x : E × F => f x.1 x.2) x :=
(f.hasFPowerSeriesAt_bilinear x).analyticAt
+protected theorem analyticWithinAt_bilinear (f : E →L[𝕜] F →L[𝕜] G) (s : Set (E × F)) (x : E × F) :
+ AnalyticWithinAt 𝕜 (fun x : E × F => f x.1 x.2) s x :=
+ (f.analyticAt_bilinear x).analyticWithinAt
+
+protected theorem analyticOnNhd_bilinear (f : E →L[𝕜] F →L[𝕜] G) (s : Set (E × F)) :
+ AnalyticOnNhd 𝕜 (fun x : E × F => f x.1 x.2) s :=
+ fun x _ ↦ f.analyticAt_bilinear x
+
+protected theorem analyticOn_bilinear (f : E →L[𝕜] F →L[𝕜] G) (s : Set (E × F)) :
+ AnalyticOn 𝕜 (fun x : E × F => f x.1 x.2) s :=
+ (f.analyticOnNhd_bilinear s).analyticOn
+
end ContinuousLinearMap
-variable (𝕜)
+variable {s : Set E} {z : E} {t : Set (E × F)} {p : E × F}
-lemma analyticAt_id (z : E) : AnalyticAt 𝕜 (id : E → E) z :=
+lemma analyticAt_id : AnalyticAt 𝕜 (id : E → E) z :=
(ContinuousLinearMap.id 𝕜 E).analyticAt z
+lemma analyticWithinAt_id : AnalyticWithinAt 𝕜 (id : E → E) s z :=
+ analyticAt_id.analyticWithinAt
+
/-- `id` is entire -/
-theorem analyticOn_id {s : Set E} : AnalyticOn 𝕜 (fun x : E ↦ x) s :=
- fun _ _ ↦ analyticAt_id _ _
+theorem analyticOnNhd_id : AnalyticOnNhd 𝕜 (fun x : E ↦ x) s :=
+ fun _ _ ↦ analyticAt_id
+
+theorem analyticOn_id : AnalyticOn 𝕜 (fun x : E ↦ x) s :=
+ fun _ _ ↦ analyticWithinAt_id
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn_id := analyticOn_id
/-- `fst` is analytic -/
-theorem analyticAt_fst {p : E × F} : AnalyticAt 𝕜 (fun p : E × F ↦ p.fst) p :=
+theorem analyticAt_fst : AnalyticAt 𝕜 (fun p : E × F ↦ p.fst) p :=
(ContinuousLinearMap.fst 𝕜 E F).analyticAt p
+theorem analyticWithinAt_fst : AnalyticWithinAt 𝕜 (fun p : E × F ↦ p.fst) t p :=
+ analyticAt_fst.analyticWithinAt
+
/-- `snd` is analytic -/
-theorem analyticAt_snd {p : E × F} : AnalyticAt 𝕜 (fun p : E × F ↦ p.snd) p :=
+theorem analyticAt_snd : AnalyticAt 𝕜 (fun p : E × F ↦ p.snd) p :=
(ContinuousLinearMap.snd 𝕜 E F).analyticAt p
+theorem analyticWithinAt_snd : AnalyticWithinAt 𝕜 (fun p : E × F ↦ p.snd) t p :=
+ analyticAt_snd.analyticWithinAt
+
/-- `fst` is entire -/
-theorem analyticOn_fst {s : Set (E × F)} : AnalyticOn 𝕜 (fun p : E × F ↦ p.fst) s :=
- fun _ _ ↦ analyticAt_fst _
+theorem analyticOnNhd_fst : AnalyticOnNhd 𝕜 (fun p : E × F ↦ p.fst) t :=
+ fun _ _ ↦ analyticAt_fst
+
+theorem analyticOn_fst : AnalyticOn 𝕜 (fun p : E × F ↦ p.fst) t :=
+ fun _ _ ↦ analyticWithinAt_fst
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn_fst := analyticOn_fst
/-- `snd` is entire -/
-theorem analyticOn_snd {s : Set (E × F)} : AnalyticOn 𝕜 (fun p : E × F ↦ p.snd) s :=
- fun _ _ ↦ analyticAt_snd _
+theorem analyticOnNhd_snd : AnalyticOnNhd 𝕜 (fun p : E × F ↦ p.snd) t :=
+ fun _ _ ↦ analyticAt_snd
+
+theorem analyticOn_snd : AnalyticOn 𝕜 (fun p : E × F ↦ p.snd) t :=
+ fun _ _ ↦ analyticWithinAt_snd
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn_snd := analyticOn_snd
+
+namespace ContinuousLinearEquiv
+
+variable (f : E ≃L[𝕜] F) (s : Set E) (x : E)
+
+protected theorem analyticAt : AnalyticAt 𝕜 f x :=
+ ((f : E →L[𝕜] F).hasFPowerSeriesAt x).analyticAt
+
+protected theorem analyticOnNhd : AnalyticOnNhd 𝕜 f s :=
+ fun x _ ↦ f.analyticAt x
+
+protected theorem analyticWithinAt (f : E →L[𝕜] F) (s : Set E) (x : E) : AnalyticWithinAt 𝕜 f s x :=
+ (f.analyticAt x).analyticWithinAt
+
+protected theorem analyticOn (f : E →L[𝕜] F) (s : Set E) : AnalyticOn 𝕜 f s :=
+ fun x _ ↦ f.analyticWithinAt _ x
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn := ContinuousLinearEquiv.analyticOn
+
+end ContinuousLinearEquiv
+
+namespace LinearIsometryEquiv
+
+variable (f : E ≃ₗᵢ[𝕜] F) (s : Set E) (x : E)
+
+protected theorem analyticAt : AnalyticAt 𝕜 f x :=
+ ((f : E →L[𝕜] F).hasFPowerSeriesAt x).analyticAt
+
+protected theorem analyticOnNhd : AnalyticOnNhd 𝕜 f s :=
+ fun x _ ↦ f.analyticAt x
+
+protected theorem analyticWithinAt (f : E →L[𝕜] F) (s : Set E) (x : E) : AnalyticWithinAt 𝕜 f s x :=
+ (f.analyticAt x).analyticWithinAt
+
+protected theorem analyticOn (f : E →L[𝕜] F) (s : Set E) : AnalyticOn 𝕜 f s :=
+ fun x _ ↦ f.analyticWithinAt _ x
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn := LinearIsometryEquiv.analyticOn
+
+end LinearIsometryEquiv
diff --git a/Mathlib/Analysis/Analytic/Meromorphic.lean b/Mathlib/Analysis/Analytic/Meromorphic.lean
index ff3b72d9bc1a5..be73e28bbbfe1 100644
--- a/Mathlib/Analysis/Analytic/Meromorphic.lean
+++ b/Mathlib/Analysis/Analytic/Meromorphic.lean
@@ -35,7 +35,7 @@ lemma AnalyticAt.meromorphicAt {f : 𝕜 → E} {x : 𝕜} (hf : AnalyticAt 𝕜
namespace MeromorphicAt
-lemma id (x : 𝕜) : MeromorphicAt id x := (analyticAt_id 𝕜 x).meromorphicAt
+lemma id (x : 𝕜) : MeromorphicAt id x := analyticAt_id.meromorphicAt
lemma const (e : E) (x : 𝕜) : MeromorphicAt (fun _ ↦ e) x :=
analyticAt_const.meromorphicAt
@@ -50,8 +50,8 @@ lemma add {f g : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f x) (hg : Meromorph
simp_rw [← mul_smul, ← pow_add, Nat.sub_add_cancel (Nat.le_max_left _ _),
Nat.sub_add_cancel (Nat.le_max_right _ _), Pi.add_apply, smul_add]
rw [this]
- exact ((((analyticAt_id 𝕜 x).sub analyticAt_const).pow _).smul hf).add
- ((((analyticAt_id 𝕜 x).sub analyticAt_const).pow _).smul hg)
+ exact (((analyticAt_id.sub analyticAt_const).pow _).smul hf).add
+ (((analyticAt_id.sub analyticAt_const).pow _).smul hg)
lemma smul {f : 𝕜 → 𝕜} {g : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) :
MeromorphicAt (f • g) x := by
@@ -59,8 +59,8 @@ lemma smul {f : 𝕜 → 𝕜} {g : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f
rcases hg with ⟨n, hg⟩
refine ⟨m + n, ?_⟩
convert hf.smul hg using 2 with z
- rw [smul_eq_mul, ← mul_smul, mul_assoc, mul_comm (f z), ← mul_assoc, pow_add,
- ← smul_eq_mul (a' := f z), smul_assoc, Pi.smul_apply']
+ rw [Pi.smul_apply', smul_eq_mul]
+ module
lemma mul {f g : 𝕜 → 𝕜} {x : 𝕜} (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) :
MeromorphicAt (f * g) x :=
@@ -88,7 +88,7 @@ lemma congr {f g : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f x) (hfg : f =ᶠ
MeromorphicAt g x := by
rcases hf with ⟨m, hf⟩
refine ⟨m + 1, ?_⟩
- have : AnalyticAt 𝕜 (fun z ↦ z - x) x := (analyticAt_id 𝕜 x).sub analyticAt_const
+ have : AnalyticAt 𝕜 (fun z ↦ z - x) x := analyticAt_id.sub analyticAt_const
refine (this.smul hf).congr ?_
rw [eventuallyEq_nhdsWithin_iff] at hfg
filter_upwards [hfg] with z hz
@@ -108,7 +108,7 @@ lemma inv {f : 𝕜 → 𝕜} {x : 𝕜} (hf : MeromorphicAt f x) : MeromorphicA
· -- interesting case: use local formula for `f`
obtain ⟨n, g, hg_an, hg_ne, hg_eq⟩ := hf.exists_eventuallyEq_pow_smul_nonzero_iff.mpr h_eq
have : AnalyticAt 𝕜 (fun z ↦ (z - x) ^ (m + 1)) x :=
- ((analyticAt_id 𝕜 x).sub analyticAt_const).pow _
+ (analyticAt_id.sub analyticAt_const).pow _
-- use `m + 1` rather than `m` to damp out any silly issues with the value at `z = x`
refine ⟨n + 1, (this.smul <| hg_an.inv hg_ne).congr ?_⟩
filter_upwards [hg_eq, hg_an.continuousAt.eventually_ne hg_ne] with z hfg hg_ne'
@@ -153,7 +153,7 @@ theorem eventually_analyticAt [CompleteSpace E] {f : 𝕜 → E} {x : 𝕜}
apply Filter.Eventually.of_forall
intro y hy hf
rw [Set.mem_compl_iff, Set.mem_singleton_iff] at hy
- have := (((analyticAt_id 𝕜 y).sub analyticAt_const).pow n).inv
+ have := ((analyticAt_id (𝕜 := 𝕜).sub analyticAt_const).pow n).inv
(pow_ne_zero _ (sub_ne_zero_of_ne hy))
apply (this.smul hf).congr ∘ (eventually_ne_nhds hy).mono
intro z hz
@@ -227,8 +227,8 @@ lemma iff_eventuallyEq_zpow_smul_analyticAt {f : 𝕜 → E} {x : 𝕜} : Meromo
∃ (n : ℤ) (g : 𝕜 → E), AnalyticAt 𝕜 g x ∧ ∀ᶠ z in 𝓝[≠] x, f z = (z - x) ^ n • g z := by
refine ⟨fun ⟨n, hn⟩ ↦ ⟨-n, _, ⟨hn, eventually_nhdsWithin_iff.mpr ?_⟩⟩, ?_⟩
· filter_upwards with z hz
- rw [← mul_smul, ← zpow_natCast, ← zpow_add₀ (sub_ne_zero.mpr hz), neg_add_cancel,
- zpow_zero, one_smul]
+ match_scalars
+ field_simp [sub_ne_zero.mpr hz]
· refine fun ⟨n, g, hg_an, hg_eq⟩ ↦ MeromorphicAt.congr ?_ (EventuallyEq.symm hg_eq)
exact (((MeromorphicAt.id x).sub (.const _ x)).zpow _).smul hg_an.meromorphicAt
@@ -237,10 +237,12 @@ end MeromorphicAt
/-- Meromorphy of a function on a set. -/
def MeromorphicOn (f : 𝕜 → E) (U : Set 𝕜) : Prop := ∀ x ∈ U, MeromorphicAt f x
-lemma AnalyticOn.meromorphicOn {f : 𝕜 → E} {U : Set 𝕜} (hf : AnalyticOn 𝕜 f U) :
+lemma AnalyticOnNhd.meromorphicOn {f : 𝕜 → E} {U : Set 𝕜} (hf : AnalyticOnNhd 𝕜 f U) :
MeromorphicOn f U :=
fun x hx ↦ (hf x hx).meromorphicAt
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.meromorphicOn := AnalyticOnNhd.meromorphicOn
namespace MeromorphicOn
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/Polynomial.lean b/Mathlib/Analysis/Analytic/Polynomial.lean
index e32bceb99f93f..77e62fd5b542b 100644
--- a/Mathlib/Analysis/Analytic/Polynomial.lean
+++ b/Mathlib/Analysis/Analytic/Polynomial.lean
@@ -23,19 +23,30 @@ open Polynomial
variable [NormedRing B] [NormedAlgebra 𝕜 B] [Algebra A B] {f : E → B}
-theorem AnalyticAt.aeval_polynomial (hf : AnalyticAt 𝕜 f z) (p : A[X]) :
- AnalyticAt 𝕜 (fun x ↦ aeval (f x) p) z := by
+theorem AnalyticWithinAt.aeval_polynomial (hf : AnalyticWithinAt 𝕜 f s z) (p : A[X]) :
+ AnalyticWithinAt 𝕜 (fun x ↦ aeval (f x) p) s z := by
refine p.induction_on (fun k ↦ ?_) (fun p q hp hq ↦ ?_) fun p i hp ↦ ?_
- · simp_rw [aeval_C]; apply analyticAt_const
+ · simp_rw [aeval_C]; apply analyticWithinAt_const
· simp_rw [aeval_add]; exact hp.add hq
· convert hp.mul hf
simp_rw [pow_succ, aeval_mul, ← mul_assoc, aeval_X]
+theorem AnalyticAt.aeval_polynomial (hf : AnalyticAt 𝕜 f z) (p : A[X]) :
+ AnalyticAt 𝕜 (fun x ↦ aeval (f x) p) z := by
+ rw [← analyticWithinAt_univ] at hf ⊢
+ exact hf.aeval_polynomial p
+
+theorem AnalyticOnNhd.aeval_polynomial (hf : AnalyticOnNhd 𝕜 f s) (p : A[X]) :
+ AnalyticOnNhd 𝕜 (fun x ↦ aeval (f x) p) s := fun x hx ↦ (hf x hx).aeval_polynomial p
+
theorem AnalyticOn.aeval_polynomial (hf : AnalyticOn 𝕜 f s) (p : A[X]) :
AnalyticOn 𝕜 (fun x ↦ aeval (f x) p) s := fun x hx ↦ (hf x hx).aeval_polynomial p
+theorem AnalyticOnNhd.eval_polynomial {A} [NormedCommRing A] [NormedAlgebra 𝕜 A] (p : A[X]) :
+ AnalyticOnNhd 𝕜 (eval · p) Set.univ := analyticOnNhd_id.aeval_polynomial p
+
theorem AnalyticOn.eval_polynomial {A} [NormedCommRing A] [NormedAlgebra 𝕜 A] (p : A[X]) :
- AnalyticOn 𝕜 (eval · p) Set.univ := (analyticOn_id 𝕜).aeval_polynomial p
+ AnalyticOn 𝕜 (eval · p) Set.univ := analyticOn_id.aeval_polynomial p
end Polynomial
@@ -51,27 +62,47 @@ theorem AnalyticAt.aeval_mvPolynomial (hf : ∀ i, AnalyticAt 𝕜 (f · i) z) (
· simp_rw [map_add]; exact hp.add hq
· simp_rw [map_mul, aeval_X]; exact hp.mul (hf i)
-theorem AnalyticOn.aeval_mvPolynomial (hf : ∀ i, AnalyticOn 𝕜 (f · i) s) (p : MvPolynomial σ A) :
- AnalyticOn 𝕜 (fun x ↦ aeval (f x) p) s := fun x hx ↦ .aeval_mvPolynomial (hf · x hx) p
+theorem AnalyticOnNhd.aeval_mvPolynomial
+ (hf : ∀ i, AnalyticOnNhd 𝕜 (f · i) s) (p : MvPolynomial σ A) :
+ AnalyticOnNhd 𝕜 (fun x ↦ aeval (f x) p) s := fun x hx ↦ .aeval_mvPolynomial (hf · x hx) p
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.aeval_mvPolynomial := AnalyticOnNhd.aeval_mvPolynomial
-theorem AnalyticOn.eval_continuousLinearMap (f : E →L[𝕜] σ → B) (p : MvPolynomial σ B) :
- AnalyticOn 𝕜 (fun x ↦ eval (f x) p) Set.univ :=
+theorem AnalyticOnNhd.eval_continuousLinearMap (f : E →L[𝕜] σ → B) (p : MvPolynomial σ B) :
+ AnalyticOnNhd 𝕜 (fun x ↦ eval (f x) p) Set.univ :=
fun x _ ↦ .aeval_mvPolynomial (fun i ↦ ((ContinuousLinearMap.proj i).comp f).analyticAt x) p
-theorem AnalyticOn.eval_continuousLinearMap' (f : σ → E →L[𝕜] B) (p : MvPolynomial σ B) :
- AnalyticOn 𝕜 (fun x ↦ eval (f · x) p) Set.univ :=
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.eval_continuousLinearMap := AnalyticOnNhd.eval_continuousLinearMap
+
+theorem AnalyticOnNhd.eval_continuousLinearMap' (f : σ → E →L[𝕜] B) (p : MvPolynomial σ B) :
+ AnalyticOnNhd 𝕜 (fun x ↦ eval (f · x) p) Set.univ :=
fun x _ ↦ .aeval_mvPolynomial (fun i ↦ (f i).analyticAt x) p
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.eval_continuousLinearMap' := AnalyticOnNhd.eval_continuousLinearMap'
+
variable [CompleteSpace 𝕜] [T2Space E] [FiniteDimensional 𝕜 E]
-theorem AnalyticOn.eval_linearMap (f : E →ₗ[𝕜] σ → B) (p : MvPolynomial σ B) :
- AnalyticOn 𝕜 (fun x ↦ eval (f x) p) Set.univ :=
- AnalyticOn.eval_continuousLinearMap { f with cont := f.continuous_of_finiteDimensional } p
+theorem AnalyticOnNhd.eval_linearMap (f : E →ₗ[𝕜] σ → B) (p : MvPolynomial σ B) :
+ AnalyticOnNhd 𝕜 (fun x ↦ eval (f x) p) Set.univ :=
+ AnalyticOnNhd.eval_continuousLinearMap { f with cont := f.continuous_of_finiteDimensional } p
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.eval_linearMap := AnalyticOnNhd.eval_linearMap
+
+theorem AnalyticOnNhd.eval_linearMap' (f : σ → E →ₗ[𝕜] B) (p : MvPolynomial σ B) :
+ AnalyticOnNhd 𝕜 (fun x ↦ eval (f · x) p) Set.univ := AnalyticOnNhd.eval_linearMap (.pi f) p
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.eval_linearMap' := AnalyticOnNhd.eval_linearMap'
-theorem AnalyticOn.eval_linearMap' (f : σ → E →ₗ[𝕜] B) (p : MvPolynomial σ B) :
- AnalyticOn 𝕜 (fun x ↦ eval (f · x) p) Set.univ := AnalyticOn.eval_linearMap (.pi f) p
+theorem AnalyticOnNhd.eval_mvPolynomial [Fintype σ] (p : MvPolynomial σ 𝕜) :
+ AnalyticOnNhd 𝕜 (eval · p) Set.univ :=
+ AnalyticOnNhd.eval_linearMap (.id (R := 𝕜) (M := σ → 𝕜)) p
-theorem AnalyticOn.eval_mvPolynomial [Fintype σ] (p : MvPolynomial σ 𝕜) :
- AnalyticOn 𝕜 (eval · p) Set.univ := AnalyticOn.eval_linearMap (.id (R := 𝕜) (M := σ → 𝕜)) p
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.eval_mvPolynomial := AnalyticOnNhd.eval_mvPolynomial
end MvPolynomial
diff --git a/Mathlib/Analysis/Analytic/RadiusLiminf.lean b/Mathlib/Analysis/Analytic/RadiusLiminf.lean
index 175d6acca7461..6aefcab0e900e 100644
--- a/Mathlib/Analysis/Analytic/RadiusLiminf.lean
+++ b/Mathlib/Analysis/Analytic/RadiusLiminf.lean
@@ -53,7 +53,7 @@ theorem radius_eq_liminf :
refine
H.mp ((eventually_gt_atTop 0).mono fun n hn₀ hn => (this _ hn₀).2 (NNReal.coe_le_coe.1 ?_))
push_cast
- exact (le_abs_self _).trans (hn.trans (pow_le_one _ ha.1.le ha.2.le))
+ exact (le_abs_self _).trans (hn.trans (pow_le_one₀ ha.1.le ha.2.le))
· refine p.le_radius_of_isBigO (IsBigO.of_bound 1 ?_)
refine (eventually_lt_of_lt_liminf hr).mp ((eventually_gt_atTop 0).mono fun n hn₀ hn => ?_)
simpa using NNReal.coe_le_coe.2 ((this _ hn₀).1 hn.le)
diff --git a/Mathlib/Analysis/Analytic/Uniqueness.lean b/Mathlib/Analysis/Analytic/Uniqueness.lean
index b18db8f4e34b7..6c836c8afcab6 100644
--- a/Mathlib/Analysis/Analytic/Uniqueness.lean
+++ b/Mathlib/Analysis/Analytic/Uniqueness.lean
@@ -5,13 +5,15 @@ Authors: Sébastien Gouëzel
-/
import Mathlib.Analysis.Analytic.Linear
import Mathlib.Analysis.Analytic.Composition
+import Mathlib.Analysis.Analytic.Constructions
import Mathlib.Analysis.Normed.Module.Completion
+import Mathlib.Analysis.Analytic.ChangeOrigin
/-!
# Uniqueness principle for analytic functions
We show that two analytic functions which coincide around a point coincide on whole connected sets,
-in `AnalyticOn.eqOn_of_preconnected_of_eventuallyEq`.
+in `AnalyticOnNhd.eqOn_of_preconnected_of_eventuallyEq`.
-/
@@ -20,15 +22,146 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCom
open Set
-open scoped Topology ENNReal
+open scoped Topology ENNReal NNReal
-namespace AnalyticOn
+/-!
+### Uniqueness of power series
+If a function `f : E → F` has two representations as power series at a point `x : E`, corresponding
+to formal multilinear series `p₁` and `p₂`, then these representations agree term-by-term. That is,
+for any `n : ℕ` and `y : E`, `p₁ n (fun i ↦ y) = p₂ n (fun i ↦ y)`. In the one-dimensional case,
+when `f : 𝕜 → E`, the continuous multilinear maps `p₁ n` and `p₂ n` are given by
+`ContinuousMultilinearMap.mkPiRing`, and hence are determined completely by the value of
+`p₁ n (fun i ↦ 1)`, so `p₁ = p₂`. Consequently, the radius of convergence for one series can be
+transferred to the other.
+-/
+
+section Uniqueness
+
+open ContinuousMultilinearMap
+
+theorem Asymptotics.IsBigO.continuousMultilinearMap_apply_eq_zero {n : ℕ} {p : E[×n]→L[𝕜] F}
+ (h : (fun y => p fun _ => y) =O[𝓝 0] fun y => ‖y‖ ^ (n + 1)) (y : E) : (p fun _ => y) = 0 := by
+ obtain ⟨c, c_pos, hc⟩ := h.exists_pos
+ obtain ⟨t, ht, t_open, z_mem⟩ := eventually_nhds_iff.mp (isBigOWith_iff.mp hc)
+ obtain ⟨δ, δ_pos, δε⟩ := (Metric.isOpen_iff.mp t_open) 0 z_mem
+ clear h hc z_mem
+ cases' n with n
+ · exact norm_eq_zero.mp (by
+ -- Porting note: the symmetric difference of the `simpa only` sets:
+ -- added `zero_add, pow_one`
+ -- removed `zero_pow, Ne.def, Nat.one_ne_zero, not_false_iff`
+ simpa only [fin0_apply_norm, norm_eq_zero, norm_zero, zero_add, pow_one,
+ mul_zero, norm_le_zero_iff] using ht 0 (δε (Metric.mem_ball_self δ_pos)))
+ · refine Or.elim (Classical.em (y = 0))
+ (fun hy => by simpa only [hy] using p.map_zero) fun hy => ?_
+ replace hy := norm_pos_iff.mpr hy
+ refine norm_eq_zero.mp (le_antisymm (le_of_forall_pos_le_add fun ε ε_pos => ?_) (norm_nonneg _))
+ have h₀ := _root_.mul_pos c_pos (pow_pos hy (n.succ + 1))
+ obtain ⟨k, k_pos, k_norm⟩ := NormedField.exists_norm_lt 𝕜
+ (lt_min (mul_pos δ_pos (inv_pos.mpr hy)) (mul_pos ε_pos (inv_pos.mpr h₀)))
+ have h₁ : ‖k • y‖ < δ := by
+ rw [norm_smul]
+ exact inv_mul_cancel_right₀ hy.ne.symm δ ▸
+ mul_lt_mul_of_pos_right (lt_of_lt_of_le k_norm (min_le_left _ _)) hy
+ have h₂ :=
+ calc
+ ‖p fun _ => k • y‖ ≤ c * ‖k • y‖ ^ (n.succ + 1) := by
+ -- Porting note: now Lean wants `_root_.`
+ simpa only [norm_pow, _root_.norm_norm] using ht (k • y) (δε (mem_ball_zero_iff.mpr h₁))
+ --simpa only [norm_pow, norm_norm] using ht (k • y) (δε (mem_ball_zero_iff.mpr h₁))
+ _ = ‖k‖ ^ n.succ * (‖k‖ * (c * ‖y‖ ^ (n.succ + 1))) := by
+ -- Porting note: added `Nat.succ_eq_add_one` since otherwise `ring` does not conclude.
+ simp only [norm_smul, mul_pow, Nat.succ_eq_add_one]
+ -- Porting note: removed `rw [pow_succ]`, since it now becomes superfluous.
+ ring
+ have h₃ : ‖k‖ * (c * ‖y‖ ^ (n.succ + 1)) < ε :=
+ inv_mul_cancel_right₀ h₀.ne.symm ε ▸
+ mul_lt_mul_of_pos_right (lt_of_lt_of_le k_norm (min_le_right _ _)) h₀
+ calc
+ ‖p fun _ => y‖ = ‖k⁻¹ ^ n.succ‖ * ‖p fun _ => k • y‖ := by
+ simpa only [inv_smul_smul₀ (norm_pos_iff.mp k_pos), norm_smul, Finset.prod_const,
+ Finset.card_fin] using
+ congr_arg norm (p.map_smul_univ (fun _ : Fin n.succ => k⁻¹) fun _ : Fin n.succ => k • y)
+ _ ≤ ‖k⁻¹ ^ n.succ‖ * (‖k‖ ^ n.succ * (‖k‖ * (c * ‖y‖ ^ (n.succ + 1)))) := by gcongr
+ _ = ‖(k⁻¹ * k) ^ n.succ‖ * (‖k‖ * (c * ‖y‖ ^ (n.succ + 1))) := by
+ rw [← mul_assoc]
+ simp [norm_mul, mul_pow]
+ _ ≤ 0 + ε := by
+ rw [inv_mul_cancel₀ (norm_pos_iff.mp k_pos)]
+ simpa using h₃.le
+
+/-- If a formal multilinear series `p` represents the zero function at `x : E`, then the
+terms `p n (fun i ↦ y)` appearing in the sum are zero for any `n : ℕ`, `y : E`. -/
+theorem HasFPowerSeriesAt.apply_eq_zero {p : FormalMultilinearSeries 𝕜 E F} {x : E}
+ (h : HasFPowerSeriesAt 0 p x) (n : ℕ) : ∀ y : E, (p n fun _ => y) = 0 := by
+ refine Nat.strong_induction_on n fun k hk => ?_
+ have psum_eq : p.partialSum (k + 1) = fun y => p k fun _ => y := by
+ funext z
+ refine Finset.sum_eq_single _ (fun b hb hnb => ?_) fun hn => ?_
+ · have := Finset.mem_range_succ_iff.mp hb
+ simp only [hk b (this.lt_of_ne hnb), Pi.zero_apply]
+ · exact False.elim (hn (Finset.mem_range.mpr (lt_add_one k)))
+ replace h := h.isBigO_sub_partialSum_pow k.succ
+ simp only [psum_eq, zero_sub, Pi.zero_apply, Asymptotics.isBigO_neg_left] at h
+ exact h.continuousMultilinearMap_apply_eq_zero
+
+/-- A one-dimensional formal multilinear series representing the zero function is zero. -/
+theorem HasFPowerSeriesAt.eq_zero {p : FormalMultilinearSeries 𝕜 𝕜 E} {x : 𝕜}
+ (h : HasFPowerSeriesAt 0 p x) : p = 0 := by
+ ext n x
+ rw [← mkPiRing_apply_one_eq_self (p n)]
+ simp [h.apply_eq_zero n 1]
+
+/-- One-dimensional formal multilinear series representing the same function are equal. -/
+theorem HasFPowerSeriesAt.eq_formalMultilinearSeries {p₁ p₂ : FormalMultilinearSeries 𝕜 𝕜 E}
+ {f : 𝕜 → E} {x : 𝕜} (h₁ : HasFPowerSeriesAt f p₁ x) (h₂ : HasFPowerSeriesAt f p₂ x) : p₁ = p₂ :=
+ sub_eq_zero.mp (HasFPowerSeriesAt.eq_zero (x := x) (by simpa only [sub_self] using h₁.sub h₂))
+
+theorem HasFPowerSeriesAt.eq_formalMultilinearSeries_of_eventually
+ {p q : FormalMultilinearSeries 𝕜 𝕜 E} {f g : 𝕜 → E} {x : 𝕜} (hp : HasFPowerSeriesAt f p x)
+ (hq : HasFPowerSeriesAt g q x) (heq : ∀ᶠ z in 𝓝 x, f z = g z) : p = q :=
+ (hp.congr heq).eq_formalMultilinearSeries hq
+
+/-- A one-dimensional formal multilinear series representing a locally zero function is zero. -/
+theorem HasFPowerSeriesAt.eq_zero_of_eventually {p : FormalMultilinearSeries 𝕜 𝕜 E} {f : 𝕜 → E}
+ {x : 𝕜} (hp : HasFPowerSeriesAt f p x) (hf : f =ᶠ[𝓝 x] 0) : p = 0 :=
+ (hp.congr hf).eq_zero
+
+/-- If a function `f : 𝕜 → E` has two power series representations at `x`, then the given radii in
+which convergence is guaranteed may be interchanged. This can be useful when the formal multilinear
+series in one representation has a particularly nice form, but the other has a larger radius. -/
+theorem HasFPowerSeriesOnBall.exchange_radius {p₁ p₂ : FormalMultilinearSeries 𝕜 𝕜 E} {f : 𝕜 → E}
+ {r₁ r₂ : ℝ≥0∞} {x : 𝕜} (h₁ : HasFPowerSeriesOnBall f p₁ x r₁)
+ (h₂ : HasFPowerSeriesOnBall f p₂ x r₂) : HasFPowerSeriesOnBall f p₁ x r₂ :=
+ h₂.hasFPowerSeriesAt.eq_formalMultilinearSeries h₁.hasFPowerSeriesAt ▸ h₂
+
+/-- If a function `f : 𝕜 → E` has power series representation `p` on a ball of some radius and for
+each positive radius it has some power series representation, then `p` converges to `f` on the whole
+`𝕜`. -/
+theorem HasFPowerSeriesOnBall.r_eq_top_of_exists {f : 𝕜 → E} {r : ℝ≥0∞} {x : 𝕜}
+ {p : FormalMultilinearSeries 𝕜 𝕜 E} (h : HasFPowerSeriesOnBall f p x r)
+ (h' : ∀ (r' : ℝ≥0) (_ : 0 < r'), ∃ p' : FormalMultilinearSeries 𝕜 𝕜 E,
+ HasFPowerSeriesOnBall f p' x r') :
+ HasFPowerSeriesOnBall f p x ∞ :=
+ { r_le := ENNReal.le_of_forall_pos_nnreal_lt fun r hr _ =>
+ let ⟨_, hp'⟩ := h' r hr
+ (h.exchange_radius hp').r_le
+ r_pos := ENNReal.coe_lt_top
+ hasSum := fun {y} _ =>
+ let ⟨r', hr'⟩ := exists_gt ‖y‖₊
+ let ⟨_, hp'⟩ := h' r' hr'.ne_bot.bot_lt
+ (h.exchange_radius hp').hasSum <| mem_emetric_ball_zero_iff.mpr (ENNReal.coe_lt_coe.2 hr') }
+
+end Uniqueness
+
+namespace AnalyticOnNhd
/-- If an analytic function vanishes around a point, then it is uniformly zero along
a connected set. Superseded by `eqOn_zero_of_preconnected_of_locally_zero` which does not assume
completeness of the target space. -/
theorem eqOn_zero_of_preconnected_of_eventuallyEq_zero_aux [CompleteSpace F] {f : E → F} {U : Set E}
- (hf : AnalyticOn 𝕜 f U) (hU : IsPreconnected U) {z₀ : E} (h₀ : z₀ ∈ U) (hfz₀ : f =ᶠ[𝓝 z₀] 0) :
+ (hf : AnalyticOnNhd 𝕜 f U) (hU : IsPreconnected U)
+ {z₀ : E} (h₀ : z₀ ∈ U) (hfz₀ : f =ᶠ[𝓝 z₀] 0) :
EqOn f 0 U := by
/- Let `u` be the set of points around which `f` vanishes. It is clearly open. We have to show
that its limit points in `U` still belong to it, from which the inclusion `U ⊆ u` will follow
@@ -72,11 +205,12 @@ neighborhood of a point `z₀`, then it is uniformly zero along a connected set.
version assuming only that the function vanishes at some points arbitrarily close to `z₀`, see
`eqOn_zero_of_preconnected_of_frequently_eq_zero`. -/
theorem eqOn_zero_of_preconnected_of_eventuallyEq_zero {f : E → F} {U : Set E}
- (hf : AnalyticOn 𝕜 f U) (hU : IsPreconnected U) {z₀ : E} (h₀ : z₀ ∈ U) (hfz₀ : f =ᶠ[𝓝 z₀] 0) :
+ (hf : AnalyticOnNhd 𝕜 f U) (hU : IsPreconnected U)
+ {z₀ : E} (h₀ : z₀ ∈ U) (hfz₀ : f =ᶠ[𝓝 z₀] 0) :
EqOn f 0 U := by
let F' := UniformSpace.Completion F
set e : F →L[𝕜] F' := UniformSpace.Completion.toComplL
- have : AnalyticOn 𝕜 (e ∘ f) U := fun x hx => (e.analyticAt _).comp (hf x hx)
+ have : AnalyticOnNhd 𝕜 (e ∘ f) U := fun x hx => (e.analyticAt _).comp (hf x hx)
have A : EqOn (e ∘ f) 0 U := by
apply eqOn_zero_of_preconnected_of_eventuallyEq_zero_aux this hU h₀
filter_upwards [hfz₀] with x hx
@@ -89,8 +223,8 @@ theorem eqOn_zero_of_preconnected_of_eventuallyEq_zero {f : E → F} {U : Set E}
neighborhood of a point `z₀`, then they coincide globally along a connected set.
For a one-dimensional version assuming only that the functions coincide at some points
arbitrarily close to `z₀`, see `eqOn_of_preconnected_of_frequently_eq`. -/
-theorem eqOn_of_preconnected_of_eventuallyEq {f g : E → F} {U : Set E} (hf : AnalyticOn 𝕜 f U)
- (hg : AnalyticOn 𝕜 g U) (hU : IsPreconnected U) {z₀ : E} (h₀ : z₀ ∈ U) (hfg : f =ᶠ[𝓝 z₀] g) :
+theorem eqOn_of_preconnected_of_eventuallyEq {f g : E → F} {U : Set E} (hf : AnalyticOnNhd 𝕜 f U)
+ (hg : AnalyticOnNhd 𝕜 g U) (hU : IsPreconnected U) {z₀ : E} (h₀ : z₀ ∈ U) (hfg : f =ᶠ[𝓝 z₀] g) :
EqOn f g U := by
have hfg' : f - g =ᶠ[𝓝 z₀] 0 := hfg.mono fun z h => by simp [h]
simpa [sub_eq_zero] using fun z hz =>
@@ -100,9 +234,9 @@ theorem eqOn_of_preconnected_of_eventuallyEq {f g : E → F} {U : Set E} (hf : A
coincide in a neighborhood of a point `z₀`, then they coincide everywhere.
For a one-dimensional version assuming only that the functions coincide at some points
arbitrarily close to `z₀`, see `eq_of_frequently_eq`. -/
-theorem eq_of_eventuallyEq {f g : E → F} [PreconnectedSpace E] (hf : AnalyticOn 𝕜 f univ)
- (hg : AnalyticOn 𝕜 g univ) {z₀ : E} (hfg : f =ᶠ[𝓝 z₀] g) : f = g :=
+theorem eq_of_eventuallyEq {f g : E → F} [PreconnectedSpace E] (hf : AnalyticOnNhd 𝕜 f univ)
+ (hg : AnalyticOnNhd 𝕜 g univ) {z₀ : E} (hfg : f =ᶠ[𝓝 z₀] g) : f = g :=
funext fun x =>
eqOn_of_preconnected_of_eventuallyEq hf hg isPreconnected_univ (mem_univ z₀) hfg (mem_univ x)
-end AnalyticOn
+end AnalyticOnNhd
diff --git a/Mathlib/Analysis/Analytic/Within.lean b/Mathlib/Analysis/Analytic/Within.lean
index d8c30c30b6b97..b9f6a8bda1b70 100644
--- a/Mathlib/Analysis/Analytic/Within.lean
+++ b/Mathlib/Analysis/Analytic/Within.lean
@@ -4,24 +4,20 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Geoffrey Irving
-/
import Mathlib.Analysis.Analytic.Constructions
-import Mathlib.Analysis.Calculus.FDeriv.Analytic
/-!
# Properties of analyticity restricted to a set
From `Mathlib.Analysis.Analytic.Basic`, we have the definitions
-1. `AnalyticWithinAt 𝕜 f s x` means a power series at `x` converges to `f` on `𝓝[s] x`, and
- `f` is continuous within `s` at `x`.
-2. `AnalyticWithinOn 𝕜 f s t` means `∀ x ∈ t, AnalyticWithinAt 𝕜 f s x`.
+1. `AnalyticWithinAt 𝕜 f s x` means a power series at `x` converges to `f` on `𝓝[insert x s] x`.
+2. `AnalyticOn 𝕜 f s t` means `∀ x ∈ t, AnalyticWithinAt 𝕜 f s x`.
This means there exists an extension of `f` which is analytic and agrees with `f` on `s ∪ {x}`, but
-`f` is allowed to be arbitrary elsewhere. Requiring `ContinuousWithinAt` is essential if `x ∉ s`:
-it is required for composition and smoothness to follow without extra hypotheses (we could
-alternately require convergence at `x` even if `x ∉ s`).
+`f` is allowed to be arbitrary elsewhere.
Here we prove basic properties of these definitions. Where convenient we assume completeness of the
-ambient space, which allows us to related `AnalyticWithinAt` to analyticity of a local extension.
+ambient space, which allows us to relate `AnalyticWithinAt` to analyticity of a local extension.
-/
noncomputable section
@@ -40,43 +36,9 @@ variable {E F G H : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedAd
### Basic properties
-/
-@[simp] lemma hasFPowerSeriesWithinOnBall_univ {f : E → F} {p : FormalMultilinearSeries 𝕜 E F}
- {x : E} {r : ℝ≥0∞} :
- HasFPowerSeriesWithinOnBall f p univ x r ↔ HasFPowerSeriesOnBall f p x r := by
- constructor
- · intro h
- exact ⟨h.r_le, h.r_pos, fun {y} m ↦ h.hasSum (mem_univ _) m⟩
- · intro h
- refine ⟨h.r_le, h.r_pos, fun {y} _ m => h.hasSum m, ?_⟩
- exact (h.continuousOn.continuousAt (EMetric.ball_mem_nhds x h.r_pos)).continuousWithinAt
-
-@[simp] lemma hasFPowerSeriesWithinAt_univ {f : E → F} {p : FormalMultilinearSeries 𝕜 E F} {x : E} :
- HasFPowerSeriesWithinAt f p univ x ↔ HasFPowerSeriesAt f p x := by
- simp only [HasFPowerSeriesWithinAt, hasFPowerSeriesWithinOnBall_univ, HasFPowerSeriesAt]
-
-@[simp] lemma analyticWithinAt_univ {f : E → F} {x : E} :
- AnalyticWithinAt 𝕜 f univ x ↔ AnalyticAt 𝕜 f x := by
- simp only [AnalyticWithinAt, hasFPowerSeriesWithinAt_univ, AnalyticAt]
-
-lemma analyticWithinOn_univ {f : E → F} :
- AnalyticWithinOn 𝕜 f univ ↔ AnalyticOn 𝕜 f univ := by
- simp only [AnalyticWithinOn, analyticWithinAt_univ, AnalyticOn]
-
-lemma HasFPowerSeriesWithinAt.continuousWithinAt {f : E → F} {p : FormalMultilinearSeries 𝕜 E F}
- {s : Set E} {x : E} (h : HasFPowerSeriesWithinAt f p s x) : ContinuousWithinAt f s x := by
- rcases h with ⟨r, h⟩
- exact h.continuousWithinAt
-
-lemma AnalyticWithinAt.continuousWithinAt {f : E → F} {s : Set E} {x : E}
- (h : AnalyticWithinAt 𝕜 f s x) : ContinuousWithinAt f s x := by
- rcases h with ⟨p, h⟩
- exact h.continuousWithinAt
-
/-- `AnalyticWithinAt` is trivial if `{x} ∈ 𝓝[s] x` -/
lemma analyticWithinAt_of_singleton_mem {f : E → F} {s : Set E} {x : E} (h : {x} ∈ 𝓝[s] x) :
AnalyticWithinAt 𝕜 f s x := by
- have fc : ContinuousWithinAt f s x :=
- Filter.Tendsto.mono_left (tendsto_pure_nhds _ _) (Filter.le_pure_iff.mpr h)
rcases mem_nhdsWithin.mp h with ⟨t, ot, xt, st⟩
rcases Metric.mem_nhds_iff.mp (ot.mem_nhds xt) with ⟨r, r0, rt⟩
exact ⟨constFormalMultilinearSeries 𝕜 E (f x), .ofReal r, {
@@ -85,38 +47,19 @@ lemma analyticWithinAt_of_singleton_mem {f : E → F} {s : Set E} {x : E} (h : {
hasSum := by
intro y ys yr
simp only [subset_singleton_iff, mem_inter_iff, and_imp] at st
- specialize st (x + y) (rt (by simpa using yr)) ys
- simp only [st]
+ simp only [mem_insert_iff, add_right_eq_self] at ys
+ have : x + y = x := by
+ rcases ys with rfl | ys
+ · simp
+ · exact st (x + y) (rt (by simpa using yr)) ys
+ simp only [this]
apply (hasFPowerSeriesOnBall_const (e := 0)).hasSum
- simp only [Metric.emetric_ball_top, mem_univ]
- continuousWithinAt := fc
- }⟩
-
-/-- Analyticity implies analyticity within any `s` -/
-lemma AnalyticAt.analyticWithinAt {f : E → F} {s : Set E} {x : E} (h : AnalyticAt 𝕜 f x) :
- AnalyticWithinAt 𝕜 f s x := by
- rcases h with ⟨p, r, hp⟩
- exact ⟨p, r, {
- r_le := hp.r_le
- r_pos := hp.r_pos
- hasSum := fun {y} _ yr ↦ hp.hasSum yr
- continuousWithinAt :=
- (hp.continuousOn.continuousAt (EMetric.ball_mem_nhds x hp.r_pos)).continuousWithinAt
- }⟩
-
-/-- Analyticity on `s` implies analyticity within `s` -/
-lemma AnalyticOn.analyticWithinOn {f : E → F} {s : Set E} (h : AnalyticOn 𝕜 f s) :
- AnalyticWithinOn 𝕜 f s :=
- fun x m ↦ (h x m).analyticWithinAt
-
-lemma AnalyticWithinOn.continuousOn {f : E → F} {s : Set E} (h : AnalyticWithinOn 𝕜 f s) :
- ContinuousOn f s :=
- fun x m ↦ (h x m).continuousWithinAt
+ simp only [Metric.emetric_ball_top, mem_univ] }⟩
-/-- If `f` is `AnalyticWithinOn` near each point in a set, it is `AnalyticWithinOn` the set -/
-lemma analyticWithinOn_of_locally_analyticWithinOn {f : E → F} {s : Set E}
- (h : ∀ x ∈ s, ∃ u, IsOpen u ∧ x ∈ u ∧ AnalyticWithinOn 𝕜 f (s ∩ u)) :
- AnalyticWithinOn 𝕜 f s := by
+/-- If `f` is `AnalyticOn` near each point in a set, it is `AnalyticOn` the set -/
+lemma analyticOn_of_locally_analyticOn {f : E → F} {s : Set E}
+ (h : ∀ x ∈ s, ∃ u, IsOpen u ∧ x ∈ u ∧ AnalyticOn 𝕜 f (s ∩ u)) :
+ AnalyticOn 𝕜 f s := by
intro x m
rcases h x m with ⟨u, ou, xu, fu⟩
rcases Metric.mem_nhds_iff.mp (ou.mem_nhds xu) with ⟨r, r0, ru⟩
@@ -125,20 +68,24 @@ lemma analyticWithinOn_of_locally_analyticWithinOn {f : E → F} {s : Set E}
r_pos := lt_min (by positivity) fp.r_pos
r_le := min_le_of_right_le fp.r_le
hasSum := by
- intro y ys yr
- simp only [EMetric.mem_ball, lt_min_iff, edist_lt_ofReal, dist_zero_right] at yr
- apply fp.hasSum ⟨ys, ru ?_⟩
- · simp only [EMetric.mem_ball, yr]
- · simp only [Metric.mem_ball, dist_self_add_left, yr]
- continuousWithinAt := by
- refine (fu.continuousOn x ⟨m, xu⟩).mono_left (le_of_eq ?_)
- exact nhdsWithin_eq_nhdsWithin xu ou (by simp only [inter_assoc, inter_self])
- }⟩
-
-/-- On open sets, `AnalyticOn` and `AnalyticWithinOn` coincide -/
-@[simp] lemma IsOpen.analyticWithinOn_iff_analyticOn {f : E → F} {s : Set E} (hs : IsOpen s) :
- AnalyticWithinOn 𝕜 f s ↔ AnalyticOn 𝕜 f s := by
- refine ⟨?_, AnalyticOn.analyticWithinOn⟩
+ intro y ys yr
+ simp only [EMetric.mem_ball, lt_min_iff, edist_lt_ofReal, dist_zero_right] at yr
+ apply fp.hasSum
+ · simp only [mem_insert_iff, add_right_eq_self] at ys
+ rcases ys with rfl | ys
+ · simp
+ · simp only [mem_insert_iff, add_right_eq_self, mem_inter_iff, ys, true_and]
+ apply Or.inr (ru ?_)
+ simp only [Metric.mem_ball, dist_self_add_left, yr]
+ · simp only [EMetric.mem_ball, yr] }⟩
+
+@[deprecated (since := "2024-09-26")]
+alias analyticWithinOn_of_locally_analyticWithinOn := analyticOn_of_locally_analyticOn
+
+/-- On open sets, `AnalyticOnNhd` and `AnalyticOn` coincide -/
+lemma IsOpen.analyticOn_iff_analyticOnNhd {f : E → F} {s : Set E} (hs : IsOpen s) :
+ AnalyticOn 𝕜 f s ↔ AnalyticOnNhd 𝕜 f s := by
+ refine ⟨?_, AnalyticOnNhd.analyticOn⟩
intro hf x m
rcases Metric.mem_nhds_iff.mp (hs.mem_nhds m) with ⟨r, r0, rs⟩
rcases hf x m with ⟨p, t, fp⟩
@@ -148,28 +95,34 @@ lemma analyticWithinOn_of_locally_analyticWithinOn {f : E → F} {s : Set E}
hasSum := by
intro y ym
simp only [EMetric.mem_ball, lt_min_iff, edist_lt_ofReal, dist_zero_right] at ym
- refine fp.hasSum (rs ?_) ym.2
- simp only [Metric.mem_ball, dist_self_add_left, ym.1]
- }⟩
+ refine fp.hasSum ?_ ym.2
+ apply mem_insert_of_mem
+ apply rs
+ simp only [Metric.mem_ball, dist_self_add_left, ym.1] }⟩
+
+@[deprecated (since := "2024-09-26")]
+alias IsOpen.analyticWithinOn_iff_analyticOn := IsOpen.analyticOn_iff_analyticOnNhd
+
/-!
### Equivalence to analyticity of a local extension
We show that `HasFPowerSeriesWithinOnBall`, `HasFPowerSeriesWithinAt`, and `AnalyticWithinAt` are
equivalent to the existence of a local extension with full analyticity. We do not yet show a
-result for `AnalyticWithinOn`, as this requires a bit more work to show that local extensions can
+result for `AnalyticOn`, as this requires a bit more work to show that local extensions can
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∞} :
HasFPowerSeriesWithinOnBall f p s x r ↔
- ContinuousWithinAt f s x ∧ ∃ g, EqOn f g (s ∩ EMetric.ball x r) ∧
+ ∃ g, EqOn f g (insert x s ∩ EMetric.ball x r) ∧
HasFPowerSeriesOnBall g p x r := by
constructor
· intro h
- refine ⟨h.continuousWithinAt, fun y ↦ p.sum (y - x), ?_, ?_⟩
+ refine ⟨fun y ↦ p.sum (y - x), ?_, ?_⟩
· intro y ⟨ys,yb⟩
simp only [EMetric.mem_ball, edist_eq_coe_nnnorm_sub] at yb
have e0 := p.hasSum (x := y - x) ?_
@@ -186,8 +139,8 @@ lemma hasFPowerSeriesWithinOnBall_iff_exists_hasFPowerSeriesOnBall [CompleteSpac
apply p.hasSum
simp only [EMetric.mem_ball] at lt ⊢
exact lt_of_lt_of_le lt h.r_le
- · intro ⟨mem, g, hfg, hg⟩
- refine ⟨hg.r_le, hg.r_pos, ?_, mem⟩
+ · intro ⟨g, hfg, hg⟩
+ refine ⟨hg.r_le, hg.r_pos, ?_⟩
intro y ys lt
rw [hfg]
· exact hg.hasSum lt
@@ -198,18 +151,18 @@ lemma hasFPowerSeriesWithinOnBall_iff_exists_hasFPowerSeriesOnBall [CompleteSpac
lemma hasFPowerSeriesWithinAt_iff_exists_hasFPowerSeriesAt [CompleteSpace F] {f : E → F}
{p : FormalMultilinearSeries 𝕜 E F} {s : Set E} {x : E} :
HasFPowerSeriesWithinAt f p s x ↔
- ContinuousWithinAt f s x ∧ ∃ g, f =ᶠ[𝓝[s] x] g ∧ HasFPowerSeriesAt g p x := by
+ ∃ g, f =ᶠ[𝓝[insert x s] x] g ∧ HasFPowerSeriesAt g p x := by
constructor
· intro ⟨r, h⟩
- rcases hasFPowerSeriesWithinOnBall_iff_exists_hasFPowerSeriesOnBall.mp h with ⟨fc, g, e, h⟩
- refine ⟨fc, g, ?_, ⟨r, h⟩⟩
+ rcases hasFPowerSeriesWithinOnBall_iff_exists_hasFPowerSeriesOnBall.mp h with ⟨g, e, h⟩
+ refine ⟨g, ?_, ⟨r, h⟩⟩
refine Filter.eventuallyEq_iff_exists_mem.mpr ⟨_, ?_, e⟩
exact inter_mem_nhdsWithin _ (EMetric.ball_mem_nhds _ h.r_pos)
- · intro ⟨mem, g, hfg, ⟨r, hg⟩⟩
+ · intro ⟨g, hfg, ⟨r, hg⟩⟩
simp only [eventuallyEq_nhdsWithin_iff, Metric.eventually_nhds_iff] at hfg
rcases hfg with ⟨e, e0, hfg⟩
refine ⟨min r (.ofReal e), ?_⟩
- refine hasFPowerSeriesWithinOnBall_iff_exists_hasFPowerSeriesOnBall.mpr ⟨mem, g, ?_, ?_⟩
+ refine hasFPowerSeriesWithinOnBall_iff_exists_hasFPowerSeriesOnBall.mpr ⟨g, ?_, ?_⟩
· intro y ⟨ys, xy⟩
refine hfg ?_ ys
simp only [EMetric.mem_ball, lt_min_iff, edist_lt_ofReal] at xy
@@ -219,147 +172,32 @@ lemma hasFPowerSeriesWithinAt_iff_exists_hasFPowerSeriesAt [CompleteSpace F] {f
/-- `f` is analytic within `s` at `x` iff some local extension of `f` is analytic at `x` -/
lemma analyticWithinAt_iff_exists_analyticAt [CompleteSpace F] {f : E → F} {s : Set E} {x : E} :
AnalyticWithinAt 𝕜 f s x ↔
- ContinuousWithinAt f s x ∧ ∃ g, f =ᶠ[𝓝[s] x] g ∧ AnalyticAt 𝕜 g x := by
+ ∃ g, f =ᶠ[𝓝[insert x s] x] g ∧ AnalyticAt 𝕜 g x := by
simp only [AnalyticWithinAt, AnalyticAt, hasFPowerSeriesWithinAt_iff_exists_hasFPowerSeriesAt]
tauto
-/-- If `f` is analytic within `s` at `x`, some local extension of `f` is analytic at `x` -/
-lemma AnalyticWithinAt.exists_analyticAt [CompleteSpace F] {f : E → F} {s : Set E} {x : E}
- (h : AnalyticWithinAt 𝕜 f s x) : ∃ g, f x = g x ∧ f =ᶠ[𝓝[s] x] g ∧ AnalyticAt 𝕜 g x := by
- by_cases s0 : 𝓝[s] x = ⊥
- · refine ⟨fun _ ↦ f x, rfl, ?_, analyticAt_const⟩
- simp only [EventuallyEq, s0, eventually_bot]
- · rcases analyticWithinAt_iff_exists_analyticAt.mp h with ⟨_, g, fg, hg⟩
- refine ⟨g, ?_, fg, hg⟩
- exact tendsto_nhds_unique' ⟨s0⟩ h.continuousWithinAt
- (hg.continuousAt.continuousWithinAt.congr' fg.symm)
-
-/-!
-### Congruence
-
-We require completeness to use equivalence to locally extensions, but this is nonessential.
--/
-
-lemma AnalyticWithinAt.congr_of_eventuallyEq [CompleteSpace F] {f g : E → F} {s : Set E} {x : E}
- (hf : AnalyticWithinAt 𝕜 f s x) (hs : f =ᶠ[𝓝[s] x] g) (hx : f x = g x) :
- AnalyticWithinAt 𝕜 g s x := by
- rcases hf.exists_analyticAt with ⟨f', fx, ef, hf'⟩
- rw [analyticWithinAt_iff_exists_analyticAt]
- have eg := hs.symm.trans ef
- refine ⟨?_, f', eg, hf'⟩
- exact hf'.continuousAt.continuousWithinAt.congr_of_eventuallyEq eg (hx.symm.trans fx)
-
-lemma AnalyticWithinAt.congr [CompleteSpace F] {f g : E → F} {s : Set E} {x : E}
- (hf : AnalyticWithinAt 𝕜 f s x) (hs : EqOn f g s) (hx : f x = g x) :
- AnalyticWithinAt 𝕜 g s x :=
- hf.congr_of_eventuallyEq hs.eventuallyEq_nhdsWithin hx
-
-lemma AnalyticWithinOn.congr [CompleteSpace F] {f g : E → F} {s : Set E}
- (hf : AnalyticWithinOn 𝕜 f s) (hs : EqOn f g s) :
- AnalyticWithinOn 𝕜 g s :=
- fun x m ↦ (hf x m).congr hs (hs m)
-
-/-!
-### Monotonicity w.r.t. the set we're analytic within
--/
-
-lemma HasFPowerSeriesWithinOnBall.mono {f : E → F} {p : FormalMultilinearSeries 𝕜 E F}
- {s t : Set E} {x : E} {r : ℝ≥0∞} (h : HasFPowerSeriesWithinOnBall f p t x r)
- (hs : s ⊆ t) : HasFPowerSeriesWithinOnBall f p s x r where
- r_le := h.r_le
- r_pos := h.r_pos
- hasSum {_} ys yb := h.hasSum (hs ys) yb
- continuousWithinAt := h.continuousWithinAt.mono hs
-
-lemma HasFPowerSeriesWithinAt.mono {f : E → F} {p : FormalMultilinearSeries 𝕜 E F}
- {s t : Set E} {x : E} (h : HasFPowerSeriesWithinAt f p t x)
- (hs : s ⊆ t) : HasFPowerSeriesWithinAt f p s x := by
- rcases h with ⟨r, hr⟩
- exact ⟨r, hr.mono hs⟩
-
-lemma AnalyticWithinAt.mono {f : E → F} {s t : Set E} {x : E} (h : AnalyticWithinAt 𝕜 f t x)
- (hs : s ⊆ t) : AnalyticWithinAt 𝕜 f s x := by
- rcases h with ⟨p, hp⟩
- exact ⟨p, hp.mono hs⟩
-
-lemma AnalyticWithinOn.mono {f : E → F} {s t : Set E} (h : AnalyticWithinOn 𝕜 f t)
- (hs : s ⊆ t) : AnalyticWithinOn 𝕜 f s :=
- fun _ m ↦ (h _ (hs m)).mono hs
-
-/-!
-### Analyticity within respects composition
-
-Currently we require `CompleteSpace`s to use equivalence to local extensions, but this is not
-essential.
--/
-
-lemma AnalyticWithinAt.comp [CompleteSpace F] [CompleteSpace G] {f : F → G} {g : E → F} {s : Set F}
- {t : Set E} {x : E} (hf : AnalyticWithinAt 𝕜 f s (g x)) (hg : AnalyticWithinAt 𝕜 g t x)
- (h : MapsTo g t s) : AnalyticWithinAt 𝕜 (f ∘ g) t x := by
- rcases hf.exists_analyticAt with ⟨f', _, ef, hf'⟩
- rcases hg.exists_analyticAt with ⟨g', gx, eg, hg'⟩
- refine analyticWithinAt_iff_exists_analyticAt.mpr ⟨?_, f' ∘ g', ?_, ?_⟩
- · exact hf.continuousWithinAt.comp hg.continuousWithinAt h
- · have gt := hg.continuousWithinAt.tendsto_nhdsWithin h
- filter_upwards [eg, gt.eventually ef]
- intro y gy fgy
- simp only [Function.comp_apply, fgy, ← gy]
- · exact hf'.comp_of_eq hg' gx.symm
-
-lemma AnalyticWithinOn.comp [CompleteSpace F] [CompleteSpace G] {f : F → G} {g : E → F} {s : Set F}
- {t : Set E} (hf : AnalyticWithinOn 𝕜 f s) (hg : AnalyticWithinOn 𝕜 g t) (h : MapsTo g t s) :
- AnalyticWithinOn 𝕜 (f ∘ g) t :=
- fun x m ↦ (hf _ (h m)).comp (hg x m) h
-
-/-!
-### Analyticity within implies smoothness
--/
-
-lemma AnalyticWithinAt.contDiffWithinAt [CompleteSpace F] {f : E → F} {s : Set E} {x : E}
- (h : AnalyticWithinAt 𝕜 f s x) {n : ℕ∞} : ContDiffWithinAt 𝕜 n f s x := by
- rcases h.exists_analyticAt with ⟨g, fx, fg, hg⟩
- exact hg.contDiffAt.contDiffWithinAt.congr_of_eventuallyEq fg fx
-
-lemma AnalyticWithinOn.contDiffOn [CompleteSpace F] {f : E → F} {s : Set E}
- (h : AnalyticWithinOn 𝕜 f s) {n : ℕ∞} : ContDiffOn 𝕜 n f s :=
- fun x m ↦ (h x m).contDiffWithinAt
-
-/-!
-### Analyticity within respects products
--/
-
-lemma HasFPowerSeriesWithinOnBall.prod {e : E} {f : E → F} {g : E → G} {s : Set E} {r t : ℝ≥0∞}
- {p : FormalMultilinearSeries 𝕜 E F} {q : FormalMultilinearSeries 𝕜 E G}
- (hf : HasFPowerSeriesWithinOnBall f p s e r) (hg : HasFPowerSeriesWithinOnBall g q s e t) :
- HasFPowerSeriesWithinOnBall (fun x ↦ (f x, g x)) (p.prod q) s e (min r t) where
- r_le := by
- rw [p.radius_prod_eq_min]
- exact min_le_min hf.r_le hg.r_le
- r_pos := lt_min hf.r_pos hg.r_pos
- hasSum := by
- intro y m hy
- simp_rw [FormalMultilinearSeries.prod, ContinuousMultilinearMap.prod_apply]
- refine (hf.hasSum m ?_).prod_mk (hg.hasSum m ?_)
- · exact EMetric.mem_ball.mpr (lt_of_lt_of_le hy (min_le_left _ _))
- · exact EMetric.mem_ball.mpr (lt_of_lt_of_le hy (min_le_right _ _))
- continuousWithinAt := hf.continuousWithinAt.prod hg.continuousWithinAt
-
-lemma HasFPowerSeriesWithinAt.prod {e : E} {f : E → F} {g : E → G} {s : Set E}
- {p : FormalMultilinearSeries 𝕜 E F} {q : FormalMultilinearSeries 𝕜 E G}
- (hf : HasFPowerSeriesWithinAt f p s e) (hg : HasFPowerSeriesWithinAt g q s e) :
- HasFPowerSeriesWithinAt (fun x ↦ (f x, g x)) (p.prod q) s e := by
- rcases hf with ⟨_, hf⟩
- rcases hg with ⟨_, hg⟩
- exact ⟨_, hf.prod hg⟩
-
-lemma AnalyticWithinAt.prod {e : E} {f : E → F} {g : E → G} {s : Set E}
- (hf : AnalyticWithinAt 𝕜 f s e) (hg : AnalyticWithinAt 𝕜 g s e) :
- AnalyticWithinAt 𝕜 (fun x ↦ (f x, g x)) s e := by
- rcases hf with ⟨_, hf⟩
- rcases hg with ⟨_, hg⟩
- exact ⟨_, hf.prod hg⟩
-
-lemma AnalyticWithinOn.prod {f : E → F} {g : E → G} {s : Set E}
- (hf : AnalyticWithinOn 𝕜 f s) (hg : AnalyticWithinOn 𝕜 g s) :
- AnalyticWithinOn 𝕜 (fun x ↦ (f x, g x)) s :=
- fun x hx ↦ (hf x hx).prod (hg x hx)
+/-- `f` is analytic within `s` at `x` iff some local extension of `f` is analytic at `x`. In this
+version, we make sure that the extension coincides with `f` on all of `insert x s`. -/
+lemma analyticWithinAt_iff_exists_analyticAt' [CompleteSpace F] {f : E → F} {s : Set E} {x : E} :
+ AnalyticWithinAt 𝕜 f s x ↔
+ ∃ g, f x = g x ∧ EqOn f g (insert x s) ∧ AnalyticAt 𝕜 g x := by
+ classical
+ simp only [analyticWithinAt_iff_exists_analyticAt]
+ refine ⟨?_, ?_⟩
+ · rintro ⟨g, hf, hg⟩
+ rcases mem_nhdsWithin.1 hf with ⟨u, u_open, xu, hu⟩
+ let g' := Set.piecewise u g f
+ refine ⟨g', ?_, ?_, ?_⟩
+ · have : x ∈ u ∩ insert x s := ⟨xu, by simp⟩
+ simpa [g', xu, this] using hu this
+ · intro y hy
+ by_cases h'y : y ∈ u
+ · have : y ∈ u ∩ insert x s := ⟨h'y, hy⟩
+ simpa [g', h'y, this] using hu this
+ · simp [g', h'y]
+ · apply hg.congr
+ filter_upwards [u_open.mem_nhds xu] with y hy using by simp [g', hy]
+ · rintro ⟨g, -, hf, hg⟩
+ exact ⟨g, by filter_upwards [self_mem_nhdsWithin] using hf, hg⟩
+
+alias ⟨AnalyticWithinAt.exists_analyticAt, _⟩ := analyticWithinAt_iff_exists_analyticAt'
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 47518d245fd96..2ac86221aead4 100644
--- a/Mathlib/Analysis/Asymptotics/Asymptotics.lean
+++ b/Mathlib/Analysis/Asymptotics/Asymptotics.lean
@@ -128,13 +128,13 @@ theorem isBigO_iff'' {g : α → E'''} :
obtain ⟨c, ⟨hc_pos, hc⟩⟩ := h
refine ⟨c⁻¹, ⟨by positivity, ?_⟩⟩
filter_upwards [hc] with x hx
- rwa [inv_mul_le_iff (by positivity)]
+ rwa [inv_mul_le_iff₀ (by positivity)]
case mpr =>
rw [isBigO_iff']
obtain ⟨c, ⟨hc_pos, hc⟩⟩ := h
refine ⟨c⁻¹, ⟨by positivity, ?_⟩⟩
filter_upwards [hc] with x hx
- rwa [← inv_inv c, inv_mul_le_iff (by positivity)] at hx
+ rwa [← inv_inv c, inv_mul_le_iff₀ (by positivity)] at hx
theorem IsBigO.of_bound (c : ℝ) (h : ∀ᶠ x in l, ‖f x‖ ≤ c * ‖g x‖) : f =O[l] g :=
isBigO_iff.2 ⟨c, h⟩
@@ -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₀
@@ -593,7 +593,7 @@ theorem isLittleO_sup : f =o[l ⊔ l'] g ↔ f =o[l] g ∧ f =o[l'] g :=
theorem isBigOWith_insert [TopologicalSpace α] {x : α} {s : Set α} {C : ℝ} {g : α → E} {g' : α → F}
(h : ‖g x‖ ≤ C * ‖g' x‖) : IsBigOWith C (𝓝[insert x s] x) g g' ↔
IsBigOWith C (𝓝[s] x) g g' := by
- simp_rw [IsBigOWith_def, nhdsWithin_insert, eventually_sup, eventually_pure, h, true_and_iff]
+ simp_rw [IsBigOWith_def, nhdsWithin_insert, eventually_sup, eventually_pure, h, true_and]
protected theorem IsBigOWith.insert [TopologicalSpace α] {x : α} {s : Set α} {C : ℝ} {g : α → E}
{g' : α → F} (h1 : IsBigOWith C (𝓝[s] x) g g') (h2 : ‖g x‖ ≤ C * ‖g' x‖) :
@@ -1059,7 +1059,7 @@ variable {g g' l}
@[simp]
theorem isBigOWith_zero_right_iff : (IsBigOWith c l f'' fun _x => (0 : F')) ↔ f'' =ᶠ[l] 0 := by
- simp only [IsBigOWith_def, exists_prop, true_and_iff, norm_zero, mul_zero,
+ simp only [IsBigOWith_def, exists_prop, norm_zero, mul_zero,
norm_le_zero_iff, EventuallyEq, Pi.zero_apply]
@[simp]
@@ -1251,6 +1251,9 @@ theorem IsLittleO.trans_tendsto (hfg : f'' =o[l] g'') (hg : Tendsto g'' l (𝓝
Tendsto f'' l (𝓝 0) :=
hfg.isBigO.trans_tendsto hg
+lemma isLittleO_id_one [One F''] [NeZero (1 : F'')] : (fun x : E'' => x) =o[𝓝 0] (1 : E'' → F'') :=
+ isLittleO_id_const one_ne_zero
+
/-! ### Multiplication by a constant -/
@@ -1447,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)
@@ -1622,8 +1625,8 @@ theorem isLittleO_const_left_of_ne {c : E''} (hc : c ≠ 0) :
theorem isLittleO_const_left {c : E''} :
(fun _x => c) =o[l] g'' ↔ c = 0 ∨ Tendsto (norm ∘ g'') l atTop := by
rcases eq_or_ne c 0 with (rfl | hc)
- · simp only [isLittleO_zero, eq_self_iff_true, true_or_iff]
- · simp only [hc, false_or_iff, isLittleO_const_left_of_ne hc]; rfl
+ · simp only [isLittleO_zero, eq_self_iff_true, true_or]
+ · simp only [hc, false_or, isLittleO_const_left_of_ne hc]; rfl
@[simp 1001] -- Porting note: increase priority so that this triggers before `isLittleO_const_left`
theorem isLittleO_const_const_iff [NeBot l] {d : E''} {c : F''} :
@@ -1700,7 +1703,7 @@ theorem isBigOWith_iff_exists_eq_mul (hc : 0 ≤ c) :
· intro h
use fun x => u x / v x
refine ⟨Eventually.mono h.bound fun y hy => ?_, h.eventually_mul_div_cancel.symm⟩
- simpa using div_le_of_nonneg_of_le_mul (norm_nonneg _) hc hy
+ simpa using div_le_of_le_mul₀ (norm_nonneg _) hc hy
· rintro ⟨φ, hφ, h⟩
exact isBigOWith_of_eq_mul φ hφ h
@@ -1741,7 +1744,7 @@ theorem div_isBoundedUnder_of_isBigO {α : Type*} {l : Filter α} {f g : α →
obtain ⟨c, h₀, hc⟩ := h.exists_nonneg
refine ⟨c, eventually_map.2 (hc.bound.mono fun x hx => ?_)⟩
rw [norm_div]
- exact div_le_of_nonneg_of_le_mul (norm_nonneg _) h₀ hx
+ exact div_le_of_le_mul₀ (norm_nonneg _) h₀ hx
theorem isBigO_iff_div_isBoundedUnder {α : Type*} {l : Filter α} {f g : α → 𝕜}
(hgf : ∀ᶠ x in l, g x = 0 → f x = 0) :
@@ -1819,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")]
@@ -1869,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)]
@@ -1915,6 +1918,13 @@ theorem isBigO_atTop_iff_eventually_exists_pos {α : Type*}
f =O[atTop] g ↔ ∀ᶠ n₀ in atTop, ∃ c > 0, ∀ n ≥ n₀, c * ‖f n‖ ≤ ‖g n‖ := by
simp_rw [isBigO_iff'', ← exists_prop, Subtype.exists', exists_eventually_atTop]
+lemma isBigO_mul_iff_isBigO_div {f g h : α → 𝕜} (hf : ∀ᶠ x in l, f x ≠ 0) :
+ (fun x ↦ f x * g x) =O[l] h ↔ g =O[l] (fun x ↦ h x / f x) := by
+ rw [isBigO_iff', isBigO_iff']
+ refine ⟨fun ⟨c, hc, H⟩ ↦ ⟨c, hc, ?_⟩, fun ⟨c, hc, H⟩ ↦ ⟨c, hc, ?_⟩⟩ <;>
+ · refine H.congr <| Eventually.mp hf <| Eventually.of_forall fun x hx ↦ ?_
+ rw [norm_mul, norm_div, ← mul_div_assoc, le_div_iff₀' (norm_pos_iff.mpr hx)]
+
end Asymptotics
open Asymptotics
@@ -1948,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}
@@ -2038,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/Asymptotics/SpecificAsymptotics.lean b/Mathlib/Analysis/Asymptotics/SpecificAsymptotics.lean
index 200ac13ef97fb..72724bc1976ef 100644
--- a/Mathlib/Analysis/Asymptotics/SpecificAsymptotics.lean
+++ b/Mathlib/Analysis/Asymptotics/SpecificAsymptotics.lean
@@ -107,11 +107,9 @@ theorem Asymptotics.IsLittleO.sum_range {α : Type*} [NormedAddCommGroup α] {f
(add_le_add le_rfl (norm_sum_le_of_le _ fun i hi => hN _ (mem_Ico.1 hi).1))
_ ≤ ‖∑ i ∈ range N, f i‖ + ∑ i ∈ range n, ε / 2 * g i := by
gcongr
- apply sum_le_sum_of_subset_of_nonneg
+ · exact fun i _ _ ↦ mul_nonneg (half_pos εpos).le (hg i)
· rw [range_eq_Ico]
exact Ico_subset_Ico (zero_le _) le_rfl
- · intro i _ _
- exact mul_nonneg (half_pos εpos).le (hg i)
_ ≤ ε / 2 * ‖∑ i ∈ range n, g i‖ + ε / 2 * ∑ i ∈ range n, g i := by rw [← mul_sum]; gcongr
_ = ε * ‖∑ i ∈ range n, g i‖ := by
simp only [B]
diff --git a/Mathlib/Analysis/Asymptotics/Theta.lean b/Mathlib/Analysis/Asymptotics/Theta.lean
index 7b78a91770b61..bf570aafef4e4 100644
--- a/Mathlib/Analysis/Asymptotics/Theta.lean
+++ b/Mathlib/Analysis/Asymptotics/Theta.lean
@@ -238,7 +238,7 @@ theorem isTheta_const_const_iff [NeBot l] {c₁ : E''} {c₂ : F''} :
@[simp]
theorem isTheta_zero_left : (fun _ ↦ (0 : E')) =Θ[l] g'' ↔ g'' =ᶠ[l] 0 := by
- simp only [IsTheta, isBigO_zero, isBigO_zero_right_iff, true_and_iff]
+ simp only [IsTheta, isBigO_zero, isBigO_zero_right_iff, true_and]
@[simp]
theorem isTheta_zero_right : (f'' =Θ[l] fun _ ↦ (0 : F')) ↔ f'' =ᶠ[l] 0 :=
diff --git a/Mathlib/Analysis/BoundedVariation.lean b/Mathlib/Analysis/BoundedVariation.lean
index dd6942a44733b..4f281d9bfca6d 100644
--- a/Mathlib/Analysis/BoundedVariation.lean
+++ b/Mathlib/Analysis/BoundedVariation.lean
@@ -292,7 +292,7 @@ theorem add_point (f : α → E) {s : Set α} {x : α} (hx : x ∈ s) (u : ℕ
apply Finset.sum_congr rfl fun i _hi => ?_
dsimp only [w]
simp only [← Npos, Nat.not_lt_zero, Nat.add_succ_sub_one, add_zero, if_false,
- add_eq_zero, Nat.one_ne_zero, false_and_iff, Nat.succ_add_sub_one, zero_add]
+ add_eq_zero, Nat.one_ne_zero, false_and, Nat.succ_add_sub_one, zero_add]
rw [add_comm 1 i]
_ = ∑ i ∈ Finset.Ico 1 (n + 1), edist (f (w (i + 1))) (f (w i)) := by
rw [Finset.range_eq_Ico]
@@ -317,7 +317,7 @@ theorem add_point (f : α → E) {s : Set α} {x : α} (hx : x ∈ s) (u : ℕ
congr 1
· congr 1
· apply Finset.sum_congr rfl fun i hi => ?_
- simp only [Finset.mem_Ico, zero_le', true_and_iff] at hi
+ simp only [Finset.mem_Ico, zero_le', true_and] at hi
dsimp only [w]
have A : i + 1 < N := Nat.lt_pred_iff.1 hi
have B : i < N := Nat.lt_of_succ_lt A
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/Box/Basic.lean b/Mathlib/Analysis/BoxIntegral/Box/Basic.lean
index 637895058dad4..f49c7df397731 100644
--- a/Mathlib/Analysis/BoxIntegral/Box/Basic.lean
+++ b/Mathlib/Analysis/BoxIntegral/Box/Basic.lean
@@ -140,15 +140,12 @@ theorem le_def : I ≤ J ↔ ∀ x ∈ I, x ∈ J := Iff.rfl
theorem le_TFAE : List.TFAE [I ≤ J, (I : Set (ι → ℝ)) ⊆ J,
Icc I.lower I.upper ⊆ Icc J.lower J.upper, J.lower ≤ I.lower ∧ I.upper ≤ J.upper] := by
- tfae_have 1 ↔ 2
- · exact Iff.rfl
+ tfae_have 1 ↔ 2 := Iff.rfl
tfae_have 2 → 3
- · intro h
- simpa [coe_eq_pi, closure_pi_set, lower_ne_upper] using closure_mono h
- tfae_have 3 ↔ 4
- · exact Icc_subset_Icc_iff I.lower_le_upper
+ | h => by simpa [coe_eq_pi, closure_pi_set, lower_ne_upper] using closure_mono h
+ tfae_have 3 ↔ 4 := Icc_subset_Icc_iff I.lower_le_upper
tfae_have 4 → 2
- · exact fun h x hx i ↦ Ioc_subset_Ioc (h.1 i) (h.2 i) (hx i)
+ | h, x, hx, i => Ioc_subset_Ioc (h.1 i) (h.2 i) (hx i)
tfae_finish
variable {I J}
diff --git a/Mathlib/Analysis/BoxIntegral/Box/SubboxInduction.lean b/Mathlib/Analysis/BoxIntegral/Box/SubboxInduction.lean
index c516b55504b50..f70f3e2cb58e1 100644
--- a/Mathlib/Analysis/BoxIntegral/Box/SubboxInduction.lean
+++ b/Mathlib/Analysis/BoxIntegral/Box/SubboxInduction.lean
@@ -52,7 +52,7 @@ theorem mem_splitCenterBox {s : Set ι} {y : ι → ℝ} :
simp only [splitCenterBox, mem_def, ← forall_and]
refine forall_congr' fun i ↦ ?_
dsimp only [Set.piecewise]
- split_ifs with hs <;> simp only [hs, iff_true_iff, iff_false_iff, not_lt]
+ split_ifs with hs <;> simp only [hs, iff_true, iff_false, not_lt]
exacts [⟨fun H ↦ ⟨⟨(left_lt_add_div_two.2 (I.lower_lt_upper i)).trans H.1, H.2⟩, H.1⟩,
fun H ↦ ⟨H.2, H.1.2⟩⟩,
⟨fun H ↦ ⟨⟨H.1, H.2.trans (add_div_two_lt_right.2 (I.lower_lt_upper i)).le⟩, H.2⟩,
diff --git a/Mathlib/Analysis/BoxIntegral/Integrability.lean b/Mathlib/Analysis/BoxIntegral/Integrability.lean
index 9cd4c5108bd04..a8a89c7794886 100644
--- a/Mathlib/Analysis/BoxIntegral/Integrability.lean
+++ b/Mathlib/Analysis/BoxIntegral/Integrability.lean
@@ -113,7 +113,7 @@ theorem HasIntegral.of_aeEq_zero {l : IntegrationParams} {I : Box ι} {f : (ι
have : ∀ n, ∃ U, N ⁻¹' {n} ⊆ U ∧ IsOpen U ∧ μ.restrict I U < δ n / n := fun n ↦ by
refine (N ⁻¹' {n}).exists_isOpen_lt_of_lt _ ?_
cases' n with n
- · simpa [ENNReal.div_zero (ENNReal.coe_pos.2 (δ0 _)).ne'] using measure_lt_top (μ.restrict I) _
+ · simp [ENNReal.div_zero (ENNReal.coe_pos.2 (δ0 _)).ne']
· refine (measure_mono_null ?_ hf).le.trans_lt ?_
· exact fun x hxN hxf => n.succ_ne_zero ((Eq.symm hxN).trans <| N0.2 hxf)
· simp [(δ0 _).ne']
@@ -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 a596f5d3c17d9..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) :
@@ -623,7 +623,7 @@ def IsPartition (π : Prepartition I) :=
∀ x ∈ I, ∃ J ∈ π, x ∈ J
theorem isPartition_iff_iUnion_eq {π : Prepartition I} : π.IsPartition ↔ π.iUnion = I := by
- simp_rw [IsPartition, Set.Subset.antisymm_iff, π.iUnion_subset, true_and_iff, Set.subset_def,
+ simp_rw [IsPartition, Set.Subset.antisymm_iff, π.iUnion_subset, true_and, Set.subset_def,
mem_iUnion, Box.mem_coe]
@[simp]
diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean b/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean
index 3a2ae15d2bd93..c1b1d7ea49571 100644
--- a/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean
+++ b/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean
@@ -223,7 +223,7 @@ instance : Inhabited IntegrationParams :=
⟨⊥⟩
instance : DecidableRel ((· ≤ ·) : IntegrationParams → IntegrationParams → Prop) :=
- fun _ _ => And.decidable
+ fun _ _ => inferInstanceAs (Decidable (_ ∧ _))
instance : DecidableEq IntegrationParams :=
fun _ _ => decidable_of_iff _ IntegrationParams.ext_iff.symm
diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Split.lean b/Mathlib/Analysis/BoxIntegral/Partition/Split.lean
index fa8553041f1e2..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]
@@ -149,7 +149,7 @@ def split (I : Box ι) (i : ι) (x : ℝ) : Prepartition I :=
rintro J (rfl | rfl)
exacts [Box.splitLower_le, Box.splitUpper_le])
(by
- simp only [Finset.coe_insert, Finset.coe_singleton, true_and_iff, Set.mem_singleton_iff,
+ simp only [Finset.coe_insert, Finset.coe_singleton, true_and, Set.mem_singleton_iff,
pairwise_insert_of_symmetric symmetric_disjoint, pairwise_singleton]
rintro J rfl -
exact I.disjoint_splitLower_splitUpper i x)
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 ced5d17785402..4a903ec4b4fda 100644
--- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean
+++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean
@@ -23,7 +23,7 @@ import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unique
elements in an `ℝ`-algebra with a continuous functional calculus for selfadjoint elements,
where every element has compact spectrum, and where nonnegative elements have nonnegative
spectrum. In particular, this includes unital C⋆-algebras over `ℝ`.
-* `CStarRing.instNonnegSpectrumClass`: In a unital C⋆-algebra over `ℂ` which is also a
+* `CStarAlgebra.instNonnegSpectrumClass`: In a unital C⋆-algebra over `ℂ` which is also a
`StarOrderedRing`, the spectrum of a nonnegative element is nonnegative.
## Tags
@@ -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
/-!
@@ -218,7 +232,7 @@ lemma QuasispectrumRestricts.isSelfAdjoint (a : A) (ha : QuasispectrumRestricts
instance IsSelfAdjoint.instNonUnitalContinuousFunctionalCalculus :
NonUnitalContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop) :=
QuasispectrumRestricts.cfc (q := IsStarNormal) (p := IsSelfAdjoint) Complex.reCLM
- Complex.isometry_ofReal.uniformEmbedding (.zero _)
+ Complex.isometry_ofReal.isUniformEmbedding (.zero _)
(fun _ ↦ isSelfAdjoint_iff_isStarNormal_and_quasispectrumRestricts)
end SelfAdjointNonUnital
@@ -264,7 +278,7 @@ lemma SpectrumRestricts.isSelfAdjoint (a : A) (ha : SpectrumRestricts a Complex.
instance IsSelfAdjoint.instContinuousFunctionalCalculus :
ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop) :=
SpectrumRestricts.cfc (q := IsStarNormal) (p := IsSelfAdjoint) Complex.reCLM
- Complex.isometry_ofReal.uniformEmbedding (.zero _)
+ Complex.isometry_ofReal.isUniformEmbedding (.zero _)
(fun _ ↦ isSelfAdjoint_iff_isStarNormal_and_spectrumRestricts)
lemma IsSelfAdjoint.spectrum_nonempty {A : Type*} [Ring A] [StarRing A]
@@ -313,7 +327,7 @@ open NNReal in
instance Nonneg.instNonUnitalContinuousFunctionalCalculus :
NonUnitalContinuousFunctionalCalculus ℝ≥0 (fun x : A ↦ 0 ≤ x) :=
QuasispectrumRestricts.cfc (q := IsSelfAdjoint) ContinuousMap.realToNNReal
- uniformEmbedding_subtype_val le_rfl
+ isUniformEmbedding_subtype_val le_rfl
(fun _ ↦ nonneg_iff_isSelfAdjoint_and_quasispectrumRestricts)
open NNReal in
@@ -359,7 +373,7 @@ open NNReal in
instance Nonneg.instContinuousFunctionalCalculus :
ContinuousFunctionalCalculus ℝ≥0 (fun x : A ↦ 0 ≤ x) :=
SpectrumRestricts.cfc (q := IsSelfAdjoint) ContinuousMap.realToNNReal
- uniformEmbedding_subtype_val le_rfl (fun _ ↦ nonneg_iff_isSelfAdjoint_and_spectrumRestricts)
+ isUniformEmbedding_subtype_val le_rfl (fun _ ↦ nonneg_iff_isSelfAdjoint_and_spectrumRestricts)
end Nonneg
@@ -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,27 +504,25 @@ 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 CStarRing.instNonnegSpectrumClass : NonnegSpectrumClass ℝ 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
open ComplexOrder in
-instance CStarRing.instNonnegSpectrumClassComplexUnital : NonnegSpectrumClass ℂ A where
+instance CStarAlgebra.instNonnegSpectrumClassComplexUnital : NonnegSpectrumClass ℂ A where
quasispectrum_nonneg_of_nonneg a ha x := by
rw [mem_quasispectrum_iff]
refine (Or.elim · ge_of_eq fun hx ↦ ?_)
@@ -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.
@@ -531,7 +541,7 @@ selfadjoint and has nonnegative spectrum.
This is not declared as an instance because one may already have a partial order with better
definitional properties. However, it can be useful to invoke this as an instance in proofs. -/
@[reducible]
-def CStarRing.spectralOrder : PartialOrder A where
+def CStarAlgebra.spectralOrder : PartialOrder A where
le x y := IsSelfAdjoint (y - x) ∧ SpectrumRestricts (y - x) ContinuousMap.realToNNReal
le_refl := by
simp only [sub_self, IsSelfAdjoint.zero, true_and, forall_const]
@@ -544,9 +554,9 @@ def CStarRing.spectralOrder : PartialOrder A where
le_trans x y z hxy hyz :=
⟨by simpa using hyz.1.add hxy.1, by simpa using hyz.2.nnreal_add hyz.1 hxy.1 hxy.2⟩
-/-- The `CStarRing.spectralOrder` on a unital C⋆-algebra is a `StarOrderedRing`. -/
-lemma CStarRing.spectralOrderedRing : @StarOrderedRing A _ (CStarRing.spectralOrder A) _ :=
- let _ := CStarRing.spectralOrder A
+/-- The `CStarAlgebra.spectralOrder` on a unital C⋆-algebra is a `StarOrderedRing`. -/
+lemma CStarAlgebra.spectralOrderedRing : @StarOrderedRing A _ (CStarAlgebra.spectralOrder A) _ :=
+ let _ := CStarAlgebra.spectralOrder A
{ le_iff := by
intro x y
constructor
@@ -557,7 +567,7 @@ lemma CStarRing.spectralOrderedRing : @StarOrderedRing A _ (CStarRing.spectralOr
· 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 CStarRing.spectralOrderedRing : @StarOrderedRing A _ (CStarRing.spectralOr
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]
-instance CStarRing.instNonnegSpectrumClass' : NonnegSpectrumClass ℝ A where
+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 _ := CStarRing.spectralOrder (Unitization ℂ A)
- have := CStarRing.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
@@ -605,14 +614,14 @@ variable {A : Type*} [TopologicalSpace A] [Ring A] [StarRing A] [Algebra ℂ A]
lemma cfcHom_real_eq_restrict {a : A} (ha : IsSelfAdjoint a) :
cfcHom ha = ha.spectrumRestricts.starAlgHom (cfcHom ha.isStarNormal) (f := Complex.reCLM) :=
- ha.spectrumRestricts.cfcHom_eq_restrict Complex.isometry_ofReal.uniformEmbedding
+ ha.spectrumRestricts.cfcHom_eq_restrict _ Complex.isometry_ofReal.isUniformEmbedding
ha ha.isStarNormal
lemma cfc_real_eq_complex {a : A} (f : ℝ → ℝ) (ha : IsSelfAdjoint a := by cfc_tac) :
cfc f a = cfc (fun x ↦ f x.re : ℂ → ℂ) a := by
replace ha : IsSelfAdjoint a := ha -- hack to avoid issues caused by autoParam
exact ha.spectrumRestricts.cfc_eq_restrict (f := Complex.reCLM)
- Complex.isometry_ofReal.uniformEmbedding ha ha.isStarNormal f
+ Complex.isometry_ofReal.isUniformEmbedding ha ha.isStarNormal f
end RealEqComplex
@@ -626,14 +635,14 @@ variable {A : Type*} [TopologicalSpace A] [NonUnitalRing A] [StarRing A] [Module
lemma cfcₙHom_real_eq_restrict {a : A} (ha : IsSelfAdjoint a) :
cfcₙHom ha = (ha.quasispectrumRestricts.2).nonUnitalStarAlgHom (cfcₙHom ha.isStarNormal)
(f := Complex.reCLM) :=
- ha.quasispectrumRestricts.2.cfcₙHom_eq_restrict Complex.isometry_ofReal.uniformEmbedding
+ ha.quasispectrumRestricts.2.cfcₙHom_eq_restrict _ Complex.isometry_ofReal.isUniformEmbedding
ha ha.isStarNormal
lemma cfcₙ_real_eq_complex {a : A} (f : ℝ → ℝ) (ha : IsSelfAdjoint a := by cfc_tac) :
cfcₙ f a = cfcₙ (fun x ↦ f x.re : ℂ → ℂ) a := by
replace ha : IsSelfAdjoint a := ha -- hack to avoid issues caused by autoParam
exact ha.quasispectrumRestricts.2.cfcₙ_eq_restrict (f := Complex.reCLM)
- Complex.isometry_ofReal.uniformEmbedding ha ha.isStarNormal f
+ Complex.isometry_ofReal.isUniformEmbedding ha ha.isStarNormal f
end RealEqComplexNonUnital
@@ -650,13 +659,13 @@ variable {A : Type*} [TopologicalSpace A] [Ring A] [PartialOrder A] [StarRing A]
lemma cfcHom_nnreal_eq_restrict {a : A} (ha : 0 ≤ a) :
cfcHom ha = (SpectrumRestricts.nnreal_of_nonneg ha).starAlgHom
(cfcHom (IsSelfAdjoint.of_nonneg ha)) := by
- apply (SpectrumRestricts.nnreal_of_nonneg ha).cfcHom_eq_restrict uniformEmbedding_subtype_val
+ apply (SpectrumRestricts.nnreal_of_nonneg ha).cfcHom_eq_restrict _ isUniformEmbedding_subtype_val
lemma cfc_nnreal_eq_real {a : A} (f : ℝ≥0 → ℝ≥0) (ha : 0 ≤ a := by cfc_tac) :
cfc f a = cfc (fun x ↦ f x.toNNReal : ℝ → ℝ) a := by
replace ha : 0 ≤ a := ha -- hack to avoid issues caused by autoParam
- apply (SpectrumRestricts.nnreal_of_nonneg ha).cfc_eq_restrict
- uniformEmbedding_subtype_val ha (.of_nonneg ha)
+ apply (SpectrumRestricts.nnreal_of_nonneg ha).cfc_eq_restrict _
+ isUniformEmbedding_subtype_val ha (.of_nonneg ha)
end NNRealEqReal
@@ -674,15 +683,54 @@ variable {A : Type*} [TopologicalSpace A] [NonUnitalRing A] [PartialOrder A] [St
lemma cfcₙHom_nnreal_eq_restrict {a : A} (ha : 0 ≤ a) :
cfcₙHom ha = (QuasispectrumRestricts.nnreal_of_nonneg ha).nonUnitalStarAlgHom
(cfcₙHom (IsSelfAdjoint.of_nonneg ha)) := by
- apply (QuasispectrumRestricts.nnreal_of_nonneg ha).cfcₙHom_eq_restrict
- uniformEmbedding_subtype_val
+ apply (QuasispectrumRestricts.nnreal_of_nonneg ha).cfcₙHom_eq_restrict _
+ isUniformEmbedding_subtype_val
lemma cfcₙ_nnreal_eq_real {a : A} (f : ℝ≥0 → ℝ≥0) (ha : 0 ≤ a := by cfc_tac) :
cfcₙ f a = cfcₙ (fun x ↦ f x.toNNReal : ℝ → ℝ) a := by
replace ha : 0 ≤ a := ha -- hack to avoid issues caused by autoParam
- apply (QuasispectrumRestricts.nnreal_of_nonneg ha).cfcₙ_eq_restrict
- uniformEmbedding_subtype_val ha (.of_nonneg ha)
+ apply (QuasispectrumRestricts.nnreal_of_nonneg ha).cfcₙ_eq_restrict _
+ isUniformEmbedding_subtype_val ha (.of_nonneg ha)
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 6a52fbf1fd1e4..3d40d1c59a022 100644
--- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/NonUnital.lean
+++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/NonUnital.lean
@@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jireh Loreaux
-/
import Mathlib.Algebra.Algebra.Quasispectrum
-import Mathlib.Topology.ContinuousFunction.Compact
-import Mathlib.Topology.ContinuousFunction.ContinuousMapZero
+import Mathlib.Topology.ContinuousMap.Compact
+import Mathlib.Topology.ContinuousMap.ContinuousMapZero
import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unital
import Mathlib.Topology.UniformSpace.CompactConvergence
@@ -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⟩)
@@ -421,7 +439,7 @@ lemma cfcₙ_comp (g f : R → R) (a : A)
ext
simp
rw [cfcₙ_apply .., cfcₙ_apply f a,
- cfcₙ_apply _ (by convert hg) (ha := cfcₙHom_predicate (show p a from ha) _) ,
+ cfcₙ_apply _ _ (by convert hg) (ha := cfcₙHom_predicate (show p a from ha) _),
← cfcₙHom_comp _ _]
swap
· exact ⟨.mk _ <| hf.restrict.codRestrict fun x ↦ by rw [sp_eq]; use x.1; simp, Subtype.ext hf0⟩
@@ -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.uniformEmbedding ⟨?_⟩).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 b1a6a94c4d085..bb02c5b46fae0 100644
--- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean
+++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean
@@ -7,14 +7,14 @@ Authors: Frédéric Dupuis
import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Instances
import Mathlib.Analysis.CStarAlgebra.Unitization
import Mathlib.Analysis.SpecialFunctions.ContinuousFunctionalCalculus.Rpow
-import Mathlib.Topology.ContinuousFunction.StarOrdered
+import Mathlib.Topology.ContinuousMap.StarOrdered
/-! # Facts about star-ordered rings that depend on the continuous functional calculus
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
@@ -24,39 +24,77 @@ the spectral order.
C⋆-algebra.
* `mul_star_le_algebraMap_norm_sq` and `star_mul_le_algebraMap_norm_sq`, which give similar
statements for `a * star a` and `star a * a`.
-* `CStarRing.norm_le_norm_of_nonneg_of_le`: in a non-unital C⋆-algebra, if `0 ≤ a ≤ b`, then
+* `CStarAlgebra.norm_le_norm_of_nonneg_of_le`: in a non-unital C⋆-algebra, if `0 ≤ a ≤ b`, then
`‖a‖ ≤ ‖b‖`.
-* `CStarRing.conjugate_le_norm_smul`: in a non-unital C⋆-algebra, we have that
+* `CStarAlgebra.conjugate_le_norm_smul`: in a non-unital C⋆-algebra, we have that
`star a * b * a ≤ ‖b‖ • (star a * a)` (and a primed version for the `a * b * star a` case).
-* `CStarRing.inv_le_inv_iff`: in a unital C⋆-algebra, `b⁻¹ ≤ a⁻¹` iff `a ≤ b`.
+* `CStarAlgebra.inv_le_inv_iff`: in a unital C⋆-algebra, `b⁻¹ ≤ a⁻¹` iff `a ≤ b`.
## Tags
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) := CStarRing.spectralOrder _
+instance instPartialOrder : PartialOrder A⁺¹ :=
+ CStarAlgebra.spectralOrder _
-instance instStarOrderedRing : StarOrderedRing (Unitization ℂ A) := CStarRing.spectralOrderedRing _
+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 ⟨?_, ?_⟩
@@ -64,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`.
@@ -83,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
@@ -124,11 +165,13 @@ lemma IsSelfAdjoint.neg_algebraMap_norm_le_self {a : A} (ha : IsSelfAdjoint a :=
exact IsSelfAdjoint.le_algebraMap_norm_self (neg ha)
exact neg_le.mp this
-lemma CStarRing.mul_star_le_algebraMap_norm_sq {a : A} : a * star a ≤ algebraMap ℝ A (‖a‖ ^ 2) := by
+lemma CStarAlgebra.mul_star_le_algebraMap_norm_sq {a : A} :
+ a * star a ≤ algebraMap ℝ A (‖a‖ ^ 2) := by
have : a * star a ≤ algebraMap ℝ A ‖a * star a‖ := IsSelfAdjoint.le_algebraMap_norm_self
rwa [CStarRing.norm_self_mul_star, ← pow_two] at this
-lemma CStarRing.star_mul_le_algebraMap_norm_sq {a : A} : star a * a ≤ algebraMap ℝ A (‖a‖ ^ 2) := by
+lemma CStarAlgebra.star_mul_le_algebraMap_norm_sq {a : A} :
+ star a * a ≤ algebraMap ℝ A (‖a‖ ^ 2) := by
have : star a * a ≤ algebraMap ℝ A ‖star a * a‖ := IsSelfAdjoint.le_algebraMap_norm_self
rwa [CStarRing.norm_star_mul_self, ← pow_two] at this
@@ -138,7 +181,7 @@ lemma IsSelfAdjoint.toReal_spectralRadius_eq_norm {a : A} (ha : IsSelfAdjoint a)
(spectralRadius ℝ a).toReal = ‖a‖ := by
simp [ha.spectrumRestricts.spectralRadius_eq, ha.spectralRadius_eq_nnnorm]
-namespace CStarRing
+namespace CStarAlgebra
lemma norm_or_neg_norm_mem_spectrum [Nontrivial A] {a : A}
(ha : IsSelfAdjoint a := by cfc_tac) : ‖a‖ ∈ spectrum ℝ a ∨ -‖a‖ ∈ spectrum ℝ a := by
@@ -189,7 +232,7 @@ lemma nnnorm_le_natCast_iff_of_nonneg (a : A) (n : ℕ) (ha : 0 ≤ a := by cfc_
‖a‖₊ ≤ n ↔ a ≤ n := by
simpa using nnnorm_le_iff_of_nonneg a n
-end CStarRing
+end CStarAlgebra
section Inv
@@ -209,15 +252,13 @@ lemma CFC.conjugate_rpow_neg_one_half {a : A} (h₀ : IsUnit a) (ha : 0 ≤ a :=
/-- In a unital C⋆-algebra, if `a` is nonnegative and invertible, and `a ≤ b`, then `b` is
invertible. -/
-lemma CStarRing.isUnit_of_le {a b : A} (h₀ : IsUnit a) (ha : 0 ≤ a := by cfc_tac)
+lemma CStarAlgebra.isUnit_of_le {a b : A} (h₀ : IsUnit a) (ha : 0 ≤ a := by cfc_tac)
(hab : a ≤ b) : IsUnit b := 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
@@ -230,7 +271,7 @@ lemma le_iff_norm_sqrt_mul_rpow {a b : A} (hbu : IsUnit b) (ha : 0 ≤ a) (hb :
rw [← sq_le_one_iff (norm_nonneg _), sq, ← CStarRing.norm_star_mul_self, star_mul,
IsSelfAdjoint.of_nonneg sqrt_nonneg, IsSelfAdjoint.of_nonneg rpow_nonneg,
← mul_assoc, mul_assoc _ _ (sqrt a), sqrt_mul_sqrt_self a,
- CStarRing.norm_le_one_iff_of_nonneg _ hbab]
+ CStarAlgebra.norm_le_one_iff_of_nonneg _ hbab]
refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩
· calc
_ ≤ ↑b ^ (-(1 / 2) : ℝ) * (b : A) * ↑b ^ (-(1 / 2) : ℝ) :=
@@ -252,8 +293,10 @@ lemma le_iff_norm_sqrt_mul_sqrt_inv {a : A} {b : Aˣ} (ha : 0 ≤ a) (hb : 0 ≤
CFC.rpow_rpow (b : A) _ _ (by simp) (by norm_num), le_iff_norm_sqrt_mul_rpow b.isUnit ha hb]
norm_num
+namespace CStarAlgebra
+
/-- In a unital C⋆-algebra, if `0 ≤ a ≤ b` and `a` and `b` are units, then `b⁻¹ ≤ a⁻¹`. -/
-protected lemma CStarRing.inv_le_inv {a b : Aˣ} (ha : 0 ≤ (a : A))
+protected lemma inv_le_inv {a b : Aˣ} (ha : 0 ≤ (a : A))
(hab : (a : A) ≤ b) : (↑b⁻¹ : A) ≤ a⁻¹ := by
have hb := ha.trans hab
have hb_inv : (0 : A) ≤ b⁻¹ := inv_nonneg_of_nonneg b hb
@@ -267,55 +310,55 @@ protected lemma CStarRing.inv_le_inv {a b : Aˣ} (ha : 0 ≤ (a : A))
/-- In a unital C⋆-algebra, if `0 ≤ a` and `0 ≤ b` and `a` and `b` are units, then `a⁻¹ ≤ b⁻¹`
if and only if `b ≤ a`. -/
-protected lemma CStarRing.inv_le_inv_iff {a b : Aˣ} (ha : 0 ≤ (a : A)) (hb : 0 ≤ (b : A)) :
+protected lemma inv_le_inv_iff {a b : Aˣ} (ha : 0 ≤ (a : A)) (hb : 0 ≤ (b : A)) :
(↑a⁻¹ : A) ≤ b⁻¹ ↔ (b : A) ≤ a :=
- ⟨CStarRing.inv_le_inv (inv_nonneg_of_nonneg a ha), CStarRing.inv_le_inv hb⟩
+ ⟨CStarAlgebra.inv_le_inv (inv_nonneg_of_nonneg a ha), CStarAlgebra.inv_le_inv hb⟩
-lemma CStarRing.inv_le_iff {a b : Aˣ} (ha : 0 ≤ (a : A)) (hb : 0 ≤ (↑b : A)) :
+lemma inv_le_iff {a b : Aˣ} (ha : 0 ≤ (a : A)) (hb : 0 ≤ (↑b : A)) :
(↑a⁻¹ : A) ≤ b ↔ (↑b⁻¹ : A) ≤ a := by
- simpa using CStarRing.inv_le_inv_iff ha (inv_nonneg_of_nonneg b hb)
+ simpa using CStarAlgebra.inv_le_inv_iff ha (inv_nonneg_of_nonneg b hb)
-lemma CStarRing.le_inv_iff {a b : Aˣ} (ha : 0 ≤ (a : A)) (hb : 0 ≤ (↑b : A)) :
+lemma le_inv_iff {a b : Aˣ} (ha : 0 ≤ (a : A)) (hb : 0 ≤ (↑b : A)) :
a ≤ (↑b⁻¹ : A) ↔ b ≤ (↑a⁻¹ : A) := by
- simpa using CStarRing.inv_le_inv_iff (inv_nonneg_of_nonneg a ha) hb
+ simpa using CStarAlgebra.inv_le_inv_iff (inv_nonneg_of_nonneg a ha) hb
-lemma CStarRing.one_le_inv_iff_le_one {a : Aˣ} (ha : 0 ≤ (a : A)) :
+lemma one_le_inv_iff_le_one {a : Aˣ} (ha : 0 ≤ (a : A)) :
1 ≤ (↑a⁻¹ : A) ↔ a ≤ 1 := by
- simpa using CStarRing.le_inv_iff (a := 1) (by simp) ha
+ simpa using CStarAlgebra.le_inv_iff (a := 1) (by simp) ha
-lemma CStarRing.inv_le_one_iff_one_le {a : Aˣ} (ha : 0 ≤ (a : A)) :
+lemma inv_le_one_iff_one_le {a : Aˣ} (ha : 0 ≤ (a : A)) :
(↑a⁻¹ : A) ≤ 1 ↔ 1 ≤ a := by
- simpa using CStarRing.inv_le_iff ha (b := 1) (by simp)
+ simpa using CStarAlgebra.inv_le_iff ha (b := 1) (by simp)
-lemma CStarRing.inv_le_one {a : Aˣ} (ha : 1 ≤ a) : (↑a⁻¹ : A) ≤ 1 :=
- CStarRing.inv_le_one_iff_one_le (zero_le_one.trans ha) |>.mpr ha
+lemma inv_le_one {a : Aˣ} (ha : 1 ≤ a) : (↑a⁻¹ : A) ≤ 1 :=
+ CStarAlgebra.inv_le_one_iff_one_le (zero_le_one.trans ha) |>.mpr ha
-lemma CStarRing.le_one_of_one_le_inv {a : Aˣ} (ha : 1 ≤ (↑a⁻¹ : A)) : (a : A) ≤ 1 := by
- simpa using CStarRing.inv_le_one ha
+lemma le_one_of_one_le_inv {a : Aˣ} (ha : 1 ≤ (↑a⁻¹ : A)) : (a : A) ≤ 1 := by
+ simpa using CStarAlgebra.inv_le_one ha
-lemma CStarRing.rpow_neg_one_le_rpow_neg_one {a b : A} (ha : 0 ≤ a) (hab : a ≤ b) (hau : IsUnit a) :
+lemma rpow_neg_one_le_rpow_neg_one {a b : A} (ha : 0 ≤ a) (hab : a ≤ b) (hau : IsUnit a) :
b ^ (-1 : ℝ) ≤ a ^ (-1 : ℝ) := by
lift b to Aˣ using isUnit_of_le hau ha hab
lift a to Aˣ using hau
rw [rpow_neg_one_eq_inv a ha, rpow_neg_one_eq_inv b (ha.trans hab)]
- exact CStarRing.inv_le_inv ha hab
+ exact CStarAlgebra.inv_le_inv ha hab
-lemma CStarRing.rpow_neg_one_le_one {a : A} (ha : 1 ≤ a) : a ^ (-1 : ℝ) ≤ 1 := by
+lemma rpow_neg_one_le_one {a : A} (ha : 1 ≤ a) : a ^ (-1 : ℝ) ≤ 1 := by
lift a to Aˣ using isUnit_of_le isUnit_one zero_le_one ha
rw [rpow_neg_one_eq_inv a (zero_le_one.trans ha)]
exact inv_le_one ha
+end CStarAlgebra
+
end Inv
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 CStarRing
+namespace CStarAlgebra
open ComplexOrder in
instance instNonnegSpectrumClassComplexNonUnital : NonnegSpectrumClass ℂ A where
@@ -325,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])
@@ -343,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]
@@ -363,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
@@ -375,6 +422,38 @@ lemma isClosed_nonneg : IsClosed {a : A | 0 ≤ a} := by
refine isClosed_eq ?_ ?_ |>.inter <| isClosed_le ?_ ?_
all_goals fun_prop
-end CStarRing
+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 9a2bf73293ea6..195b717b64044 100644
--- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean
+++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean
@@ -82,28 +82,37 @@ 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)
- (halg : UniformEmbedding (algebraMap R S)) :
- ClosedEmbedding (h.starAlgHom φ) :=
- hφ.comp <| UniformEmbedding.toClosedEmbedding <| .comp
- (ContinuousMap.uniformEmbedding_comp _ halg)
- (UniformEquiv.arrowCongr h.homeomorph.symm (.refl _) |>.uniformEmbedding)
+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)) :
+ 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
`ContinuousFunctionalCalculus R p`. -/
-protected theorem cfc (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S)) (h0 : p 0)
+protected theorem cfc (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) (h0 : p 0)
(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
@@ -133,14 +142,14 @@ protected theorem cfc (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S)) (
variable [ContinuousFunctionalCalculus R p] [UniqueContinuousFunctionalCalculus R A]
-lemma cfcHom_eq_restrict (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S))
+lemma cfcHom_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S))
{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 : UniformEmbedding (algebraMap R S)) {a : A} (hpa : p a)
+lemma cfc_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) {a : A} (hpa : p a)
(hqa : q a) (h : SpectrumRestricts a f) (g : R → R) :
cfc g a = cfc (fun x ↦ algebraMap R S (g (f x))) a := by
by_cases hg : ContinuousOn g (spectrum R a)
@@ -151,9 +160,9 @@ lemma cfc_eq_restrict (f : C(S, R)) (halg : UniformEmbedding (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,14 +225,17 @@ 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)
- (halg : UniformEmbedding (algebraMap R S)) :
- ClosedEmbedding (h.nonUnitalStarAlgHom φ) := by
+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)) :
+ IsClosedEmbedding (h.nonUnitalStarAlgHom φ) := by
have : h.homeomorph.symm 0 = 0 := Subtype.ext (map_zero <| algebraMap _ _)
- refine hφ.comp <| UniformEmbedding.toClosedEmbedding <| .comp
- (ContinuousMapZero.uniformEmbedding_comp _ halg)
- (UniformEquiv.arrowCongrLeft₀ h.homeomorph.symm this |>.uniformEmbedding)
+ 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]
@@ -231,16 +243,20 @@ variable [IsScalarTower R A A] [SMulCommClass R A A]
characterized by: `q a` and the quasispectrum of `a` restricts to the scalar subring `R` via
`f : C(S, R)`, then we can get a restricted functional calculus
`NonUnitalContinuousFunctionalCalculus R p`. -/
-protected theorem cfc (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S)) (h0 : p 0)
+protected theorem cfc (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) (h0 : p 0)
(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
@@ -275,15 +291,15 @@ protected theorem cfc (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S)) (
variable [NonUnitalContinuousFunctionalCalculus R p]
variable [UniqueNonUnitalContinuousFunctionalCalculus R A]
-lemma cfcₙHom_eq_restrict (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S)) {a : A}
+lemma cfcₙHom_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) {a : A}
(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 : UniformEmbedding (algebraMap R S)) {a : A} (hpa : p a)
- (hqa : q a) (h : QuasispectrumRestricts a f) (g : R → R) :
+lemma cfcₙ_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) {a : A}
+ (hpa : p a) (hqa : q a) (h : QuasispectrumRestricts a f) (g : R → R) :
cfcₙ g a = cfcₙ (fun x ↦ algebraMap R S (g (f x))) a := by
by_cases hg : ContinuousOn g (σₙ R a) ∧ g 0 = 0
· obtain ⟨hg, hg0⟩ := hg
@@ -296,9 +312,9 @@ lemma cfcₙ_eq_restrict (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S)
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 d2a626a9dded0..0643b90789114 100644
--- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unique.lean
+++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unique.lean
@@ -5,7 +5,7 @@ Authors: Jireh Loreaux
-/
import Mathlib.Analysis.Normed.Algebra.Spectrum
import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.NonUnital
-import Mathlib.Topology.ContinuousFunction.StoneWeierstrass
+import Mathlib.Topology.ContinuousMap.StoneWeierstrass
/-!
# Uniqueness of the continuous functional calculus
@@ -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ψ
@@ -428,14 +428,14 @@ open scoped ContinuousMapZero
variable {F R S A B : Type*} {p : A → Prop} {q : B → Prop}
[CommSemiring R] [Nontrivial R] [StarRing R] [MetricSpace R] [TopologicalSemiring R]
[ContinuousStar R] [CommRing S] [Algebra R S]
- [Ring A] [StarRing A] [TopologicalSpace A] [Module R A]
+ [NonUnitalRing A] [StarRing A] [TopologicalSpace A] [Module R A]
[IsScalarTower R A A] [SMulCommClass R A A]
- [Ring B] [StarRing B] [TopologicalSpace B] [Module R B]
+ [NonUnitalRing B] [StarRing B] [TopologicalSpace B] [Module R B]
[IsScalarTower R B B] [SMulCommClass R B B]
[Module S A] [Module S B] [IsScalarTower R S A] [IsScalarTower R S B]
[NonUnitalContinuousFunctionalCalculus R p] [NonUnitalContinuousFunctionalCalculus R q]
[UniqueNonUnitalContinuousFunctionalCalculus R B] [FunLike F A B] [NonUnitalAlgHomClass F S A B]
- [NonUnitalStarAlgHomClass F S A B]
+ [StarHomClass F A B]
include S in
/-- Non-unital star algebra homomorphisms commute with the non-unital continuous functional
@@ -484,7 +484,7 @@ variable {F R S A B : Type*} {p : A → Prop} {q : B → Prop}
[CommSemiring S] [Algebra R S] [Algebra S A] [Algebra S B] [IsScalarTower R S A]
[IsScalarTower R S B] [ContinuousFunctionalCalculus R p] [ContinuousFunctionalCalculus R q]
[UniqueContinuousFunctionalCalculus R B] [FunLike F A B] [AlgHomClass F S A B]
- [StarAlgHomClass F S A B]
+ [StarHomClass F A B]
include S in
/-- Star algebra homomorphisms commute with the continuous functional calculus. -/
diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean
index e64b9cdf7d629..6e8de01f4cc2d 100644
--- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean
+++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean
@@ -7,7 +7,7 @@ import Mathlib.Algebra.Algebra.Quasispectrum
import Mathlib.Algebra.Algebra.Spectrum
import Mathlib.Algebra.Order.Star.Basic
import Mathlib.Topology.Algebra.Polynomial
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.Topology.ContinuousMap.Algebra
import Mathlib.Tactic.ContinuousFunctionalCalculus
/-!
@@ -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⟩)
@@ -723,7 +743,7 @@ noncomputable def cfcUnits (hf' : ∀ x ∈ spectrum R a, f x ≠ 0)
lemma cfcUnits_pow (hf' : ∀ x ∈ spectrum R a, f x ≠ 0) (n : ℕ)
(hf : ContinuousOn f (spectrum R a) := by cfc_cont_tac) (ha : p a := by cfc_tac) :
(cfcUnits f a hf') ^ n =
- cfcUnits (forall₂_imp (fun _ _ ↦ pow_ne_zero n) hf') (hf := hf.pow n) := by
+ cfcUnits _ _ (forall₂_imp (fun _ _ ↦ pow_ne_zero n) hf') (hf := hf.pow n) := by
ext
cases n with
| zero => simp [cfc_const_one R a]
@@ -778,7 +798,7 @@ lemma cfcUnits_zpow (hf' : ∀ x ∈ spectrum R a, f x ≠ 0) (n : ℤ)
| negSucc n =>
simp only [zpow_negSucc, ← inv_pow]
ext
- exact cfc_pow (hf := hf.inv₀ hf') _ |>.symm
+ exact cfc_pow (hf := hf.inv₀ hf') .. |>.symm
lemma cfc_zpow (a : Aˣ) (n : ℤ) (ha : p a := by cfc_tac) :
cfc (fun x : R ↦ x ^ n) (a : A) = ↑(a ^ n) := by
@@ -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 c3e2791a52a09..88aeab7e08956 100644
--- a/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean
+++ b/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean
@@ -4,13 +4,14 @@ 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.ContinuousFunction.Units
-import Mathlib.Topology.ContinuousFunction.Compact
+import Mathlib.Topology.ContinuousMap.Units
+import Mathlib.Topology.ContinuousMap.Compact
import Mathlib.Topology.Algebra.Algebra
-import Mathlib.Topology.ContinuousFunction.Ideals
-import Mathlib.Topology.ContinuousFunction.StoneWeierstrass
+import Mathlib.Topology.ContinuousMap.Ideals
+import Mathlib.Topology.ContinuousMap.StoneWeierstrass
/-!
# Gelfand Duality
@@ -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
new file mode 100644
index 0000000000000..86e747a27affb
--- /dev/null
+++ b/Mathlib/Analysis/CStarAlgebra/Hom.lean
@@ -0,0 +1,78 @@
+/-
+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
+
+/-! # Properties of C⋆-algebra homomorphisms
+
+Here we collect properties of C⋆-algebra homomorphisms.
+
+## Main declarations
+
++ `NonUnitalStarAlgHom.norm_map`: A non-unital star algebra monomorphism of complex C⋆-algebras
+ is isometric.
+-/
+
+open CStarAlgebra in
+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
+ have h_spec := AlgHom.spectrum_apply_subset ((φ : A →⋆ₐ[ℂ] B).restrictScalars ℝ) a
+ refine Set.eq_of_subset_of_subset h_spec fun x hx ↦ ?_
+ /- we prove the reverse inclusion by contradiction, so assume that `x ∈ spectrum ℝ a`, but
+ `x ∉ spectrum ℝ (φ a)`. Then by Urysohn's lemma we can get a function for which `f x = 1`, but
+ `f = 0` on `spectrum ℝ a`. -/
+ by_contra hx'
+ obtain ⟨f, h_eqOn, h_eqOn_x, -⟩ := exists_continuous_zero_one_of_isClosed
+ (spectrum.isClosed (𝕜 := ℝ) (φ a)) (isClosed_singleton (x := x)) <| by simpa
+ /- it suffices to show that `φ (f a) = 0`, for if so, then `f a = 0` by injectivity of `φ`, and
+ hence `f = 0` on `spectrum ℝ a`, contradicting the fact that `f x = 1`. -/
+ suffices φ (cfc f a) = 0 by
+ rw [map_eq_zero_iff φ hφ, ← cfc_zero ℝ a, cfc_eq_cfc_iff_eqOn] at this
+ exact zero_ne_one <| calc
+ 0 = f x := (this hx).symm
+ _ = 1 := h_eqOn_x <| Set.mem_singleton x
+ /- Finally, `φ (f a) = f (φ a) = 0`, where the last equality follows since `f = 0` on
+ `spectrum ℝ (φ a)`. -/
+ calc φ (cfc f a) = cfc f (φ a) := StarAlgHomClass.map_cfc φ f a
+ _ = cfc (0 : ℝ → ℝ) (φ a) := cfc_congr h_eqOn
+ _ = 0 := by simp
+
+namespace NonUnitalStarAlgHom
+
+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
+/-- A non-unital star algebra monomorphism of complex C⋆-algebras is isometric. -/
+lemma norm_map (φ : F) (hφ : Function.Injective φ) (a : A) : ‖φ a‖ = ‖a‖ := by
+ /- Since passing to the unitization is functorial, and it is an isometric embedding, we may assume
+ that `φ` is a unital star algebra monomorphism and that `A` and `B` are unital C⋆-algebras. -/
+ suffices ∀ {ψ : Unitization ℂ A →⋆ₐ[ℂ] Unitization ℂ B} (_ : Function.Injective ψ)
+ (a : Unitization ℂ A), ‖ψ a‖ = ‖a‖ by
+ simpa [norm_inr] using this (starMap_injective (φ := (φ : A →⋆ₙₐ[ℂ] B)) hφ) a
+ intro ψ hψ a
+ -- to show `‖ψ a‖ = ‖a‖`, by the C⋆-property it suffices to show `‖ψ (star a * a)‖ = ‖star a * a‖`
+ rw [← sq_eq_sq (by positivity) (by positivity)]
+ simp only [sq, ← CStarRing.norm_star_mul_self, ← map_star, ← map_mul]
+ /- since `star a * a` is selfadjoint, it has the same `ℝ`-spectrum as `ψ (star a * a)`.
+ Since the spectral radius over `ℝ` coincides with the norm, `‖ψ (star a * a)‖ = ‖star a * a‖`. -/
+ have ha : IsSelfAdjoint (star a * a) := .star_mul_self a
+ calc ‖ψ (star a * a)‖ = (spectralRadius ℝ (ψ (star a * a))).toReal :=
+ ha.map ψ |>.toReal_spectralRadius_eq_norm.symm
+ _ = (spectralRadius ℝ (star a * a)).toReal := by
+ simp only [spectralRadius, ha.map_spectrum_real ψ hψ]
+ _ = ‖star a * a‖ := ha.toReal_spectralRadius_eq_norm
+
+/-- A non-unital star algebra monomorphism of complex C⋆-algebras is isometric. -/
+lemma nnnorm_map (φ : F) (hφ : Function.Injective φ) (a : A) : ‖φ a‖₊ = ‖a‖₊ :=
+ Subtype.ext <| norm_map φ hφ a
+
+lemma isometry (φ : F) (hφ : Function.Injective φ) : Isometry φ :=
+ AddMonoidHomClass.isometry_of_norm φ (norm_map φ hφ)
+
+end NonUnitalStarAlgHom
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 7fb42a09b19aa..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
@@ -81,6 +81,7 @@ instance : CStarModule A A where
rw [← sq_eq_sq (norm_nonneg _) (by positivity)]
simpa [sq] using Eq.symm <| CStarRing.norm_star_mul_self
+open scoped InnerProductSpace in
lemma inner_def (x y : A) : ⟪x, y⟫_A = star x * y := rfl
end Self
@@ -89,6 +90,8 @@ end Self
section Prod
+open scoped InnerProductSpace
+
variable {E F : Type*}
variable [NormedAddCommGroup E] [Module ℂ E] [SMul Aᵐᵒᵖ E]
variable [NormedAddCommGroup F] [Module ℂ F] [SMul Aᵐᵒᵖ F]
@@ -109,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
@@ -130,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),
@@ -139,7 +140,7 @@ lemma max_le_prod_norm (x : C⋆ᵐᵒᵈ (E × F)) : max ‖x.1‖ ‖x.2‖
Real.sqrt_le_sqrt_iff]
constructor
all_goals
- apply norm_le_norm_of_nonneg_of_le
+ apply CStarAlgebra.norm_le_norm_of_nonneg_of_le
all_goals
aesop (add safe apply CStarModule.inner_self_nonneg)
@@ -189,6 +190,8 @@ end Prod
section Pi
+open scoped InnerProductSpace
+
variable {ι : Type*} {E : ι → Type*} [Fintype ι]
variable [∀ i, NormedAddCommGroup (E i)] [∀ i, Module ℂ (E i)] [∀ i, SMul Aᵐᵒᵖ (E i)]
variable [∀ i, CStarModule A (E i)]
@@ -209,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
@@ -242,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
@@ -255,7 +256,7 @@ lemma norm_apply_le_norm (x : C⋆ᵐᵒᵈ (Π i, E i)) (i : ι) : ‖x i‖
let _ : NormedAddCommGroup (C⋆ᵐᵒᵈ (Π i, E i)) := normedAddCommGroup
refine abs_le_of_sq_le_sq' ?_ (by positivity) |>.2
rw [pi_norm_sq, norm_sq_eq]
- refine norm_le_norm_of_nonneg_of_le inner_self_nonneg ?_
+ refine CStarAlgebra.norm_le_norm_of_nonneg_of_le inner_self_nonneg ?_
exact Finset.single_le_sum (fun j _ ↦ inner_self_nonneg (x := x j)) (Finset.mem_univ i)
open Finset in
@@ -312,6 +313,7 @@ variable {E : Type*}
variable [NormedAddCommGroup E] [InnerProductSpace ℂ E]
variable [instSMulOp : SMul ℂᵐᵒᵖ E] [instCentral : IsCentralScalar ℂ E]
+open scoped InnerProductSpace in
/-- Reinterpret an inner product space `E` over `ℂ` as a `CStarModule` over `ℂ`.
Note: this instance requires `SMul ℂᵐᵒᵖ E` and `IsCentralScalar ℂ E` instances to exist on `E`,
diff --git a/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean b/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean
index 1c4045a1ebb24..4abfbcecbf696 100644
--- a/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean
+++ b/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean
@@ -153,11 +153,12 @@ 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
+open scoped InnerProductSpace in
/-- The norm associated with a Hilbert C⋆-module. It is not registered as a norm, since a type
might already have a norm defined on it. -/
noncomputable def norm (A : Type*) {E : Type*} [Norm A] [Inner A E] : Norm E where
@@ -176,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 :=
@@ -186,11 +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),
@@ -207,7 +206,7 @@ lemma inner_mul_inner_swap_le [CompleteSpace A] {x y : E} : ⟪y, x⟫ * ⟪x, y
_ ≤ ‖x‖ ^ 2 • (star a * a) - ‖x‖ ^ 2 • (⟪y, x⟫ * a)
- ‖x‖ ^ 2 • (star a * ⟪x, y⟫) + ‖x‖ ^ 2 • (‖x‖ ^ 2 • ⟪y, y⟫) := by
gcongr
- calc _ ≤ ‖⟪x, x⟫_A‖ • (star a * a) := CStarRing.conjugate_le_norm_smul
+ calc _ ≤ ‖⟪x, x⟫_A‖ • (star a * a) := CStarAlgebra.conjugate_le_norm_smul
_ = (Real.sqrt ‖⟪x, x⟫_A‖) ^ 2 • (star a * a) := by
congr
have : 0 ≤ ‖⟪x, x⟫_A‖ := by positivity
@@ -217,13 +216,14 @@ lemma inner_mul_inner_swap_le [CompleteSpace A] {x y : E} : ⟪y, x⟫ * ⟪x, y
simp only [star_inner, sub_self, zero_sub, le_neg_add_iff_add_le, add_zero] at h₁
rwa [smul_le_smul_iff_of_pos_left (pow_pos (CStarModule.norm_pos h) _)] at h₁
+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
- refine CStarRing.norm_le_norm_of_nonneg_of_le ?_ inner_mul_inner_swap_le
+ refine CStarAlgebra.norm_le_norm_of_nonneg_of_le ?_ inner_mul_inner_swap_le
rw [← star_inner x]
exact star_mul_self_nonneg ⟪x, y⟫_A
_ = ‖x‖ ^ 2 * ‖⟪y, y⟫‖ := by simp [norm_smul]
@@ -233,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
@@ -247,25 +248,27 @@ 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
-lemma norm_eq_csSup [CompleteSpace A] (v : E) :
+open scoped InnerProductSpace in
+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
refine Eq.symm <| IsGreatest.csSup_eq ⟨⟨‖v‖⁻¹ • v, ?_, ?_⟩, ?_⟩
- · simpa only [norm_smul, norm_inv, norm_norm] using inv_mul_le_one_of_le le_rfl (by positivity)
+ · simpa only [norm_smul, norm_inv, norm_norm] using inv_mul_le_one_of_le₀ le_rfl (by positivity)
· simp [norm_smul, ← norm_sq_eq, pow_two, ← mul_assoc]
· rintro - ⟨w, hw, rfl⟩
calc _ ≤ ‖w‖ * ‖v‖ := norm_inner_le E
@@ -276,14 +279,14 @@ end norm
section NormedAddCommGroup
+open scoped InnerProductSpace
+
/- Note: one generally creates a `CStarModule` instance for a type `E` first before getting the
`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 248d3fa9e31ac..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 _ _))
@@ -534,11 +535,15 @@ instance instNormedSpace : NormedSpace 𝕜 𝓜(𝕜, A) :=
instance instNormedAlgebra : NormedAlgebra 𝕜 𝓜(𝕜, A) :=
{ DoubleCentralizer.instAlgebra, DoubleCentralizer.instNormedSpace with }
-theorem uniformEmbedding_toProdMulOpposite : UniformEmbedding (@toProdMulOpposite 𝕜 A _ _ _ _ _) :=
- uniformEmbedding_comap toProdMulOpposite_injective
+theorem isUniformEmbedding_toProdMulOpposite :
+ IsUniformEmbedding (toProdMulOpposite (𝕜 := 𝕜) (A := A)) :=
+ isUniformEmbedding_comap toProdMulOpposite_injective
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_toProdMulOpposite := isUniformEmbedding_toProdMulOpposite
instance [CompleteSpace A] : CompleteSpace 𝓜(𝕜, A) := by
- rw [completeSpace_iff_isComplete_range uniformEmbedding_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 ?_ ?_
@@ -663,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 37ba786634cc4..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,12 +230,8 @@ 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 [FunLike F A B] [NonUnitalAlgHomClass F ℂ A B] [NonUnitalStarAlgHomClass F ℂ A 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,11 +267,8 @@ end NonUnitalStarAlgHom
namespace StarAlgEquiv
-variable {F A B : Type*} [NormedRing A] [NormedSpace ℂ A] [SMulCommClass ℂ A A]
-variable [IsScalarTower ℂ A A] [CompleteSpace A] [StarRing A] [CStarRing A] [StarModule ℂ A]
-variable [NormedRing B] [NormedSpace ℂ B] [SMulCommClass ℂ B B] [IsScalarTower ℂ B B]
-variable [CompleteSpace B] [StarRing B] [CStarRing B] [StarModule ℂ B] [EquivLike F A B]
-variable [NonUnitalAlgEquivClass F ℂ A B] [StarAlgEquivClass 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‖₊ :=
le_antisymm (NonUnitalStarAlgHom.nnnorm_apply_le φ a) <| by
@@ -289,10 +290,9 @@ 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 `StarAlgHomClass` to avoid type class inference loops.
+/-- This instance is provided instead of `StarHomClass` to avoid type class inference loops.
See note [lower instance priority] -/
noncomputable instance (priority := 100) Complex.instStarHomClass : StarHomClass F A ℂ where
map_star φ a := by
@@ -309,13 +309,13 @@ noncomputable instance (priority := 100) Complex.instStarHomClass : StarHomClass
/-- This is not an instance to avoid type class inference loops. See
`WeakDual.Complex.instStarHomClass`. -/
-lemma _root_.AlgHomClass.instStarAlgHomClass : StarAlgHomClass F ℂ A ℂ :=
+lemma _root_.AlgHomClass.instStarHomClass : StarHomClass F A ℂ :=
{ WeakDual.Complex.instStarHomClass, hF with }
namespace CharacterSpace
-noncomputable instance instStarAlgHomClass : StarAlgHomClass (characterSpace ℂ A) ℂ A ℂ :=
- { AlgHomClass.instStarAlgHomClass with }
+noncomputable instance instStarHomClass : StarHomClass (characterSpace ℂ A) A ℂ :=
+ { AlgHomClass.instStarHomClass with }
end CharacterSpace
diff --git a/Mathlib/Analysis/CStarAlgebra/Unitization.lean b/Mathlib/Analysis/CStarAlgebra/Unitization.lean
index d664e50c7c219..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
@@ -72,7 +75,7 @@ instance CStarRing.instRegularNormedAlgebra : RegularNormedAlgebra 𝕜 E where
· simpa only [mem_closedBall_zero_iff, norm_smul, one_mul, norm_star] using
(NNReal.le_inv_iff_mul_le ha.ne').1 (one_mul ‖a‖₊⁻¹ ▸ hk₂.le : ‖k‖₊ ≤ ‖a‖₊⁻¹)
· simp only [map_smul, nnnorm_smul, mul_apply', mul_smul_comm, CStarRing.nnnorm_self_mul_star]
- rwa [← NNReal.div_lt_iff (mul_pos ha ha).ne', div_eq_mul_inv, mul_inv, ← mul_assoc]
+ rwa [← div_lt_iff₀ (mul_pos ha ha), div_eq_mul_inv, mul_inv, ← mul_assoc]
section CStarProperty
@@ -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/Convolution.lean b/Mathlib/Analysis/Calculus/BumpFunction/Convolution.lean
index 6640b13a2e378..4b70bd94ec863 100644
--- a/Mathlib/Analysis/Calculus/BumpFunction/Convolution.lean
+++ b/Mathlib/Analysis/Calculus/BumpFunction/Convolution.lean
@@ -115,7 +115,7 @@ theorem ae_convolution_tendsto_right_of_locallyIntegrable
tendsto_nhdsWithin_iff.2 ⟨hφ, Eventually.of_forall (fun i ↦ (φ i).rOut_pos)⟩
have := (h₀.comp (Besicovitch.tendsto_filterAt μ x₀)).comp hφ'
simp only [Function.comp] at this
- apply tendsto_integral_smul_of_tendsto_average_norm_sub (K ^ (FiniteDimensional.finrank ℝ G)) this
+ apply tendsto_integral_smul_of_tendsto_average_norm_sub (K ^ (Module.finrank ℝ G)) this
· filter_upwards with i using
hg.integrableOn_isCompact (isCompact_closedBall _ _)
· apply tendsto_const_nhds.congr (fun i ↦ ?_)
diff --git a/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean b/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean
index 314fbbe3fa861..d0f390973978c 100644
--- a/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean
+++ b/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean
@@ -25,7 +25,7 @@ the indicator function of `closedBall 0 1` with a function as above with `s = ba
noncomputable section
-open Set Metric TopologicalSpace Function Asymptotics MeasureTheory FiniteDimensional
+open Set Metric TopologicalSpace Function Asymptotics MeasureTheory Module
ContinuousLinearMap Filter MeasureTheory.Measure Bornology
open scoped Pointwise Topology NNReal Convolution
@@ -407,7 +407,7 @@ theorem y_pos_of_mem_ball {D : ℝ} {x : E} (Dpos : 0 < D) (D_lt_one : D < 1)
intro y hy
simp only [support_mul, w_support E Dpos]
simp only [φ, mem_inter_iff, mem_support, Ne, indicator_apply_eq_zero,
- mem_closedBall_zero_iff, one_ne_zero, not_forall, not_false_iff, exists_prop, and_true_iff]
+ mem_closedBall_zero_iff, one_ne_zero, not_forall, not_false_iff, exists_prop, and_true]
constructor
· apply ball_subset_ball' _ hy
simp only [hz, norm_smul, abs_of_nonneg Dpos.le, abs_of_nonneg B.le, dist_zero_right,
@@ -512,7 +512,7 @@ instance (priority := 100) {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E
· rintro ⟨R, x⟩ ⟨hR : 1 < R, _⟩
have A : 0 < (R - 1) / (R + 1) := by apply div_pos <;> linarith
have B : (R - 1) / (R + 1) < 1 := by apply (div_lt_one _).2 <;> linarith
- simp only [mem_preimage, prod_mk_mem_set_prod_eq, mem_Ioo, mem_univ, and_true_iff, A, B]
+ simp only [mem_preimage, prod_mk_mem_set_prod_eq, mem_Ioo, mem_univ, and_true, A, B]
eq_one := fun R hR x hx => by
have A : 0 < R + 1 := by linarith
simp only [hR, if_true]
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 1846ced215ae9..fd3e53a98f231 100644
--- a/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean
+++ b/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean
@@ -16,7 +16,7 @@ In this file we define `ContDiffBump.normed f μ` to be the bump function `f` no
noncomputable section
-open Function Filter Set Metric MeasureTheory FiniteDimensional Measure
+open Function Filter Set Metric MeasureTheory Module Measure
open scoped Topology
namespace ContDiffBump
@@ -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 5f5e8ede6c4c1..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.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
@@ -892,7 +1028,7 @@ theorem ContDiffWithinAt.hasFDerivWithinAt_nhds {f : E → F → G} {g : E → F
have hst : insert x₀ s ×ˢ t ∈ 𝓝[(fun x => (x, g x)) '' s] (x₀, g x₀) := by
refine nhdsWithin_mono _ ?_ (nhdsWithin_prod self_mem_nhdsWithin hgt)
simp_rw [image_subset_iff, mk_preimage_prod, preimage_id', subset_inter_iff, subset_insert,
- true_and_iff, subset_preimage_image]
+ true_and, subset_preimage_image]
obtain ⟨v, hv, hvs, f', hvf', hf'⟩ := contDiffWithinAt_succ_iff_hasFDerivWithinAt'.mp hf
refine
⟨(fun z => (z, g z)) ⁻¹' v ∩ insert x₀ s, ?_, inter_subset_right, fun z =>
@@ -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) :
@@ -982,7 +1129,8 @@ theorem ContDiffWithinAt.iteratedFderivWithin_right {i : ℕ} (hf : ContDiffWith
((continuousMultilinearCurryFin0 𝕜 E F).symm : _ →L[𝕜] E [×0]→L[𝕜] F)
· rw [Nat.cast_succ, add_comm _ 1, ← add_assoc] at hmn
exact ((hi hmn).fderivWithin_right hs le_rfl hx₀s).continuousLinearMap_comp
- (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (i+1) ↦ E) F : _ →L[𝕜] E [×(i+1)]→L[𝕜] F)
+ ((continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (i+1) ↦ E) F).symm :
+ _ →L[𝕜] E [×(i+1)]→L[𝕜] F)
/-- `x ↦ fderiv 𝕜 (f x) (g x)` is smooth at `x₀`. -/
protected theorem ContDiffAt.fderiv {f : E → F → G} {g : E → F} {n : ℕ∞}
@@ -1070,15 +1218,14 @@ theorem hasFTaylorSeriesUpToOn_pi :
set L : ∀ m : ℕ, (∀ i, E[×m]→L[𝕜] F' i) ≃ₗᵢ[𝕜] E[×m]→L[𝕜] ∀ i, F' i := fun m =>
ContinuousMultilinearMap.piₗᵢ _ _
refine ⟨fun h i => ?_, fun h => ⟨fun x hx => ?_, ?_, ?_⟩⟩
- · convert h.continuousLinearMap_comp (pr i)
+ · exact h.continuousLinearMap_comp (pr i)
· ext1 i
exact (h i).zero_eq x hx
· intro m hm x hx
- have := hasFDerivWithinAt_pi.2 fun i => (h i).fderivWithin m hm x hx
- convert (L m).hasFDerivAt.comp_hasFDerivWithinAt x this
+ exact (L m).hasFDerivAt.comp_hasFDerivWithinAt x <|
+ hasFDerivWithinAt_pi.2 fun i => (h i).fderivWithin m hm x hx
· intro m hm
- have := continuousOn_pi.2 fun i => (h i).cont m hm
- convert (L m).continuous.comp_continuousOn this
+ exact (L m).continuous.comp_continuousOn <| continuousOn_pi.2 fun i => (h i).cont m hm
@[simp]
theorem hasFTaylorSeriesUpToOn_pi' :
@@ -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 d5cce4ded4d53..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 ?_))
@@ -304,7 +304,7 @@ theorem norm_iteratedFDerivWithin_prod_le [DecidableEq ι] [NormOneClass A'] {u
(g := (fun v ↦ v.multinomial *
∏ j ∈ insert i u, ‖iteratedFDerivWithin 𝕜 (v.count j) (f j) s x‖) ∘
Sym.toMultiset ∘ Subtype.val ∘ (Finset.symInsertEquiv hi).symm)
- (by simp) (by simp only [← comp_apply (g := Finset.symInsertEquiv hi), comp.assoc]; simp)]
+ (by simp) (by simp only [← comp_apply (g := Finset.symInsertEquiv hi), comp_assoc]; simp)]
rw [← Finset.univ_sigma_univ, Finset.sum_sigma, Finset.sum_range]
simp only [comp_apply, Finset.symInsertEquiv_symm_apply_coe]
refine Finset.sum_le_sum ?_
@@ -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 1bacbe9448ff7..bd9eaa1126d55 100644
--- a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean
+++ b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean
@@ -3,8 +3,7 @@ Copyright (c) 2019 Sébastien Gouëzel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel
-/
-import Mathlib.Analysis.Calculus.FDeriv.Equiv
-import Mathlib.Analysis.Calculus.FormalMultilinearSeries
+import Mathlib.Analysis.Calculus.ContDiff.FTaylorSeries
/-!
# Higher differentiability
@@ -14,11 +13,7 @@ By induction, it is `C^n` if it is `C^{n-1}` and its (n-1)-th derivative is `C^1
equivalently, if it is `C^1` and its derivative is `C^{n-1}`.
Finally, it is `C^∞` if it is `C^n` for all n.
-We formalize these notions by defining iteratively the `n+1`-th derivative of a function as the
-derivative of the `n`-th derivative. It is called `iteratedFDeriv 𝕜 n f x` where `𝕜` is the
-field, `n` is the number of iterations, `f` is the function and `x` is the point, and it is given
-as an `n`-multilinear map. We also define a version `iteratedFDerivWithin` relative to a domain,
-as well as predicates `ContDiffWithinAt`, `ContDiffAt`, `ContDiffOn` and
+We formalize these notions with predicates `ContDiffWithinAt`, `ContDiffAt`, `ContDiffOn` and
`ContDiff` saying that the function is `C^n` within a set at a point, at a point, on a set
and on the whole space respectively.
@@ -26,28 +21,18 @@ To avoid the issue of choice when choosing a derivative in sets where the deriva
necessarily unique, `ContDiffOn` is not defined directly in terms of the
regularity of the specific choice `iteratedFDerivWithin 𝕜 n f s` inside `s`, but in terms of the
existence of a nice sequence of derivatives, expressed with a predicate
-`HasFTaylorSeriesUpToOn`.
+`HasFTaylorSeriesUpToOn` defined in the file `FTaylorSeries`.
We prove basic properties of these notions.
## Main definitions and results
Let `f : E → F` be a map between normed vector spaces over a nontrivially normed field `𝕜`.
-* `HasFTaylorSeriesUpTo n f p`: expresses that the formal multilinear series `p` is a sequence
- of iterated derivatives of `f`, up to the `n`-th term (where `n` is a natural number or `∞`).
-* `HasFTaylorSeriesUpToOn n f p s`: same thing, but inside a set `s`. The notion of derivative
- is now taken inside `s`. In particular, derivatives don't have to be unique.
* `ContDiff 𝕜 n f`: expresses that `f` is `C^n`, i.e., it admits a Taylor series up to
rank `n`.
* `ContDiffOn 𝕜 n f s`: expresses that `f` is `C^n` in `s`.
* `ContDiffAt 𝕜 n f x`: expresses that `f` is `C^n` around `x`.
* `ContDiffWithinAt 𝕜 n f s x`: expresses that `f` is `C^n` around `x` within the set `s`.
-* `iteratedFDerivWithin 𝕜 n f s x` is an `n`-th derivative of `f` over the field `𝕜` on the
- set `s` at the point `x`. It is a continuous multilinear map from `E^n` to `F`, defined as a
- derivative within `s` of `iteratedFDerivWithin 𝕜 (n-1) f s` if one exists, and `0` otherwise.
-* `iteratedFDeriv 𝕜 n f x` is the `n`-th derivative of `f` over the field `𝕜` at the point `x`.
- It is a continuous multilinear map from `E^n` to `F`, defined as a derivative of
- `iteratedFDeriv 𝕜 (n-1) f` if one exists, and `0` otherwise.
In sets of unique differentiability, `ContDiffOn 𝕜 n f s` can be expressed in terms of the
properties of `iteratedFDerivWithin 𝕜 m f s` for `m ≤ n`. In the whole space,
@@ -91,55 +76,6 @@ within `s`. However, this does not imply continuity or differentiability within
at `x` when `x` does not belong to `s`. Therefore, we require such existence and good behavior on
a neighborhood of `x` within `s ∪ {x}` (which appears as `insert x s` in this file).
-### Side of the composition, and universe issues
-
-With a naïve direct definition, the `n`-th derivative of a function belongs to the space
-`E →L[𝕜] (E →L[𝕜] (E ... F)...)))` where there are n iterations of `E →L[𝕜]`. This space
-may also be seen as the space of continuous multilinear functions on `n` copies of `E` with
-values in `F`, by uncurrying. This is the point of view that is usually adopted in textbooks,
-and that we also use. This means that the definition and the first proofs are slightly involved,
-as one has to keep track of the uncurrying operation. The uncurrying can be done from the
-left or from the right, amounting to defining the `n+1`-th derivative either as the derivative of
-the `n`-th derivative, or as the `n`-th derivative of the derivative.
-For proofs, it would be more convenient to use the latter approach (from the right),
-as it means to prove things at the `n+1`-th step we only need to understand well enough the
-derivative in `E →L[𝕜] F` (contrary to the approach from the left, where one would need to know
-enough on the `n`-th derivative to deduce things on the `n+1`-th derivative).
-
-However, the definition from the right leads to a universe polymorphism problem: if we define
-`iteratedFDeriv 𝕜 (n + 1) f x = iteratedFDeriv 𝕜 n (fderiv 𝕜 f) x` by induction, we need to
-generalize over all spaces (as `f` and `fderiv 𝕜 f` don't take values in the same space). It is
-only possible to generalize over all spaces in some fixed universe in an inductive definition.
-For `f : E → F`, then `fderiv 𝕜 f` is a map `E → (E →L[𝕜] F)`. Therefore, the definition will only
-work if `F` and `E →L[𝕜] F` are in the same universe.
-
-This issue does not appear with the definition from the left, where one does not need to generalize
-over all spaces. Therefore, we use the definition from the left. This means some proofs later on
-become a little bit more complicated: to prove that a function is `C^n`, the most efficient approach
-is to exhibit a formula for its `n`-th derivative and prove it is continuous (contrary to the
-inductive approach where one would prove smoothness statements without giving a formula for the
-derivative). In the end, this approach is still satisfactory as it is good to have formulas for the
-iterated derivatives in various constructions.
-
-One point where we depart from this explicit approach is in the proof of smoothness of a
-composition: there is a formula for the `n`-th derivative of a composition (Faà di Bruno's formula),
-but it is very complicated and barely usable, while the inductive proof is very simple. Thus, we
-give the inductive proof. As explained above, it works by generalizing over the target space, hence
-it only works well if all spaces belong to the same universe. To get the general version, we lift
-things to a common universe using a trick.
-
-### Variables management
-
-The textbook definitions and proofs use various identifications and abuse of notations, for instance
-when saying that the natural space in which the derivative lives, i.e.,
-`E →L[𝕜] (E →L[𝕜] ( ... →L[𝕜] F))`, is the same as a space of multilinear maps. When doing things
-formally, we need to provide explicit maps for these identifications, and chase some diagrams to see
-everything is compatible with the identifications. In particular, one needs to check that taking the
-derivative and then doing the identification, or first doing the identification and then taking the
-derivative, gives the same result. The key point for this is that taking the derivative commutes
-with continuous linear equivalences. Therefore, we need to implement all our identifications with
-continuous linear equivs.
-
## Notations
We use the notation `E [×n]→L[𝕜] F` for the space of continuous multilinear maps on `E^n` with
@@ -175,221 +111,6 @@ variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {E : Type uE} [NormedAdd
{s s₁ t u : Set E} {f f₁ : E → F} {g : F → G} {x x₀ : E} {c : F} {m n : ℕ∞}
{p : E → FormalMultilinearSeries 𝕜 E F}
-/-! ### Functions with a Taylor series on a domain -/
-
-/-- `HasFTaylorSeriesUpToOn n f p s` registers the fact that `p 0 = f` and `p (m+1)` is a
-derivative of `p m` for `m < n`, and is continuous for `m ≤ n`. This is a predicate analogous to
-`HasFDerivWithinAt` but for higher order derivatives.
-
-Notice that `p` does not sum up to `f` on the diagonal (`FormalMultilinearSeries.sum`), even if
-`f` is analytic and `n = ∞`: an additional `1/m!` factor on the `m`th term is necessary for that. -/
-structure HasFTaylorSeriesUpToOn (n : ℕ∞) (f : E → F) (p : E → FormalMultilinearSeries 𝕜 E F)
- (s : Set E) : Prop where
- zero_eq : ∀ x ∈ s, (p x 0).uncurry0 = f x
- protected fderivWithin : ∀ m : ℕ, (m : ℕ∞) < n → ∀ x ∈ s,
- HasFDerivWithinAt (p · m) (p x m.succ).curryLeft s x
- cont : ∀ m : ℕ, (m : ℕ∞) ≤ n → ContinuousOn (p · m) s
-
-theorem HasFTaylorSeriesUpToOn.zero_eq' (h : HasFTaylorSeriesUpToOn n f p s) {x : E} (hx : x ∈ s) :
- p x 0 = (continuousMultilinearCurryFin0 𝕜 E F).symm (f x) := by
- rw [← h.zero_eq x hx]
- exact (p x 0).uncurry0_curry0.symm
-
-/-- If two functions coincide on a set `s`, then a Taylor series for the first one is as well a
-Taylor series for the second one. -/
-theorem HasFTaylorSeriesUpToOn.congr (h : HasFTaylorSeriesUpToOn n f p s)
- (h₁ : ∀ x ∈ s, f₁ x = f x) : HasFTaylorSeriesUpToOn n f₁ p s := by
- refine ⟨fun x hx => ?_, h.fderivWithin, h.cont⟩
- rw [h₁ x hx]
- exact h.zero_eq x hx
-
-theorem HasFTaylorSeriesUpToOn.mono (h : HasFTaylorSeriesUpToOn n f p s) {t : Set E} (hst : t ⊆ s) :
- HasFTaylorSeriesUpToOn n f p t :=
- ⟨fun x hx => h.zero_eq x (hst hx), fun m hm x hx => (h.fderivWithin m hm x (hst hx)).mono hst,
- fun m hm => (h.cont m hm).mono hst⟩
-
-theorem HasFTaylorSeriesUpToOn.of_le (h : HasFTaylorSeriesUpToOn n f p s) (hmn : m ≤ n) :
- HasFTaylorSeriesUpToOn m f p s :=
- ⟨h.zero_eq, fun k hk x hx => h.fderivWithin k (lt_of_lt_of_le hk hmn) x hx, fun k hk =>
- h.cont k (le_trans hk hmn)⟩
-
-theorem HasFTaylorSeriesUpToOn.continuousOn (h : HasFTaylorSeriesUpToOn n f p s) :
- ContinuousOn f s := by
- have := (h.cont 0 bot_le).congr fun x hx => (h.zero_eq' hx).symm
- rwa [← (continuousMultilinearCurryFin0 𝕜 E F).symm.comp_continuousOn_iff]
-
-theorem hasFTaylorSeriesUpToOn_zero_iff :
- HasFTaylorSeriesUpToOn 0 f p s ↔ ContinuousOn f s ∧ ∀ x ∈ s, (p x 0).uncurry0 = f x := by
- refine ⟨fun H => ⟨H.continuousOn, H.zero_eq⟩, fun H =>
- ⟨H.2, fun m hm => False.elim (not_le.2 hm bot_le), fun m hm ↦ ?_⟩⟩
- obtain rfl : m = 0 := mod_cast hm.antisymm (zero_le _)
- have : EqOn (p · 0) ((continuousMultilinearCurryFin0 𝕜 E F).symm ∘ f) s := fun x hx ↦
- (continuousMultilinearCurryFin0 𝕜 E F).eq_symm_apply.2 (H.2 x hx)
- rw [continuousOn_congr this, LinearIsometryEquiv.comp_continuousOn_iff]
- exact H.1
-
-theorem hasFTaylorSeriesUpToOn_top_iff :
- HasFTaylorSeriesUpToOn ∞ f p s ↔ ∀ n : ℕ, HasFTaylorSeriesUpToOn n f p s := by
- constructor
- · intro H n; exact H.of_le le_top
- · intro H
- constructor
- · exact (H 0).zero_eq
- · intro m _
- apply (H m.succ).fderivWithin m (WithTop.coe_lt_coe.2 (lt_add_one m))
- · intro m _
- apply (H m).cont m le_rfl
-
-/-- In the case that `n = ∞` we don't need the continuity assumption in
-`HasFTaylorSeriesUpToOn`. -/
-theorem hasFTaylorSeriesUpToOn_top_iff' :
- HasFTaylorSeriesUpToOn ∞ f p s ↔
- (∀ x ∈ s, (p x 0).uncurry0 = f x) ∧
- ∀ m : ℕ, ∀ x ∈ s, HasFDerivWithinAt (fun y => p y m) (p x m.succ).curryLeft s x :=
- -- Everything except for the continuity is trivial:
- ⟨fun h => ⟨h.1, fun m => h.2 m (WithTop.coe_lt_top m)⟩, fun h =>
- ⟨h.1, fun m _ => h.2 m, fun m _ x hx =>
- -- The continuity follows from the existence of a derivative:
- (h.2 m x hx).continuousWithinAt⟩⟩
-
-/-- If a function has a Taylor series at order at least `1`, then the term of order `1` of this
-series is a derivative of `f`. -/
-theorem HasFTaylorSeriesUpToOn.hasFDerivWithinAt (h : HasFTaylorSeriesUpToOn n f p s) (hn : 1 ≤ n)
- (hx : x ∈ s) : HasFDerivWithinAt f (continuousMultilinearCurryFin1 𝕜 E F (p x 1)) s x := by
- have A : ∀ y ∈ s, f y = (continuousMultilinearCurryFin0 𝕜 E F) (p y 0) := fun y hy ↦
- (h.zero_eq y hy).symm
- suffices H : HasFDerivWithinAt (continuousMultilinearCurryFin0 𝕜 E F ∘ (p · 0))
- (continuousMultilinearCurryFin1 𝕜 E F (p x 1)) s x from H.congr A (A x hx)
- rw [LinearIsometryEquiv.comp_hasFDerivWithinAt_iff']
- have : ((0 : ℕ) : ℕ∞) < n := zero_lt_one.trans_le hn
- convert h.fderivWithin _ this x hx
- ext y v
- change (p x 1) (snoc 0 y) = (p x 1) (cons y v)
- congr with i
- rw [Unique.eq_default (α := Fin 1) i]
- rfl
-
-theorem HasFTaylorSeriesUpToOn.differentiableOn (h : HasFTaylorSeriesUpToOn n f p s) (hn : 1 ≤ n) :
- DifferentiableOn 𝕜 f s := fun _x hx => (h.hasFDerivWithinAt hn hx).differentiableWithinAt
-
-/-- If a function has a Taylor series at order at least `1` on a neighborhood of `x`, then the term
-of order `1` of this series is a derivative of `f` at `x`. -/
-theorem HasFTaylorSeriesUpToOn.hasFDerivAt (h : HasFTaylorSeriesUpToOn n f p s) (hn : 1 ≤ n)
- (hx : s ∈ 𝓝 x) : HasFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p x 1)) x :=
- (h.hasFDerivWithinAt hn (mem_of_mem_nhds hx)).hasFDerivAt hx
-
-/-- If a function has a Taylor series at order at least `1` on a neighborhood of `x`, then
-in a neighborhood of `x`, the term of order `1` of this series is a derivative of `f`. -/
-theorem HasFTaylorSeriesUpToOn.eventually_hasFDerivAt (h : HasFTaylorSeriesUpToOn n f p s)
- (hn : 1 ≤ n) (hx : s ∈ 𝓝 x) :
- ∀ᶠ y in 𝓝 x, HasFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p y 1)) y :=
- (eventually_eventually_nhds.2 hx).mono fun _y hy => h.hasFDerivAt hn hy
-
-/-- If a function has a Taylor series at order at least `1` on a neighborhood of `x`, then
-it is differentiable at `x`. -/
-theorem HasFTaylorSeriesUpToOn.differentiableAt (h : HasFTaylorSeriesUpToOn n f p s) (hn : 1 ≤ n)
- (hx : s ∈ 𝓝 x) : DifferentiableAt 𝕜 f x :=
- (h.hasFDerivAt hn hx).differentiableAt
-
-/-- `p` is a Taylor series of `f` up to `n+1` if and only if `p` is a Taylor series up to `n`, and
-`p (n + 1)` is a derivative of `p n`. -/
-theorem hasFTaylorSeriesUpToOn_succ_iff_left {n : ℕ} :
- HasFTaylorSeriesUpToOn (n + 1) f p s ↔
- HasFTaylorSeriesUpToOn n f p s ∧
- (∀ x ∈ s, HasFDerivWithinAt (fun y => p y n) (p x n.succ).curryLeft s x) ∧
- ContinuousOn (fun x => p x (n + 1)) s := by
- constructor
- · exact fun h ↦ ⟨h.of_le (WithTop.coe_le_coe.2 (Nat.le_succ n)),
- h.fderivWithin _ (WithTop.coe_lt_coe.2 (lt_add_one n)), h.cont (n + 1) le_rfl⟩
- · intro h
- constructor
- · exact h.1.zero_eq
- · intro m hm
- by_cases h' : m < n
- · exact h.1.fderivWithin m (WithTop.coe_lt_coe.2 h')
- · have : m = n := Nat.eq_of_lt_succ_of_not_lt (WithTop.coe_lt_coe.1 hm) h'
- rw [this]
- exact h.2.1
- · intro m hm
- by_cases h' : m ≤ n
- · apply h.1.cont m (WithTop.coe_le_coe.2 h')
- · have : m = n + 1 := le_antisymm (WithTop.coe_le_coe.1 hm) (not_le.1 h')
- rw [this]
- exact h.2.2
-
-#adaptation_note
-/--
-After https://github.com/leanprover/lean4/pull/4119,
-without `set_option maxSynthPendingDepth 2` this proof needs substantial repair.
--/
-set_option maxSynthPendingDepth 2 in
--- Porting note: this was split out from `hasFTaylorSeriesUpToOn_succ_iff_right` to avoid a timeout.
-theorem HasFTaylorSeriesUpToOn.shift_of_succ
- {n : ℕ} (H : HasFTaylorSeriesUpToOn (n + 1 : ℕ) f p s) :
- (HasFTaylorSeriesUpToOn n (fun x => continuousMultilinearCurryFin1 𝕜 E F (p x 1))
- (fun x => (p x).shift)) s := by
- constructor
- · intro x _
- rfl
- · intro m (hm : (m : ℕ∞) < n) x (hx : x ∈ s)
- have A : (m.succ : ℕ∞) < n.succ := by
- rw [Nat.cast_lt] at hm ⊢
- exact Nat.succ_lt_succ hm
- change HasFDerivWithinAt ((continuousMultilinearCurryRightEquiv' 𝕜 m E F).symm ∘ (p · m.succ))
- (p x m.succ.succ).curryRight.curryLeft s x
- rw [((continuousMultilinearCurryRightEquiv' 𝕜 m E F).symm).comp_hasFDerivWithinAt_iff']
- convert H.fderivWithin _ A x hx
- ext y v
- change p x (m + 2) (snoc (cons y (init v)) (v (last _))) = p x (m + 2) (cons y v)
- rw [← cons_snoc_eq_snoc_cons, snoc_init_self]
- · intro m (hm : (m : ℕ∞) ≤ n)
- suffices A : ContinuousOn (p · (m + 1)) s from
- ((continuousMultilinearCurryRightEquiv' 𝕜 m E F).symm).continuous.comp_continuousOn A
- refine H.cont _ ?_
- rw [Nat.cast_le] at hm ⊢
- exact Nat.succ_le_succ hm
-
-/-- `p` is a Taylor series of `f` up to `n+1` if and only if `p.shift` is a Taylor series up to `n`
-for `p 1`, which is a derivative of `f`. -/
-theorem hasFTaylorSeriesUpToOn_succ_iff_right {n : ℕ} :
- HasFTaylorSeriesUpToOn (n + 1 : ℕ) f p s ↔
- (∀ x ∈ s, (p x 0).uncurry0 = f x) ∧
- (∀ x ∈ s, HasFDerivWithinAt (fun y => p y 0) (p x 1).curryLeft s x) ∧
- HasFTaylorSeriesUpToOn n (fun x => continuousMultilinearCurryFin1 𝕜 E F (p x 1))
- (fun x => (p x).shift) s := by
- constructor
- · intro H
- refine ⟨H.zero_eq, H.fderivWithin 0 (Nat.cast_lt.2 (Nat.succ_pos n)), ?_⟩
- exact H.shift_of_succ
- · rintro ⟨Hzero_eq, Hfderiv_zero, Htaylor⟩
- constructor
- · exact Hzero_eq
- · intro m (hm : (m : ℕ∞) < n.succ) x (hx : x ∈ s)
- cases' m with m
- · exact Hfderiv_zero x hx
- · have A : (m : ℕ∞) < n := by
- rw [Nat.cast_lt] at hm ⊢
- exact Nat.lt_of_succ_lt_succ hm
- have :
- HasFDerivWithinAt ((continuousMultilinearCurryRightEquiv' 𝕜 m E F).symm ∘ (p · m.succ))
- ((p x).shift m.succ).curryLeft s x := Htaylor.fderivWithin _ A x hx
- rw [LinearIsometryEquiv.comp_hasFDerivWithinAt_iff'] at this
- convert this
- ext y v
- change
- (p x (Nat.succ (Nat.succ m))) (cons y v) =
- (p x m.succ.succ) (snoc (cons y (init v)) (v (last _)))
- rw [← cons_snoc_eq_snoc_cons, snoc_init_self]
- · intro m (hm : (m : ℕ∞) ≤ n.succ)
- cases' m with m
- · have : DifferentiableOn 𝕜 (fun x => p x 0) s := fun x hx =>
- (Hfderiv_zero x hx).differentiableWithinAt
- exact this.continuousOn
- · refine (continuousMultilinearCurryRightEquiv' 𝕜 m E F).symm.comp_continuousOn_iff.mp ?_
- refine Htaylor.cont _ ?_
- rw [Nat.cast_le] at hm ⊢
- exact Nat.lt_succ_iff.mp hm
-
/-! ### Smooth functions within a set around a point -/
variable (𝕜)
@@ -427,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 =>
@@ -435,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_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 (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
+@[deprecated (since := "2024-10-23")]
+alias ContDiffWithinAt.congr_nhds := ContDiffWithinAt.congr_set
-theorem contDiffWithinAt_congr_nhds {t : Set E} (hst : 𝓝[s] x = 𝓝[t] x) :
+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 :=
@@ -499,19 +267,26 @@ 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⟩
rw [inter_comm] at tu
- have := ((H.mono tu).differentiableOn le_rfl) x ⟨mem_insert x s, xt⟩
- exact (differentiableWithinAt_inter (IsOpen.mem_nhds t_open xt)).1 this
+ 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 : ℕ} :
@@ -577,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'⟩
@@ -602,7 +377,7 @@ theorem HasFTaylorSeriesUpToOn.contDiffOn {f' : E → FormalMultilinearSeries
(hf : HasFTaylorSeriesUpToOn n f f' s) : ContDiffOn 𝕜 n f s := by
intro x hx m hm
use s
- simp only [Set.insert_eq_of_mem hx, self_mem_nhdsWithin, true_and_iff]
+ simp only [Set.insert_eq_of_mem hx, self_mem_nhdsWithin, true_and]
exact ⟨f', hf.of_le hm⟩
theorem ContDiffOn.contDiffWithinAt (h : ContDiffOn 𝕜 n f s) (hx : x ∈ s) :
@@ -622,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 =>
@@ -701,211 +487,6 @@ theorem contDiffOn_succ_iff_hasFDerivWithinAt {n : ℕ} :
have : x ∈ u := mem_of_mem_nhdsWithin (mem_insert _ _) u_nhbd
exact ⟨u, u_nhbd, f', hu, hf' x this⟩
-/-! ### Iterated derivative within a set -/
-
-
-variable (𝕜)
-
-/-- The `n`-th derivative of a function along a set, defined inductively by saying that the `n+1`-th
-derivative of `f` is the derivative of the `n`-th derivative of `f` along this set, together with
-an uncurrying step to see it as a multilinear map in `n+1` variables..
--/
-noncomputable def iteratedFDerivWithin (n : ℕ) (f : E → F) (s : Set E) : E → E[×n]→L[𝕜] F :=
- Nat.recOn n (fun x => ContinuousMultilinearMap.curry0 𝕜 E (f x)) fun _ rec x =>
- ContinuousLinearMap.uncurryLeft (fderivWithin 𝕜 rec s x)
-
-/-- Formal Taylor series associated to a function within a set. -/
-def ftaylorSeriesWithin (f : E → F) (s : Set E) (x : E) : FormalMultilinearSeries 𝕜 E F := fun n =>
- iteratedFDerivWithin 𝕜 n f s x
-
-variable {𝕜}
-
-@[simp]
-theorem iteratedFDerivWithin_zero_apply (m : Fin 0 → E) :
- (iteratedFDerivWithin 𝕜 0 f s x : (Fin 0 → E) → F) m = f x :=
- rfl
-
-theorem iteratedFDerivWithin_zero_eq_comp :
- iteratedFDerivWithin 𝕜 0 f s = (continuousMultilinearCurryFin0 𝕜 E F).symm ∘ f :=
- rfl
-
-@[simp]
-theorem norm_iteratedFDerivWithin_zero : ‖iteratedFDerivWithin 𝕜 0 f s x‖ = ‖f x‖ := by
- -- Porting note: added `comp_apply`.
- rw [iteratedFDerivWithin_zero_eq_comp, comp_apply, LinearIsometryEquiv.norm_map]
-
-theorem iteratedFDerivWithin_succ_apply_left {n : ℕ} (m : Fin (n + 1) → E) :
- (iteratedFDerivWithin 𝕜 (n + 1) f s x : (Fin (n + 1) → E) → F) m =
- (fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n f s) s x : E → E[×n]→L[𝕜] F) (m 0) (tail m) :=
- rfl
-
-/-- Writing explicitly the `n+1`-th derivative as the composition of a currying linear equiv,
-and the derivative of the `n`-th derivative. -/
-theorem iteratedFDerivWithin_succ_eq_comp_left {n : ℕ} :
- iteratedFDerivWithin 𝕜 (n + 1) f s =
- (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) => E) F :
- (E →L[𝕜] (E [×n]→L[𝕜] F)) → (E [×n.succ]→L[𝕜] F)) ∘
- fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n f s) s :=
- rfl
-
-theorem fderivWithin_iteratedFDerivWithin {s : Set E} {n : ℕ} :
- fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n f s) s =
- (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) => E) F).symm ∘
- iteratedFDerivWithin 𝕜 (n + 1) f s := by
- rw [iteratedFDerivWithin_succ_eq_comp_left]
- ext1 x
- simp only [Function.comp_apply, LinearIsometryEquiv.symm_apply_apply]
-
-theorem norm_fderivWithin_iteratedFDerivWithin {n : ℕ} :
- ‖fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n f s) s x‖ =
- ‖iteratedFDerivWithin 𝕜 (n + 1) f s x‖ := by
- -- Porting note: added `comp_apply`.
- rw [iteratedFDerivWithin_succ_eq_comp_left, comp_apply, LinearIsometryEquiv.norm_map]
-
-theorem iteratedFDerivWithin_succ_apply_right {n : ℕ} (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s)
- (m : Fin (n + 1) → E) :
- (iteratedFDerivWithin 𝕜 (n + 1) f s x : (Fin (n + 1) → E) → F) m =
- iteratedFDerivWithin 𝕜 n (fun y => fderivWithin 𝕜 f s y) s x (init m) (m (last n)) := by
- induction' n with n IH generalizing x
- · rw [iteratedFDerivWithin_succ_eq_comp_left, iteratedFDerivWithin_zero_eq_comp,
- iteratedFDerivWithin_zero_apply, Function.comp_apply,
- LinearIsometryEquiv.comp_fderivWithin _ (hs x hx)]
- rfl
- · let I := continuousMultilinearCurryRightEquiv' 𝕜 n E F
- have A : ∀ y ∈ s, iteratedFDerivWithin 𝕜 n.succ f s y =
- (I ∘ iteratedFDerivWithin 𝕜 n (fun y => fderivWithin 𝕜 f s y) s) y := fun y hy ↦ by
- ext m
- rw [@IH y hy m]
- rfl
- calc
- (iteratedFDerivWithin 𝕜 (n + 2) f s x : (Fin (n + 2) → E) → F) m =
- (fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n.succ f s) s x : E → E[×n + 1]→L[𝕜] F) (m 0)
- (tail m) :=
- rfl
- _ = (fderivWithin 𝕜 (I ∘ iteratedFDerivWithin 𝕜 n (fderivWithin 𝕜 f s) s) s x :
- E → E[×n + 1]→L[𝕜] F) (m 0) (tail m) := by
- rw [fderivWithin_congr A (A x hx)]
- _ = (I ∘ fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n (fderivWithin 𝕜 f s) s) s x :
- E → E[×n + 1]→L[𝕜] F) (m 0) (tail m) := by
- #adaptation_note
- /--
- After https://github.com/leanprover/lean4/pull/4119 we need to either use
- `set_option maxSynthPendingDepth 2 in`
- or fill in an explicit argument as
- ```
- simp only [LinearIsometryEquiv.comp_fderivWithin _
- (f := iteratedFDerivWithin 𝕜 n (fderivWithin 𝕜 f s) s) (hs x hx)]
- ```
- -/
- set_option maxSynthPendingDepth 2 in
- simp only [LinearIsometryEquiv.comp_fderivWithin _ (hs x hx)]
- rfl
- _ = (fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n (fun y => fderivWithin 𝕜 f s y) s) s x :
- E → E[×n]→L[𝕜] E →L[𝕜] F) (m 0) (init (tail m)) ((tail m) (last n)) := rfl
- _ = iteratedFDerivWithin 𝕜 (Nat.succ n) (fun y => fderivWithin 𝕜 f s y) s x (init m)
- (m (last (n + 1))) := by
- rw [iteratedFDerivWithin_succ_apply_left, tail_init_eq_init_tail]
- rfl
-
-/-- Writing explicitly the `n+1`-th derivative as the composition of a currying linear equiv,
-and the `n`-th derivative of the derivative. -/
-theorem iteratedFDerivWithin_succ_eq_comp_right {n : ℕ} (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) :
- iteratedFDerivWithin 𝕜 (n + 1) f s x =
- (continuousMultilinearCurryRightEquiv' 𝕜 n E F ∘
- iteratedFDerivWithin 𝕜 n (fun y => fderivWithin 𝕜 f s y) s)
- x := by
- ext m; rw [iteratedFDerivWithin_succ_apply_right hs hx]; rfl
-
-theorem norm_iteratedFDerivWithin_fderivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) :
- ‖iteratedFDerivWithin 𝕜 n (fderivWithin 𝕜 f s) s x‖ =
- ‖iteratedFDerivWithin 𝕜 (n + 1) f s x‖ := by
- -- Porting note: added `comp_apply`.
- rw [iteratedFDerivWithin_succ_eq_comp_right hs hx, comp_apply, LinearIsometryEquiv.norm_map]
-
-@[simp]
-theorem iteratedFDerivWithin_one_apply (h : UniqueDiffWithinAt 𝕜 s x) (m : Fin 1 → E) :
- iteratedFDerivWithin 𝕜 1 f s x m = fderivWithin 𝕜 f s x (m 0) := by
- simp only [iteratedFDerivWithin_succ_apply_left, iteratedFDerivWithin_zero_eq_comp,
- (continuousMultilinearCurryFin0 𝕜 E F).symm.comp_fderivWithin h]
- rfl
-
-/-- On a set of unique differentiability, the second derivative is obtained by taking the
-derivative of the derivative. -/
-lemma iteratedFDerivWithin_two_apply (f : E → F) {z : E} (hs : UniqueDiffOn 𝕜 s) (hz : z ∈ s)
- (m : Fin 2 → E) :
- iteratedFDerivWithin 𝕜 2 f s z m = fderivWithin 𝕜 (fderivWithin 𝕜 f s) s z (m 0) (m 1) := by
- simp only [iteratedFDerivWithin_succ_apply_right hs hz]
- rfl
-
-theorem Filter.EventuallyEq.iteratedFDerivWithin' (h : f₁ =ᶠ[𝓝[s] x] f) (ht : t ⊆ s) (n : ℕ) :
- iteratedFDerivWithin 𝕜 n f₁ t =ᶠ[𝓝[s] x] iteratedFDerivWithin 𝕜 n f t := by
- induction n with
- | zero => exact h.mono fun y hy => DFunLike.ext _ _ fun _ => hy
- | succ n ihn =>
- have : fderivWithin 𝕜 _ t =ᶠ[𝓝[s] x] fderivWithin 𝕜 _ t := ihn.fderivWithin' ht
- refine this.mono fun y hy => ?_
- simp only [iteratedFDerivWithin_succ_eq_comp_left, hy, (· ∘ ·)]
-
-protected theorem Filter.EventuallyEq.iteratedFDerivWithin (h : f₁ =ᶠ[𝓝[s] x] f) (n : ℕ) :
- iteratedFDerivWithin 𝕜 n f₁ s =ᶠ[𝓝[s] x] iteratedFDerivWithin 𝕜 n f s :=
- h.iteratedFDerivWithin' Subset.rfl n
-
-/-- If two functions coincide in a neighborhood of `x` within a set `s` and at `x`, then their
-iterated differentials within this set at `x` coincide. -/
-theorem Filter.EventuallyEq.iteratedFDerivWithin_eq (h : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x)
- (n : ℕ) : iteratedFDerivWithin 𝕜 n f₁ s x = iteratedFDerivWithin 𝕜 n f s x :=
- have : f₁ =ᶠ[𝓝[insert x s] x] f := by simpa [EventuallyEq, hx]
- (this.iteratedFDerivWithin' (subset_insert _ _) n).self_of_nhdsWithin (mem_insert _ _)
-
-/-- If two functions coincide on a set `s`, then their iterated differentials within this set
-coincide. See also `Filter.EventuallyEq.iteratedFDerivWithin_eq` and
-`Filter.EventuallyEq.iteratedFDerivWithin`. -/
-theorem iteratedFDerivWithin_congr (hs : EqOn f₁ f s) (hx : x ∈ s) (n : ℕ) :
- iteratedFDerivWithin 𝕜 n f₁ s x = iteratedFDerivWithin 𝕜 n f s x :=
- (hs.eventuallyEq.filter_mono inf_le_right).iteratedFDerivWithin_eq (hs hx) _
-
-/-- If two functions coincide on a set `s`, then their iterated differentials within this set
-coincide. See also `Filter.EventuallyEq.iteratedFDerivWithin_eq` and
-`Filter.EventuallyEq.iteratedFDerivWithin`. -/
-protected theorem Set.EqOn.iteratedFDerivWithin (hs : EqOn f₁ f s) (n : ℕ) :
- EqOn (iteratedFDerivWithin 𝕜 n f₁ s) (iteratedFDerivWithin 𝕜 n f s) s := fun _x hx =>
- iteratedFDerivWithin_congr hs hx n
-
-theorem iteratedFDerivWithin_eventually_congr_set' (y : E) (h : s =ᶠ[𝓝[{y}ᶜ] x] t) (n : ℕ) :
- iteratedFDerivWithin 𝕜 n f s =ᶠ[𝓝 x] iteratedFDerivWithin 𝕜 n f t := by
- induction n generalizing x with
- | zero => rfl
- | succ n ihn =>
- refine (eventually_nhds_nhdsWithin.2 h).mono fun y hy => ?_
- simp only [iteratedFDerivWithin_succ_eq_comp_left, (· ∘ ·)]
- rw [(ihn hy).fderivWithin_eq_nhds, fderivWithin_congr_set' _ hy]
-
-theorem iteratedFDerivWithin_eventually_congr_set (h : s =ᶠ[𝓝 x] t) (n : ℕ) :
- iteratedFDerivWithin 𝕜 n f s =ᶠ[𝓝 x] iteratedFDerivWithin 𝕜 n f t :=
- iteratedFDerivWithin_eventually_congr_set' x (h.filter_mono inf_le_left) n
-
-theorem iteratedFDerivWithin_congr_set (h : s =ᶠ[𝓝 x] t) (n : ℕ) :
- iteratedFDerivWithin 𝕜 n f s x = iteratedFDerivWithin 𝕜 n f t x :=
- (iteratedFDerivWithin_eventually_congr_set h n).self_of_nhds
-
-/-- The iterated differential within a set `s` at a point `x` is not modified if one intersects
-`s` with a neighborhood of `x` within `s`. -/
-theorem iteratedFDerivWithin_inter' {n : ℕ} (hu : u ∈ 𝓝[s] x) :
- iteratedFDerivWithin 𝕜 n f (s ∩ u) x = iteratedFDerivWithin 𝕜 n f s x :=
- iteratedFDerivWithin_congr_set (nhdsWithin_eq_iff_eventuallyEq.1 <| nhdsWithin_inter_of_mem' hu) _
-
-/-- The iterated differential within a set `s` at a point `x` is not modified if one intersects
-`s` with a neighborhood of `x`. -/
-theorem iteratedFDerivWithin_inter {n : ℕ} (hu : u ∈ 𝓝 x) :
- iteratedFDerivWithin 𝕜 n f (s ∩ u) x = iteratedFDerivWithin 𝕜 n f s x :=
- iteratedFDerivWithin_inter' (mem_nhdsWithin_of_mem_nhds hu)
-
-/-- The iterated differential within a set `s` at a point `x` is not modified if one intersects
-`s` with an open set containing `x`. -/
-theorem iteratedFDerivWithin_inter_open {n : ℕ} (hu : IsOpen u) (hx : x ∈ u) :
- iteratedFDerivWithin 𝕜 n f (s ∩ u) x = iteratedFDerivWithin 𝕜 n f s x :=
- iteratedFDerivWithin_inter (hu.mem_nhds hx)
-
@[simp]
theorem contDiffOn_zero : ContDiffOn 𝕜 0 f s ↔ ContinuousOn f s := by
refine ⟨fun H => H.continuousOn, fun H => fun x hx m hm ↦ ?_⟩
@@ -929,33 +510,13 @@ theorem contDiffWithinAt_zero (hx : x ∈ s) :
have h' : x ∈ s ∩ u := ⟨hx, mem_of_mem_nhdsWithin hx H⟩
exact (contDiffOn_zero.mpr hu).contDiffWithinAt h'
-/-- On a set with unique differentiability, any choice of iterated differential has to coincide
-with the one we have chosen in `iteratedFDerivWithin 𝕜 m f s`. -/
-theorem HasFTaylorSeriesUpToOn.eq_iteratedFDerivWithin_of_uniqueDiffOn
- (h : HasFTaylorSeriesUpToOn n f p s) {m : ℕ} (hmn : (m : ℕ∞) ≤ n) (hs : UniqueDiffOn 𝕜 s)
- (hx : x ∈ s) : p x m = iteratedFDerivWithin 𝕜 m f s x := by
- induction' m with m IH generalizing x
- · rw [h.zero_eq' hx, iteratedFDerivWithin_zero_eq_comp]; rfl
- · have A : (m : ℕ∞) < n := lt_of_lt_of_le (WithTop.coe_lt_coe.2 (lt_add_one m)) hmn
- have :
- HasFDerivWithinAt (fun y : E => iteratedFDerivWithin 𝕜 m f s y)
- (ContinuousMultilinearMap.curryLeft (p x (Nat.succ m))) s x :=
- (h.fderivWithin m A x hx).congr (fun y hy => (IH (le_of_lt A) hy).symm)
- (IH (le_of_lt A) hx).symm
- rw [iteratedFDerivWithin_succ_eq_comp_left, Function.comp_apply, this.fderivWithin (hs x hx)]
- exact (ContinuousMultilinearMap.uncurry_curryLeft _).symm
-
-@[deprecated (since := "2024-03-28")]
-alias HasFTaylorSeriesUpToOn.eq_ftaylor_series_of_uniqueDiffOn :=
- HasFTaylorSeriesUpToOn.eq_iteratedFDerivWithin_of_uniqueDiffOn
-
/-- When a function is `C^n` in a set `s` of unique differentiability, it admits
`ftaylorSeriesWithin 𝕜 f s` as a Taylor series up to order `n` in `s`. -/
protected theorem ContDiffOn.ftaylorSeriesWithin (h : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) :
HasFTaylorSeriesUpToOn n f (ftaylorSeriesWithin 𝕜 f s) s := by
constructor
· intro x _
- simp only [ftaylorSeriesWithin, ContinuousMultilinearMap.uncurry0_apply,
+ simp only [ftaylorSeriesWithin, ContinuousMultilinearMap.curry0_apply,
iteratedFDerivWithin_zero_apply]
· intro m hm x hx
rcases (h x hx) m.succ (Order.add_one_le_of_lt hm) with ⟨u, hu, p, Hp⟩
@@ -1002,7 +563,7 @@ theorem contDiffOn_of_continuousOn_differentiableOn
refine ⟨s, self_mem_nhdsWithin, ftaylorSeriesWithin 𝕜 f s, ?_⟩
constructor
· intro y _
- simp only [ftaylorSeriesWithin, ContinuousMultilinearMap.uncurry0_apply,
+ simp only [ftaylorSeriesWithin, ContinuousMultilinearMap.curry0_apply,
iteratedFDerivWithin_zero_apply]
· intro k hk y hy
convert (Hdiff k (lt_of_lt_of_le hk hm) y hy).hasFDerivWithinAt
@@ -1069,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 => ?_
@@ -1084,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`. -/
@@ -1139,99 +700,6 @@ theorem ContDiffOn.continuousOn_fderiv_of_isOpen (h : ContDiffOn 𝕜 n f s) (hs
(hn : 1 ≤ n) : ContinuousOn (fun x => fderiv 𝕜 f x) s :=
((contDiffOn_succ_iff_fderiv_of_isOpen hs).1 (h.of_le hn)).2.continuousOn
-/-! ### Functions with a Taylor series on the whole space -/
-
-/-- `HasFTaylorSeriesUpTo n f p` registers the fact that `p 0 = f` and `p (m+1)` is a
-derivative of `p m` for `m < n`, and is continuous for `m ≤ n`. This is a predicate analogous to
-`HasFDerivAt` but for higher order derivatives.
-
-Notice that `p` does not sum up to `f` on the diagonal (`FormalMultilinearSeries.sum`), even if
-`f` is analytic and `n = ∞`: an addition `1/m!` factor on the `m`th term is necessary for that. -/
-structure HasFTaylorSeriesUpTo (n : ℕ∞) (f : E → F) (p : E → FormalMultilinearSeries 𝕜 E F) :
- Prop where
- zero_eq : ∀ x, (p x 0).uncurry0 = f x
- fderiv : ∀ m : ℕ, (m : ℕ∞) < n → ∀ x, HasFDerivAt (fun y => p y m) (p x m.succ).curryLeft x
- cont : ∀ m : ℕ, (m : ℕ∞) ≤ n → Continuous fun x => p x m
-
-theorem HasFTaylorSeriesUpTo.zero_eq' (h : HasFTaylorSeriesUpTo n f p) (x : E) :
- p x 0 = (continuousMultilinearCurryFin0 𝕜 E F).symm (f x) := by
- rw [← h.zero_eq x]
- exact (p x 0).uncurry0_curry0.symm
-
-theorem hasFTaylorSeriesUpToOn_univ_iff :
- HasFTaylorSeriesUpToOn n f p univ ↔ HasFTaylorSeriesUpTo n f p := by
- constructor
- · intro H
- constructor
- · exact fun x => H.zero_eq x (mem_univ x)
- · intro m hm x
- rw [← hasFDerivWithinAt_univ]
- exact H.fderivWithin m hm x (mem_univ x)
- · intro m hm
- rw [continuous_iff_continuousOn_univ]
- exact H.cont m hm
- · intro H
- constructor
- · exact fun x _ => H.zero_eq x
- · intro m hm x _
- rw [hasFDerivWithinAt_univ]
- exact H.fderiv m hm x
- · intro m hm
- rw [← continuous_iff_continuousOn_univ]
- exact H.cont m hm
-
-theorem HasFTaylorSeriesUpTo.hasFTaylorSeriesUpToOn (h : HasFTaylorSeriesUpTo n f p) (s : Set E) :
- HasFTaylorSeriesUpToOn n f p s :=
- (hasFTaylorSeriesUpToOn_univ_iff.2 h).mono (subset_univ _)
-
-theorem HasFTaylorSeriesUpTo.ofLe (h : HasFTaylorSeriesUpTo n f p) (hmn : m ≤ n) :
- HasFTaylorSeriesUpTo m f p := by
- rw [← hasFTaylorSeriesUpToOn_univ_iff] at h ⊢; exact h.of_le hmn
-
-theorem HasFTaylorSeriesUpTo.continuous (h : HasFTaylorSeriesUpTo n f p) : Continuous f := by
- rw [← hasFTaylorSeriesUpToOn_univ_iff] at h
- rw [continuous_iff_continuousOn_univ]
- exact h.continuousOn
-
-theorem hasFTaylorSeriesUpTo_zero_iff :
- HasFTaylorSeriesUpTo 0 f p ↔ Continuous f ∧ ∀ x, (p x 0).uncurry0 = f x := by
- simp [hasFTaylorSeriesUpToOn_univ_iff.symm, continuous_iff_continuousOn_univ,
- hasFTaylorSeriesUpToOn_zero_iff]
-
-theorem hasFTaylorSeriesUpTo_top_iff :
- HasFTaylorSeriesUpTo ∞ f p ↔ ∀ n : ℕ, HasFTaylorSeriesUpTo n f p := by
- simp only [← hasFTaylorSeriesUpToOn_univ_iff, hasFTaylorSeriesUpToOn_top_iff]
-
-/-- In the case that `n = ∞` we don't need the continuity assumption in
-`HasFTaylorSeriesUpTo`. -/
-theorem hasFTaylorSeriesUpTo_top_iff' :
- HasFTaylorSeriesUpTo ∞ f p ↔
- (∀ x, (p x 0).uncurry0 = f x) ∧
- ∀ (m : ℕ) (x), HasFDerivAt (fun y => p y m) (p x m.succ).curryLeft x := by
- simp only [← hasFTaylorSeriesUpToOn_univ_iff, hasFTaylorSeriesUpToOn_top_iff', mem_univ,
- forall_true_left, hasFDerivWithinAt_univ]
-
-/-- If a function has a Taylor series at order at least `1`, then the term of order `1` of this
-series is a derivative of `f`. -/
-theorem HasFTaylorSeriesUpTo.hasFDerivAt (h : HasFTaylorSeriesUpTo n f p) (hn : 1 ≤ n) (x : E) :
- HasFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p x 1)) x := by
- rw [← hasFDerivWithinAt_univ]
- exact (hasFTaylorSeriesUpToOn_univ_iff.2 h).hasFDerivWithinAt hn (mem_univ _)
-
-theorem HasFTaylorSeriesUpTo.differentiable (h : HasFTaylorSeriesUpTo n f p) (hn : 1 ≤ n) :
- Differentiable 𝕜 f := fun x => (h.hasFDerivAt hn x).differentiableAt
-
-/-- `p` is a Taylor series of `f` up to `n+1` if and only if `p.shift` is a Taylor series up to `n`
-for `p 1`, which is a derivative of `f`. -/
-theorem hasFTaylorSeriesUpTo_succ_iff_right {n : ℕ} :
- HasFTaylorSeriesUpTo (n + 1 : ℕ) f p ↔
- (∀ x, (p x 0).uncurry0 = f x) ∧
- (∀ x, HasFDerivAt (fun y => p y 0) (p x 1).curryLeft x) ∧
- HasFTaylorSeriesUpTo n (fun x => continuousMultilinearCurryFin1 𝕜 E F (p x 1)) fun x =>
- (p x).shift := by
- simp only [hasFTaylorSeriesUpToOn_succ_iff_right, ← hasFTaylorSeriesUpToOn_univ_iff, mem_univ,
- forall_true_left, hasFDerivWithinAt_univ]
-
/-! ### Smooth functions at a point -/
variable (𝕜)
@@ -1256,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
@@ -1270,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
@@ -1392,152 +873,6 @@ theorem contDiff_one_iff_hasFDerivAt : ContDiff 𝕜 1 f ↔
∃ f' : E → E →L[𝕜] F, Continuous f' ∧ ∀ x, HasFDerivAt f (f' x) x := by
convert contDiff_succ_iff_hasFDerivAt using 4; simp
-/-! ### Iterated derivative -/
-
-
-variable (𝕜)
-
-/-- The `n`-th derivative of a function, as a multilinear map, defined inductively. -/
-noncomputable def iteratedFDeriv (n : ℕ) (f : E → F) : E → E[×n]→L[𝕜] F :=
- Nat.recOn n (fun x => ContinuousMultilinearMap.curry0 𝕜 E (f x)) fun _ rec x =>
- ContinuousLinearMap.uncurryLeft (fderiv 𝕜 rec x)
-
-/-- Formal Taylor series associated to a function. -/
-def ftaylorSeries (f : E → F) (x : E) : FormalMultilinearSeries 𝕜 E F := fun n =>
- iteratedFDeriv 𝕜 n f x
-
-variable {𝕜}
-
-@[simp]
-theorem iteratedFDeriv_zero_apply (m : Fin 0 → E) :
- (iteratedFDeriv 𝕜 0 f x : (Fin 0 → E) → F) m = f x :=
- rfl
-
-theorem iteratedFDeriv_zero_eq_comp :
- iteratedFDeriv 𝕜 0 f = (continuousMultilinearCurryFin0 𝕜 E F).symm ∘ f :=
- rfl
-
-@[simp]
-theorem norm_iteratedFDeriv_zero : ‖iteratedFDeriv 𝕜 0 f x‖ = ‖f x‖ := by
- -- Porting note: added `comp_apply`.
- rw [iteratedFDeriv_zero_eq_comp, comp_apply, LinearIsometryEquiv.norm_map]
-
-theorem iteratedFDerivWithin_zero_eq : iteratedFDerivWithin 𝕜 0 f s = iteratedFDeriv 𝕜 0 f := rfl
-
-theorem iteratedFDeriv_succ_apply_left {n : ℕ} (m : Fin (n + 1) → E) :
- (iteratedFDeriv 𝕜 (n + 1) f x : (Fin (n + 1) → E) → F) m =
- (fderiv 𝕜 (iteratedFDeriv 𝕜 n f) x : E → E[×n]→L[𝕜] F) (m 0) (tail m) :=
- rfl
-
-/-- Writing explicitly the `n+1`-th derivative as the composition of a currying linear equiv,
-and the derivative of the `n`-th derivative. -/
-theorem iteratedFDeriv_succ_eq_comp_left {n : ℕ} :
- iteratedFDeriv 𝕜 (n + 1) f =
- continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) => E) F ∘
- fderiv 𝕜 (iteratedFDeriv 𝕜 n f) :=
- rfl
-
-/-- Writing explicitly the derivative of the `n`-th derivative as the composition of a currying
-linear equiv, and the `n + 1`-th derivative. -/
-theorem fderiv_iteratedFDeriv {n : ℕ} :
- fderiv 𝕜 (iteratedFDeriv 𝕜 n f) =
- (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) => E) F).symm ∘
- iteratedFDeriv 𝕜 (n + 1) f := by
- rw [iteratedFDeriv_succ_eq_comp_left]
- ext1 x
- simp only [Function.comp_apply, LinearIsometryEquiv.symm_apply_apply]
-
-theorem tsupport_iteratedFDeriv_subset (n : ℕ) : tsupport (iteratedFDeriv 𝕜 n f) ⊆ tsupport f := by
- induction n with
- | zero =>
- rw [iteratedFDeriv_zero_eq_comp]
- exact closure_minimal ((support_comp_subset (LinearIsometryEquiv.map_zero _) _).trans
- subset_closure) isClosed_closure
- | succ n IH =>
- rw [iteratedFDeriv_succ_eq_comp_left]
- exact closure_minimal ((support_comp_subset (LinearIsometryEquiv.map_zero _) _).trans
- ((support_fderiv_subset 𝕜).trans IH)) isClosed_closure
-
-theorem support_iteratedFDeriv_subset (n : ℕ) : support (iteratedFDeriv 𝕜 n f) ⊆ tsupport f :=
- subset_closure.trans (tsupport_iteratedFDeriv_subset n)
-
-theorem HasCompactSupport.iteratedFDeriv (hf : HasCompactSupport f) (n : ℕ) :
- HasCompactSupport (iteratedFDeriv 𝕜 n f) :=
- hf.of_isClosed_subset isClosed_closure (tsupport_iteratedFDeriv_subset n)
-
-theorem norm_fderiv_iteratedFDeriv {n : ℕ} :
- ‖fderiv 𝕜 (iteratedFDeriv 𝕜 n f) x‖ = ‖iteratedFDeriv 𝕜 (n + 1) f x‖ := by
- -- Porting note: added `comp_apply`.
- rw [iteratedFDeriv_succ_eq_comp_left, comp_apply, LinearIsometryEquiv.norm_map]
-
-theorem iteratedFDerivWithin_univ {n : ℕ} :
- iteratedFDerivWithin 𝕜 n f univ = iteratedFDeriv 𝕜 n f := by
- induction n with
- | zero => ext x; simp
- | succ n IH =>
- ext x m
- rw [iteratedFDeriv_succ_apply_left, iteratedFDerivWithin_succ_apply_left, IH, fderivWithin_univ]
-
-theorem HasFTaylorSeriesUpTo.eq_iteratedFDeriv
- (h : HasFTaylorSeriesUpTo n f p) {m : ℕ} (hmn : (m : ℕ∞) ≤ n) (x : E) :
- p x m = iteratedFDeriv 𝕜 m f x := by
- rw [← iteratedFDerivWithin_univ]
- rw [← hasFTaylorSeriesUpToOn_univ_iff] at h
- exact h.eq_iteratedFDerivWithin_of_uniqueDiffOn hmn uniqueDiffOn_univ (mem_univ _)
-
-/-- In an open set, the iterated derivative within this set coincides with the global iterated
-derivative. -/
-theorem iteratedFDerivWithin_of_isOpen (n : ℕ) (hs : IsOpen s) :
- EqOn (iteratedFDerivWithin 𝕜 n f s) (iteratedFDeriv 𝕜 n f) s := by
- induction n with
- | zero =>
- intro x _
- ext1
- simp only [iteratedFDerivWithin_zero_apply, iteratedFDeriv_zero_apply]
- | succ n IH =>
- intro x hx
- rw [iteratedFDeriv_succ_eq_comp_left, iteratedFDerivWithin_succ_eq_comp_left]
- dsimp
- congr 1
- rw [fderivWithin_of_isOpen hs hx]
- apply Filter.EventuallyEq.fderiv_eq
- filter_upwards [hs.mem_nhds hx]
- exact IH
-
-theorem ftaylorSeriesWithin_univ : ftaylorSeriesWithin 𝕜 f univ = ftaylorSeries 𝕜 f := by
- ext1 x; ext1 n
- change iteratedFDerivWithin 𝕜 n f univ x = iteratedFDeriv 𝕜 n f x
- rw [iteratedFDerivWithin_univ]
-
-theorem iteratedFDeriv_succ_apply_right {n : ℕ} (m : Fin (n + 1) → E) :
- (iteratedFDeriv 𝕜 (n + 1) f x : (Fin (n + 1) → E) → F) m =
- iteratedFDeriv 𝕜 n (fun y => fderiv 𝕜 f y) x (init m) (m (last n)) := by
- rw [← iteratedFDerivWithin_univ, ← iteratedFDerivWithin_univ, ← fderivWithin_univ]
- exact iteratedFDerivWithin_succ_apply_right uniqueDiffOn_univ (mem_univ _) _
-
-/-- Writing explicitly the `n+1`-th derivative as the composition of a currying linear equiv,
-and the `n`-th derivative of the derivative. -/
-theorem iteratedFDeriv_succ_eq_comp_right {n : ℕ} :
- iteratedFDeriv 𝕜 (n + 1) f x =
- (continuousMultilinearCurryRightEquiv' 𝕜 n E F ∘ iteratedFDeriv 𝕜 n fun y => fderiv 𝕜 f y)
- x := by
- ext m; rw [iteratedFDeriv_succ_apply_right]; rfl
-
-theorem norm_iteratedFDeriv_fderiv {n : ℕ} :
- ‖iteratedFDeriv 𝕜 n (fderiv 𝕜 f) x‖ = ‖iteratedFDeriv 𝕜 (n + 1) f x‖ := by
- -- Porting note: added `comp_apply`.
- rw [iteratedFDeriv_succ_eq_comp_right, comp_apply, LinearIsometryEquiv.norm_map]
-
-@[simp]
-theorem iteratedFDeriv_one_apply (m : Fin 1 → E) :
- iteratedFDeriv 𝕜 1 f x m = fderiv 𝕜 f x (m 0) := by
- rw [iteratedFDeriv_succ_apply_right, iteratedFDeriv_zero_apply]; rfl
-
-lemma iteratedFDeriv_two_apply (f : E → F) (z : E) (m : Fin 2 → E) :
- iteratedFDeriv 𝕜 2 f z m = fderiv 𝕜 (fderiv 𝕜 f) z (m 0) (m 1) := by
- simp only [iteratedFDeriv_succ_apply_right]
- rfl
-
/-- When a function is `C^n` in a set `s` of unique differentiability, it admits
`ftaylorSeriesWithin 𝕜 f s` as a Taylor series up to order `n` in `s`. -/
theorem contDiff_iff_ftaylorSeries :
@@ -1598,5 +933,3 @@ theorem ContDiff.continuous_fderiv_apply (h : ContDiff 𝕜 n f) (hn : 1 ≤ n)
have B : Continuous fun p : E × E => (fderiv 𝕜 f p.1, p.2) :=
((h.continuous_fderiv hn).comp continuous_fst).prod_mk continuous_snd
A.comp B
-
-set_option linter.style.longFile 1700
diff --git a/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean b/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean
new file mode 100644
index 0000000000000..6bc8d6009890d
--- /dev/null
+++ b/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean
@@ -0,0 +1,796 @@
+/-
+Copyright (c) 2019 Sébastien Gouëzel. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Sébastien Gouëzel
+-/
+import Mathlib.Analysis.Calculus.FDeriv.Equiv
+import Mathlib.Analysis.Calculus.FormalMultilinearSeries
+
+/-!
+# Iterated derivatives of a function
+
+In this file, we define iteratively the `n+1`-th derivative of a function as the
+derivative of the `n`-th derivative. It is called `iteratedFDeriv 𝕜 n f x` where `𝕜` is the
+field, `n` is the number of iterations, `f` is the function and `x` is the point, and it is given
+as an `n`-multilinear map. We also define a version `iteratedFDerivWithin` relative to a domain.
+Note that, in domains, there may be several choices of possible derivative, so we make some
+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 accommodates well the
+non-uniqueness of derivatives.
+
+## Main definitions and results
+
+Let `f : E → F` be a map between normed vector spaces over a nontrivially normed field `𝕜`.
+
+* `HasFTaylorSeriesUpTo n f p`: expresses that the formal multilinear series `p` is a sequence
+ of iterated derivatives of `f`, up to the `n`-th term (where `n` is a natural number or `∞`).
+* `HasFTaylorSeriesUpToOn n f p s`: same thing, but inside a set `s`. The notion of derivative
+ is now taken inside `s`. In particular, derivatives don't have to be unique.
+
+* `iteratedFDerivWithin 𝕜 n f s x` is an `n`-th derivative of `f` over the field `𝕜` on the
+ set `s` at the point `x`. It is a continuous multilinear map from `E^n` to `F`, defined as a
+ derivative within `s` of `iteratedFDerivWithin 𝕜 (n-1) f s` if one exists, and `0` otherwise.
+* `iteratedFDeriv 𝕜 n f x` is the `n`-th derivative of `f` over the field `𝕜` at the point `x`.
+ It is a continuous multilinear map from `E^n` to `F`, defined as a derivative of
+ `iteratedFDeriv 𝕜 (n-1) f` if one exists, and `0` otherwise.
+
+
+### Side of the composition, and universe issues
+
+With a naïve direct definition, the `n`-th derivative of a function belongs to the space
+`E →L[𝕜] (E →L[𝕜] (E ... F)...)))` where there are n iterations of `E →L[𝕜]`. This space
+may also be seen as the space of continuous multilinear functions on `n` copies of `E` with
+values in `F`, by uncurrying. This is the point of view that is usually adopted in textbooks,
+and that we also use. This means that the definition and the first proofs are slightly involved,
+as one has to keep track of the uncurrying operation. The uncurrying can be done from the
+left or from the right, amounting to defining the `n+1`-th derivative either as the derivative of
+the `n`-th derivative, or as the `n`-th derivative of the derivative.
+For proofs, it would be more convenient to use the latter approach (from the right),
+as it means to prove things at the `n+1`-th step we only need to understand well enough the
+derivative in `E →L[𝕜] F` (contrary to the approach from the left, where one would need to know
+enough on the `n`-th derivative to deduce things on the `n+1`-th derivative).
+
+However, the definition from the right leads to a universe polymorphism problem: if we define
+`iteratedFDeriv 𝕜 (n + 1) f x = iteratedFDeriv 𝕜 n (fderiv 𝕜 f) x` by induction, we need to
+generalize over all spaces (as `f` and `fderiv 𝕜 f` don't take values in the same space). It is
+only possible to generalize over all spaces in some fixed universe in an inductive definition.
+For `f : E → F`, then `fderiv 𝕜 f` is a map `E → (E →L[𝕜] F)`. Therefore, the definition will only
+work if `F` and `E →L[𝕜] F` are in the same universe.
+
+This issue does not appear with the definition from the left, where one does not need to generalize
+over all spaces. Therefore, we use the definition from the left. This means some proofs later on
+become a little bit more complicated: to prove that a function is `C^n`, the most efficient approach
+is to exhibit a formula for its `n`-th derivative and prove it is continuous (contrary to the
+inductive approach where one would prove smoothness statements without giving a formula for the
+derivative). In the end, this approach is still satisfactory as it is good to have formulas for the
+iterated derivatives in various constructions.
+
+One point where we depart from this explicit approach is in the proof of smoothness of a
+composition: there is a formula for the `n`-th derivative of a composition (Faà di Bruno's formula),
+but it is very complicated and barely usable, while the inductive proof is very simple. Thus, we
+give the inductive proof. As explained above, it works by generalizing over the target space, hence
+it only works well if all spaces belong to the same universe. To get the general version, we lift
+things to a common universe using a trick.
+
+### Variables management
+
+The textbook definitions and proofs use various identifications and abuse of notations, for instance
+when saying that the natural space in which the derivative lives, i.e.,
+`E →L[𝕜] (E →L[𝕜] ( ... →L[𝕜] F))`, is the same as a space of multilinear maps. When doing things
+formally, we need to provide explicit maps for these identifications, and chase some diagrams to see
+everything is compatible with the identifications. In particular, one needs to check that taking the
+derivative and then doing the identification, or first doing the identification and then taking the
+derivative, gives the same result. The key point for this is that taking the derivative commutes
+with continuous linear equivalences. Therefore, we need to implement all our identifications with
+continuous linear equivs.
+
+## Notations
+
+We use the notation `E [×n]→L[𝕜] F` for the space of continuous multilinear maps on `E^n` with
+values in `F`. This is the space in which the `n`-th derivative of a function from `E` to `F` lives.
+
+In this file, we denote `⊤ : ℕ∞` with `∞`.
+-/
+
+
+noncomputable section
+
+open scoped Classical
+open NNReal Topology Filter
+
+local notation "∞" => (⊤ : ℕ∞)
+
+/-
+Porting note: These lines are not required in Mathlib4.
+attribute [local instance 1001]
+ NormedAddCommGroup.toAddCommGroup NormedSpace.toModule' AddCommGroup.toAddCommMonoid
+-/
+
+open Set Fin Filter Function
+
+universe u uE uF uG uX
+
+variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {E : Type uE} [NormedAddCommGroup E]
+ [NormedSpace 𝕜 E] {F : Type uF} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type uG}
+ [NormedAddCommGroup G] [NormedSpace 𝕜 G] {X : Type uX} [NormedAddCommGroup X] [NormedSpace 𝕜 X]
+ {s s₁ t u : Set E} {f f₁ : E → F} {g : F → G} {x x₀ : E} {c : F} {m n : ℕ∞}
+ {p : E → FormalMultilinearSeries 𝕜 E F}
+
+/-! ### Functions with a Taylor series on a domain -/
+
+/-- `HasFTaylorSeriesUpToOn n f p s` registers the fact that `p 0 = f` and `p (m+1)` is a
+derivative of `p m` for `m < n`, and is continuous for `m ≤ n`. This is a predicate analogous to
+`HasFDerivWithinAt` but for higher order derivatives.
+
+Notice that `p` does not sum up to `f` on the diagonal (`FormalMultilinearSeries.sum`), even if
+`f` is analytic and `n = ∞`: an additional `1/m!` factor on the `m`th term is necessary for that. -/
+structure HasFTaylorSeriesUpToOn (n : ℕ∞) (f : E → F) (p : E → FormalMultilinearSeries 𝕜 E F)
+ (s : Set E) : Prop where
+ zero_eq : ∀ x ∈ s, (p x 0).curry0 = f x
+ protected fderivWithin : ∀ m : ℕ, (m : ℕ∞) < n → ∀ x ∈ s,
+ HasFDerivWithinAt (p · m) (p x m.succ).curryLeft s x
+ cont : ∀ m : ℕ, (m : ℕ∞) ≤ n → ContinuousOn (p · m) s
+
+theorem HasFTaylorSeriesUpToOn.zero_eq' (h : HasFTaylorSeriesUpToOn n f p s) {x : E} (hx : x ∈ s) :
+ p x 0 = (continuousMultilinearCurryFin0 𝕜 E F).symm (f x) := by
+ rw [← h.zero_eq x hx]
+ exact (p x 0).uncurry0_curry0.symm
+
+/-- If two functions coincide on a set `s`, then a Taylor series for the first one is as well a
+Taylor series for the second one. -/
+theorem HasFTaylorSeriesUpToOn.congr (h : HasFTaylorSeriesUpToOn n f p s)
+ (h₁ : ∀ x ∈ s, f₁ x = f x) : HasFTaylorSeriesUpToOn n f₁ p s := by
+ refine ⟨fun x hx => ?_, h.fderivWithin, h.cont⟩
+ rw [h₁ x hx]
+ exact h.zero_eq x hx
+
+theorem HasFTaylorSeriesUpToOn.mono (h : HasFTaylorSeriesUpToOn n f p s) {t : Set E} (hst : t ⊆ s) :
+ HasFTaylorSeriesUpToOn n f p t :=
+ ⟨fun x hx => h.zero_eq x (hst hx), fun m hm x hx => (h.fderivWithin m hm x (hst hx)).mono hst,
+ fun m hm => (h.cont m hm).mono hst⟩
+
+theorem HasFTaylorSeriesUpToOn.of_le (h : HasFTaylorSeriesUpToOn n f p s) (hmn : m ≤ n) :
+ HasFTaylorSeriesUpToOn m f p s :=
+ ⟨h.zero_eq, fun k hk x hx => h.fderivWithin k (lt_of_lt_of_le hk hmn) x hx, fun k hk =>
+ h.cont k (le_trans hk hmn)⟩
+
+theorem HasFTaylorSeriesUpToOn.continuousOn (h : HasFTaylorSeriesUpToOn n f p s) :
+ ContinuousOn f s := by
+ have := (h.cont 0 bot_le).congr fun x hx => (h.zero_eq' hx).symm
+ rwa [← (continuousMultilinearCurryFin0 𝕜 E F).symm.comp_continuousOn_iff]
+
+theorem hasFTaylorSeriesUpToOn_zero_iff :
+ HasFTaylorSeriesUpToOn 0 f p s ↔ ContinuousOn f s ∧ ∀ x ∈ s, (p x 0).curry0 = f x := by
+ refine ⟨fun H => ⟨H.continuousOn, H.zero_eq⟩, fun H =>
+ ⟨H.2, fun m hm => False.elim (not_le.2 hm bot_le), fun m hm ↦ ?_⟩⟩
+ obtain rfl : m = 0 := mod_cast hm.antisymm (zero_le _)
+ have : EqOn (p · 0) ((continuousMultilinearCurryFin0 𝕜 E F).symm ∘ f) s := fun x hx ↦
+ (continuousMultilinearCurryFin0 𝕜 E F).eq_symm_apply.2 (H.2 x hx)
+ rw [continuousOn_congr this, LinearIsometryEquiv.comp_continuousOn_iff]
+ exact H.1
+
+theorem hasFTaylorSeriesUpToOn_top_iff :
+ HasFTaylorSeriesUpToOn ∞ f p s ↔ ∀ n : ℕ, HasFTaylorSeriesUpToOn n f p s := by
+ constructor
+ · intro H n; exact H.of_le le_top
+ · intro H
+ constructor
+ · exact (H 0).zero_eq
+ · intro m _
+ apply (H m.succ).fderivWithin m (WithTop.coe_lt_coe.2 (lt_add_one m))
+ · intro m _
+ apply (H m).cont m le_rfl
+
+/-- In the case that `n = ∞` we don't need the continuity assumption in
+`HasFTaylorSeriesUpToOn`. -/
+theorem hasFTaylorSeriesUpToOn_top_iff' :
+ HasFTaylorSeriesUpToOn ∞ f p s ↔
+ (∀ x ∈ s, (p x 0).curry0 = f x) ∧
+ ∀ m : ℕ, ∀ x ∈ s, HasFDerivWithinAt (fun y => p y m) (p x m.succ).curryLeft s x :=
+ -- Everything except for the continuity is trivial:
+ ⟨fun h => ⟨h.1, fun m => h.2 m (WithTop.coe_lt_top m)⟩, fun h =>
+ ⟨h.1, fun m _ => h.2 m, fun m _ x hx =>
+ -- The continuity follows from the existence of a derivative:
+ (h.2 m x hx).continuousWithinAt⟩⟩
+
+/-- If a function has a Taylor series at order at least `1`, then the term of order `1` of this
+series is a derivative of `f`. -/
+theorem HasFTaylorSeriesUpToOn.hasFDerivWithinAt (h : HasFTaylorSeriesUpToOn n f p s) (hn : 1 ≤ n)
+ (hx : x ∈ s) : HasFDerivWithinAt f (continuousMultilinearCurryFin1 𝕜 E F (p x 1)) s x := by
+ have A : ∀ y ∈ s, f y = (continuousMultilinearCurryFin0 𝕜 E F) (p y 0) := fun y hy ↦
+ (h.zero_eq y hy).symm
+ suffices H : HasFDerivWithinAt (continuousMultilinearCurryFin0 𝕜 E F ∘ (p · 0))
+ (continuousMultilinearCurryFin1 𝕜 E F (p x 1)) s x from H.congr A (A x hx)
+ rw [LinearIsometryEquiv.comp_hasFDerivWithinAt_iff']
+ have : ((0 : ℕ) : ℕ∞) < n := zero_lt_one.trans_le hn
+ convert h.fderivWithin _ this x hx
+ ext y v
+ change (p x 1) (snoc 0 y) = (p x 1) (cons y v)
+ congr with i
+ rw [Unique.eq_default (α := Fin 1) i]
+ rfl
+
+theorem HasFTaylorSeriesUpToOn.differentiableOn (h : HasFTaylorSeriesUpToOn n f p s) (hn : 1 ≤ n) :
+ DifferentiableOn 𝕜 f s := fun _x hx => (h.hasFDerivWithinAt hn hx).differentiableWithinAt
+
+/-- If a function has a Taylor series at order at least `1` on a neighborhood of `x`, then the term
+of order `1` of this series is a derivative of `f` at `x`. -/
+theorem HasFTaylorSeriesUpToOn.hasFDerivAt (h : HasFTaylorSeriesUpToOn n f p s) (hn : 1 ≤ n)
+ (hx : s ∈ 𝓝 x) : HasFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p x 1)) x :=
+ (h.hasFDerivWithinAt hn (mem_of_mem_nhds hx)).hasFDerivAt hx
+
+/-- If a function has a Taylor series at order at least `1` on a neighborhood of `x`, then
+in a neighborhood of `x`, the term of order `1` of this series is a derivative of `f`. -/
+theorem HasFTaylorSeriesUpToOn.eventually_hasFDerivAt (h : HasFTaylorSeriesUpToOn n f p s)
+ (hn : 1 ≤ n) (hx : s ∈ 𝓝 x) :
+ ∀ᶠ y in 𝓝 x, HasFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p y 1)) y :=
+ (eventually_eventually_nhds.2 hx).mono fun _y hy => h.hasFDerivAt hn hy
+
+/-- If a function has a Taylor series at order at least `1` on a neighborhood of `x`, then
+it is differentiable at `x`. -/
+theorem HasFTaylorSeriesUpToOn.differentiableAt (h : HasFTaylorSeriesUpToOn n f p s) (hn : 1 ≤ n)
+ (hx : s ∈ 𝓝 x) : DifferentiableAt 𝕜 f x :=
+ (h.hasFDerivAt hn hx).differentiableAt
+
+/-- `p` is a Taylor series of `f` up to `n+1` if and only if `p` is a Taylor series up to `n`, and
+`p (n + 1)` is a derivative of `p n`. -/
+theorem hasFTaylorSeriesUpToOn_succ_iff_left {n : ℕ} :
+ HasFTaylorSeriesUpToOn (n + 1) f p s ↔
+ HasFTaylorSeriesUpToOn n f p s ∧
+ (∀ x ∈ s, HasFDerivWithinAt (fun y => p y n) (p x n.succ).curryLeft s x) ∧
+ ContinuousOn (fun x => p x (n + 1)) s := by
+ constructor
+ · exact fun h ↦ ⟨h.of_le (WithTop.coe_le_coe.2 (Nat.le_succ n)),
+ h.fderivWithin _ (WithTop.coe_lt_coe.2 (lt_add_one n)), h.cont (n + 1) le_rfl⟩
+ · intro h
+ constructor
+ · exact h.1.zero_eq
+ · intro m hm
+ by_cases h' : m < n
+ · exact h.1.fderivWithin m (WithTop.coe_lt_coe.2 h')
+ · have : m = n := Nat.eq_of_lt_succ_of_not_lt (WithTop.coe_lt_coe.1 hm) h'
+ rw [this]
+ exact h.2.1
+ · intro m hm
+ by_cases h' : m ≤ n
+ · apply h.1.cont m (WithTop.coe_le_coe.2 h')
+ · have : m = n + 1 := le_antisymm (WithTop.coe_le_coe.1 hm) (not_le.1 h')
+ rw [this]
+ exact h.2.2
+
+#adaptation_note
+/--
+After https://github.com/leanprover/lean4/pull/4119,
+without `set_option maxSynthPendingDepth 2` this proof needs substantial repair.
+-/
+set_option maxSynthPendingDepth 2 in
+-- Porting note: this was split out from `hasFTaylorSeriesUpToOn_succ_iff_right` to avoid a timeout.
+theorem HasFTaylorSeriesUpToOn.shift_of_succ
+ {n : ℕ} (H : HasFTaylorSeriesUpToOn (n + 1 : ℕ) f p s) :
+ (HasFTaylorSeriesUpToOn n (fun x => continuousMultilinearCurryFin1 𝕜 E F (p x 1))
+ (fun x => (p x).shift)) s := by
+ constructor
+ · intro x _
+ rfl
+ · intro m (hm : (m : ℕ∞) < n) x (hx : x ∈ s)
+ have A : (m.succ : ℕ∞) < n.succ := by
+ rw [Nat.cast_lt] at hm ⊢
+ exact Nat.succ_lt_succ hm
+ change HasFDerivWithinAt (continuousMultilinearCurryRightEquiv' 𝕜 m E F ∘ (p · m.succ))
+ (p x m.succ.succ).curryRight.curryLeft s x
+ rw [(continuousMultilinearCurryRightEquiv' 𝕜 m E F).comp_hasFDerivWithinAt_iff']
+ convert H.fderivWithin _ A x hx
+ ext y v
+ change p x (m + 2) (snoc (cons y (init v)) (v (last _))) = p x (m + 2) (cons y v)
+ rw [← cons_snoc_eq_snoc_cons, snoc_init_self]
+ · intro m (hm : (m : ℕ∞) ≤ n)
+ suffices A : ContinuousOn (p · (m + 1)) s from
+ (continuousMultilinearCurryRightEquiv' 𝕜 m E F).continuous.comp_continuousOn A
+ refine H.cont _ ?_
+ rw [Nat.cast_le] at hm ⊢
+ exact Nat.succ_le_succ hm
+
+/-- `p` is a Taylor series of `f` up to `n+1` if and only if `p.shift` is a Taylor series up to `n`
+for `p 1`, which is a derivative of `f`. -/
+theorem hasFTaylorSeriesUpToOn_succ_iff_right {n : ℕ} :
+ HasFTaylorSeriesUpToOn (n + 1 : ℕ) f p s ↔
+ (∀ x ∈ s, (p x 0).curry0 = f x) ∧
+ (∀ x ∈ s, HasFDerivWithinAt (fun y => p y 0) (p x 1).curryLeft s x) ∧
+ HasFTaylorSeriesUpToOn n (fun x => continuousMultilinearCurryFin1 𝕜 E F (p x 1))
+ (fun x => (p x).shift) s := by
+ constructor
+ · intro H
+ refine ⟨H.zero_eq, H.fderivWithin 0 (Nat.cast_lt.2 (Nat.succ_pos n)), ?_⟩
+ exact H.shift_of_succ
+ · rintro ⟨Hzero_eq, Hfderiv_zero, Htaylor⟩
+ constructor
+ · exact Hzero_eq
+ · intro m (hm : (m : ℕ∞) < n.succ) x (hx : x ∈ s)
+ cases' m with m
+ · exact Hfderiv_zero x hx
+ · have A : (m : ℕ∞) < n := by
+ rw [Nat.cast_lt] at hm ⊢
+ exact Nat.lt_of_succ_lt_succ hm
+ have :
+ HasFDerivWithinAt (continuousMultilinearCurryRightEquiv' 𝕜 m E F ∘ (p · m.succ))
+ ((p x).shift m.succ).curryLeft s x := Htaylor.fderivWithin _ A x hx
+ rw [LinearIsometryEquiv.comp_hasFDerivWithinAt_iff'] at this
+ convert this
+ ext y v
+ change
+ (p x (Nat.succ (Nat.succ m))) (cons y v) =
+ (p x m.succ.succ) (snoc (cons y (init v)) (v (last _)))
+ rw [← cons_snoc_eq_snoc_cons, snoc_init_self]
+ · intro m (hm : (m : ℕ∞) ≤ n.succ)
+ cases' m with m
+ · have : DifferentiableOn 𝕜 (fun x => p x 0) s := fun x hx =>
+ (Hfderiv_zero x hx).differentiableWithinAt
+ exact this.continuousOn
+ · refine (continuousMultilinearCurryRightEquiv' 𝕜 m E F).comp_continuousOn_iff.mp ?_
+ refine Htaylor.cont _ ?_
+ rw [Nat.cast_le] at hm ⊢
+ exact Nat.lt_succ_iff.mp hm
+
+/-! ### Iterated derivative within a set -/
+
+
+variable (𝕜)
+
+/-- The `n`-th derivative of a function along a set, defined inductively by saying that the `n+1`-th
+derivative of `f` is the derivative of the `n`-th derivative of `f` along this set, together with
+an uncurrying step to see it as a multilinear map in `n+1` variables..
+-/
+noncomputable def iteratedFDerivWithin (n : ℕ) (f : E → F) (s : Set E) : E → E[×n]→L[𝕜] F :=
+ Nat.recOn n (fun x => ContinuousMultilinearMap.uncurry0 𝕜 E (f x)) fun _ rec x =>
+ ContinuousLinearMap.uncurryLeft (fderivWithin 𝕜 rec s x)
+
+/-- Formal Taylor series associated to a function within a set. -/
+def ftaylorSeriesWithin (f : E → F) (s : Set E) (x : E) : FormalMultilinearSeries 𝕜 E F := fun n =>
+ iteratedFDerivWithin 𝕜 n f s x
+
+variable {𝕜}
+
+@[simp]
+theorem iteratedFDerivWithin_zero_apply (m : Fin 0 → E) :
+ (iteratedFDerivWithin 𝕜 0 f s x : (Fin 0 → E) → F) m = f x :=
+ rfl
+
+theorem iteratedFDerivWithin_zero_eq_comp :
+ iteratedFDerivWithin 𝕜 0 f s = (continuousMultilinearCurryFin0 𝕜 E F).symm ∘ f :=
+ rfl
+
+@[simp]
+theorem norm_iteratedFDerivWithin_zero : ‖iteratedFDerivWithin 𝕜 0 f s x‖ = ‖f x‖ := by
+ -- Porting note: added `comp_apply`.
+ rw [iteratedFDerivWithin_zero_eq_comp, comp_apply, LinearIsometryEquiv.norm_map]
+
+theorem iteratedFDerivWithin_succ_apply_left {n : ℕ} (m : Fin (n + 1) → E) :
+ (iteratedFDerivWithin 𝕜 (n + 1) f s x : (Fin (n + 1) → E) → F) m =
+ (fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n f s) s x : E → E[×n]→L[𝕜] F) (m 0) (tail m) :=
+ rfl
+
+/-- Writing explicitly the `n+1`-th derivative as the composition of a currying linear equiv,
+and the derivative of the `n`-th derivative. -/
+theorem iteratedFDerivWithin_succ_eq_comp_left {n : ℕ} :
+ iteratedFDerivWithin 𝕜 (n + 1) f s =
+ (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) => E) F).symm ∘
+ fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n f s) s :=
+ rfl
+
+theorem fderivWithin_iteratedFDerivWithin {s : Set E} {n : ℕ} :
+ fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n f s) s =
+ (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) => E) F) ∘
+ iteratedFDerivWithin 𝕜 (n + 1) f s :=
+ rfl
+
+theorem norm_fderivWithin_iteratedFDerivWithin {n : ℕ} :
+ ‖fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n f s) s x‖ =
+ ‖iteratedFDerivWithin 𝕜 (n + 1) f s x‖ := by
+ -- Porting note: added `comp_apply`.
+ rw [iteratedFDerivWithin_succ_eq_comp_left, comp_apply, LinearIsometryEquiv.norm_map]
+
+theorem iteratedFDerivWithin_succ_apply_right {n : ℕ} (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s)
+ (m : Fin (n + 1) → E) :
+ (iteratedFDerivWithin 𝕜 (n + 1) f s x : (Fin (n + 1) → E) → F) m =
+ iteratedFDerivWithin 𝕜 n (fun y => fderivWithin 𝕜 f s y) s x (init m) (m (last n)) := by
+ induction' n with n IH generalizing x
+ · rw [iteratedFDerivWithin_succ_eq_comp_left, iteratedFDerivWithin_zero_eq_comp,
+ iteratedFDerivWithin_zero_apply, Function.comp_apply,
+ LinearIsometryEquiv.comp_fderivWithin _ (hs x hx)]
+ rfl
+ · let I := (continuousMultilinearCurryRightEquiv' 𝕜 n E F).symm
+ have A : ∀ y ∈ s, iteratedFDerivWithin 𝕜 n.succ f s y =
+ (I ∘ iteratedFDerivWithin 𝕜 n (fun y => fderivWithin 𝕜 f s y) s) y := fun y hy ↦ by
+ ext m
+ rw [@IH y hy m]
+ rfl
+ calc
+ (iteratedFDerivWithin 𝕜 (n + 2) f s x : (Fin (n + 2) → E) → F) m =
+ (fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n.succ f s) s x : E → E[×n + 1]→L[𝕜] F) (m 0)
+ (tail m) :=
+ rfl
+ _ = (fderivWithin 𝕜 (I ∘ iteratedFDerivWithin 𝕜 n (fderivWithin 𝕜 f s) s) s x :
+ E → E[×n + 1]→L[𝕜] F) (m 0) (tail m) := by
+ rw [fderivWithin_congr A (A x hx)]
+ _ = (I ∘ fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n (fderivWithin 𝕜 f s) s) s x :
+ E → E[×n + 1]→L[𝕜] F) (m 0) (tail m) := by
+ #adaptation_note
+ /--
+ After https://github.com/leanprover/lean4/pull/4119 we need to either use
+ `set_option maxSynthPendingDepth 2 in`
+ or fill in an explicit argument as
+ ```
+ simp only [LinearIsometryEquiv.comp_fderivWithin _
+ (f := iteratedFDerivWithin 𝕜 n (fderivWithin 𝕜 f s) s) (hs x hx)]
+ ```
+ -/
+ set_option maxSynthPendingDepth 2 in
+ simp only [LinearIsometryEquiv.comp_fderivWithin _ (hs x hx)]
+ rfl
+ _ = (fderivWithin 𝕜 (iteratedFDerivWithin 𝕜 n (fun y => fderivWithin 𝕜 f s y) s) s x :
+ E → E[×n]→L[𝕜] E →L[𝕜] F) (m 0) (init (tail m)) ((tail m) (last n)) := rfl
+ _ = iteratedFDerivWithin 𝕜 (Nat.succ n) (fun y => fderivWithin 𝕜 f s y) s x (init m)
+ (m (last (n + 1))) := by
+ rw [iteratedFDerivWithin_succ_apply_left, tail_init_eq_init_tail]
+ rfl
+
+/-- Writing explicitly the `n+1`-th derivative as the composition of a currying linear equiv,
+and the `n`-th derivative of the derivative. -/
+theorem iteratedFDerivWithin_succ_eq_comp_right {n : ℕ} (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) :
+ iteratedFDerivWithin 𝕜 (n + 1) f s x =
+ ((continuousMultilinearCurryRightEquiv' 𝕜 n E F).symm ∘
+ iteratedFDerivWithin 𝕜 n (fun y => fderivWithin 𝕜 f s y) s)
+ x := by
+ ext m; rw [iteratedFDerivWithin_succ_apply_right hs hx]; rfl
+
+theorem norm_iteratedFDerivWithin_fderivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) :
+ ‖iteratedFDerivWithin 𝕜 n (fderivWithin 𝕜 f s) s x‖ =
+ ‖iteratedFDerivWithin 𝕜 (n + 1) f s x‖ := by
+ -- Porting note: added `comp_apply`.
+ rw [iteratedFDerivWithin_succ_eq_comp_right hs hx, comp_apply, LinearIsometryEquiv.norm_map]
+
+@[simp]
+theorem iteratedFDerivWithin_one_apply (h : UniqueDiffWithinAt 𝕜 s x) (m : Fin 1 → E) :
+ iteratedFDerivWithin 𝕜 1 f s x m = fderivWithin 𝕜 f s x (m 0) := by
+ simp only [iteratedFDerivWithin_succ_apply_left, iteratedFDerivWithin_zero_eq_comp,
+ (continuousMultilinearCurryFin0 𝕜 E F).symm.comp_fderivWithin h]
+ rfl
+
+/-- On a set of unique differentiability, the second derivative is obtained by taking the
+derivative of the derivative. -/
+lemma iteratedFDerivWithin_two_apply (f : E → F) {z : E} (hs : UniqueDiffOn 𝕜 s) (hz : z ∈ s)
+ (m : Fin 2 → E) :
+ iteratedFDerivWithin 𝕜 2 f s z m = fderivWithin 𝕜 (fderivWithin 𝕜 f s) s z (m 0) (m 1) := by
+ simp only [iteratedFDerivWithin_succ_apply_right hs hz]
+ rfl
+
+theorem Filter.EventuallyEq.iteratedFDerivWithin' (h : f₁ =ᶠ[𝓝[s] x] f) (ht : t ⊆ s) (n : ℕ) :
+ iteratedFDerivWithin 𝕜 n f₁ t =ᶠ[𝓝[s] x] iteratedFDerivWithin 𝕜 n f t := by
+ induction n with
+ | zero => exact h.mono fun y hy => DFunLike.ext _ _ fun _ => hy
+ | succ n ihn =>
+ have : fderivWithin 𝕜 _ t =ᶠ[𝓝[s] x] fderivWithin 𝕜 _ t := ihn.fderivWithin' ht
+ refine this.mono fun y hy => ?_
+ simp only [iteratedFDerivWithin_succ_eq_comp_left, hy, (· ∘ ·)]
+
+protected theorem Filter.EventuallyEq.iteratedFDerivWithin (h : f₁ =ᶠ[𝓝[s] x] f) (n : ℕ) :
+ iteratedFDerivWithin 𝕜 n f₁ s =ᶠ[𝓝[s] x] iteratedFDerivWithin 𝕜 n f s :=
+ h.iteratedFDerivWithin' Subset.rfl n
+
+/-- If two functions coincide in a neighborhood of `x` within a set `s` and at `x`, then their
+iterated differentials within this set at `x` coincide. -/
+theorem Filter.EventuallyEq.iteratedFDerivWithin_eq (h : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x)
+ (n : ℕ) : iteratedFDerivWithin 𝕜 n f₁ s x = iteratedFDerivWithin 𝕜 n f s x :=
+ have : f₁ =ᶠ[𝓝[insert x s] x] f := by simpa [EventuallyEq, hx]
+ (this.iteratedFDerivWithin' (subset_insert _ _) n).self_of_nhdsWithin (mem_insert _ _)
+
+/-- If two functions coincide on a set `s`, then their iterated differentials within this set
+coincide. See also `Filter.EventuallyEq.iteratedFDerivWithin_eq` and
+`Filter.EventuallyEq.iteratedFDerivWithin`. -/
+theorem iteratedFDerivWithin_congr (hs : EqOn f₁ f s) (hx : x ∈ s) (n : ℕ) :
+ iteratedFDerivWithin 𝕜 n f₁ s x = iteratedFDerivWithin 𝕜 n f s x :=
+ (hs.eventuallyEq.filter_mono inf_le_right).iteratedFDerivWithin_eq (hs hx) _
+
+/-- If two functions coincide on a set `s`, then their iterated differentials within this set
+coincide. See also `Filter.EventuallyEq.iteratedFDerivWithin_eq` and
+`Filter.EventuallyEq.iteratedFDerivWithin`. -/
+protected theorem Set.EqOn.iteratedFDerivWithin (hs : EqOn f₁ f s) (n : ℕ) :
+ EqOn (iteratedFDerivWithin 𝕜 n f₁ s) (iteratedFDerivWithin 𝕜 n f s) s := fun _x hx =>
+ iteratedFDerivWithin_congr hs hx n
+
+theorem iteratedFDerivWithin_eventually_congr_set' (y : E) (h : s =ᶠ[𝓝[{y}ᶜ] x] t) (n : ℕ) :
+ iteratedFDerivWithin 𝕜 n f s =ᶠ[𝓝 x] iteratedFDerivWithin 𝕜 n f t := by
+ induction n generalizing x with
+ | zero => rfl
+ | succ n ihn =>
+ refine (eventually_nhds_nhdsWithin.2 h).mono fun y hy => ?_
+ simp only [iteratedFDerivWithin_succ_eq_comp_left, (· ∘ ·)]
+ rw [(ihn hy).fderivWithin_eq_nhds, fderivWithin_congr_set' _ hy]
+
+theorem iteratedFDerivWithin_eventually_congr_set (h : s =ᶠ[𝓝 x] t) (n : ℕ) :
+ iteratedFDerivWithin 𝕜 n f s =ᶠ[𝓝 x] iteratedFDerivWithin 𝕜 n f t :=
+ iteratedFDerivWithin_eventually_congr_set' x (h.filter_mono inf_le_left) n
+
+theorem iteratedFDerivWithin_congr_set (h : s =ᶠ[𝓝 x] t) (n : ℕ) :
+ iteratedFDerivWithin 𝕜 n f s x = iteratedFDerivWithin 𝕜 n f t x :=
+ (iteratedFDerivWithin_eventually_congr_set h n).self_of_nhds
+
+/-- The iterated differential within a set `s` at a point `x` is not modified if one intersects
+`s` with a neighborhood of `x` within `s`. -/
+theorem iteratedFDerivWithin_inter' {n : ℕ} (hu : u ∈ 𝓝[s] x) :
+ iteratedFDerivWithin 𝕜 n f (s ∩ u) x = iteratedFDerivWithin 𝕜 n f s x :=
+ iteratedFDerivWithin_congr_set (nhdsWithin_eq_iff_eventuallyEq.1 <| nhdsWithin_inter_of_mem' hu) _
+
+/-- The iterated differential within a set `s` at a point `x` is not modified if one intersects
+`s` with a neighborhood of `x`. -/
+theorem iteratedFDerivWithin_inter {n : ℕ} (hu : u ∈ 𝓝 x) :
+ iteratedFDerivWithin 𝕜 n f (s ∩ u) x = iteratedFDerivWithin 𝕜 n f s x :=
+ iteratedFDerivWithin_inter' (mem_nhdsWithin_of_mem_nhds hu)
+
+/-- The iterated differential within a set `s` at a point `x` is not modified if one intersects
+`s` with an open set containing `x`. -/
+theorem iteratedFDerivWithin_inter_open {n : ℕ} (hu : IsOpen u) (hx : x ∈ u) :
+ iteratedFDerivWithin 𝕜 n f (s ∩ u) x = iteratedFDerivWithin 𝕜 n f s x :=
+ iteratedFDerivWithin_inter (hu.mem_nhds hx)
+
+/-- On a set with unique differentiability, any choice of iterated differential has to coincide
+with the one we have chosen in `iteratedFDerivWithin 𝕜 m f s`. -/
+theorem HasFTaylorSeriesUpToOn.eq_iteratedFDerivWithin_of_uniqueDiffOn
+ (h : HasFTaylorSeriesUpToOn n f p s) {m : ℕ} (hmn : (m : ℕ∞) ≤ n) (hs : UniqueDiffOn 𝕜 s)
+ (hx : x ∈ s) : p x m = iteratedFDerivWithin 𝕜 m f s x := by
+ induction' m with m IH generalizing x
+ · rw [h.zero_eq' hx, iteratedFDerivWithin_zero_eq_comp]; rfl
+ · have A : (m : ℕ∞) < n := lt_of_lt_of_le (WithTop.coe_lt_coe.2 (lt_add_one m)) hmn
+ have :
+ HasFDerivWithinAt (fun y : E => iteratedFDerivWithin 𝕜 m f s y)
+ (ContinuousMultilinearMap.curryLeft (p x (Nat.succ m))) s x :=
+ (h.fderivWithin m A x hx).congr (fun y hy => (IH (le_of_lt A) hy).symm)
+ (IH (le_of_lt A) hx).symm
+ rw [iteratedFDerivWithin_succ_eq_comp_left, Function.comp_apply, this.fderivWithin (hs x hx)]
+ exact (ContinuousMultilinearMap.uncurry_curryLeft _).symm
+
+@[deprecated (since := "2024-03-28")]
+alias HasFTaylorSeriesUpToOn.eq_ftaylor_series_of_uniqueDiffOn :=
+ HasFTaylorSeriesUpToOn.eq_iteratedFDerivWithin_of_uniqueDiffOn
+
+
+/-! ### Functions with a Taylor series on the whole space -/
+
+/-- `HasFTaylorSeriesUpTo n f p` registers the fact that `p 0 = f` and `p (m+1)` is a
+derivative of `p m` for `m < n`, and is continuous for `m ≤ n`. This is a predicate analogous to
+`HasFDerivAt` but for higher order derivatives.
+
+Notice that `p` does not sum up to `f` on the diagonal (`FormalMultilinearSeries.sum`), even if
+`f` is analytic and `n = ∞`: an addition `1/m!` factor on the `m`th term is necessary for that. -/
+structure HasFTaylorSeriesUpTo (n : ℕ∞) (f : E → F) (p : E → FormalMultilinearSeries 𝕜 E F) :
+ Prop where
+ zero_eq : ∀ x, (p x 0).curry0 = f x
+ fderiv : ∀ m : ℕ, (m : ℕ∞) < n → ∀ x, HasFDerivAt (fun y => p y m) (p x m.succ).curryLeft x
+ cont : ∀ m : ℕ, (m : ℕ∞) ≤ n → Continuous fun x => p x m
+
+theorem HasFTaylorSeriesUpTo.zero_eq' (h : HasFTaylorSeriesUpTo n f p) (x : E) :
+ p x 0 = (continuousMultilinearCurryFin0 𝕜 E F).symm (f x) := by
+ rw [← h.zero_eq x]
+ exact (p x 0).uncurry0_curry0.symm
+
+theorem hasFTaylorSeriesUpToOn_univ_iff :
+ HasFTaylorSeriesUpToOn n f p univ ↔ HasFTaylorSeriesUpTo n f p := by
+ constructor
+ · intro H
+ constructor
+ · exact fun x => H.zero_eq x (mem_univ x)
+ · intro m hm x
+ rw [← hasFDerivWithinAt_univ]
+ exact H.fderivWithin m hm x (mem_univ x)
+ · intro m hm
+ rw [continuous_iff_continuousOn_univ]
+ exact H.cont m hm
+ · intro H
+ constructor
+ · exact fun x _ => H.zero_eq x
+ · intro m hm x _
+ rw [hasFDerivWithinAt_univ]
+ exact H.fderiv m hm x
+ · intro m hm
+ rw [← continuous_iff_continuousOn_univ]
+ exact H.cont m hm
+
+theorem HasFTaylorSeriesUpTo.hasFTaylorSeriesUpToOn (h : HasFTaylorSeriesUpTo n f p) (s : Set E) :
+ HasFTaylorSeriesUpToOn n f p s :=
+ (hasFTaylorSeriesUpToOn_univ_iff.2 h).mono (subset_univ _)
+
+theorem HasFTaylorSeriesUpTo.ofLe (h : HasFTaylorSeriesUpTo n f p) (hmn : m ≤ n) :
+ HasFTaylorSeriesUpTo m f p := by
+ rw [← hasFTaylorSeriesUpToOn_univ_iff] at h ⊢; exact h.of_le hmn
+
+theorem HasFTaylorSeriesUpTo.continuous (h : HasFTaylorSeriesUpTo n f p) : Continuous f := by
+ rw [← hasFTaylorSeriesUpToOn_univ_iff] at h
+ rw [continuous_iff_continuousOn_univ]
+ exact h.continuousOn
+
+theorem hasFTaylorSeriesUpTo_zero_iff :
+ HasFTaylorSeriesUpTo 0 f p ↔ Continuous f ∧ ∀ x, (p x 0).curry0 = f x := by
+ simp [hasFTaylorSeriesUpToOn_univ_iff.symm, continuous_iff_continuousOn_univ,
+ hasFTaylorSeriesUpToOn_zero_iff]
+
+theorem hasFTaylorSeriesUpTo_top_iff :
+ HasFTaylorSeriesUpTo ∞ f p ↔ ∀ n : ℕ, HasFTaylorSeriesUpTo n f p := by
+ simp only [← hasFTaylorSeriesUpToOn_univ_iff, hasFTaylorSeriesUpToOn_top_iff]
+
+/-- In the case that `n = ∞` we don't need the continuity assumption in
+`HasFTaylorSeriesUpTo`. -/
+theorem hasFTaylorSeriesUpTo_top_iff' :
+ HasFTaylorSeriesUpTo ∞ f p ↔
+ (∀ x, (p x 0).curry0 = f x) ∧
+ ∀ (m : ℕ) (x), HasFDerivAt (fun y => p y m) (p x m.succ).curryLeft x := by
+ simp only [← hasFTaylorSeriesUpToOn_univ_iff, hasFTaylorSeriesUpToOn_top_iff', mem_univ,
+ forall_true_left, hasFDerivWithinAt_univ]
+
+/-- If a function has a Taylor series at order at least `1`, then the term of order `1` of this
+series is a derivative of `f`. -/
+theorem HasFTaylorSeriesUpTo.hasFDerivAt (h : HasFTaylorSeriesUpTo n f p) (hn : 1 ≤ n) (x : E) :
+ HasFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p x 1)) x := by
+ rw [← hasFDerivWithinAt_univ]
+ exact (hasFTaylorSeriesUpToOn_univ_iff.2 h).hasFDerivWithinAt hn (mem_univ _)
+
+theorem HasFTaylorSeriesUpTo.differentiable (h : HasFTaylorSeriesUpTo n f p) (hn : 1 ≤ n) :
+ Differentiable 𝕜 f := fun x => (h.hasFDerivAt hn x).differentiableAt
+
+/-- `p` is a Taylor series of `f` up to `n+1` if and only if `p.shift` is a Taylor series up to `n`
+for `p 1`, which is a derivative of `f`. -/
+theorem hasFTaylorSeriesUpTo_succ_iff_right {n : ℕ} :
+ HasFTaylorSeriesUpTo (n + 1 : ℕ) f p ↔
+ (∀ x, (p x 0).curry0 = f x) ∧
+ (∀ x, HasFDerivAt (fun y => p y 0) (p x 1).curryLeft x) ∧
+ HasFTaylorSeriesUpTo n (fun x => continuousMultilinearCurryFin1 𝕜 E F (p x 1)) fun x =>
+ (p x).shift := by
+ simp only [hasFTaylorSeriesUpToOn_succ_iff_right, ← hasFTaylorSeriesUpToOn_univ_iff, mem_univ,
+ forall_true_left, hasFDerivWithinAt_univ]
+
+
+/-! ### Iterated derivative -/
+
+
+variable (𝕜)
+
+/-- The `n`-th derivative of a function, as a multilinear map, defined inductively. -/
+noncomputable def iteratedFDeriv (n : ℕ) (f : E → F) : E → E[×n]→L[𝕜] F :=
+ Nat.recOn n (fun x => ContinuousMultilinearMap.uncurry0 𝕜 E (f x)) fun _ rec x =>
+ ContinuousLinearMap.uncurryLeft (fderiv 𝕜 rec x)
+
+/-- Formal Taylor series associated to a function. -/
+def ftaylorSeries (f : E → F) (x : E) : FormalMultilinearSeries 𝕜 E F := fun n =>
+ iteratedFDeriv 𝕜 n f x
+
+variable {𝕜}
+
+@[simp]
+theorem iteratedFDeriv_zero_apply (m : Fin 0 → E) :
+ (iteratedFDeriv 𝕜 0 f x : (Fin 0 → E) → F) m = f x :=
+ rfl
+
+theorem iteratedFDeriv_zero_eq_comp :
+ iteratedFDeriv 𝕜 0 f = (continuousMultilinearCurryFin0 𝕜 E F).symm ∘ f :=
+ rfl
+
+@[simp]
+theorem norm_iteratedFDeriv_zero : ‖iteratedFDeriv 𝕜 0 f x‖ = ‖f x‖ := by
+ -- Porting note: added `comp_apply`.
+ rw [iteratedFDeriv_zero_eq_comp, comp_apply, LinearIsometryEquiv.norm_map]
+
+theorem iteratedFDerivWithin_zero_eq : iteratedFDerivWithin 𝕜 0 f s = iteratedFDeriv 𝕜 0 f := rfl
+
+theorem iteratedFDeriv_succ_apply_left {n : ℕ} (m : Fin (n + 1) → E) :
+ (iteratedFDeriv 𝕜 (n + 1) f x : (Fin (n + 1) → E) → F) m =
+ (fderiv 𝕜 (iteratedFDeriv 𝕜 n f) x : E → E[×n]→L[𝕜] F) (m 0) (tail m) :=
+ rfl
+
+/-- Writing explicitly the `n+1`-th derivative as the composition of a currying linear equiv,
+and the derivative of the `n`-th derivative. -/
+theorem iteratedFDeriv_succ_eq_comp_left {n : ℕ} :
+ iteratedFDeriv 𝕜 (n + 1) f =
+ (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) => E) F).symm ∘
+ fderiv 𝕜 (iteratedFDeriv 𝕜 n f) :=
+ rfl
+
+/-- Writing explicitly the derivative of the `n`-th derivative as the composition of a currying
+linear equiv, and the `n + 1`-th derivative. -/
+theorem fderiv_iteratedFDeriv {n : ℕ} :
+ fderiv 𝕜 (iteratedFDeriv 𝕜 n f) =
+ continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) => E) F ∘
+ iteratedFDeriv 𝕜 (n + 1) f :=
+ rfl
+
+theorem tsupport_iteratedFDeriv_subset (n : ℕ) : tsupport (iteratedFDeriv 𝕜 n f) ⊆ tsupport f := by
+ induction n with
+ | zero =>
+ rw [iteratedFDeriv_zero_eq_comp]
+ exact closure_minimal ((support_comp_subset (LinearIsometryEquiv.map_zero _) _).trans
+ subset_closure) isClosed_closure
+ | succ n IH =>
+ rw [iteratedFDeriv_succ_eq_comp_left]
+ exact closure_minimal ((support_comp_subset (LinearIsometryEquiv.map_zero _) _).trans
+ ((support_fderiv_subset 𝕜).trans IH)) isClosed_closure
+
+theorem support_iteratedFDeriv_subset (n : ℕ) : support (iteratedFDeriv 𝕜 n f) ⊆ tsupport f :=
+ subset_closure.trans (tsupport_iteratedFDeriv_subset n)
+
+theorem HasCompactSupport.iteratedFDeriv (hf : HasCompactSupport f) (n : ℕ) :
+ HasCompactSupport (iteratedFDeriv 𝕜 n f) :=
+ hf.of_isClosed_subset isClosed_closure (tsupport_iteratedFDeriv_subset n)
+
+theorem norm_fderiv_iteratedFDeriv {n : ℕ} :
+ ‖fderiv 𝕜 (iteratedFDeriv 𝕜 n f) x‖ = ‖iteratedFDeriv 𝕜 (n + 1) f x‖ := by
+ -- Porting note: added `comp_apply`.
+ rw [iteratedFDeriv_succ_eq_comp_left, comp_apply, LinearIsometryEquiv.norm_map]
+
+theorem iteratedFDerivWithin_univ {n : ℕ} :
+ iteratedFDerivWithin 𝕜 n f univ = iteratedFDeriv 𝕜 n f := by
+ induction n with
+ | zero => ext x; simp
+ | succ n IH =>
+ ext x m
+ rw [iteratedFDeriv_succ_apply_left, iteratedFDerivWithin_succ_apply_left, IH, fderivWithin_univ]
+
+theorem HasFTaylorSeriesUpTo.eq_iteratedFDeriv
+ (h : HasFTaylorSeriesUpTo n f p) {m : ℕ} (hmn : (m : ℕ∞) ≤ n) (x : E) :
+ p x m = iteratedFDeriv 𝕜 m f x := by
+ rw [← iteratedFDerivWithin_univ]
+ rw [← hasFTaylorSeriesUpToOn_univ_iff] at h
+ exact h.eq_iteratedFDerivWithin_of_uniqueDiffOn hmn uniqueDiffOn_univ (mem_univ _)
+
+/-- In an open set, the iterated derivative within this set coincides with the global iterated
+derivative. -/
+theorem iteratedFDerivWithin_of_isOpen (n : ℕ) (hs : IsOpen s) :
+ EqOn (iteratedFDerivWithin 𝕜 n f s) (iteratedFDeriv 𝕜 n f) s := by
+ induction n with
+ | zero =>
+ intro x _
+ ext1
+ simp only [iteratedFDerivWithin_zero_apply, iteratedFDeriv_zero_apply]
+ | succ n IH =>
+ intro x hx
+ rw [iteratedFDeriv_succ_eq_comp_left, iteratedFDerivWithin_succ_eq_comp_left]
+ dsimp
+ congr 1
+ rw [fderivWithin_of_isOpen hs hx]
+ apply Filter.EventuallyEq.fderiv_eq
+ filter_upwards [hs.mem_nhds hx]
+ exact IH
+
+theorem ftaylorSeriesWithin_univ : ftaylorSeriesWithin 𝕜 f univ = ftaylorSeries 𝕜 f := by
+ ext1 x; ext1 n
+ change iteratedFDerivWithin 𝕜 n f univ x = iteratedFDeriv 𝕜 n f x
+ rw [iteratedFDerivWithin_univ]
+
+theorem iteratedFDeriv_succ_apply_right {n : ℕ} (m : Fin (n + 1) → E) :
+ (iteratedFDeriv 𝕜 (n + 1) f x : (Fin (n + 1) → E) → F) m =
+ iteratedFDeriv 𝕜 n (fun y => fderiv 𝕜 f y) x (init m) (m (last n)) := by
+ rw [← iteratedFDerivWithin_univ, ← iteratedFDerivWithin_univ, ← fderivWithin_univ]
+ exact iteratedFDerivWithin_succ_apply_right uniqueDiffOn_univ (mem_univ _) _
+
+/-- Writing explicitly the `n+1`-th derivative as the composition of a currying linear equiv,
+and the `n`-th derivative of the derivative. -/
+theorem iteratedFDeriv_succ_eq_comp_right {n : ℕ} :
+ iteratedFDeriv 𝕜 (n + 1) f x =
+ ((continuousMultilinearCurryRightEquiv' 𝕜 n E F).symm ∘
+ iteratedFDeriv 𝕜 n fun y => fderiv 𝕜 f y) x := by
+ ext m; rw [iteratedFDeriv_succ_apply_right]; rfl
+
+theorem norm_iteratedFDeriv_fderiv {n : ℕ} :
+ ‖iteratedFDeriv 𝕜 n (fderiv 𝕜 f) x‖ = ‖iteratedFDeriv 𝕜 (n + 1) f x‖ := by
+ -- Porting note: added `comp_apply`.
+ rw [iteratedFDeriv_succ_eq_comp_right, comp_apply, LinearIsometryEquiv.norm_map]
+
+@[simp]
+theorem iteratedFDeriv_one_apply (m : Fin 1 → E) :
+ iteratedFDeriv 𝕜 1 f x m = fderiv 𝕜 f x (m 0) := by
+ rw [iteratedFDeriv_succ_apply_right, iteratedFDeriv_zero_apply]; rfl
+
+lemma iteratedFDeriv_two_apply (f : E → F) (z : E) (m : Fin 2 → E) :
+ iteratedFDeriv 𝕜 2 f z m = fderiv 𝕜 (fderiv 𝕜 f) z (m 0) (m 1) := by
+ simp only [iteratedFDeriv_succ_apply_right]
+ rfl
diff --git a/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean b/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean
index 7b0d3e391e4fd..e5d673c7ffac0 100644
--- a/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean
+++ b/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean
@@ -14,32 +14,33 @@ 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 -/
section FiniteDimensional
-open Function FiniteDimensional
+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
new file mode 100644
index 0000000000000..a5f01ae326dcf
--- /dev/null
+++ b/Mathlib/Analysis/Calculus/Deriv/Abs.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.Add
+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 analogous file for norms derived
+from an inner product space.
+
+## Tags
+
+absolute value, derivative
+-/
+
+open Filter Real Set
+
+variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ 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
+
+theorem ContDiffAt.abs (hf : ContDiffAt ℝ n f x) (h₀ : f x ≠ 0) :
+ ContDiffAt ℝ n (fun x ↦ |f x|) x := hf.norm ℝ h₀
+
+theorem contDiffWithinAt_abs {x : ℝ} (hx : x ≠ 0) (s : Set ℝ) :
+ ContDiffWithinAt ℝ n (|·|) s x := (contDiffAt_abs hx).contDiffWithinAt
+
+theorem ContDiffWithinAt.abs (hf : ContDiffWithinAt ℝ n f s x) (h₀ : f x ≠ 0) :
+ ContDiffWithinAt ℝ n (fun y ↦ |f y|) s x :=
+ (contDiffAt_abs h₀).comp_contDiffWithinAt x hf
+
+theorem contDiffOn_abs {s : Set ℝ} (hs : ∀ x ∈ s, x ≠ 0) :
+ ContDiffOn ℝ n (|·|) s := fun x hx ↦ contDiffWithinAt_abs (hs x hx) s
+
+theorem ContDiffOn.abs (hf : ContDiffOn ℝ n f s) (h₀ : ∀ x ∈ s, f x ≠ 0) :
+ ContDiffOn ℝ n (fun y ↦ |f y|) s := fun x hx ↦ (hf x hx).abs (h₀ x hx)
+
+theorem ContDiff.abs (hf : ContDiff ℝ n f) (h₀ : ∀ x, f x ≠ 0) : ContDiff ℝ n fun y ↦ |f y| :=
+ contDiff_iff_contDiffAt.2 fun x ↦ hf.contDiffAt.abs (h₀ x)
+
+theorem hasStrictDerivAt_abs_neg {x : ℝ} (hx : x < 0) :
+ HasStrictDerivAt (|·|) (-1) x :=
+ (hasStrictDerivAt_neg x).congr_of_eventuallyEq <|
+ EqOn.eventuallyEq_of_mem (fun _ hy ↦ (abs_of_neg (mem_Iio.1 hy)).symm) (Iio_mem_nhds hx)
+
+theorem hasDerivAt_abs_neg {x : ℝ} (hx : x < 0) :
+ HasDerivAt (|·|) (-1) x := (hasStrictDerivAt_abs_neg hx).hasDerivAt
+
+theorem hasStrictDerivAt_abs_pos {x : ℝ} (hx : 0 < x) :
+ HasStrictDerivAt (|·|) 1 x :=
+ (hasStrictDerivAt_id x).congr_of_eventuallyEq <|
+ EqOn.eventuallyEq_of_mem (fun _ hy ↦ (abs_of_pos (mem_Iio.1 hy)).symm) (Ioi_mem_nhds hx)
+
+theorem hasDerivAt_abs_pos {x : ℝ} (hx : 0 < x) :
+ HasDerivAt (|·|) 1 x := (hasStrictDerivAt_abs_pos hx).hasDerivAt
+
+theorem hasStrictDerivAt_abs {x : ℝ} (hx : x ≠ 0) :
+ HasStrictDerivAt (|·|) (SignType.sign x : ℝ) x := by
+ obtain hx | hx := hx.lt_or_lt
+ · simpa [hx] using hasStrictDerivAt_abs_neg hx
+ · simpa [hx] using hasStrictDerivAt_abs_pos hx
+
+theorem hasDerivAt_abs {x : ℝ} (hx : x ≠ 0) :
+ HasDerivAt (|·|) (SignType.sign x : ℝ) x := (hasStrictDerivAt_abs hx).hasDerivAt
+
+theorem HasStrictFDerivAt.abs_of_neg (hf : HasStrictFDerivAt f f' x)
+ (h₀ : f x < 0) : HasStrictFDerivAt (fun x ↦ |f x|) (-f') x := by
+ convert (hasStrictDerivAt_abs_neg h₀).hasStrictFDerivAt.comp x hf using 1
+ ext y
+ simp
+
+theorem HasFDerivAt.abs_of_neg (hf : HasFDerivAt f f' x)
+ (h₀ : f x < 0) : HasFDerivAt (fun x ↦ |f x|) (-f') x := by
+ convert (hasDerivAt_abs_neg h₀).hasFDerivAt.comp x hf using 1
+ ext y
+ simp
+
+theorem HasStrictFDerivAt.abs_of_pos (hf : HasStrictFDerivAt f f' x)
+ (h₀ : 0 < f x) : HasStrictFDerivAt (fun x ↦ |f x|) f' x := by
+ convert (hasStrictDerivAt_abs_pos h₀).hasStrictFDerivAt.comp x hf using 1
+ ext y
+ simp
+
+theorem HasFDerivAt.abs_of_pos (hf : HasFDerivAt f f' x)
+ (h₀ : 0 < f x) : HasFDerivAt (fun x ↦ |f x|) f' x := by
+ convert (hasDerivAt_abs_pos h₀).hasFDerivAt.comp x hf using 1
+ ext y
+ simp
+
+theorem HasStrictFDerivAt.abs (hf : HasStrictFDerivAt f f' x)
+ (h₀ : f x ≠ 0) : HasStrictFDerivAt (fun x ↦ |f x|) ((SignType.sign (f x) : ℝ) • f') x := by
+ convert (hasStrictDerivAt_abs h₀).hasStrictFDerivAt.comp x hf using 1
+ ext y
+ simp [mul_comm]
+
+theorem HasFDerivAt.abs (hf : HasFDerivAt f f' x)
+ (h₀ : f x ≠ 0) : HasFDerivAt (fun x ↦ |f x|) ((SignType.sign (f x) : ℝ) • f') x := by
+ convert (hasDerivAt_abs h₀).hasFDerivAt.comp x hf using 1
+ ext y
+ simp [mul_comm]
+
+theorem hasDerivWithinAt_abs_neg (s : Set ℝ) {x : ℝ} (hx : x < 0) :
+ HasDerivWithinAt (|·|) (-1) s x := (hasDerivAt_abs_neg hx).hasDerivWithinAt
+
+theorem hasDerivWithinAt_abs_pos (s : Set ℝ) {x : ℝ} (hx : 0 < x) :
+ HasDerivWithinAt (|·|) 1 s x := (hasDerivAt_abs_pos hx).hasDerivWithinAt
+
+theorem hasDerivWithinAt_abs (s : Set ℝ) {x : ℝ} (hx : x ≠ 0) :
+ HasDerivWithinAt (|·|) (SignType.sign x : ℝ) s x := (hasDerivAt_abs hx).hasDerivWithinAt
+
+theorem HasFDerivWithinAt.abs_of_neg (hf : HasFDerivWithinAt f f' s x)
+ (h₀ : f x < 0) : HasFDerivWithinAt (fun x ↦ |f x|) (-f') s x := by
+ convert (hasDerivAt_abs_neg h₀).comp_hasFDerivWithinAt x hf using 1
+ simp
+
+theorem HasFDerivWithinAt.abs_of_pos (hf : HasFDerivWithinAt f f' s x)
+ (h₀ : 0 < f x) : HasFDerivWithinAt (fun x ↦ |f x|) f' s x := by
+ convert (hasDerivAt_abs_pos h₀).comp_hasFDerivWithinAt x hf using 1
+ simp
+
+theorem HasFDerivWithinAt.abs (hf : HasFDerivWithinAt f f' s x)
+ (h₀ : f x ≠ 0) : HasFDerivWithinAt (fun x ↦ |f x|) ((SignType.sign (f x) : ℝ) • f') s x :=
+ (hasDerivAt_abs h₀).comp_hasFDerivWithinAt x hf
+
+theorem differentiableAt_abs_neg {x : ℝ} (hx : x < 0) :
+ DifferentiableAt ℝ (|·|) x := (hasDerivAt_abs_neg hx).differentiableAt
+
+theorem differentiableAt_abs_pos {x : ℝ} (hx : 0 < x) :
+ DifferentiableAt ℝ (|·|) x := (hasDerivAt_abs_pos hx).differentiableAt
+
+theorem differentiableAt_abs {x : ℝ} (hx : x ≠ 0) :
+ DifferentiableAt ℝ (|·|) x := (hasDerivAt_abs hx).differentiableAt
+
+theorem DifferentiableAt.abs_of_neg (hf : DifferentiableAt ℝ f x) (h₀ : f x < 0) :
+ DifferentiableAt ℝ (fun x ↦ |f x|) x := (differentiableAt_abs_neg h₀).comp x hf
+
+theorem DifferentiableAt.abs_of_pos (hf : DifferentiableAt ℝ f x) (h₀ : 0 < f x) :
+ DifferentiableAt ℝ (fun x ↦ |f x|) x := (differentiableAt_abs_pos h₀).comp x hf
+
+theorem DifferentiableAt.abs (hf : DifferentiableAt ℝ f x) (h₀ : f x ≠ 0) :
+ DifferentiableAt ℝ (fun x ↦ |f x|) x := (differentiableAt_abs h₀).comp x hf
+
+theorem differentiableWithinAt_abs_neg (s : Set ℝ) {x : ℝ} (hx : x < 0) :
+ DifferentiableWithinAt ℝ (|·|) s x := (differentiableAt_abs_neg hx).differentiableWithinAt
+
+theorem differentiableWithinAt_abs_pos (s : Set ℝ) {x : ℝ} (hx : 0 < x) :
+ DifferentiableWithinAt ℝ (|·|) s x := (differentiableAt_abs_pos hx).differentiableWithinAt
+
+theorem differentiableWithinAt_abs (s : Set ℝ) {x : ℝ} (hx : x ≠ 0) :
+ DifferentiableWithinAt ℝ (|·|) s x := (differentiableAt_abs hx).differentiableWithinAt
+
+theorem DifferentiableWithinAt.abs_of_neg (hf : DifferentiableWithinAt ℝ f s x) (h₀ : f x < 0) :
+ DifferentiableWithinAt ℝ (fun x ↦ |f x|) s x :=
+ (differentiableAt_abs_neg h₀).comp_differentiableWithinAt x hf
+
+theorem DifferentiableWithinAt.abs_of_pos (hf : DifferentiableWithinAt ℝ f s x) (h₀ : 0 < f x) :
+ DifferentiableWithinAt ℝ (fun x ↦ |f x|) s x :=
+ (differentiableAt_abs_pos h₀).comp_differentiableWithinAt x hf
+
+theorem DifferentiableWithinAt.abs (hf : DifferentiableWithinAt ℝ f s x) (h₀ : f x ≠ 0) :
+ DifferentiableWithinAt ℝ (fun x ↦ |f x|) s x :=
+ (differentiableAt_abs h₀).comp_differentiableWithinAt x hf
+
+theorem differentiableOn_abs {s : Set ℝ} (hs : ∀ x ∈ s, x ≠ 0) : DifferentiableOn ℝ (|·|) s :=
+ fun x hx ↦ differentiableWithinAt_abs s (hs x hx)
+
+theorem DifferentiableOn.abs (hf : DifferentiableOn ℝ f s) (h₀ : ∀ x ∈ s, f x ≠ 0) :
+ DifferentiableOn ℝ (fun x ↦ |f x|) s :=
+ fun x hx ↦ (hf x hx).abs (h₀ x hx)
+
+theorem Differentiable.abs (hf : Differentiable ℝ f) (h₀ : ∀ x, f x ≠ 0) :
+ Differentiable ℝ (fun x ↦ |f x|) := fun x ↦ (hf x).abs (h₀ x)
+
+theorem not_differentiableAt_abs_zero : ¬ DifferentiableAt ℝ (abs : ℝ → ℝ) 0 := by
+ intro h
+ have h₁ : deriv abs (0 : ℝ) = 1 :=
+ (uniqueDiffOn_Ici _ _ Set.left_mem_Ici).eq_deriv _ h.hasDerivAt.hasDerivWithinAt <|
+ (hasDerivWithinAt_id _ _).congr_of_mem (fun _ h ↦ abs_of_nonneg h) Set.left_mem_Ici
+ have h₂ : deriv abs (0 : ℝ) = -1 :=
+ (uniqueDiffOn_Iic _ _ Set.right_mem_Iic).eq_deriv _ h.hasDerivAt.hasDerivWithinAt <|
+ (hasDerivWithinAt_neg _ _).congr_of_mem (fun _ h ↦ abs_of_nonpos h) Set.right_mem_Iic
+ linarith
+
+theorem deriv_abs_neg {x : ℝ} (hx : x < 0) : deriv (|·|) x = -1 := (hasDerivAt_abs_neg hx).deriv
+
+theorem deriv_abs_pos {x : ℝ} (hx : 0 < x) : deriv (|·|) x = 1 := (hasDerivAt_abs_pos hx).deriv
+
+theorem deriv_abs_zero : deriv (|·|) (0 : ℝ) = 0 :=
+ deriv_zero_of_not_differentiableAt not_differentiableAt_abs_zero
+
+theorem deriv_abs (x : ℝ) : deriv (|·|) x = SignType.sign x := by
+ obtain rfl | hx := eq_or_ne x 0
+ · simpa using deriv_abs_zero
+ · simpa [hx] using (hasDerivAt_abs hx).deriv
diff --git a/Mathlib/Analysis/Calculus/Deriv/Add.lean b/Mathlib/Analysis/Calculus/Deriv/Add.lean
index 6f51814995811..169722bc11409 100644
--- a/Mathlib/Analysis/Calculus/Deriv/Add.lean
+++ b/Mathlib/Analysis/Calculus/Deriv/Add.lean
@@ -247,16 +247,6 @@ theorem differentiable_neg : Differentiable 𝕜 (Neg.neg : 𝕜 → 𝕜) :=
theorem differentiableOn_neg : DifferentiableOn 𝕜 (Neg.neg : 𝕜 → 𝕜) s :=
DifferentiableOn.neg differentiableOn_id
-theorem not_differentiableAt_abs_zero : ¬ DifferentiableAt ℝ (abs : ℝ → ℝ) 0 := by
- intro h
- have h₁ : deriv abs (0 : ℝ) = 1 :=
- (uniqueDiffOn_Ici _ _ Set.left_mem_Ici).eq_deriv _ h.hasDerivAt.hasDerivWithinAt <|
- (hasDerivWithinAt_id _ _).congr_of_mem (fun _ h ↦ abs_of_nonneg h) Set.left_mem_Ici
- have h₂ : deriv abs (0 : ℝ) = -1 :=
- (uniqueDiffOn_Iic _ _ Set.right_mem_Iic).eq_deriv _ h.hasDerivAt.hasDerivWithinAt <|
- (hasDerivWithinAt_neg _ _).congr_of_mem (fun _ h ↦ abs_of_nonpos h) Set.right_mem_Iic
- linarith
-
lemma differentiableAt_comp_neg {a : 𝕜} :
DifferentiableAt 𝕜 (fun x ↦ f (-x)) a ↔ DifferentiableAt 𝕜 f (-a) := by
refine ⟨fun H ↦ ?_, fun H ↦ H.comp a differentiable_neg.differentiableAt⟩
diff --git a/Mathlib/Analysis/Calculus/Deriv/Basic.lean b/Mathlib/Analysis/Calculus/Deriv/Basic.lean
index edda887e12373..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 𝕜}
@@ -416,7 +415,7 @@ theorem norm_deriv_eq_norm_fderiv : ‖deriv f x‖ = ‖fderiv 𝕜 f x‖ := b
theorem DifferentiableAt.derivWithin (h : DifferentiableAt 𝕜 f x) (hxs : UniqueDiffWithinAt 𝕜 s x) :
derivWithin f s x = deriv f x := by
- unfold derivWithin deriv
+ unfold _root_.derivWithin deriv
rw [h.fderivWithin hxs]
theorem HasDerivWithinAt.deriv_eq_zero (hd : HasDerivWithinAt f 0 s x)
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 ffa6762826f8e..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
@@ -63,20 +56,13 @@ theorem hasDerivWithinAt_inv (x_ne_zero : x ≠ 0) (s : Set 𝕜) :
HasDerivWithinAt (fun x => x⁻¹) (-(x ^ 2)⁻¹) s x :=
(hasDerivAt_inv x_ne_zero).hasDerivWithinAt
-theorem differentiableAt_inv : DifferentiableAt 𝕜 (fun x => x⁻¹) x ↔ x ≠ 0 :=
+theorem differentiableAt_inv_iff : DifferentiableAt 𝕜 (fun x => x⁻¹) x ↔ x ≠ 0 :=
⟨fun H => NormedField.continuousAt_inv.1 H.continuousAt, fun H =>
(hasDerivAt_inv H).differentiableAt⟩
-theorem differentiableWithinAt_inv (x_ne_zero : x ≠ 0) :
- DifferentiableWithinAt 𝕜 (fun x => x⁻¹) s x :=
- (differentiableAt_inv.2 x_ne_zero).differentiableWithinAt
-
-theorem differentiableOn_inv : DifferentiableOn 𝕜 (fun x : 𝕜 => x⁻¹) { x | x ≠ 0 } := fun _x hx =>
- differentiableWithinAt_inv hx
-
theorem deriv_inv : deriv (fun x => x⁻¹) x = -(x ^ 2)⁻¹ := by
rcases eq_or_ne x 0 with (rfl | hne)
- · simp [deriv_zero_of_not_differentiableAt (mt differentiableAt_inv.1 (not_not.2 rfl))]
+ · simp [deriv_zero_of_not_differentiableAt (mt differentiableAt_inv_iff.1 (not_not.2 rfl))]
· exact (hasDerivAt_inv hne).deriv
@[simp]
@@ -85,13 +71,17 @@ theorem deriv_inv' : (deriv fun x : 𝕜 => x⁻¹) = fun x => -(x ^ 2)⁻¹ :=
theorem derivWithin_inv (x_ne_zero : x ≠ 0) (hxs : UniqueDiffWithinAt 𝕜 s x) :
derivWithin (fun x => x⁻¹) s x = -(x ^ 2)⁻¹ := by
- rw [DifferentiableAt.derivWithin (differentiableAt_inv.2 x_ne_zero) hxs]
+ rw [DifferentiableAt.derivWithin (differentiableAt_inv x_ne_zero) hxs]
exact deriv_inv
theorem hasFDerivAt_inv (x_ne_zero : x ≠ 0) :
HasFDerivAt (fun x => x⁻¹) (smulRight (1 : 𝕜 →L[𝕜] 𝕜) (-(x ^ 2)⁻¹) : 𝕜 →L[𝕜] 𝕜) x :=
hasDerivAt_inv x_ne_zero
+theorem hasStrictFDerivAt_inv (x_ne_zero : x ≠ 0) :
+ HasStrictFDerivAt (fun x => x⁻¹) (smulRight (1 : 𝕜 →L[𝕜] 𝕜) (-(x ^ 2)⁻¹) : 𝕜 →L[𝕜] 𝕜) x :=
+ hasStrictDerivAt_inv x_ne_zero
+
theorem hasFDerivWithinAt_inv (x_ne_zero : x ≠ 0) :
HasFDerivWithinAt (fun x => x⁻¹) (smulRight (1 : 𝕜 →L[𝕜] 𝕜) (-(x ^ 2)⁻¹) : 𝕜 →L[𝕜] 𝕜) s x :=
(hasFDerivAt_inv x_ne_zero).hasFDerivWithinAt
@@ -101,10 +91,10 @@ theorem fderiv_inv : fderiv 𝕜 (fun x => x⁻¹) x = smulRight (1 : 𝕜 →L[
theorem fderivWithin_inv (x_ne_zero : x ≠ 0) (hxs : UniqueDiffWithinAt 𝕜 s x) :
fderivWithin 𝕜 (fun x => x⁻¹) s x = smulRight (1 : 𝕜 →L[𝕜] 𝕜) (-(x ^ 2)⁻¹) := by
- rw [DifferentiableAt.fderivWithin (differentiableAt_inv.2 x_ne_zero) hxs]
+ 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
@@ -116,22 +106,6 @@ theorem HasDerivAt.inv (hc : HasDerivAt c c' x) (hx : c x ≠ 0) :
rw [← hasDerivWithinAt_univ] at *
exact hc.inv hx
-theorem DifferentiableWithinAt.inv (hf : DifferentiableWithinAt 𝕜 h S z) (hz : h z ≠ 0) :
- DifferentiableWithinAt 𝕜 (fun x => (h x)⁻¹) S z :=
- (differentiableAt_inv.mpr hz).comp_differentiableWithinAt z hf
-
-@[simp]
-theorem DifferentiableAt.inv (hf : DifferentiableAt 𝕜 h z) (hz : h z ≠ 0) :
- DifferentiableAt 𝕜 (fun x => (h x)⁻¹) z :=
- (differentiableAt_inv.mpr hz).comp z hf
-
-theorem DifferentiableOn.inv (hf : DifferentiableOn 𝕜 h S) (hz : ∀ x ∈ S, h x ≠ 0) :
- DifferentiableOn 𝕜 (fun x => (h x)⁻¹) S := fun x h => (hf x h).inv (hz x h)
-
-@[simp]
-theorem Differentiable.inv (hf : Differentiable 𝕜 h) (hz : ∀ x, h x ≠ 0) :
- Differentiable 𝕜 fun x => (h x)⁻¹ := fun x => (hf x).inv (hz x)
-
theorem derivWithin_inv' (hc : DifferentiableWithinAt 𝕜 c s x) (hx : c x ≠ 0)
(hxs : UniqueDiffWithinAt 𝕜 s x) :
derivWithin (fun x => (c x)⁻¹) s x = -derivWithin c s x / c x ^ 2 :=
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/DiffContOnCl.lean b/Mathlib/Analysis/Calculus/DiffContOnCl.lean
index 10a6fd3b0a289..03f7ad0b9609c 100644
--- a/Mathlib/Analysis/Calculus/DiffContOnCl.lean
+++ b/Mathlib/Analysis/Calculus/DiffContOnCl.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.Analysis.Calculus.Deriv.Inv
import Mathlib.Analysis.NormedSpace.Real
+import Mathlib.Analysis.Calculus.FDeriv.Add
+import Mathlib.Analysis.Calculus.FDeriv.Mul
/-!
# Functions differentiable on a domain and continuous on its closure
diff --git a/Mathlib/Analysis/Calculus/Dslope.lean b/Mathlib/Analysis/Calculus/Dslope.lean
index a35fb76d7fa45..df304274fc2ac 100644
--- a/Mathlib/Analysis/Calculus/Dslope.lean
+++ b/Mathlib/Analysis/Calculus/Dslope.lean
@@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
import Mathlib.Analysis.Calculus.Deriv.Slope
-import Mathlib.Analysis.Calculus.Deriv.Inv
+import Mathlib.Analysis.Calculus.Deriv.Comp
+import Mathlib.Analysis.Calculus.FDeriv.Add
+import Mathlib.Analysis.Calculus.FDeriv.Mul
/-!
# Slope of a differentiable function
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 791e3537c7217..4a3807f990caf 100644
--- a/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean
+++ b/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean
@@ -3,11 +3,14 @@ Copyright (c) 2021 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
-import Mathlib.Analysis.Analytic.Basic
import Mathlib.Analysis.Analytic.CPolynomial
+import Mathlib.Analysis.Analytic.Inverse
+import Mathlib.Analysis.Analytic.Within
import Mathlib.Analysis.Calculus.Deriv.Basic
import Mathlib.Analysis.Calculus.ContDiff.Defs
import Mathlib.Analysis.Calculus.FDeriv.Add
+import Mathlib.Analysis.Calculus.FDeriv.Prod
+import Mathlib.Analysis.Normed.Module.Completion
/-!
# Frechet derivatives of analytic functions.
@@ -17,11 +20,50 @@ Also the special case in terms of `deriv` when the domain is 1-dimensional.
As an application, we show that continuous multilinear maps are smooth. We also compute their
iterated derivatives, in `ContinuousMultilinearMap.iteratedFDeriv_eq`.
+
+## Main definitions and results
+
+* `AnalyticAt.differentiableAt` : an analytic function at a point is differentiable there.
+* `AnalyticOnNhd.fderiv` : in a complete space, if a function is analytic on a
+ neighborhood of a set `s`, so is its derivative.
+* `AnalyticOnNhd.fderiv_of_isOpen` : if a function is analytic on a neighborhood of an
+ open set `s`, so is its derivative.
+* `AnalyticOn.fderivWithin` : if a function is analytic on a set of unique differentiability,
+ so is its derivative within this set.
+* `PartialHomeomorph.analyticAt_symm` : if a partial homeomorphism `f` is analytic at a
+ point `f.symm a`, with invertible derivative, then its inverse is analytic at `a`.
+
+## Comments on completeness
+
+Some theorems need a complete space, some don't, for the following reason.
+
+(1) If a function is analytic at a point `x`, then it is differentiable there (with derivative given
+by the first term in the power series). There is no issue of convergence here.
+
+(2) If a function has a power series on a ball `B (x, r)`, there is no guarantee that the power
+series for the derivative will converge at `y ≠ x`, if the space is not complete. So, to deduce
+that `f` is differentiable at `y`, one needs completeness in general.
+
+(3) However, if a function `f` has a power series on a ball `B (x, r)`, and is a priori known to be
+differentiable at some point `y ≠ x`, then the power series for the derivative of `f` will
+automatically converge at `y`, towards the given derivative: this follows from the facts that this
+is true in the completion (thanks to the previous point) and that the map to the completion is
+an embedding.
+
+(4) Therefore, if one assumes `AnalyticOn 𝕜 f s` where `s` is an open set, then `f` is analytic
+therefore differentiable at every point of `s`, by (1), so by (3) the power series for its
+derivative converges on whole balls. Therefore, the derivative of `f` is also analytic on `s`. The
+same holds if `s` is merely a set with unique differentials.
+
+(5) However, this does not work for `AnalyticOnNhd 𝕜 f s`, as we don't get for free
+differentiability at points in a neighborhood of `s`. Therefore, the theorem that deduces
+`AnalyticOnNhd 𝕜 (fderiv 𝕜 f) s` from `AnalyticOnNhd 𝕜 f s` requires completeness of the space.
+
-/
-open Filter Asymptotics
+open Filter Asymptotics Set
-open scoped ENNReal
+open scoped ENNReal Topology
universe u v
@@ -34,49 +76,123 @@ section fderiv
variable {p : FormalMultilinearSeries 𝕜 E F} {r : ℝ≥0∞}
variable {f : E → F} {x : E} {s : Set E}
-theorem HasFPowerSeriesAt.hasStrictFDerivAt (h : HasFPowerSeriesAt f p x) :
- HasStrictFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p 1)) x := by
+/-- A function which is analytic within a set is strictly differentiable there. Since we
+don't have a predicate `HasStrictFDerivWithinAt`, we spell out what it would mean. -/
+theorem HasFPowerSeriesWithinAt.hasStrictFDerivWithinAt (h : HasFPowerSeriesWithinAt f p s x) :
+ (fun y ↦ f y.1 - f y.2 - ((continuousMultilinearCurryFin1 𝕜 E F) (p 1)) (y.1 - y.2))
+ =o[𝓝[insert x s ×ˢ insert x s] (x, x)] fun y ↦ y.1 - y.2 := by
refine h.isBigO_image_sub_norm_mul_norm_sub.trans_isLittleO (IsLittleO.of_norm_right ?_)
refine isLittleO_iff_exists_eq_mul.2 ⟨fun y => ‖y - (x, x)‖, ?_, EventuallyEq.rfl⟩
+ apply Tendsto.mono_left _ nhdsWithin_le_nhds
refine (continuous_id.sub continuous_const).norm.tendsto' _ _ ?_
rw [_root_.id, sub_self, norm_zero]
+theorem HasFPowerSeriesAt.hasStrictFDerivAt (h : HasFPowerSeriesAt f p x) :
+ HasStrictFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p 1)) x := by
+ simpa only [Set.insert_eq_of_mem, Set.mem_univ, Set.univ_prod_univ, nhdsWithin_univ]
+ using (h.hasFPowerSeriesWithinAt (s := Set.univ)).hasStrictFDerivWithinAt
+
+theorem HasFPowerSeriesWithinAt.hasFDerivWithinAt (h : HasFPowerSeriesWithinAt f p s x) :
+ HasFDerivWithinAt f (continuousMultilinearCurryFin1 𝕜 E F (p 1)) (insert x s) x := by
+ rw [HasFDerivWithinAt, hasFDerivAtFilter_iff_isLittleO, isLittleO_iff]
+ intro c hc
+ have : Tendsto (fun y ↦ (y, x)) (𝓝[insert x s] x) (𝓝[insert x s ×ˢ insert x s] (x, x)) := by
+ rw [nhdsWithin_prod_eq]
+ exact Tendsto.prod_mk tendsto_id (tendsto_const_nhdsWithin (by simp))
+ exact this (isLittleO_iff.1 h.hasStrictFDerivWithinAt hc)
+
theorem HasFPowerSeriesAt.hasFDerivAt (h : HasFPowerSeriesAt f p x) :
HasFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p 1)) x :=
h.hasStrictFDerivAt.hasFDerivAt
+theorem HasFPowerSeriesWithinAt.differentiableWithinAt (h : HasFPowerSeriesWithinAt f p s x) :
+ DifferentiableWithinAt 𝕜 f (insert x s) x :=
+ h.hasFDerivWithinAt.differentiableWithinAt
+
theorem HasFPowerSeriesAt.differentiableAt (h : HasFPowerSeriesAt f p x) : DifferentiableAt 𝕜 f x :=
h.hasFDerivAt.differentiableAt
+theorem AnalyticWithinAt.differentiableWithinAt (h : AnalyticWithinAt 𝕜 f s x) :
+ DifferentiableWithinAt 𝕜 f (insert x s) x := by
+ obtain ⟨p, hp⟩ := h
+ exact hp.differentiableWithinAt
+
theorem AnalyticAt.differentiableAt : AnalyticAt 𝕜 f x → DifferentiableAt 𝕜 f x
| ⟨_, hp⟩ => hp.differentiableAt
theorem AnalyticAt.differentiableWithinAt (h : AnalyticAt 𝕜 f x) : DifferentiableWithinAt 𝕜 f s x :=
h.differentiableAt.differentiableWithinAt
+theorem HasFPowerSeriesWithinAt.fderivWithin_eq
+ (h : HasFPowerSeriesWithinAt f p s x) (hu : UniqueDiffWithinAt 𝕜 (insert x s) x) :
+ fderivWithin 𝕜 f (insert x s) x = continuousMultilinearCurryFin1 𝕜 E F (p 1) :=
+ h.hasFDerivWithinAt.fderivWithin hu
+
theorem HasFPowerSeriesAt.fderiv_eq (h : HasFPowerSeriesAt f p x) :
fderiv 𝕜 f x = continuousMultilinearCurryFin1 𝕜 E F (p 1) :=
h.hasFDerivAt.fderiv
+theorem AnalyticAt.hasStrictFDerivAt (h : AnalyticAt 𝕜 f x) :
+ HasStrictFDerivAt f (fderiv 𝕜 f x) x := by
+ rcases h with ⟨p, hp⟩
+ rw [hp.fderiv_eq]
+ exact hp.hasStrictFDerivAt
+
+theorem HasFPowerSeriesWithinOnBall.differentiableOn [CompleteSpace F]
+ (h : HasFPowerSeriesWithinOnBall f p s x r) :
+ DifferentiableOn 𝕜 f (insert x s ∩ EMetric.ball x r) := by
+ intro y hy
+ have Z := (h.analyticWithinAt_of_mem hy).differentiableWithinAt
+ rcases eq_or_ne y x with rfl | hy
+ · exact Z.mono inter_subset_left
+ · apply (Z.mono (subset_insert _ _)).mono_of_mem
+ suffices s ∈ 𝓝[insert x s] y from nhdsWithin_mono _ inter_subset_left this
+ rw [nhdsWithin_insert_of_ne hy]
+ exact self_mem_nhdsWithin
+
theorem HasFPowerSeriesOnBall.differentiableOn [CompleteSpace F]
(h : HasFPowerSeriesOnBall f p x r) : DifferentiableOn 𝕜 f (EMetric.ball x r) := fun _ hy =>
(h.analyticAt_of_mem hy).differentiableWithinAt
-theorem AnalyticOn.differentiableOn (h : AnalyticOn 𝕜 f s) : DifferentiableOn 𝕜 f s := fun y hy =>
- (h y hy).differentiableWithinAt
+theorem AnalyticOn.differentiableOn (h : AnalyticOn 𝕜 f s) : DifferentiableOn 𝕜 f s :=
+ fun y hy ↦ (h y hy).differentiableWithinAt.mono (by simp)
+
+theorem AnalyticOnNhd.differentiableOn (h : AnalyticOnNhd 𝕜 f s) : DifferentiableOn 𝕜 f s :=
+ fun y hy ↦ (h y hy).differentiableWithinAt
+
+theorem HasFPowerSeriesWithinOnBall.hasFDerivWithinAt [CompleteSpace F]
+ (h : HasFPowerSeriesWithinOnBall f p s x r)
+ {y : E} (hy : (‖y‖₊ : ℝ≥0∞) < r) (h'y : x + y ∈ insert x s) :
+ HasFDerivWithinAt f (continuousMultilinearCurryFin1 𝕜 E F (p.changeOrigin y 1))
+ (insert x s) (x + y) := by
+ rcases eq_or_ne y 0 with rfl | h''y
+ · convert (h.changeOrigin hy h'y).hasFPowerSeriesWithinAt.hasFDerivWithinAt
+ simp
+ · have Z := (h.changeOrigin hy h'y).hasFPowerSeriesWithinAt.hasFDerivWithinAt
+ apply (Z.mono (subset_insert _ _)).mono_of_mem
+ rw [nhdsWithin_insert_of_ne]
+ · exact self_mem_nhdsWithin
+ · simpa using h''y
theorem HasFPowerSeriesOnBall.hasFDerivAt [CompleteSpace F] (h : HasFPowerSeriesOnBall f p x r)
{y : E} (hy : (‖y‖₊ : ℝ≥0∞) < r) :
HasFDerivAt f (continuousMultilinearCurryFin1 𝕜 E F (p.changeOrigin y 1)) (x + y) :=
(h.changeOrigin hy).hasFPowerSeriesAt.hasFDerivAt
+theorem HasFPowerSeriesWithinOnBall.fderivWithin_eq [CompleteSpace F]
+ (h : HasFPowerSeriesWithinOnBall f p s x r)
+ {y : E} (hy : (‖y‖₊ : ℝ≥0∞) < r) (h'y : x + y ∈ insert x s) (hu : UniqueDiffOn 𝕜 (insert x s)) :
+ fderivWithin 𝕜 f (insert x s) (x + y) =
+ continuousMultilinearCurryFin1 𝕜 E F (p.changeOrigin y 1) :=
+ (h.hasFDerivWithinAt hy h'y).fderivWithin (hu _ h'y)
+
theorem HasFPowerSeriesOnBall.fderiv_eq [CompleteSpace F] (h : HasFPowerSeriesOnBall f p x r)
{y : E} (hy : (‖y‖₊ : ℝ≥0∞) < r) :
fderiv 𝕜 f (x + y) = continuousMultilinearCurryFin1 𝕜 E F (p.changeOrigin y 1) :=
(h.hasFDerivAt hy).fderiv
-/-- If a function has a power series on a ball, then so does its derivative. -/
-theorem HasFPowerSeriesOnBall.fderiv [CompleteSpace F] (h : HasFPowerSeriesOnBall f p x r) :
+protected theorem HasFPowerSeriesOnBall.fderiv [CompleteSpace F]
+ (h : HasFPowerSeriesOnBall f p x r) :
HasFPowerSeriesOnBall (fderiv 𝕜 f) p.derivSeries x r := by
refine .congr (f := fun z ↦ continuousMultilinearCurryFin1 𝕜 E F (p.changeOrigin (z - x) 1)) ?_
fun z hz ↦ ?_
@@ -88,33 +204,76 @@ theorem HasFPowerSeriesOnBall.fderiv [CompleteSpace F] (h : HasFPowerSeriesOnBal
rw [← h.fderiv_eq, add_sub_cancel]
simpa only [edist_eq_coe_nnnorm_sub, EMetric.mem_ball] using hz
+/-- If a function has a power series within a set on a ball, then so does its derivative. -/
+protected theorem HasFPowerSeriesWithinOnBall.fderivWithin [CompleteSpace F]
+ (h : HasFPowerSeriesWithinOnBall f p s x r) (hu : UniqueDiffOn 𝕜 (insert x s)) :
+ HasFPowerSeriesWithinOnBall (fderivWithin 𝕜 f (insert x s)) p.derivSeries s x r := by
+ refine .congr' (f := fun z ↦ continuousMultilinearCurryFin1 𝕜 E F (p.changeOrigin (z - x) 1)) ?_
+ (fun z hz ↦ ?_)
+ · refine continuousMultilinearCurryFin1 𝕜 E F
+ |>.toContinuousLinearEquiv.toContinuousLinearMap.comp_hasFPowerSeriesWithinOnBall ?_
+ apply HasFPowerSeriesOnBall.hasFPowerSeriesWithinOnBall
+ simpa using ((p.hasFPowerSeriesOnBall_changeOrigin 1
+ (h.r_pos.trans_le h.r_le)).mono h.r_pos h.r_le).comp_sub x
+ · dsimp only
+ rw [← h.fderivWithin_eq _ _ hu, add_sub_cancel]
+ · simpa only [edist_eq_coe_nnnorm_sub, EMetric.mem_ball] using hz.2
+ · simpa using hz.1
+
/-- If a function is analytic on a set `s`, so is its Fréchet derivative. -/
-theorem AnalyticOn.fderiv [CompleteSpace F] (h : AnalyticOn 𝕜 f s) :
- AnalyticOn 𝕜 (fderiv 𝕜 f) s := by
- intro y hy
- rcases h y hy with ⟨p, r, hp⟩
+protected theorem AnalyticAt.fderiv [CompleteSpace F] (h : AnalyticAt 𝕜 f x) :
+ AnalyticAt 𝕜 (fderiv 𝕜 f) x := by
+ rcases h with ⟨p, r, hp⟩
exact hp.fderiv.analyticAt
-/-- If a function is analytic on a set `s`, so are its successive Fréchet derivative. -/
-theorem AnalyticOn.iteratedFDeriv [CompleteSpace F] (h : AnalyticOn 𝕜 f s) (n : ℕ) :
- AnalyticOn 𝕜 (iteratedFDeriv 𝕜 n f) s := by
+/-- If a function is analytic on a set `s`, so is its Fréchet derivative. See also
+`AnalyticOnNhd.fderiv_of_isOpen`, removing the completeness assumption but requiring the set
+to be open. -/
+protected theorem AnalyticOnNhd.fderiv [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f s) :
+ AnalyticOnNhd 𝕜 (fderiv 𝕜 f) s :=
+ fun y hy ↦ AnalyticAt.fderiv (h y hy)
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.fderiv := AnalyticOnNhd.fderiv
+
+/-- If a function is analytic on a set `s`, so are its successive Fréchet derivative. See also
+`AnalyticOnNhd.iteratedFDeruv_of_isOpen`, removing the completeness assumption but requiring the set
+to be open.-/
+protected theorem AnalyticOnNhd.iteratedFDeriv [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f s) (n : ℕ) :
+ AnalyticOnNhd 𝕜 (iteratedFDeriv 𝕜 n f) s := by
induction n with
| zero =>
rw [iteratedFDeriv_zero_eq_comp]
- exact ((continuousMultilinearCurryFin0 𝕜 E F).symm : F →L[𝕜] E[×0]→L[𝕜] F).comp_analyticOn h
+ exact ((continuousMultilinearCurryFin0 𝕜 E F).symm : F →L[𝕜] E[×0]→L[𝕜] F).comp_analyticOnNhd h
| succ n IH =>
rw [iteratedFDeriv_succ_eq_comp_left]
-- Porting note: for reasons that I do not understand at all, `?g` cannot be inlined.
- convert ContinuousLinearMap.comp_analyticOn ?g IH.fderiv
- case g => exact ↑(continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) ↦ E) F)
+ convert ContinuousLinearMap.comp_analyticOnNhd ?g IH.fderiv
+ case g => exact ↑(continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) ↦ E) F).symm
simp
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.iteratedFDeriv := AnalyticOnNhd.iteratedFDeriv
+
+/-- If a function is analytic on a neighborhood of a set `s`, then it has a Taylor series given
+by the sequence of its derivatives. Note that, if the function were just analytic on `s`, then
+one would have to use instead the sequence of derivatives inside the set, as in
+`AnalyticOn.hasFTaylorSeriesUpToOn`. -/
+lemma AnalyticOnNhd.hasFTaylorSeriesUpToOn [CompleteSpace F]
+ (n : ℕ∞) (h : AnalyticOnNhd 𝕜 f s) :
+ HasFTaylorSeriesUpToOn n f (ftaylorSeries 𝕜 f) s := by
+ refine ⟨fun x _hx ↦ rfl, fun m _hm x hx ↦ ?_, fun m _hm x hx ↦ ?_⟩
+ · apply HasFDerivAt.hasFDerivWithinAt
+ exact ((h.iteratedFDeriv m x hx).differentiableAt).hasFDerivAt
+ · apply (DifferentiableAt.continuousAt (𝕜 := 𝕜) ?_).continuousWithinAt
+ exact (h.iteratedFDeriv m x hx).differentiableAt
+
/-- An analytic function is infinitely differentiable. -/
-theorem AnalyticOn.contDiffOn [CompleteSpace F] (h : AnalyticOn 𝕜 f s) {n : ℕ∞} :
+protected theorem AnalyticOnNhd.contDiffOn [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f s) {n : ℕ∞} :
ContDiffOn 𝕜 n f s :=
let t := { x | AnalyticAt 𝕜 f x }
suffices ContDiffOn 𝕜 n f t from this.mono h
- have H : AnalyticOn 𝕜 f t := fun _x hx ↦ hx
+ have H : AnalyticOnNhd 𝕜 f t := fun _x hx ↦ hx
have t_open : IsOpen t := isOpen_analyticAt 𝕜 f
contDiffOn_of_continuousOn_differentiableOn
(fun m _ ↦ (H.iteratedFDeriv m).continuousOn.congr
@@ -122,11 +281,150 @@ theorem AnalyticOn.contDiffOn [CompleteSpace F] (h : AnalyticOn 𝕜 f s) {n :
(fun m _ ↦ (H.iteratedFDeriv m).differentiableOn.congr
fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx)
+/-- An analytic function on the whole space is infinitely differentiable there. -/
+theorem AnalyticOnNhd.contDiff [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f univ) {n : ℕ∞} :
+ ContDiff 𝕜 n f := by
+ rw [← contDiffOn_univ]
+ exact h.contDiffOn
+
theorem AnalyticAt.contDiffAt [CompleteSpace F] (h : AnalyticAt 𝕜 f x) {n : ℕ∞} :
ContDiffAt 𝕜 n f x := by
- obtain ⟨s, hs, hf⟩ := h.exists_mem_nhds_analyticOn
+ obtain ⟨s, hs, hf⟩ := h.exists_mem_nhds_analyticOnNhd
exact hf.contDiffOn.contDiffAt hs
+protected lemma AnalyticWithinAt.contDiffWithinAt [CompleteSpace F] {f : E → F} {s : Set E} {x : E}
+ (h : AnalyticWithinAt 𝕜 f s x) {n : ℕ∞} : ContDiffWithinAt 𝕜 n f s x := by
+ rcases h.exists_analyticAt with ⟨g, fx, fg, hg⟩
+ exact hg.contDiffAt.contDiffWithinAt.congr (fg.mono (subset_insert _ _)) fx
+
+protected lemma AnalyticOn.contDiffOn [CompleteSpace F] {f : E → F} {s : Set E}
+ (h : AnalyticOn 𝕜 f s) {n : ℕ∞} : ContDiffOn 𝕜 n f s :=
+ fun x m ↦ (h x m).contDiffWithinAt
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticWithinOn.contDiffOn := AnalyticOn.contDiffOn
+
+lemma AnalyticWithinAt.exists_hasFTaylorSeriesUpToOn [CompleteSpace F]
+ (n : ℕ∞) (h : AnalyticWithinAt 𝕜 f s x) :
+ ∃ u ∈ 𝓝[insert x s] x, ∃ (p : E → FormalMultilinearSeries 𝕜 E F),
+ HasFTaylorSeriesUpToOn n f p u ∧ ∀ i, AnalyticOn 𝕜 (fun x ↦ p x i) u := by
+ rcases h.exists_analyticAt with ⟨g, -, fg, hg⟩
+ rcases hg.exists_mem_nhds_analyticOnNhd with ⟨v, vx, hv⟩
+ refine ⟨insert x s ∩ v, inter_mem_nhdsWithin _ vx, ftaylorSeries 𝕜 g, ?_, fun i ↦ ?_⟩
+ · suffices HasFTaylorSeriesUpToOn n g (ftaylorSeries 𝕜 g) (insert x s ∩ v) from
+ this.congr (fun y hy ↦ fg hy.1)
+ exact AnalyticOnNhd.hasFTaylorSeriesUpToOn _ (hv.mono Set.inter_subset_right)
+ · exact (hv.iteratedFDeriv i).analyticOn.mono Set.inter_subset_right
+
+/-- If a function has a power series `p` within a set of unique differentiability, inside a ball,
+and is differentiable at a point, then the derivative series of `p` is summable at a point, with
+sum the given differential. Note that this theorem does not require completeness of the space.-/
+theorem HasFPowerSeriesWithinOnBall.hasSum_derivSeries_of_hasFDerivWithinAt
+ (h : HasFPowerSeriesWithinOnBall f p s x r)
+ {f' : E →L[𝕜] F}
+ {y : E} (hy : (‖y‖₊ : ℝ≥0∞) < r) (h'y : x + y ∈ insert x s)
+ (hf' : HasFDerivWithinAt f f' (insert x s) (x + y))
+ (hu : UniqueDiffOn 𝕜 (insert x s)) :
+ HasSum (fun n ↦ p.derivSeries n (fun _ ↦ y)) f' := by
+ /- In the completion of the space, the derivative series is summable, and its sum is a derivative
+ of the function. Therefore, by uniqueness of derivatives, its sum is the image of `f'` under
+ the canonical embedding. As this is an embedding, it means that there was also convergence in
+ the original space, to `f'`. -/
+ 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.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)
+ have : fderivWithin 𝕜 (a ∘ f) (insert x s) (x + y) = a ∘L f' := by
+ apply HasFDerivWithinAt.fderivWithin _ (hu _ h'y)
+ exact a.hasFDerivAt.comp_hasFDerivWithinAt (x + y) hf'
+ rw [this] at Z
+ convert Z with n
+ ext v
+ simp only [FormalMultilinearSeries.derivSeries,
+ ContinuousLinearMap.compFormalMultilinearSeries_apply,
+ FormalMultilinearSeries.changeOriginSeries,
+ ContinuousLinearMap.compContinuousMultilinearMap_coe, ContinuousLinearEquiv.coe_coe,
+ LinearIsometryEquiv.coe_coe, Function.comp_apply, ContinuousMultilinearMap.sum_apply, map_sum,
+ ContinuousLinearMap.coe_sum', Finset.sum_apply,
+ Matrix.zero_empty]
+ rfl
+
+/-- If a function is analytic within a set with unique differentials, then so is its derivative.
+Note that this theorem does not require completeness of the space. -/
+protected theorem AnalyticOn.fderivWithin (h : AnalyticOn 𝕜 f s) (hu : UniqueDiffOn 𝕜 s) :
+ AnalyticOn 𝕜 (fderivWithin 𝕜 f s) s := by
+ intro x hx
+ rcases h x hx with ⟨p, r, hr⟩
+ refine ⟨p.derivSeries, r, ?_⟩
+ refine ⟨hr.r_le.trans p.radius_le_radius_derivSeries, hr.r_pos, fun {y} hy h'y ↦ ?_⟩
+ apply hr.hasSum_derivSeries_of_hasFDerivWithinAt (by simpa [edist_eq_coe_nnnorm] using h'y) hy
+ · rw [insert_eq_of_mem hx] at hy ⊢
+ apply DifferentiableWithinAt.hasFDerivWithinAt
+ exact h.differentiableOn _ hy
+ · rwa [insert_eq_of_mem hx]
+
+/-- If a function is analytic on a set `s`, so are its successive Fréchet derivative within this
+set. Note that this theorem does not require completeness of the space. -/
+protected theorem AnalyticOn.iteratedFDerivWithin (h : AnalyticOn 𝕜 f s)
+ (hu : UniqueDiffOn 𝕜 s) (n : ℕ) :
+ AnalyticOn 𝕜 (iteratedFDerivWithin 𝕜 n f s) s := by
+ induction n with
+ | zero =>
+ rw [iteratedFDerivWithin_zero_eq_comp]
+ exact ((continuousMultilinearCurryFin0 𝕜 E F).symm : F →L[𝕜] E[×0]→L[𝕜] F)
+ |>.comp_analyticOn h
+ | succ n IH =>
+ rw [iteratedFDerivWithin_succ_eq_comp_left]
+ apply AnalyticOnNhd.comp_analyticOn _ (IH.fderivWithin hu) (mapsTo_univ _ _)
+ apply LinearIsometryEquiv.analyticOnNhd
+
+lemma AnalyticOn.hasFTaylorSeriesUpToOn {n : ℕ∞}
+ (h : AnalyticOn 𝕜 f s) (hu : UniqueDiffOn 𝕜 s) :
+ HasFTaylorSeriesUpToOn n f (ftaylorSeriesWithin 𝕜 f s) s := by
+ refine ⟨fun x _hx ↦ rfl, fun m _hm x hx ↦ ?_, fun m _hm x hx ↦ ?_⟩
+ · have := (h.iteratedFDerivWithin hu m x hx).differentiableWithinAt.hasFDerivWithinAt
+ rwa [insert_eq_of_mem hx] at this
+ · exact (h.iteratedFDerivWithin hu m x hx).continuousWithinAt
+
+lemma AnalyticOn.exists_hasFTaylorSeriesUpToOn
+ (h : AnalyticOn 𝕜 f s) (hu : UniqueDiffOn 𝕜 s) :
+ ∃ (p : E → FormalMultilinearSeries 𝕜 E F),
+ HasFTaylorSeriesUpToOn ⊤ f p s ∧ ∀ i, AnalyticOn 𝕜 (fun x ↦ p x i) s :=
+ ⟨ftaylorSeriesWithin 𝕜 f s, h.hasFTaylorSeriesUpToOn hu, h.iteratedFDerivWithin hu⟩
+
+theorem AnalyticOnNhd.fderiv_of_isOpen (h : AnalyticOnNhd 𝕜 f s) (hs : IsOpen s) :
+ AnalyticOnNhd 𝕜 (fderiv 𝕜 f) s := by
+ rw [← hs.analyticOn_iff_analyticOnNhd] at h ⊢
+ exact (h.fderivWithin hs.uniqueDiffOn).congr (fun x hx ↦ (fderivWithin_of_isOpen hs hx).symm)
+
+theorem AnalyticOnNhd.iteratedFDeriv_of_isOpen (h : AnalyticOnNhd 𝕜 f s) (hs : IsOpen s) (n : ℕ) :
+ AnalyticOnNhd 𝕜 (iteratedFDeriv 𝕜 n f) s := by
+ rw [← hs.analyticOn_iff_analyticOnNhd] at h ⊢
+ exact (h.iteratedFDerivWithin hs.uniqueDiffOn n).congr
+ (fun x hx ↦ (iteratedFDerivWithin_of_isOpen n hs hx).symm)
+
+/-- If a partial homeomorphism `f` is analytic at a point `a`, with invertible derivative, then
+its inverse is analytic at `f a`. -/
+theorem PartialHomeomorph.analyticAt_symm' (f : PartialHomeomorph E F) {a : E}
+ {i : E ≃L[𝕜] F} (h0 : a ∈ f.source) (h : AnalyticAt 𝕜 f a) (h' : fderiv 𝕜 f a = i) :
+ AnalyticAt 𝕜 f.symm (f a) := by
+ rcases h with ⟨p, hp⟩
+ have : p 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm i := by simp [← h', hp.fderiv_eq]
+ exact (f.hasFPowerSeriesAt_symm h0 hp this).analyticAt
+
+/-- If a partial homeomorphism `f` is analytic at a point `f.symm a`, with invertible derivative,
+then its inverse is analytic at `a`. -/
+theorem PartialHomeomorph.analyticAt_symm (f : PartialHomeomorph E F) {a : F}
+ {i : E ≃L[𝕜] F} (h0 : a ∈ f.target) (h : AnalyticAt 𝕜 f (f.symm a))
+ (h' : fderiv 𝕜 f (f.symm a) = i) :
+ AnalyticAt 𝕜 f.symm a := by
+ have : a = f (f.symm a) := by simp [h0]
+ rw [this]
+ exact f.analyticAt_symm' (by simp [h0]) h h'
+
end fderiv
section deriv
@@ -146,17 +444,29 @@ protected theorem HasFPowerSeriesAt.deriv (h : HasFPowerSeriesAt f p x) :
deriv f x = p 1 fun _ => 1 :=
h.hasDerivAt.deriv
-/-- If a function is analytic on a set `s`, so is its derivative. -/
-theorem AnalyticOn.deriv [CompleteSpace F] (h : AnalyticOn 𝕜 f s) : AnalyticOn 𝕜 (deriv f) s :=
- (ContinuousLinearMap.apply 𝕜 F (1 : 𝕜)).comp_analyticOn h.fderiv
+/-- If a function is analytic on a set `s` in a complete space, so is its derivative. -/
+protected theorem AnalyticOnNhd.deriv [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f s) :
+ AnalyticOnNhd 𝕜 (deriv f) s :=
+ (ContinuousLinearMap.apply 𝕜 F (1 : 𝕜)).comp_analyticOnNhd h.fderiv
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.deriv := AnalyticOnNhd.deriv
+
+/-- If a function is analytic on an open set `s`, so is its derivative. -/
+theorem AnalyticOnNhd.deriv_of_isOpen (h : AnalyticOnNhd 𝕜 f s) (hs : IsOpen s) :
+ AnalyticOnNhd 𝕜 (deriv f) s :=
+ (ContinuousLinearMap.apply 𝕜 F (1 : 𝕜)).comp_analyticOnNhd (h.fderiv_of_isOpen hs)
/-- If a function is analytic on a set `s`, so are its successive derivatives. -/
-theorem AnalyticOn.iterated_deriv [CompleteSpace F] (h : AnalyticOn 𝕜 f s) (n : ℕ) :
- AnalyticOn 𝕜 (_root_.deriv^[n] f) s := by
+theorem AnalyticOnNhd.iterated_deriv [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f s) (n : ℕ) :
+ AnalyticOnNhd 𝕜 (_root_.deriv^[n] f) s := by
induction n with
| zero => exact h
| succ n IH => simpa only [Function.iterate_succ', Function.comp_apply] using IH.deriv
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.iterated_deriv := AnalyticOnNhd.iterated_deriv
+
end deriv
section fderiv
@@ -230,7 +540,7 @@ theorem CPolynomialOn.iteratedFDeriv (h : CPolynomialOn 𝕜 f s) (n : ℕ) :
| succ n IH =>
rw [iteratedFDeriv_succ_eq_comp_left]
convert ContinuousLinearMap.comp_cPolynomialOn ?g IH.fderiv
- case g => exact ↑(continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) ↦ E) F)
+ case g => exact ↑(continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (n + 1) ↦ E) F).symm
simp
/-- A polynomial function is infinitely differentiable. -/
@@ -243,7 +553,7 @@ theorem CPolynomialOn.contDiffOn (h : CPolynomialOn 𝕜 f s) {n : ℕ∞} :
contDiffOn_of_continuousOn_differentiableOn
(fun m _ ↦ (H.iteratedFDeriv m).continuousOn.congr
fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx)
- (fun m _ ↦ (H.iteratedFDeriv m).analyticOn.differentiableOn.congr
+ (fun m _ ↦ (H.iteratedFDeriv m).analyticOnNhd.differentiableOn.congr
fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx)
theorem CPolynomialAt.contDiffAt (h : CPolynomialAt 𝕜 f x) {n : ℕ∞} :
@@ -278,13 +588,6 @@ variable {ι : Type*} {E : ι → Type*} [∀ i, NormedAddCommGroup (E i)] [∀
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
- 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
-
theorem changeOriginSeries_support {k l : ℕ} (h : k + l ≠ Fintype.card ι) :
f.toFormalMultilinearSeries.changeOriginSeries k l = 0 :=
Finset.sum_eq_zero fun _ _ ↦ by
@@ -313,10 +616,10 @@ theorem changeOrigin_toFormalMultilinearSeries [DecidableEq ι] :
refine (Fintype.sum_bijective (?_ ∘ Fintype.equivFinOfCardEq (Nat.add_sub_of_le
Fintype.card_pos).symm) (.comp ?_ <| Equiv.bijective _) _ _ fun i ↦ ?_).symm
· exact (⟨{·}ᶜ, by
- rw [card_compl, Fintype.card_fin, card_singleton, Nat.add_sub_cancel_left]⟩)
+ 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,
@@ -333,6 +636,30 @@ protected theorem hasFDerivAt [DecidableEq ι] : HasFDerivAt f (f.linearDeriv x)
convert f.hasFiniteFPowerSeriesOnBall.hasFDerivAt (y := x) ENNReal.coe_lt_top
rw [zero_add]
+/-- Given `f` a multilinear map, then the derivative of `x ↦ f (g₁ x, ..., gₙ x)` at `x` applied
+to a vector `v` is given by `∑ i, f (g₁ x, ..., g'ᵢ v, ..., gₙ x)`. Version inside a set. -/
+theorem _root_.HasFDerivWithinAt.multilinear_comp
+ [DecidableEq ι] {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G]
+ {g : ∀ i, G → E i} {g' : ∀ i, G →L[𝕜] E i} {s : Set G} {x : G}
+ (hg : ∀ i, HasFDerivWithinAt (g i) (g' i) s x) :
+ HasFDerivWithinAt (fun x ↦ f (fun i ↦ g i x))
+ ((∑ i : ι, (f.toContinuousLinearMap (fun j ↦ g j x) i) ∘L (g' i))) s x := by
+ convert (f.hasFDerivAt (fun j ↦ g j x)).comp_hasFDerivWithinAt x (hasFDerivWithinAt_pi.2 hg)
+ ext v
+ simp [linearDeriv]
+
+/-- Given `f` a multilinear map, then the derivative of `x ↦ f (g₁ x, ..., gₙ x)` at `x` applied
+to a vector `v` is given by `∑ i, f (g₁ x, ..., g'ᵢ v, ..., gₙ x)`. -/
+theorem _root_.HasFDerivAt.multilinear_comp
+ [DecidableEq ι] {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G]
+ {g : ∀ i, G → E i} {g' : ∀ i, G →L[𝕜] E i} {x : G}
+ (hg : ∀ i, HasFDerivAt (g i) (g' i) x) :
+ HasFDerivAt (fun x ↦ f (fun i ↦ g i x))
+ ((∑ i : ι, (f.toContinuousLinearMap (fun j ↦ g j x) i) ∘L (g' i))) x := by
+ convert (f.hasFDerivAt (fun j ↦ g j x)).comp x (hasFDerivAt_pi.2 hg)
+ ext v
+ simp [linearDeriv]
+
/-- Technical lemma used in the proof of `hasFTaylorSeriesUpTo_iteratedFDeriv`, to compare sums
over embedding of `Fin k` and `Fin (k + 1)`. -/
private lemma _root_.Equiv.succ_embeddingFinSucc_fst_symm_apply {ι : Type*} [DecidableEq ι]
@@ -487,3 +814,73 @@ theorem hasSum_iteratedFDeriv [CharZero 𝕜] {y : E} (hy : y ∈ EMetric.ball 0
mul_inv_cancel₀ <| cast_ne_zero.mpr n.factorial_ne_zero, one_smul]
end HasFPowerSeriesOnBall
+
+/-!
+### Derivative of a linear map into multilinear maps
+-/
+
+namespace ContinuousLinearMap
+
+variable {ι : Type*} {G : ι → Type*} [∀ i, NormedAddCommGroup (G i)] [∀ i, NormedSpace 𝕜 (G i)]
+ [Fintype ι] {H : Type*} [NormedAddCommGroup H]
+ [NormedSpace 𝕜 H]
+
+theorem hasFDerivAt_uncurry_of_multilinear [DecidableEq ι]
+ (f : E →L[𝕜] ContinuousMultilinearMap 𝕜 G F) (v : E × Π i, G i) :
+ HasFDerivAt (fun (p : E × Π i, G i) ↦ f p.1 p.2)
+ ((f.flipMultilinear v.2) ∘L (.fst _ _ _) +
+ ∑ i : ι, ((f v.1).toContinuousLinearMap v.2 i) ∘L (.proj _) ∘L (.snd _ _ _)) v := by
+ convert HasFDerivAt.multilinear_comp (f.continuousMultilinearMapOption)
+ (g := fun (_ : Option ι) p ↦ p) (g' := fun _ ↦ ContinuousLinearMap.id _ _) (x := v)
+ (fun _ ↦ hasFDerivAt_id _)
+ have I : f.continuousMultilinearMapOption.toContinuousLinearMap (fun _ ↦ v) none =
+ (f.flipMultilinear v.2) ∘L (.fst _ _ _) := by
+ simp [ContinuousMultilinearMap.toContinuousLinearMap, continuousMultilinearMapOption]
+ apply ContinuousLinearMap.ext (fun w ↦ ?_)
+ simp
+ have J : ∀ (i : ι), f.continuousMultilinearMapOption.toContinuousLinearMap (fun _ ↦ v) (some i)
+ = ((f v.1).toContinuousLinearMap v.2 i) ∘L (.proj _) ∘L (.snd _ _ _) := by
+ intro i
+ apply ContinuousLinearMap.ext (fun w ↦ ?_)
+ simp only [ContinuousMultilinearMap.toContinuousLinearMap, continuousMultilinearMapOption,
+ coe_mk', MultilinearMap.toLinearMap_apply, ContinuousMultilinearMap.coe_coe,
+ MultilinearMap.coe_mkContinuous, MultilinearMap.coe_mk, ne_eq, reduceCtorEq,
+ not_false_eq_true, Function.update_noteq, coe_comp', coe_snd', Function.comp_apply,
+ proj_apply]
+ congr
+ ext j
+ rcases eq_or_ne j i with rfl | hij
+ · simp
+ · simp [hij]
+ simp [I, J]
+
+/-- Given `f` a linear map into multilinear maps, then the derivative
+of `x ↦ f (a x) (b₁ x, ..., bₙ x)` at `x` applied to a vector `v` is given by
+`f (a' v) (b₁ x, ...., bₙ x) + ∑ i, f a (b₁ x, ..., b'ᵢ v, ..., bₙ x)`. Version inside a set. -/
+theorem _root_.HasFDerivWithinAt.linear_multilinear_comp
+ [DecidableEq ι] {a : H → E} {a' : H →L[𝕜] E}
+ {b : ∀ i, H → G i} {b' : ∀ i, H →L[𝕜] G i} {s : Set H} {x : H}
+ (ha : HasFDerivWithinAt a a' s x) (hb : ∀ i, HasFDerivWithinAt (b i) (b' i) s x)
+ (f : E →L[𝕜] ContinuousMultilinearMap 𝕜 G F) :
+ HasFDerivWithinAt (fun y ↦ f (a y) (fun i ↦ b i y))
+ ((f.flipMultilinear (fun i ↦ b i x)) ∘L a' +
+ ∑ i, ((f (a x)).toContinuousLinearMap (fun j ↦ b j x) i) ∘L (b' i)) s x := by
+ convert (hasFDerivAt_uncurry_of_multilinear f (a x, fun i ↦ b i x)).comp_hasFDerivWithinAt x
+ (ha.prod (hasFDerivWithinAt_pi.mpr hb))
+ ext v
+ simp
+
+/-- Given `f` a linear map into multilinear maps, then the derivative
+of `x ↦ f (a x) (b₁ x, ..., bₙ x)` at `x` applied to a vector `v` is given by
+`f (a' v) (b₁ x, ...., bₙ x) + ∑ i, f a (b₁ x, ..., b'ᵢ v, ..., bₙ x)`. -/
+theorem _root_.HasFDerivAt.linear_multilinear_comp [DecidableEq ι] {a : H → E} {a' : H →L[𝕜] E}
+ {b : ∀ i, H → G i} {b' : ∀ i, H →L[𝕜] G i} {x : H}
+ (ha : HasFDerivAt a a' x) (hb : ∀ i, HasFDerivAt (b i) (b' i) x)
+ (f : E →L[𝕜] ContinuousMultilinearMap 𝕜 G F) :
+ HasFDerivAt (fun y ↦ f (a y) (fun i ↦ b i y))
+ ((f.flipMultilinear (fun i ↦ b i x)) ∘L a' +
+ ∑ i, ((f (a x)).toContinuousLinearMap (fun j ↦ b j x) i) ∘L (b' i)) x := by
+ simp_rw [← hasFDerivWithinAt_univ] at ha hb ⊢
+ exact HasFDerivWithinAt.linear_multilinear_comp ha hb f
+
+end ContinuousLinearMap
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 beaf6fad6b9fe..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))
@@ -172,7 +175,7 @@ theorem Differentiable.comp_differentiableOn {g : F → G} (hg : Differentiable
protected theorem HasStrictFDerivAt.comp {g : F → G} {g' : F →L[𝕜] G}
(hg : HasStrictFDerivAt g g' (f x)) (hf : HasStrictFDerivAt f f' x) :
HasStrictFDerivAt (fun x => g (f x)) (g'.comp f') x :=
- ((hg.comp_tendsto (hf.continuousAt.prod_map' hf.continuousAt)).trans_isBigO
+ ((hg.comp_tendsto (hf.continuousAt.prodMap' hf.continuousAt)).trans_isBigO
hf.isBigO_sub).triangle <| by
simpa only [g'.map_sub, f'.coe_comp'] using (g'.isBigO_comp _ _).trans_isLittleO hf
diff --git a/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean b/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean
index e2f34a6adc71a..ac47ac267e108 100644
--- a/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean
+++ b/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean
@@ -87,7 +87,7 @@ theorem comp_differentiableWithinAt_iff {f : G → E} {s : Set G} {x : G} :
⟨fun H => ?_, fun H => iso.differentiable.differentiableAt.comp_differentiableWithinAt x H⟩
have : DifferentiableWithinAt 𝕜 (iso.symm ∘ iso ∘ f) s x :=
iso.symm.differentiable.differentiableAt.comp_differentiableWithinAt x H
- rwa [← Function.comp.assoc iso.symm iso f, iso.symm_comp_self] at this
+ rwa [← Function.comp_assoc iso.symm iso f, iso.symm_comp_self] at this
theorem comp_differentiableAt_iff {f : G → E} {x : G} :
DifferentiableAt 𝕜 (iso ∘ f) x ↔ DifferentiableAt 𝕜 f x := by
@@ -107,7 +107,7 @@ theorem comp_hasFDerivWithinAt_iff {f : G → E} {s : Set G} {x : G} {f' : G →
HasFDerivWithinAt (iso ∘ f) ((iso : E →L[𝕜] F).comp f') s x ↔ HasFDerivWithinAt f f' s x := by
refine ⟨fun H => ?_, fun H => iso.hasFDerivAt.comp_hasFDerivWithinAt x H⟩
have A : f = iso.symm ∘ iso ∘ f := by
- rw [← Function.comp.assoc, iso.symm_comp_self]
+ rw [← Function.comp_assoc, iso.symm_comp_self]
rfl
have B : f' = (iso.symm : F →L[𝕜] E).comp ((iso : E →L[𝕜] F).comp f') := by
rw [← ContinuousLinearMap.comp_assoc, iso.coe_symm_comp_coe, ContinuousLinearMap.id_comp]
@@ -174,7 +174,7 @@ theorem comp_right_differentiableWithinAt_iff {f : F → G} {s : Set F} {x : E}
apply H.comp (iso x) iso.symm.differentiableWithinAt
intro y hy
simpa only [mem_preimage, apply_symm_apply] using hy
- rwa [Function.comp.assoc, iso.self_comp_symm] at this
+ rwa [Function.comp_assoc, iso.self_comp_symm] at this
theorem comp_right_differentiableAt_iff {f : F → G} {x : E} :
DifferentiableAt 𝕜 (f ∘ iso) x ↔ DifferentiableAt 𝕜 f (iso x) := by
@@ -198,7 +198,7 @@ theorem comp_right_hasFDerivWithinAt_iff {f : F → G} {s : Set F} {x : E} {f' :
refine ⟨fun H => ?_, fun H => H.comp x iso.hasFDerivWithinAt (mapsTo_preimage _ s)⟩
rw [← iso.symm_apply_apply x] at H
have A : f = (f ∘ iso) ∘ iso.symm := by
- rw [Function.comp.assoc, iso.self_comp_symm]
+ rw [Function.comp_assoc, iso.self_comp_symm]
rfl
have B : f' = (f'.comp (iso : E →L[𝕜] F)).comp (iso.symm : F →L[𝕜] E) := by
rw [ContinuousLinearMap.comp_assoc, iso.coe_comp_coe_symm, ContinuousLinearMap.comp_id]
@@ -339,7 +339,7 @@ inverse function. -/
theorem HasStrictFDerivAt.of_local_left_inverse {f : E → F} {f' : E ≃L[𝕜] F} {g : F → E} {a : F}
(hg : ContinuousAt g a) (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) (g a))
(hfg : ∀ᶠ y in 𝓝 a, f (g y) = y) : HasStrictFDerivAt g (f'.symm : F →L[𝕜] E) a := by
- replace hg := hg.prod_map' hg
+ replace hg := hg.prodMap' hg
replace hfg := hfg.prod_mk_nhds hfg
have :
(fun p : F × F => g p.1 - g p.2 - f'.symm (p.1 - p.2)) =O[𝓝 (a, a)] fun p : F × F =>
@@ -355,7 +355,7 @@ theorem HasStrictFDerivAt.of_local_left_inverse {f : E → F} {f' : E ≃L[𝕜]
· refine (hf.isBigO_sub_rev.comp_tendsto hg).congr' (Eventually.of_forall fun _ => rfl)
(hfg.mono ?_)
rintro p ⟨hp1, hp2⟩
- simp only [(· ∘ ·), hp1, hp2]
+ simp only [(· ∘ ·), hp1, hp2, Prod.map]
/-- If `f (g y) = y` for `y` in some neighborhood of `a`, `g` is continuous at `a`, and `f` has an
invertible derivative `f'` at `g a`, then `g` has the derivative `f'⁻¹` at `a`.
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 5623962121150..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
@@ -303,7 +303,7 @@ theorem D_subset_differentiable_set {K : Set (E →L[𝕜] F)} (hK : IsComplete
· simp [y_pos]
have yzero : 0 < ‖y‖ := norm_pos_iff.mpr y_pos
have y_lt : ‖y‖ < (1 / 2) ^ (n e + 1) := by simpa using mem_ball_iff_norm.1 hy
- have yone : ‖y‖ ≤ 1 := le_trans y_lt.le (pow_le_one _ (by norm_num) (by norm_num))
+ have yone : ‖y‖ ≤ 1 := le_trans y_lt.le (pow_le_one₀ (by norm_num) (by norm_num))
-- define the scale `k`.
obtain ⟨k, hk, h'k⟩ : ∃ k : ℕ, (1 / 2) ^ (k + 1) < ‖y‖ ∧ ‖y‖ ≤ (1 / 2) ^ k :=
exists_nat_pow_near_of_lt_one yzero yone (by norm_num : (0 : ℝ) < 1 / 2)
@@ -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
@@ -638,7 +637,7 @@ theorem D_subset_differentiable_set {K : Set F} (hK : IsComplete K) :
· simp only [sub_self, zero_smul, norm_zero, mul_zero, le_rfl]
have yzero : 0 < y - x := sub_pos.2 xy
have y_le : y - x ≤ (1 / 2) ^ (n e + 1) := by linarith [hy.2]
- have yone : y - x ≤ 1 := le_trans y_le (pow_le_one _ (by norm_num) (by norm_num))
+ have yone : y - x ≤ 1 := le_trans y_le (pow_le_one₀ (by norm_num) (by norm_num))
-- define the scale `k`.
obtain ⟨k, hk, h'k⟩ : ∃ k : ℕ, (1 / 2) ^ (k + 1) < y - x ∧ y - x ≤ (1 / 2) ^ k :=
exists_nat_pow_near_of_lt_one yzero yone (by norm_num : (0 : ℝ) < 1 / 2)
@@ -661,7 +660,7 @@ theorem D_subset_differentiable_set {K : Set F} (hK : IsComplete K) :
· simp only [one_div, inv_pow, left_mem_Icc, le_add_iff_nonneg_right]
positivity
· simp only [pow_add, tsub_le_iff_left] at h'k
- simpa only [hy.1, mem_Icc, true_and_iff, one_div, pow_one] using h'k
+ simpa only [hy.1, mem_Icc, true_and, one_div, pow_one] using h'k
_ = 4 * (1 / 2) ^ e * (1 / 2) ^ (m + 2) := by field_simp; ring
_ ≤ 4 * (1 / 2) ^ e * (y - x) := by gcongr
_ = 4 * (1 / 2) ^ e * ‖y - x‖ := by rw [Real.norm_of_nonneg yzero.le]
@@ -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 9c79b4bf2279c..a33ed2ab821e1 100644
--- a/Mathlib/Analysis/Calculus/FDeriv/Mul.lean
+++ b/Mathlib/Analysis/Calculus/FDeriv/Mul.lean
@@ -3,6 +3,8 @@ Copyright (c) 2019 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Sébastien Gouëzel, Yury Kudryashov
-/
+import Mathlib.Analysis.Analytic.Constructions
+import Mathlib.Analysis.Calculus.FDeriv.Analytic
import Mathlib.Analysis.Calculus.FDeriv.Bilinear
/-!
@@ -19,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
@@ -30,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
@@ -50,20 +46,20 @@ variable {H : Type*} [NormedAddCommGroup H] [NormedSpace 𝕜 H] {c : E → G
theorem HasStrictFDerivAt.clm_comp (hc : HasStrictFDerivAt c c' x) (hd : HasStrictFDerivAt d d' x) :
HasStrictFDerivAt (fun y => (c y).comp (d y))
((compL 𝕜 F G H (c x)).comp d' + ((compL 𝕜 F G H).flip (d x)).comp c') x :=
- (isBoundedBilinearMap_comp.hasStrictFDerivAt (c x, d x)).comp x <| hc.prod hd
+ (isBoundedBilinearMap_comp.hasStrictFDerivAt (c x, d x) :).comp x <| hc.prod hd
@[fun_prop]
theorem HasFDerivWithinAt.clm_comp (hc : HasFDerivWithinAt c c' s x)
(hd : HasFDerivWithinAt d d' s x) :
HasFDerivWithinAt (fun y => (c y).comp (d y))
((compL 𝕜 F G H (c x)).comp d' + ((compL 𝕜 F G H).flip (d x)).comp c') s x :=
- (isBoundedBilinearMap_comp.hasFDerivAt (c x, d x)).comp_hasFDerivWithinAt x <| hc.prod hd
+ (isBoundedBilinearMap_comp.hasFDerivAt (c x, d x) :).comp_hasFDerivWithinAt x <| hc.prod hd
@[fun_prop]
theorem HasFDerivAt.clm_comp (hc : HasFDerivAt c c' x) (hd : HasFDerivAt d d' x) :
HasFDerivAt (fun y => (c y).comp (d y))
((compL 𝕜 F G H (c x)).comp d' + ((compL 𝕜 F G H).flip (d x)).comp c') x :=
- (isBoundedBilinearMap_comp.hasFDerivAt (c x, d x)).comp x <| hc.prod hd
+ (isBoundedBilinearMap_comp.hasFDerivAt (c x, d x) :).comp x <| hc.prod hd
@[fun_prop]
theorem DifferentiableWithinAt.clm_comp (hc : DifferentiableWithinAt 𝕜 c s x)
@@ -107,12 +103,12 @@ theorem HasStrictFDerivAt.clm_apply (hc : HasStrictFDerivAt c c' x)
theorem HasFDerivWithinAt.clm_apply (hc : HasFDerivWithinAt c c' s x)
(hu : HasFDerivWithinAt u u' s x) :
HasFDerivWithinAt (fun y => (c y) (u y)) ((c x).comp u' + c'.flip (u x)) s x :=
- (isBoundedBilinearMap_apply.hasFDerivAt (c x, u x)).comp_hasFDerivWithinAt x (hc.prod hu)
+ (isBoundedBilinearMap_apply.hasFDerivAt (c x, u x) :).comp_hasFDerivWithinAt x (hc.prod hu)
@[fun_prop]
theorem HasFDerivAt.clm_apply (hc : HasFDerivAt c c' x) (hu : HasFDerivAt u u' x) :
HasFDerivAt (fun y => (c y) (u y)) ((c x).comp u' + c'.flip (u x)) x :=
- (isBoundedBilinearMap_apply.hasFDerivAt (c x, u x)).comp x (hc.prod hu)
+ (isBoundedBilinearMap_apply.hasFDerivAt (c x, u x) :).comp x (hc.prod hu)
@[fun_prop]
theorem DifferentiableWithinAt.clm_apply (hc : DifferentiableWithinAt 𝕜 c s x)
@@ -239,12 +235,13 @@ theorem HasStrictFDerivAt.smul (hc : HasStrictFDerivAt c c' x) (hf : HasStrictFD
@[fun_prop]
theorem HasFDerivWithinAt.smul (hc : HasFDerivWithinAt c c' s x) (hf : HasFDerivWithinAt f f' s x) :
HasFDerivWithinAt (fun y => c y • f y) (c x • f' + c'.smulRight (f x)) s x :=
- (isBoundedBilinearMap_smul.hasFDerivAt (c x, f x)).comp_hasFDerivWithinAt x <| hc.prod hf
+ (isBoundedBilinearMap_smul.hasFDerivAt (𝕜 := 𝕜) (c x, f x) :).comp_hasFDerivWithinAt x <|
+ hc.prod hf
@[fun_prop]
theorem HasFDerivAt.smul (hc : HasFDerivAt c c' x) (hf : HasFDerivAt f f' x) :
HasFDerivAt (fun y => c y • f y) (c x • f' + c'.smulRight (f x)) x :=
- (isBoundedBilinearMap_smul.hasFDerivAt (c x, f x)).comp x <| hc.prod hf
+ (isBoundedBilinearMap_smul.hasFDerivAt (𝕜 := 𝕜) (c x, f x) :).comp x <| hc.prod hf
@[fun_prop]
theorem DifferentiableWithinAt.smul (hc : DifferentiableWithinAt 𝕜 c s x)
@@ -570,10 +567,10 @@ theorem hasStrictFDerivAt_list_prod_finRange' {n : ℕ} {x : Fin n → 𝔸} :
theorem hasStrictFDerivAt_list_prod_attach' [DecidableEq ι] {l : List ι} {x : {i // i ∈ l} → 𝔸} :
HasStrictFDerivAt (𝕜 := 𝕜) (fun x ↦ (l.attach.map x).prod)
(∑ i : Fin l.length, ((l.attach.take i).map x).prod •
- smulRight (proj l.attach[i.cast l.length_attach.symm])
+ smulRight (proj l.attach[i.cast List.length_attach.symm])
((l.attach.drop (.succ i)).map x).prod) x :=
hasStrictFDerivAt_list_prod'.congr_fderiv <| Eq.symm <|
- Finset.sum_equiv (finCongr l.length_attach.symm) (by simp) (by simp)
+ Finset.sum_equiv (finCongr List.length_attach.symm) (by simp) (by simp)
@[fun_prop]
theorem hasFDerivAt_list_prod' [Fintype ι] {l : List ι} {x : ι → 𝔸'} :
@@ -593,7 +590,7 @@ theorem hasFDerivAt_list_prod_finRange' {n : ℕ} {x : Fin n → 𝔸} :
theorem hasFDerivAt_list_prod_attach' [DecidableEq ι] {l : List ι} {x : {i // i ∈ l} → 𝔸} :
HasFDerivAt (𝕜 := 𝕜) (fun x ↦ (l.attach.map x).prod)
(∑ i : Fin l.length, ((l.attach.take i).map x).prod •
- smulRight (proj l.attach[i.cast l.length_attach.symm])
+ smulRight (proj l.attach[i.cast List.length_attach.symm])
((l.attach.drop (.succ i)).map x).prod) x :=
hasStrictFDerivAt_list_prod_attach'.hasFDerivAt
@@ -645,7 +642,7 @@ theorem HasStrictFDerivAt.list_prod' {l : List ι} {x : E}
smulRight (f' l[i]) ((l.drop (.succ i)).map (f · x)).prod) x := by
simp only [← List.finRange_map_get l, List.map_map]
refine .congr_fderiv (hasStrictFDerivAt_list_prod_finRange'.comp x
- (hasStrictFDerivAt_pi.mpr fun i ↦ h l[i] (l.getElem_mem ..))) ?_
+ (hasStrictFDerivAt_pi.mpr fun i ↦ h l[i] (List.getElem_mem ..))) ?_
ext m
simp [← List.map_map]
@@ -660,7 +657,7 @@ theorem HasFDerivAt.list_prod' {l : List ι} {x : E}
smulRight (f' l[i]) ((l.drop (.succ i)).map (f · x)).prod) x := by
simp only [← List.finRange_map_get l, List.map_map]
refine .congr_fderiv (hasFDerivAt_list_prod_finRange'.comp x
- (hasFDerivAt_pi.mpr fun i ↦ h l[i] (l.getElem_mem i i.isLt))) ?_
+ (hasFDerivAt_pi.mpr fun i ↦ h l[i] (List.getElem_mem i.isLt))) ?_
ext m
simp [← List.map_map]
@@ -774,16 +771,15 @@ end Prod
section AlgebraInverse
-variable {R : Type*} [NormedRing R] [NormedAlgebra 𝕜 R] [CompleteSpace R]
+variable {R : Type*} [NormedRing R] [HasSummableGeomSeries R] [NormedAlgebra 𝕜 R]
open NormedRing ContinuousLinearMap Ring
/-- At an invertible element `x` of a normed algebra `R`, the Fréchet derivative of the inversion
operation is the linear map `fun t ↦ - x⁻¹ * t * x⁻¹`.
-TODO: prove that `Ring.inverse` is analytic and use it to prove a `HasStrictFDerivAt` lemma.
-TODO (low prio): prove a version without assumption `[CompleteSpace R]` but within the set of
-units. -/
+TODO (low prio): prove a version without assumption `[HasSummableGeomSeries R]` but within the set
+of units. -/
@[fun_prop]
theorem hasFDerivAt_ring_inverse (x : Rˣ) :
HasFDerivAt Ring.inverse (-mulLeftRight 𝕜 R ↑x⁻¹ ↑x⁻¹) x :=
@@ -808,6 +804,11 @@ theorem differentiableOn_inverse : DifferentiableOn 𝕜 (@Ring.inverse R _) {x
theorem fderiv_inverse (x : Rˣ) : fderiv 𝕜 (@Ring.inverse R _) x = -mulLeftRight 𝕜 R ↑x⁻¹ ↑x⁻¹ :=
(hasFDerivAt_ring_inverse x).fderiv
+theorem hasStrictFDerivAt_ring_inverse (x : Rˣ) :
+ HasStrictFDerivAt Ring.inverse (-mulLeftRight 𝕜 R ↑x⁻¹ ↑x⁻¹) x := by
+ convert (analyticAt_inverse (𝕜 := 𝕜) x).hasStrictFDerivAt
+ exact (fderiv_inverse x).symm
+
variable {h : E → R} {z : E} {S : Set E}
@[fun_prop]
@@ -832,35 +833,51 @@ end AlgebraInverse
/-! ### Derivative of the inverse in a division ring
-Note these lemmas are primed as they need `CompleteSpace R`, whereas the other lemmas in
-`Mathlib/Analysis/Calculus/Deriv/Inv.lean` do not, but instead need `NontriviallyNormedField R`.
+Note that some lemmas are primed as they are expressed without commutativity, whereas their
+counterparts in commutative fields involve simpler expressions, and are given in
+`Mathlib/Analysis/Calculus/Deriv/Inv.lean`.
-/
section DivisionRingInverse
-variable {R : Type*} [NormedDivisionRing R] [NormedAlgebra 𝕜 R] [CompleteSpace R]
+variable {R : Type*} [NormedDivisionRing R] [NormedAlgebra 𝕜 R]
open NormedRing ContinuousLinearMap Ring
+/-- At an invertible element `x` of a normed division algebra `R`, the inversion is strictly
+differentiable, with derivative the linear map `fun t ↦ - x⁻¹ * t * x⁻¹`. For a nicer formula in
+the commutative case, see `hasStrictFDerivAt_inv`. -/
+theorem hasStrictFDerivAt_inv' {x : R} (hx : x ≠ 0) :
+ HasStrictFDerivAt Inv.inv (-mulLeftRight 𝕜 R x⁻¹ x⁻¹) x := by
+ simpa using hasStrictFDerivAt_ring_inverse (Units.mk0 _ hx)
+
/-- At an invertible element `x` of a normed division algebra `R`, the Fréchet derivative of the
-inversion operation is the linear map `fun t ↦ - x⁻¹ * t * x⁻¹`. -/
+inversion operation is the linear map `fun t ↦ - x⁻¹ * t * x⁻¹`. For a nicer formula in the
+commutative case, see `hasFDerivAt_inv`. -/
@[fun_prop]
theorem hasFDerivAt_inv' {x : R} (hx : x ≠ 0) :
HasFDerivAt Inv.inv (-mulLeftRight 𝕜 R x⁻¹ x⁻¹) x := by
simpa using hasFDerivAt_ring_inverse (Units.mk0 _ hx)
@[fun_prop]
-theorem differentiableAt_inv' {x : R} (hx : x ≠ 0) : DifferentiableAt 𝕜 Inv.inv x :=
+theorem differentiableAt_inv {x : R} (hx : x ≠ 0) : DifferentiableAt 𝕜 Inv.inv x :=
(hasFDerivAt_inv' hx).differentiableAt
+@[deprecated (since := "2024-09-21")] alias differentiableAt_inv' := differentiableAt_inv
+
@[fun_prop]
-theorem differentiableWithinAt_inv' {x : R} (hx : x ≠ 0) (s : Set R) :
+theorem differentiableWithinAt_inv {x : R} (hx : x ≠ 0) (s : Set R) :
DifferentiableWithinAt 𝕜 (fun x => x⁻¹) s x :=
- (differentiableAt_inv' hx).differentiableWithinAt
+ (differentiableAt_inv hx).differentiableWithinAt
+
+@[deprecated (since := "2024-09-21")]
+alias differentiableWithinAt_inv' := differentiableWithinAt_inv
@[fun_prop]
-theorem differentiableOn_inv' : DifferentiableOn 𝕜 (fun x : R => x⁻¹) {x | x ≠ 0} := fun _x hx =>
- differentiableWithinAt_inv' hx _
+theorem differentiableOn_inv : DifferentiableOn 𝕜 (fun x : R => x⁻¹) {x | x ≠ 0} := fun _x hx =>
+ differentiableWithinAt_inv hx _
+
+@[deprecated (since := "2024-09-21")] alias differentiableOn_inv' := differentiableOn_inv
/-- Non-commutative version of `fderiv_inv` -/
theorem fderiv_inv' {x : R} (hx : x ≠ 0) : fderiv 𝕜 Inv.inv x = -mulLeftRight 𝕜 R x⁻¹ x⁻¹ :=
@@ -869,28 +886,37 @@ theorem fderiv_inv' {x : R} (hx : x ≠ 0) : fderiv 𝕜 Inv.inv x = -mulLeftRig
/-- Non-commutative version of `fderivWithin_inv` -/
theorem fderivWithin_inv' {s : Set R} {x : R} (hx : x ≠ 0) (hxs : UniqueDiffWithinAt 𝕜 s x) :
fderivWithin 𝕜 (fun x => x⁻¹) s x = -mulLeftRight 𝕜 R x⁻¹ x⁻¹ := by
- rw [DifferentiableAt.fderivWithin (differentiableAt_inv' hx) hxs]
+ rw [DifferentiableAt.fderivWithin (differentiableAt_inv hx) hxs]
exact fderiv_inv' hx
variable {h : E → R} {z : E} {S : Set E}
@[fun_prop]
-theorem DifferentiableWithinAt.inv' (hf : DifferentiableWithinAt 𝕜 h S z) (hz : h z ≠ 0) :
+theorem DifferentiableWithinAt.inv (hf : DifferentiableWithinAt 𝕜 h S z) (hz : h z ≠ 0) :
DifferentiableWithinAt 𝕜 (fun x => (h x)⁻¹) S z :=
- (differentiableAt_inv' hz).comp_differentiableWithinAt z hf
+ (differentiableAt_inv hz).comp_differentiableWithinAt z hf
+
+@[deprecated (since := "2024-09-21")]
+alias DifferentiableWithinAt.inv' := DifferentiableWithinAt.inv
@[simp, fun_prop]
-theorem DifferentiableAt.inv' (hf : DifferentiableAt 𝕜 h z) (hz : h z ≠ 0) :
+theorem DifferentiableAt.inv (hf : DifferentiableAt 𝕜 h z) (hz : h z ≠ 0) :
DifferentiableAt 𝕜 (fun x => (h x)⁻¹) z :=
- (differentiableAt_inv' hz).comp z hf
+ (differentiableAt_inv hz).comp z hf
+
+@[deprecated (since := "2024-09-21")] alias DifferentiableAt.inv' := DifferentiableAt.inv
@[fun_prop]
-theorem DifferentiableOn.inv' (hf : DifferentiableOn 𝕜 h S) (hz : ∀ x ∈ S, h x ≠ 0) :
- DifferentiableOn 𝕜 (fun x => (h x)⁻¹) S := fun x h => (hf x h).inv' (hz x h)
+theorem DifferentiableOn.inv (hf : DifferentiableOn 𝕜 h S) (hz : ∀ x ∈ S, h x ≠ 0) :
+ DifferentiableOn 𝕜 (fun x => (h x)⁻¹) S := fun x h => (hf x h).inv (hz x h)
+
+@[deprecated (since := "2024-09-21")] alias DifferentiableOn.inv' := DifferentiableOn.inv
@[simp, fun_prop]
-theorem Differentiable.inv' (hf : Differentiable 𝕜 h) (hz : ∀ x, h x ≠ 0) :
- Differentiable 𝕜 fun x => (h x)⁻¹ := fun x => (hf x).inv' (hz x)
+theorem Differentiable.inv (hf : Differentiable 𝕜 h) (hz : ∀ x, h x ≠ 0) :
+ Differentiable 𝕜 fun x => (h x)⁻¹ := fun x => (hf x).inv (hz x)
+
+@[deprecated (since := "2024-09-21")] alias Differentiable.inv' := Differentiable.inv
end DivisionRingInverse
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/Symmetric.lean b/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean
index 1835d8c1d6fa5..399dada358cca 100644
--- a/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean
+++ b/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean
@@ -97,8 +97,8 @@ theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s)
rw [← smul_smul]
apply s_conv.interior.add_smul_mem this _ ht
rw [add_assoc] at hw
- rw [add_assoc, ← smul_add]
- exact s_conv.add_smul_mem_interior xs hw ⟨hpos, h_lt_1.le⟩
+ convert s_conv.add_smul_mem_interior xs hw ⟨hpos, h_lt_1.le⟩ using 1
+ module
-- define a function `g` on `[0,1]` (identified with `[v, v + w]`) such that `g 1 - g 0` is the
-- quantity to be estimated. We will check that its derivative is given by an explicit
-- expression `g'`, that we can bound. Then the desired bound for `g 1 - g 0` follows from the
@@ -139,14 +139,14 @@ theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s)
calc
‖g' t‖ = ‖(f' (x + h • v + (t * h) • w) - f' x - f'' (h • v + (t * h) • w)) (h • w)‖ := by
rw [hg']
- have : h * (t * h) = t * (h * h) := by ring
- simp only [ContinuousLinearMap.coe_sub', ContinuousLinearMap.map_add, pow_two,
- ContinuousLinearMap.add_apply, Pi.smul_apply, smul_sub, smul_add, smul_smul, ← sub_sub,
- ContinuousLinearMap.coe_smul', Pi.sub_apply, ContinuousLinearMap.map_smul, this]
+ congrm ‖?_‖
+ simp only [ContinuousLinearMap.sub_apply, ContinuousLinearMap.add_apply,
+ ContinuousLinearMap.smul_apply, map_add, map_smul]
+ module
_ ≤ ‖f' (x + h • v + (t * h) • w) - f' x - f'' (h • v + (t * h) • w)‖ * ‖h • w‖ :=
(ContinuousLinearMap.le_opNorm _ _)
_ ≤ ε * ‖h • v + (t * h) • w‖ * ‖h • w‖ := by
- apply mul_le_mul_of_nonneg_right _ (norm_nonneg _)
+ gcongr
have H : x + h • v + (t * h) • w ∈ Metric.ball x δ ∩ interior s := by
refine ⟨?_, xt_mem t ⟨ht.1, ht.2.le⟩⟩
rw [add_assoc, add_mem_ball_iff_norm]
@@ -157,7 +157,7 @@ theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s)
apply (norm_add_le _ _).trans
gcongr
simp only [norm_smul, Real.norm_eq_abs, abs_mul, abs_of_nonneg, ht.1, hpos.le, mul_assoc]
- exact mul_le_of_le_one_left (mul_nonneg hpos.le (norm_nonneg _)) ht.2.le
+ exact mul_le_of_le_one_left (by positivity) ht.2.le
_ = ε * ((‖v‖ + ‖w‖) * ‖w‖) * h ^ 2 := by
simp only [norm_smul, Real.norm_eq_abs, abs_mul, abs_of_nonneg, hpos.le]; ring
-- conclude using the mean value inequality
@@ -169,8 +169,8 @@ theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s)
simp only [g, Nat.one_ne_zero, add_zero, one_mul, zero_div, zero_mul, sub_zero,
zero_smul, Ne, not_false_iff, zero_pow, reduceCtorEq]
abel
- · simp only [Real.norm_eq_abs, abs_mul, add_nonneg (norm_nonneg v) (norm_nonneg w), abs_of_nonneg,
- hpos.le, mul_assoc, norm_nonneg, abs_pow]
+ · simp (discharger := positivity) only [Real.norm_eq_abs, abs_mul, abs_of_nonneg, abs_pow]
+ ring
/-- One can get `f'' v w` as the limit of `h ^ (-2)` times the alternate sum of the values of `f`
along the vertices of a quadrilateral with sides `h v` and `h w` based at `x`.
@@ -183,40 +183,27 @@ theorem Convex.isLittleO_alternate_sum_square {v w : E} (h4v : x + (4 : ℝ) •
fun h => h ^ 2 := by
have A : (1 : ℝ) / 2 ∈ Ioc (0 : ℝ) 1 := ⟨by norm_num, by norm_num⟩
have B : (1 : ℝ) / 2 ∈ Icc (0 : ℝ) 1 := ⟨by norm_num, by norm_num⟩
- have C : ∀ w : E, (2 : ℝ) • w = 2 • w := fun w => by simp only [two_smul]
have h2v2w : x + (2 : ℝ) • v + (2 : ℝ) • w ∈ interior s := by
convert s_conv.interior.add_smul_sub_mem h4v h4w B using 1
- simp only [smul_sub, smul_smul, one_div, add_sub_add_left_eq_sub, mul_add, add_smul]
- norm_num
- simp only [show (4 : ℝ) = (2 : ℝ) + (2 : ℝ) by norm_num, _root_.add_smul]
- abel
+ module
have h2vww : x + (2 • v + w) + w ∈ interior s := by
convert h2v2w using 1
- simp only [two_smul]
- abel
+ module
have h2v : x + (2 : ℝ) • v ∈ interior s := by
convert s_conv.add_smul_sub_mem_interior xs h4v A using 1
- simp only [smul_smul, one_div, add_sub_cancel_left, add_right_inj]
- norm_num
+ module
have h2w : x + (2 : ℝ) • w ∈ interior s := by
convert s_conv.add_smul_sub_mem_interior xs h4w A using 1
- simp only [smul_smul, one_div, add_sub_cancel_left, add_right_inj]
- norm_num
+ module
have hvw : x + (v + w) ∈ interior s := by
convert s_conv.add_smul_sub_mem_interior xs h2v2w A using 1
- simp only [smul_smul, one_div, add_sub_cancel_left, add_right_inj, smul_add, smul_sub]
- norm_num
- abel
+ module
have h2vw : x + (2 • v + w) ∈ interior s := by
convert s_conv.interior.add_smul_sub_mem h2v h2v2w B using 1
- simp only [smul_add, smul_sub, smul_smul, ← C]
- norm_num
- abel
+ module
have hvww : x + (v + w) + w ∈ interior s := by
convert s_conv.interior.add_smul_sub_mem h2w h2v2w B using 1
- rw [one_div, add_sub_add_right_eq_sub, add_sub_cancel_left, inv_smul_smul₀ two_ne_zero,
- two_smul]
- abel
+ module
have TA1 := s_conv.taylor_approx_two_segment hf xs hx h2vw h2vww
have TA2 := s_conv.taylor_approx_two_segment hf xs hx hvw hvww
convert TA1.sub TA2 using 1
@@ -245,11 +232,9 @@ theorem Convex.second_derivative_within_at_symmetric_of_mem_interior {v w : E}
apply C.congr' _ _
· filter_upwards [self_mem_nhdsWithin]
intro h (hpos : 0 < h)
- rw [← one_smul ℝ (f'' w v - f'' v w), smul_smul, smul_smul]
- congr 1
- field_simp [LT.lt.ne' hpos]
+ match_scalars <;> field_simp
· filter_upwards [self_mem_nhdsWithin] with h (hpos : 0 < h)
- field_simp [LT.lt.ne' hpos, SMul.smul]
+ field_simp
simpa only [sub_eq_zero] using isLittleO_const_const_iff.1 B
end
@@ -298,8 +283,8 @@ theorem Convex.second_derivative_within_at_symmetric {s : Set E} (s_conv : Conve
s_conv.second_derivative_within_at_symmetric_of_mem_interior hf xs hx (ts w) (ts v)
simp only [ContinuousLinearMap.map_add, ContinuousLinearMap.map_smul, smul_add, smul_smul,
ContinuousLinearMap.add_apply, Pi.smul_apply, ContinuousLinearMap.coe_smul', C] at this
- rw [add_assoc, add_assoc, add_right_inj, add_left_comm, add_right_inj, add_right_inj, mul_comm]
- at this
+ have : (t v * t w) • (f'' v) w = (t v * t w) • (f'' w) v := by
+ linear_combination (norm := module) this
apply smul_right_injective F _ this
simp [(tpos v).ne', (tpos w).ne']
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 2a99f4113e978..7de7ac1214369 100644
--- a/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean
+++ b/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean
@@ -88,6 +88,15 @@ def prod (p : FormalMultilinearSeries 𝕜 E F) (q : FormalMultilinearSeries
FormalMultilinearSeries 𝕜 E (F × G)
| n => (p n).prod (q n)
+/-- Product of formal multilinear series (with the same field `𝕜` and the same source
+space, but possibly different target spaces). -/
+@[simp] def pi {ι : Type*} {F : ι → Type*}
+ [∀ i, AddCommGroup (F i)] [∀ i, Module 𝕜 (F i)] [∀ i, TopologicalSpace (F i)]
+ [∀ i, TopologicalAddGroup (F i)] [∀ i, ContinuousConstSMul 𝕜 (F i)]
+ (p : Π i, FormalMultilinearSeries 𝕜 E (F i)) :
+ FormalMultilinearSeries 𝕜 E (Π i, F i)
+ | n => ContinuousMultilinearMap.pi (fun i ↦ p i n)
+
/-- Killing the zeroth coefficient in a formal multilinear series -/
def removeZero (p : FormalMultilinearSeries 𝕜 E F) : FormalMultilinearSeries 𝕜 E F
| 0 => 0
@@ -158,9 +167,7 @@ corresponds to starting from a Taylor series (`HasFTaylorSeriesUpTo`) for the de
function, and building a Taylor series for the function itself. -/
def unshift (q : FormalMultilinearSeries 𝕜 E (E →L[𝕜] F)) (z : F) : FormalMultilinearSeries 𝕜 E F
| 0 => (continuousMultilinearCurryFin0 𝕜 E F).symm z
- | n + 1 => -- Porting note: added type hint here and explicit universes to fix compile
- (continuousMultilinearCurryRightEquiv' 𝕜 n E F :
- (E [×n]→L[𝕜] E →L[𝕜] F) → (E [×n.succ]→L[𝕜] F)) (q n)
+ | n + 1 => (continuousMultilinearCurryRightEquiv' 𝕜 n E F).symm (q n)
end FormalMultilinearSeries
@@ -295,7 +302,7 @@ noncomputable def fslope (p : FormalMultilinearSeries 𝕜 𝕜 E) : FormalMulti
theorem coeff_fslope : p.fslope.coeff n = p.coeff (n + 1) := by
simp only [fslope, coeff, ContinuousMultilinearMap.curryLeft_apply]
congr 1
- exact Fin.cons_self_tail 1
+ exact Fin.cons_self_tail (fun _ => (1 : 𝕜))
@[simp]
theorem coeff_iterate_fslope (k n : ℕ) : (fslope^[k] p).coeff n = p.coeff (n + k) := by
@@ -316,7 +323,7 @@ def constFormalMultilinearSeries (𝕜 : Type*) [NontriviallyNormedField 𝕜] (
[NormedAddCommGroup E] [NormedSpace 𝕜 E] [ContinuousConstSMul 𝕜 E] [TopologicalAddGroup E]
{F : Type*} [NormedAddCommGroup F] [TopologicalAddGroup F] [NormedSpace 𝕜 F]
[ContinuousConstSMul 𝕜 F] (c : F) : FormalMultilinearSeries 𝕜 E F
- | 0 => ContinuousMultilinearMap.curry0 _ _ c
+ | 0 => ContinuousMultilinearMap.uncurry0 _ _ c
| _ => 0
@[simp]
@@ -333,7 +340,7 @@ lemma constFormalMultilinearSeries_zero [NontriviallyNormedField 𝕜] [NormedAd
simp only [FormalMultilinearSeries.zero_apply, ContinuousMultilinearMap.zero_apply,
constFormalMultilinearSeries]
induction n
- · simp only [ContinuousMultilinearMap.curry0_apply]
+ · simp only [ContinuousMultilinearMap.uncurry0_apply]
· simp only [constFormalMultilinearSeries.match_1.eq_2, ContinuousMultilinearMap.zero_apply]
end Const
@@ -349,25 +356,24 @@ namespace ContinuousLinearMap
/-- Formal power series of a continuous linear map `f : E →L[𝕜] F` at `x : E`:
`f y = f x + f (y - x)`. -/
def fpowerSeries (f : E →L[𝕜] F) (x : E) : FormalMultilinearSeries 𝕜 E F
- | 0 => ContinuousMultilinearMap.curry0 𝕜 _ (f x)
+ | 0 => ContinuousMultilinearMap.uncurry0 𝕜 _ (f x)
| 1 => (continuousMultilinearCurryFin1 𝕜 E F).symm f
| _ => 0
+@[simp]
theorem fpowerSeries_apply_zero (f : E →L[𝕜] F) (x : E) :
- f.fpowerSeries x 0 = ContinuousMultilinearMap.curry0 𝕜 _ (f x) :=
+ 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 72620c2d28d46..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
@@ -326,12 +322,12 @@ theorem to_implicitFunctionOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' :
· ext
-- Porting note: added parentheses to help `simp`
simp only [Classical.choose_spec hker, implicitFunctionDataOfComplemented,
- ContinuousLinearMap.comp_apply, Submodule.coe_subtypeL', Submodule.coeSubtype,
+ ContinuousLinearMap.comp_apply, Submodule.coe_subtypeL', Submodule.coe_subtype,
ContinuousLinearMap.id_apply]
swap
· ext
-- Porting note: added parentheses to help `simp`
- simp only [(ContinuousLinearMap.comp_apply), Submodule.coe_subtypeL', Submodule.coeSubtype,
+ simp only [(ContinuousLinearMap.comp_apply), Submodule.coe_subtypeL', Submodule.coe_subtype,
LinearMap.map_coe_ker, (ContinuousLinearMap.zero_apply)]
simp only [implicitFunctionDataOfComplemented, map_sub, sub_self]
diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean
index 56145cc2bf428..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
@@ -144,7 +142,7 @@ theorem surjOn_closedBall_of_nonlinearRightInverse
simp only [dist_le_zero] at this
rw [this]
have If' : (0 : ℝ) < f'symm.nnnorm := by rw [← inv_pos]; exact (NNReal.coe_nonneg _).trans_lt hc
- have Icf' : (c : ℝ) * f'symm.nnnorm < 1 := by rwa [inv_eq_one_div, lt_div_iff If'] at hc
+ have Icf' : (c : ℝ) * f'symm.nnnorm < 1 := by rwa [inv_eq_one_div, lt_div_iff₀ If'] at hc
have Jf' : (f'symm.nnnorm : ℝ) ≠ 0 := ne_of_gt If'
have Jcf' : (1 : ℝ) - c * f'symm.nnnorm ≠ 0 := by apply ne_of_gt; linarith
/- We have to show that `y` can be written as `f x` for some `x ∈ closedBall b ε`.
@@ -257,7 +255,7 @@ theorem surjOn_closedBall_of_nonlinearRightInverse
-- It remains to check that `f x = y`. This follows from continuity of `f` on `closedBall b ε`
-- and from the fact that `f uₙ` is converging to `y` by construction.
have hx' : Tendsto u atTop (𝓝[closedBall b ε] x) := by
- simp only [nhdsWithin, tendsto_inf, hx, true_and_iff, tendsto_principal]
+ simp only [nhdsWithin, tendsto_inf, hx, true_and, tendsto_principal]
exact Eventually.of_forall fun n => C n _ (D n).2
have T1 : Tendsto (f ∘ u) atTop (𝓝 (f x)) :=
(hf.continuousOn.mono hε x xmem).tendsto.comp hx'
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 b662ec13e36fc..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 :=
@@ -82,7 +81,7 @@ iterated derivative. -/
theorem iteratedFDerivWithin_eq_equiv_comp :
iteratedFDerivWithin 𝕜 n f s =
ContinuousMultilinearMap.piFieldEquiv 𝕜 (Fin n) F ∘ iteratedDerivWithin n f s := by
- rw [iteratedDerivWithin_eq_equiv_comp, ← Function.comp.assoc, LinearIsometryEquiv.self_comp_symm,
+ rw [iteratedDerivWithin_eq_equiv_comp, ← Function.comp_assoc, LinearIsometryEquiv.self_comp_symm,
Function.id_comp]
/-- The `n`-th Fréchet derivative applied to a vector `(m 0, ..., m (n-1))` is the derivative
@@ -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
@@ -203,7 +202,7 @@ theorem iteratedDeriv_eq_equiv_comp : iteratedDeriv n f =
iterated derivative. -/
theorem iteratedFDeriv_eq_equiv_comp : iteratedFDeriv 𝕜 n f =
ContinuousMultilinearMap.piFieldEquiv 𝕜 (Fin n) F ∘ iteratedDeriv n f := by
- rw [iteratedDeriv_eq_equiv_comp, ← Function.comp.assoc, LinearIsometryEquiv.self_comp_symm,
+ rw [iteratedDeriv_eq_equiv_comp, ← Function.comp_assoc, LinearIsometryEquiv.self_comp_symm,
Function.id_comp]
/-- The `n`-th Fréchet derivative applied to a vector `(m 0, ..., m (n-1))` is the derivative
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 6d2876fdc8402..21a62a2741891 100644
--- a/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean
+++ b/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean
@@ -44,7 +44,7 @@ TODO: prove similar theorems assuming that the functions tend to zero at infinit
integrable derivatives.
-/
-open MeasureTheory Measure FiniteDimensional
+open MeasureTheory Measure Module
variable {E F G W : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [NormedAddCommGroup F]
[NormedSpace ℝ F] [NormedAddCommGroup G] [NormedSpace ℝ G] [NormedAddCommGroup W]
@@ -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 707218f441f7c..b386d402623c8 100644
--- a/Mathlib/Analysis/Calculus/MeanValue.lean
+++ b/Mathlib/Analysis/Calculus/MeanValue.lean
@@ -416,22 +416,28 @@ end
### Vector-valued functions `f : E → G`
Theorems in this section work both for real and complex differentiable functions. We use assumptions
-`[RCLike 𝕜] [NormedSpace 𝕜 E] [NormedSpace 𝕜 G]` to achieve this result. For the domain `E` we
-also assume `[NormedSpace ℝ E]` to have a notion of a `Convex` set. -/
+`[NontriviallyNormedField 𝕜] [IsRCLikeNormedField 𝕜] [NormedSpace 𝕜 E] [NormedSpace 𝕜 G]` to
+achieve this result. For the domain `E` we also assume `[NormedSpace ℝ E]` to have a notion
+of a `Convex` set. -/
section
-variable {𝕜 G : Type*} [RCLike 𝕜] [NormedSpace 𝕜 E] [NormedAddCommGroup G] [NormedSpace 𝕜 G]
-
namespace Convex
-variable {f g : E → G} {C : ℝ} {s : Set E} {x y : E} {f' g' : E → E →L[𝕜] G} {φ : E →L[𝕜] G}
+variable {𝕜 G : Type*} [NontriviallyNormedField 𝕜] [IsRCLikeNormedField 𝕜]
+ [NormedSpace 𝕜 E] [NormedAddCommGroup G] [NormedSpace 𝕜 G]
+ {f g : E → G} {C : ℝ} {s : Set E} {x y : E} {f' g' : E → E →L[𝕜] G} {φ : E →L[𝕜] G}
+
+instance (priority := 100) : PathConnectedSpace 𝕜 := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
+ infer_instance
/-- The mean value theorem on a convex set: if the derivative of a function is bounded by `C`, then
the function is `C`-Lipschitz. Version with `HasFDerivWithinAt`. -/
theorem norm_image_sub_le_of_norm_hasFDerivWithin_le
(hf : ∀ x ∈ s, HasFDerivWithinAt f (f' x) s x) (bound : ∀ x ∈ s, ‖f' x‖ ≤ C) (hs : Convex ℝ s)
(xs : x ∈ s) (ys : y ∈ s) : ‖f y - f x‖ ≤ C * ‖y - x‖ := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
letI : NormedSpace ℝ G := RestrictScalars.normedSpace ℝ 𝕜 G
/- By composition with `AffineMap.lineMap x y`, we reduce to a statement for functions defined
on `[0,1]`, for which it is proved in `norm_image_sub_le_of_norm_deriv_le_segment`.
@@ -524,6 +530,7 @@ theorem _root_.lipschitzWith_of_nnnorm_fderiv_le
{E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {f : E → G}
{C : ℝ≥0} (hf : Differentiable 𝕜 f)
(bound : ∀ x, ‖fderiv 𝕜 f x‖₊ ≤ C) : LipschitzWith C f := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
let A : NormedSpace ℝ E := RestrictScalars.normedSpace ℝ 𝕜 E
rw [← lipschitzOnWith_univ]
exact lipschitzOnWith_of_nnnorm_fderiv_le (fun x _ ↦ hf x) (fun x _ ↦ bound x) convex_univ
@@ -573,6 +580,7 @@ theorem _root_.is_const_of_fderiv_eq_zero
{E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {f : E → G}
(hf : Differentiable 𝕜 f) (hf' : ∀ x, fderiv 𝕜 f x = 0)
(x y : E) : f x = f y := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
let A : NormedSpace ℝ E := RestrictScalars.normedSpace ℝ 𝕜 E
exact convex_univ.is_const_of_fderivWithin_eq_zero hf.differentiableOn
(fun x _ => by rw [fderivWithin_univ]; exact hf' x) trivial trivial
@@ -591,6 +599,7 @@ theorem _root_.eq_of_fderiv_eq
{E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {f g : E → G}
(hf : Differentiable 𝕜 f) (hg : Differentiable 𝕜 g)
(hf' : ∀ x, fderiv 𝕜 f x = fderiv 𝕜 g x) (x : E) (hfgx : f x = g x) : f = g := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
let A : NormedSpace ℝ E := RestrictScalars.normedSpace ℝ 𝕜 E
suffices Set.univ.EqOn f g from funext fun x => this <| mem_univ x
exact convex_univ.eqOn_of_fderivWithin_eq hf.differentiableOn hg.differentiableOn
@@ -600,7 +609,8 @@ end Convex
namespace Convex
-variable {f f' : 𝕜 → G} {s : Set 𝕜} {x y : 𝕜}
+variable {𝕜 G : Type*} [RCLike 𝕜] [NormedAddCommGroup G] [NormedSpace 𝕜 G]
+ {f f' : 𝕜 → G} {s : Set 𝕜} {x y : 𝕜}
/-- The mean value theorem on a convex set in dimension 1: if the derivative of a function is
bounded by `C`, then the function is `C`-Lipschitz. Version with `HasDerivWithinAt`. -/
@@ -798,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]
@@ -891,7 +901,7 @@ theorem Convex.mul_sub_lt_image_sub_of_lt_deriv {D : Set ℝ} (hD : Convex ℝ D
obtain ⟨a, a_mem, ha⟩ : ∃ a ∈ Ioo x y, deriv f a = (f y - f x) / (y - x) :=
exists_deriv_eq_slope f hxy (hf.mono hxyD) (hf'.mono hxyD')
have : C < (f y - f x) / (y - x) := ha ▸ hf'_gt _ (hxyD' a_mem)
- exact (lt_div_iff (sub_pos.2 hxy)).1 this
+ exact (lt_div_iff₀ (sub_pos.2 hxy)).1 this
/-- Let `f : ℝ → ℝ` be a differentiable function. If `C < f'`, then `f` grows faster than
`C * x`, i.e., `C * (y - x) < f y - f x` whenever `x < y`. -/
@@ -1029,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`
@@ -1104,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/ParametricIntegral.lean b/Mathlib/Analysis/Calculus/ParametricIntegral.lean
index e6088a80f8437..6bafbed0ec063 100644
--- a/Mathlib/Analysis/Calculus/ParametricIntegral.lean
+++ b/Mathlib/Analysis/Calculus/ParametricIntegral.lean
@@ -140,7 +140,7 @@ theorem hasFDerivAt_integral_of_dominated_loc_of_lip' {F' : α → H →L[𝕜]
gcongr; exact (F' a).le_opNorm _
_ ≤ b a + ‖F' a‖ := ?_
simp only [← div_eq_inv_mul]
- apply_rules [add_le_add, div_le_of_nonneg_of_le_mul] <;> first | rfl | positivity
+ apply_rules [add_le_add, div_le_of_le_mul₀] <;> first | rfl | positivity
· exact b_int.add hF'_int.norm
· apply h_diff.mono
intro a ha
diff --git a/Mathlib/Analysis/Calculus/Rademacher.lean b/Mathlib/Analysis/Calculus/Rademacher.lean
index b1924f51dde25..28ad0559741a1 100644
--- a/Mathlib/Analysis/Calculus/Rademacher.lean
+++ b/Mathlib/Analysis/Calculus/Rademacher.lean
@@ -42,7 +42,7 @@ See `LipschitzWith.hasFderivAt_of_hasLineDerivAt_of_closure`.
* [Pertti Mattila, Geometry of sets and measures in Euclidean spaces, Theorem 7.3][Federer1996]
-/
-open Filter MeasureTheory Measure FiniteDimensional Metric Set Asymptotics
+open Filter MeasureTheory Measure Module Metric Set Asymptotics
open scoped NNReal ENNReal Topology
@@ -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/SmoothSeries.lean b/Mathlib/Analysis/Calculus/SmoothSeries.lean
index db033d220a52a..58d0f39d86c54 100644
--- a/Mathlib/Analysis/Calculus/SmoothSeries.lean
+++ b/Mathlib/Analysis/Calculus/SmoothSeries.lean
@@ -26,8 +26,8 @@ open Set Metric TopologicalSpace Function Asymptotics Filter
open scoped Topology NNReal
-variable {α β 𝕜 E F : Type*} [RCLike 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E]
- [NormedAddCommGroup F] [CompleteSpace F] {u : α → ℝ}
+variable {α β 𝕜 E F : Type*} [NontriviallyNormedField 𝕜] [IsRCLikeNormedField 𝕜]
+ [NormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedAddCommGroup F] [CompleteSpace F] {u : α → ℝ}
/-! ### Differentiability -/
@@ -77,7 +77,7 @@ theorem hasFDerivAt_tsum_of_isPreconnected (hu : Summable u) (hs : IsOpen s)
apply Summable.hasSum
exact summable_of_summable_hasFDerivAt_of_isPreconnected hu hs h's hf hf' hx₀ hf0 hy
refine hasFDerivAt_of_tendstoUniformlyOn hs (tendstoUniformlyOn_tsum hu hf')
- (fun t y hy => ?_) A _ hx
+ (fun t y hy => ?_) A hx
exact HasFDerivAt.sum fun n _ => hf n y hy
/-- Consider a series of functions `∑' n, f n x` on a preconnected open set. If the series converges
@@ -100,6 +100,7 @@ then the series converges everywhere. -/
theorem summable_of_summable_hasFDerivAt (hu : Summable u)
(hf : ∀ n x, HasFDerivAt (f n) (f' n x) x) (hf' : ∀ n x, ‖f' n x‖ ≤ u n)
(hf0 : Summable fun n => f n x₀) (x : E) : Summable fun n => f n x := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
let _ : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ 𝕜 _
exact summable_of_summable_hasFDerivAt_of_isPreconnected hu isOpen_univ isPreconnected_univ
(fun n x _ => hf n x) (fun n x _ => hf' n x) (mem_univ _) hf0 (mem_univ _)
@@ -119,6 +120,7 @@ then the series is differentiable and its derivative is the sum of the derivativ
theorem hasFDerivAt_tsum (hu : Summable u) (hf : ∀ n x, HasFDerivAt (f n) (f' n x) x)
(hf' : ∀ n x, ‖f' n x‖ ≤ u n) (hf0 : Summable fun n => f n x₀) (x : E) :
HasFDerivAt (fun y => ∑' n, f n y) (∑' n, f' n x) x := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
let A : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ 𝕜 _
exact hasFDerivAt_tsum_of_isPreconnected hu isOpen_univ isPreconnected_univ
(fun n x _ => hf n x) (fun n x _ => hf' n x) (mem_univ _) hf0 (mem_univ _)
@@ -199,7 +201,7 @@ theorem iteratedFDeriv_tsum (hf : ∀ i, ContDiff 𝕜 N (f i))
rw [fderiv_tsum (hv _ hk) (fun n => (hf n).differentiable_iteratedFDeriv h'k) _ A]
· ext1 x
exact (continuousMultilinearCurryLeftEquiv 𝕜
- (fun _ : Fin (k + 1) => E) F).toContinuousLinearEquiv.map_tsum
+ (fun _ : Fin (k + 1) => E) F).symm.toContinuousLinearEquiv.map_tsum
· intro n x
simpa only [iteratedFDeriv_succ_eq_comp_left, LinearIsometryEquiv.norm_map, comp_apply]
using h'f k.succ n x hk
diff --git a/Mathlib/Analysis/Calculus/TangentCone.lean b/Mathlib/Analysis/Calculus/TangentCone.lean
index 280e5356cb943..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 :=
@@ -196,7 +196,7 @@ theorem mem_tangentCone_of_openSegment_subset {s : Set G} {x y : G} (h : openSeg
rw [openSegment_eq_image]
refine ⟨(1 / 2) ^ n, ⟨?_, ?_⟩, ?_⟩
· exact pow_pos one_half_pos _
- · exact pow_lt_one one_half_pos.le one_half_lt_one hn
+ · exact pow_lt_one₀ one_half_pos.le one_half_lt_one hn
· simp only [sub_smul, one_smul, smul_sub]; abel
/-- If a subset of a real vector space contains a segment, then the direction of this
diff --git a/Mathlib/Analysis/Calculus/UniformLimitsDeriv.lean b/Mathlib/Analysis/Calculus/UniformLimitsDeriv.lean
index 75ca96be5b582..434945a20c58c 100644
--- a/Mathlib/Analysis/Calculus/UniformLimitsDeriv.lean
+++ b/Mathlib/Analysis/Calculus/UniformLimitsDeriv.lean
@@ -99,7 +99,8 @@ open scoped uniformity Filter Topology
section LimitsOfDerivatives
-variable {ι : Type*} {l : Filter ι} {E : Type*} [NormedAddCommGroup E] {𝕜 : Type*} [RCLike 𝕜]
+variable {ι : Type*} {l : Filter ι} {E : Type*} [NormedAddCommGroup E] {𝕜 : Type*}
+ [NontriviallyNormedField 𝕜] [IsRCLikeNormedField 𝕜]
[NormedSpace 𝕜 E] {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] {f : ι → E → G}
{g : E → G} {f' : ι → E → E →L[𝕜] G} {g' : E → E →L[𝕜] G} {x : E}
@@ -110,6 +111,7 @@ sequence in a neighborhood of `x`. -/
theorem uniformCauchySeqOnFilter_of_fderiv (hf' : UniformCauchySeqOnFilter f' l (𝓝 x))
(hf : ∀ᶠ n : ι × E in l ×ˢ 𝓝 x, HasFDerivAt (f n.1) (f' n.1 n.2) n.2)
(hfg : Cauchy (map (fun n => f n x) l)) : UniformCauchySeqOnFilter f l (𝓝 x) := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
letI : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ 𝕜 _
rw [SeminormedAddGroup.uniformCauchySeqOnFilter_iff_tendstoUniformlyOnFilter_zero] at hf' ⊢
suffices
@@ -173,6 +175,7 @@ convergence. See `cauchy_map_of_uniformCauchySeqOn_fderiv`.
theorem uniformCauchySeqOn_ball_of_fderiv {r : ℝ} (hf' : UniformCauchySeqOn f' l (Metric.ball x r))
(hf : ∀ n : ι, ∀ y : E, y ∈ Metric.ball x r → HasFDerivAt (f n) (f' n y) y)
(hfg : Cauchy (map (fun n => f n x) l)) : UniformCauchySeqOn f l (Metric.ball x r) := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
letI : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ 𝕜 _
have : NeBot l := (cauchy_map_iff.1 hfg).1
rcases le_or_lt r 0 with (hr | hr)
@@ -249,15 +252,16 @@ theorem cauchy_map_of_uniformCauchySeqOn_fderiv {s : Set E} (hs : IsOpen s) (h's
/-- If `f_n → g` pointwise and the derivatives `(f_n)' → h` _uniformly_ converge, then
in fact for a fixed `y`, the difference quotients `‖z - y‖⁻¹ • (f_n z - f_n y)` converge
_uniformly_ to `‖z - y‖⁻¹ • (g z - g y)` -/
-theorem difference_quotients_converge_uniformly (hf' : TendstoUniformlyOnFilter f' g' l (𝓝 x))
+theorem difference_quotients_converge_uniformly
+ {E : Type*} [NormedAddCommGroup E] {𝕜 : Type*} [RCLike 𝕜]
+ [NormedSpace 𝕜 E] {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] {f : ι → E → G}
+ {g : E → G} {f' : ι → E → E →L[𝕜] G} {g' : E → E →L[𝕜] G} {x : E}
+ (hf' : TendstoUniformlyOnFilter f' g' l (𝓝 x))
(hf : ∀ᶠ n : ι × E in l ×ˢ 𝓝 x, HasFDerivAt (f n.1) (f' n.1 n.2) n.2)
(hfg : ∀ᶠ y : E in 𝓝 x, Tendsto (fun n => f n y) l (𝓝 (g y))) :
TendstoUniformlyOnFilter (fun n : ι => fun y : E => (‖y - x‖⁻¹ : 𝕜) • (f n y - f n x))
(fun y : E => (‖y - x‖⁻¹ : 𝕜) • (g y - g x)) l (𝓝 x) := by
let A : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ 𝕜 _
- rcases eq_or_ne l ⊥ with (hl | hl)
- · simp only [hl, TendstoUniformlyOnFilter, bot_prod, eventually_bot, imp_true_iff]
- haveI : NeBot l := ⟨hl⟩
refine
UniformCauchySeqOnFilter.tendstoUniformlyOnFilter_of_tendsto ?_
((hfg.and (eventually_const.mpr hfg.self_of_nhds)).mono fun y hy =>
@@ -282,7 +286,7 @@ theorem difference_quotients_converge_uniformly (hf' : TendstoUniformlyOnFilter
refine lt_of_le_of_lt ?_ hqε
by_cases hyz' : x = y; · simp [hyz', hqpos.le]
have hyz : 0 < ‖y - x‖ := by rw [norm_pos_iff]; intro hy'; exact hyz' (eq_of_sub_eq_zero hy').symm
- rw [inv_mul_le_iff hyz, mul_comm, sub_sub_sub_comm]
+ rw [inv_mul_le_iff₀ hyz, mul_comm, sub_sub_sub_comm]
simp only [Pi.zero_apply, dist_zero_left] at e
refine
Convex.norm_image_sub_le_of_norm_hasFDerivWithin_le
@@ -302,6 +306,7 @@ theorem hasFDerivAt_of_tendstoUniformlyOnFilter [NeBot l]
(hf' : TendstoUniformlyOnFilter f' g' l (𝓝 x))
(hf : ∀ᶠ n : ι × E in l ×ˢ 𝓝 x, HasFDerivAt (f n.1) (f' n.1 n.2) n.2)
(hfg : ∀ᶠ y in 𝓝 x, Tendsto (fun n => f n y) l (𝓝 (g y))) : HasFDerivAt g (g' x) x := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
-- The proof strategy follows several steps:
-- 1. The quantifiers in the definition of the derivative are
-- `∀ ε > 0, ∃δ > 0, ∀y ∈ B_δ(x)`. We will introduce a quantifier in the middle:
@@ -351,8 +356,8 @@ theorem hasFDerivAt_of_tendstoUniformlyOnFilter [NeBot l]
apply ((this ε hε).filter_mono curry_le_prod).mono
intro n hn
rw [dist_eq_norm] at hn ⊢
- rw [← smul_sub] at hn
- rwa [sub_zero]
+ convert hn using 2
+ module
· -- (Almost) the definition of the derivatives
rw [Metric.tendsto_nhds]
intro ε hε
@@ -380,7 +385,7 @@ theorem hasFDerivAt_of_tendstoUniformlyOnFilter [NeBot l]
by_cases hx : x = n.2; · simp [hx]
have hnx : 0 < ‖n.2 - x‖ := by
rw [norm_pos_iff]; intro hx'; exact hx (eq_of_sub_eq_zero hx').symm
- rw [inv_mul_le_iff hnx, mul_comm]
+ rw [inv_mul_le_iff₀ hnx, mul_comm]
simp only [Function.comp_apply, Prod.map_apply']
rw [norm_sub_rev]
exact (f' n.1 x - g' x).le_opNorm (n.2 - x)
@@ -411,20 +416,19 @@ _uniformly_ to their limit on an open set containing `x`. -/
theorem hasFDerivAt_of_tendstoUniformlyOn [NeBot l] {s : Set E} (hs : IsOpen s)
(hf' : TendstoUniformlyOn f' g' l s)
(hf : ∀ n : ι, ∀ x : E, x ∈ s → HasFDerivAt (f n) (f' n x) x)
- (hfg : ∀ x : E, x ∈ s → Tendsto (fun n => f n x) l (𝓝 (g x))) :
- ∀ x : E, x ∈ s → HasFDerivAt g (g' x) x := fun _ =>
- hasFDerivAt_of_tendstoLocallyUniformlyOn hs hf'.tendstoLocallyUniformlyOn hf hfg
+ (hfg : ∀ x : E, x ∈ s → Tendsto (fun n => f n x) l (𝓝 (g x))) (hx : x ∈ s) :
+ HasFDerivAt g (g' x) x :=
+ hasFDerivAt_of_tendstoLocallyUniformlyOn hs hf'.tendstoLocallyUniformlyOn hf hfg hx
/-- `(d/dx) lim_{n → ∞} f n x = lim_{n → ∞} f' n x` when the `f' n` converge
_uniformly_ to their limit. -/
theorem hasFDerivAt_of_tendstoUniformly [NeBot l] (hf' : TendstoUniformly f' g' l)
(hf : ∀ n : ι, ∀ x : E, HasFDerivAt (f n) (f' n x) x)
- (hfg : ∀ x : E, Tendsto (fun n => f n x) l (𝓝 (g x))) : ∀ x : E, HasFDerivAt g (g' x) x := by
- intro x
+ (hfg : ∀ x : E, Tendsto (fun n => f n x) l (𝓝 (g x))) (x : E) : HasFDerivAt g (g' x) x := by
have hf : ∀ n : ι, ∀ x : E, x ∈ Set.univ → HasFDerivAt (f n) (f' n x) x := by simp [hf]
have hfg : ∀ x : E, x ∈ Set.univ → Tendsto (fun n => f n x) l (𝓝 (g x)) := by simp [hfg]
have hf' : TendstoUniformlyOn f' g' l Set.univ := by rwa [tendstoUniformlyOn_univ]
- exact hasFDerivAt_of_tendstoUniformlyOn isOpen_univ hf' hf hfg x (Set.mem_univ x)
+ exact hasFDerivAt_of_tendstoUniformlyOn isOpen_univ hf' hf hfg (Set.mem_univ x)
end LimitsOfDerivatives
@@ -436,7 +440,8 @@ In this section, we provide `deriv` equivalents of the `fderiv` lemmas in the pr
-/
-variable {ι : Type*} {l : Filter ι} {𝕜 : Type*} [RCLike 𝕜] {G : Type*} [NormedAddCommGroup G]
+variable {ι : Type*} {l : Filter ι} {𝕜 : Type*} [NontriviallyNormedField 𝕜]
+ {G : Type*} [NormedAddCommGroup G]
[NormedSpace 𝕜 G] {f : ι → 𝕜 → G} {g : 𝕜 → G} {f' : ι → 𝕜 → G} {g' : 𝕜 → G} {x : 𝕜}
/-- If our derivatives converge uniformly, then the Fréchet derivatives converge uniformly -/
@@ -461,6 +466,8 @@ theorem UniformCauchySeqOnFilter.one_smulRight {l' : Filter 𝕜}
rw [← smul_sub, norm_smul, mul_comm]
gcongr
+variable [IsRCLikeNormedField 𝕜]
+
theorem uniformCauchySeqOnFilter_of_deriv (hf' : UniformCauchySeqOnFilter f' l (𝓝 x))
(hf : ∀ᶠ n : ι × 𝕜 in l ×ˢ 𝓝 x, HasDerivAt (f n.1) (f' n.1 n.2) n.2)
(hfg : Cauchy (map (fun n => f n x) l)) : UniformCauchySeqOnFilter f l (𝓝 x) := by
@@ -530,18 +537,17 @@ theorem hasDerivAt_of_tendsto_locally_uniformly_on' [NeBot l] {s : Set 𝕜} (hs
theorem hasDerivAt_of_tendstoUniformlyOn [NeBot l] {s : Set 𝕜} (hs : IsOpen s)
(hf' : TendstoUniformlyOn f' g' l s)
(hf : ∀ᶠ n in l, ∀ x : 𝕜, x ∈ s → HasDerivAt (f n) (f' n x) x)
- (hfg : ∀ x : 𝕜, x ∈ s → Tendsto (fun n => f n x) l (𝓝 (g x))) :
- ∀ x : 𝕜, x ∈ s → HasDerivAt g (g' x) x := fun _ =>
- hasDerivAt_of_tendstoLocallyUniformlyOn hs hf'.tendstoLocallyUniformlyOn hf hfg
+ (hfg : ∀ x : 𝕜, x ∈ s → Tendsto (fun n => f n x) l (𝓝 (g x))) (hx : x ∈ s) :
+ HasDerivAt g (g' x) x :=
+ hasDerivAt_of_tendstoLocallyUniformlyOn hs hf'.tendstoLocallyUniformlyOn hf hfg hx
theorem hasDerivAt_of_tendstoUniformly [NeBot l] (hf' : TendstoUniformly f' g' l)
(hf : ∀ᶠ n in l, ∀ x : 𝕜, HasDerivAt (f n) (f' n x) x)
- (hfg : ∀ x : 𝕜, Tendsto (fun n => f n x) l (𝓝 (g x))) : ∀ x : 𝕜, HasDerivAt g (g' x) x := by
- intro x
+ (hfg : ∀ x : 𝕜, Tendsto (fun n => f n x) l (𝓝 (g x))) (x : 𝕜) : HasDerivAt g (g' x) x := by
have hf : ∀ᶠ n in l, ∀ x : 𝕜, x ∈ Set.univ → HasDerivAt (f n) (f' n x) x := by
filter_upwards [hf] with n h x _ using h x
have hfg : ∀ x : 𝕜, x ∈ Set.univ → Tendsto (fun n => f n x) l (𝓝 (g x)) := by simp [hfg]
have hf' : TendstoUniformlyOn f' g' l Set.univ := by rwa [tendstoUniformlyOn_univ]
- exact hasDerivAt_of_tendstoUniformlyOn isOpen_univ hf' hf hfg x (Set.mem_univ x)
+ exact hasDerivAt_of_tendstoUniformlyOn isOpen_univ hf' hf hfg (Set.mem_univ x)
end deriv
diff --git a/Mathlib/Analysis/Complex/AbelLimit.lean b/Mathlib/Analysis/Complex/AbelLimit.lean
index d00d00856facc..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 ↦ ?_⟩
@@ -206,9 +207,9 @@ theorem tendsto_tsum_powerSeries_nhdsWithin_stolzSet
calc
_ ≤ ‖1 - z‖ * ∑ i ∈ range B₁, ‖l - s (i + 1)‖ := by
gcongr; nth_rw 3 [← mul_one ‖_‖]
- gcongr; exact pow_le_one _ (norm_nonneg _) zn.le
+ gcongr; exact pow_le_one₀ (norm_nonneg _) zn.le
_ ≤ ‖1 - z‖ * (F + 1) := by gcongr; linarith only
- _ < _ := by rwa [norm_sub_rev, lt_div_iff (by positivity)] at zd
+ _ < _ := by rwa [norm_sub_rev, lt_div_iff₀ (by positivity)] at zd
have S₂ : ‖1 - z‖ * ∑ i ∈ Ico B₁ (max B₁ B₂), ‖l - s (i + 1)‖ * ‖z‖ ^ i < ε / 4 :=
calc
_ ≤ ‖1 - z‖ * ∑ i ∈ Ico B₁ (max B₁ B₂), ε / 4 / M * ‖z‖ ^ i := by
@@ -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/Arg.lean b/Mathlib/Analysis/Complex/Arg.lean
index ec78377f02673..13b4096755966 100644
--- a/Mathlib/Analysis/Complex/Arg.lean
+++ b/Mathlib/Analysis/Complex/Arg.lean
@@ -31,7 +31,7 @@ theorem sameRay_iff : SameRay ℝ x y ↔ x = 0 ∨ y = 0 ∨ x.arg = y.arg := b
· simp
rcases eq_or_ne y 0 with (rfl | hy)
· simp
- simp only [hx, hy, false_or_iff, sameRay_iff_norm_smul_eq, arg_eq_arg_iff hx hy]
+ simp only [hx, hy, sameRay_iff_norm_smul_eq, arg_eq_arg_iff hx hy]
field_simp [hx, hy]
rw [mul_comm, eq_comm]
diff --git a/Mathlib/Analysis/Complex/Basic.lean b/Mathlib/Analysis/Complex/Basic.lean
index 492769068a2f2..eefdc2d5f0b00 100644
--- a/Mathlib/Analysis/Complex/Basic.lean
+++ b/Mathlib/Analysis/Complex/Basic.lean
@@ -208,11 +208,14 @@ theorem antilipschitz_equivRealProd : AntilipschitzWith (NNReal.sqrt 2) equivRea
AddMonoidHomClass.antilipschitz_of_bound equivRealProdLm fun z ↦ by
simpa only [Real.coe_sqrt, NNReal.coe_ofNat] using abs_le_sqrt_two_mul_max z
-theorem uniformEmbedding_equivRealProd : UniformEmbedding equivRealProd :=
- antilipschitz_equivRealProd.uniformEmbedding lipschitz_equivRealProd.uniformContinuous
+theorem isUniformEmbedding_equivRealProd : IsUniformEmbedding equivRealProd :=
+ antilipschitz_equivRealProd.isUniformEmbedding lipschitz_equivRealProd.uniformContinuous
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_equivRealProd := isUniformEmbedding_equivRealProd
instance : CompleteSpace ℂ :=
- (completeSpace_congr uniformEmbedding_equivRealProd).mpr inferInstance
+ (completeSpace_congr isUniformEmbedding_equivRealProd).mpr inferInstance
instance instT2Space : T2Space ℂ := TopologicalSpace.t2Space_of_metrizableSpace
@@ -281,7 +284,7 @@ theorem restrictScalars_one_smulRight' (x : E) :
ContinuousLinearMap.restrictScalars ℝ ((1 : ℂ →L[ℂ] ℂ).smulRight x : ℂ →L[ℂ] E) =
reCLM.smulRight x + I • imCLM.smulRight x := by
ext ⟨a, b⟩
- simp [mk_eq_add_mul_I, mul_smul, smul_comm I b x]
+ simp [map_add, mk_eq_add_mul_I, mul_smul, smul_comm I b x]
theorem restrictScalars_one_smulRight (x : ℂ) :
ContinuousLinearMap.restrictScalars ℝ ((1 : ℂ →L[ℂ] ℂ).smulRight x : ℂ →L[ℂ] ℂ) =
@@ -355,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 ℝ ℂ)
@@ -595,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/CauchyIntegral.lean b/Mathlib/Analysis/Complex/CauchyIntegral.lean
index adda35554977c..ebc991f8801e8 100644
--- a/Mathlib/Analysis/Complex/CauchyIntegral.lean
+++ b/Mathlib/Analysis/Complex/CauchyIntegral.lean
@@ -3,15 +3,14 @@ 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.MeasureTheory.Measure.Lebesgue.Complex
-import Mathlib.MeasureTheory.Integral.DivergenceTheorem
-import Mathlib.MeasureTheory.Integral.CircleIntegral
-import Mathlib.Analysis.Calculus.Dslope
-import Mathlib.Analysis.Analytic.Basic
-import Mathlib.Analysis.Complex.ReImTopology
+import Mathlib.Analysis.Analytic.Uniqueness
import Mathlib.Analysis.Calculus.DiffContOnCl
+import Mathlib.Analysis.Calculus.Dslope
import Mathlib.Analysis.Calculus.FDeriv.Analytic
-import Mathlib.Data.Real.Cardinality
+import Mathlib.Analysis.Complex.ReImTopology
+import Mathlib.MeasureTheory.Integral.CircleIntegral
+import Mathlib.MeasureTheory.Integral.DivergenceTheorem
+import Mathlib.MeasureTheory.Measure.Lebesgue.Complex
/-!
# Cauchy integral formula
@@ -569,14 +568,18 @@ protected theorem _root_.DifferentiableOn.analyticAt {s : Set ℂ} {f : ℂ →
lift R to ℝ≥0 using hR0.le
exact ((hd.mono hRs).hasFPowerSeriesOnBall hR0).analyticAt
+theorem _root_.DifferentiableOn.analyticOnNhd {s : Set ℂ} {f : ℂ → E} (hd : DifferentiableOn ℂ f s)
+ (hs : IsOpen s) : AnalyticOnNhd ℂ f s := fun _z hz => hd.analyticAt (hs.mem_nhds hz)
+
theorem _root_.DifferentiableOn.analyticOn {s : Set ℂ} {f : ℂ → E} (hd : DifferentiableOn ℂ f s)
- (hs : IsOpen s) : AnalyticOn ℂ f s := fun _z hz => hd.analyticAt (hs.mem_nhds hz)
+ (hs : IsOpen s) : AnalyticOn ℂ f s :=
+ (hd.analyticOnNhd hs).analyticOn
/-- If `f : ℂ → E` is complex differentiable on some open set `s`, then it is continuously
differentiable on `s`. -/
protected theorem _root_.DifferentiableOn.contDiffOn {s : Set ℂ} {f : ℂ → E} {n : ℕ}
(hd : DifferentiableOn ℂ f s) (hs : IsOpen s) : ContDiffOn ℂ n f s :=
- (hd.analyticOn hs).contDiffOn
+ (hd.analyticOnNhd hs).contDiffOn
/-- A complex differentiable function `f : ℂ → E` is analytic at every point. -/
protected theorem _root_.Differentiable.analyticAt {f : ℂ → E} (hf : Differentiable ℂ f) (z : ℂ) :
@@ -595,16 +598,27 @@ protected theorem _root_.Differentiable.hasFPowerSeriesOnBall {f : ℂ → E} (h
(h.differentiableOn.hasFPowerSeriesOnBall hR).r_eq_top_of_exists fun _r hr =>
⟨_, h.differentiableOn.hasFPowerSeriesOnBall hr⟩
+/-- On an open set, `f : ℂ → E` is analytic iff it is differentiable -/
+theorem analyticOnNhd_iff_differentiableOn {f : ℂ → E} {s : Set ℂ} (o : IsOpen s) :
+ AnalyticOnNhd ℂ f s ↔ DifferentiableOn ℂ f s :=
+ ⟨AnalyticOnNhd.differentiableOn, fun d _ zs ↦ d.analyticAt (o.mem_nhds zs)⟩
+
/-- On an open set, `f : ℂ → E` is analytic iff it is differentiable -/
theorem analyticOn_iff_differentiableOn {f : ℂ → E} {s : Set ℂ} (o : IsOpen s) :
- AnalyticOn ℂ f s ↔ DifferentiableOn ℂ f s :=
- ⟨AnalyticOn.differentiableOn, fun d _ zs ↦ d.analyticAt (o.mem_nhds zs)⟩
+ AnalyticOn ℂ f s ↔ DifferentiableOn ℂ f s := by
+ rw [o.analyticOn_iff_analyticOnNhd]
+ exact analyticOnNhd_iff_differentiableOn o
/-- `f : ℂ → E` is entire iff it's differentiable -/
+theorem analyticOnNhd_univ_iff_differentiable {f : ℂ → E} :
+ AnalyticOnNhd ℂ f univ ↔ Differentiable ℂ f := by
+ simp only [← differentiableOn_univ]
+ exact analyticOnNhd_iff_differentiableOn isOpen_univ
+
theorem analyticOn_univ_iff_differentiable {f : ℂ → E} :
AnalyticOn ℂ f univ ↔ Differentiable ℂ f := by
- simp only [← differentiableOn_univ]
- exact analyticOn_iff_differentiableOn isOpen_univ
+ rw [analyticOn_univ]
+ exact analyticOnNhd_univ_iff_differentiable
/-- `f : ℂ → E` is analytic at `z` iff it's differentiable near `z` -/
theorem analyticAt_iff_eventually_differentiableAt {f : ℂ → E} {c : ℂ} :
@@ -615,8 +629,8 @@ theorem analyticAt_iff_eventually_differentiableAt {f : ℂ → E} {c : ℂ} :
apply AnalyticAt.differentiableAt
· intro d
rcases _root_.eventually_nhds_iff.mp d with ⟨s, d, o, m⟩
- have h : AnalyticOn ℂ f s := by
- refine DifferentiableOn.analyticOn ?_ o
+ have h : AnalyticOnNhd ℂ f s := by
+ refine DifferentiableOn.analyticOnNhd ?_ o
intro z m
exact (d z m).differentiableWithinAt
exact h _ m
diff --git a/Mathlib/Analysis/Complex/Circle.lean b/Mathlib/Analysis/Complex/Circle.lean
index bda86fd651ad1..72e66ae46c1b7 100644
--- a/Mathlib/Analysis/Complex/Circle.lean
+++ b/Mathlib/Analysis/Complex/Circle.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Heather Macbeth
-/
import Mathlib.Analysis.SpecialFunctions.Exp
-import Mathlib.Topology.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Basic
import Mathlib.Analysis.Normed.Field.UnitBall
/-!
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/Hadamard.lean b/Mathlib/Analysis/Complex/Hadamard.lean
index 88d6c801d518c..37d20a8d07540 100644
--- a/Mathlib/Analysis/Complex/Hadamard.lean
+++ b/Mathlib/Analysis/Complex/Hadamard.lean
@@ -189,14 +189,14 @@ lemma F_edge_le_one (f : ℂ → E) (ε : ℝ) (hε : ε > 0) (z : ℂ)
rcases hz with hz0 | hz1
-- `z.re = 0`
· simp only [hz0, zero_sub, Real.rpow_neg_one, neg_zero, Real.rpow_zero, mul_one,
- inv_mul_le_iff (sSupNormIm_eps_pos f hε 0)]
+ inv_mul_le_iff₀ (sSupNormIm_eps_pos f hε 0)]
rw [← hz0]
apply le_of_lt (norm_lt_sSupNormIm_eps f ε hε _ _ hB)
simp only [verticalClosedStrip, mem_preimage, zero_le_one, left_mem_Icc, hz0]
-- `z.re = 1`
· rw [mem_singleton_iff] at hz1
simp only [hz1, one_mul, Real.rpow_zero, sub_self, Real.rpow_neg_one,
- inv_mul_le_iff (sSupNormIm_eps_pos f hε 1), mul_one]
+ inv_mul_le_iff₀ (sSupNormIm_eps_pos f hε 1), mul_one]
rw [← hz1]
apply le_of_lt (norm_lt_sSupNormIm_eps f ε hε _ _ hB)
simp only [verticalClosedStrip, mem_preimage, zero_le_one, hz1, right_mem_Icc]
@@ -304,7 +304,7 @@ lemma norm_le_interpStrip_of_mem_verticalClosedStrip_eps (ε : ℝ) (hε : ε >
‖f z‖ ≤ ‖((ε + sSupNormIm f 0) ^ (1-z) * (ε + sSupNormIm f 1) ^ z : ℂ)‖ := by
simp only [F, abs_invInterpStrip _ _ hε, norm_smul, norm_mul, norm_eq_abs,
← ofReal_add, abs_cpow_eq_rpow_re_of_pos (sSupNormIm_eps_pos f hε _) _, sub_re, one_re]
- rw [← mul_inv_le_iff, ← one_mul (((ε + sSupNormIm f 1) ^ z.re)), ← mul_inv_le_iff',
+ rw [← mul_inv_le_iff₀', ← one_mul (((ε + sSupNormIm f 1) ^ z.re)), ← mul_inv_le_iff₀,
← Real.rpow_neg_one, ← Real.rpow_neg_one]
· simp only [← Real.rpow_mul (le_of_lt (sSupNormIm_eps_pos f hε _)),
mul_neg, mul_one, neg_sub, mul_assoc]
diff --git a/Mathlib/Analysis/Complex/OpenMapping.lean b/Mathlib/Analysis/Complex/OpenMapping.lean
index 9ce4d01945319..b926e8a60be91 100644
--- a/Mathlib/Analysis/Complex/OpenMapping.lean
+++ b/Mathlib/Analysis/Complex/OpenMapping.lean
@@ -27,7 +27,7 @@ That second step is implemented in `DiffContOnCl.ball_subset_image_closedBall`.
* `AnalyticAt.eventually_constant_or_nhds_le_map_nhds` is the local version of the open mapping
theorem around a point;
-* `AnalyticOn.is_constant_or_isOpen` is the open mapping theorem on a connected open set.
+* `AnalyticOnNhd.is_constant_or_isOpen` is the open mapping theorem on a connected open set.
-/
@@ -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`. -/
@@ -51,7 +51,7 @@ theorem DiffContOnCl.ball_subset_image_closedBall (h : DiffContOnCl ℂ f (ball
have h1 : DiffContOnCl ℂ (fun z => f z - v) (ball z₀ r) := h.sub_const v
have h2 : ContinuousOn (fun z => ‖f z - v‖) (closedBall z₀ r) :=
continuous_norm.comp_continuousOn (closure_ball z₀ hr.ne.symm ▸ h1.continuousOn)
- have h3 : AnalyticOn ℂ f (ball z₀ r) := h.differentiableOn.analyticOn isOpen_ball
+ have h3 : AnalyticOnNhd ℂ f (ball z₀ r) := h.differentiableOn.analyticOnNhd isOpen_ball
have h4 : ∀ z ∈ sphere z₀ r, ε / 2 ≤ ‖f z - v‖ := fun z hz => by
linarith [hf z hz, show ‖v - f z₀‖ < ε / 2 from mem_ball.mp hv,
norm_sub_sub_norm_sub_le_norm_sub (f z) v (f z₀)]
@@ -64,7 +64,7 @@ theorem DiffContOnCl.ball_subset_image_closedBall (h : DiffContOnCl ℂ f (ball
have h7 : ∀ᶠ w in 𝓝 z, f w = f z := by filter_upwards [key] with h; field_simp
replace h7 : ∃ᶠ w in 𝓝[≠] z, f w = f z := (h7.filter_mono nhdsWithin_le_nhds).frequently
have h8 : IsPreconnected (ball z₀ r) := (convex_ball z₀ r).isPreconnected
- have h9 := h3.eqOn_of_preconnected_of_frequently_eq analyticOn_const h8 hz1 h7
+ have h9 := h3.eqOn_of_preconnected_of_frequently_eq analyticOnNhd_const h8 hz1 h7
have h10 : f z = f z₀ := (h9 (mem_ball_self hr)).symm
exact not_eventually.mpr hz₀ (mem_of_superset (ball_mem_nhds z₀ hr) (h10 ▸ h9))
@@ -83,7 +83,7 @@ theorem AnalyticAt.eventually_constant_or_nhds_le_map_nhds_aux (hf : AnalyticAt
have h1 := (hf.eventually_eq_or_eventually_ne analyticAt_const).resolve_left h
have h2 : ∀ᶠ z in 𝓝 z₀, AnalyticAt ℂ f z := (isOpen_analyticAt ℂ f).eventually_mem hf
obtain ⟨ρ, hρ, h3, h4⟩ :
- ∃ ρ > 0, AnalyticOn ℂ f (closedBall z₀ ρ) ∧ ∀ z ∈ closedBall z₀ ρ, z ≠ z₀ → f z ≠ f z₀ := by
+ ∃ ρ > 0, AnalyticOnNhd ℂ f (closedBall z₀ ρ) ∧ ∀ z ∈ closedBall z₀ ρ, z ≠ z₀ → f z ≠ f z₀ := by
simpa only [setOf_and, subset_inter_iff] using
nhds_basis_closedBall.mem_iff.mp (h2.and (eventually_nhdsWithin_iff.mp h1))
replace h3 : DiffContOnCl ℂ f (ball z₀ ρ) :=
@@ -118,7 +118,7 @@ theorem AnalyticAt.eventually_constant_or_nhds_le_map_nhds {z₀ : E} (hg : Anal
let ray : E → ℂ → E := fun z t => z₀ + t • z
let gray : E → ℂ → ℂ := fun z => g ∘ ray z
obtain ⟨r, hr, hgr⟩ := isOpen_iff.mp (isOpen_analyticAt ℂ g) z₀ hg
- have h1 : ∀ z ∈ sphere (0 : E) 1, AnalyticOn ℂ (gray z) (ball 0 r) := by
+ have h1 : ∀ z ∈ sphere (0 : E) 1, AnalyticOnNhd ℂ (gray z) (ball 0 r) := by
refine fun z hz t ht => AnalyticAt.comp ?_ ?_
· exact hgr (by simpa [ray, norm_smul, mem_sphere_zero_iff_norm.mp hz] using ht)
· exact analyticAt_const.add
@@ -134,7 +134,7 @@ theorem AnalyticAt.eventually_constant_or_nhds_le_map_nhds {z₀ : E} (hg : Anal
have e1 : IsPreconnected (ball (0 : ℂ) r) := (convex_ball 0 r).isPreconnected
have e2 : w ∈ sphere (0 : E) 1 := by simp [w, norm_smul, inv_mul_cancel₀ h']
specialize h1 w e2
- apply h1.eqOn_of_preconnected_of_eventuallyEq analyticOn_const e1 (mem_ball_self hr)
+ apply h1.eqOn_of_preconnected_of_eventuallyEq analyticOnNhd_const e1 (mem_ball_self hr)
simpa [ray, gray] using h w e2
have h4 : ‖z - z₀‖ < r := by simpa [dist_eq_norm] using mem_ball.mp hz
replace h4 : ↑‖z - z₀‖ ∈ ball (0 : ℂ) r := by
@@ -156,13 +156,16 @@ theorem AnalyticAt.eventually_constant_or_nhds_le_map_nhds {z₀ : E} (hg : Anal
/-- The *open mapping theorem* for holomorphic functions, global version: if a function `g : E → ℂ`
is analytic on a connected set `U`, then either it is constant on `U`, or it is open on `U` (in the
sense that it maps any open set contained in `U` to an open set in `ℂ`). -/
-theorem AnalyticOn.is_constant_or_isOpen (hg : AnalyticOn ℂ g U) (hU : IsPreconnected U) :
+theorem AnalyticOnNhd.is_constant_or_isOpen (hg : AnalyticOnNhd ℂ g U) (hU : IsPreconnected U) :
(∃ w, ∀ z ∈ U, g z = w) ∨ ∀ s ⊆ U, IsOpen s → IsOpen (g '' s) := by
by_cases h : ∃ z₀ ∈ U, ∀ᶠ z in 𝓝 z₀, g z = g z₀
· obtain ⟨z₀, hz₀, h⟩ := h
- exact Or.inl ⟨g z₀, hg.eqOn_of_preconnected_of_eventuallyEq analyticOn_const hU hz₀ h⟩
+ exact Or.inl ⟨g z₀, hg.eqOn_of_preconnected_of_eventuallyEq analyticOnNhd_const hU hz₀ h⟩
· push_neg at h
refine Or.inr fun s hs1 hs2 => isOpen_iff_mem_nhds.mpr ?_
rintro z ⟨w, hw1, rfl⟩
exact (hg w (hs1 hw1)).eventually_constant_or_nhds_le_map_nhds.resolve_left (h w (hs1 hw1))
(image_mem_map (hs2.mem_nhds hw1))
+
+@[deprecated (since := "2024-09-26")]
+alias AnalyticOn.is_constant_or_isOpen := AnalyticOnNhd.is_constant_or_isOpen
diff --git a/Mathlib/Analysis/Complex/PhragmenLindelof.lean b/Mathlib/Analysis/Complex/PhragmenLindelof.lean
index e172dd9cfe031..a457d182cf842 100644
--- a/Mathlib/Analysis/Complex/PhragmenLindelof.lean
+++ b/Mathlib/Analysis/Complex/PhragmenLindelof.lean
@@ -133,7 +133,7 @@ theorem horizontal_strip (hfd : DiffContOnCl ℂ f (im ⁻¹' Ioo a b))
rcases hB with ⟨c, hc, B, hO⟩
obtain ⟨d, ⟨hcd, hd₀⟩, hd⟩ : ∃ d, (c < d ∧ 0 < d) ∧ d < π / 2 / b := by
simpa only [max_lt_iff] using exists_between (max_lt hc hπb)
- have hb' : d * b < π / 2 := (lt_div_iff hb).1 hd
+ have hb' : d * b < π / 2 := (lt_div_iff₀ hb).1 hd
set aff := (fun w => d * (w - a * I) : ℂ → ℂ)
set g := fun (ε : ℝ) (w : ℂ) => exp (ε * (exp (aff w) + exp (-aff w)))
/- Since `g ε z → 1` as `ε → 0⁻`, it suffices to prove that `‖g ε z • f z‖ ≤ C`
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 6afa53eec6ef1..303996fd5e2dd 100644
--- a/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean
+++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean
@@ -3,13 +3,9 @@ Copyright (c) 2021 Alex Kontorovich and Heather Macbeth and Marc Masdeu. All rig
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Alex Kontorovich, Heather Macbeth, Marc Masdeu
-/
-import Mathlib.Algebra.GroupWithZero.Action.Defs
import Mathlib.Analysis.Complex.Basic
import Mathlib.Data.Fintype.Parity
import Mathlib.LinearAlgebra.Matrix.GeneralLinearGroup.Defs
-import Mathlib.LinearAlgebra.Matrix.SpecialLinearGroup
-import Mathlib.Tactic.AdaptationNote
-import Mathlib.Tactic.LinearCombination
/-!
# The upper half plane and its automorphisms
@@ -182,7 +178,7 @@ theorem linear_ne_zero (cd : Fin 2 → ℝ) (z : ℍ) (h : cd ≠ 0) : (cd 0 :
have : cd 0 = 0 := by
-- we will need this twice
apply_fun Complex.im at h
- simpa only [z.im_ne_zero, Complex.add_im, add_zero, coe_im, zero_mul, or_false_iff,
+ simpa only [z.im_ne_zero, Complex.add_im, add_zero, coe_im, zero_mul, or_false,
Complex.ofReal_im, Complex.zero_im, Complex.mul_im, mul_eq_zero] using h
simp only [this, zero_mul, Complex.ofReal_zero, zero_add, Complex.ofReal_eq_zero]
at h
@@ -404,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 dec00ac0e5457..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
@@ -261,7 +261,7 @@ instance : MetricSpace ℍ :=
have h₀ : 0 < R / im z + 1 := one_pos.trans h₁
refine ⟨log (R / im z + 1), Real.log_pos h₁, ?_⟩
refine fun w hw => (dist_coe_le w z).trans_lt ?_
- rwa [← lt_div_iff' z.im_pos, sub_lt_iff_lt_add, ← Real.lt_log_iff_exp_lt h₀]
+ rwa [← lt_div_iff₀' z.im_pos, sub_lt_iff_lt_add, ← Real.lt_log_iff_exp_lt h₀]
theorem im_pos_of_dist_center_le {z : ℍ} {r : ℝ} {w : ℂ}
(h : dist w (center z r) ≤ z.im * Real.sinh r) : 0 < w.im :=
@@ -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
@@ -327,7 +327,7 @@ instance : IsometricSMul SL(2, ℝ) ℍ :=
have h₂ : Complex.abs (y₁ * y₂) ≠ 0 := by simp [y₁.ne_zero, y₂.ne_zero]
simp only [dist_eq, modular_S_smul, inv_neg, neg_div, div_mul_div_comm, coe_mk, mk_im,
div_one, Complex.inv_im, Complex.neg_im, coe_im, neg_neg, Complex.normSq_neg,
- mul_eq_mul_left_iff, Real.arsinh_inj, one_ne_zero, or_false_iff,
+ mul_eq_mul_left_iff, Real.arsinh_inj, one_ne_zero,
dist_neg_neg, mul_neg, neg_mul, dist_inv_inv₀ y₁.ne_zero y₂.ne_zero, ←
AbsoluteValue.map_mul, ← Complex.normSq_mul, Real.sqrt_div h₁, ← Complex.abs_apply,
mul_div (2 : ℝ), div_div_div_comm, div_self h₂, Complex.norm_eq_abs]
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 f07e88d57f245..4f249aa4e3023 100644
--- a/Mathlib/Analysis/Convex/Basic.lean
+++ b/Mathlib/Analysis/Convex/Basic.lean
@@ -8,6 +8,8 @@ import Mathlib.Algebra.Order.Module.OrderedSMul
import Mathlib.Algebra.Order.Module.Synonym
import Mathlib.Analysis.Convex.Star
import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace
+import Mathlib.Tactic.FieldSimp
+import Mathlib.Tactic.NoncommRing
/-!
# Convex sets and functions in vector spaces
@@ -74,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
@@ -158,8 +160,7 @@ theorem convex_segment (x y : E) : Convex 𝕜 [x -[𝕜] y] := by
⟨a * ap + b * aq, a * bp + b * bq, add_nonneg (mul_nonneg ha hap) (mul_nonneg hb haq),
add_nonneg (mul_nonneg ha hbp) (mul_nonneg hb hbq), ?_, ?_⟩
· rw [add_add_add_comm, ← mul_add, ← mul_add, habp, habq, mul_one, mul_one, hab]
- · simp_rw [add_smul, mul_smul, smul_add]
- exact add_add_add_comm _ _ _ _
+ · match_scalars <;> noncomm_ring
theorem Convex.linear_image (hs : Convex 𝕜 s) (f : E →ₗ[𝕜] F) : Convex 𝕜 (f '' s) := by
rintro _ ⟨x, hx, rfl⟩ _ ⟨y, hy, rfl⟩ a b ha hb hab
@@ -406,8 +407,8 @@ theorem convex_openSegment (a b : E) : Convex 𝕜 (openSegment 𝕜 a b) := by
rw [convex_iff_openSegment_subset]
rintro p ⟨ap, bp, hap, hbp, habp, rfl⟩ q ⟨aq, bq, haq, hbq, habq, rfl⟩ z ⟨a, b, ha, hb, hab, rfl⟩
refine ⟨a * ap + b * aq, a * bp + b * bq, by positivity, by positivity, ?_, ?_⟩
- · rw [add_add_add_comm, ← mul_add, ← mul_add, habp, habq, mul_one, mul_one, hab]
- · simp_rw [add_smul, mul_smul, smul_add, add_add_add_comm]
+ · linear_combination (norm := noncomm_ring) a * habp + b * habq + hab
+ · module
end StrictOrderedCommSemiring
@@ -425,8 +426,7 @@ theorem convex_vadd (a : E) : Convex 𝕜 (a +ᵥ s) ↔ Convex 𝕜 s :=
theorem Convex.add_smul_mem (hs : Convex 𝕜 s) {x y : E} (hx : x ∈ s) (hy : x + y ∈ s) {t : 𝕜}
(ht : t ∈ Icc (0 : 𝕜) 1) : x + t • y ∈ s := by
- have h : x + t • y = (1 - t) • x + t • (x + y) := by
- rw [smul_add, ← add_assoc, ← add_smul, sub_add_cancel, one_smul]
+ have h : x + t • y = (1 - t) • x + t • (x + y) := by match_scalars <;> noncomm_ring
rw [h]
exact hs hx hy (sub_nonneg_of_le ht.2) ht.1 (sub_add_cancel _ _)
@@ -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
@@ -515,7 +516,7 @@ theorem Convex.exists_mem_add_smul_eq (h : Convex 𝕜 s) {x y : E} {p q : 𝕜}
· replace hpq : 0 < p + q :=
(add_nonneg hp hq).lt_of_ne' (mt (add_eq_zero_iff_of_nonneg hp hq).1 hpq)
refine ⟨_, convex_iff_div.1 h hx hy hp hq hpq, ?_⟩
- simp only [smul_add, smul_smul, mul_div_cancel₀ _ hpq.ne']
+ match_scalars <;> field_simp
theorem Convex.add_smul (h_conv : Convex 𝕜 s) {p q : 𝕜} (hp : 0 ≤ p) (hq : 0 ≤ q) :
(p + q) • s = p • s + q • s := (add_smul_subset _ _ _).antisymm <| by
@@ -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 ccbae3b13d6c8..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
@@ -392,7 +401,7 @@ theorem sbtw_one_zero_iff {x : R} : Sbtw R 1 x 0 ↔ x ∈ Set.Ioo (0 : R) 1 :=
theorem Wbtw.trans_left {w x y z : P} (h₁ : Wbtw R w y z) (h₂ : Wbtw R w x y) : Wbtw R w x z := by
rcases h₁ with ⟨t₁, ht₁, rfl⟩
rcases h₂ with ⟨t₂, ht₂, rfl⟩
- refine ⟨t₂ * t₁, ⟨mul_nonneg ht₂.1 ht₁.1, mul_le_one ht₂.2 ht₁.1 ht₁.2⟩, ?_⟩
+ refine ⟨t₂ * t₁, ⟨mul_nonneg ht₂.1 ht₁.1, mul_le_one₀ ht₂.2 ht₁.1 ht₁.2⟩, ?_⟩
rw [lineMap_apply, lineMap_apply, lineMap_vsub_left, smul_smul]
theorem Wbtw.trans_right {w x y z : P} (h₁ : Wbtw R w x z) (h₂ : Wbtw R x y z) : Wbtw R w y z := by
@@ -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,9 +662,15 @@ 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₂)⟩, ?_⟩
+ refine ⟨r₁ / r₂, ⟨div_nonneg hr₁ (hr₁.trans hr₂), div_le_one_of_le₀ hr₂ (hr₁.trans hr₂)⟩, ?_⟩
by_cases h : r₁ = 0; · simp [h]
simp [lineMap_apply, smul_smul, ((hr₁.lt_of_ne' h).trans_le hr₂).ne.symm]
@@ -695,8 +710,8 @@ theorem Wbtw.trans_left_right {w x y z : P} (h₁ : Wbtw R w y z) (h₂ : Wbtw R
refine
⟨(t₁ - t₂ * t₁) / (1 - t₂ * t₁),
⟨div_nonneg (sub_nonneg.2 (mul_le_of_le_one_left ht₁.1 ht₂.2))
- (sub_nonneg.2 (mul_le_one ht₂.2 ht₁.1 ht₁.2)),
- div_le_one_of_le (sub_le_sub_right ht₁.2 _) (sub_nonneg.2 (mul_le_one ht₂.2 ht₁.1 ht₁.2))⟩,
+ (sub_nonneg.2 (mul_le_one₀ ht₂.2 ht₁.1 ht₁.2)), div_le_one_of_le₀
+ (sub_le_sub_right ht₁.2 _) (sub_nonneg.2 (mul_le_one₀ ht₂.2 ht₁.1 ht₁.2))⟩,
?_⟩
simp only [lineMap_apply, smul_smul, ← add_vadd, vsub_vadd_eq_vsub_sub, smul_sub, ← sub_smul,
← add_smul, vadd_vsub, vadd_right_cancel_iff, div_mul_eq_mul_div, div_sub_div_same]
@@ -772,7 +787,7 @@ theorem wbtw_iff_sameRay_vsub {x y z : P} : Wbtw R x y z ↔ SameRay R (y -ᵥ x
· refine
⟨r₂ / (r₁ + r₂),
⟨div_nonneg hr₂.le (add_nonneg hr₁.le hr₂.le),
- div_le_one_of_le (le_add_of_nonneg_left hr₁.le) (add_nonneg hr₁.le hr₂.le)⟩,
+ div_le_one_of_le₀ (le_add_of_nonneg_left hr₁.le) (add_nonneg hr₁.le hr₂.le)⟩,
?_⟩
have h' : z = r₂⁻¹ • r₁ • (y -ᵥ x) +ᵥ y := by simp [h, hr₂.ne']
rw [eq_comm]
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 ab8c493ff10c3..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 :=
@@ -212,7 +212,7 @@ theorem iInter_smul_eq_self [T2Space V] {u : ℕ → ℝ≥0} (K : ConvexBody V)
rw [show (1 + u n : ℝ) • y - y = (u n : ℝ) • y by rw [add_smul, one_smul, add_sub_cancel_left],
norm_smul, Real.norm_eq_abs]
specialize hn n le_rfl
- rw [_root_.lt_div_iff' hC_pos, mul_comm, NNReal.coe_zero, sub_zero, Real.norm_eq_abs] at hn
+ rw [lt_div_iff₀' hC_pos, mul_comm, NNReal.coe_zero, sub_zero, Real.norm_eq_abs] at hn
refine lt_of_le_of_lt ?_ hn
exact mul_le_mul_of_nonneg_left (hC_bdd _ hyK) (abs_nonneg _)
· refine Set.mem_iInter.mpr (fun n => Convex.mem_smul_of_zero_mem K.convex h_zero h ?_)
diff --git a/Mathlib/Analysis/Convex/Caratheodory.lean b/Mathlib/Analysis/Convex/Caratheodory.lean
index 75f0b5f68dfeb..59b4f09c6a3ec 100644
--- a/Mathlib/Analysis/Convex/Caratheodory.lean
+++ b/Mathlib/Analysis/Convex/Caratheodory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison
+Authors: Johan Commelin, Kim Morrison
-/
import Mathlib.Analysis.Convex.Combination
import Mathlib.LinearAlgebra.AffineSpace.Independent
@@ -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
@@ -85,7 +85,7 @@ theorem mem_convexHull_erase [DecidableEq E] {t : Finset E} (h : ¬AffineIndepen
_ ≤ 0 := by
apply mul_nonpos_of_nonneg_of_nonpos
· apply div_nonneg (fpos i₀ (mem_of_subset (filter_subset _ t) mem)) (le_of_lt hg)
- · simpa only [s, mem_filter, het, true_and_iff, not_lt] using hes
+ · simpa only [s, mem_filter, het, true_and, not_lt] using hes
_ ≤ f e := fpos e het
· rw [Subtype.coe_mk, centerMass_eq_of_sum_1 _ id ksum]
calc
@@ -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 b851e544f9998..6fe599b4f51f7 100644
--- a/Mathlib/Analysis/Convex/Combination.lean
+++ b/Mathlib/Analysis/Convex/Combination.lean
@@ -50,7 +50,8 @@ theorem Finset.centerMass_empty : (∅ : Finset ι).centerMass w z = 0 := by
theorem Finset.centerMass_pair (hne : i ≠ j) :
({i, j} : Finset ι).centerMass w z = (w i / (w i + w j)) • z i + (w j / (w i + w j)) • z j := by
- simp only [centerMass, sum_pair hne, smul_add, (mul_smul _ _ _).symm, div_eq_inv_mul]
+ simp only [centerMass, sum_pair hne]
+ module
variable {w}
@@ -63,7 +64,9 @@ theorem Finset.centerMass_insert (ha : i ∉ t) (hw : ∑ j ∈ t, w j ≠ 0) :
rw [div_mul_eq_mul_div, mul_inv_cancel₀ hw, one_div]
theorem Finset.centerMass_singleton (hw : w i ≠ 0) : ({i} : Finset ι).centerMass w z = z i := by
- rw [centerMass, sum_singleton, sum_singleton, ← mul_smul, inv_mul_cancel₀ hw, one_smul]
+ rw [centerMass, sum_singleton, sum_singleton]
+ match_scalars
+ field_simp
@[simp] lemma Finset.centerMass_neg_left : t.centerMass (-w) z = t.centerMass w z := by
simp [centerMass, inv_neg]
@@ -121,10 +124,9 @@ 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_iff, Ne, Classical.not_not] using hit'
+ simpa only [hit, mem_filter, true_and, Ne, Classical.not_not] using hit'
namespace Finset
@@ -261,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]
@@ -387,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 63d49213b6aba..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 -/
@@ -147,6 +145,7 @@ section CompleteSpace
variable [CompleteSpace H]
+open scoped InnerProductSpace in
/-- This is a stronger version of the Hahn-Banach separation theorem for closed convex cones. This
is also the geometric interpretation of Farkas' lemma. -/
theorem ConvexCone.hyperplane_separation_of_nonempty_of_isClosed_of_nmem (K : ConvexCone ℝ H)
diff --git a/Mathlib/Analysis/Convex/Cone/Pointed.lean b/Mathlib/Analysis/Convex/Cone/Pointed.lean
index 80484baf0da84..b8353729d6675 100644
--- a/Mathlib/Analysis/Convex/Cone/Pointed.lean
+++ b/Mathlib/Analysis/Convex/Cone/Pointed.lean
@@ -186,6 +186,7 @@ def dual (S : PointedCone ℝ E) : PointedCone ℝ E :=
theorem toConvexCone_dual (S : PointedCone ℝ E) : ↑(dual S) = (S : Set E).innerDualCone :=
rfl
+open scoped InnerProductSpace in
@[simp]
theorem mem_dual {S : PointedCone ℝ E} {y : E} : y ∈ dual S ↔ ∀ ⦃x⦄, x ∈ S → 0 ≤ ⟪x, y⟫_ℝ := by
rfl
diff --git a/Mathlib/Analysis/Convex/Cone/Proper.lean b/Mathlib/Analysis/Convex/Cone/Proper.lean
index fe4f8e9acd54a..a2ebcdc0f1ef2 100644
--- a/Mathlib/Analysis/Convex/Cone/Proper.lean
+++ b/Mathlib/Analysis/Convex/Cone/Proper.lean
@@ -170,6 +170,7 @@ def dual (K : ProperCone ℝ E) : ProperCone ℝ E where
theorem coe_dual (K : ProperCone ℝ E) : K.dual = (K : Set E).innerDualCone :=
rfl
+open scoped InnerProductSpace in
@[simp]
theorem mem_dual {K : ProperCone ℝ E} {y : E} : y ∈ dual K ↔ ∀ ⦃x⦄, x ∈ K → 0 ≤ ⟪x, y⟫_ℝ := by
aesop
@@ -201,6 +202,8 @@ end InnerProductSpace
section CompleteSpace
+open scoped InnerProductSpace
+
variable {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℝ E] [CompleteSpace E]
variable {F : Type*} [NormedAddCommGroup F] [InnerProductSpace ℝ F] [CompleteSpace F]
diff --git a/Mathlib/Analysis/Convex/Continuous.lean b/Mathlib/Analysis/Convex/Continuous.lean
new file mode 100644
index 0000000000000..4b2ebd632b395
--- /dev/null
+++ b/Mathlib/Analysis/Convex/Continuous.lean
@@ -0,0 +1,232 @@
+/-
+Copyright (c) 2023 Yaël Dillies, Zichen Wang. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Yaël Dillies, Zichen Wang
+-/
+import Mathlib.Analysis.Convex.Normed
+
+/-!
+# Convex functions are continuous
+
+This file proves that a convex function from a finite dimensional real normed space to `ℝ` is
+continuous.
+-/
+
+open FiniteDimensional Metric Set List Bornology
+open scoped Topology
+
+variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
+ {C : Set E} {f : E → ℝ} {x₀ : E} {ε r r' M : ℝ}
+
+lemma ConvexOn.lipschitzOnWith_of_abs_le (hf : ConvexOn ℝ (ball x₀ r) f) (hε : 0 < ε)
+ (hM : ∀ a, dist a x₀ < r → |f a| ≤ M) :
+ LipschitzOnWith (2 * M / ε).toNNReal f (ball x₀ (r - ε)) := by
+ set K := 2 * M / ε with hK
+ have oneside {x y : E} (hx : x ∈ ball x₀ (r - ε)) (hy : y ∈ ball x₀ (r - ε)) :
+ f x - f y ≤ K * ‖x - y‖ := by
+ obtain rfl | hxy := eq_or_ne x y
+ · simp
+ have hx₀r : ball x₀ (r - ε) ⊆ ball x₀ r := ball_subset_ball <| by linarith
+ have hx' : x ∈ ball x₀ r := hx₀r hx
+ have hy' : y ∈ ball x₀ r := hx₀r hy
+ let z := x + (ε / ‖x - y‖) • (x - y)
+ replace hxy : 0 < ‖x - y‖ := by rwa [norm_sub_pos_iff]
+ have hz : z ∈ ball x₀ r := mem_ball_iff_norm.2 <| by
+ calc
+ _ = ‖(x - x₀) + (ε / ‖x - y‖) • (x - y)‖ := by simp only [z, add_sub_right_comm]
+ _ ≤ ‖x - x₀‖ + ‖(ε / ‖x - y‖) • (x - y)‖ := norm_add_le ..
+ _ < r - ε + ε :=
+ add_lt_add_of_lt_of_le (mem_ball_iff_norm.1 hx) <| by
+ simp [norm_smul, abs_of_nonneg, hε.le, hxy.ne']
+ _ = r := by simp
+ let a := ε / (ε + ‖x - y‖)
+ let b := ‖x - y‖ / (ε + ‖x - y‖)
+ have hab : a + b = 1 := by field_simp [a, b]
+ have hxyz : x = a • y + b • z := by
+ calc
+ x = a • x + b • x := by rw [Convex.combo_self hab]
+ _ = a • y + b • z := by simp [z, a, b, smul_smul, hxy.ne', smul_sub]; abel
+ rw [hK, mul_comm, ← mul_div_assoc, le_div_iff₀' hε]
+ calc
+ ε * (f x - f y) ≤ ‖x - y‖ * (f z - f x) := by
+ rw [mul_sub, mul_sub, sub_le_sub_iff, ← add_mul]
+ have h := hf.2 hy' hz (by positivity) (by positivity) hab
+ field_simp [← hxyz, a, b, ← mul_div_right_comm] at h
+ rwa [← le_div_iff₀' (by positivity), add_comm (_ * _)]
+ _ ≤ _ := by
+ rw [sub_eq_add_neg (f _), two_mul]
+ gcongr
+ · exact (le_abs_self _).trans <| hM _ hz
+ · exact (neg_le_abs _).trans <| hM _ hx'
+ refine .of_dist_le' fun x hx y hy ↦ ?_
+ simp_rw [dist_eq_norm_sub, Real.norm_eq_abs, abs_sub_le_iff]
+ exact ⟨oneside hx hy, norm_sub_rev x _ ▸ oneside hy hx⟩
+
+lemma ConcaveOn.lipschitzOnWith_of_abs_le (hf : ConcaveOn ℝ (ball x₀ r) f) (hε : 0 < ε)
+ (hM : ∀ a, dist a x₀ < r → |f a| ≤ M) :
+ LipschitzOnWith (2 * M / ε).toNNReal f (ball x₀ (r - ε)) := by
+ simpa using hf.neg.lipschitzOnWith_of_abs_le hε <| by simpa using hM
+
+lemma ConvexOn.exists_lipschitzOnWith_of_isBounded (hf : ConvexOn ℝ (ball x₀ r) f) (hr : r' < r)
+ (hf' : IsBounded (f '' ball x₀ r)) : ∃ K, LipschitzOnWith K f (ball x₀ r') := by
+ rw [isBounded_iff_subset_ball 0] at hf'
+ simp only [Set.subset_def, mem_image, mem_ball, dist_zero_right, Real.norm_eq_abs,
+ forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] at hf'
+ obtain ⟨M, hM⟩ := hf'
+ rw [← sub_sub_cancel r r']
+ exact ⟨_, hf.lipschitzOnWith_of_abs_le (sub_pos.2 hr) fun a ha ↦ (hM a ha).le⟩
+
+lemma ConcaveOn.exists_lipschitzOnWith_of_isBounded (hf : ConcaveOn ℝ (ball x₀ r) f) (hr : r' < r)
+ (hf' : IsBounded (f '' ball x₀ r)) : ∃ K, LipschitzOnWith K f (ball x₀ r') := by
+ replace hf' : IsBounded ((-f) '' ball x₀ r) := by convert hf'.neg; ext; simp [neg_eq_iff_eq_neg]
+ simpa using hf.neg.exists_lipschitzOnWith_of_isBounded hr hf'
+
+lemma ConvexOn.isBoundedUnder_abs (hf : ConvexOn ℝ C f) {x₀ : E} (hC : C ∈ 𝓝 x₀) :
+ (𝓝 x₀).IsBoundedUnder (· ≤ ·) |f| ↔ (𝓝 x₀).IsBoundedUnder (· ≤ ·) f := by
+ refine ⟨fun h ↦ h.mono_le <| .of_forall fun x ↦ le_abs_self _, ?_⟩
+ rintro ⟨r, hr⟩
+ refine ⟨|r| + 2 * |f x₀|, ?_⟩
+ have : (𝓝 x₀).Tendsto (fun y => 2 • x₀ - y) (𝓝 x₀) :=
+ tendsto_nhds_nhds.2 (⟨·, ·, by simp [two_nsmul, dist_comm]⟩)
+ simp only [Filter.eventually_map, Pi.abs_apply, abs_le'] at hr ⊢
+ filter_upwards [this.eventually_mem hC, hC, hr, this.eventually hr] with y hx hx' hfr hfr'
+ refine ⟨hfr.trans <| (le_abs_self _).trans <| by simp, ?_⟩
+ rw [← sub_le_iff_le_add, neg_sub_comm, sub_le_iff_le_add', ← abs_two, ← abs_mul]
+ calc
+ -|2 * f x₀| ≤ 2 * f x₀ := neg_abs_le _
+ _ ≤ f y + f (2 • x₀ - y) := by
+ have := hf.2 hx' hx (by positivity) (by positivity) (add_halves _)
+ simp only [one_div, ← Nat.cast_smul_eq_nsmul ℝ, Nat.cast_ofNat, smul_sub, ne_eq,
+ OfNat.ofNat_ne_zero, not_false_eq_true, inv_smul_smul₀, add_sub_cancel, smul_eq_mul] at this
+ cancel_denoms at this
+ rwa [← Nat.cast_two, Nat.cast_smul_eq_nsmul] at this
+ _ ≤ f y + |r| := by gcongr; exact hfr'.trans (le_abs_self _)
+
+lemma ConcaveOn.isBoundedUnder_abs (hf : ConcaveOn ℝ C f) {x₀ : E} (hC : C ∈ 𝓝 x₀) :
+ (𝓝 x₀).IsBoundedUnder (· ≤ ·) |f| ↔ (𝓝 x₀).IsBoundedUnder (· ≥ ·) f := by
+ simpa [Pi.neg_def, Pi.abs_def] using hf.neg.isBoundedUnder_abs hC
+
+lemma ConvexOn.continuousOn_tfae (hC : IsOpen C) (hC' : C.Nonempty) (hf : ConvexOn ℝ C f) : TFAE [
+ LocallyLipschitzOn C f,
+ ContinuousOn f C,
+ ∃ x₀ ∈ C, ContinuousAt f x₀,
+ ∃ x₀ ∈ C, (𝓝 x₀).IsBoundedUnder (· ≤ ·) f,
+ ∀ ⦃x₀⦄, x₀ ∈ C → (𝓝 x₀).IsBoundedUnder (· ≤ ·) f,
+ ∀ ⦃x₀⦄, x₀ ∈ C → (𝓝 x₀).IsBoundedUnder (· ≤ ·) |f|] := by
+ tfae_have 1 → 2
+ · exact LocallyLipschitzOn.continuousOn
+ tfae_have 2 → 3
+ · obtain ⟨x₀, hx₀⟩ := hC'
+ exact fun h ↦ ⟨x₀, hx₀, h.continuousAt <| hC.mem_nhds hx₀⟩
+ tfae_have 3 → 4
+ · rintro ⟨x₀, hx₀, h⟩
+ exact ⟨x₀, hx₀, f x₀ + 1, by simpa using h.eventually (eventually_le_nhds (by simp))⟩
+ tfae_have 4 → 5
+ · rintro ⟨x₀, hx₀, r, hr⟩ x hx
+ have : ∀ᶠ δ in 𝓝 (0 : ℝ), (1 - δ)⁻¹ • x - (δ / (1 - δ)) • x₀ ∈ C := by
+ have h : ContinuousAt (fun δ : ℝ ↦ (1 - δ)⁻¹ • x - (δ / (1 - δ)) • x₀) 0 := by
+ fun_prop (disch := norm_num)
+ exact h (by simpa using hC.mem_nhds hx)
+ obtain ⟨δ, hδ₀, hy, hδ₁⟩ := (this.and <| eventually_lt_nhds zero_lt_one).exists_gt
+ set y := (1 - δ)⁻¹ • x - (δ / (1 - δ)) • x₀
+ refine ⟨max r (f y), ?_⟩
+ simp only [Filter.eventually_map, Pi.abs_apply] at hr ⊢
+ obtain ⟨ε, hε, hr⟩ := Metric.eventually_nhds_iff.1 <| hr.and (hC.eventually_mem hx₀)
+ refine Metric.eventually_nhds_iff.2 ⟨ε * δ, by positivity, fun z hz ↦ ?_⟩
+ have hx₀' : δ⁻¹ • (x - y) + y = x₀ := MulAction.injective₀ (sub_ne_zero.2 hδ₁.ne') <| by
+ simp [y, smul_sub, smul_smul, hδ₀.ne', div_eq_mul_inv, sub_ne_zero.2 hδ₁.ne', mul_left_comm,
+ sub_mul, sub_smul]
+ let w := δ⁻¹ • (z - y) + y
+ have hwyz : δ • w + (1 - δ) • y = z := by simp [w, hδ₀.ne', sub_smul]
+ have hw : dist w x₀ < ε := by
+ simpa [w, ← hx₀', dist_smul₀, abs_of_nonneg, hδ₀.le, inv_mul_lt_iff₀', hδ₀]
+ calc
+ f z ≤ max (f w) (f y) :=
+ hf.le_max_of_mem_segment (hr hw).2 hy ⟨_, _, hδ₀.le, sub_nonneg.2 hδ₁.le, by simp, hwyz⟩
+ _ ≤ max r (f y) := by gcongr; exact (hr hw).1
+ tfae_have 6 ↔ 5
+ · exact forall₂_congr fun x₀ hx₀ ↦ hf.isBoundedUnder_abs (hC.mem_nhds hx₀)
+ tfae_have 6 → 1
+ · rintro h x hx
+ obtain ⟨r, hr⟩ := h hx
+ obtain ⟨ε, hε, hεD⟩ := Metric.mem_nhds_iff.1 <| Filter.inter_mem (hC.mem_nhds hx) hr
+ simp only [preimage_setOf_eq, Pi.abs_apply, subset_inter_iff, hC.nhdsWithin_eq hx] at hεD ⊢
+ obtain ⟨K, hK⟩ := exists_lipschitzOnWith_of_isBounded (hf.subset hεD.1 (convex_ball ..))
+ (half_lt_self hε) <| isBounded_iff_forall_norm_le.2 ⟨r, by simpa using hεD.2⟩
+ exact ⟨K, _, ball_mem_nhds _ (by simpa), hK⟩
+ tfae_finish
+
+lemma ConcaveOn.continuousOn_tfae (hC : IsOpen C) (hC' : C.Nonempty) (hf : ConcaveOn ℝ C f) : TFAE [
+ LocallyLipschitzOn C f,
+ ContinuousOn f C,
+ ∃ x₀ ∈ C, ContinuousAt f x₀,
+ ∃ x₀ ∈ C, (𝓝 x₀).IsBoundedUnder (· ≥ ·) f,
+ ∀ ⦃x₀⦄, x₀ ∈ C → (𝓝 x₀).IsBoundedUnder (· ≥ ·) f,
+ ∀ ⦃x₀⦄, x₀ ∈ C → (𝓝 x₀).IsBoundedUnder (· ≤ ·) |f|] := by
+ have := hf.neg.continuousOn_tfae hC hC'
+ simp at this
+ convert this using 8 <;> exact (Equiv.neg ℝ).exists_congr (by simp)
+
+lemma ConvexOn.locallyLipschitzOn_iff_continuousOn (hC : IsOpen C) (hf : ConvexOn ℝ C f) :
+ LocallyLipschitzOn C f ↔ ContinuousOn f C := by
+ obtain rfl | hC' := C.eq_empty_or_nonempty
+ · simp
+ · exact (hf.continuousOn_tfae hC hC').out 0 1
+
+lemma ConcaveOn.locallyLipschitzOn_iff_continuousOn (hC : IsOpen C) (hf : ConcaveOn ℝ C f) :
+ LocallyLipschitzOn C f ↔ ContinuousOn f C := by
+ simpa using hf.neg.locallyLipschitzOn_iff_continuousOn hC
+
+variable [FiniteDimensional ℝ E]
+
+protected lemma ConvexOn.locallyLipschitzOn (hC : IsOpen C) (hf : ConvexOn ℝ C f) :
+ LocallyLipschitzOn C f := by
+ obtain rfl | ⟨x₀, hx₀⟩ := C.eq_empty_or_nonempty
+ · simp
+ · obtain ⟨b, hx₀b, hbC⟩ := exists_mem_interior_convexHull_affineBasis (hC.mem_nhds hx₀)
+ refine ((hf.continuousOn_tfae hC ⟨x₀, hx₀⟩).out 3 0).mp ?_
+ refine ⟨x₀, hx₀, BddAbove.isBoundedUnder (IsOpen.mem_nhds isOpen_interior hx₀b) ?_⟩
+ exact (hf.bddAbove_convexHull ((subset_convexHull ..).trans hbC)
+ ((finite_range _).image _).bddAbove).mono (by gcongr; exact interior_subset)
+
+protected lemma ConcaveOn.locallyLipschitzOn (hC : IsOpen C) (hf : ConcaveOn ℝ C f) :
+ LocallyLipschitzOn C f := by simpa using hf.neg.locallyLipschitzOn hC
+
+protected lemma ConvexOn.continuousOn (hC : IsOpen C) (hf : ConvexOn ℝ C f) :
+ ContinuousOn f C := (hf.locallyLipschitzOn hC).continuousOn
+
+protected lemma ConcaveOn.continuousOn (hC : IsOpen C) (hf : ConcaveOn ℝ C f) :
+ ContinuousOn f C := (hf.locallyLipschitzOn hC).continuousOn
+
+lemma ConvexOn.locallyLipschitzOn_interior (hf : ConvexOn ℝ C f) :
+ LocallyLipschitzOn (interior C) f :=
+ (hf.subset interior_subset hf.1.interior).locallyLipschitzOn isOpen_interior
+
+lemma ConcaveOn.locallyLipschitzOn_interior (hf : ConcaveOn ℝ C f) :
+ LocallyLipschitzOn (interior C) f :=
+ (hf.subset interior_subset hf.1.interior).locallyLipschitzOn isOpen_interior
+
+lemma ConvexOn.continuousOn_interior (hf : ConvexOn ℝ C f) : ContinuousOn f (interior C) :=
+ hf.locallyLipschitzOn_interior.continuousOn
+
+lemma ConcaveOn.continuousOn_interior (hf : ConcaveOn ℝ C f) : ContinuousOn f (interior C) :=
+ hf.locallyLipschitzOn_interior.continuousOn
+
+protected lemma ConvexOn.locallyLipschitz (hf : ConvexOn ℝ univ f) : LocallyLipschitz f := by
+ simpa using hf.locallyLipschitzOn_interior
+
+protected lemma ConcaveOn.locallyLipschitz (hf : ConcaveOn ℝ univ f) : LocallyLipschitz f := by
+ simpa using hf.locallyLipschitzOn_interior
+
+-- Commented out since `intrinsicInterior` is not imported (but should be once these are proved)
+-- proof_wanted ConvexOn.locallyLipschitzOn_intrinsicInterior (hf : ConvexOn ℝ C f) :
+-- ContinuousOn f (intrinsicInterior ℝ C)
+
+-- proof_wanted ConcaveOn.locallyLipschitzOn_intrinsicInterior (hf : ConcaveOn ℝ C f) :
+-- ContinuousOn f (intrinsicInterior ℝ C)
+
+-- proof_wanted ConvexOn.continuousOn_intrinsicInterior (hf : ConvexOn ℝ C f) :
+-- ContinuousOn f (intrinsicInterior ℝ C)
+
+-- proof_wanted ConcaveOn.continuousOn_intrinsicInterior (hf : ConcaveOn ℝ C f) :
+-- ContinuousOn f (intrinsicInterior ℝ C)
diff --git a/Mathlib/Analysis/Convex/Deriv.lean b/Mathlib/Analysis/Convex/Deriv.lean
index 6954ba6c48f2b..4d71b529373a4 100644
--- a/Mathlib/Analysis/Convex/Deriv.lean
+++ b/Mathlib/Analysis/Convex/Deriv.lean
@@ -95,7 +95,7 @@ theorem StrictMonoOn.exists_slope_lt_deriv {x y : ℝ} {f : ℝ → ℝ} (hf : C
apply ne_of_gt
exact hf'_mono ⟨hxw, hwy⟩ ⟨hxw.trans hz.1, hz.2⟩ hz.1
refine ⟨b, ⟨hxw.trans hwb, hby⟩, ?_⟩
- simp only [div_lt_iff, hxy, hxw, hwy, sub_pos] at ha hb ⊢
+ simp only [div_lt_iff₀, hxy, hxw, hwy, sub_pos] at ha hb ⊢
have : deriv f a * (w - x) < deriv f b * (w - x) := by
apply mul_lt_mul _ le_rfl (sub_pos.2 hxw) _
· exact hf'_mono ⟨hxa, haw.trans hwy⟩ ⟨hxw.trans hwb, hby⟩ (haw.trans hwb)
@@ -139,7 +139,7 @@ theorem StrictMonoOn.exists_deriv_lt_slope {x y : ℝ} {f : ℝ → ℝ} (hf : C
apply ne_of_gt
exact hf'_mono ⟨hxw, hwy⟩ ⟨hxw.trans hz.1, hz.2⟩ hz.1
refine ⟨a, ⟨hxa, haw.trans hwy⟩, ?_⟩
- simp only [lt_div_iff, hxy, hxw, hwy, sub_pos] at ha hb ⊢
+ simp only [lt_div_iff₀, hxy, hxw, hwy, sub_pos] at ha hb ⊢
have : deriv f a * (y - w) < deriv f b * (y - w) := by
apply mul_lt_mul _ le_rfl (sub_pos.2 hwy) _
· exact hf'_mono ⟨hxa, haw.trans hwy⟩ ⟨hxw.trans hwb, hby⟩ (haw.trans hwb)
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 b73b52f91006a..5ecb5e8b2c4cd 100644
--- a/Mathlib/Analysis/Convex/Gauge.lean
+++ b/Mathlib/Analysis/Convex/Gauge.lean
@@ -111,7 +111,7 @@ theorem gauge_of_subset_zero (h : s ⊆ 0) : gauge s = 0 := by
/-- The gauge is always nonnegative. -/
theorem gauge_nonneg (x : E) : 0 ≤ gauge s x :=
- Real.sInf_nonneg _ fun _ hx => hx.1.le
+ Real.sInf_nonneg fun _ hx => hx.1.le
theorem gauge_neg (symmetric : ∀ x ∈ s, -x ∈ s) (x : E) : gauge s (-x) = gauge s x := by
have : ∀ x, -x ∈ s ↔ x ∈ s := fun x => ⟨fun h => by simpa using symmetric _ h, symmetric x⟩
@@ -139,7 +139,7 @@ theorem gauge_le_eq (hs₁ : Convex ℝ s) (hs₀ : (0 : E) ∈ s) (hs₂ : Abso
suffices (r⁻¹ * δ) • δ⁻¹ • x ∈ s by rwa [smul_smul, mul_inv_cancel_right₀ δ_pos.ne'] at this
rw [mem_smul_set_iff_inv_smul_mem₀ δ_pos.ne'] at hδ
refine hs₁.smul_mem_of_zero_mem hs₀ hδ ⟨by positivity, ?_⟩
- rw [inv_mul_le_iff hr', mul_one]
+ rw [inv_mul_le_iff₀ hr', mul_one]
exact hδr.le
· have hε' := (lt_add_iff_pos_right a).2 (half_pos hε)
exact
@@ -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) :
@@ -214,7 +214,7 @@ theorem le_gauge_of_not_mem (hs₀ : StarConvex ℝ 0 s) (hs₂ : Absorbs ℝ s
have ha := hb.trans hba
refine ⟨(a⁻¹ * b) • x, hs₀ hx' (by positivity) ?_, ?_⟩
· rw [← div_eq_inv_mul]
- exact div_le_one_of_le hba.le ha.le
+ exact div_le_one_of_le₀ hba.le ha.le
· dsimp only
rw [← mul_smul, mul_inv_cancel_left₀ ha.ne']
@@ -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']
@@ -369,7 +369,7 @@ theorem gauge_lt_of_mem_smul (x : E) (ε : ℝ) (hε : 0 < ε) (hs₂ : IsOpen s
gauge s x < ε := by
have : ε⁻¹ • x ∈ s := by rwa [← mem_smul_set_iff_inv_smul_mem₀ hε.ne']
have h_gauge_lt := gauge_lt_one_of_mem_of_isOpen hs₂ this
- rwa [gauge_smul_of_nonneg (inv_nonneg.2 hε.le), smul_eq_mul, inv_mul_lt_iff hε, mul_one]
+ rwa [gauge_smul_of_nonneg (inv_nonneg.2 hε.le), smul_eq_mul, inv_mul_lt_iff₀ hε, mul_one]
at h_gauge_lt
theorem mem_closure_of_gauge_le_one (hc : Convex ℝ s) (hs₀ : 0 ∈ s) (ha : Absorbent ℝ s)
@@ -500,7 +500,7 @@ protected theorem Seminorm.gauge_ball (p : Seminorm ℝ E) : gauge (p.ball 0 1)
have hpx₂ : 0 < 2 * p x := mul_pos zero_lt_two hpx
refine hp.subset ⟨hpx₂, (2 * p x)⁻¹ • x, ?_, smul_inv_smul₀ hpx₂.ne' _⟩
rw [p.mem_ball_zero, map_smul_eq_mul, Real.norm_eq_abs, abs_of_pos (inv_pos.2 hpx₂),
- inv_mul_lt_iff hpx₂, mul_one]
+ inv_mul_lt_iff₀ hpx₂, mul_one]
exact lt_mul_of_one_lt_left hpx one_lt_two
refine IsGLB.csInf_eq ⟨fun r => ?_, fun r hr => le_of_forall_pos_le_add fun ε hε => ?_⟩ hp
· rintro ⟨hr, y, hy, rfl⟩
@@ -512,7 +512,7 @@ protected theorem Seminorm.gauge_ball (p : Seminorm ℝ E) : gauge (p.ball 0 1)
add_pos_of_nonneg_of_pos (apply_nonneg _ _) hε
refine hr ⟨hpε, (p x + ε)⁻¹ • x, ?_, smul_inv_smul₀ hpε.ne' _⟩
rw [p.mem_ball_zero, map_smul_eq_mul, Real.norm_eq_abs, abs_of_pos (inv_pos.2 hpε),
- inv_mul_lt_iff hpε, mul_one]
+ inv_mul_lt_iff₀ hpε, mul_one]
exact lt_add_of_pos_right _ hε
theorem Seminorm.gaugeSeminorm_ball (p : Seminorm ℝ E) :
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 12b11b68057db..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
@@ -328,7 +327,7 @@ theorem ae_eq_const_or_norm_integral_lt_of_norm_le_const [StrictConvexSpace ℝ
simp [ENNReal.toReal_pos_iff, pos_iff_ne_zero, h₀, measure_lt_top]
refine (ae_eq_const_or_norm_average_lt_of_norm_le_const h_le).imp_right fun H => ?_
rwa [average_eq, norm_smul, norm_inv, Real.norm_eq_abs, abs_of_pos hμ, ← div_eq_inv_mul,
- div_lt_iff' hμ] at H
+ div_lt_iff₀' hμ] at H
/-- If `E` is a strictly convex normed space and `f : α → E` is a function such that `‖f x‖ ≤ C`
a.e. on a set `t` of finite measure, then either this function is a.e. equal to its average value on
diff --git a/Mathlib/Analysis/Convex/Intrinsic.lean b/Mathlib/Analysis/Convex/Intrinsic.lean
index d05235e251337..1706893f1b382 100644
--- a/Mathlib/Analysis/Convex/Intrinsic.lean
+++ b/Mathlib/Analysis/Convex/Intrinsic.lean
@@ -96,24 +96,6 @@ theorem intrinsicFrontier_subset_intrinsicClosure : intrinsicFrontier 𝕜 s ⊆
theorem subset_intrinsicClosure : s ⊆ intrinsicClosure 𝕜 s :=
fun x hx => ⟨⟨x, subset_affineSpan _ _ hx⟩, subset_closure hx, rfl⟩
-lemma intrinsicInterior_eq_interior_of_span (hs : affineSpan 𝕜 s = ⊤) :
- intrinsicInterior 𝕜 s = interior s := by
- set f : affineSpan 𝕜 s ≃ₜ P := .trans (.setCongr (congr_arg SetLike.coe hs)) (.Set.univ _)
- change f '' interior (f ⁻¹' s) = interior s
- rw [f.image_interior, f.image_preimage]
-
-lemma intrinsicFrontier_eq_frontier_of_span (hs : affineSpan 𝕜 s = ⊤) :
- intrinsicFrontier 𝕜 s = frontier s := by
- set f : affineSpan 𝕜 s ≃ₜ P := .trans (.setCongr (congr_arg SetLike.coe hs)) (.Set.univ _)
- change f '' frontier (f ⁻¹' s) = frontier s
- rw [f.image_frontier, f.image_preimage]
-
-lemma intrinsicClosure_eq_closure_of_span (hs : affineSpan 𝕜 s = ⊤) :
- intrinsicClosure 𝕜 s = closure s := by
- set f : affineSpan 𝕜 s ≃ₜ P := .trans (.setCongr (congr_arg SetLike.coe hs)) (.Set.univ _)
- change f '' closure (f ⁻¹' s) = closure s
- rw [f.image_closure, f.image_preimage]
-
@[simp]
theorem intrinsicInterior_empty : intrinsicInterior 𝕜 (∅ : Set P) = ∅ := by simp [intrinsicInterior]
@@ -123,15 +105,6 @@ theorem intrinsicFrontier_empty : intrinsicFrontier 𝕜 (∅ : Set P) = ∅ :=
@[simp]
theorem intrinsicClosure_empty : intrinsicClosure 𝕜 (∅ : Set P) = ∅ := by simp [intrinsicClosure]
-@[simp] lemma intrinsicInterior_univ : intrinsicInterior 𝕜 (univ : Set P) = univ := by
- simp [intrinsicInterior]
-
-@[simp] lemma intrinsicFrontier_univ : intrinsicFrontier 𝕜 (univ : Set P) = ∅ := by
- simp [intrinsicFrontier]
-
-@[simp] lemma intrinsicClosure_univ : intrinsicClosure 𝕜 (univ : Set P) = univ := by
- simp [intrinsicClosure]
-
@[simp]
theorem intrinsicClosure_nonempty : (intrinsicClosure 𝕜 s).Nonempty ↔ s.Nonempty :=
⟨by simp_rw [nonempty_iff_ne_empty]; rintro h rfl; exact h intrinsicClosure_empty,
@@ -203,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) :
@@ -250,8 +223,8 @@ theorem image_intrinsicInterior (φ : P →ᵃⁱ[𝕜] Q) (s : Set P) :
let f := ((affineSpan 𝕜 s).isometryEquivMap φ).toHomeomorph
have : φ.toAffineMap ∘ (↑) ∘ f.symm = (↑) := funext isometryEquivMap.apply_symm_apply
rw [intrinsicInterior, intrinsicInterior, ← φ.coe_toAffineMap, ← map_span φ.toAffineMap s, ← this,
- ← Function.comp.assoc, image_comp, image_comp, f.symm.image_interior, f.image_symm,
- ← preimage_comp, Function.comp.assoc, f.symm_comp_self, AffineIsometry.coe_toAffineMap,
+ ← Function.comp_assoc, image_comp, image_comp, f.symm.image_interior, f.image_symm,
+ ← preimage_comp, Function.comp_assoc, f.symm_comp_self, AffineIsometry.coe_toAffineMap,
Function.comp_id, preimage_comp, φ.injective.preimage_image]
@[simp]
@@ -263,8 +236,8 @@ theorem image_intrinsicFrontier (φ : P →ᵃⁱ[𝕜] Q) (s : Set P) :
let f := ((affineSpan 𝕜 s).isometryEquivMap φ).toHomeomorph
have : φ.toAffineMap ∘ (↑) ∘ f.symm = (↑) := funext isometryEquivMap.apply_symm_apply
rw [intrinsicFrontier, intrinsicFrontier, ← φ.coe_toAffineMap, ← map_span φ.toAffineMap s, ← this,
- ← Function.comp.assoc, image_comp, image_comp, f.symm.image_frontier, f.image_symm,
- ← preimage_comp, Function.comp.assoc, f.symm_comp_self, AffineIsometry.coe_toAffineMap,
+ ← Function.comp_assoc, image_comp, image_comp, f.symm.image_frontier, f.image_symm,
+ ← preimage_comp, Function.comp_assoc, f.symm_comp_self, AffineIsometry.coe_toAffineMap,
Function.comp_id, preimage_comp, φ.injective.preimage_image]
@[simp]
@@ -276,8 +249,8 @@ theorem image_intrinsicClosure (φ : P →ᵃⁱ[𝕜] Q) (s : Set P) :
let f := ((affineSpan 𝕜 s).isometryEquivMap φ).toHomeomorph
have : φ.toAffineMap ∘ (↑) ∘ f.symm = (↑) := funext isometryEquivMap.apply_symm_apply
rw [intrinsicClosure, intrinsicClosure, ← φ.coe_toAffineMap, ← map_span φ.toAffineMap s, ← this,
- ← Function.comp.assoc, image_comp, image_comp, f.symm.image_closure, f.image_symm,
- ← preimage_comp, Function.comp.assoc, f.symm_comp_self, AffineIsometry.coe_toAffineMap,
+ ← Function.comp_assoc, image_comp, image_comp, f.symm.image_closure, f.image_symm,
+ ← preimage_comp, Function.comp_assoc, f.symm_comp_self, AffineIsometry.coe_toAffineMap,
Function.comp_id, preimage_comp, φ.injective.preimage_image]
end AffineIsometry
diff --git a/Mathlib/Analysis/Convex/Jensen.lean b/Mathlib/Analysis/Convex/Jensen.lean
index 20e5b017a492d..90692868f122b 100644
--- a/Mathlib/Analysis/Convex/Jensen.lean
+++ b/Mathlib/Analysis/Convex/Jensen.lean
@@ -118,11 +118,10 @@ lemma StrictConvexOn.map_sum_lt (hf : StrictConvexOn 𝕜 s f) (h₀ : ∀ i ∈
have := h₀ k <| by simp
let c := w j + w k
have hc : w j / c + w k / c = 1 := by field_simp
- have hcj : c * (w j / c) = w j := by field_simp
- have hck : c * (w k / c) = w k := by field_simp
calc f (w j • p j + (w k • p k + ∑ x ∈ u, w x • p x))
_ = f (c • ((w j / c) • p j + (w k / c) • p k) + ∑ x ∈ u, w x • p x) := by
- rw [smul_add, ← mul_smul, ← mul_smul, hcj, hck, add_assoc]
+ congrm f ?_
+ match_scalars <;> field_simp
_ ≤ c • f ((w j / c) • p j + (w k / c) • p k) + ∑ x ∈ u, w x • f (p x) :=
-- apply the usual Jensen's inequality wrt the weighted average of the two distinguished
-- points and all the other points
@@ -134,7 +133,7 @@ lemma StrictConvexOn.map_sum_lt (hf : StrictConvexOn 𝕜 s f) (h₀ : ∀ i ∈
-- then apply the definition of strict convexity for the two distinguished points
gcongr; refine hf.2 (hmem _ <| by simp) (hmem _ <| by simp) hjk ?_ ?_ hc <;> positivity
_ = (w j • f (p j) + w k • f (p k)) + ∑ x ∈ u, w x • f (p x) := by
- rw [smul_add, ← mul_smul, ← mul_smul, hcj, hck]
+ match_scalars <;> field_simp
_ = w j • f (p j) + (w k • f (p k) + ∑ x ∈ u, w x • f (p x)) := by abel_nf
/-- Concave **strict Jensen inequality**.
@@ -272,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 a8641487cfccd..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]
@@ -113,19 +112,13 @@ theorem convexJoin_assoc_aux (s t u : Set E) :
rintro _ ⟨z, ⟨x, hx, y, hy, a₁, b₁, ha₁, hb₁, hab₁, rfl⟩, z, hz, a₂, b₂, ha₂, hb₂, hab₂, rfl⟩
obtain rfl | hb₂ := hb₂.eq_or_lt
· refine ⟨x, hx, y, ⟨y, hy, z, hz, left_mem_segment 𝕜 _ _⟩, a₁, b₁, ha₁, hb₁, hab₁, ?_⟩
- rw [add_zero] at hab₂
- rw [hab₂, one_smul, zero_smul, add_zero]
- have ha₂b₁ : 0 ≤ a₂ * b₁ := mul_nonneg ha₂ hb₁
- have hab : 0 < a₂ * b₁ + b₂ := add_pos_of_nonneg_of_pos ha₂b₁ hb₂
+ linear_combination (norm := module) congr(-$hab₂ • (a₁ • x + b₁ • y))
refine
⟨x, hx, (a₂ * b₁ / (a₂ * b₁ + b₂)) • y + (b₂ / (a₂ * b₁ + b₂)) • z,
- ⟨y, hy, z, hz, _, _, ?_, ?_, ?_, rfl⟩,
- a₂ * a₁, a₂ * b₁ + b₂, mul_nonneg ha₂ ha₁, hab.le, ?_, ?_⟩
- · exact div_nonneg ha₂b₁ hab.le
- · exact div_nonneg hb₂.le hab.le
- · rw [← add_div, div_self hab.ne']
- · rw [← add_assoc, ← mul_add, hab₁, mul_one, hab₂]
- · simp_rw [smul_add, ← mul_smul, mul_div_cancel₀ _ hab.ne', add_assoc]
+ ⟨y, hy, z, hz, _, _, by positivity, by positivity, by field_simp, rfl⟩,
+ a₂ * a₁, a₂ * b₁ + b₂, by positivity, by positivity, ?_, ?_⟩
+ · linear_combination a₂ * hab₁ + hab₂
+ · match_scalars <;> field_simp
theorem convexJoin_assoc (s t u : Set E) :
convexJoin 𝕜 (convexJoin 𝕜 s t) u = convexJoin 𝕜 s (convexJoin 𝕜 t u) := by
@@ -155,9 +148,9 @@ protected theorem Convex.convexJoin (hs : Convex 𝕜 s) (ht : Convex 𝕜 t) :
rcases hs.exists_mem_add_smul_eq hx₁ hx₂ (mul_nonneg hp ha₁) (mul_nonneg hq ha₂) with ⟨x, hxs, hx⟩
rcases ht.exists_mem_add_smul_eq hy₁ hy₂ (mul_nonneg hp hb₁) (mul_nonneg hq hb₂) with ⟨y, hyt, hy⟩
refine ⟨_, hxs, _, hyt, p * a₁ + q * a₂, p * b₁ + q * b₂, ?_, ?_, ?_, ?_⟩ <;> try positivity
- · rwa [add_add_add_comm, ← mul_add, ← mul_add, hab₁, hab₂, mul_one, mul_one]
- · rw [hx, hy, add_add_add_comm]
- simp only [smul_add, smul_smul]
+ · linear_combination p * hab₁ + q * hab₂ + hpq
+ · rw [hx, hy]
+ module
protected theorem Convex.convexHull_union (hs : Convex 𝕜 s) (ht : Convex 𝕜 t) (hs₀ : s.Nonempty)
(ht₀ : t.Nonempty) : convexHull 𝕜 (s ∪ t) = convexJoin 𝕜 s t :=
diff --git a/Mathlib/Analysis/Convex/Measure.lean b/Mathlib/Analysis/Convex/Measure.lean
index d8b9b78be2d4b..cf276ed3f8958 100644
--- a/Mathlib/Analysis/Convex/Measure.lean
+++ b/Mathlib/Analysis/Convex/Measure.lean
@@ -18,7 +18,7 @@ convex set in `E`. Then the frontier of `s` has measure zero (see `Convex.addHaa
open MeasureTheory MeasureTheory.Measure Set Metric Filter Bornology
-open FiniteDimensional (finrank)
+open Module (finrank)
open scoped Topology NNReal ENNReal
@@ -64,7 +64,7 @@ theorem addHaar_frontier (hs : Convex ℝ s) : μ (frontier s) = 0 := by
/- Due to `Convex.closure_subset_image_homothety_interior_of_one_lt`, for any `r > 1` we have
`closure s ⊆ homothety x r '' interior s`, hence `μ (closure s) ≤ r ^ d * μ (interior s)`,
where `d = finrank ℝ E`. -/
- set d : ℕ := FiniteDimensional.finrank ℝ E
+ set d : ℕ := Module.finrank ℝ E
have : ∀ r : ℝ≥0, 1 < r → μ (closure s) ≤ ↑(r ^ d) * μ (interior s) := fun r hr ↦ by
refine (measure_mono <|
hs.closure_subset_image_homothety_interior_of_one_lt hx r hr).trans_eq ?_
diff --git a/Mathlib/Analysis/Convex/Normed.lean b/Mathlib/Analysis/Convex/Normed.lean
index 2cb4a8b2db0d7..fae3e58b55f18 100644
--- a/Mathlib/Analysis/Convex/Normed.lean
+++ b/Mathlib/Analysis/Convex/Normed.lean
@@ -27,7 +27,7 @@ We prove the following facts:
variable {ι : Type*} {E P : Type*}
-open AffineBasis FiniteDimensional Metric Set
+open AffineBasis Module Metric Set
open scoped Convex Pointwise Topology
section SeminormedAddCommGroup
@@ -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 ee505ba41b251..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
@@ -62,12 +62,12 @@ theorem radon_partition {f : ι → E} (h : ¬ AffineIndependent 𝕜 f) :
· linarith only [hI, hJI]
· exact (mem_filter.mp hi').2.not_lt (mem_filter.mp hi).2
-open FiniteDimensional
+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 87adc0a70ac2e..1c4e577df9e16 100644
--- a/Mathlib/Analysis/Convex/Segment.lean
+++ b/Mathlib/Analysis/Convex/Segment.lean
@@ -122,7 +122,7 @@ theorem segment_same (x : E) : [x -[𝕜] x] = {x} :=
theorem insert_endpoints_openSegment (x y : E) :
insert x (insert y (openSegment 𝕜 x y)) = [x -[𝕜] y] := by
simp only [subset_antisymm_iff, insert_subset_iff, left_mem_segment, right_mem_segment,
- openSegment_subset_segment, true_and_iff]
+ openSegment_subset_segment, true_and]
rintro z ⟨a, b, ha, hb, hab, rfl⟩
refine hb.eq_or_gt.imp ?_ fun hb' => ha.eq_or_gt.imp ?_ fun ha' => ?_
· rintro rfl
@@ -140,7 +140,7 @@ theorem mem_openSegment_of_ne_left_right (hx : x ≠ z) (hy : y ≠ z) (hz : z
theorem openSegment_subset_iff_segment_subset (hx : x ∈ s) (hy : y ∈ s) :
openSegment 𝕜 x y ⊆ s ↔ [x -[𝕜] y] ⊆ s := by
- simp only [← insert_endpoints_openSegment, insert_subset_iff, *, true_and_iff]
+ simp only [← insert_endpoints_openSegment, insert_subset_iff, *, true_and]
end Module
@@ -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 13933585a56e0..9504c21166ab9 100644
--- a/Mathlib/Analysis/Convex/Side.lean
+++ b/Mathlib/Analysis/Convex/Side.lean
@@ -333,12 +333,8 @@ theorem _root_.Wbtw.wOppSide₁₃ {s : AffineSubspace R P} {x y z : P} (h : Wbt
rcases ht0.lt_or_eq with (ht0' | rfl); swap
· rw [lineMap_apply_zero]; simp
refine Or.inr (Or.inr ⟨1 - t, t, sub_pos.2 ht1', ht0', ?_⟩)
- -- TODO: after lean4#2336 "simp made no progress feature"
- -- had to add `_` to several lemmas here. Not sure why!
- simp_rw [lineMap_apply _, vadd_vsub_assoc _, vsub_vadd_eq_vsub_sub _,
- ← neg_vsub_eq_vsub_rev z x, vsub_self _, zero_sub, ← neg_one_smul R (z -ᵥ x),
- ← add_smul, smul_neg, ← neg_smul, smul_smul]
- ring_nf
+ rw [lineMap_apply, vadd_vsub_assoc, vsub_vadd_eq_vsub_sub, ← neg_vsub_eq_vsub_rev z, vsub_self]
+ module
theorem _root_.Wbtw.wOppSide₃₁ {s : AffineSubspace R P} {x y z : P} (h : Wbtw R x y z)
(hy : y ∈ s) : s.WOppSide z x :=
@@ -349,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
@@ -411,9 +406,9 @@ theorem wOppSide_iff_exists_left {s : AffineSubspace R P} {x y p₁ : P} (h : p
exact SameRay.zero_right _
· refine Or.inr ⟨(-r₁ / r₂) • (p₁ -ᵥ p₁') +ᵥ p₂', s.smul_vsub_vadd_mem _ h hp₁' hp₂',
Or.inr (Or.inr ⟨r₁, r₂, hr₁, hr₂, ?_⟩)⟩
- rw [vadd_vsub_assoc, smul_add, ← hr, smul_smul, neg_div, mul_neg,
- mul_div_cancel₀ _ hr₂.ne.symm, neg_smul, neg_add_eq_sub, ← smul_sub,
- vsub_sub_vsub_cancel_right]
+ rw [vadd_vsub_assoc, ← vsub_sub_vsub_cancel_right x p₁ p₁']
+ linear_combination (norm := match_scalars <;> field_simp) hr
+ ring
· rintro (h' | ⟨h₁, h₂, h₃⟩)
· exact wOppSide_of_left_mem y h'
· exact ⟨p₁, h, h₁, h₂, h₃⟩
@@ -584,16 +579,15 @@ theorem wOppSide_iff_exists_wbtw {s : AffineSubspace R P} {x y : P} :
· refine ⟨lineMap x y (r₂ / (r₁ + r₂)), ?_, ?_⟩
· have : (r₂ / (r₁ + r₂)) • (y -ᵥ p₂ + (p₂ -ᵥ p₁) - (x -ᵥ p₁)) + (x -ᵥ p₁) =
(r₂ / (r₁ + r₂)) • (p₂ -ᵥ p₁) := by
- rw [add_comm (y -ᵥ p₂), smul_sub, smul_add, add_sub_assoc, add_assoc, add_right_eq_self,
- div_eq_inv_mul, ← neg_vsub_eq_vsub_rev, smul_neg, ← smul_smul, ← h, smul_smul, ← neg_smul,
- ← sub_smul, ← div_eq_inv_mul, ← div_eq_inv_mul, ← neg_div, ← sub_div, sub_eq_add_neg,
- ← neg_add, neg_div, div_self (Left.add_pos hr₁ hr₂).ne.symm, neg_one_smul, neg_add_cancel]
+ rw [← neg_vsub_eq_vsub_rev p₂ y]
+ linear_combination (norm := match_scalars <;> field_simp) congr((r₁ + r₂)⁻¹ • $h)
+ ring
rw [lineMap_apply, ← vsub_vadd x p₁, ← vsub_vadd y p₂, vsub_vadd_eq_vsub_sub, vadd_vsub_assoc,
← vadd_assoc, vadd_eq_add, this]
exact s.smul_vsub_vadd_mem (r₂ / (r₁ + r₂)) hp₂ hp₁ hp₁
· exact Set.mem_image_of_mem _
- ⟨div_nonneg hr₂.le (Left.add_pos hr₁ hr₂).le,
- div_le_one_of_le (le_add_of_nonneg_left hr₁.le) (Left.add_pos hr₁ hr₂).le⟩
+ ⟨by positivity,
+ div_le_one_of_le₀ (le_add_of_nonneg_left hr₁.le) (Left.add_pos hr₁ hr₂).le⟩
theorem SOppSide.exists_sbtw {s : AffineSubspace R P} {x y : P} (h : s.SOppSide x y) :
∃ p ∈ s, Sbtw R x p y := by
@@ -776,7 +770,7 @@ theorem isPreconnected_setOf_sSameSide (s : AffineSubspace ℝ P) (x : P) :
simp only [h, not_sSameSide_bot]
exact isPreconnected_empty
· by_cases hx : x ∈ s
- · simp only [hx, SSameSide, not_true, false_and_iff, and_false_iff]
+ · simp only [hx, SSameSide, not_true, false_and, and_false]
exact isPreconnected_empty
· exact (isConnected_setOf_sSameSide hx h).isPreconnected
@@ -817,7 +811,7 @@ theorem isPreconnected_setOf_sOppSide (s : AffineSubspace ℝ P) (x : P) :
simp only [h, not_sOppSide_bot]
exact isPreconnected_empty
· by_cases hx : x ∈ s
- · simp only [hx, SOppSide, not_true, false_and_iff, and_false_iff]
+ · simp only [hx, SOppSide, not_true, false_and, and_false]
exact isPreconnected_empty
· exact (isConnected_setOf_sOppSide hx h).isPreconnected
diff --git a/Mathlib/Analysis/Convex/Slope.lean b/Mathlib/Analysis/Convex/Slope.lean
index ea7ca88a2e853..38072902d3e91 100644
--- a/Mathlib/Analysis/Convex/Slope.lean
+++ b/Mathlib/Analysis/Convex/Slope.lean
@@ -158,7 +158,7 @@ theorem strictConvexOn_of_slope_strict_mono_adjacent (hs : Convex 𝕜 s)
simp_rw [div_eq_iff hxz.ne', ← hab]
ring
rwa [sub_mul, sub_mul, sub_lt_iff_lt_add', ← add_sub_assoc, lt_sub_iff_add_lt, ← mul_add,
- sub_add_sub_cancel, ← lt_div_iff hxz, add_div, mul_div_assoc, mul_div_assoc, mul_comm (f x),
+ sub_add_sub_cancel, ← lt_div_iff₀ hxz, add_div, mul_div_assoc, mul_div_assoc, mul_comm (f x),
mul_comm (f z), ha, hb] at this
/-- If for any three points `x < y < z`, the slope of the secant line of `f : 𝕜 → 𝕜` on `[x, y]` is
@@ -267,7 +267,7 @@ theorem StrictConvexOn.secant_strict_mono_aux1 (hf : StrictConvexOn 𝕜 s f) {x
have hxy' : 0 < y - x := by linarith
have hyz' : 0 < z - y := by linarith
have hxz' : 0 < z - x := by linarith
- rw [← lt_div_iff' hxz']
+ rw [← lt_div_iff₀' hxz']
have ha : 0 < (z - y) / (z - x) := by positivity
have hb : 0 < (y - x) / (z - x) := by positivity
calc
diff --git a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean
index 922b18543ffe0..b293f4c6a7eb3 100644
--- a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean
+++ b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean
@@ -40,14 +40,14 @@ theorem strictConvexOn_exp : StrictConvexOn ℝ univ exp := by
trans exp y
· have h1 : 0 < y - x := by linarith
have h2 : x - y < 0 := by linarith
- rw [div_lt_iff h1]
+ rw [div_lt_iff₀ h1]
calc
exp y - exp x = exp y - exp y * exp (x - y) := by rw [← exp_add]; ring_nf
_ = exp y * (1 - exp (x - y)) := by ring
_ < exp y * -(x - y) := by gcongr; linarith [add_one_lt_exp h2.ne]
_ = exp y * (y - x) := by ring
· have h1 : 0 < z - y := by linarith
- rw [lt_div_iff h1]
+ rw [lt_div_iff₀ h1]
calc
exp y * (z - y) < exp y * (exp (z - y) - 1) := by
gcongr _ * ?_
@@ -66,7 +66,7 @@ theorem strictConcaveOn_log_Ioi : StrictConcaveOn ℝ (Ioi 0) log := by
have hy : 0 < y := hx.trans hxy
trans y⁻¹
· have h : 0 < z - y := by linarith
- rw [div_lt_iff h]
+ rw [div_lt_iff₀ h]
have hyz' : 0 < z / y := by positivity
have hyz'' : z / y ≠ 1 := by
contrapose! h
@@ -77,7 +77,7 @@ theorem strictConcaveOn_log_Ioi : StrictConcaveOn ℝ (Ioi 0) log := by
_ < z / y - 1 := log_lt_sub_one_of_pos hyz' hyz''
_ = y⁻¹ * (z - y) := by field_simp
· have h : 0 < y - x := by linarith
- rw [lt_div_iff h]
+ rw [lt_div_iff₀ h]
have hxy' : 0 < x / y := by positivity
have hxy'' : x / y ≠ 1 := by
contrapose! h
@@ -105,12 +105,12 @@ theorem one_add_mul_self_lt_rpow_one_add {s : ℝ} (hs : -1 ≤ s) (hs' : s ≠
rw [rpow_def_of_pos hs1, ← exp_log hs2]
apply exp_strictMono
cases' lt_or_gt_of_ne hs' with hs' hs'
- · rw [← div_lt_iff hp', ← div_lt_div_right_of_neg hs']
+ · rw [← div_lt_iff₀ hp', ← div_lt_div_right_of_neg hs']
convert strictConcaveOn_log_Ioi.secant_strict_mono (zero_lt_one' ℝ) hs2 hs1 hs4 hs3 _ using 1
· rw [add_sub_cancel_left, log_one, sub_zero]
· rw [add_sub_cancel_left, div_div, log_one, sub_zero]
· apply add_lt_add_left (mul_lt_of_one_lt_left hs' hp)
- · rw [← div_lt_iff hp', ← div_lt_div_right hs']
+ · rw [← div_lt_iff₀ hp', ← div_lt_div_right hs']
convert strictConcaveOn_log_Ioi.secant_strict_mono (zero_lt_one' ℝ) hs1 hs2 hs3 hs4 _ using 1
· rw [add_sub_cancel_left, div_div, log_one, sub_zero]
· rw [add_sub_cancel_left, log_one, sub_zero]
@@ -144,12 +144,12 @@ theorem rpow_one_add_lt_one_add_mul_self {s : ℝ} (hs : -1 ≤ s) (hs' : s ≠
rw [rpow_def_of_pos hs1, ← exp_log hs2]
apply exp_strictMono
cases' lt_or_gt_of_ne hs' with hs' hs'
- · rw [← lt_div_iff hp1, ← div_lt_div_right_of_neg hs']
+ · rw [← lt_div_iff₀ hp1, ← div_lt_div_right_of_neg hs']
convert strictConcaveOn_log_Ioi.secant_strict_mono (zero_lt_one' ℝ) hs1 hs2 hs3 hs4 _ using 1
· rw [add_sub_cancel_left, div_div, log_one, sub_zero]
· rw [add_sub_cancel_left, log_one, sub_zero]
· apply add_lt_add_left (lt_mul_of_lt_one_left hs' hp2)
- · rw [← lt_div_iff hp1, ← div_lt_div_right hs']
+ · rw [← lt_div_iff₀ hp1, ← div_lt_div_right hs']
convert strictConcaveOn_log_Ioi.secant_strict_mono (zero_lt_one' ℝ) hs2 hs1 hs4 hs3 _ using 1
· rw [add_sub_cancel_left, log_one, sub_zero]
· rw [add_sub_cancel_left, div_div, log_one, sub_zero]
@@ -175,20 +175,21 @@ theorem strictConvexOn_rpow {p : ℝ} (hp : 1 < p) : StrictConvexOn ℝ (Ici 0)
have hy' : 0 < y ^ p := rpow_pos_of_pos hy _
trans p * y ^ (p - 1)
· have q : 0 < y - x := by rwa [sub_pos]
- rw [div_lt_iff q, ← div_lt_div_right hy', _root_.sub_div, div_self hy'.ne', ← div_rpow hx hy.le,
- sub_lt_comm, ← add_sub_cancel_right (x / y) 1, add_comm, add_sub_assoc, ← div_mul_eq_mul_div,
- mul_div_assoc, ← rpow_sub hy, sub_sub_cancel_left, rpow_neg_one, mul_assoc, ← div_eq_inv_mul,
- sub_eq_add_neg, ← mul_neg, ← neg_div, neg_sub, _root_.sub_div, div_self hy.ne']
+ rw [div_lt_iff₀ q, ← div_lt_div_right hy', _root_.sub_div, div_self hy'.ne',
+ ← div_rpow hx hy.le, sub_lt_comm, ← add_sub_cancel_right (x / y) 1, add_comm, add_sub_assoc,
+ ← div_mul_eq_mul_div, mul_div_assoc, ← rpow_sub hy, sub_sub_cancel_left, rpow_neg_one,
+ mul_assoc, ← div_eq_inv_mul, sub_eq_add_neg, ← mul_neg, ← neg_div, neg_sub, _root_.sub_div,
+ div_self hy.ne']
apply one_add_mul_self_lt_rpow_one_add _ _ hp
· rw [le_sub_iff_add_le, neg_add_cancel, div_nonneg_iff]
exact Or.inl ⟨hx, hy.le⟩
· rw [sub_ne_zero]
exact ((div_lt_one hy).mpr hxy).ne
· have q : 0 < z - y := by rwa [sub_pos]
- rw [lt_div_iff q, ← div_lt_div_right hy', _root_.sub_div, div_self hy'.ne', ← div_rpow hz hy.le,
- lt_sub_iff_add_lt', ← add_sub_cancel_right (z / y) 1, add_comm _ 1, add_sub_assoc,
- ← div_mul_eq_mul_div, mul_div_assoc, ← rpow_sub hy, sub_sub_cancel_left, rpow_neg_one,
- mul_assoc, ← div_eq_inv_mul, _root_.sub_div, div_self hy.ne']
+ rw [lt_div_iff₀ q, ← div_lt_div_right hy', _root_.sub_div, div_self hy'.ne',
+ ← div_rpow hz hy.le, lt_sub_iff_add_lt', ← add_sub_cancel_right (z / y) 1, add_comm _ 1,
+ add_sub_assoc, ← div_mul_eq_mul_div, mul_div_assoc, ← rpow_sub hy, sub_sub_cancel_left,
+ rpow_neg_one, mul_assoc, ← div_eq_inv_mul, _root_.sub_div, div_self hy.ne']
apply one_add_mul_self_lt_rpow_one_add _ _ hp
· rw [le_sub_iff_add_le, neg_add_cancel, div_nonneg_iff]
exact Or.inl ⟨hz, hy.le⟩
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 44f1a60ccabfb..ad0ee8acf1ca5 100644
--- a/Mathlib/Analysis/Convex/Star.lean
+++ b/Mathlib/Analysis/Convex/Star.lean
@@ -8,6 +8,7 @@ import Mathlib.Algebra.Order.Module.Synonym
import Mathlib.Algebra.Order.Group.Instances
import Mathlib.Analysis.Convex.Segment
import Mathlib.Tactic.GCongr
+import Mathlib.Tactic.Module
/-!
# Star-convex sets
@@ -210,14 +211,14 @@ theorem StarConvex.add_left (hs : StarConvex 𝕜 x s) (z : E) :
intro y hy a b ha hb hab
obtain ⟨y', hy', rfl⟩ := hy
refine ⟨a • x + b • y', hs hy' ha hb hab, ?_⟩
- rw [smul_add, smul_add, add_add_add_comm, ← add_smul, hab, one_smul]
+ match_scalars <;> simp [hab]
theorem StarConvex.add_right (hs : StarConvex 𝕜 x s) (z : E) :
StarConvex 𝕜 (x + z) ((fun x => x + z) '' s) := by
intro y hy a b ha hb hab
obtain ⟨y', hy', rfl⟩ := hy
refine ⟨a • x + b • y', hs hy' ha hb hab, ?_⟩
- rw [smul_add, smul_add, add_add_add_comm, ← add_smul, hab, one_smul]
+ match_scalars <;> simp [hab]
/-- The translation of a star-convex set is also star-convex. -/
theorem StarConvex.preimage_add_right (hs : StarConvex 𝕜 (z + x) s) :
@@ -385,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/StoneSeparation.lean b/Mathlib/Analysis/Convex/StoneSeparation.lean
index 4f746cd1909fd..1027690d2b881 100644
--- a/Mathlib/Analysis/Convex/StoneSeparation.lean
+++ b/Mathlib/Analysis/Convex/StoneSeparation.lean
@@ -46,9 +46,6 @@ theorem not_disjoint_segment_convexHull_triple {p q u v x y z : E} (hz : z ∈ s
· positivity
· positivity
· rw [← add_div, div_self]; positivity
- rw [smul_add, smul_add, add_add_add_comm]
- nth_rw 2 [add_comm]
- rw [← mul_smul, ← mul_smul]
classical
let w : Fin 3 → 𝕜 := ![az * av * bu, bz * au * bv, au * av]
let z : Fin 3 → E := ![p, q, az • x + bz • y]
@@ -61,18 +58,15 @@ theorem not_disjoint_segment_convexHull_triple {p q u v x y z : E} (hz : z ∈ s
have hw : ∑ i, w i = az * av + bz * au := by
trans az * av * bu + (bz * au * bv + au * av)
· simp [w, Fin.sum_univ_succ, Fin.sum_univ_zero]
- rw [← one_mul (au * av), ← habz, add_mul, ← add_assoc, add_add_add_comm, mul_assoc, ← mul_add,
- mul_assoc, ← mul_add, mul_comm av, ← add_mul, ← mul_add, add_comm bu, add_comm bv, habu,
- habv, one_mul, mul_one]
+ linear_combination (au * bv - 1 * au) * habz + (-(1 * az * au) + au) * habv + az * av * habu
have hz : ∀ i, z i ∈ ({p, q, az • x + bz • y} : Set E) := fun i => by fin_cases i <;> simp [z]
convert (Finset.centerMass_mem_convexHull (Finset.univ : Finset (Fin 3)) (fun i _ => hw₀ i)
(by rwa [hw]) fun i _ => hz i : Finset.univ.centerMass w z ∈ _)
- rw [Finset.centerMass]
- simp_rw [div_eq_inv_mul, hw, mul_assoc, mul_smul (az * av + bz * au)⁻¹, ← smul_add, add_assoc, ←
- mul_assoc]
+ rw [Finset.centerMass, hw]
+ trans (az * av + bz * au)⁻¹ •
+ ((az * av * bu) • p + ((bz * au * bv) • q + (au * av) • (az • x + bz • y)))
+ · module
congr 3
- rw [← mul_smul, ← mul_rotate, mul_right_comm, mul_smul, ← mul_smul _ av, mul_rotate,
- mul_smul _ bz, ← smul_add]
simp only [w, z, smul_add, List.foldr, Matrix.cons_val_succ', Fin.mk_one,
Matrix.cons_val_one, Matrix.head_cons, add_zero]
diff --git a/Mathlib/Analysis/Convex/Strict.lean b/Mathlib/Analysis/Convex/Strict.lean
index da771a82ffc55..1eabcd86ec380 100644
--- a/Mathlib/Analysis/Convex/Strict.lean
+++ b/Mathlib/Analysis/Convex/Strict.lean
@@ -302,8 +302,7 @@ theorem StrictConvex.eq_of_openSegment_subset_frontier [Nontrivial 𝕜] [Densel
theorem StrictConvex.add_smul_mem (hs : StrictConvex 𝕜 s) (hx : x ∈ s) (hxy : x + y ∈ s)
(hy : y ≠ 0) {t : 𝕜} (ht₀ : 0 < t) (ht₁ : t < 1) : x + t • y ∈ interior s := by
- have h : x + t • y = (1 - t) • x + t • (x + y) := by
- rw [smul_add, ← add_assoc, ← _root_.add_smul, sub_add_cancel, one_smul]
+ have h : x + t • y = (1 - t) • x + t • (x + y) := by match_scalars <;> field_simp
rw [h]
exact hs hx hxy (fun h => hy <| add_left_cancel (a := x) (by rw [← h, add_zero]))
(sub_pos_of_lt ht₁) ht₀ (sub_add_cancel 1 t)
@@ -359,16 +358,14 @@ theorem strictConvex_iff_div :
StrictConvex 𝕜 s ↔
s.Pairwise fun x y =>
∀ ⦃a b : 𝕜⦄, 0 < a → 0 < b → (a / (a + b)) • x + (b / (a + b)) • y ∈ interior s :=
- ⟨fun h x hx y hy hxy a b ha hb => by
- apply h hx hy hxy (div_pos ha <| add_pos ha hb) (div_pos hb <| add_pos ha hb)
- rw [← add_div]
- exact div_self (add_pos ha hb).ne', fun h x hx y hy hxy a b ha hb hab => by
+ ⟨fun h x hx y hy hxy a b ha hb ↦ h hx hy hxy (by positivity) (by positivity) (by field_simp),
+ fun h x hx y hy hxy a b ha hb hab ↦ by
convert h hx hy hxy ha hb <;> rw [hab, div_one]⟩
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₀ (zero_lt_one.trans ht).ne']
- exact hs.smul_mem_of_zero_mem zero_mem hx hx₀ (inv_pos.2 <| zero_lt_one.trans ht) (inv_lt_one ht)
+ 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_of_one_lt₀ ht)
end AddCommGroup
diff --git a/Mathlib/Analysis/Convex/StrictConvexBetween.lean b/Mathlib/Analysis/Convex/StrictConvexBetween.lean
index c3bb34bd7fb30..08a6eed3ee484 100644
--- a/Mathlib/Analysis/Convex/StrictConvexBetween.lean
+++ b/Mathlib/Analysis/Convex/StrictConvexBetween.lean
@@ -58,13 +58,13 @@ theorem Collinear.wbtw_of_dist_eq_of_dist_le {p p₁ p₂ p₃ : P} {r : ℝ}
· simp [hp₃p₂]
have hs : Sbtw ℝ p₂ p₃ p₁ := ⟨hw, hp₃p₂, hp₁p₃.symm⟩
have hs' := hs.dist_lt_max_dist p
- rw [hp₁, hp₃, lt_max_iff, lt_self_iff_false, or_false_iff] at hs'
+ rw [hp₁, hp₃, lt_max_iff, lt_self_iff_false, or_false] at hs'
exact False.elim (hp₂.not_lt hs')
· by_cases hp₁p₂ : p₁ = p₂
· simp [hp₁p₂]
have hs : Sbtw ℝ p₃ p₁ p₂ := ⟨hw, hp₁p₃, hp₁p₂⟩
have hs' := hs.dist_lt_max_dist p
- rw [hp₁, hp₃, lt_max_iff, lt_self_iff_false, false_or_iff] at hs'
+ rw [hp₁, hp₃, lt_max_iff, lt_self_iff_false, false_or] at hs'
exact False.elim (hp₂.not_lt hs')
/-- Given three collinear points, two (not equal) with distance `r` from `p` and one with
diff --git a/Mathlib/Analysis/Convex/StrictConvexSpace.lean b/Mathlib/Analysis/Convex/StrictConvexSpace.lean
index 80a4039dba35a..32a1cef9cd3a9 100644
--- a/Mathlib/Analysis/Convex/StrictConvexSpace.lean
+++ b/Mathlib/Analysis/Convex/StrictConvexSpace.lean
@@ -4,10 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies, Yury Kudryashov
-/
import Mathlib.Analysis.Convex.Normed
-import Mathlib.Analysis.Convex.Strict
-import Mathlib.Analysis.Normed.Order.Basic
-import Mathlib.Analysis.Normed.Affine.AddTorsor
-import Mathlib.Analysis.NormedSpace.Pointwise
import Mathlib.Analysis.Normed.Module.Ray
/-!
@@ -208,5 +204,5 @@ theorem not_sameRay_iff_abs_lt_norm_sub : ¬SameRay ℝ x y ↔ |‖x‖ - ‖y
theorem norm_midpoint_lt_iff (h : ‖x‖ = ‖y‖) : ‖(1 / 2 : ℝ) • (x + y)‖ < ‖x‖ ↔ x ≠ y := by
rw [norm_smul, Real.norm_of_nonneg (one_div_nonneg.2 zero_le_two), ← inv_eq_one_div, ←
- div_eq_inv_mul, div_lt_iff (zero_lt_two' ℝ), mul_two, ← not_sameRay_iff_of_norm_eq h,
+ div_eq_inv_mul, div_lt_iff₀ (zero_lt_two' ℝ), mul_two, ← not_sameRay_iff_of_norm_eq h,
not_sameRay_iff_norm_add_lt, h]
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/Topology.lean b/Mathlib/Analysis/Convex/Topology.lean
index 312786bb4c364..c6d92df1bdcf2 100644
--- a/Mathlib/Analysis/Convex/Topology.lean
+++ b/Mathlib/Analysis/Convex/Topology.lean
@@ -26,9 +26,20 @@ open Metric Bornology Set Pointwise Convex
variable {ι 𝕜 E : Type*}
-theorem Real.convex_iff_isPreconnected {s : Set ℝ} : Convex ℝ s ↔ IsPreconnected s :=
+namespace Real
+variable {s : Set ℝ} {r ε : ℝ}
+
+lemma closedBall_eq_segment (hε : 0 ≤ ε) : closedBall r ε = segment ℝ (r - ε) (r + ε) := by
+ rw [closedBall_eq_Icc, segment_eq_Icc ((sub_le_self _ hε).trans <| le_add_of_nonneg_right hε)]
+
+lemma ball_eq_openSegment (hε : 0 < ε) : ball r ε = openSegment ℝ (r - ε) (r + ε) := by
+ rw [ball_eq_Ioo, openSegment_eq_Ioo ((sub_lt_self _ hε).trans <| lt_add_of_pos_right _ hε)]
+
+theorem convex_iff_isPreconnected : Convex ℝ s ↔ IsPreconnected s :=
convex_iff_ordConnected.trans isPreconnected_iff_ordConnected.symm
+end Real
+
alias ⟨_, IsPreconnected.convex⟩ := Real.convex_iff_isPreconnected
/-! ### Standard simplex -/
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 4b2168a084049..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
@@ -1031,10 +1031,10 @@ theorem hasFDerivAt_convolution_right_with_param {g : P → G → E'} {s : Set P
let g' := fderiv 𝕜 ↿g
have A : ∀ p ∈ s, Continuous (g p) := fun p hp ↦ by
refine hg.continuousOn.comp_continuous (continuous_const.prod_mk continuous_id') fun x => ?_
- simpa only [prod_mk_mem_set_prod_eq, mem_univ, and_true_iff] using hp
+ simpa only [prod_mk_mem_set_prod_eq, mem_univ, and_true] using hp
have A' : ∀ q : P × G, q.1 ∈ s → s ×ˢ univ ∈ 𝓝 q := fun q hq ↦ by
apply (hs.prod isOpen_univ).mem_nhds
- simpa only [mem_prod, mem_univ, and_true_iff] using hq
+ simpa only [mem_prod, mem_univ, and_true] using hq
-- The derivative of `g` vanishes away from `k`.
have g'_zero : ∀ p x, p ∈ s → x ∉ k → g' (p, x) = 0 := by
intro p x hp hx
@@ -1055,7 +1055,7 @@ theorem hasFDerivAt_convolution_right_with_param {g : P → G → E'} {s : Set P
hg.continuousOn_fderiv_of_isOpen (hs.prod isOpen_univ) le_rfl
apply exists_isOpen_isBounded_image_of_isCompact_of_continuousOn A (hs.prod isOpen_univ) _ B
simp only [prod_subset_prod_iff, hq₀, singleton_subset_iff, subset_univ, and_self_iff,
- true_or_iff]
+ true_or]
obtain ⟨ε, εpos, hε, h'ε⟩ :
∃ ε : ℝ, 0 < ε ∧ thickening ε ({q₀.fst} ×ˢ k) ⊆ t ∧ ball q₀.1 ε ⊆ s := by
obtain ⟨ε, εpos, hε⟩ : ∃ ε : ℝ, 0 < ε ∧ thickening ε (({q₀.fst} : Set P) ×ˢ k) ⊆ t :=
@@ -1071,10 +1071,10 @@ theorem hasFDerivAt_convolution_right_with_param {g : P → G → E'} {s : Set P
· have H : (p, x) ∈ t := by
apply hε
refine mem_thickening_iff.2 ⟨(q₀.1, x), ?_, ?_⟩
- · simp only [hx, singleton_prod, mem_image, Prod.mk.inj_iff, eq_self_iff_true, true_and_iff,
+ · simp only [hx, singleton_prod, mem_image, Prod.mk.inj_iff, eq_self_iff_true, true_and,
exists_eq_right]
· rw [← dist_eq_norm] at hp
- simpa only [Prod.dist_eq, εpos, dist_self, max_lt_iff, and_true_iff] using hp
+ simpa only [Prod.dist_eq, εpos, dist_self, max_lt_iff, and_true] using hp
have : g' (p, x) ∈ closedBall (0 : P × G →L[𝕜] E') C := hC (mem_image_of_mem _ H)
rwa [mem_closedBall_zero_iff] at this
· have : g' (p, x) = 0 := g'_zero _ _ hps hx
@@ -1102,7 +1102,7 @@ theorem hasFDerivAt_convolution_right_with_param {g : P → G → E'} {s : Set P
hg.continuousOn_fderiv_of_isOpen (hs.prod isOpen_univ) le_rfl
apply this.comp_continuous (continuous_const.prod_mk continuous_id')
intro x
- simpa only [prod_mk_mem_set_prod_eq, mem_univ, and_true_iff] using hq₀
+ simpa only [prod_mk_mem_set_prod_eq, mem_univ, and_true] using hq₀
set K' := (-k + {q₀.2} : Set G) with K'_def
have hK' : IsCompact K' := hk.neg.add isCompact_singleton
obtain ⟨U, U_open, K'U, hU⟩ : ∃ U, IsOpen U ∧ K' ⊆ U ∧ IntegrableOn f U μ :=
@@ -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
@@ -1251,12 +1251,12 @@ theorem contDiffOn_convolution_right_with_param {f : G → E} {n : ℕ∞} (L :
apply hg.comp (isoP.prod isoG).contDiff.contDiffOn
rintro ⟨p, x⟩ ⟨hp, -⟩
simpa only [mem_preimage, ContinuousLinearEquiv.prod_apply, prod_mk_mem_set_prod_eq, mem_univ,
- and_true_iff] using hp
+ and_true] using hp
have A : ContDiffOn 𝕜 n (isoF ∘ R ∘ (isoP.prod isoG).symm) (s ×ˢ univ) := by
apply isoF.contDiff.comp_contDiffOn
apply R_contdiff.comp (ContinuousLinearEquiv.contDiff _).contDiffOn
rintro ⟨p, x⟩ ⟨hp, -⟩
- simpa only [mem_preimage, mem_prod, mem_univ, and_true_iff, ContinuousLinearEquiv.prod_symm,
+ simpa only [mem_preimage, mem_prod, mem_univ, and_true, ContinuousLinearEquiv.prod_symm,
ContinuousLinearEquiv.prod_apply, ContinuousLinearEquiv.apply_symm_apply] using hp
have : isoF ∘ R ∘ (isoP.prod isoG).symm = fun q : P × G => (f ⋆[L, μ] g q.1) q.2 := by
apply funext
@@ -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 73c009395f7d1..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
@@ -533,7 +529,7 @@ theorem _root_.Function.HasTemperateGrowth.norm_iteratedFDeriv_le_uniform_aux {f
choose k C f using hf_temperate.2
use (Finset.range (n + 1)).sup k
let C' := max (0 : ℝ) ((Finset.range (n + 1)).sup' (by simp) C)
- have hC' : 0 ≤ C' := by simp only [C', le_refl, Finset.le_sup'_iff, true_or_iff, le_max_iff]
+ have hC' : 0 ≤ C' := by simp only [C', le_refl, Finset.le_sup'_iff, true_or, le_max_iff]
use C', hC'
intro N hN x
rw [← Finset.mem_range_succ_iff] at hN
@@ -575,11 +571,11 @@ lemma _root_.ContinuousLinearMap.hasTemperateGrowth (f : E →L[ℝ] F) :
variable [NormedAddCommGroup D] [MeasurableSpace D]
-open MeasureTheory FiniteDimensional
+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
@@ -616,7 +612,7 @@ lemma pow_mul_le_of_le_of_pow_mul_le {C₁ C₂ : ℝ} {k l : ℕ} {x f : ℝ} (
rw [this]
rcases le_total x 1 with h'x|h'x
· gcongr
- · apply (pow_le_one k hx h'x).trans
+ · apply (pow_le_one₀ hx h'x).trans
apply Real.one_le_rpow_of_pos_of_le_one_of_nonpos
· linarith
· linarith
@@ -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. -/
@@ -854,7 +848,7 @@ def compCLM {g : D → E} (hg : g.HasTemperateGrowth)
refine add_le_add ?_ (hg_upper' x)
nth_rw 1 [← one_mul (1 : ℝ)]
gcongr
- apply one_le_pow_of_one_le
+ apply one_le_pow₀
simp only [le_add_iff_nonneg_right, norm_nonneg]
have hbound :
∀ i, i ≤ n → ‖iteratedFDeriv ℝ i f (g x)‖ ≤ 2 ^ k' * seminorm_f / (1 + ‖g x‖) ^ k' := by
@@ -870,8 +864,8 @@ def compCLM {g : D → E} (hg : g.HasTemperateGrowth)
rw [mul_pow]
have hN₁' := (lt_of_lt_of_le zero_lt_one hN₁).ne'
gcongr
- · exact le_trans (by simp [hC]) (le_self_pow (by simp [hC]) hN₁')
- · refine le_self_pow (one_le_pow_of_one_le ?_ l) hN₁'
+ · exact le_trans (by simp [hC]) (le_self_pow₀ (by simp [hC]) hN₁')
+ · refine le_self_pow₀ (one_le_pow₀ ?_) hN₁'
simp only [le_add_iff_nonneg_right, norm_nonneg]
have := norm_iteratedFDeriv_comp_le f.smooth' hg.1 le_top x hbound hgrowth'
have hxk : ‖x‖ ^ k ≤ (1 + ‖x‖) ^ k :=
@@ -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
@@ -1036,7 +1030,7 @@ section Integration
/-! ### Integration -/
-open Real Complex Filter MeasureTheory MeasureTheory.Measure FiniteDimensional
+open Real Complex Filter MeasureTheory MeasureTheory.Measure Module
variable [RCLike 𝕜]
variable [NormedAddCommGroup D] [NormedSpace ℝ D]
@@ -1182,7 +1176,7 @@ instance instZeroAtInftyContinuousMapClass : ZeroAtInftyContinuousMapClass 𝓢(
intro ε hε
use (SchwartzMap.seminorm ℝ 1 0) f / ε
intro x hx
- rw [div_lt_iff hε] at hx
+ rw [div_lt_iff₀ hε] at hx
have hxpos : 0 < ‖x‖ := by
rw [norm_pos_iff']
intro hxzero
@@ -1191,7 +1185,7 @@ instance instZeroAtInftyContinuousMapClass : ZeroAtInftyContinuousMapClass 𝓢(
have := norm_pow_mul_le_seminorm ℝ f 1 x
rw [pow_one, ← le_div_iff₀' hxpos] at this
apply lt_of_le_of_lt this
- rwa [div_lt_iff' hxpos]
+ rwa [div_lt_iff₀' hxpos]
/-- Schwartz functions as continuous functions vanishing at infinity. -/
def toZeroAtInfty (f : 𝓢(E, F)) : C₀(E, F) where
diff --git a/Mathlib/Analysis/Fourier/AddCircle.lean b/Mathlib/Analysis/Fourier/AddCircle.lean
index 86ac394b06e8d..6a5971c612314 100644
--- a/Mathlib/Analysis/Fourier/AddCircle.lean
+++ b/Mathlib/Analysis/Fourier/AddCircle.lean
@@ -10,7 +10,7 @@ import Mathlib.MeasureTheory.Function.ContinuousMapDense
import Mathlib.MeasureTheory.Function.L2Space
import Mathlib.MeasureTheory.Group.Integral
import Mathlib.MeasureTheory.Integral.Periodic
-import Mathlib.Topology.ContinuousFunction.StoneWeierstrass
+import Mathlib.Topology.ContinuousMap.StoneWeierstrass
import Mathlib.MeasureTheory.Integral.FundThmCalculus
/-!
@@ -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/FourierTransformDeriv.lean b/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean
index 8f2eedfc69969..0fbe303edbe46 100644
--- a/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean
+++ b/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean
@@ -327,8 +327,7 @@ lemma norm_fourierPowSMulRight_le (f : V → E) (v : V) (n : ℕ) :
simp [_root_.abs_of_nonneg pi_nonneg, norm_smul]
_ ≤ (2 * π) ^ n * ((∏ x : Fin n, ‖L‖ * ‖v‖ * ‖m x‖) * ‖f v‖) := by
gcongr with i _hi
- · exact fun i _hi ↦ abs_nonneg _
- · exact L.le_opNorm₂ v (m i)
+ exact L.le_opNorm₂ v (m i)
_ = (2 * π * ‖L‖) ^ n * ‖v‖ ^ n * ‖f v‖ * ∏ i : Fin n, ‖m i‖ := by
simp [Finset.prod_mul_distrib, mul_pow]; ring
@@ -414,7 +413,7 @@ lemma norm_iteratedFDeriv_fourierPowSMulRight
· rw [← Nat.cast_pow, Nat.cast_le]
calc n.descFactorial i ≤ n ^ i := Nat.descFactorial_le_pow _ _
_ ≤ (n + 1) ^ i := pow_le_pow_left (by omega) (by omega) i
- _ ≤ (n + 1) ^ k := pow_le_pow_right (by omega) (Finset.mem_range_succ_iff.mp hi)
+ _ ≤ (n + 1) ^ k := pow_right_mono₀ (by omega) (Finset.mem_range_succ_iff.mp hi)
· exact hv _ (by omega) _ (by omega)
_ = (2 * n + 2) ^ k * (‖L‖^n * C) := by
simp only [← Finset.sum_mul, ← Nat.cast_sum, Nat.sum_range_choose, mul_one, ← mul_assoc,
@@ -448,7 +447,7 @@ lemma hasFTaylorSeriesUpTo_fourierIntegral {N : ℕ∞}
(fun w n ↦ fourierIntegral 𝐞 μ L.toLinearMap₂ (fun v ↦ fourierPowSMulRight L f v n) w) := by
constructor
· intro w
- rw [uncurry0_apply, Matrix.zero_empty, fourierIntegral_continuousMultilinearMap_apply'
+ rw [curry0_apply, Matrix.zero_empty, fourierIntegral_continuousMultilinearMap_apply'
(integrable_fourierPowSMulRight L (hf 0 bot_le) h'f)]
simp only [fourierPowSMulRight_apply, pow_zero, Finset.univ_eq_empty, Finset.prod_empty,
one_smul]
@@ -628,7 +627,7 @@ lemma pow_mul_norm_iteratedFDeriv_fourierIntegral_le [FiniteDimensional ℝ V]
_ ≤ (2 * π) ^ n
* (|L v w| ^ n * ‖iteratedFDeriv ℝ k (fourierIntegral 𝐞 μ L.toLinearMap₂ f) w‖) := by
apply le_mul_of_one_le_left (by positivity)
- apply one_le_pow_of_one_le
+ apply one_le_pow₀
linarith [one_le_pi_div_two]
_ = ‖fourierPowSMulRight (-L.flip)
(iteratedFDeriv ℝ k (fourierIntegral 𝐞 μ L.toLinearMap₂ f)) w n (fun _ ↦ v)‖ := by
diff --git a/Mathlib/Analysis/Fourier/Inversion.lean b/Mathlib/Analysis/Fourier/Inversion.lean
index cea8c2f5ade12..158aae8391b20 100644
--- a/Mathlib/Analysis/Fourier/Inversion.lean
+++ b/Mathlib/Analysis/Fourier/Inversion.lean
@@ -37,7 +37,7 @@ To check the concentration property of the middle factor and the fact that it ha
rely on the explicit computation of the Fourier transform of Gaussians.
-/
-open Filter MeasureTheory Complex FiniteDimensional Metric Real Bornology
+open Filter MeasureTheory Complex Module Metric Real Bornology
open scoped Topology FourierTransform RealInnerProductSpace Complex
diff --git a/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean b/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean
index e3095be779ad6..1531edb4f4be0 100644
--- a/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean
+++ b/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean
@@ -11,6 +11,7 @@ import Mathlib.MeasureTheory.Group.Integral
import Mathlib.MeasureTheory.Integral.SetIntegral
import Mathlib.Topology.EMetricSpace.Paracompact
import Mathlib.MeasureTheory.Measure.Haar.Unique
+import Mathlib.Topology.Algebra.Module.WeakDual
/-!
# The Riemann-Lebesgue Lemma
@@ -44,7 +45,7 @@ equivalence to an inner-product space.
noncomputable section
-open MeasureTheory Filter Complex Set FiniteDimensional
+open MeasureTheory Filter Complex Set Module
open scoped Filter Topology Real ENNReal FourierTransform RealInnerProductSpace NNReal
@@ -139,7 +140,7 @@ theorem tendsto_integral_exp_inner_smul_cocompact_of_continuous_compact_support
have : ‖(1 / 2 : ℂ)‖ = 2⁻¹ := by norm_num
rw [fourierIntegral_eq_half_sub_half_period_translate hw_ne
(hf1.integrable_of_hasCompactSupport hf2),
- norm_smul, this, inv_mul_eq_div, div_lt_iff' two_pos]
+ norm_smul, this, inv_mul_eq_div, div_lt_iff₀' two_pos]
refine lt_of_le_of_lt (norm_integral_le_integral_norm _) ?_
simp_rw [Circle.norm_smul]
--* Show integral can be taken over A only.
@@ -163,8 +164,8 @@ theorem tendsto_integral_exp_inner_smul_cocompact_of_continuous_compact_support
simp_rw [norm_norm]
simp_rw [dist_eq_norm] at hδ2
refine fun x _ => (hδ2 ?_).le
- rw [sub_add_cancel_left, norm_neg, hw'_nm, ← div_div, div_lt_iff (norm_pos_iff.mpr hw_ne), ←
- div_lt_iff' hδ1, div_div]
+ rw [sub_add_cancel_left, norm_neg, hw'_nm, ← div_div, div_lt_iff₀ (norm_pos_iff.mpr hw_ne), ←
+ div_lt_iff₀' hδ1, div_div]
exact (lt_add_of_pos_left _ one_half_pos).trans_le hw_bd
have bdA2 := norm_setIntegral_le_of_norm_le_const (hB_vol.trans_lt ENNReal.coe_lt_top) bdA ?_
swap
@@ -176,7 +177,7 @@ theorem tendsto_integral_exp_inner_smul_cocompact_of_continuous_compact_support
Real.norm_of_nonneg (setIntegral_nonneg mA fun x _ => norm_nonneg _)
rw [this] at bdA2
refine bdA2.trans_lt ?_
- rw [div_mul_eq_mul_div, div_lt_iff (NNReal.coe_pos.mpr hB_pos), mul_comm (2 : ℝ), mul_assoc,
+ rw [div_mul_eq_mul_div, div_lt_iff₀ (NNReal.coe_pos.mpr hB_pos), mul_comm (2 : ℝ), mul_assoc,
mul_lt_mul_left hε]
rw [← ENNReal.toReal_le_toReal] at hB_vol
· refine hB_vol.trans_lt ?_
diff --git a/Mathlib/Analysis/Fourier/ZMod.lean b/Mathlib/Analysis/Fourier/ZMod.lean
index e817057d937c2..ae3c4f996bbcc 100644
--- a/Mathlib/Analysis/Fourier/ZMod.lean
+++ b/Mathlib/Analysis/Fourier/ZMod.lean
@@ -3,6 +3,7 @@ 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.EvenFunction
import Mathlib.Analysis.SpecialFunctions.Complex.CircleAddChar
import Mathlib.Analysis.Fourier.FourierTransform
import Mathlib.NumberTheory.DirichletCharacter.GaussSum
@@ -177,13 +178,32 @@ lemma dft_comp_unitMul (Φ : ZMod N → E) (u : (ZMod N)ˣ) (k : ZMod N) :
refine Fintype.sum_equiv u.mulLeft _ _ fun x ↦ ?_
simp only [mul_comm u.val, u.mulLeft_apply, ← mul_assoc, u.mul_inv_cancel_right]
+section signs
+
+/-- The discrete Fourier transform of `Φ` is even if and only if `Φ` itself is. -/
+lemma dft_even_iff {Φ : ZMod N → ℂ} : (𝓕 Φ).Even ↔ Φ.Even := by
+ have h {f : ZMod N → ℂ} (hf : f.Even) : (𝓕 f).Even := by
+ simp only [Function.Even, ← congr_fun (dft_comp_neg f), funext hf, implies_true]
+ refine ⟨fun hΦ x ↦ ?_, h⟩
+ simpa only [neg_neg, smul_right_inj (NeZero.ne (N : ℂ)), dft_dft] using h hΦ (-x)
+
+/-- The discrete Fourier transform of `Φ` is odd if and only if `Φ` itself is. -/
+lemma dft_odd_iff {Φ : ZMod N → ℂ} : (𝓕 Φ).Odd ↔ Φ.Odd := by
+ have h {f : ZMod N → ℂ} (hf : f.Odd) : (𝓕 f).Odd := by
+ simp only [Function.Odd, ← congr_fun (dft_comp_neg f), funext hf, ← Pi.neg_apply, map_neg,
+ implies_true]
+ refine ⟨fun hΦ x ↦ ?_, h⟩
+ simpa only [neg_neg, dft_dft, ← smul_neg, smul_right_inj (NeZero.ne (N : ℂ))] using h hΦ (-x)
+
+end signs
+
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
@@ -191,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 6b402f751dabd..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
@@ -349,7 +349,7 @@ theorem lintegral_pow_le_pow_lintegral_fderiv_aux [Fintype ι]
variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [MeasurableSpace E] [BorelSpace E]
[FiniteDimensional ℝ E] (μ : Measure E) [IsAddHaarMeasure μ]
-open FiniteDimensional
+open Module
/-- The constant factor occurring in the conclusion of `lintegral_pow_le_pow_lintegral_fderiv`.
It only depends on `E`, `μ` and `p`.
@@ -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 f2d58902381c5..6862b4376ce2a 100644
--- a/Mathlib/Analysis/InnerProductSpace/Basic.lean
+++ b/Mathlib/Analysis/InnerProductSpace/Basic.lean
@@ -82,7 +82,7 @@ class Inner (𝕜 E : Type*) where
export Inner (inner)
/-- The inner product with values in `𝕜`. -/
-notation3:max "⟪" x ", " y "⟫_" 𝕜:max => @inner 𝕜 _ _ x y
+scoped[InnerProductSpace] notation3:max "⟪" x ", " y "⟫_" 𝕜:max => @inner 𝕜 _ _ x y
section Notations
@@ -447,7 +447,7 @@ theorem inner_self_eq_zero {x : F} : ⟪x, x⟫ = 0 ↔ x = 0 :=
theorem normSq_eq_zero {x : F} : normSqF x = 0 ↔ x = 0 :=
Iff.trans
- (by simp only [normSq, ext_iff, map_zero, inner_self_im, eq_self_iff_true, and_true_iff])
+ (by simp only [normSq, ext_iff, map_zero, inner_self_im, eq_self_iff_true, and_true])
(@inner_self_eq_zero 𝕜 _ _ _ _ _ x)
theorem inner_self_ne_zero {x : F} : ⟪x, x⟫ ≠ 0 ↔ x ≠ 0 :=
@@ -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
@@ -508,9 +508,10 @@ end
/-! ### Properties of inner product spaces -/
-
section BasicProperties_Seminormed
+open scoped InnerProductSpace
+
variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E]
variable [SeminormedAddCommGroup F] [InnerProductSpace ℝ F]
@@ -547,8 +548,30 @@ theorem inner_re_symm (x y : E) : re ⟪x, y⟫ = re ⟪y, x⟫ := by rw [← in
theorem inner_im_symm (x y : E) : im ⟪x, y⟫ = -im ⟪y, x⟫ := by rw [← inner_conj_symm, conj_im]
+section Algebra
+variable {𝕝 : Type*} [CommSemiring 𝕝] [StarRing 𝕝] [Algebra 𝕝 𝕜] [Module 𝕝 E]
+ [IsScalarTower 𝕝 𝕜 E] [StarModule 𝕝 𝕜]
+
+/-- See `inner_smul_left` for the common special when `𝕜 = 𝕝`. -/
+lemma inner_smul_left_eq_star_smul (x y : E) (r : 𝕝) : ⟪r • x, y⟫ = r† • ⟪x, y⟫ := by
+ rw [← algebraMap_smul 𝕜 r, InnerProductSpace.smul_left, starRingEnd_apply, starRingEnd_apply,
+ ← algebraMap_star_comm, ← smul_eq_mul, algebraMap_smul]
+
+/-- Special case of `inner_smul_left_eq_star_smul` when the acting ring has a trivial star
+(eg `ℕ`, `ℤ`, `ℚ≥0`, `ℚ`, `ℝ`). -/
+lemma inner_smul_left_eq_smul [TrivialStar 𝕝] (x y : E) (r : 𝕝) : ⟪r • x, y⟫ = r • ⟪x, y⟫ := by
+ rw [inner_smul_left_eq_star_smul, starRingEnd_apply, star_trivial]
+
+/-- See `inner_smul_right` for the common special when `𝕜 = 𝕝`. -/
+lemma inner_smul_right_eq_smul (x y : E) (r : 𝕝) : ⟪x, r • y⟫ = r • ⟪x, y⟫ := by
+ rw [← inner_conj_symm, inner_smul_left_eq_star_smul, starRingEnd_apply, starRingEnd_apply,
+ star_smul, star_star, ← starRingEnd_apply, inner_conj_symm]
+
+end Algebra
+
+/-- See `inner_smul_left_eq_star_smul` for the case of a general algebra action. -/
theorem inner_smul_left (x y : E) (r : 𝕜) : ⟪r • x, y⟫ = r† * ⟪x, y⟫ :=
- InnerProductSpace.smul_left _ _ _
+ inner_smul_left_eq_star_smul ..
theorem real_inner_smul_left (x y : F) (r : ℝ) : ⟪r • x, y⟫_ℝ = r * ⟪x, y⟫_ℝ :=
inner_smul_left _ _ _
@@ -556,8 +579,9 @@ theorem real_inner_smul_left (x y : F) (r : ℝ) : ⟪r • x, y⟫_ℝ = r *
theorem inner_smul_real_left (x y : E) (r : ℝ) : ⟪(r : 𝕜) • x, y⟫ = r • ⟪x, y⟫ := by
rw [inner_smul_left, conj_ofReal, Algebra.smul_def]
-theorem inner_smul_right (x y : E) (r : 𝕜) : ⟪x, r • y⟫ = r * ⟪x, y⟫ := by
- rw [← inner_conj_symm, inner_smul_left, RingHom.map_mul, conj_conj, inner_conj_symm]
+/-- See `inner_smul_right_eq_smul` for the case of a general algebra action. -/
+theorem inner_smul_right (x y : E) (r : 𝕜) : ⟪x, r • y⟫ = r * ⟪x, y⟫ :=
+ inner_smul_right_eq_smul ..
theorem real_inner_smul_right (x y : F) (r : ℝ) : ⟪x, r • y⟫_ℝ = r * ⟪x, y⟫_ℝ :=
inner_smul_right _ _ _
@@ -754,6 +778,7 @@ variable {𝕜}
theorem inner_self_nonpos {x : E} : re ⟪x, x⟫ ≤ 0 ↔ x = 0 := by
rw [← norm_sq_eq_inner, (sq_nonneg _).le_iff_eq, sq_eq_zero_iff, norm_eq_zero]
+open scoped InnerProductSpace in
theorem real_inner_self_nonpos {x : F} : ⟪x, x⟫_ℝ ≤ 0 ↔ x = 0 :=
@inner_self_nonpos ℝ F _ _ _ x
@@ -988,7 +1013,7 @@ theorem exists_maximal_orthonormal {s : Set E} (hs : Orthonormal 𝕜 (Subtype.v
· exact orthonormal_sUnion_of_directed cc.directedOn fun x xc => hc xc
· exact fun _ => Set.subset_sUnion_of_mem
-open FiniteDimensional
+open Module
/-- A family of orthonormal vectors with the correct cardinality forms a basis. -/
def basisOfOrthonormalOfCardEqFinrank [Fintype ι] [Nonempty ι] {v : ι → E} (hv : Orthonormal 𝕜 v)
@@ -1001,30 +1026,17 @@ theorem coe_basisOfOrthonormalOfCardEqFinrank [Fintype ι] [Nonempty ι] {v : ι
(basisOfOrthonormalOfCardEqFinrank hv card_eq : ι → E) = v :=
coe_basisOfLinearIndependentOfCardEqFinrank _ _
-end OrthonormalSets_Seminormed
-
-section OrthonormalSets
-
-variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
-variable [NormedAddCommGroup F] [InnerProductSpace ℝ F]
-variable {ι : Type*}
-
-local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y
-
-local notation "IK" => @RCLike.I 𝕜 _
-
-local postfix:90 "†" => starRingEnd _
-
theorem Orthonormal.ne_zero {v : ι → E} (hv : Orthonormal 𝕜 v) (i : ι) : v i ≠ 0 := by
- have : ‖v i‖ ≠ 0 := by
- rw [hv.1 i]
- norm_num
- simpa using this
+ refine ne_of_apply_ne norm ?_
+ rw [hv.1 i, norm_zero]
+ norm_num
-end OrthonormalSets
+end OrthonormalSets_Seminormed
section Norm_Seminormed
+open scoped InnerProductSpace
+
variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E]
variable [SeminormedAddCommGroup F] [InnerProductSpace ℝ F]
@@ -1194,9 +1206,9 @@ instance (priority := 100) InnerProductSpace.toUniformConvexSpace : UniformConve
ring_nf
exact sub_le_sub_left (pow_le_pow_left hε.le hxy _) 4⟩
-section Complex
+section Complex_Seminormed
-variable {V : Type*} [NormedAddCommGroup V] [InnerProductSpace ℂ V]
+variable {V : Type*} [SeminormedAddCommGroup V] [InnerProductSpace ℂ V]
/-- A complex polarization identity, with a linear map
-/
@@ -1222,6 +1234,12 @@ theorem inner_map_polarization' (T : V →ₗ[ℂ] V) (x y : V) :
mul_add, ← mul_assoc, mul_neg, neg_neg, sub_neg_eq_add, one_mul, neg_one_mul, mul_sub, sub_sub]
ring
+end Complex_Seminormed
+
+section Complex
+
+variable {V : Type*} [NormedAddCommGroup V] [InnerProductSpace ℂ V]
+
/-- A linear map `T` is zero, if and only if the identity `⟪T x, x⟫_ℂ = 0` holds for all `x`.
-/
theorem inner_map_self_eq_zero (T : V →ₗ[ℂ] V) : (∀ x : V, ⟪T x, x⟫_ℂ = 0) ↔ T = 0 := by
@@ -1477,7 +1495,7 @@ theorem norm_sub_eq_norm_add {v w : E} (h : ⟪v, w⟫ = 0) : ‖w - v‖ = ‖w
norms, has absolute value at most 1. -/
theorem abs_real_inner_div_norm_mul_norm_le_one (x y : F) : |⟪x, y⟫_ℝ / (‖x‖ * ‖y‖)| ≤ 1 := by
rw [abs_div, abs_mul, abs_norm, abs_norm]
- exact div_le_one_of_le (abs_real_inner_le_norm x y) (by positivity)
+ exact div_le_one_of_le₀ (abs_real_inner_le_norm x y) (by positivity)
/-- The inner product of a vector with a multiple of itself. -/
theorem real_inner_smul_self_left (x : F) (r : ℝ) : ⟪r • x, x⟫_ℝ = r * (‖x‖ * ‖x‖) := by
@@ -1547,7 +1565,7 @@ variable {𝕜}
namespace ContinuousLinearMap
-variable {E' : Type*} [NormedAddCommGroup E'] [InnerProductSpace 𝕜 E']
+variable {E' : Type*} [SeminormedAddCommGroup E'] [InnerProductSpace 𝕜 E']
-- Note: odd and expensive build behavior is explicitly turned off using `noncomputable`
/-- Given `f : E →L[𝕜] E'`, construct the continuous sesquilinear form `fun x y ↦ ⟪x, A y⟫`, given
@@ -1572,10 +1590,89 @@ theorem toSesqForm_apply_norm_le {f : E →L[𝕜] E'} {v : E'} : ‖toSesqForm
end ContinuousLinearMap
+section
+
+variable {ι : Type*} {ι' : Type*} {ι'' : Type*}
+variable {E' : Type*} [SeminormedAddCommGroup E'] [InnerProductSpace 𝕜 E']
+variable {E'' : Type*} [SeminormedAddCommGroup E''] [InnerProductSpace 𝕜 E'']
+
+@[simp]
+theorem Orthonormal.equiv_refl {v : Basis ι 𝕜 E} (hv : Orthonormal 𝕜 v) :
+ hv.equiv hv (Equiv.refl ι) = LinearIsometryEquiv.refl 𝕜 E :=
+ v.ext_linearIsometryEquiv fun i => by
+ simp only [Orthonormal.equiv_apply, Equiv.coe_refl, id, LinearIsometryEquiv.coe_refl]
+
+@[simp]
+theorem Orthonormal.equiv_symm {v : Basis ι 𝕜 E} (hv : Orthonormal 𝕜 v) {v' : Basis ι' 𝕜 E'}
+ (hv' : Orthonormal 𝕜 v') (e : ι ≃ ι') : (hv.equiv hv' e).symm = hv'.equiv hv e.symm :=
+ v'.ext_linearIsometryEquiv fun i =>
+ (hv.equiv hv' e).injective <| by
+ simp only [LinearIsometryEquiv.apply_symm_apply, Orthonormal.equiv_apply, e.apply_symm_apply]
+
+end
+
+variable (𝕜)
+
+/-- `innerSL` is an isometry. Note that the associated `LinearIsometry` is defined in
+`InnerProductSpace.Dual` as `toDualMap`. -/
+@[simp]
+theorem innerSL_apply_norm (x : E) : ‖innerSL 𝕜 x‖ = ‖x‖ := by
+ refine
+ le_antisymm ((innerSL 𝕜 x).opNorm_le_bound (norm_nonneg _) fun y => norm_inner_le_norm _ _) ?_
+ rcases (norm_nonneg x).eq_or_gt with (h | h)
+ · simp [h]
+ · refine (mul_le_mul_right h).mp ?_
+ calc
+ ‖x‖ * ‖x‖ = ‖(⟪x, x⟫ : 𝕜)‖ := by
+ rw [← sq, inner_self_eq_norm_sq_to_K, norm_pow, norm_ofReal, abs_norm]
+ _ ≤ ‖innerSL 𝕜 x‖ * ‖x‖ := (innerSL 𝕜 x).le_opNorm _
+
+lemma norm_innerSL_le : ‖innerSL 𝕜 (E := E)‖ ≤ 1 :=
+ ContinuousLinearMap.opNorm_le_bound _ zero_le_one (by simp)
+
+variable {𝕜}
+
+/-- When an inner product space `E` over `𝕜` is considered as a real normed space, its inner
+product satisfies `IsBoundedBilinearMap`.
+
+In order to state these results, we need a `NormedSpace ℝ E` instance. We will later establish
+such an instance by restriction-of-scalars, `InnerProductSpace.rclikeToReal 𝕜 E`, but this
+instance may be not definitionally equal to some other “natural” instance. So, we assume
+`[NormedSpace ℝ E]`.
+-/
+theorem _root_.isBoundedBilinearMap_inner [NormedSpace ℝ E] [IsScalarTower ℝ 𝕜 E] :
+ IsBoundedBilinearMap ℝ fun p : E × E => ⟪p.1, p.2⟫ :=
+ { add_left := inner_add_left
+ smul_left := fun r x y => by
+ simp only [← algebraMap_smul 𝕜 r x, algebraMap_eq_ofReal, inner_smul_real_left]
+ add_right := inner_add_right
+ smul_right := fun r x y => by
+ simp only [← algebraMap_smul 𝕜 r y, algebraMap_eq_ofReal, inner_smul_real_right]
+ bound :=
+ ⟨1, zero_lt_one, fun x y => by
+ rw [one_mul]
+ exact norm_inner_le_norm x y⟩ }
+
+/-- The inner product of two weighted sums, where the weights in each
+sum add to 0, in terms of the norms of pairwise differences. -/
+theorem inner_sum_smul_sum_smul_of_sum_eq_zero {ι₁ : Type*} {s₁ : Finset ι₁} {w₁ : ι₁ → ℝ}
+ (v₁ : ι₁ → F) (h₁ : ∑ i ∈ s₁, w₁ i = 0) {ι₂ : Type*} {s₂ : Finset ι₂} {w₂ : ι₂ → ℝ}
+ (v₂ : ι₂ → F) (h₂ : ∑ i ∈ s₂, w₂ i = 0) :
+ ⟪∑ i₁ ∈ s₁, w₁ i₁ • v₁ i₁, ∑ i₂ ∈ s₂, w₂ i₂ • v₂ i₂⟫_ℝ =
+ (-∑ i₁ ∈ s₁, ∑ i₂ ∈ s₂, w₁ i₁ * w₂ i₂ * (‖v₁ i₁ - v₂ i₂‖ * ‖v₁ i₁ - v₂ i₂‖)) / 2 := by
+ simp_rw [sum_inner, inner_sum, real_inner_smul_left, real_inner_smul_right,
+ real_inner_eq_norm_mul_self_add_norm_mul_self_sub_norm_sub_mul_self_div_two, ← div_sub_div_same,
+ ← div_add_div_same, mul_sub_left_distrib, left_distrib, Finset.sum_sub_distrib,
+ Finset.sum_add_distrib, ← Finset.mul_sum, ← Finset.sum_mul, h₁, h₂, zero_mul,
+ mul_zero, Finset.sum_const_zero, zero_add, zero_sub, Finset.mul_sum, neg_div,
+ Finset.sum_div, mul_div_assoc, mul_assoc]
+
end Norm_Seminormed
section Norm
+open scoped InnerProductSpace
+
variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
variable [NormedAddCommGroup F] [InnerProductSpace ℝ F]
variable {ι : Type*} {ι' : Type*} {ι'' : Type*}
@@ -1605,27 +1702,6 @@ theorem dist_div_norm_sq_smul {x y : F} (hx : x ≠ 0) (hy : y ≠ 0) (R : ℝ)
_ = R ^ 2 / (‖x‖ * ‖y‖) * dist x y := by
rw [sqrt_mul, sqrt_sq, sqrt_sq, dist_eq_norm] <;> positivity
-section
-
-variable {ι : Type*} {ι' : Type*} {ι'' : Type*}
-variable {E' : Type*} [NormedAddCommGroup E'] [InnerProductSpace 𝕜 E']
-variable {E'' : Type*} [NormedAddCommGroup E''] [InnerProductSpace 𝕜 E'']
-
-@[simp]
-theorem Orthonormal.equiv_refl {v : Basis ι 𝕜 E} (hv : Orthonormal 𝕜 v) :
- hv.equiv hv (Equiv.refl ι) = LinearIsometryEquiv.refl 𝕜 E :=
- v.ext_linearIsometryEquiv fun i => by
- simp only [Orthonormal.equiv_apply, Equiv.coe_refl, id, LinearIsometryEquiv.coe_refl]
-
-@[simp]
-theorem Orthonormal.equiv_symm {v : Basis ι 𝕜 E} (hv : Orthonormal 𝕜 v) {v' : Basis ι' 𝕜 E'}
- (hv' : Orthonormal 𝕜 v') (e : ι ≃ ι') : (hv.equiv hv' e).symm = hv'.equiv hv e.symm :=
- v'.ext_linearIsometryEquiv fun i =>
- (hv.equiv hv' e).injective <| by
- simp only [LinearIsometryEquiv.apply_symm_apply, Orthonormal.equiv_apply, e.apply_symm_apply]
-
-end
-
/-- The inner product of a nonzero vector with a nonzero multiple of
itself, divided by the product of their norms, has absolute value
1. -/
@@ -1665,8 +1741,8 @@ theorem norm_inner_eq_norm_tfae (x y : E) :
x = 0 ∨ y = (⟪x, y⟫ / ⟪x, x⟫) • x,
x = 0 ∨ ∃ r : 𝕜, y = r • x,
x = 0 ∨ y ∈ 𝕜 ∙ x] := by
- tfae_have 1 → 2
- · refine fun h => or_iff_not_imp_left.2 fun hx₀ => ?_
+ tfae_have 1 → 2 := by
+ refine fun h => or_iff_not_imp_left.2 fun hx₀ => ?_
have : ‖x‖ ^ 2 ≠ 0 := pow_ne_zero _ (norm_ne_zero_iff.2 hx₀)
rw [← sq_eq_sq, mul_pow, ← mul_right_inj' this, eq_comm, ← sub_eq_zero, ← mul_sub] at h <;>
try positivity
@@ -1676,13 +1752,12 @@ theorem norm_inner_eq_norm_tfae (x y : E) :
sub_eq_zero] at h
rw [div_eq_inv_mul, mul_smul, h, inv_smul_smul₀]
rwa [inner_self_ne_zero]
- tfae_have 2 → 3
- · exact fun h => h.imp_right fun h' => ⟨_, h'⟩
- tfae_have 3 → 1
- · rintro (rfl | ⟨r, rfl⟩) <;>
+ tfae_have 2 → 3 := fun h => h.imp_right fun h' => ⟨_, h'⟩
+ tfae_have 3 → 1 := by
+ rintro (rfl | ⟨r, rfl⟩) <;>
simp [inner_smul_right, norm_smul, inner_self_eq_norm_sq_to_K, inner_self_eq_norm_mul_norm,
sq, mul_left_comm]
- tfae_have 3 ↔ 4; · simp only [Submodule.mem_span_singleton, eq_comm]
+ tfae_have 3 ↔ 4 := by simp only [Submodule.mem_span_singleton, eq_comm]
tfae_finish
/-- If the inner product of two vectors is equal to the product of their norms, then the two vectors
@@ -1799,62 +1874,6 @@ theorem eq_of_norm_le_re_inner_eq_norm_sq {x y : E} (hle : ‖x‖ ≤ ‖y‖)
have H₂ : re ⟪y, x⟫ = ‖y‖ ^ 2 := by rwa [← inner_conj_symm, conj_re]
simpa [inner_sub_left, inner_sub_right, ← norm_sq_eq_inner, h, H₂] using H₁
-/-- The inner product of two weighted sums, where the weights in each
-sum add to 0, in terms of the norms of pairwise differences. -/
-theorem inner_sum_smul_sum_smul_of_sum_eq_zero {ι₁ : Type*} {s₁ : Finset ι₁} {w₁ : ι₁ → ℝ}
- (v₁ : ι₁ → F) (h₁ : ∑ i ∈ s₁, w₁ i = 0) {ι₂ : Type*} {s₂ : Finset ι₂} {w₂ : ι₂ → ℝ}
- (v₂ : ι₂ → F) (h₂ : ∑ i ∈ s₂, w₂ i = 0) :
- ⟪∑ i₁ ∈ s₁, w₁ i₁ • v₁ i₁, ∑ i₂ ∈ s₂, w₂ i₂ • v₂ i₂⟫_ℝ =
- (-∑ i₁ ∈ s₁, ∑ i₂ ∈ s₂, w₁ i₁ * w₂ i₂ * (‖v₁ i₁ - v₂ i₂‖ * ‖v₁ i₁ - v₂ i₂‖)) / 2 := by
- simp_rw [sum_inner, inner_sum, real_inner_smul_left, real_inner_smul_right,
- real_inner_eq_norm_mul_self_add_norm_mul_self_sub_norm_sub_mul_self_div_two, ← div_sub_div_same,
- ← div_add_div_same, mul_sub_left_distrib, left_distrib, Finset.sum_sub_distrib,
- Finset.sum_add_distrib, ← Finset.mul_sum, ← Finset.sum_mul, h₁, h₂, zero_mul,
- mul_zero, Finset.sum_const_zero, zero_add, zero_sub, Finset.mul_sum, neg_div,
- Finset.sum_div, mul_div_assoc, mul_assoc]
-
-variable (𝕜)
-
-/-- `innerSL` is an isometry. Note that the associated `LinearIsometry` is defined in
-`InnerProductSpace.Dual` as `toDualMap`. -/
-@[simp]
-theorem innerSL_apply_norm (x : E) : ‖innerSL 𝕜 x‖ = ‖x‖ := by
- refine
- le_antisymm ((innerSL 𝕜 x).opNorm_le_bound (norm_nonneg _) fun y => norm_inner_le_norm _ _) ?_
- rcases eq_or_ne x 0 with (rfl | h)
- · simp
- · refine (mul_le_mul_right (norm_pos_iff.2 h)).mp ?_
- calc
- ‖x‖ * ‖x‖ = ‖(⟪x, x⟫ : 𝕜)‖ := by
- rw [← sq, inner_self_eq_norm_sq_to_K, norm_pow, norm_ofReal, abs_norm]
- _ ≤ ‖innerSL 𝕜 x‖ * ‖x‖ := (innerSL 𝕜 x).le_opNorm _
-
-lemma norm_innerSL_le : ‖innerSL 𝕜 (E := E)‖ ≤ 1 :=
- ContinuousLinearMap.opNorm_le_bound _ zero_le_one (by simp)
-
-variable {𝕜}
-
-/-- When an inner product space `E` over `𝕜` is considered as a real normed space, its inner
-product satisfies `IsBoundedBilinearMap`.
-
-In order to state these results, we need a `NormedSpace ℝ E` instance. We will later establish
-such an instance by restriction-of-scalars, `InnerProductSpace.rclikeToReal 𝕜 E`, but this
-instance may be not definitionally equal to some other “natural” instance. So, we assume
-`[NormedSpace ℝ E]`.
--/
-theorem _root_.isBoundedBilinearMap_inner [NormedSpace ℝ E] :
- IsBoundedBilinearMap ℝ fun p : E × E => ⟪p.1, p.2⟫ :=
- { add_left := inner_add_left
- smul_left := fun r x y => by
- simp only [← algebraMap_smul 𝕜 r x, algebraMap_eq_ofReal, inner_smul_real_left]
- add_right := inner_add_right
- smul_right := fun r x y => by
- simp only [← algebraMap_smul 𝕜 r y, algebraMap_eq_ofReal, inner_smul_real_right]
- bound :=
- ⟨1, zero_lt_one, fun x y => by
- rw [one_mul]
- exact norm_inner_le_norm x y⟩ }
-
end Norm
section BesselsInequality
@@ -2021,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]
@@ -2196,6 +2215,8 @@ end OrthogonalFamily
section RCLikeToReal
+open scoped InnerProductSpace
+
variable {G : Type*}
variable (𝕜 E)
variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E]
@@ -2219,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]
@@ -2261,7 +2282,7 @@ end RCLikeToReal
section Continuous
-variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
+variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E]
local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y
@@ -2276,6 +2297,7 @@ local postfix:90 "†" => starRingEnd _
theorem continuous_inner : Continuous fun p : E × E => ⟪p.1, p.2⟫ :=
letI : InnerProductSpace ℝ E := InnerProductSpace.rclikeToReal 𝕜 E
+ letI : IsScalarTower ℝ 𝕜 E := RestrictScalars.isScalarTower _ _ _
isBoundedBilinearMap_inner.continuous
variable {α : Type*}
@@ -2326,7 +2348,7 @@ end ReApplyInnerSelf
section ReApplyInnerSelf_Seminormed
-variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
+variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E]
local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y
@@ -2346,9 +2368,36 @@ 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 [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
+variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E]
local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y
@@ -2362,11 +2411,11 @@ open UniformSpace Function
instance toInner {𝕜' E' : Type*} [TopologicalSpace 𝕜'] [UniformSpace E'] [Inner 𝕜' E'] :
Inner 𝕜' (Completion E') where
- inner := curry <| (denseInducing_coe.prod denseInducing_coe).extend (uncurry inner)
+ inner := curry <| (isDenseInducing_coe.prodMap isDenseInducing_coe).extend (uncurry inner)
@[simp]
theorem inner_coe (a b : E) : inner (a : Completion E) (b : Completion E) = (inner a b : 𝕜) :=
- (denseInducing_coe.prod denseInducing_coe).extend_eq
+ (isDenseInducing_coe.prodMap isDenseInducing_coe).extend_eq
(continuous_inner : Continuous (uncurry inner : E × E → 𝕜)) (a, b)
protected theorem continuous_inner :
@@ -2379,9 +2428,9 @@ protected theorem continuous_inner :
rw [Completion.toInner, inner, uncurry_curry _]
change
Continuous
- (((denseInducing_toCompl E).prod (denseInducing_toCompl E)).extend fun p : E × E =>
+ (((isDenseInducing_toCompl E).prodMap (isDenseInducing_toCompl E)).extend fun p : E × E =>
inner' p.1 p.2)
- exact (denseInducing_toCompl E).extend_Z_bilin (denseInducing_toCompl E) this
+ exact (isDenseInducing_toCompl E).extend_Z_bilin (isDenseInducing_toCompl E) this
protected theorem Continuous.inner {α : Type*} [TopologicalSpace α] {f g : α → Completion E}
(hf : Continuous f) (hg : Continuous g) : Continuous (fun x : α => inner (f x) (g x) : α → 𝕜) :=
diff --git a/Mathlib/Analysis/InnerProductSpace/Calculus.lean b/Mathlib/Analysis/InnerProductSpace/Calculus.lean
index 031592910f445..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
@@ -80,15 +82,18 @@ theorem HasFDerivWithinAt.inner (hf : HasFDerivWithinAt f f' s x)
(hg : HasFDerivWithinAt g g' s x) :
HasFDerivWithinAt (fun t => ⟪f t, g t⟫) ((fderivInnerCLM 𝕜 (f x, g x)).comp <| f'.prod g') s
x :=
- (isBoundedBilinearMap_inner.hasFDerivAt (f x, g x)).comp_hasFDerivWithinAt x (hf.prod hg)
+ isBoundedBilinearMap_inner (𝕜 := 𝕜) (E := E)
+ |>.hasFDerivAt (f x, g x) |>.comp_hasFDerivWithinAt x (hf.prod hg)
theorem HasStrictFDerivAt.inner (hf : HasStrictFDerivAt f f' x) (hg : HasStrictFDerivAt g g' x) :
HasStrictFDerivAt (fun t => ⟪f t, g t⟫) ((fderivInnerCLM 𝕜 (f x, g x)).comp <| f'.prod g') x :=
- (isBoundedBilinearMap_inner.hasStrictFDerivAt (f x, g x)).comp x (hf.prod hg)
+ isBoundedBilinearMap_inner (𝕜 := 𝕜) (E := E)
+ |>.hasStrictFDerivAt (f x, g x) |>.comp x (hf.prod hg)
theorem HasFDerivAt.inner (hf : HasFDerivAt f f' x) (hg : HasFDerivAt g g' x) :
HasFDerivAt (fun t => ⟪f t, g t⟫) ((fderivInnerCLM 𝕜 (f x, g x)).comp <| f'.prod g') x :=
- (isBoundedBilinearMap_inner.hasFDerivAt (f x, g x)).comp x (hf.prod hg)
+ isBoundedBilinearMap_inner (𝕜 := 𝕜) (E := E)
+ |>.hasFDerivAt (f x, g x) |>.comp x (hf.prod hg)
theorem HasDerivWithinAt.inner {f g : ℝ → E} {f' g' : E} {s : Set ℝ} {x : ℝ}
(hf : HasDerivWithinAt f f' s x) (hg : HasDerivWithinAt g g' s x) :
@@ -261,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/Dual.lean b/Mathlib/Analysis/InnerProductSpace/Dual.lean
index e6af204a8c575..58aba1f6281ae 100644
--- a/Mathlib/Analysis/InnerProductSpace/Dual.lean
+++ b/Mathlib/Analysis/InnerProductSpace/Dual.lean
@@ -45,8 +45,10 @@ namespace InnerProductSpace
open RCLike ContinuousLinearMap
-variable (𝕜 : Type*)
-variable (E : Type*) [RCLike 𝕜] [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
+variable (𝕜 E : Type*)
+
+section Seminormed
+variable [RCLike 𝕜] [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E]
local notation "⟪" x ", " y "⟫" => @inner 𝕜 E _ x y
@@ -67,10 +69,19 @@ variable {E}
theorem toDualMap_apply {x y : E} : toDualMap 𝕜 E x y = ⟪x, y⟫ :=
rfl
+end Seminormed
+
+section Normed
+variable [RCLike 𝕜] [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
+
+local notation "⟪" x ", " y "⟫" => @inner 𝕜 E _ x y
+
+local postfix:90 "†" => starRingEnd _
+
theorem innerSL_norm [Nontrivial E] : ‖(innerSL 𝕜 : E →L⋆[𝕜] E →L[𝕜] 𝕜)‖ = 1 :=
show ‖(toDualMap 𝕜 E).toContinuousLinearMap‖ = 1 from LinearIsometry.norm_toContinuousLinearMap _
-variable {𝕜}
+variable {E 𝕜}
theorem ext_inner_left_basis {ι : Type*} {x y : E} (b : Basis ι 𝕜 E)
(h : ∀ i : ι, ⟪b i, x⟫ = ⟪b i, y⟫) : x = y := by
@@ -170,4 +181,6 @@ theorem unique_continuousLinearMapOfBilin {v f : E} (is_lax_milgram : ∀ w, ⟪
rw [continuousLinearMapOfBilin_apply]
exact is_lax_milgram w
+end Normed
+
end InnerProductSpace
diff --git a/Mathlib/Analysis/InnerProductSpace/EuclideanDist.lean b/Mathlib/Analysis/InnerProductSpace/EuclideanDist.lean
index 69889f1ed8e41..50173dd6a64c2 100644
--- a/Mathlib/Analysis/InnerProductSpace/EuclideanDist.lean
+++ b/Mathlib/Analysis/InnerProductSpace/EuclideanDist.lean
@@ -29,7 +29,7 @@ variable {E : Type*} [AddCommGroup E] [TopologicalSpace E] [TopologicalAddGroup
noncomputable section
-open FiniteDimensional
+open Module
/-- If `E` is a finite dimensional space over `ℝ`, then `toEuclidean` is a continuous `ℝ`-linear
equivalence between `E` and the Euclidean space of the same dimension. -/
diff --git a/Mathlib/Analysis/InnerProductSpace/GramSchmidtOrtho.lean b/Mathlib/Analysis/InnerProductSpace/GramSchmidtOrtho.lean
index a3c9277c121f4..b0351cdc69d46 100644
--- a/Mathlib/Analysis/InnerProductSpace/GramSchmidtOrtho.lean
+++ b/Mathlib/Analysis/InnerProductSpace/GramSchmidtOrtho.lean
@@ -35,7 +35,7 @@ and outputs a set of orthogonal vectors which have the same span.
-/
-open Finset Submodule FiniteDimensional
+open Finset Submodule Module
variable (𝕜 : Type*) {E : Type*} [RCLike 𝕜] [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
variable {ι : Type*} [LinearOrder ι] [LocallyFiniteOrderBot ι] [IsWellOrder ι (· < ·)]
diff --git a/Mathlib/Analysis/InnerProductSpace/JointEigenspace.lean b/Mathlib/Analysis/InnerProductSpace/JointEigenspace.lean
index 868496a0b3462..049ba1532a238 100644
--- a/Mathlib/Analysis/InnerProductSpace/JointEigenspace.lean
+++ b/Mathlib/Analysis/InnerProductSpace/JointEigenspace.lean
@@ -49,7 +49,7 @@ variable {α : 𝕜} {A B : E →ₗ[𝕜] E}
theorem eigenspace_invariant_of_commute
(hAB : A ∘ₗ B = B ∘ₗ A) (α : 𝕜) : ∀ v ∈ (eigenspace A α), (B v ∈ eigenspace A α) := by
intro v hv
- rw [eigenspace, mem_ker, sub_apply, Module.algebraMap_end_apply, ← comp_apply A B v, hAB,
+ rw [eigenspace_def, mem_ker, sub_apply, smul_apply, one_apply, ← comp_apply A B v, hAB,
comp_apply B A v, ← map_smul, ← map_sub, hv, map_zero] at *
/--The simultaneous eigenspaces of a pair of commuting symmetric operators form an
diff --git a/Mathlib/Analysis/InnerProductSpace/LaxMilgram.lean b/Mathlib/Analysis/InnerProductSpace/LaxMilgram.lean
index 7ac440395d2e8..9aa623e738fae 100644
--- a/Mathlib/Analysis/InnerProductSpace/LaxMilgram.lean
+++ b/Mathlib/Analysis/InnerProductSpace/LaxMilgram.lean
@@ -64,7 +64,7 @@ theorem antilipschitz (coercive : IsCoercive B) : ∃ C : ℝ≥0, 0 < C ∧ Ant
refine ⟨C⁻¹.toNNReal, Real.toNNReal_pos.mpr (inv_pos.mpr C_pos), ?_⟩
refine ContinuousLinearMap.antilipschitz_of_bound B♯ ?_
simp_rw [Real.coe_toNNReal', max_eq_left_of_lt (inv_pos.mpr C_pos), ←
- inv_mul_le_iff (inv_pos.mpr C_pos)]
+ inv_mul_le_iff₀ (inv_pos.mpr C_pos)]
simpa using below_bound
theorem ker_eq_bot (coercive : IsCoercive B) : ker B♯ = ⊥ := by
diff --git a/Mathlib/Analysis/InnerProductSpace/LinearPMap.lean b/Mathlib/Analysis/InnerProductSpace/LinearPMap.lean
index 9019b62655b0c..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
- uniformEmbedding_subtype_val.toUniformInducing
+ isUniformEmbedding_subtype_val.isUniformInducing
@[simp]
theorem adjointDomainMkCLMExtend_apply (y : T.adjointDomain) (x : T.domain) :
@@ -202,7 +202,7 @@ as taking the `ContinuousLinearMap.adjoint` interpreted as a `LinearPMap`. -/
theorem toPMap_adjoint_eq_adjoint_toPMap_of_dense (hp : Dense (p : Set E)) :
(A.toPMap p).adjoint = A.adjoint.toPMap ⊤ := by
ext x y hxy
- · simp only [LinearMap.toPMap_domain, Submodule.mem_top, iff_true_iff,
+ · simp only [LinearMap.toPMap_domain, Submodule.mem_top, iff_true,
LinearPMap.mem_adjoint_domain_iff, LinearMap.coe_comp, innerₛₗ_apply_coe]
exact ((innerSL 𝕜 x).comp <| A.comp <| Submodule.subtypeL _).cont
refine LinearPMap.adjoint_apply_eq ?_ _ fun v => ?_
diff --git a/Mathlib/Analysis/InnerProductSpace/OfNorm.lean b/Mathlib/Analysis/InnerProductSpace/OfNorm.lean
index ad51b9d339160..b62522a0e45d6 100644
--- a/Mathlib/Analysis/InnerProductSpace/OfNorm.lean
+++ b/Mathlib/Analysis/InnerProductSpace/OfNorm.lean
@@ -5,6 +5,8 @@ Authors: Heather Macbeth
-/
import Mathlib.Topology.Algebra.Algebra
import Mathlib.Analysis.InnerProductSpace.Basic
+import Mathlib.Algebra.Module.LinearMap.Rat
+import Mathlib.Tactic.Module
/-!
# Inner product space derived from a norm
@@ -97,199 +99,118 @@ private def innerProp' (r : 𝕜) : Prop :=
variable {E}
-theorem innerProp_neg_one : innerProp' E ((-1 : ℤ) : 𝕜) := by
- intro x y
- simp only [inner_, neg_mul_eq_neg_mul, one_mul, Int.cast_one, one_smul, RingHom.map_one, map_neg,
- Int.cast_neg, neg_smul, neg_one_mul]
- rw [neg_mul_comm]
- congr 1
- have h₁ : ‖-x - y‖ = ‖x + y‖ := by rw [← neg_add', norm_neg]
- have h₂ : ‖-x + y‖ = ‖x - y‖ := by rw [← neg_sub, norm_neg, sub_eq_neg_add]
- have h₃ : ‖(I : 𝕜) • -x + y‖ = ‖(I : 𝕜) • x - y‖ := by
- rw [← neg_sub, norm_neg, sub_eq_neg_add, ← smul_neg]
- have h₄ : ‖(I : 𝕜) • -x - y‖ = ‖(I : 𝕜) • x + y‖ := by rw [smul_neg, ← neg_add', norm_neg]
- rw [h₁, h₂, h₃, h₄]
- ring
-
theorem _root_.Continuous.inner_ {f g : ℝ → E} (hf : Continuous f) (hg : Continuous g) :
Continuous fun x => inner_ 𝕜 (f x) (g x) := by
- unfold inner_
+ unfold _root_.inner_
fun_prop
theorem inner_.norm_sq (x : E) : ‖x‖ ^ 2 = re (inner_ 𝕜 x x) := by
- simp only [inner_]
- have h₁ : RCLike.normSq (4 : 𝕜) = 16 := by
- have : ((4 : ℝ) : 𝕜) = (4 : 𝕜) := by norm_cast
- rw [← this, normSq_eq_def', RCLike.norm_of_nonneg (by norm_num : (0 : ℝ) ≤ 4)]
- norm_num
- have h₂ : ‖x + x‖ = 2 * ‖x‖ := by rw [← two_smul 𝕜, norm_smul, RCLike.norm_two]
- simp only [h₁, h₂, algebraMap_eq_ofReal, sub_self, norm_zero, mul_re, inv_re, ofNat_re, map_sub,
- map_add, ofReal_re, ofNat_im, ofReal_im, mul_im, I_re, inv_im]
+ simp only [inner_, normSq_apply, ofNat_re, ofNat_im, map_sub, map_add, map_zero, map_mul,
+ ofReal_re, ofReal_im, mul_re, inv_re, mul_im, I_re, inv_im]
+ have h₁ : ‖x - x‖ = 0 := by simp
+ have h₂ : ‖x + x‖ = 2 • ‖x‖ := by convert norm_nsmul 𝕜 2 x using 2; module
+ rw [h₁, h₂]
ring
-attribute [local simp] map_ofNat in -- use `ofNat` simp theorem with bad keys
theorem inner_.conj_symm (x y : E) : conj (inner_ 𝕜 y x) = inner_ 𝕜 x y := by
- simp only [inner_]
- have h4 : conj (4⁻¹ : 𝕜) = 4⁻¹ := by norm_num
- rw [map_mul, h4]
- congr 1
- simp only [map_sub, map_add, conj_ofReal, map_mul, conj_I]
+ simp only [inner_, map_sub, map_add, map_mul, map_inv₀, map_ofNat, conj_ofReal, conj_I]
rw [add_comm y x, norm_sub_rev]
by_cases hI : (I : 𝕜) = 0
· simp only [hI, neg_zero, zero_mul]
- -- Porting note: this replaces `norm_I_of_ne_zero` which does not exist in Lean 4
- have : ‖(I : 𝕜)‖ = 1 := by
- rw [← mul_self_inj_of_nonneg (norm_nonneg I) zero_le_one, one_mul, ← norm_mul,
- I_mul_I_of_nonzero hI, norm_neg, norm_one]
+ have hI' := I_mul_I_of_nonzero hI
+ have I_smul (v : E) : ‖(I : 𝕜) • v‖ = ‖v‖ := by rw [norm_smul, norm_I_of_ne_zero hI, one_mul]
have h₁ : ‖(I : 𝕜) • y - x‖ = ‖(I : 𝕜) • x + y‖ := by
- trans ‖(I : 𝕜) • ((I : 𝕜) • y - x)‖
- · rw [norm_smul, this, one_mul]
- · rw [smul_sub, smul_smul, I_mul_I_of_nonzero hI, neg_one_smul, ← neg_add', add_comm, norm_neg]
+ convert I_smul ((I : 𝕜) • x + y) using 2
+ linear_combination (norm := module) congr(-$hI' • x)
have h₂ : ‖(I : 𝕜) • y + x‖ = ‖(I : 𝕜) • x - y‖ := by
- trans ‖(I : 𝕜) • ((I : 𝕜) • y + x)‖
- · rw [norm_smul, this, one_mul]
- · rw [smul_add, smul_smul, I_mul_I_of_nonzero hI, neg_one_smul, ← neg_add_eq_sub]
- rw [h₁, h₂, ← sub_add_eq_add_sub]
- simp only [neg_mul, sub_eq_add_neg, neg_neg]
+ convert (I_smul ((I : 𝕜) • y + x)).symm using 2
+ linear_combination (norm := module) congr(-$hI' • y)
+ rw [h₁, h₂]
+ ring
variable [InnerProductSpaceable E]
-private theorem add_left_aux1 (x y z : E) : ‖x + y + z‖ * ‖x + y + z‖ =
- (‖2 • x + y‖ * ‖2 • x + y‖ + ‖2 • z + y‖ * ‖2 • z + y‖) / 2 - ‖x - z‖ * ‖x - z‖ := by
- rw [eq_sub_iff_add_eq, eq_div_iff (two_ne_zero' ℝ), mul_comm _ (2 : ℝ), eq_comm]
- convert parallelogram_identity (x + y + z) (x - z) using 4 <;> · rw [two_smul]; abel
-
-private theorem add_left_aux2 (x y z : E) : ‖x + y - z‖ * ‖x + y - z‖ =
- (‖2 • x + y‖ * ‖2 • x + y‖ + ‖y - 2 • z‖ * ‖y - 2 • z‖) / 2 - ‖x + z‖ * ‖x + z‖ := by
- rw [eq_sub_iff_add_eq, eq_div_iff (two_ne_zero' ℝ), mul_comm _ (2 : ℝ), eq_comm]
- have h₀ := parallelogram_identity (x + y - z) (x + z)
- convert h₀ using 4 <;> · rw [two_smul]; abel
+private theorem add_left_aux1 (x y z : E) :
+ ‖2 • x + y‖ * ‖2 • x + y‖ + ‖2 • z + y‖ * ‖2 • z + y‖
+ = 2 * (‖x + y + z‖ * ‖x + y + z‖ + ‖x - z‖ * ‖x - z‖) := by
+ convert parallelogram_identity (x + y + z) (x - z) using 4 <;> abel
-private theorem add_left_aux2' (x y z : E) :
- ‖x + y + z‖ * ‖x + y + z‖ - ‖x + y - z‖ * ‖x + y - z‖ =
- ‖x + z‖ * ‖x + z‖ - ‖x - z‖ * ‖x - z‖ +
- (‖2 • z + y‖ * ‖2 • z + y‖ - ‖y - 2 • z‖ * ‖y - 2 • z‖) / 2 := by
- rw [add_left_aux1, add_left_aux2]; ring
+private theorem add_left_aux2 (x y z : E) : ‖2 • x + y‖ * ‖2 • x + y‖ + ‖y - 2 • z‖ * ‖y - 2 • z‖
+ = 2 * (‖x + y - z‖ * ‖x + y - z‖ + ‖x + z‖ * ‖x + z‖) := by
+ convert parallelogram_identity (x + y - z) (x + z) using 4 <;> abel
private theorem add_left_aux3 (y z : E) :
- ‖2 • z + y‖ * ‖2 • z + y‖ = 2 * (‖y + z‖ * ‖y + z‖ + ‖z‖ * ‖z‖) - ‖y‖ * ‖y‖ := by
- apply eq_sub_of_add_eq
- convert parallelogram_identity (y + z) z using 4 <;> (try rw [two_smul]) <;> abel
+ ‖2 • z + y‖ * ‖2 • z + y‖ + ‖y‖ * ‖y‖ = 2 * (‖y + z‖ * ‖y + z‖ + ‖z‖ * ‖z‖) := by
+ convert parallelogram_identity (y + z) z using 4 <;> abel
private theorem add_left_aux4 (y z : E) :
- ‖y - 2 • z‖ * ‖y - 2 • z‖ = 2 * (‖y - z‖ * ‖y - z‖ + ‖z‖ * ‖z‖) - ‖y‖ * ‖y‖ := by
- apply eq_sub_of_add_eq'
- have h₀ := parallelogram_identity (y - z) z
- convert h₀ using 4 <;> (try rw [two_smul]) <;> abel
+ ‖y‖ * ‖y‖ + ‖y - 2 • z‖ * ‖y - 2 • z‖ = 2 * (‖y - z‖ * ‖y - z‖ + ‖z‖ * ‖z‖) := by
+ convert parallelogram_identity (y - z) z using 4 <;> abel
-private theorem add_left_aux4' (y z : E) :
- (‖2 • z + y‖ * ‖2 • z + y‖ - ‖y - 2 • z‖ * ‖y - 2 • z‖) / 2 =
- ‖y + z‖ * ‖y + z‖ - ‖y - z‖ * ‖y - z‖ := by
- rw [add_left_aux3, add_left_aux4]; ring
+variable (𝕜)
private theorem add_left_aux5 (x y z : E) :
- ‖(I : 𝕜) • (x + y) + z‖ * ‖(I : 𝕜) • (x + y) + z‖ =
- (‖(I : 𝕜) • (2 • x + y)‖ * ‖(I : 𝕜) • (2 • x + y)‖ +
- ‖(I : 𝕜) • y + 2 • z‖ * ‖(I : 𝕜) • y + 2 • z‖) / 2 -
- ‖(I : 𝕜) • x - z‖ * ‖(I : 𝕜) • x - z‖ := by
- rw [eq_sub_iff_add_eq, eq_div_iff (two_ne_zero' ℝ), mul_comm _ (2 : ℝ), eq_comm]
- have h₀ := parallelogram_identity ((I : 𝕜) • (x + y) + z) ((I : 𝕜) • x - z)
- convert h₀ using 4 <;> · try simp only [two_smul, smul_add]; abel
+ ‖(I : 𝕜) • (2 • x + y)‖ * ‖(I : 𝕜) • (2 • x + y)‖
+ + ‖(I : 𝕜) • y + 2 • z‖ * ‖(I : 𝕜) • y + 2 • z‖
+ = 2 * (‖(I : 𝕜) • (x + y) + z‖ * ‖(I : 𝕜) • (x + y) + z‖
+ + ‖(I : 𝕜) • x - z‖ * ‖(I : 𝕜) • x - z‖) := by
+ convert parallelogram_identity ((I : 𝕜) • (x + y) + z) ((I : 𝕜) • x - z) using 4 <;> module
private theorem add_left_aux6 (x y z : E) :
- ‖(I : 𝕜) • (x + y) - z‖ * ‖(I : 𝕜) • (x + y) - z‖ =
(‖(I : 𝕜) • (2 • x + y)‖ * ‖(I : 𝕜) • (2 • x + y)‖ +
- ‖(I : 𝕜) • y - 2 • z‖ * ‖(I : 𝕜) • y - 2 • z‖) / 2 -
- ‖(I : 𝕜) • x + z‖ * ‖(I : 𝕜) • x + z‖ := by
- rw [eq_sub_iff_add_eq, eq_div_iff (two_ne_zero' ℝ), mul_comm _ (2 : ℝ), eq_comm]
- have h₀ := parallelogram_identity ((I : 𝕜) • (x + y) - z) ((I : 𝕜) • x + z)
- convert h₀ using 4 <;> · try simp only [two_smul, smul_add]; abel
+ ‖(I : 𝕜) • y - 2 • z‖ * ‖(I : 𝕜) • y - 2 • z‖)
+ = 2 * (‖(I : 𝕜) • (x + y) - z‖ * ‖(I : 𝕜) • (x + y) - z‖ +
+ ‖(I : 𝕜) • x + z‖ * ‖(I : 𝕜) • x + z‖) := by
+ convert parallelogram_identity ((I : 𝕜) • (x + y) - z) ((I : 𝕜) • x + z) using 4 <;> module
private theorem add_left_aux7 (y z : E) :
- ‖(I : 𝕜) • y + 2 • z‖ * ‖(I : 𝕜) • y + 2 • z‖ =
- 2 * (‖(I : 𝕜) • y + z‖ * ‖(I : 𝕜) • y + z‖ + ‖z‖ * ‖z‖) - ‖(I : 𝕜) • y‖ * ‖(I : 𝕜) • y‖ := by
- apply eq_sub_of_add_eq
- have h₀ := parallelogram_identity ((I : 𝕜) • y + z) z
- convert h₀ using 4 <;> · (try simp only [two_smul, smul_add]); abel
+ ‖(I : 𝕜) • y + 2 • z‖ * ‖(I : 𝕜) • y + 2 • z‖ + ‖(I : 𝕜) • y‖ * ‖(I : 𝕜) • y‖ =
+ 2 * (‖(I : 𝕜) • y + z‖ * ‖(I : 𝕜) • y + z‖ + ‖z‖ * ‖z‖) := by
+ convert parallelogram_identity ((I : 𝕜) • y + z) z using 4 <;> module
private theorem add_left_aux8 (y z : E) :
- ‖(I : 𝕜) • y - 2 • z‖ * ‖(I : 𝕜) • y - 2 • z‖ =
- 2 * (‖(I : 𝕜) • y - z‖ * ‖(I : 𝕜) • y - z‖ + ‖z‖ * ‖z‖) - ‖(I : 𝕜) • y‖ * ‖(I : 𝕜) • y‖ := by
- apply eq_sub_of_add_eq'
- have h₀ := parallelogram_identity ((I : 𝕜) • y - z) z
- convert h₀ using 4 <;> · (try simp only [two_smul, smul_add]); abel
+ ‖(I : 𝕜) • y‖ * ‖(I : 𝕜) • y‖ + ‖(I : 𝕜) • y - 2 • z‖ * ‖(I : 𝕜) • y - 2 • z‖ =
+ 2 * (‖(I : 𝕜) • y - z‖ * ‖(I : 𝕜) • y - z‖ + ‖z‖ * ‖z‖) := by
+ convert parallelogram_identity ((I : 𝕜) • y - z) z using 4 <;> module
+
+variable {𝕜}
theorem add_left (x y z : E) : inner_ 𝕜 (x + y) z = inner_ 𝕜 x z + inner_ 𝕜 y z := by
- simp only [inner_, ← mul_add]
- congr
- simp only [mul_assoc, ← map_mul, add_sub_assoc, ← mul_sub, ← map_sub]
- rw [add_add_add_comm]
- simp only [← map_add, ← mul_add]
- congr
- · rw [← add_sub_assoc, add_left_aux2', add_left_aux4']
- · rw [add_left_aux5, add_left_aux6, add_left_aux7, add_left_aux8]
- simp only [map_sub, map_mul, map_add, div_eq_mul_inv]
- ring
-
-theorem nat (n : ℕ) (x y : E) : inner_ 𝕜 ((n : 𝕜) • x) y = (n : 𝕜) * inner_ 𝕜 x y := by
- induction' n with n ih
- · simp only [inner_, zero_sub, Nat.cast_zero, zero_mul,
- eq_self_iff_true, zero_smul, zero_add, mul_zero, sub_self, norm_neg, smul_zero]
- · simp only [Nat.cast_succ, add_smul, one_smul]
- rw [add_left, ih, add_mul, one_mul]
-
-private theorem nat_prop (r : ℕ) : innerProp' E (r : 𝕜) := fun x y => by
- simp only [map_natCast]; exact nat r x y
-
-private theorem int_prop (n : ℤ) : innerProp' E (n : 𝕜) := by
- intro x y
- rw [← n.sign_mul_natAbs]
- simp only [Int.cast_natCast, map_natCast, map_intCast, Int.cast_mul, map_mul, mul_smul]
- obtain hn | rfl | hn := lt_trichotomy n 0
- · rw [Int.sign_eq_neg_one_of_neg hn, innerProp_neg_one ((n.natAbs : 𝕜) • x), nat]
- simp only [map_neg, neg_mul, one_mul, mul_eq_mul_left_iff, true_or_iff, Int.natAbs_eq_zero,
- eq_self_iff_true, Int.cast_one, map_one, neg_inj, Nat.cast_eq_zero, Int.cast_neg]
- · simp only [inner_, Int.cast_zero, zero_sub, Nat.cast_zero, zero_mul,
- eq_self_iff_true, Int.sign_zero, zero_smul, zero_add, mul_zero, smul_zero,
- sub_self, norm_neg, Int.natAbs_zero]
- · rw [Int.sign_eq_one_of_pos hn]
- simp only [one_mul, mul_eq_mul_left_iff, true_or_iff, Int.natAbs_eq_zero, eq_self_iff_true,
- Int.cast_one, one_smul, Nat.cast_eq_zero, nat]
+ have H_re := congr(- $(add_left_aux1 x y z) + $(add_left_aux2 x y z)
+ + $(add_left_aux3 y z) - $(add_left_aux4 y z))
+ have H_im := congr(- $(add_left_aux5 𝕜 x y z) + $(add_left_aux6 𝕜 x y z)
+ + $(add_left_aux7 𝕜 y z) - $(add_left_aux8 𝕜 y z))
+ have H := congr(𝓚 $H_re + I * 𝓚 $H_im)
+ simp only [inner_, map_add, map_sub, map_neg, map_mul, map_ofNat] at H ⊢
+ linear_combination H / 8
private theorem rat_prop (r : ℚ) : innerProp' E (r : 𝕜) := by
intro x y
- have : (r.den : 𝕜) ≠ 0 := by
- haveI : CharZero 𝕜 := RCLike.charZero_rclike
- exact mod_cast r.pos.ne'
- rw [← r.num_div_den, ← mul_right_inj' this, ← nat r.den _ y, smul_smul, Rat.cast_div]
- simp only [map_natCast, Rat.cast_natCast, map_intCast, Rat.cast_intCast, map_div₀]
- rw [← mul_assoc, mul_div_cancel₀ _ this, int_prop _ x, map_intCast]
+ let hom : 𝕜 →ₗ[ℚ] 𝕜 := AddMonoidHom.toRatLinearMap <|
+ AddMonoidHom.mk' (fun r ↦ inner_ 𝕜 (r • x) y) <| fun a b ↦ by
+ simpa [add_smul] using add_left (a • x) (b • x) y
+ simpa [hom, Rat.smul_def] using map_smul hom r 1
private theorem real_prop (r : ℝ) : innerProp' E (r : 𝕜) := by
intro x y
revert r
- rw [← Function.funext_iff]
- refine Rat.denseEmbedding_coe_real.dense.equalizer ?_ ?_ (funext fun X => ?_)
+ 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
· simp only [Function.comp_apply, RCLike.ofReal_ratCast, rat_prop _ _]
private theorem I_prop : innerProp' E (I : 𝕜) := by
by_cases hI : (I : 𝕜) = 0
- · rw [hI, ← Nat.cast_zero]; exact nat_prop _
+ · rw [hI]
+ simpa using real_prop (𝕜 := 𝕜) 0
intro x y
- have hI' : (-I : 𝕜) * I = 1 := by rw [← inv_I, inv_mul_cancel₀ hI]
- rw [conj_I, inner_, inner_, mul_left_comm]
- congr 1
- rw [smul_smul, I_mul_I_of_nonzero hI, neg_one_smul]
- rw [mul_sub, mul_add, mul_sub, mul_assoc I (𝓚 ‖I • x - y‖), ← mul_assoc (-I) I, hI', one_mul,
- mul_assoc I (𝓚 ‖I • x + y‖), ← mul_assoc (-I) I, hI', one_mul]
+ have hI' := I_mul_I_of_nonzero hI
+ rw [conj_I, inner_, inner_, mul_left_comm, smul_smul, hI', neg_one_smul]
have h₁ : ‖-x - y‖ = ‖x + y‖ := by rw [← neg_add', norm_neg]
have h₂ : ‖-x + y‖ = ‖x - y‖ := by rw [← neg_sub, norm_neg, sub_eq_neg_add]
rw [h₁, h₂]
- simp only [sub_eq_add_neg, mul_assoc]
- rw [← neg_mul_eq_neg_mul, ← neg_mul_eq_neg_mul]
- abel
+ linear_combination (- 𝓚 ‖(I : 𝕜) • x - y‖ ^ 2 + 𝓚 ‖(I : 𝕜) • x + y‖ ^ 2) * hI' / 4
theorem innerProp (r : 𝕜) : innerProp' E r := by
intro x y
diff --git a/Mathlib/Analysis/InnerProductSpace/Orientation.lean b/Mathlib/Analysis/InnerProductSpace/Orientation.lean
index 60b27da658fe3..fb73168b5bab2 100644
--- a/Mathlib/Analysis/InnerProductSpace/Orientation.lean
+++ b/Mathlib/Analysis/InnerProductSpace/Orientation.lean
@@ -38,7 +38,7 @@ noncomputable section
variable {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℝ E]
-open FiniteDimensional
+open Module
open scoped RealInnerProductSpace
diff --git a/Mathlib/Analysis/InnerProductSpace/Orthogonal.lean b/Mathlib/Analysis/InnerProductSpace/Orthogonal.lean
index c2b5db639db34..7b857c4ae5eba 100644
--- a/Mathlib/Analysis/InnerProductSpace/Orthogonal.lean
+++ b/Mathlib/Analysis/InnerProductSpace/Orthogonal.lean
@@ -112,8 +112,7 @@ theorem orthogonal_eq_inter : Kᗮ = ⨅ v : K, LinearMap.ker (innerSL 𝕜 (v :
/-- The orthogonal complement of any submodule `K` is closed. -/
theorem isClosed_orthogonal : IsClosed (Kᗮ : Set E) := by
rw [orthogonal_eq_inter K]
- have := fun v : K => ContinuousLinearMap.isClosed_ker (innerSL 𝕜 (v : E))
- convert isClosed_iInter this
+ convert isClosed_iInter <| fun v : K => ContinuousLinearMap.isClosed_ker (innerSL 𝕜 (v : E))
simp only [iInf_coe]
/-- In a complete space, the orthogonal complement of any submodule `K` is complete. -/
diff --git a/Mathlib/Analysis/InnerProductSpace/PiL2.lean b/Mathlib/Analysis/InnerProductSpace/PiL2.lean
index b157563aab735..3a77d1f7c5328 100644
--- a/Mathlib/Analysis/InnerProductSpace/PiL2.lean
+++ b/Mathlib/Analysis/InnerProductSpace/PiL2.lean
@@ -144,11 +144,11 @@ variable [Fintype ι]
@[simp]
theorem finrank_euclideanSpace :
- FiniteDimensional.finrank 𝕜 (EuclideanSpace 𝕜 ι) = Fintype.card ι := by
+ Module.finrank 𝕜 (EuclideanSpace 𝕜 ι) = Fintype.card ι := by
simp [EuclideanSpace, PiLp, WithLp]
theorem finrank_euclideanSpace_fin {n : ℕ} :
- FiniteDimensional.finrank 𝕜 (EuclideanSpace 𝕜 (Fin n)) = n := by simp
+ Module.finrank 𝕜 (EuclideanSpace 𝕜 (Fin n)) = n := by simp
theorem EuclideanSpace.inner_eq_star_dotProduct (x y : EuclideanSpace 𝕜 ι) :
⟪x, y⟫ = Matrix.dotProduct (star <| WithLp.equiv _ _ x) (WithLp.equiv _ _ y) :=
@@ -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 : 𝕜))
@@ -386,6 +378,7 @@ protected theorem sum_repr (b : OrthonormalBasis ι 𝕜 E) (x : E) : ∑ i, b.r
simp_rw [← b.coe_toBasis_repr_apply, ← b.coe_toBasis]
exact b.toBasis.sum_repr x
+open scoped InnerProductSpace in
protected theorem sum_repr' (b : OrthonormalBasis ι 𝕜 E) (x : E) : ∑ i, ⟪b i, x⟫_𝕜 • b i = x := by
nth_rw 2 [← (b.sum_repr x)]
simp_rw [b.repr_apply_apply x]
@@ -668,7 +661,7 @@ theorem Complex.isometryOfOrthonormal_apply (v : OrthonormalBasis (Fin 2) ℝ F)
end Complex
-open FiniteDimensional
+open Module
/-! ### Matrix representation of an orthonormal basis with respect to another -/
@@ -678,6 +671,28 @@ section ToMatrix
variable [DecidableEq ι]
section
+open scoped Matrix
+
+/-- A version of `OrthonormalBasis.toMatrix_orthonormalBasis_mem_unitary` that works for bases with
+different index types. -/
+@[simp]
+theorem OrthonormalBasis.toMatrix_orthonormalBasis_conjTranspose_mul_self [Fintype ι']
+ (a : OrthonormalBasis ι' 𝕜 E) (b : OrthonormalBasis ι 𝕜 E) :
+ (a.toBasis.toMatrix b)ᴴ * a.toBasis.toMatrix b = 1 := by
+ ext i j
+ convert a.repr.inner_map_map (b i) (b j)
+ rw [orthonormal_iff_ite.mp b.orthonormal i j]
+ rfl
+
+/-- A version of `OrthonormalBasis.toMatrix_orthonormalBasis_mem_unitary` that works for bases with
+different index types. -/
+@[simp]
+theorem OrthonormalBasis.toMatrix_orthonormalBasis_self_mul_conjTranspose [Fintype ι']
+ (a : OrthonormalBasis ι 𝕜 E) (b : OrthonormalBasis ι' 𝕜 E) :
+ a.toBasis.toMatrix b * (a.toBasis.toMatrix b)ᴴ = 1 := by
+ classical
+ rw [Matrix.mul_eq_one_comm_of_equiv (a.toBasis.indexEquiv b.toBasis),
+ a.toMatrix_orthonormalBasis_conjTranspose_mul_self b]
variable (a b : OrthonormalBasis ι 𝕜 E)
@@ -685,10 +700,7 @@ variable (a b : OrthonormalBasis ι 𝕜 E)
theorem OrthonormalBasis.toMatrix_orthonormalBasis_mem_unitary :
a.toBasis.toMatrix b ∈ Matrix.unitaryGroup ι 𝕜 := by
rw [Matrix.mem_unitaryGroup_iff']
- ext i j
- convert a.repr.inner_map_map (b i) (b j)
- rw [orthonormal_iff_ite.mp b.orthonormal i j]
- rfl
+ exact a.toMatrix_orthonormalBasis_conjTranspose_mul_self b
/-- The determinant of the change-of-basis matrix between two orthonormal bases `a`, `b` has
unit length. -/
@@ -772,7 +784,7 @@ theorem Orthonormal.exists_orthonormalBasis_extension_of_card_eq {ι : Type*} [F
obtain ⟨Y, b₀, hX, hb₀⟩ := hX.exists_orthonormalBasis_extension
have hιY : Fintype.card ι = Y.card := by
refine card_ι.symm.trans ?_
- exact FiniteDimensional.finrank_eq_card_finset_basis b₀.toBasis
+ exact Module.finrank_eq_card_finset_basis b₀.toBasis
have hvsY : s.MapsTo v Y := (s.mapsTo_image v).mono_right (by rwa [← range_restrict])
have hsv' : Set.InjOn v s := by
rw [Set.injOn_iff_injective]
@@ -820,7 +832,7 @@ irreducible_def DirectSum.IsInternal.sigmaOrthonormalBasisIndexEquiv
(hV' : OrthogonalFamily 𝕜 (fun i => V i) fun i => (V i).subtypeₗᵢ) :
(Σi, Fin (finrank 𝕜 (V i))) ≃ Fin n :=
let b := hV.collectedOrthonormalBasis hV' fun i => stdOrthonormalBasis 𝕜 (V i)
- Fintype.equivFinOfCardEq <| (FiniteDimensional.finrank_eq_card_basis b.toBasis).symm.trans hn
+ Fintype.equivFinOfCardEq <| (Module.finrank_eq_card_basis b.toBasis).symm.trans hn
/-- An `n`-dimensional `InnerProductSpace` equipped with a decomposition as an internal direct
sum has an orthonormal basis indexed by `Fin n` and subordinate to that direct sum. -/
@@ -865,7 +877,7 @@ section LinearIsometry
variable {V : Type*} [NormedAddCommGroup V] [InnerProductSpace 𝕜 V] [FiniteDimensional 𝕜 V]
variable {S : Submodule 𝕜 V} {L : S →ₗᵢ[𝕜] V}
-open FiniteDimensional
+open Module
/-- Let `S` be a subspace of a finite-dimensional complex inner product space `V`. A linear
isometry mapping `S` into `V` can be extended to a full isometry of `V`.
@@ -915,7 +927,7 @@ noncomputable def LinearIsometry.extend (L : S →ₗᵢ[𝕜] V) : V →ₗᵢ[
simp only [sq, Mx_decomp]
rw [norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero (L (p1 x)) (L3 (p2 x)) Mx_orth]
simp only [p1, p2, LinearIsometry.norm_map, _root_.add_left_inj, mul_eq_mul_left_iff,
- norm_eq_zero, true_or_iff, eq_self_iff_true, ContinuousLinearMap.coe_coe, Submodule.coe_norm,
+ norm_eq_zero, eq_self_iff_true, ContinuousLinearMap.coe_coe, Submodule.coe_norm,
Submodule.coe_eq_zero]
exact
{ toLinearMap := M
@@ -927,7 +939,7 @@ theorem LinearIsometry.extend_apply (L : S →ₗᵢ[𝕜] V) (s : S) : L.extend
simp only [add_right_eq_self, LinearIsometry.coe_toLinearMap,
LinearIsometryEquiv.coe_toLinearIsometry, LinearIsometry.coe_comp, Function.comp_apply,
orthogonalProjection_mem_subspace_eq_self, LinearMap.coe_comp, ContinuousLinearMap.coe_coe,
- Submodule.coeSubtype, LinearMap.add_apply, Submodule.coe_eq_zero,
+ Submodule.coe_subtype, LinearMap.add_apply, Submodule.coe_eq_zero,
LinearIsometryEquiv.map_eq_zero_iff, Submodule.coe_subtypeₗᵢ,
orthogonalProjection_mem_subspace_orthogonalComplement_eq_zero, Submodule.orthogonal_orthogonal,
Submodule.coe_mem]
diff --git a/Mathlib/Analysis/InnerProductSpace/Projection.lean b/Mathlib/Analysis/InnerProductSpace/Projection.lean
index 3c73dd623565f..6edcc178e0c8e 100644
--- a/Mathlib/Analysis/InnerProductSpace/Projection.lean
+++ b/Mathlib/Analysis/InnerProductSpace/Projection.lean
@@ -42,6 +42,8 @@ The Coq code is available at the following address: (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
@@ -889,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ᗮ`. -/
@@ -1028,7 +1030,7 @@ theorem orthogonalProjection_isSymmetric [HasOrthogonalProjection K] :
(K.subtypeL ∘L orthogonalProjection K : E →ₗ[𝕜] E).IsSymmetric :=
inner_orthogonalProjection_left_eq_right K
-open FiniteDimensional
+open Module
/-- Given a finite-dimensional subspace `K₂`, and a subspace `K₁`
contained in it, the dimensions of `K₁` and the intersection of its
@@ -1037,7 +1039,7 @@ theorem Submodule.finrank_add_inf_finrank_orthogonal {K₁ K₂ : Submodule 𝕜
[FiniteDimensional 𝕜 K₂] (h : K₁ ≤ K₂) :
finrank 𝕜 K₁ + finrank 𝕜 (K₁ᗮ ⊓ K₂ : Submodule 𝕜 E) = finrank 𝕜 K₂ := by
haveI : FiniteDimensional 𝕜 K₁ := Submodule.finiteDimensional_of_le h
- haveI := proper_rclike 𝕜 K₁
+ haveI := FiniteDimensional.proper_rclike 𝕜 K₁
have hd := Submodule.finrank_sup_add_finrank_inf_eq K₁ (K₁ᗮ ⊓ K₂)
rw [← inf_assoc, (Submodule.orthogonal_disjoint K₁).eq_bot, bot_inf_eq, finrank_bot,
Submodule.sup_orthogonal_inf_of_completeSpace h] at hd
@@ -1187,7 +1189,7 @@ theorem OrthogonalFamily.isInternal_iff_of_isComplete [DecidableEq ι] {V : ι
(hc : IsComplete (↑(iSup V) : Set E)) : DirectSum.IsInternal V ↔ (iSup V)ᗮ = ⊥ := by
haveI : CompleteSpace (↥(iSup V)) := hc.completeSpace_coe
simp only [DirectSum.isInternal_submodule_iff_independent_and_iSup_eq_top, hV.independent,
- true_and_iff, Submodule.orthogonal_eq_bot_iff]
+ true_and, Submodule.orthogonal_eq_bot_iff]
/-- An orthogonal family of subspaces of `E` satisfies `DirectSum.IsInternal` (that is,
they provide an internal direct sum decomposition of `E`) if and only if their span has trivial
@@ -1269,7 +1271,7 @@ section OrthonormalBasis
variable {v : Set E}
-open FiniteDimensional Submodule Set
+open Module Submodule Set
/-- An orthonormal set in an `InnerProductSpace` is maximal, if and only if the orthogonal
complement of its span is empty. -/
@@ -1340,7 +1342,7 @@ variable [FiniteDimensional 𝕜 E]
is a basis. -/
theorem maximal_orthonormal_iff_basis_of_finiteDimensional (hv : Orthonormal 𝕜 ((↑) : v → E)) :
(∀ u ⊇ v, Orthonormal 𝕜 ((↑) : u → E) → u = v) ↔ ∃ b : Basis v 𝕜 E, ⇑b = ((↑) : v → E) := by
- haveI := proper_rclike 𝕜 (span 𝕜 v)
+ haveI := FiniteDimensional.proper_rclike 𝕜 (span 𝕜 v)
rw [maximal_orthonormal_iff_orthogonalComplement_eq_bot hv]
rw [Submodule.orthogonal_eq_bot_iff]
have hv_coe : range ((↑) : v → E) = v := by simp
diff --git a/Mathlib/Analysis/InnerProductSpace/Rayleigh.lean b/Mathlib/Analysis/InnerProductSpace/Rayleigh.lean
index 1758106c5c5f0..8d29cca646b3d 100644
--- a/Mathlib/Analysis/InnerProductSpace/Rayleigh.lean
+++ b/Mathlib/Analysis/InnerProductSpace/Rayleigh.lean
@@ -130,6 +130,7 @@ theorem linearly_dependent_of_isLocalExtrOn (hT : IsSelfAdjoint T) {x₀ : F}
apply smul_right_injective (F →L[ℝ] ℝ) (two_ne_zero : (2 : ℝ) ≠ 0)
simpa only [two_smul, smul_add, add_smul, add_zero] using h₂
+open scoped InnerProductSpace in
theorem eq_smul_self_of_isLocalExtrOn_real (hT : IsSelfAdjoint T) {x₀ : F}
(hextr : IsLocalExtrOn T.reApplyInnerSelf (sphere (0 : F) ‖x₀‖) x₀) :
T x₀ = T.rayleighQuotient x₀ • x₀ := by
diff --git a/Mathlib/Analysis/InnerProductSpace/Spectrum.lean b/Mathlib/Analysis/InnerProductSpace/Spectrum.lean
index 68d1c7ecfc1b4..0f4bd55b7bae8 100644
--- a/Mathlib/Analysis/InnerProductSpace/Spectrum.lean
+++ b/Mathlib/Analysis/InnerProductSpace/Spectrum.lean
@@ -184,7 +184,7 @@ end Version1
section Version2
-variable {n : ℕ} (hn : FiniteDimensional.finrank 𝕜 E = n)
+variable {n : ℕ} (hn : Module.finrank 𝕜 E = n)
/-- A choice of orthonormal basis of eigenvectors for self-adjoint operator `T` on a
finite-dimensional inner product space `E`.
diff --git a/Mathlib/Analysis/InnerProductSpace/StarOrder.lean b/Mathlib/Analysis/InnerProductSpace/StarOrder.lean
index 2dc91976a43c2..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`
@@ -25,6 +26,7 @@ open scoped NNReal
variable {𝕜 H : Type*} [RCLike 𝕜] [NormedAddCommGroup H] [InnerProductSpace 𝕜 H] [CompleteSpace H]
variable [Algebra ℝ (H →L[𝕜] H)] [IsScalarTower ℝ 𝕜 (H →L[𝕜] H)]
+open scoped InnerProductSpace in
lemma IsPositive.spectrumRestricts {f : H →L[𝕜] H} (hf : f.IsPositive) :
SpectrumRestricts f ContinuousMap.realToNNReal := by
rw [SpectrumRestricts.nnreal_iff]
@@ -62,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 cc99f2f374367..2fcd08ccaa66d 100644
--- a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean
+++ b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean
@@ -36,11 +36,10 @@ open RCLike
open ComplexConjugate
-variable {𝕜 E E' F G : Type*} [RCLike 𝕜]
-variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
-variable [NormedAddCommGroup F] [InnerProductSpace 𝕜 F]
-variable [NormedAddCommGroup G] [InnerProductSpace 𝕜 G]
-variable [NormedAddCommGroup E'] [InnerProductSpace ℝ E']
+section Seminormed
+
+variable {𝕜 E : Type*} [RCLike 𝕜]
+variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E]
local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y
@@ -72,33 +71,47 @@ theorem IsSymmetric.apply_clm {T : E →L[𝕜] E} (hT : IsSymmetric (T : E →
⟪T x, y⟫ = ⟪x, T y⟫ :=
hT x y
-theorem isSymmetric_zero : (0 : E →ₗ[𝕜] E).IsSymmetric := fun x y =>
+@[simp]
+protected theorem IsSymmetric.zero : (0 : E →ₗ[𝕜] E).IsSymmetric := fun x y =>
(inner_zero_right x : ⟪x, 0⟫ = 0).symm ▸ (inner_zero_left y : ⟪0, y⟫ = 0)
-theorem isSymmetric_id : (LinearMap.id : E →ₗ[𝕜] E).IsSymmetric := fun _ _ => rfl
+@[deprecated (since := "2024-09-30")] alias isSymmetric_zero := IsSymmetric.zero
+@[simp]
+protected theorem IsSymmetric.id : (LinearMap.id : E →ₗ[𝕜] E).IsSymmetric := fun _ _ => rfl
+
+@[deprecated (since := "2024-09-30")] alias isSymmetric_id := IsSymmetric.id
+
+@[aesop safe apply]
theorem IsSymmetric.add {T S : E →ₗ[𝕜] E} (hT : T.IsSymmetric) (hS : S.IsSymmetric) :
(T + S).IsSymmetric := by
intro x y
rw [LinearMap.add_apply, inner_add_left, hT x y, hS x y, ← inner_add_right]
rfl
-/-- The **Hellinger--Toeplitz theorem**: if a symmetric operator is defined on a complete space,
- then it is automatically continuous. -/
-theorem IsSymmetric.continuous [CompleteSpace E] {T : E →ₗ[𝕜] E} (hT : IsSymmetric T) :
- Continuous T := by
- -- We prove it by using the closed graph theorem
- refine T.continuous_of_seq_closed_graph fun u x y hu hTu => ?_
- rw [← sub_eq_zero, ← @inner_self_eq_zero 𝕜]
- have hlhs : ∀ k : ℕ, ⟪T (u k) - T x, y - T x⟫ = ⟪u k - x, T (y - T x)⟫ := by
- intro k
- rw [← T.map_sub, hT]
- refine tendsto_nhds_unique ((hTu.sub_const _).inner tendsto_const_nhds) ?_
- simp_rw [Function.comp_apply, hlhs]
- rw [← inner_zero_left (T (y - T x))]
- refine Filter.Tendsto.inner ?_ tendsto_const_nhds
- rw [← sub_self x]
- exact hu.sub_const _
+@[aesop safe apply]
+theorem IsSymmetric.sub {T S : E →ₗ[𝕜] E} (hT : T.IsSymmetric) (hS : S.IsSymmetric) :
+ (T - S).IsSymmetric := by
+ intro x y
+ rw [LinearMap.sub_apply, inner_sub_left, hT x y, hS x y, ← inner_sub_right]
+ rfl
+
+@[aesop safe apply]
+theorem IsSymmetric.smul {c : 𝕜} (hc : conj c = c) {T : E →ₗ[𝕜] E} (hT : T.IsSymmetric) :
+ c • T |>.IsSymmetric := by
+ intro x y
+ simp only [smul_apply, inner_smul_left, hc, hT x y, inner_smul_right]
+
+@[aesop 30% apply]
+lemma IsSymmetric.mul_of_commute {S T : E →ₗ[𝕜] E} (hS : S.IsSymmetric) (hT : T.IsSymmetric)
+ (hST : Commute S T) : (S * T).IsSymmetric :=
+ fun _ _ ↦ by rw [mul_apply, hS, hT, hST, mul_apply]
+
+@[aesop safe apply]
+lemma IsSymmetric.pow {T : E →ₗ[𝕜] E} (hT : T.IsSymmetric) (n : ℕ) : (T ^ n).IsSymmetric := by
+ refine Nat.le_induction (by simp [one_eq_id]) (fun k _ ih ↦ ?_) n n.zero_le
+ rw [iterate_succ, ← mul_eq_comp]
+ exact ih.mul_of_commute hT <| .pow_left rfl k
/-- For a symmetric operator `T`, the function `fun x ↦ ⟪T x, x⟫` is real-valued. -/
@[simp]
@@ -115,16 +128,17 @@ theorem IsSymmetric.restrict_invariant {T : E →ₗ[𝕜] E} (hT : IsSymmetric
(hV : ∀ v ∈ V, T v ∈ V) : IsSymmetric (T.restrict hV) := fun v w => hT v w
theorem IsSymmetric.restrictScalars {T : E →ₗ[𝕜] E} (hT : T.IsSymmetric) :
- @LinearMap.IsSymmetric ℝ E _ _ (InnerProductSpace.rclikeToReal 𝕜 E)
- (@LinearMap.restrictScalars ℝ 𝕜 _ _ _ _ _ _ (InnerProductSpace.rclikeToReal 𝕜 E).toModule
- (InnerProductSpace.rclikeToReal 𝕜 E).toModule _ _ _ T) :=
+ letI := InnerProductSpace.rclikeToReal 𝕜 E
+ letI : IsScalarTower ℝ 𝕜 E := RestrictScalars.isScalarTower _ _ _
+ (T.restrictScalars ℝ).IsSymmetric :=
fun x y => by simp [hT x y, real_inner_eq_re_inner, LinearMap.coe_restrictScalars ℝ]
section Complex
-variable {V : Type*} [NormedAddCommGroup V] [InnerProductSpace ℂ V]
+variable {V : Type*} [SeminormedAddCommGroup V] [InnerProductSpace ℂ V]
attribute [local simp] map_ofNat in -- use `ofNat` simp theorem with bad keys
+open scoped InnerProductSpace in
/-- A linear operator on a complex inner product space is symmetric precisely when
`⟪T v, v⟫_ℂ` is real for all v. -/
theorem isSymmetric_iff_inner_map_self_real (T : V →ₗ[ℂ] V) :
@@ -166,6 +180,36 @@ theorem IsSymmetric.inner_map_polarization {T : E →ₗ[𝕜] E} (hT : T.IsSymm
sub_sub, ← mul_assoc, mul_neg, h, neg_neg, one_mul, neg_one_mul]
ring
+end LinearMap
+
+end Seminormed
+
+section Normed
+
+variable {𝕜 E : Type*} [RCLike 𝕜]
+variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E]
+
+local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y
+
+namespace LinearMap
+
+/-- The **Hellinger--Toeplitz theorem**: if a symmetric operator is defined on a complete space,
+ then it is automatically continuous. -/
+theorem IsSymmetric.continuous [CompleteSpace E] {T : E →ₗ[𝕜] E} (hT : IsSymmetric T) :
+ Continuous T := by
+ -- We prove it by using the closed graph theorem
+ refine T.continuous_of_seq_closed_graph fun u x y hu hTu => ?_
+ rw [← sub_eq_zero, ← @inner_self_eq_zero 𝕜]
+ have hlhs : ∀ k : ℕ, ⟪T (u k) - T x, y - T x⟫ = ⟪u k - x, T (y - T x)⟫ := by
+ intro k
+ rw [← T.map_sub, hT]
+ refine tendsto_nhds_unique ((hTu.sub_const _).inner tendsto_const_nhds) ?_
+ simp_rw [Function.comp_apply, hlhs]
+ rw [← inner_zero_left (T (y - T x))]
+ refine Filter.Tendsto.inner ?_ tendsto_const_nhds
+ rw [← sub_self x]
+ exact hu.sub_const _
+
/-- A symmetric linear map `T` is zero if and only if `⟪T x, x⟫_ℝ = 0` for all `x`.
See `inner_map_self_eq_zero` for the complex version without the symmetric assumption. -/
theorem IsSymmetric.inner_map_self_eq_zero {T : E →ₗ[𝕜] E} (hT : T.IsSymmetric) :
@@ -177,3 +221,5 @@ theorem IsSymmetric.inner_map_self_eq_zero {T : E →ₗ[𝕜] E} (hT : T.IsSymm
ring
end LinearMap
+
+end Normed
diff --git a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean
index 5f43d060381e7..a68bcb961c62e 100644
--- a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean
+++ b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean
@@ -71,7 +71,7 @@ noncomputable section
open scoped RealInnerProductSpace ComplexConjugate
-open FiniteDimensional
+open Module
lemma FiniteDimensional.of_fact_finrank_eq_two {K V : Type*} [DivisionRing K]
[AddCommGroup V] [Module K V] [Fact (finrank K V = 2)] : FiniteDimensional K V :=
@@ -204,7 +204,7 @@ def rightAngleRotationAux₂ : E →ₗᵢ[ℝ] E :=
exact o.areaForm_le x (o.rightAngleRotationAux₁ x)
· let K : Submodule ℝ E := ℝ ∙ x
have : Nontrivial Kᗮ := by
- apply @FiniteDimensional.nontrivial_of_finrank_pos ℝ
+ apply nontrivial_of_finrank_pos (R := ℝ)
have : finrank ℝ K ≤ Finset.card {x} := by
rw [← Set.toFinset_singleton]
exact finrank_span_le_card ({x} : Set E)
@@ -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]
@@ -422,8 +420,7 @@ theorem nonneg_inner_and_areaForm_eq_zero_iff_sameRay (x y : E) :
· intro h
obtain ⟨r, hr, rfl⟩ := h.exists_nonneg_left hx
simp only [inner_smul_right, real_inner_self_eq_norm_sq, LinearMap.map_smulₛₗ,
- areaForm_apply_self, Algebra.id.smul_eq_mul, mul_zero, eq_self_iff_true,
- and_true_iff]
+ areaForm_apply_self, Algebra.id.smul_eq_mul, mul_zero, eq_self_iff_true, and_true]
positivity
/-- A complex-valued real-bilinear map on an oriented real inner product space of dimension 2. Its
diff --git a/Mathlib/Analysis/InnerProductSpace/WeakOperatorTopology.lean b/Mathlib/Analysis/InnerProductSpace/WeakOperatorTopology.lean
index 34f154ad37514..52173af64e2c0 100644
--- a/Mathlib/Analysis/InnerProductSpace/WeakOperatorTopology.lean
+++ b/Mathlib/Analysis/InnerProductSpace/WeakOperatorTopology.lean
@@ -15,7 +15,7 @@ Hilbert spaces. This mostly involves using the Fréchet-Riesz representation to
applications of elements of the dual and inner products with vectors in the space.
-/
-open scoped Topology
+open scoped Topology InnerProductSpace
namespace ContinuousLinearMapWOT
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 5667478982a21..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
@@ -131,7 +139,13 @@ theorem balancedHull.balanced (s : Set E) : Balanced 𝕜 (balancedHull 𝕜 s)
simp_rw [balancedHull, smul_set_iUnion₂, subset_def, mem_iUnion₂]
rintro x ⟨r, hr, hx⟩
rw [← smul_assoc] at hx
- exact ⟨a • r, (SeminormedRing.norm_mul _ _).trans (mul_le_one ha (norm_nonneg r) hr), 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
@@ -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 03bfae8efd21d..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
@@ -183,7 +186,7 @@ theorem Balanced.smul_mono (hs : Balanced 𝕝 s) {a : 𝕝} {b : 𝕜} (h : ‖
a • s = b • (b⁻¹ • a) • s := by rw [smul_assoc, smul_inv_smul₀ hb]
_ ⊆ b • s := smul_set_mono <| hs _ <| by
rw [norm_smul, norm_inv, ← div_eq_inv_mul]
- exact div_le_one_of_le h (norm_nonneg _)
+ exact div_le_one_of_le₀ h (norm_nonneg _)
theorem Balanced.smul_mem_mono [SMulCommClass 𝕝 𝕜 E] (hs : Balanced 𝕝 s) {a : 𝕜} {b : 𝕝}
(ha : a • x ∈ s) (hba : ‖b‖ ≤ ‖a‖) : b • x ∈ s := by
@@ -193,7 +196,7 @@ theorem Balanced.smul_mem_mono [SMulCommClass 𝕝 𝕜 E] (hs : Balanced 𝕝 s
(a⁻¹ • b) • a • x ∈ s := by
refine hs.smul_mem ?_ ha
rw [norm_smul, norm_inv, ← div_eq_inv_mul]
- exact div_le_one_of_le hba (norm_nonneg _)
+ exact div_le_one_of_le₀ hba (norm_nonneg _)
(a⁻¹ • b) • a • x = b • x := by rw [smul_comm, smul_assoc, smul_inv_smul₀ ha₀]
theorem Balanced.subset_smul (hA : Balanced 𝕜 A) (ha : 1 ≤ ‖a‖) : A ⊆ a • A := by
diff --git a/Mathlib/Analysis/LocallyConvex/Bounded.lean b/Mathlib/Analysis/LocallyConvex/Bounded.lean
index e1d8921b60a53..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
@@ -176,6 +177,11 @@ lemma isVonNBounded_iff_tendsto_smallSets_nhds {𝕜 E : Type*} [NormedDivisionR
alias ⟨IsVonNBounded.tendsto_smallSets_nhds, _⟩ := isVonNBounded_iff_tendsto_smallSets_nhds
+lemma isVonNBounded_iff_absorbing_le {𝕜 E : Type*} [NormedDivisionRing 𝕜]
+ [AddCommGroup E] [Module 𝕜 E] [TopologicalSpace E] {S : Set E} :
+ IsVonNBounded 𝕜 S ↔ Filter.absorbing 𝕜 S ≤ 𝓝 0 :=
+ .rfl
+
lemma isVonNBounded_pi_iff {𝕜 ι : Type*} {E : ι → Type*} [NormedDivisionRing 𝕜]
[∀ i, AddCommGroup (E i)] [∀ i, Module 𝕜 (E i)] [∀ i, TopologicalSpace (E i)]
{S : Set (∀ i, E i)} : IsVonNBounded 𝕜 S ↔ ∀ i, IsVonNBounded 𝕜 (eval i '' S) := by
@@ -193,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
@@ -239,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 a58db852ed74d..d1b8d23fb2ca3 100644
--- a/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean
+++ b/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean
@@ -99,7 +99,7 @@ theorem LinearMap.continuousAt_zero_of_locally_bounded (f : E →ₛₗ[σ] F)
refine bE.1.to_hasBasis ?_ ?_
· intro n _
use n + 1
- simp only [Ne, Nat.succ_ne_zero, not_false_iff, Nat.cast_add, Nat.cast_one, true_and_iff]
+ simp only [Ne, Nat.succ_ne_zero, not_false_iff, Nat.cast_add, Nat.cast_one, true_and]
-- `b (n + 1) ⊆ b n` follows from `Antitone`.
have h : b (n + 1) ⊆ b n := bE.2 (by simp)
refine _root_.trans ?_ h
@@ -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/Polar.lean b/Mathlib/Analysis/LocallyConvex/Polar.lean
index e0235090926dc..dba80d95bd857 100644
--- a/Mathlib/Analysis/LocallyConvex/Polar.lean
+++ b/Mathlib/Analysis/LocallyConvex/Polar.lean
@@ -5,7 +5,7 @@ Authors: Moritz Doll, Kalle Kytölä
-/
import Mathlib.Analysis.Normed.Field.Basic
import Mathlib.LinearAlgebra.SesquilinearForm
-import Mathlib.Topology.Algebra.Module.WeakDual
+import Mathlib.Topology.Algebra.Module.WeakBilin
/-!
# Polar set
@@ -64,6 +64,10 @@ theorem polar_mem (s : Set E) (y : F) (hy : y ∈ B.polar s) : ∀ x ∈ s, ‖B
theorem zero_mem_polar (s : Set E) : (0 : F) ∈ B.polar s := fun _ _ => by
simp only [map_zero, norm_zero, zero_le_one]
+theorem polar_nonempty (s : Set E) : Set.Nonempty (B.polar s) := by
+ use 0
+ exact zero_mem_polar B s
+
theorem polar_eq_iInter {s : Set E} : B.polar s = ⋂ x ∈ s, { y : F | ‖B x y‖ ≤ 1 } := by
ext
simp only [polar_mem_iff, Set.mem_iInter, Set.mem_setOf_eq]
diff --git a/Mathlib/Analysis/LocallyConvex/WeakDual.lean b/Mathlib/Analysis/LocallyConvex/WeakDual.lean
index 455453490b735..9e7b880fc4e4d 100644
--- a/Mathlib/Analysis/LocallyConvex/WeakDual.lean
+++ b/Mathlib/Analysis/LocallyConvex/WeakDual.lean
@@ -3,9 +3,9 @@ Copyright (c) 2022 Moritz Doll. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Moritz Doll
-/
-import Mathlib.Topology.Algebra.Module.WeakDual
import Mathlib.Analysis.Normed.Field.Lemmas
import Mathlib.Analysis.LocallyConvex.WithSeminorms
+import Mathlib.Topology.Algebra.Module.WeakBilin
/-!
# Weak Dual in Topological Vector Spaces
@@ -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_iff]
- 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/WeakSpace.lean b/Mathlib/Analysis/LocallyConvex/WeakSpace.lean
new file mode 100644
index 0000000000000..ff4823a65b3fb
--- /dev/null
+++ b/Mathlib/Analysis/LocallyConvex/WeakSpace.lean
@@ -0,0 +1,100 @@
+/-
+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.LinearAlgebra.Dual
+import Mathlib.Analysis.NormedSpace.HahnBanach.Separation
+import Mathlib.Topology.Algebra.Module.WeakDual
+
+/-! # Closures of convex sets in locally convex spaces
+
+This file contains the standard result that if `E` is a vector space with two locally convex
+topologies, then the closure of a convex set is the same in either topology, provided they have the
+same collection of continuous linear functionals. In particular, the weak closure of a convex set
+in a locally convex space coincides with the closure in the original topology.
+Of course, we phrase this in terms of linear maps between locally convex spaces, rather than
+creating two separate topologies on the same space.
+-/
+
+variable {𝕜 E F : Type*}
+variable [RCLike 𝕜] [AddCommGroup E] [Module 𝕜 E] [AddCommGroup F] [Module 𝕜 F]
+variable [Module ℝ E] [IsScalarTower ℝ 𝕜 E] [Module ℝ F] [IsScalarTower ℝ 𝕜 F]
+variable [TopologicalSpace E] [TopologicalAddGroup E] [ContinuousSMul 𝕜 E] [LocallyConvexSpace ℝ E]
+variable [TopologicalSpace F] [TopologicalAddGroup F] [ContinuousSMul 𝕜 F] [LocallyConvexSpace ℝ F]
+
+variable (𝕜) in
+/-- If `E` is a locally convex space over `𝕜` (with `RCLike 𝕜`), and `s : Set E` is `ℝ`-convex, then
+the closure of `s` and the weak closure of `s` coincide. More precisely, the topological closure
+commutes with `toWeakSpace 𝕜 E`.
+
+This holds more generally for any linear equivalence `e : E ≃ₗ[𝕜] F` between locally convex spaces
+such that precomposition with `e` and `e.symm` preserves continuity of linear functionals. See
+`LinearEquiv.image_closure_of_convex`. -/
+theorem Convex.toWeakSpace_closure {s : Set E} (hs : Convex ℝ s) :
+ (toWeakSpace 𝕜 E) '' (closure s) = closure (toWeakSpace 𝕜 E '' s) := by
+ refine le_antisymm (map_continuous <| toWeakSpaceCLM 𝕜 E).continuousOn.image_closure
+ (Set.compl_subset_compl.mp fun x hx ↦ ?_)
+ obtain ⟨x, -, rfl⟩ := (toWeakSpace 𝕜 E).toEquiv.image_compl (closure s) |>.symm.subset hx
+ have : ContinuousSMul ℝ E := IsScalarTower.continuousSMul 𝕜
+ obtain ⟨f, u, hus, hux⟩ := RCLike.geometric_hahn_banach_closed_point (𝕜 := 𝕜)
+ hs.closure isClosed_closure (by simpa using hx)
+ let f' : WeakSpace 𝕜 E →L[𝕜] 𝕜 :=
+ { toLinearMap := (f : E →ₗ[𝕜] 𝕜).comp ((toWeakSpace 𝕜 E).symm : WeakSpace 𝕜 E →ₗ[𝕜] E)
+ cont := WeakBilin.eval_continuous (topDualPairing 𝕜 E).flip _ }
+ have hux' : u < RCLike.reCLM.comp (f'.restrictScalars ℝ) (toWeakSpace 𝕜 E x) := by simpa [f']
+ have hus' : closure (toWeakSpace 𝕜 E '' s) ⊆
+ {y | RCLike.reCLM.comp (f'.restrictScalars ℝ) y ≤ u} := by
+ refine closure_minimal ?_ <| isClosed_le (by fun_prop) (by fun_prop)
+ rintro - ⟨y, hy, rfl⟩
+ simpa [f'] using (hus y <| subset_closure hy).le
+ exact (hux'.not_le <| hus' ·)
+
+/-- If `e : E →ₗ[𝕜] F` is a linear map between locally convex spaces, and `f ∘ e` is continuous
+for every continuous linear functional `f : F →L[𝕜] 𝕜`, then `e` commutes with the closure on
+convex sets. -/
+theorem LinearMap.image_closure_of_convex {s : Set E} (hs : Convex ℝ s) (e : E →ₗ[𝕜] F)
+ (he : ∀ f : F →L[𝕜] 𝕜, Continuous (e.dualMap f)) :
+ e '' (closure s) ⊆ closure (e '' s) := by
+ suffices he' : Continuous (toWeakSpace 𝕜 F <| e <| (toWeakSpace 𝕜 E).symm ·) by
+ have h_convex : Convex ℝ (e '' s) := hs.linear_image e
+ rw [← Set.image_subset_image_iff (toWeakSpace 𝕜 F).injective, h_convex.toWeakSpace_closure 𝕜]
+ simpa only [Set.image_image, ← hs.toWeakSpace_closure 𝕜, LinearEquiv.symm_apply_apply]
+ using he'.continuousOn.image_closure (s := toWeakSpace 𝕜 E '' s)
+ exact WeakBilin.continuous_of_continuous_eval _ fun f ↦
+ WeakBilin.eval_continuous _ { toLinearMap := e.dualMap f : E →L[𝕜] 𝕜 }
+
+/-- If `e` is a linear isomorphism between two locally convex spaces, and `e` induces (via
+precomposition) an isomorphism between their continuous duals, then `e` commutes with the closure
+on convex sets.
+
+The hypotheses hold automatically for `e := toWeakSpace 𝕜 E`, see `Convex.toWeakSpace_closure`. -/
+theorem LinearEquiv.image_closure_of_convex {s : Set E} (hs : Convex ℝ s) (e : E ≃ₗ[𝕜] F)
+ (he₁ : ∀ f : F →L[𝕜] 𝕜, Continuous (e.dualMap f))
+ (he₂ : ∀ f : E →L[𝕜] 𝕜, Continuous (e.symm.dualMap f)) :
+ e '' (closure s) = closure (e '' s) := by
+ refine le_antisymm ((e : E →ₗ[𝕜] F).image_closure_of_convex hs he₁) ?_
+ simp only [Set.le_eq_subset, ← Set.image_subset_image_iff e.symm.injective]
+ simpa [Set.image_image]
+ using (e.symm : F →ₗ[𝕜] E).image_closure_of_convex (hs.linear_image (e : E →ₗ[𝕜] F)) he₂
+
+/-- If `e` is a linear isomorphism between two locally convex spaces, and `e` induces (via
+precomposition) an isomorphism between their continuous duals, then `e` commutes with the closure
+on convex sets.
+
+The hypotheses hold automatically for `e := toWeakSpace 𝕜 E`, see `Convex.toWeakSpace_closure`. -/
+theorem LinearEquiv.image_closure_of_convex' {s : Set E} (hs : Convex ℝ s) (e : E ≃ₗ[𝕜] F)
+ (e_dual : (F →L[𝕜] 𝕜) ≃ (E →L[𝕜] 𝕜))
+ (he : ∀ f : F →L[𝕜] 𝕜, (e_dual f : E →ₗ[𝕜] 𝕜) = e.dualMap f) :
+ e '' (closure s) = closure (e '' s) := by
+ have he' (f : E →L[𝕜] 𝕜) : (e_dual.symm f : F →ₗ[𝕜] 𝕜) = e.symm.dualMap f := by
+ simp only [DFunLike.ext'_iff, ContinuousLinearMap.coe_coe] at he ⊢
+ have (g : E →L[𝕜] 𝕜) : ⇑g = e_dual.symm g ∘ e := by
+ have := he _ ▸ congr(⇑$(e_dual.apply_symm_apply g)).symm
+ simpa
+ ext x
+ conv_rhs => rw [LinearEquiv.dualMap_apply, ContinuousLinearMap.coe_coe, this]
+ simp
+ refine e.image_closure_of_convex hs ?_ ?_
+ · simpa [← he] using fun f ↦ map_continuous (e_dual f)
+ · simpa [← he'] using fun f ↦ map_continuous (e_dual.symm f)
diff --git a/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean b/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean
index c562e61f2eae3..03f93e0ed2cb9 100644
--- a/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean
+++ b/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean
@@ -135,7 +135,7 @@ theorem basisSets_smul_right (v : E) (U : Set E) (hU : U ∈ p.basisSets) :
rw [hU, Filter.eventually_iff]
simp_rw [(s.sup p).mem_ball_zero, map_smul_eq_mul]
by_cases h : 0 < (s.sup p) v
- · simp_rw [(lt_div_iff h).symm]
+ · simp_rw [(lt_div_iff₀ h).symm]
rw [← _root_.ball_zero_eq]
exact Metric.ball_mem_nhds 0 (div_pos hr h)
simp_rw [le_antisymm (not_lt.mp h) (apply_nonneg _ v), mul_zero, hr]
@@ -623,14 +623,11 @@ protected theorem _root_.WithSeminorms.equicontinuous_TFAE {κ : Type*}
clear u hu hq
-- Now we can prove the equivalence in this setting
simp only [List.map]
- tfae_have 1 → 3
- · exact uniformEquicontinuous_of_equicontinuousAt_zero f
- tfae_have 3 → 2
- · exact UniformEquicontinuous.equicontinuous
- tfae_have 2 → 1
- · exact fun H ↦ H 0
+ tfae_have 1 → 3 := uniformEquicontinuous_of_equicontinuousAt_zero f
+ tfae_have 3 → 2 := UniformEquicontinuous.equicontinuous
+ tfae_have 2 → 1 := fun H ↦ H 0
tfae_have 3 → 5
- · intro H
+ | H => by
have : ∀ᶠ x in 𝓝 0, ∀ k, q i (f k x) ≤ 1 := by
filter_upwards [Metric.equicontinuousAt_iff_right.mp (H.equicontinuous 0) 1 one_pos]
with x hx k
@@ -642,17 +639,16 @@ protected theorem _root_.WithSeminorms.equicontinuous_TFAE {κ : Type*}
refine ⟨bdd, Seminorm.continuous' (r := 1) ?_⟩
filter_upwards [this] with x hx
simpa only [closedBall_iSup bdd _ one_pos, mem_iInter, mem_closedBall_zero] using hx
- tfae_have 5 → 4
- · exact fun H ↦ ⟨⨆ k, (q i).comp (f k), Seminorm.coe_iSup_eq H.1 ▸ H.2, le_ciSup H.1⟩
+ tfae_have 5 → 4 := fun H ↦ ⟨⨆ k, (q i).comp (f k), Seminorm.coe_iSup_eq H.1 ▸ H.2, le_ciSup H.1⟩
tfae_have 4 → 1 -- This would work over any `NormedField`
- · intro ⟨p, hp, hfp⟩
- exact Metric.equicontinuousAt_of_continuity_modulus p (map_zero p ▸ hp.tendsto 0) _ <|
+ | ⟨p, hp, hfp⟩ =>
+ Metric.equicontinuousAt_of_continuity_modulus p (map_zero p ▸ hp.tendsto 0) _ <|
Eventually.of_forall fun x k ↦ by simpa using hfp k x
tfae_finish
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 :=
@@ -660,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)) ∧
@@ -869,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) :=
@@ -881,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 e871352abb1cc..d75d457d35cf7 100644
--- a/Mathlib/Analysis/MeanInequalities.lean
+++ b/Mathlib/Analysis/MeanInequalities.lean
@@ -3,6 +3,7 @@ Copyright (c) 2019 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov, Sébastien Gouëzel, Rémy Degenne
-/
+import Mathlib.Algebra.BigOperators.Expect
import Mathlib.Analysis.Convex.Jensen
import Mathlib.Analysis.Convex.SpecificFunctions.Basic
import Mathlib.Analysis.SpecialFunctions.Pow.NNReal
@@ -105,6 +106,7 @@ less than or equal to the sum of the maximum values of the summands.
universe u v
open Finset NNReal ENNReal
+open scoped BigOperators
noncomputable section
@@ -270,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
@@ -492,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)
@@ -520,7 +522,7 @@ theorem isGreatest_Lp (f : ι → ℝ≥0) {p q : ℝ} (hpq : p.IsConjExponent q
simp [h, hpq.ne_zero]
simp only [Set.mem_setOf_eq, div_rpow, ← sum_div, ← rpow_mul,
div_mul_cancel₀ _ hpq.symm.ne_zero, rpow_one, div_le_iff₀ hf, one_mul, hpq.mul_eq_add, ←
- rpow_sub' A, add_sub_cancel_right, le_refl, true_and_iff, ← mul_div_assoc, B]
+ rpow_sub' A, add_sub_cancel_right, le_refl, true_and, ← mul_div_assoc, B]
rw [div_eq_iff, ← rpow_add hf.ne', one_div, one_div, hpq.inv_add_inv_conj, rpow_one]
simpa [hpq.symm.ne_zero] using hf.ne'
· rintro _ ⟨g, hg, rfl⟩
@@ -618,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)
@@ -660,6 +662,18 @@ lemma inner_le_weight_mul_Lp_of_nonneg (s : Finset ι) {p : ℝ} (hp : 1 ≤ p)
norm_cast at *
exact NNReal.inner_le_weight_mul_Lp _ hp _ _
+/-- **Weighted Hölder inequality** in terms of `Finset.expect`. -/
+lemma compact_inner_le_weight_mul_Lp_of_nonneg (s : Finset ι) {p : ℝ} (hp : 1 ≤ p) {w f : ι → ℝ}
+ (hw : ∀ i, 0 ≤ w i) (hf : ∀ i, 0 ≤ f i) :
+ 𝔼 i ∈ s, w i * f i ≤ (𝔼 i ∈ s, w i) ^ (1 - p⁻¹) * (𝔼 i ∈ s, w i * f i ^ p) ^ p⁻¹ := by
+ simp_rw [expect_eq_sum_div_card]
+ rw [div_rpow, div_rpow, div_mul_div_comm, ← rpow_add', sub_add_cancel, rpow_one]
+ · gcongr
+ exact inner_le_weight_mul_Lp_of_nonneg s hp _ _ hw hf
+ any_goals simp
+ · exact sum_nonneg fun i _ ↦ by have := hw i; have := hf i; positivity
+ · exact sum_nonneg fun i _ ↦ by have := hw i; positivity
+
/-- **Hölder inequality**: the scalar product of two functions is bounded by the product of their
`L^p` and `L^q` norms when `p` and `q` are conjugate exponents. A version for `ℝ`-valued functions.
For an alternative version, convenient if the infinite sums are already expressed as `p`-th powers,
@@ -708,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]
@@ -807,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/MeanInequalitiesPow.lean b/Mathlib/Analysis/MeanInequalitiesPow.lean
index 2c7f60fd4576c..fdee6d8fdbe46 100644
--- a/Mathlib/Analysis/MeanInequalitiesPow.lean
+++ b/Mathlib/Analysis/MeanInequalitiesPow.lean
@@ -61,23 +61,6 @@ theorem pow_arith_mean_le_arith_mean_pow_of_even (w z : ι → ℝ) (hw : ∀ i
(∑ i ∈ s, w i * z i) ^ n ≤ ∑ i ∈ s, w i * z i ^ n :=
hn.convexOn_pow.map_sum_le hw hw' fun _ _ => Set.mem_univ _
-/-- Specific case of Jensen's inequality for sums of powers -/
-theorem pow_sum_div_card_le_sum_pow {f : ι → ℝ} (n : ℕ) (hf : ∀ a ∈ s, 0 ≤ f a) :
- (∑ x ∈ s, f x) ^ (n + 1) / (s.card : ℝ) ^ n ≤ ∑ x ∈ s, f x ^ (n + 1) := by
- rcases s.eq_empty_or_nonempty with (rfl | hs)
- · simp_rw [Finset.sum_empty, zero_pow n.succ_ne_zero, zero_div]; rfl
- · have hs0 : 0 < (s.card : ℝ) := Nat.cast_pos.2 hs.card_pos
- suffices (∑ x ∈ s, f x / s.card) ^ (n + 1) ≤ ∑ x ∈ s, f x ^ (n + 1) / s.card by
- rwa [← Finset.sum_div, ← Finset.sum_div, div_pow, pow_succ (s.card : ℝ), ← div_div,
- div_le_iff₀ hs0, div_mul, div_self hs0.ne', div_one] at this
- have :=
- @ConvexOn.map_sum_le ℝ ℝ ℝ ι _ _ _ _ _ _ (Set.Ici 0) (fun x => x ^ (n + 1)) s
- (fun _ => 1 / s.card) ((↑) ∘ f) (convexOn_pow (n + 1)) ?_ ?_ fun i hi =>
- Set.mem_Ici.2 (hf i hi)
- · simpa only [inv_mul_eq_div, one_div, Algebra.id.smul_eq_mul] using this
- · simp only [one_div, inv_nonneg, Nat.cast_nonneg, imp_true_iff]
- · simpa only [one_div, Finset.sum_const, nsmul_eq_mul] using mul_inv_cancel₀ hs0.ne'
-
theorem zpow_arith_mean_le_arith_mean_zpow (w z : ι → ℝ) (hw : ∀ i ∈ s, 0 ≤ w i)
(hw' : ∑ i ∈ s, w i = 1) (hz : ∀ i ∈ s, 0 < z i) (m : ℤ) :
(∑ i ∈ s, w i * z i) ^ m ≤ ∑ i ∈ s, w i * z i ^ m :=
@@ -111,11 +94,6 @@ theorem pow_arith_mean_le_arith_mean_pow (w z : ι → ℝ≥0) (hw' : ∑ i ∈
Real.pow_arith_mean_le_arith_mean_pow s _ _ (fun i _ => (w i).coe_nonneg)
(mod_cast hw') (fun i _ => (z i).coe_nonneg) n
-theorem pow_sum_div_card_le_sum_pow (f : ι → ℝ≥0) (n : ℕ) :
- (∑ x ∈ s, f x) ^ (n + 1) / (s.card : ℝ) ^ n ≤ ∑ x ∈ s, f x ^ (n + 1) := by
- simpa only [← NNReal.coe_le_coe, NNReal.coe_sum, Nonneg.coe_div, NNReal.coe_pow] using
- @Real.pow_sum_div_card_le_sum_pow ι s (((↑) : ℝ≥0 → ℝ) ∘ f) n fun _ _ => NNReal.coe_nonneg _
-
/-- Weighted generalized mean inequality, version for sums over finite sets, with `ℝ≥0`-valued
functions and real exponents. -/
theorem rpow_arith_mean_le_arith_mean_rpow (w z : ι → ℝ≥0) (hw' : ∑ i ∈ s, w i = 1) {p : ℝ}
@@ -221,7 +199,7 @@ theorem rpow_arith_mean_le_arith_mean_rpow (w z : ι → ℝ≥0∞) (hw' : ∑
· -- first, prove `(∑ i ∈ s, w i * z i) ^ p = ⊤ → ∑ i ∈ s, (w i * z i ^ p) = ⊤`
rw [rpow_eq_top_iff, sum_eq_top, sum_eq_top]
intro h
- simp only [and_false_iff, hp_not_neg, false_or_iff] at h
+ simp only [and_false, hp_not_neg, false_or] at h
rcases h.left with ⟨a, H, ha⟩
use a, H
rwa [← h_top_iff_rpow_top a 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 caa4e080fffdf..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
@@ -220,7 +221,7 @@ theorem eventually_homothety_mem_of_mem_interior (x : Q) {s : Set Q} {y : Q} (hy
obtain ⟨u, hu₁, hu₂, hu₃⟩ := mem_interior.mp hy
obtain ⟨ε, hε, hyε⟩ := Metric.isOpen_iff.mp hu₂ y hu₃
refine ⟨ε / ‖y -ᵥ x‖, div_pos hε hxy, fun δ (hδ : ‖δ - 1‖ < ε / ‖y -ᵥ x‖) => hu₁ (hyε ?_)⟩
- rw [lt_div_iff hxy, ← norm_smul, sub_smul, one_smul] at hδ
+ rw [lt_div_iff₀ hxy, ← norm_smul, sub_smul, one_smul] at hδ
rwa [homothety_apply, Metric.mem_ball, dist_eq_norm_vsub W, vadd_vsub_eq_sub_vsub]
theorem eventually_homothety_image_subset_of_finite_subset_interior (x : Q) {s : Set Q} {t : Set Q}
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 f0545ea11cc87..d6db878a74fdd 100644
--- a/Mathlib/Analysis/Normed/Affine/Isometry.lean
+++ b/Mathlib/Analysis/Normed/Affine/Isometry.lean
@@ -69,9 +69,9 @@ theorem linear_eq_linearIsometry : f.linear = f.linearIsometry.toLinearMap := by
ext
rfl
-instance : FunLike (P →ᵃⁱ[𝕜] P₂) P P₂ :=
- { coe := fun f => f.toFun,
- coe_injective' := fun f g => by cases f; cases g; simp }
+instance : FunLike (P →ᵃⁱ[𝕜] P₂) P P₂ where
+ coe f := f.toFun
+ coe_injective' f g := by cases f; cases g; simp
@[simp]
theorem coe_toAffineMap : ⇑f.toAffineMap = f := by
@@ -282,16 +282,16 @@ theorem linear_eq_linear_isometry : e.linear = e.linearIsometryEquiv.toLinearEqu
ext
rfl
-instance : EquivLike (P ≃ᵃⁱ[𝕜] P₂) P P₂ :=
- { coe := fun f => f.toFun
- inv := fun f => f.invFun
- left_inv := fun f => f.left_inv
- right_inv := fun f => f.right_inv,
- coe_injective' := fun f g h _ => by
- cases f
- cases g
- congr
- simpa [DFunLike.coe_injective.eq_iff] using h }
+instance : EquivLike (P ≃ᵃⁱ[𝕜] P₂) P P₂ where
+ coe f := f.toFun
+ inv f := f.invFun
+ left_inv f := f.left_inv
+ right_inv f := f.right_inv
+ coe_injective' f g h _ := by
+ cases f
+ cases g
+ congr
+ simpa [DFunLike.coe_injective.eq_iff] using h
@[simp]
theorem coe_mk (e : P ≃ᵃ[𝕜] P₂) (he : ∀ x, ‖e.linear x‖ = ‖x‖) : ⇑(mk e he) = e :=
@@ -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 1e8094ecb6331..a417ad5c90908 100644
--- a/Mathlib/Analysis/Normed/Algebra/Exponential.lean
+++ b/Mathlib/Analysis/Normed/Algebra/Exponential.lean
@@ -3,12 +3,9 @@ Copyright (c) 2021 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.Analytic.Basic
+import Mathlib.Analysis.Analytic.ChangeOrigin
import Mathlib.Analysis.Complex.Basic
-import Mathlib.Analysis.Normed.Field.InfiniteSum
import Mathlib.Data.Nat.Choose.Cast
-import Mathlib.Data.Finset.NoncommProd
-import Mathlib.Topology.Algebra.Algebra
/-!
# Exponential in a Banach algebra
@@ -389,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 {𝕂 𝔸 𝔹}
@@ -473,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 2f0463ab0aa36..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
@@ -145,25 +145,23 @@ nonrec theorem isUnit_exp (A : Matrix m m 𝔸) : IsUnit (exp 𝕂 A) := by
letI : NormedAlgebra 𝕂 (Matrix m m 𝔸) := Matrix.linftyOpNormedAlgebra
exact isUnit_exp _ A
--- TODO(mathlib4#6607): fix elaboration so `val` isn't needed
nonrec theorem exp_units_conj (U : (Matrix m m 𝔸)ˣ) (A : Matrix m m 𝔸) :
- exp 𝕂 (U.val * A * (U⁻¹).val) = U.val * exp 𝕂 A * (U⁻¹).val := by
+ exp 𝕂 (U * A * U⁻¹) = U * exp 𝕂 A * U⁻¹ := by
letI : SeminormedRing (Matrix m m 𝔸) := Matrix.linftyOpSemiNormedRing
letI : NormedRing (Matrix m m 𝔸) := Matrix.linftyOpNormedRing
letI : NormedAlgebra 𝕂 (Matrix m m 𝔸) := Matrix.linftyOpNormedAlgebra
exact exp_units_conj _ U A
--- TODO(mathlib4#6607): fix elaboration so `val` isn't needed
theorem exp_units_conj' (U : (Matrix m m 𝔸)ˣ) (A : Matrix m m 𝔸) :
- exp 𝕂 ((U⁻¹).val * A * U.val) = (U⁻¹).val * exp 𝕂 A * U.val :=
+ exp 𝕂 (U⁻¹ * A * U) = U⁻¹ * exp 𝕂 A * U :=
exp_units_conj 𝕂 U⁻¹ A
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
new file mode 100644
index 0000000000000..715ad8694cf6f
--- /dev/null
+++ b/Mathlib/Analysis/Normed/Algebra/Norm.lean
@@ -0,0 +1,194 @@
+/-
+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.Analysis.Normed.Ring.Seminorm
+import Mathlib.Analysis.Seminorm
+
+/-!
+# Algebra norms
+
+We define algebra norms and multiplicative algebra norms.
+
+## Main Definitions
+* `AlgebraNorm` : an algebra norm on an `R`-algebra `S` is a ring norm on `S` compatible with
+ the action of `R`.
+* `MulAlgebraNorm` : a multiplicative algebra norm on an `R`-algebra `S` is a multiplicative
+ ring norm on `S` compatible with the action of `R`.
+
+## Tags
+
+norm, algebra norm
+-/
+
+/-- An algebra norm on an `R`-algebra `S` is a ring norm on `S` compatible with the
+action of `R`. -/
+structure AlgebraNorm (R : Type*) [SeminormedCommRing R] (S : Type*) [Ring S] [Algebra R S] extends
+ RingNorm S, Seminorm R S
+
+attribute [nolint docBlame] AlgebraNorm.toSeminorm AlgebraNorm.toRingNorm
+
+instance (K : Type*) [NormedField K] : Inhabited (AlgebraNorm K K) :=
+ ⟨{ toFun := norm
+ map_zero' := norm_zero
+ add_le' := norm_add_le
+ neg' := norm_neg
+ smul' := norm_mul
+ mul_le' := norm_mul_le
+ eq_zero_of_map_eq_zero' := fun _ => norm_eq_zero.mp }⟩
+
+/-- `AlgebraNormClass F R S` states that `F` is a type of `R`-algebra norms on the ring `S`.
+You should extend this class when you extend `AlgebraNorm`. -/
+class AlgebraNormClass (F : Type*) (R : outParam <| Type*) [SeminormedCommRing R]
+ (S : outParam <| Type*) [Ring S] [Algebra R S] [FunLike F S ℝ] extends RingNormClass F S ℝ,
+ SeminormClass F R S : Prop
+
+namespace AlgebraNorm
+
+variable {R : Type*} [SeminormedCommRing R] {S : Type*} [Ring S] [Algebra R S] {f : AlgebraNorm R S}
+
+/-- The ring seminorm underlying an algebra norm. -/
+def toRingSeminorm' (f : AlgebraNorm R S) : RingSeminorm S :=
+ f.toRingNorm.toRingSeminorm
+
+instance : FunLike (AlgebraNorm R S) S ℝ where
+ coe f := f.toFun
+ coe_injective' f f' h := by
+ simp only [AddGroupSeminorm.toFun_eq_coe, RingSeminorm.toFun_eq_coe] at h
+ cases f; cases f'; congr;
+ simp only at h
+ ext s
+ erw [h]
+ rfl
+
+instance algebraNormClass : AlgebraNormClass (AlgebraNorm R S) R S where
+ map_zero f := f.map_zero'
+ map_add_le_add f := f.add_le'
+ map_mul_le_mul f := f.mul_le'
+ map_neg_eq_map f := f.neg'
+ eq_zero_of_map_eq_zero f := f.eq_zero_of_map_eq_zero' _
+ map_smul_eq_mul f := f.smul'
+
+theorem toFun_eq_coe (p : AlgebraNorm R S) : p.toFun = p := rfl
+
+@[ext]
+theorem ext {p q : AlgebraNorm R S} : (∀ x, p x = q x) → p = q :=
+ DFunLike.ext p q
+
+/-- An `R`-algebra norm such that `f 1 = 1` extends the norm on `R`. -/
+theorem extends_norm' (hf1 : f 1 = 1) (a : R) : f (a • (1 : S)) = ‖a‖ := by
+ rw [← mul_one ‖a‖, ← hf1]; exact f.smul' _ _
+
+/-- An `R`-algebra norm such that `f 1 = 1` extends the norm on `R`. -/
+theorem extends_norm (hf1 : f 1 = 1) (a : R) : f (algebraMap R S a) = ‖a‖ := by
+ rw [Algebra.algebraMap_eq_smul_one]; exact extends_norm' hf1 _
+
+/-- The restriction of an algebra norm to a subalgebra. -/
+def restriction (A : Subalgebra R S) (f : AlgebraNorm R S) : AlgebraNorm R A where
+ toFun := fun x : A => f x.val
+ map_zero' := map_zero f
+ add_le' x y := map_add_le_add _ _ _
+ neg' x := map_neg_eq_map _ _
+ mul_le' x y := map_mul_le_mul _ _ _
+ eq_zero_of_map_eq_zero' x hx := by
+ rw [← ZeroMemClass.coe_eq_zero]; exact eq_zero_of_map_eq_zero f hx
+ smul' r x := map_smul_eq_mul _ _ _
+
+/-- The restriction of an algebra norm in a scalar tower. -/
+def isScalarTower_restriction {A : Type*} [CommRing A] [Algebra R A] [Algebra A S]
+ [IsScalarTower R A S] (hinj : Function.Injective (algebraMap A S)) (f : AlgebraNorm R S) :
+ AlgebraNorm R A where
+ toFun := fun x : A => f (algebraMap A S x)
+ map_zero' := by simp only [map_zero]
+ add_le' x y := by simp only [map_add, map_add_le_add]
+ neg' x := by simp only [map_neg, map_neg_eq_map]
+ mul_le' x y := by simp only [map_mul, map_mul_le_mul]
+ eq_zero_of_map_eq_zero' x hx := by
+ rw [← map_eq_zero_iff (algebraMap A S) hinj]
+ exact eq_zero_of_map_eq_zero f hx
+ smul' r x := by
+ simp only [Algebra.smul_def, map_mul, ← IsScalarTower.algebraMap_apply]
+ simp only [← smul_eq_mul, algebraMap_smul, map_smul_eq_mul]
+
+end AlgebraNorm
+
+/-- A multiplicative algebra norm on an `R`-algebra norm `S` is a multiplicative ring norm on `S`
+ compatible with the action of `R`. -/
+structure MulAlgebraNorm (R : Type*) [SeminormedCommRing R] (S : Type*) [Ring S] [Algebra R S]
+ extends MulRingNorm S, Seminorm R S
+
+attribute [nolint docBlame] MulAlgebraNorm.toSeminorm MulAlgebraNorm.toMulRingNorm
+
+instance (K : Type*) [NormedField K] : Inhabited (MulAlgebraNorm K K) :=
+ ⟨{ toFun := norm
+ map_zero' := norm_zero
+ add_le' := norm_add_le
+ neg' := norm_neg
+ smul' := norm_mul
+ map_one' := norm_one
+ map_mul' := norm_mul
+ eq_zero_of_map_eq_zero' := fun _ => norm_eq_zero.mp }⟩
+
+/-- `MulAlgebraNormClass F R S` states that `F` is a type of multiplicative `R`-algebra norms on
+the ring `S`. You should extend this class when you extend `MulAlgebraNorm`. -/
+class MulAlgebraNormClass (F : Type*) (R : outParam <| Type*) [SeminormedCommRing R]
+ (S : outParam <| Type*) [Ring S] [Algebra R S] [FunLike F S ℝ] extends MulRingNormClass F S ℝ,
+ SeminormClass F R S : Prop
+
+namespace MulAlgebraNorm
+
+variable {R S : outParam <| Type*} [SeminormedCommRing R] [Ring S] [Algebra R S]
+ {f : AlgebraNorm R S}
+
+instance : FunLike (MulAlgebraNorm R S) S ℝ where
+ coe f := f.toFun
+ coe_injective' f f' h:= by
+ simp only [AddGroupSeminorm.toFun_eq_coe, MulRingSeminorm.toFun_eq_coe, DFunLike.coe_fn_eq] at h
+ obtain ⟨⟨_, _⟩, _⟩ := f; obtain ⟨⟨_, _⟩, _⟩ := f'; congr;
+
+instance mulAlgebraNormClass : MulAlgebraNormClass (MulAlgebraNorm R S) R S where
+ map_zero f := f.map_zero'
+ map_add_le_add f := f.add_le'
+ map_one f := f.map_one'
+ map_mul f := f.map_mul'
+ map_neg_eq_map f := f.neg'
+ eq_zero_of_map_eq_zero f := f.eq_zero_of_map_eq_zero' _
+ map_smul_eq_mul f := f.smul'
+
+theorem toFun_eq_coe (p : MulAlgebraNorm R S) : p.toFun = p := rfl
+
+@[ext]
+theorem ext {p q : MulAlgebraNorm R S} : (∀ x, p x = q x) → p = q :=
+ DFunLike.ext p q
+
+/-- A multiplicative `R`-algebra norm extends the norm on `R`. -/
+theorem extends_norm' (f : MulAlgebraNorm R S) (a : R) : f (a • (1 : S)) = ‖a‖ := by
+ rw [← mul_one ‖a‖, ← f.map_one', ← f.smul']; rfl
+
+/-- A multiplicative `R`-algebra norm extends the norm on `R`. -/
+theorem extends_norm (f : MulAlgebraNorm R S) (a : R) : f (algebraMap R S a) = ‖a‖ := by
+ rw [Algebra.algebraMap_eq_smul_one]; exact extends_norm' _ _
+
+end MulAlgebraNorm
+
+namespace MulRingNorm
+
+variable {R : Type*} [NonAssocRing R]
+
+/-- The ring norm underlying a multiplicative ring norm. -/
+def toRingNorm (f : MulRingNorm R) : RingNorm R where
+ toFun := f
+ map_zero' := f.map_zero'
+ add_le' := f.add_le'
+ neg' := f.neg'
+ mul_le' x y := le_of_eq (f.map_mul' x y)
+ eq_zero_of_map_eq_zero' := f.eq_zero_of_map_eq_zero'
+
+/-- A multiplicative ring norm is power-multiplicative. -/
+theorem isPowMul {A : Type*} [Ring A] (f : MulRingNorm A) : IsPowMul f := fun x n hn => by
+ cases n
+ · exfalso; linarith
+ · rw [map_pow]
+
+end MulRingNorm
diff --git a/Mathlib/Analysis/Normed/Algebra/Spectrum.lean b/Mathlib/Analysis/Normed/Algebra/Spectrum.lean
index e6e984888bc72..6c924b2091498 100644
--- a/Mathlib/Analysis/Normed/Algebra/Spectrum.lean
+++ b/Mathlib/Analysis/Normed/Algebra/Spectrum.lean
@@ -101,7 +101,7 @@ theorem mem_resolventSet_of_norm_lt_mul {a : A} {k : 𝕜} (h : ‖a‖ * ‖(1
ne_zero_of_norm_ne_zero ((mul_nonneg (norm_nonneg _) (norm_nonneg _)).trans_lt h).ne'
letI ku := Units.map ↑ₐ.toMonoidHom (Units.mk0 k hk)
rw [← inv_inv ‖(1 : A)‖,
- mul_inv_lt_iff (inv_pos.2 <| norm_pos_iff.2 (one_ne_zero : (1 : A) ≠ 0))] at h
+ mul_inv_lt_iff₀' (inv_pos.2 <| norm_pos_iff.2 (one_ne_zero : (1 : A) ≠ 0))] at h
have hku : ‖-a‖ < ‖(↑ku⁻¹ : A)‖⁻¹ := by simpa [ku, norm_algebraMap] using h
simpa [ku, sub_eq_add_neg, Algebra.algebraMap_eq_smul_one] using (ku.add (-a) hku).isUnit
@@ -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
@@ -203,11 +220,9 @@ theorem spectralRadius_le_liminf_pow_nnnorm_pow_one_div (a : A) :
refine ENNReal.le_of_forall_lt_one_mul_le fun ε hε => ?_
by_cases h : ε = 0
· simp only [h, zero_mul, zero_le']
- have hε' : ε⁻¹ ≠ ∞ := fun h' =>
- h (by simpa only [inv_inv, inv_top] using congr_arg (fun x : ℝ≥0∞ => x⁻¹) h')
simp only [ENNReal.mul_le_iff_le_inv h (hε.trans_le le_top).ne, mul_comm ε⁻¹,
liminf_eq_iSup_iInf_of_nat', ENNReal.iSup_mul]
- conv_rhs => arg 1; intro i; rw [ENNReal.iInf_mul hε']
+ conv_rhs => arg 1; intro i; rw [ENNReal.iInf_mul (by simp [h])]
rw [← ENNReal.inv_lt_inv, inv_one] at hε
obtain ⟨N, hN⟩ := eventually_atTop.mp
(ENNReal.eventually_pow_one_div_le (ENNReal.coe_ne_top : ↑‖(1 : A)‖₊ ≠ ∞) hε)
@@ -272,7 +287,7 @@ variable (𝕜)
/-- In a Banach algebra `A` over a nontrivially normed field `𝕜`, for any `a : A` the
power series with coefficients `a ^ n` represents the function `(1 - z • a)⁻¹` in a disk of
radius `‖a‖₊⁻¹`. -/
-theorem hasFPowerSeriesOnBall_inverse_one_sub_smul [CompleteSpace A] (a : A) :
+theorem hasFPowerSeriesOnBall_inverse_one_sub_smul [HasSummableGeomSeries A] (a : A) :
HasFPowerSeriesOnBall (fun z : 𝕜 => Ring.inverse (1 - z • a))
(fun n => ContinuousMultilinearMap.mkPiRing 𝕜 (Fin n) (a ^ n)) 0 ‖a‖₊⁻¹ :=
{ r_le := by
@@ -280,7 +295,7 @@ theorem hasFPowerSeriesOnBall_inverse_one_sub_smul [CompleteSpace A] (a : A) :
le_radius_of_bound_nnreal _ (max 1 ‖(1 : A)‖₊) fun n => ?_
rw [← norm_toNNReal, norm_mkPiRing, norm_toNNReal]
cases' n with n
- · simp only [le_refl, mul_one, or_true_iff, le_max_iff, pow_zero]
+ · simp only [le_refl, mul_one, or_true, le_max_iff, pow_zero]
· refine
le_trans (le_trans (mul_le_mul_right' (nnnorm_pow_le' a n.succ_pos) (r ^ n.succ)) ?_)
(le_max_left _ _)
@@ -297,7 +312,7 @@ theorem hasFPowerSeriesOnBall_inverse_one_sub_smul [CompleteSpace A] (a : A) :
simpa only [← coe_inv h, mem_ball_zero_iff, Metric.emetric_ball_nnreal] using hy
rwa [← coe_nnnorm, ← Real.lt_toNNReal_iff_coe_lt, Real.toNNReal_one, nnnorm_smul,
← NNReal.lt_inv_iff_mul_lt h]
- simpa [← smul_pow, (NormedRing.summable_geometric_of_norm_lt_one _ norm_lt).hasSum_iff] using
+ simpa [← smul_pow, (summable_geometric_of_norm_lt_one norm_lt).hasSum_iff] using
(NormedRing.inverse_one_sub _ norm_lt).symm }
variable {𝕜}
@@ -554,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 90fcffffc0c67..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,21 +202,24 @@ 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) :=
Bornology.induced <| addEquiv 𝕜 A
-theorem uniformEmbedding_addEquiv {𝕜} [NontriviallyNormedField 𝕜] :
- UniformEmbedding (addEquiv 𝕜 A) where
+theorem isUniformEmbedding_addEquiv {𝕜} [NontriviallyNormedField 𝕜] :
+ IsUniformEmbedding (addEquiv 𝕜 A) where
comap_uniformity := rfl
inj := (addEquiv 𝕜 A).injective
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_addEquiv := isUniformEmbedding_addEquiv
+
/-- `Unitization 𝕜 A` is complete whenever `𝕜` and `A` are also. -/
instance instCompleteSpace [CompleteSpace 𝕜] [CompleteSpace A] :
CompleteSpace (Unitization 𝕜 A) :=
- (completeSpace_congr uniformEmbedding_addEquiv).mpr CompleteSpace.prod
+ uniformEquivProd.completeSpace_iff.2 .prod
/-- Pull back the metric structure from `𝕜 × (A →L[𝕜] A)` to `Unitization 𝕜 A` using the
algebra homomorphism `Unitization.splitMul 𝕜 A`, but replace the bornology and the uniformity so
@@ -253,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/Algebra/UnitizationL1.lean b/Mathlib/Analysis/Normed/Algebra/UnitizationL1.lean
index 4a0ab143ce2a1..bb8f42626297c 100644
--- a/Mathlib/Analysis/Normed/Algebra/UnitizationL1.lean
+++ b/Mathlib/Analysis/Normed/Algebra/UnitizationL1.lean
@@ -50,7 +50,7 @@ noncomputable def uniformEquiv_unitization_addEquiv_prod :
instance instCompleteSpace [CompleteSpace 𝕜] [CompleteSpace A] :
CompleteSpace (WithLp 1 (Unitization 𝕜 A)) :=
- completeSpace_congr (uniformEquiv_unitization_addEquiv_prod 𝕜 A).uniformEmbedding |>.mpr
+ completeSpace_congr (uniformEquiv_unitization_addEquiv_prod 𝕜 A).isUniformEmbedding |>.mpr
CompleteSpace.prod
variable {𝕜 A}
diff --git a/Mathlib/Analysis/Normed/Field/Basic.lean b/Mathlib/Analysis/Normed/Field/Basic.lean
index 02d24cb406d37..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
@@ -14,6 +15,14 @@ import Mathlib.Data.Set.Pointwise.Interval
In this file we define (semi)normed rings and fields. We also prove some theorems about these
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.
@@ -209,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 _ _
@@ -218,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)
@@ -345,7 +365,7 @@ theorem List.norm_prod_le' : ∀ {l : List α}, l ≠ [] → ‖l.prod‖ ≤ (l
| [], h => (h rfl).elim
| [a], _ => by simp
| a::b::l, _ => by
- rw [List.map_cons, List.prod_cons, @List.prod_cons _ _ _ ‖a‖]
+ rw [List.map_cons, List.prod_cons, List.prod_cons (a := ‖a‖)]
refine le_trans (norm_mul_le _ _) (mul_le_mul_of_nonneg_left ?_ (norm_nonneg _))
exact List.norm_prod_le' (List.cons_ne_nil b l)
@@ -440,6 +460,29 @@ 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 β]
+ (f : α →+* β) : Prop :=
+ ∃ C : ℝ, 0 < C ∧ ∀ x : α, norm (f x) ≤ C * norm x
+
end SeminormedRing
section NonUnitalNormedRing
@@ -583,11 +626,17 @@ instance MulOpposite.instNormedCommRing : NormedCommRing αᵐᵒᵖ where
__ := instNormedRing
__ := instSeminormedCommRing
+/-- The restriction of a power-multiplicative function to a subalgebra is power-multiplicative. -/
+theorem IsPowMul.restriction {R S : Type*} [NormedCommRing R] [CommRing S] [Algebra R S]
+ (A : Subalgebra R S) {f : S → ℝ} (hf_pm : IsPowMul f) :
+ IsPowMul fun x : A => f x.val := fun x n hn => by
+ simpa [SubsemiringClass.coe_pow] using hf_pm (↑x) hn
+
end NormedCommRing
section NormedDivisionRing
-variable [NormedDivisionRing α] {a : α}
+variable [NormedDivisionRing α] {a b : α}
@[simp]
theorem norm_mul (a b : α) : ‖a * b‖ = ‖a‖ * ‖b‖ :=
@@ -669,6 +718,54 @@ 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
+
+variable {𝕜 : Type*} [NormedDivisionRing 𝕜] [DiscreteTopology 𝕜]
+
+lemma norm_eq_one_iff_ne_zero_of_discrete {x : 𝕜} : ‖x‖ = 1 ↔ x ≠ 0 := by
+ constructor <;> intro hx
+ · contrapose! hx
+ simp [hx]
+ · have : IsOpen {(0 : 𝕜)} := isOpen_discrete {0}
+ simp_rw [Metric.isOpen_singleton_iff, dist_eq_norm, sub_zero] at this
+ obtain ⟨ε, εpos, h'⟩ := this
+ wlog h : ‖x‖ < 1 generalizing 𝕜 with H
+ · push_neg at h
+ rcases h.eq_or_lt with h|h
+ · rw [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
+ rw [← norm_pow] at hk
+ specialize h' _ hk
+ simp [hx] at h'
+
+@[simp]
+lemma norm_le_one_of_discrete
+ (x : 𝕜) : ‖x‖ ≤ 1 := by
+ rcases eq_or_ne x 0 with rfl|hx
+ · simp
+ · simp [norm_eq_one_iff_ne_zero_of_discrete.mpr hx]
+
+lemma discreteTopology_unit_closedBall_eq_univ : (Metric.closedBall 0 1 : Set 𝕜) = Set.univ := by
+ ext
+ simp
+
+end Discrete
+
+end NormedDivisionRing
+
end NormedDivisionRing
/-- A normed field is a field with a norm satisfying ‖x y‖ = ‖x‖ ‖y‖. -/
@@ -795,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 ℝ :=
@@ -826,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]
@@ -844,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])
@@ -999,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 f56d61465db91..e22f72874193c 100644
--- a/Mathlib/Analysis/Normed/Field/Lemmas.lean
+++ b/Mathlib/Analysis/Normed/Field/Lemmas.lean
@@ -17,6 +17,11 @@ import Mathlib.Topology.MetricSpace.DilationEquiv
# Normed fields
In this file we continue building the theory of (semi)normed rings and fields.
+
+Some useful results that relate the topology of the normed field to the discrete topology include:
+* `discreteTopology_or_nontriviallyNormedField`
+* `discreteTopology_of_bddAbove_range_norm`
+
-/
-- Guard against import creep.
@@ -143,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
@@ -152,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 ?_
@@ -169,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 : α}
@@ -264,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 ?_
@@ -287,10 +318,49 @@ 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
+/-- A normed field is either nontrivially normed or has a discrete topology.
+In the discrete topology case, all the norms are 1, by `norm_eq_one_iff_ne_zero_of_discrete`.
+The nontrivially normed field instance is provided by a subtype with a proof that the
+forgetful inheritance to the existing `NormedField` instance is definitionally true.
+This allows one to have the new `NontriviallyNormedField` instance without data clashes. -/
+lemma discreteTopology_or_nontriviallyNormedField (𝕜 : Type*) [h : NormedField 𝕜] :
+ DiscreteTopology 𝕜 ∨ Nonempty ({h' : NontriviallyNormedField 𝕜 // h'.toNormedField = h}) := by
+ by_cases H : ∃ x : 𝕜, x ≠ 0 ∧ ‖x‖ ≠ 1
+ · exact Or.inr ⟨(⟨NontriviallyNormedField.ofNormNeOne H, rfl⟩)⟩
+ · simp_rw [discreteTopology_iff_isOpen_singleton_zero, Metric.isOpen_singleton_iff, dist_eq_norm,
+ sub_zero]
+ refine Or.inl ⟨1, zero_lt_one, ?_⟩
+ contrapose! H
+ refine H.imp ?_
+ -- contextual to reuse the `a ≠ 0` hypothesis in the proof of `a ≠ 0 ∧ ‖a‖ ≠ 1`
+ simp (config := {contextual := true}) [add_comm, ne_of_lt]
+
+lemma discreteTopology_of_bddAbove_range_norm {𝕜 : Type*} [NormedField 𝕜]
+ (h : BddAbove (Set.range fun k : 𝕜 ↦ ‖k‖)) :
+ DiscreteTopology 𝕜 := by
+ refine (NormedField.discreteTopology_or_nontriviallyNormedField _).resolve_right ?_
+ rintro ⟨_, rfl⟩
+ obtain ⟨x, h⟩ := h
+ obtain ⟨k, hk⟩ := NormedField.exists_lt_norm 𝕜 x
+ exact hk.not_le (h (Set.mem_range_self k))
+
section Densely
variable (α) [DenselyNormedField α]
@@ -302,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
@@ -333,3 +419,31 @@ instance Rat.instDenselyNormedField : DenselyNormedField ℚ where
lt_norm_lt r₁ r₂ h₀ hr :=
let ⟨q, h⟩ := exists_rat_btwn hr
⟨q, by rwa [← Rat.norm_cast_real, Real.norm_eq_abs, abs_of_pos (h₀.trans_lt h.1)]⟩
+
+section Complete
+
+lemma NormedField.completeSpace_iff_isComplete_closedBall {K : Type*} [NormedField K] :
+ CompleteSpace K ↔ IsComplete (Metric.closedBall 0 1 : Set K) := by
+ constructor <;> intro h
+ · exact Metric.isClosed_ball.isComplete
+ rcases NormedField.discreteTopology_or_nontriviallyNormedField K with _|⟨_, rfl⟩
+ · rwa [completeSpace_iff_isComplete_univ,
+ ← NormedDivisionRing.discreteTopology_unit_closedBall_eq_univ]
+ refine Metric.complete_of_cauchySeq_tendsto fun u hu ↦ ?_
+ obtain ⟨k, hk⟩ := hu.norm_bddAbove
+ have kpos : 0 ≤ k := (_root_.norm_nonneg (u 0)).trans (hk (by simp))
+ obtain ⟨x, hx⟩ := NormedField.exists_lt_norm K k
+ have hu' : CauchySeq ((· / x) ∘ u) := (uniformContinuous_div_const' x).comp_cauchySeq hu
+ have hb : ∀ n, ((· / x) ∘ u) n ∈ Metric.closedBall 0 1 := by
+ intro
+ simp only [Function.comp_apply, Metric.mem_closedBall, dist_zero_right, norm_div]
+ rw [div_le_one (kpos.trans_lt hx)]
+ exact hx.le.trans' (hk (by simp))
+ obtain ⟨a, -, ha'⟩ := cauchySeq_tendsto_of_isComplete h hb hu'
+ refine ⟨a * x, (((continuous_mul_right x).tendsto a).comp ha').congr ?_⟩
+ have hx' : x ≠ 0 := by
+ contrapose! hx
+ simp [hx, kpos]
+ simp [div_mul_cancel₀ _ hx']
+
+end Complete
diff --git a/Mathlib/Analysis/Normed/Field/ProperSpace.lean b/Mathlib/Analysis/Normed/Field/ProperSpace.lean
new file mode 100644
index 0000000000000..58a51d47a39f0
--- /dev/null
+++ b/Mathlib/Analysis/Normed/Field/ProperSpace.lean
@@ -0,0 +1,48 @@
+/-
+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.Lemmas
+import Mathlib.Analysis.SpecificLimits.Basic
+import Mathlib.Topology.MetricSpace.ProperSpace
+
+/-!
+# Proper nontrivally normed fields
+
+Nontrivially normed fields are `ProperSpaces` when they are `WeaklyLocallyCompact`.
+
+## Main results
+
+* `ProperSpace.of_nontriviallyNormedField_of_weaklyLocallyCompactSpace`
+
+## Implementation details
+
+This is a special case of `ProperSpace.of_locallyCompactSpace` from
+`Mathlib.Analysis.Normed.Module.FiniteDimension`, specialized to be on the field itself
+with a proof that requires fewer imports.
+-/
+
+assert_not_exists FiniteDimensional
+
+open Metric Filter
+
+/-- A weakly locally compact normed field is proper.
+This is a specialization of `ProperSpace.of_locallyCompactSpace`
+which holds for `NormedSpace`s but requires more imports. -/
+lemma ProperSpace.of_nontriviallyNormedField_of_weaklyLocallyCompactSpace
+ (𝕜 : Type*) [NontriviallyNormedField 𝕜] [WeaklyLocallyCompactSpace 𝕜] :
+ ProperSpace 𝕜 := by
+ rcases exists_isCompact_closedBall (0 : 𝕜) with ⟨r, rpos, hr⟩
+ rcases NormedField.exists_one_lt_norm 𝕜 with ⟨c, hc⟩
+ have hC n : IsCompact (closedBall (0 : 𝕜) (‖c‖^n * r)) := by
+ have : c ^ n ≠ 0 := pow_ne_zero _ <| fun h ↦ by simp [h, zero_le_one.not_lt] at hc
+ convert hr.smul (c ^ n)
+ ext
+ simp only [mem_closedBall, dist_zero_right, Set.mem_smul_set_iff_inv_smul_mem₀ this,
+ smul_eq_mul, norm_mul, norm_inv, norm_pow,
+ inv_mul_le_iff₀ (by simpa only [norm_pow] using norm_pos_iff.mpr this)]
+ have hTop : Tendsto (fun n ↦ ‖c‖^n * r) atTop atTop :=
+ Tendsto.atTop_mul_const rpos (tendsto_pow_atTop_atTop_of_one_lt hc)
+ exact .of_seq_closedBall hTop (Eventually.of_forall hC)
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/Field/UnitBall.lean b/Mathlib/Analysis/Normed/Field/UnitBall.lean
index 2817b533b7761..146e37b0e5af2 100644
--- a/Mathlib/Analysis/Normed/Field/UnitBall.lean
+++ b/Mathlib/Analysis/Normed/Field/UnitBall.lean
@@ -51,7 +51,7 @@ def Subsemigroup.unitClosedBall (𝕜 : Type*) [NonUnitalSeminormedRing 𝕜] :
carrier := closedBall 0 1
mul_mem' hx hy := by
rw [mem_closedBall_zero_iff] at *
- exact (norm_mul_le _ _).trans (mul_le_one hx (norm_nonneg _) hy)
+ exact (norm_mul_le _ _).trans (mul_le_one₀ hx (norm_nonneg _) hy)
instance Metric.unitClosedBall.semigroup [NonUnitalSeminormedRing 𝕜] :
Semigroup (closedBall (0 : 𝕜) 1) :=
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 bde983756cf20..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
@@ -1129,7 +1154,7 @@ theorem nnnorm_prod_le (s : Finset ι) (f : ι → E) : ‖∏ a ∈ s, f a‖
@[to_additive]
theorem nnnorm_prod_le_of_le (s : Finset ι) {f : ι → E} {n : ι → ℝ≥0} (h : ∀ b ∈ s, ‖f b‖₊ ≤ n b) :
‖∏ b ∈ s, f b‖₊ ≤ ∑ b ∈ s, n b :=
- (norm_prod_le_of_le s h).trans_eq NNReal.coe_sum.symm
+ (norm_prod_le_of_le s h).trans_eq (NNReal.coe_sum ..).symm
namespace Real
@@ -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/CocompactMap.lean b/Mathlib/Analysis/Normed/Group/CocompactMap.lean
index ff947f47393ef..40889eae41c45 100644
--- a/Mathlib/Analysis/Normed/Group/CocompactMap.lean
+++ b/Mathlib/Analysis/Normed/Group/CocompactMap.lean
@@ -5,7 +5,7 @@ Authors: Moritz Doll
-/
import Mathlib.Analysis.Normed.Group.Basic
-import Mathlib.Topology.ContinuousFunction.CocompactMap
+import Mathlib.Topology.ContinuousMap.CocompactMap
import Mathlib.Topology.MetricSpace.Bounded
/-!
diff --git a/Mathlib/Analysis/Normed/Group/Constructions.lean b/Mathlib/Analysis/Normed/Group/Constructions.lean
index a43e9e963c9ee..c9ee9cc5d178f 100644
--- a/Mathlib/Analysis/Normed/Group/Constructions.lean
+++ b/Mathlib/Analysis/Normed/Group/Constructions.lean
@@ -362,7 +362,7 @@ lemma Pi.sum_norm_apply_le_norm' : ∑ i, ‖f i‖ ≤ Fintype.card ι • ‖f
@[to_additive Pi.sum_nnnorm_apply_le_nnnorm "The $L^1$ norm is less than the $L^\\infty$ norm
scaled by the cardinality."]
lemma Pi.sum_nnnorm_apply_le_nnnorm' : ∑ i, ‖f i‖₊ ≤ Fintype.card ι • ‖f‖₊ :=
- NNReal.coe_sum.trans_le <| Pi.sum_norm_apply_le_norm' _
+ (NNReal.coe_sum ..).trans_le <| Pi.sum_norm_apply_le_norm' _
end SeminormedGroup
diff --git a/Mathlib/Analysis/Normed/Group/Hom.lean b/Mathlib/Analysis/Normed/Group/Hom.lean
index 9f1984fa88764..7cde007647e8d 100644
--- a/Mathlib/Analysis/Normed/Group/Hom.lean
+++ b/Mathlib/Analysis/Normed/Group/Hom.lean
@@ -82,7 +82,7 @@ def ofLipschitz (f : V₁ →+ V₂) {K : ℝ≥0} (h : LipschitzWith K f) : Nor
instance funLike : FunLike (NormedAddGroupHom V₁ V₂) V₁ V₂ where
coe := toFun
- coe_injective' := fun f g h => by cases f; cases g; congr
+ coe_injective' f g h := by cases f; cases g; congr
-- Porting note: moved this declaration up so we could get a `FunLike` instance sooner.
instance toAddMonoidHomClass : AddMonoidHomClass (NormedAddGroupHom V₁ V₂) V₁ V₂ where
@@ -231,7 +231,7 @@ protected theorem continuous (f : NormedAddGroupHom V₁ V₂) : Continuous f :=
f.uniformContinuous.continuous
theorem ratio_le_opNorm (x : V₁) : ‖f x‖ / ‖x‖ ≤ ‖f‖ :=
- div_le_of_nonneg_of_le_mul (norm_nonneg _) f.opNorm_nonneg (le_opNorm _ _)
+ div_le_of_le_mul₀ (norm_nonneg _) f.opNorm_nonneg (le_opNorm _ _)
/-- If one controls the norm of every `f x`, then one controls the norm of `f`. -/
theorem opNorm_le_bound {M : ℝ} (hMp : 0 ≤ M) (hM : ∀ x, ‖f x‖ ≤ M * ‖x‖) : ‖f‖ ≤ M :=
@@ -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/HomCompletion.lean b/Mathlib/Analysis/Normed/Group/HomCompletion.lean
index ca7368753ff56..3ef2814acd733 100644
--- a/Mathlib/Analysis/Normed/Group/HomCompletion.lean
+++ b/Mathlib/Analysis/Normed/Group/HomCompletion.lean
@@ -132,7 +132,7 @@ theorem NormedAddCommGroup.norm_toCompl (x : G) : ‖toCompl x‖ = ‖x‖ :=
Completion.norm_coe x
theorem NormedAddCommGroup.denseRange_toCompl : DenseRange (toCompl : G → Completion G) :=
- Completion.denseInducing_coe.dense
+ Completion.isDenseInducing_coe.dense
@[simp]
theorem NormedAddGroupHom.completion_toCompl (f : NormedAddGroupHom G H) :
@@ -158,12 +158,13 @@ theorem NormedAddGroupHom.ker_completion {f : NormedAddGroupHom G H} {C : ℝ}
rcases h.exists_pos with ⟨C', C'_pos, hC'⟩
rcases exists_pos_mul_lt ε_pos (1 + C' * ‖f‖) with ⟨δ, δ_pos, hδ⟩
obtain ⟨_, ⟨g : G, rfl⟩, hg : ‖hatg - g‖ < δ⟩ :=
- SeminormedAddCommGroup.mem_closure_iff.mp (Completion.denseInducing_coe.dense hatg) δ δ_pos
+ SeminormedAddCommGroup.mem_closure_iff.mp (Completion.isDenseInducing_coe.dense hatg) δ δ_pos
obtain ⟨g' : G, hgg' : f g' = f g, hfg : ‖g'‖ ≤ C' * ‖f g‖⟩ := hC' (f g) (mem_range_self _ g)
have mem_ker : g - g' ∈ f.ker := by rw [f.mem_ker, map_sub, sub_eq_zero.mpr hgg'.symm]
refine ⟨_, ⟨⟨g - g', mem_ker⟩, rfl⟩, ?_⟩
have : ‖f g‖ ≤ ‖f‖ * δ := calc
- ‖f g‖ ≤ ‖f‖ * ‖hatg - g‖ := by simpa [hatg_in] using f.completion.le_opNorm (hatg - g)
+ ‖f g‖ ≤ ‖f‖ * ‖hatg - g‖ := by
+ simpa [map_sub, hatg_in] using f.completion.le_opNorm (hatg - g)
_ ≤ ‖f‖ * δ := by gcongr
calc ‖hatg - ↑(g - g')‖ = ‖hatg - g + g'‖ := by rw [Completion.coe_sub, sub_add]
_ ≤ ‖hatg - g‖ + ‖(g' : Completion G)‖ := norm_add_le _ _
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 085dab581687e..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
/-!
@@ -156,7 +156,7 @@ theorem quotient_norm_mk_eq (S : AddSubgroup M) (m : M) :
/-- The quotient norm is nonnegative. -/
theorem quotient_norm_nonneg (S : AddSubgroup M) (x : M ⧸ S) : 0 ≤ ‖x‖ :=
- Real.sInf_nonneg _ <| forall_mem_image.2 fun _ _ ↦ norm_nonneg _
+ Real.sInf_nonneg <| forall_mem_image.2 fun _ _ ↦ norm_nonneg _
/-- The quotient norm is nonnegative. -/
theorem norm_mk_nonneg (S : AddSubgroup M) (m : M) : 0 ≤ ‖mk' S m‖ :=
@@ -282,9 +282,9 @@ theorem _root_.QuotientAddGroup.norm_lift_apply_le {S : AddSubgroup M} (f : Norm
rcases mk_surjective x with ⟨x, rfl⟩
simpa [h] using le_opNorm f x
| inr h =>
- rw [← not_lt, ← _root_.lt_div_iff' h, norm_lt_iff]
+ rw [← not_lt, ← lt_div_iff₀' h, norm_lt_iff]
rintro ⟨x, rfl, hx⟩
- exact ((lt_div_iff' h).1 hx).not_le (le_opNorm f x)
+ exact ((lt_div_iff₀' h).1 hx).not_le (le_opNorm f x)
/-- The operator norm of the projection is `1` if the subspace is not dense. -/
theorem norm_normedMk (S : AddSubgroup M) (h : (S.topologicalClosure : Set M) ≠ univ) :
diff --git a/Mathlib/Analysis/Normed/Group/SemiNormedGrp.lean b/Mathlib/Analysis/Normed/Group/SemiNormedGrp.lean
index 2e56d519dc3b2..40b402cc07b73 100644
--- a/Mathlib/Analysis/Normed/Group/SemiNormedGrp.lean
+++ b/Mathlib/Analysis/Normed/Group/SemiNormedGrp.lean
@@ -56,7 +56,7 @@ instance (M : SemiNormedGrp) : SeminormedAddCommGroup M :=
-- Porting note (#10754): added instance
instance funLike {V W : SemiNormedGrp} : FunLike (V ⟶ W) V W where
coe := (forget SemiNormedGrp).map
- coe_injective' := fun f g h => by cases f; cases g; congr
+ coe_injective' f g h := by cases f; cases g; congr
instance toAddMonoidHomClass {V W : SemiNormedGrp} : AddMonoidHomClass (V ⟶ W) V W where
map_add f := f.map_add'
@@ -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 1f32d6b23b009..01fad0a4ff9d9 100644
--- a/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Kernels.lean
+++ b/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Kernels.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Riccardo Brasca, Johan Commelin, Scott Morrison
+Authors: Riccardo Brasca, Johan Commelin, Kim Morrison
-/
import Mathlib.Analysis.Normed.Group.SemiNormedGrp
import Mathlib.Analysis.Normed.Group.Quotient
@@ -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 39f1d2b490a43..73c549f43211b 100644
--- a/Mathlib/Analysis/Normed/Group/Seminorm.lean
+++ b/Mathlib/Analysis/Normed/Group/Seminorm.lean
@@ -3,8 +3,9 @@ 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.Tactic.GCongr.Core
+import Mathlib.Data.NNReal.Defs
+import Mathlib.Order.ConditionallyCompleteLattice.Group
+import Mathlib.Tactic.GCongr.CoreAttrs
/-!
# Group seminorms
@@ -48,7 +49,7 @@ open Set
open NNReal
-variable {ι R R' E F G : Type*}
+variable {R R' E F G : Type*}
/-- A seminorm on an additive group `G` is a function `f : G → ℝ` that preserves zero, is
subadditive and such that `f (-x) = f x` for all `x`. -/
@@ -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
@@ -325,7 +320,7 @@ end Group
section CommGroup
-variable [CommGroup E] [CommGroup F] (p q : GroupSeminorm E) (x y : E)
+variable [CommGroup E] [CommGroup F] (p q : GroupSeminorm E) (x : E)
@[to_additive]
theorem comp_mul_le (f g : F →* E) : p.comp (f * g) ≤ p.comp f + p.comp g := fun _ =>
@@ -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
@@ -381,7 +376,7 @@ end GroupSeminorm
see that `SMul R ℝ` should be fixed because `ℝ` is fixed. -/
namespace AddGroupSeminorm
-variable [AddGroup E] [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] (p : AddGroupSeminorm E)
+variable [AddGroup E] [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ]
instance toOne [DecidableEq E] : One (AddGroupSeminorm E) :=
⟨{ toFun := fun x => if x = 0 then 0 else 1
@@ -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
@@ -435,7 +430,7 @@ namespace NonarchAddGroupSeminorm
section AddGroup
-variable [AddGroup E] [AddGroup F] [AddGroup G] {p q : NonarchAddGroupSeminorm E}
+variable [AddGroup E] {p q : NonarchAddGroupSeminorm E}
instance funLike : FunLike (NonarchAddGroupSeminorm E) E ℝ where
coe f := f.toFun
@@ -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
@@ -477,13 +468,13 @@ theorem coe_le_coe : (p : E → ℝ) ≤ q ↔ p ≤ q :=
theorem coe_lt_coe : (p : E → ℝ) < q ↔ p < q :=
Iff.rfl
-variable (p q) (f : F →+ E)
+variable (p q)
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 :=
@@ -522,7 +513,7 @@ end AddGroup
section AddCommGroup
-variable [AddCommGroup E] [AddCommGroup F] (p q : NonarchAddGroupSeminorm E) (x y : E)
+variable [AddCommGroup E]
theorem add_bddBelow_range_add {p q : NonarchAddGroupSeminorm E} {x : E} :
BddBelow (range fun y => p y + q (x - y)) :=
@@ -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
@@ -653,7 +644,7 @@ namespace GroupNorm
section Group
-variable [Group E] [Group F] [Group G] {p q : GroupNorm E}
+variable [Group E] {p q : GroupNorm E}
@[to_additive]
instance funLike : FunLike (GroupNorm E) E ℝ where
@@ -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 :=
@@ -703,7 +687,7 @@ theorem coe_le_coe : (p : E → ℝ) ≤ q ↔ p ≤ q :=
theorem coe_lt_coe : (p : E → ℝ) < q ↔ p < q :=
Iff.rfl
-variable (p q) (f : F →* E)
+variable (p q)
@[to_additive]
instance : Add (GroupNorm E) :=
@@ -787,7 +771,7 @@ namespace NonarchAddGroupNorm
section AddGroup
-variable [AddGroup E] [AddGroup F] {p q : NonarchAddGroupNorm E}
+variable [AddGroup E] {p q : NonarchAddGroupNorm E}
instance funLike : FunLike (NonarchAddGroupNorm E) E ℝ where
coe f := f.toFun
@@ -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 :=
@@ -829,7 +809,7 @@ theorem coe_le_coe : (p : E → ℝ) ≤ q ↔ p ≤ q :=
theorem coe_lt_coe : (p : E → ℝ) < q ↔ p < q :=
Iff.rfl
-variable (p q) (f : F →+ E)
+variable (p q)
instance : Sup (NonarchAddGroupNorm E) :=
⟨fun p q =>
diff --git a/Mathlib/Analysis/Normed/Group/Ultra.lean b/Mathlib/Analysis/Normed/Group/Ultra.lean
new file mode 100644
index 0000000000000..44bfd92a9f0fe
--- /dev/null
+++ b/Mathlib/Analysis/Normed/Group/Ultra.lean
@@ -0,0 +1,328 @@
+/-
+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.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
+
+This file contains results on the behavior of norms in ultrametric groups.
+
+## Main results
+
+* `IsUltrametricDist.isUltrametricDist_of_isNonarchimedean_norm`:
+ a normed additive group has an ultrametric iff the norm is nonarchimedean
+* `IsUltrametricDist.nonarchimedeanGroup` and its additive version: instance showing that a
+ commutative group with a nonarchimedean seminorm is a nonarchimedean topological group (i.e.
+ there is a neighbourhood basis of the identity consisting of open subgroups).
+
+## Implementation details
+
+Some results are proved first about `nnnorm : X → ℝ≥0` because the bottom element
+in `NNReal` is 0, so easier to make statements about maxima of empty sets.
+
+## Tags
+
+ultrametric, nonarchimedean
+-/
+open Metric NNReal
+
+namespace IsUltrametricDist
+
+section Group
+
+variable {S S' ι : Type*} [SeminormedGroup S] [SeminormedGroup S'] [IsUltrametricDist S]
+
+@[to_additive]
+lemma norm_mul_le_max (x y : S) :
+ ‖x * y‖ ≤ max ‖x‖ ‖y‖ := by
+ simpa only [le_max_iff, dist_eq_norm_div, div_inv_eq_mul, div_one, one_mul] using
+ dist_triangle_max x 1 y⁻¹
+
+@[to_additive]
+lemma isUltrametricDist_of_forall_norm_mul_le_max_norm
+ (h : ∀ x y : S', ‖x * y‖ ≤ max ‖x‖ ‖y‖) : IsUltrametricDist S' where
+ dist_triangle_max x y z := by
+ simpa only [dist_eq_norm_div, le_max_iff, div_mul_div_cancel] using h (x / y) (y / z)
+
+lemma isUltrametricDist_of_isNonarchimedean_norm {S' : Type*} [SeminormedAddGroup S']
+ (h : IsNonarchimedean (norm : S' → ℝ)) : IsUltrametricDist S' :=
+ isUltrametricDist_of_forall_norm_add_le_max_norm h
+
+@[to_additive]
+lemma nnnorm_mul_le_max (x y : S) :
+ ‖x * y‖₊ ≤ max ‖x‖₊ ‖y‖₊ :=
+ norm_mul_le_max _ _
+
+@[to_additive]
+lemma isUltrametricDist_of_forall_nnnorm_mul_le_max_nnnorm
+ (h : ∀ x y : S', ‖x * y‖₊ ≤ max ‖x‖₊ ‖y‖₊) : IsUltrametricDist S' :=
+ isUltrametricDist_of_forall_norm_mul_le_max_norm h
+
+lemma isUltrametricDist_of_isNonarchimedean_nnnorm {S' : Type*} [SeminormedAddGroup S']
+ (h : IsNonarchimedean ((↑) ∘ (nnnorm : S' → ℝ≥0))) : IsUltrametricDist S' :=
+ isUltrametricDist_of_forall_nnnorm_add_le_max_nnnorm h
+
+/-- All triangles are isosceles in an ultrametric normed group. -/
+@[to_additive "All triangles are isosceles in an ultrametric normed additive group."]
+lemma norm_mul_eq_max_of_norm_ne_norm
+ {x y : S} (h : ‖x‖ ≠ ‖y‖) : ‖x * y‖ = max ‖x‖ ‖y‖ := by
+ rw [← div_inv_eq_mul, ← dist_eq_norm_div, dist_eq_max_of_dist_ne_dist _ 1 _ (by simp [h])]
+ simp only [dist_one_right, dist_one_left, norm_inv']
+
+@[to_additive]
+lemma norm_eq_of_mul_norm_lt_max {x y : S} (h : ‖x * y‖ < max ‖x‖ ‖y‖) :
+ ‖x‖ = ‖y‖ :=
+ not_ne_iff.mp (h.ne ∘ norm_mul_eq_max_of_norm_ne_norm)
+
+/-- All triangles are isosceles in an ultrametric normed group. -/
+@[to_additive "All triangles are isosceles in an ultrametric normed additive group."]
+lemma nnnorm_mul_eq_max_of_nnnorm_ne_nnnorm
+ {x y : S} (h : ‖x‖₊ ≠ ‖y‖₊) : ‖x * y‖₊ = max ‖x‖₊ ‖y‖₊ := by
+ simpa only [← NNReal.coe_inj, NNReal.coe_max] using
+ norm_mul_eq_max_of_norm_ne_norm (NNReal.coe_injective.ne h)
+
+@[to_additive]
+lemma nnnorm_eq_of_mul_nnnorm_lt_max {x y : S} (h : ‖x * y‖₊ < max ‖x‖₊ ‖y‖₊) :
+ ‖x‖₊ = ‖y‖₊ :=
+ not_ne_iff.mp (h.ne ∘ nnnorm_mul_eq_max_of_nnnorm_ne_nnnorm)
+
+/-- All triangles are isosceles in an ultrametric normed group. -/
+@[to_additive "All triangles are isosceles in an ultrametric normed additive group."]
+lemma norm_div_eq_max_of_norm_div_ne_norm_div (x y z : S) (h : ‖x / y‖ ≠ ‖y / z‖) :
+ ‖x / z‖ = max ‖x / y‖ ‖y / z‖ := by
+ simpa only [div_mul_div_cancel] using norm_mul_eq_max_of_norm_ne_norm h
+
+/-- All triangles are isosceles in an ultrametric normed group. -/
+@[to_additive "All triangles are isosceles in an ultrametric normed additive group."]
+lemma nnnorm_div_eq_max_of_nnnorm_div_ne_nnnorm_div (x y z : S) (h : ‖x / y‖₊ ≠ ‖y / z‖₊) :
+ ‖x / z‖₊ = max ‖x / y‖₊ ‖y / z‖₊ := by
+ simpa only [← NNReal.coe_inj, NNReal.coe_max] using
+ norm_div_eq_max_of_norm_div_ne_norm_div _ _ _ (NNReal.coe_injective.ne h)
+
+@[to_additive]
+lemma nnnorm_pow_le (x : S) (n : ℕ) :
+ ‖x ^ n‖₊ ≤ ‖x‖₊ := by
+ induction n with
+ | zero => simp
+ | succ n hn => simpa [pow_add, hn] using nnnorm_mul_le_max (x ^ n) x
+
+@[to_additive]
+lemma norm_pow_le (x : S) (n : ℕ) :
+ ‖x ^ n‖ ≤ ‖x‖ :=
+ nnnorm_pow_le x n
+
+@[to_additive]
+lemma nnnorm_zpow_le (x : S) (z : ℤ) :
+ ‖x ^ z‖₊ ≤ ‖x‖₊ := by
+ cases z <;>
+ simpa using nnnorm_pow_le _ _
+
+@[to_additive]
+lemma norm_zpow_le (x : S) (z : ℤ) :
+ ‖x ^ z‖ ≤ ‖x‖ :=
+ nnnorm_zpow_le x z
+
+section nonarch
+
+variable (S)
+/--
+In a group with an ultrametric norm, open balls around 1 of positive radius are open subgroups.
+-/
+@[to_additive "In an additive group with an ultrametric norm, open balls around 0 of
+positive radius are open subgroups."]
+def ball_openSubgroup {r : ℝ} (hr : 0 < r) : OpenSubgroup S where
+ carrier := Metric.ball (1 : S) r
+ mul_mem' {x} {y} hx hy := by
+ simp only [Metric.mem_ball, dist_eq_norm_div, div_one] at hx hy ⊢
+ exact (norm_mul_le_max x y).trans_lt (max_lt hx hy)
+ one_mem' := Metric.mem_ball_self hr
+ inv_mem' := by simp only [Metric.mem_ball, dist_one_right, norm_inv', imp_self, implies_true]
+ isOpen' := Metric.isOpen_ball
+
+/--
+In a group with an ultrametric norm, closed balls around 1 of positive radius are open subgroups.
+-/
+@[to_additive "In an additive group with an ultrametric norm, closed balls around 0 of positive
+radius are open subgroups."]
+def closedBall_openSubgroup {r : ℝ} (hr : 0 < r) : OpenSubgroup S where
+ carrier := Metric.closedBall (1 : S) r
+ mul_mem' {x} {y} hx hy := by
+ simp only [Metric.mem_closedBall, dist_eq_norm_div, div_one] at hx hy ⊢
+ exact (norm_mul_le_max x y).trans (max_le hx hy)
+ one_mem' := Metric.mem_closedBall_self hr.le
+ inv_mem' := by simp only [mem_closedBall, dist_one_right, norm_inv', imp_self, implies_true]
+ isOpen' := IsUltrametricDist.isOpen_closedBall _ hr.ne'
+
+end nonarch
+
+end Group
+
+section CommGroup
+
+variable {M ι : Type*} [SeminormedCommGroup M] [IsUltrametricDist M]
+
+/-- A commutative group with an ultrametric group seminorm is nonarchimedean (as a topological
+group, i.e. every neighborhood of 1 contains an open subgroup). -/
+@[to_additive "A commutative additive group with an ultrametric group seminorm is nonarchimedean
+(as a topological group, i.e. every neighborhood of 0 contains an open subgroup)."]
+instance nonarchimedeanGroup : NonarchimedeanGroup M where
+ is_nonarchimedean := by simpa only [Metric.mem_nhds_iff]
+ using fun U ⟨ε, hεp, hεU⟩ ↦ ⟨ball_openSubgroup M hεp, hεU⟩
+
+/-- Nonarchimedean norm of a product is less than or equal the norm of any term in the product.
+This version is phrased using `Finset.sup'` and `Finset.Nonempty` due to `Finset.sup`
+operating over an `OrderBot`, which `ℝ` is not.
+-/
+@[to_additive "Nonarchimedean norm of a sum is less than or equal the norm of any term in the sum.
+This version is phrased using `Finset.sup'` and `Finset.Nonempty` due to `Finset.sup`
+operating over an `OrderBot`, which `ℝ` is not. "]
+lemma _root_.Finset.Nonempty.norm_prod_le_sup'_norm {s : Finset ι} (hs : s.Nonempty) (f : ι → M) :
+ ‖∏ i ∈ s, f i‖ ≤ s.sup' hs (‖f ·‖) := by
+ simp only [Finset.le_sup'_iff]
+ induction hs using Finset.Nonempty.cons_induction with
+ | singleton j => simp only [Finset.mem_singleton, Finset.prod_singleton, exists_eq_left, le_refl]
+ | cons j t hj _ IH =>
+ simp only [Finset.prod_cons, Finset.mem_cons, exists_eq_or_imp]
+ refine (le_total ‖∏ i ∈ t, f i‖ ‖f j‖).imp ?_ ?_ <;> intro h
+ · exact (norm_mul_le_max _ _).trans (max_eq_left h).le
+ · exact ⟨_, IH.choose_spec.left, (norm_mul_le_max _ _).trans <|
+ ((max_eq_right h).le.trans IH.choose_spec.right)⟩
+
+/-- Nonarchimedean norm of a product is less than or equal to the largest norm of a term in the
+product. -/
+@[to_additive "Nonarchimedean norm of a sum is less than or equal to the largest norm of a term in
+the sum."]
+lemma _root_.Finset.nnnorm_prod_le_sup_nnnorm (s : Finset ι) (f : ι → M) :
+ ‖∏ i ∈ s, f i‖₊ ≤ s.sup (‖f ·‖₊) := by
+ rcases s.eq_empty_or_nonempty with rfl|hs
+ · simp only [Finset.prod_empty, nnnorm_one', Finset.sup_empty, bot_eq_zero', le_refl]
+ · simpa only [← Finset.sup'_eq_sup hs, Finset.le_sup'_iff, coe_le_coe, coe_nnnorm']
+ using hs.norm_prod_le_sup'_norm f
+
+/--
+Generalised ultrametric triangle inequality for finite products in commutative groups with
+an ultrametric norm.
+-/
+@[to_additive "Generalised ultrametric triangle inequality for finite sums in additive commutative
+groups with an ultrametric norm."]
+lemma nnnorm_prod_le_of_forall_le {s : Finset ι} {f : ι → M} {C : ℝ≥0}
+ (hC : ∀ i ∈ s, ‖f i‖₊ ≤ C) : ‖∏ i ∈ s, f i‖₊ ≤ C :=
+ (s.nnnorm_prod_le_sup_nnnorm f).trans <| Finset.sup_le hC
+
+/--
+Generalised ultrametric triangle inequality for nonempty finite products in commutative groups with
+an ultrametric norm.
+-/
+@[to_additive "Generalised ultrametric triangle inequality for nonempty finite sums in additive
+commutative groups with an ultrametric norm."]
+lemma norm_prod_le_of_forall_le_of_nonempty {s : Finset ι} (hs : s.Nonempty) {f : ι → M} {C : ℝ}
+ (hC : ∀ i ∈ s, ‖f i‖ ≤ C) : ‖∏ i ∈ s, f i‖ ≤ C :=
+ (hs.norm_prod_le_sup'_norm f).trans (Finset.sup'_le hs _ hC)
+
+/--
+Generalised ultrametric triangle inequality for finite products in commutative groups with
+an ultrametric norm.
+-/
+@[to_additive "Generalised ultrametric triangle inequality for finite sums in additive commutative
+groups with an ultrametric norm."]
+lemma norm_prod_le_of_forall_le_of_nonneg {s : Finset ι} {f : ι → M} {C : ℝ}
+ (h_nonneg : 0 ≤ C) (hC : ∀ i ∈ s, ‖f i‖ ≤ C) : ‖∏ i ∈ s, f i‖ ≤ C := by
+ 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 42621d3976ca7..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) :
@@ -379,4 +399,17 @@ theorem cauchySeq_prod_of_eventually_eq {u v : ℕ → E} {N : ℕ} (huv : ∀ n
intro m hm
simp [huv m (le_of_lt hm)]
+@[to_additive CauchySeq.norm_bddAbove]
+lemma CauchySeq.mul_norm_bddAbove {G : Type*} [SeminormedGroup G] {u : ℕ → G}
+ (hu : CauchySeq u) : BddAbove (Set.range (fun n ↦ ‖u n‖)) := by
+ obtain ⟨C, -, hC⟩ := cauchySeq_bdd hu
+ simp_rw [SeminormedGroup.dist_eq] at hC
+ have : ∀ n, ‖u n‖ ≤ C + ‖u 0‖ := by
+ intro n
+ rw [add_comm]
+ refine (norm_le_norm_add_norm_div' (u n) (u 0)).trans ?_
+ simp [(hC _ _).le]
+ rw [bddAbove_def]
+ exact ⟨C + ‖u 0‖, by simpa using this⟩
+
end SeminormedCommGroup
diff --git a/Mathlib/Analysis/Normed/Group/ZeroAtInfty.lean b/Mathlib/Analysis/Normed/Group/ZeroAtInfty.lean
index a2cabd37f31d1..825bb7c7941a6 100644
--- a/Mathlib/Analysis/Normed/Group/ZeroAtInfty.lean
+++ b/Mathlib/Analysis/Normed/Group/ZeroAtInfty.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Moritz Doll
-/
-import Mathlib.Topology.ContinuousFunction.ZeroAtInfty
+import Mathlib.Topology.ContinuousMap.ZeroAtInfty
/-!
# ZeroAtInftyContinuousMapClass in normed additive groups
diff --git a/Mathlib/Analysis/Normed/Lp/LpEquiv.lean b/Mathlib/Analysis/Normed/Lp/LpEquiv.lean
index 8be09ea3634f1..013c08de891cd 100644
--- a/Mathlib/Analysis/Normed/Lp/LpEquiv.lean
+++ b/Mathlib/Analysis/Normed/Lp/LpEquiv.lean
@@ -5,7 +5,7 @@ Authors: Jireh Loreaux
-/
import Mathlib.Analysis.Normed.Lp.lpSpace
import Mathlib.Analysis.Normed.Lp.PiLp
-import Mathlib.Topology.ContinuousFunction.Bounded
+import Mathlib.Topology.ContinuousMap.Bounded
/-!
# Equivalences among $L^p$ spaces
@@ -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 aed43fb34f51d..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
@@ -354,7 +361,7 @@ abbrev pseudoMetricAux : PseudoMetricSpace (PiLp p α) :=
PseudoMetricSpace.edist_dist]
-- Porting note: `le_iSup` needed some help
exact le_iSup (fun k => edist (f k) (g k)) i
- · refine ENNReal.toReal_le_of_le_ofReal (Real.sSup_nonneg _ ?_) (iSup_le fun i => ?_)
+ · refine ENNReal.toReal_le_of_le_ofReal (Real.sSup_nonneg ?_) (iSup_le fun i => ?_)
· rintro - ⟨i, rfl⟩
exact dist_nonneg
· change PseudoMetricSpace.edist _ _ ≤ _
@@ -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 a14d459bc6280..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
@@ -186,7 +189,7 @@ theorem NormedSpace.exists_lt_norm (c : ℝ) : ∃ x : E, c < ‖x‖ := by
rcases exists_ne (0 : E) with ⟨x, hx⟩
rcases NormedField.exists_lt_norm 𝕜 (c / ‖x‖) with ⟨r, hr⟩
use r • x
- rwa [norm_smul, ← _root_.div_lt_iff]
+ rwa [norm_smul, ← div_lt_iff₀]
rwa [norm_pos_iff]
protected theorem NormedSpace.unbounded_univ : ¬Bornology.IsBounded (univ : Set E) := fun h =>
@@ -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/Completion.lean b/Mathlib/Analysis/Normed/Module/Completion.lean
index 451aed37e833c..f0a8fdeed667d 100644
--- a/Mathlib/Analysis/Normed/Module/Completion.lean
+++ b/Mathlib/Analysis/Normed/Module/Completion.lean
@@ -27,20 +27,16 @@ namespace UniformSpace
namespace Completion
-variable (𝕜 E : Type*) [NormedField 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E]
+variable (𝕜 E : Type*)
-instance (priority := 100) NormedSpace.to_uniformContinuousConstSMul :
- UniformContinuousConstSMul 𝕜 E :=
- ⟨fun c => (lipschitzWith_smul c).uniformContinuous⟩
+instance [NormedField 𝕜] [SeminormedAddCommGroup E] [NormedSpace 𝕜 E] :
+ NormedSpace 𝕜 (Completion E) where
+ norm_smul_le := norm_smul_le
-instance : NormedSpace 𝕜 (Completion E) :=
- { Completion.instModule with
- norm_smul_le := fun c x =>
- induction_on x
- (isClosed_le (continuous_const_smul _).norm (continuous_const.mul continuous_norm)) fun y =>
- by simp only [← coe_smul, norm_coe, norm_smul, le_rfl] }
+section Module
variable {𝕜 E}
+variable [Semiring 𝕜] [SeminormedAddCommGroup E] [Module 𝕜 E] [UniformContinuousConstSMul 𝕜 E]
/-- Embedding of a normed space to its completion as a linear isometry. -/
def toComplₗᵢ : E →ₗᵢ[𝕜] Completion E :=
@@ -66,46 +62,35 @@ theorem norm_toComplL {𝕜 E : Type*} [NontriviallyNormedField 𝕜] [NormedAdd
[NormedSpace 𝕜 E] [Nontrivial E] : ‖(toComplL : E →L[𝕜] Completion E)‖ = 1 :=
(toComplₗᵢ : E →ₗᵢ[𝕜] Completion E).norm_toContinuousLinearMap
+end Module
+
section Algebra
-variable (𝕜) (A : Type*)
-
-instance [SeminormedRing A] : NormedRing (Completion A) :=
- { Completion.ring,
- Completion.instMetricSpace with
- dist_eq := fun x y => by
- refine Completion.induction_on₂ x y ?_ ?_ <;> clear x y
- · refine isClosed_eq (Completion.uniformContinuous_extension₂ _).continuous ?_
- exact Continuous.comp Completion.continuous_extension continuous_sub
- · intro x y
- rw [← Completion.coe_sub, norm_coe, Completion.dist_eq, dist_eq_norm]
- norm_mul := fun x y => by
- refine Completion.induction_on₂ x y ?_ ?_ <;> clear x y
- · exact
- isClosed_le (Continuous.comp continuous_norm continuous_mul)
- (Continuous.comp _root_.continuous_mul
- (Continuous.prod_map continuous_norm continuous_norm))
- · intro x y
- simp only [← coe_mul, norm_coe]
- exact norm_mul_le x y }
-
-instance [SeminormedCommRing A] [NormedAlgebra 𝕜 A] [UniformContinuousConstSMul 𝕜 A] :
- NormedAlgebra 𝕜 (Completion A) :=
- { Completion.algebra A 𝕜 with
- norm_smul_le := fun r x => by
- refine Completion.induction_on x ?_ ?_ <;> clear x
- · exact
- isClosed_le (Continuous.comp continuous_norm (continuous_const_smul r))
- (Continuous.comp (continuous_mul_left _) continuous_norm)
- · intro x
- simp only [← coe_smul, norm_coe]
- exact norm_smul_le r x }
+variable (A : Type*)
+
+instance [SeminormedRing A] : NormedRing (Completion A) where
+ __ : NormedAddCommGroup (Completion A) := inferInstance
+ __ : Ring (Completion A) := inferInstance
+ norm_mul x y := by
+ induction x, y using induction_on₂ with
+ | hp =>
+ apply isClosed_le <;> fun_prop
+ | ih x y =>
+ simp only [← coe_mul, norm_coe]
+ exact norm_mul_le x y
+
+instance [SeminormedCommRing A] : NormedCommRing (Completion A) where
+ __ : CommRing (Completion A) := inferInstance
+ __ : NormedRing (Completion A) := inferInstance
+
+instance [NormedField 𝕜] [SeminormedCommRing A] [NormedAlgebra 𝕜 A] :
+ NormedAlgebra 𝕜 (Completion A) where
+ norm_smul_le := norm_smul_le
instance [NormedField A] [CompletableTopField A] :
NormedField (UniformSpace.Completion A) where
- dist_eq x y := by
- refine induction_on₂ x y ?_ (by simp [← coe_sub, dist_eq_norm])
- exact isClosed_eq (uniformContinuous_extension₂ _).continuous (by fun_prop)
+ __ : NormedCommRing (Completion A) := inferInstance
+ __ : Field (Completion A) := inferInstance
norm_mul' x y := induction_on₂ x y (isClosed_eq (by fun_prop) (by fun_prop)) (by simp [← coe_mul])
end Algebra
diff --git a/Mathlib/Analysis/Normed/Module/Dual.lean b/Mathlib/Analysis/Normed/Module/Dual.lean
index 91bfbe1dc1f82..f8115711046c5 100644
--- a/Mathlib/Analysis/Normed/Module/Dual.lean
+++ b/Mathlib/Analysis/Normed/Module/Dual.lean
@@ -159,6 +159,13 @@ variable {E : Type*} [SeminormedAddCommGroup E] [NormedSpace 𝕜 E]
theorem mem_polar_iff {x' : Dual 𝕜 E} (s : Set E) : x' ∈ polar 𝕜 s ↔ ∀ z ∈ s, ‖x' z‖ ≤ 1 :=
Iff.rfl
+@[simp]
+theorem zero_mem_polar (s : Set E) : (0 : Dual 𝕜 E) ∈ polar 𝕜 s :=
+ LinearMap.zero_mem_polar _ s
+
+theorem polar_nonempty (s : Set E) : Set.Nonempty (polar 𝕜 s) :=
+ LinearMap.polar_nonempty _ _
+
@[simp]
theorem polar_univ : polar 𝕜 (univ : Set E) = {(0 : Dual 𝕜 E)} :=
(dualPairing 𝕜 E).flip.polar_univ
@@ -205,7 +212,7 @@ theorem polar_ball_subset_closedBall_div {c : 𝕜} (hc : 1 < ‖c‖) {r : ℝ}
refine ContinuousLinearMap.opNorm_le_of_shell hr hcr.le hc fun x h₁ h₂ => ?_
calc
‖x' x‖ ≤ 1 := hx' _ h₂
- _ ≤ ‖c‖ / r * ‖x‖ := (inv_pos_le_iff_one_le_mul' hcr).1 (by rwa [inv_div])
+ _ ≤ ‖c‖ / r * ‖x‖ := (inv_le_iff_one_le_mul₀' hcr).1 (by rwa [inv_div])
variable (𝕜)
@@ -238,11 +245,11 @@ theorem polar_ball {𝕜 E : Type*} [RCLike 𝕜] [NormedAddCommGroup E] [Normed
intro a ha
rw [← mem_closedBall_zero_iff, ← (mul_div_cancel_left₀ a (Ne.symm (ne_of_lt hr)))]
rw [← RCLike.norm_of_nonneg (K := 𝕜) (le_trans zero_le_one
- (le_of_lt ((inv_pos_lt_iff_one_lt_mul' hr).mp ha)))]
+ (le_of_lt ((inv_lt_iff_one_lt_mul₀' hr).mp ha)))]
apply polar_ball_subset_closedBall_div _ hr hx
rw [RCLike.norm_of_nonneg (K := 𝕜) (le_trans zero_le_one
- (le_of_lt ((inv_pos_lt_iff_one_lt_mul' hr).mp ha)))]
- exact (inv_pos_lt_iff_one_lt_mul' hr).mp ha
+ (le_of_lt ((inv_lt_iff_one_lt_mul₀' hr).mp ha)))]
+ exact (inv_lt_iff_one_lt_mul₀' hr).mp ha
· rw [← polar_closedBall hr]
exact LinearMap.polar_antitone _ ball_subset_closedBall
@@ -256,6 +263,10 @@ theorem isBounded_polar_of_mem_nhds_zero {s : Set E} (s_nhd : s ∈ 𝓝 (0 : E)
(((dualPairing 𝕜 E).flip.polar_antitone r_ball).trans <|
polar_ball_subset_closedBall_div ha r_pos)
+@[simp]
+theorem polar_empty : polar 𝕜 (∅ : Set E) = Set.univ :=
+ LinearMap.polar_empty _
+
@[simp]
theorem polar_singleton {a : E} : polar 𝕜 {a} = { x | ‖x a‖ ≤ 1 } := by
simp only [polar, LinearMap.polar_singleton, LinearMap.flip_apply, dualPairing_apply]
@@ -263,6 +274,9 @@ theorem polar_singleton {a : E} : polar 𝕜 {a} = { x | ‖x a‖ ≤ 1 } := by
theorem mem_polar_singleton {a : E} (y : Dual 𝕜 E) : y ∈ polar 𝕜 {a} ↔ ‖y a‖ ≤ 1 := by
simp only [polar_singleton, mem_setOf_eq]
+theorem polar_zero : polar 𝕜 ({0} : Set E) = Set.univ :=
+ LinearMap.polar_zero _
+
theorem sInter_polar_eq_closedBall {𝕜 E : Type*} [RCLike 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E]
{r : ℝ} (hr : 0 < r) :
⋂₀ (polar 𝕜 '' { F | F.Finite ∧ F ⊆ closedBall (0 : E) r⁻¹ }) = closedBall 0 r := by
diff --git a/Mathlib/Analysis/Normed/Module/FiniteDimension.lean b/Mathlib/Analysis/Normed/Module/FiniteDimension.lean
index 4c55f7d09dafa..34b802ea77856 100644
--- a/Mathlib/Analysis/Normed/Module/FiniteDimension.lean
+++ b/Mathlib/Analysis/Normed/Module/FiniteDimension.lean
@@ -48,7 +48,7 @@ universe u v w x
noncomputable section
-open Set FiniteDimensional TopologicalSpace Filter Asymptotics Topology NNReal Metric
+open Asymptotics Filter Module Metric Module NNReal Set TopologicalSpace Topology
namespace LinearIsometry
@@ -323,14 +323,14 @@ theorem Basis.exists_opNorm_le {ι : Type*} [Finite ι] (v : Basis ι 𝕜 E) :
instance [FiniteDimensional 𝕜 E] [SecondCountableTopology F] :
SecondCountableTopology (E →L[𝕜] F) := by
- set d := FiniteDimensional.finrank 𝕜 E
+ set d := Module.finrank 𝕜 E
suffices
∀ ε > (0 : ℝ), ∃ n : (E →L[𝕜] F) → Fin d → ℕ, ∀ f g : E →L[𝕜] F, n f = n g → dist f g ≤ ε from
Metric.secondCountable_of_countable_discretization fun ε ε_pos =>
⟨Fin d → ℕ, by infer_instance, this ε ε_pos⟩
intro ε ε_pos
obtain ⟨u : ℕ → F, hu : DenseRange u⟩ := exists_dense_seq F
- let v := FiniteDimensional.finBasis 𝕜 E
+ let v := Module.finBasis 𝕜 E
obtain
⟨C : ℝ, C_pos : 0 < C, hC :
∀ {φ : E →L[𝕜] F} {M : ℝ}, 0 ≤ M → (∀ i, ‖φ (v i)‖ ≤ M) → ‖φ‖ ≤ C * M⟩ :=
@@ -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")]
@@ -647,7 +647,7 @@ theorem summable_norm_iff {α E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ
refine ⟨Summable.of_norm, fun hf ↦ ?_⟩
-- First we use a finite basis to reduce the problem to the case `E = Fin N → ℝ`
suffices ∀ {N : ℕ} {g : α → Fin N → ℝ}, Summable g → Summable fun x => ‖g x‖ by
- obtain v := finBasis ℝ E
+ obtain v := Module.finBasis ℝ E
set e := v.equivFunL
have H : Summable fun x => ‖e (f x)‖ := this (e.summable.2 hf)
refine .of_norm_bounded _ (H.mul_left ↑‖(e.symm : (Fin (finrank ℝ E) → ℝ) →L[ℝ] E)‖₊) fun i ↦ ?_
diff --git a/Mathlib/Analysis/Normed/Module/Ray.lean b/Mathlib/Analysis/Normed/Module/Ray.lean
index 93b860a1c1924..f01da59497153 100644
--- a/Mathlib/Analysis/Normed/Module/Ray.lean
+++ b/Mathlib/Analysis/Normed/Module/Ray.lean
@@ -81,7 +81,7 @@ the unit vectors `‖x‖⁻¹ • x` and `‖y‖⁻¹ • y` are equal. -/
theorem sameRay_iff_inv_norm_smul_eq : SameRay ℝ x y ↔ x = 0 ∨ y = 0 ∨ ‖x‖⁻¹ • x = ‖y‖⁻¹ • y := by
rcases eq_or_ne x 0 with (rfl | hx); · simp [SameRay.zero_left]
rcases eq_or_ne y 0 with (rfl | hy); · simp [SameRay.zero_right]
- simp only [sameRay_iff_inv_norm_smul_eq_of_ne hx hy, *, false_or_iff]
+ simp only [sameRay_iff_inv_norm_smul_eq_of_ne hx hy, *, false_or]
/-- Two vectors of the same norm are on the same ray if and only if they are equal. -/
theorem sameRay_iff_of_norm_eq (h : ‖x‖ = ‖y‖) : SameRay ℝ x y ↔ x = y := by
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 71dc2da624481..a5798eaf704c2 100644
--- a/Mathlib/Analysis/Normed/Module/WeakDual.lean
+++ b/Mathlib/Analysis/Normed/Module/WeakDual.lean
@@ -5,6 +5,7 @@ Authors: Kalle Kytölä, Yury Kudryashov
-/
import Mathlib.Analysis.Normed.Module.Dual
import Mathlib.Analysis.NormedSpace.OperatorNorm.Completeness
+import Mathlib.Topology.Algebra.Module.WeakDual
/-!
# Weak dual of normed space
@@ -197,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/MulAction.lean b/Mathlib/Analysis/Normed/MulAction.lean
index 1c42cc236b1e9..2c9c706fdb6c1 100644
--- a/Mathlib/Analysis/Normed/MulAction.lean
+++ b/Mathlib/Analysis/Normed/MulAction.lean
@@ -5,6 +5,7 @@ Authors: Eric Wieser
-/
import Mathlib.Analysis.Normed.Field.Basic
import Mathlib.Topology.MetricSpace.Algebra
+import Mathlib.Topology.Algebra.UniformMulAction
/-!
# Lemmas for `BoundedSMul` over normed additive groups
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 114bd3205cea4..39c1d73dc03d4 100644
--- a/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean
+++ b/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean
@@ -59,14 +59,14 @@ open Filter (Tendsto)
open Metric ContinuousLinearMap
-variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E]
- [NormedSpace 𝕜 E] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*}
- [NormedAddCommGroup G] [NormedSpace 𝕜 G]
+variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [SeminormedAddCommGroup E]
+ [NormedSpace 𝕜 E] {F : Type*} [SeminormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*}
+ [SeminormedAddCommGroup G] [NormedSpace 𝕜 G]
/-- A function `f` satisfies `IsBoundedLinearMap 𝕜 f` if it is linear and satisfies the
inequality `‖f x‖ ≤ M * ‖x‖` for some positive constant `M`. -/
-structure IsBoundedLinearMap (𝕜 : Type*) [NormedField 𝕜] {E : Type*} [NormedAddCommGroup E]
- [NormedSpace 𝕜 E] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] (f : E → F) extends
+structure IsBoundedLinearMap (𝕜 : Type*) [NormedField 𝕜] {E : Type*} [SeminormedAddCommGroup E]
+ [NormedSpace 𝕜 E] {F : Type*} [SeminormedAddCommGroup F] [NormedSpace 𝕜 F] (f : E → F) extends
IsLinearMap 𝕜 f : Prop where
bound : ∃ M, 0 < M ∧ ∀ x : E, ‖f x‖ ≤ M * ‖x‖
@@ -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
@@ -186,7 +186,7 @@ variable {ι : Type*} [Fintype ι]
/-- Taking the cartesian product of two continuous multilinear maps is a bounded linear
operation. -/
-theorem isBoundedLinearMap_prod_multilinear {E : ι → Type*} [∀ i, NormedAddCommGroup (E i)]
+theorem isBoundedLinearMap_prod_multilinear {E : ι → Type*} [∀ i, SeminormedAddCommGroup (E i)]
[∀ i, NormedSpace 𝕜 (E i)] :
IsBoundedLinearMap 𝕜 fun p : ContinuousMultilinearMap 𝕜 E F × ContinuousMultilinearMap 𝕜 E G =>
p.1.prod p.2 where
@@ -244,7 +244,7 @@ variable {R : Type*}
variable {𝕜₂ 𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NontriviallyNormedField 𝕜₂]
variable {M : Type*} [TopologicalSpace M]
variable {σ₁₂ : 𝕜 →+* 𝕜₂}
-variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace 𝕜₂ G'] [NormedSpace 𝕜' G']
+variable {G' : Type*} [SeminormedAddCommGroup G'] [NormedSpace 𝕜₂ G'] [NormedSpace 𝕜' G']
variable [SMulCommClass 𝕜₂ 𝕜' G']
section Semiring
@@ -374,7 +374,7 @@ theorem IsBoundedBilinearMap.isBoundedLinearMap_right (h : IsBoundedBilinearMap
(h.toContinuousLinearMap x).isBoundedLinearMap
theorem isBoundedBilinearMap_smul {𝕜' : Type*} [NormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] {E : Type*}
- [NormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedSpace 𝕜' E] [IsScalarTower 𝕜 𝕜' E] :
+ [SeminormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedSpace 𝕜' E] [IsScalarTower 𝕜 𝕜' E] :
IsBoundedBilinearMap 𝕜 fun p : 𝕜' × E => p.1 • p.2 :=
(lsmul 𝕜 𝕜' : 𝕜' →L[𝕜] E →L[𝕜] E).isBoundedBilinearMap
@@ -436,7 +436,7 @@ variable (𝕜)
/-- The function `ContinuousLinearMap.mulLeftRight : 𝕜' × 𝕜' → (𝕜' →L[𝕜] 𝕜')` is a bounded
bilinear map. -/
-theorem ContinuousLinearMap.mulLeftRight_isBoundedBilinear (𝕜' : Type*) [NormedRing 𝕜']
+theorem ContinuousLinearMap.mulLeftRight_isBoundedBilinear (𝕜' : Type*) [SeminormedRing 𝕜']
[NormedAlgebra 𝕜 𝕜'] :
IsBoundedBilinearMap 𝕜 fun p : 𝕜' × 𝕜' => ContinuousLinearMap.mulLeftRight 𝕜 𝕜' p.1 p.2 :=
(ContinuousLinearMap.mulLeftRight 𝕜 𝕜').isBoundedBilinearMap
@@ -471,9 +471,16 @@ theorem ContinuousOn.clm_apply {X} [TopologicalSpace X] {f : X → (E →L[𝕜]
ContinuousOn (fun x ↦ f x (g x)) s :=
isBoundedBilinearMap_apply.continuous.comp_continuousOn (hf.prod hg)
+end
+
namespace ContinuousLinearEquiv
+variable {𝕜 : Type*} [NontriviallyNormedField 𝕜]
+variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E]
+variable {F : Type*} [SeminormedAddCommGroup F] [NormedSpace 𝕜 F]
+
open Set
+open scoped Topology
/-!
### The set of continuous linear equivalences between two Banach spaces is open
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 eedbaba72b905..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
@@ -153,9 +154,13 @@ variable [Ring 𝕜] [Ring 𝕜₂]
variable [NormedAddCommGroup E] [NormedAddCommGroup F] [Module 𝕜 E] [Module 𝕜₂ F]
variable {σ : 𝕜 →+* 𝕜₂} (f g : E →SL[σ] F) (x y z : E)
-theorem ContinuousLinearMap.uniformEmbedding_of_bound {K : ℝ≥0} (hf : ∀ x, ‖x‖ ≤ K * ‖f x‖) :
- UniformEmbedding f :=
- (AddMonoidHomClass.antilipschitz_of_bound f hf).uniformEmbedding f.uniformContinuous
+theorem ContinuousLinearMap.isUniformEmbedding_of_bound {K : ℝ≥0} (hf : ∀ x, ‖x‖ ≤ K * ‖f x‖) :
+ IsUniformEmbedding f :=
+ (AddMonoidHomClass.antilipschitz_of_bound f hf).isUniformEmbedding f.uniformContinuous
+
+@[deprecated (since := "2024-10-01")]
+alias ContinuousLinearMap.uniformEmbedding_of_bound :=
+ ContinuousLinearMap.isUniformEmbedding_of_bound
end Normed
diff --git a/Mathlib/Analysis/Normed/Operator/LinearIsometry.lean b/Mathlib/Analysis/Normed/Operator/LinearIsometry.lean
index 578fd81859e6d..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,10 +200,15 @@ theorem nnnorm_map (x : E) : ‖f x‖₊ = ‖x‖₊ :=
protected theorem isometry : Isometry f :=
AddMonoidHomClass.isometry_of_norm f.toLinearMap (norm_map _)
+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} :
@@ -484,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₂) (↑) :=
@@ -635,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
@@ -799,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
@@ -840,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
@@ -952,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
new file mode 100644
index 0000000000000..f460ba8405dda
--- /dev/null
+++ b/Mathlib/Analysis/Normed/Ring/IsPowMulFaithful.lean
@@ -0,0 +1,96 @@
+/-
+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.Analysis.Normed.Algebra.Norm
+import Mathlib.Analysis.SpecialFunctions.Pow.Continuity
+
+/-!
+# Equivalent power-multiplicative norms
+
+In this file, we prove [BGR, Proposition 3.1.5/1][bosch-guntzer-remmert]: if `R` is a normed
+commutative ring and `f₁` and `f₂` are two power-multiplicative `R`-algebra norms on `S`, then if
+`f₁` and `f₂` are equivalent on every subring `R[y]` for `y : S`, it follows that `f₁ = f₂`.
+
+## Main Results
+* `eq_of_powMul_faithful` : the proof of [BGR, Proposition 3.1.5/1][bosch-guntzer-remmert].
+
+## References
+* [S. Bosch, U. Güntzer, R. Remmert, *Non-Archimedean Analysis*][bosch-guntzer-remmert]
+
+## Tags
+
+norm, equivalent, power-multiplicative
+-/
+
+open Filter Real
+open scoped Topology
+
+/-- If `f : α →+* β` is bounded with respect to a ring seminorm `nα` on `α` and a
+ power-multiplicative function `nβ : β → ℝ`, then `∀ x : α, nβ (f x) ≤ nα x`. -/
+theorem contraction_of_isPowMul_of_boundedWrt {F : Type*} {α : outParam (Type*)} [Ring α]
+ [FunLike F α ℝ] [RingSeminormClass F α ℝ] {β : Type*} [Ring β] (nα : F) {nβ : β → ℝ}
+ (hβ : IsPowMul nβ) {f : α →+* β} (hf : f.IsBoundedWrt nα nβ) (x : α) : nβ (f x) ≤ nα x := by
+ obtain ⟨C, hC0, hC⟩ := hf
+ have hlim : Tendsto (fun n : ℕ => C ^ (1 / (n : ℝ)) * nα x) atTop (𝓝 (nα x)) := by
+ nth_rewrite 2 [← one_mul (nα x)]
+ exact ((rpow_zero C ▸ ContinuousAt.tendsto (continuousAt_const_rpow (ne_of_gt hC0))).comp
+ (tendsto_const_div_atTop_nhds_zero_nat 1)).mul tendsto_const_nhds
+ apply ge_of_tendsto hlim
+ simp only [eventually_atTop, ge_iff_le]
+ use 1
+ intro n hn
+ have h : (C ^ (1 / n : ℝ)) ^ n = C := by
+ have hn0 : (n : ℝ) ≠ 0 := Nat.cast_ne_zero.mpr (ne_of_gt hn)
+ rw [← rpow_natCast, ← rpow_mul (le_of_lt hC0), one_div, inv_mul_cancel₀ hn0, rpow_one]
+ apply le_of_pow_le_pow_left (ne_of_gt hn)
+ (mul_nonneg (rpow_nonneg (le_of_lt hC0) _) (apply_nonneg _ _))
+ · rw [mul_pow, h, ← hβ _ hn, ← RingHom.map_pow]
+ apply le_trans (hC (x ^ n))
+ rw [mul_le_mul_left hC0]
+ exact map_pow_le_pow _ _ (Nat.one_le_iff_ne_zero.mp hn)
+
+/-- Given a bounded `f : α →+* β` between seminormed rings, is the seminorm on `β` is
+ power-multiplicative, then `f` is a contraction. -/
+theorem contraction_of_isPowMul {α β : Type*} [SeminormedRing α] [SeminormedRing β]
+ (hβ : IsPowMul (norm : β → ℝ)) {f : α →+* β} (hf : f.IsBounded) (x : α) : norm (f x) ≤ norm x :=
+ 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 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)
+ (hgf : ∃ (r : ℝ) (_ : 0 < r), ∀ a : α, g a ≤ r * f a) : f = g := by
+ obtain ⟨r, hr0, hr⟩ := hfg
+ obtain ⟨s, hs0, hs⟩ := hgf
+ have hle : RingHom.IsBoundedWrt f g (RingHom.id _) := ⟨s, hs0, hs⟩
+ have hge : RingHom.IsBoundedWrt g f (RingHom.id _) := ⟨r, hr0, hr⟩
+ rw [← Function.Injective.eq_iff DFunLike.coe_injective']
+ ext x
+ exact le_antisymm (contraction_of_isPowMul_of_boundedWrt g hfpm hge x)
+ (contraction_of_isPowMul_of_boundedWrt f hgpm hle x)
+
+variable {R S : Type*} [NormedCommRing R] [CommRing S] [Algebra R S]
+
+/-- If `R` is a normed commutative ring and `f₁` and `f₂` are two power-multiplicative `R`-algebra
+ norms on `S`, then if `f₁` and `f₂` are equivalent on every subring `R[y]` for `y : S`, it
+ follows that `f₁ = f₂` [BGR, Proposition 3.1.5/1][bosch-guntzer-remmert]. -/
+theorem eq_of_powMul_faithful (f₁ : AlgebraNorm R S) (hf₁_pm : IsPowMul f₁) (f₂ : AlgebraNorm R S)
+ (hf₂_pm : IsPowMul f₂)
+ (h_eq : ∀ y : S, ∃ (C₁ C₂ : ℝ) (_ : 0 < C₁) (_ : 0 < C₂),
+ ∀ x : Algebra.adjoin R {y}, f₁ x.val ≤ C₁ * f₂ x.val ∧ f₂ x.val ≤ C₂ * f₁ x.val) :
+ f₁ = f₂ := by
+ ext x
+ set g₁ : AlgebraNorm R (Algebra.adjoin R ({x} : Set S)) := AlgebraNorm.restriction _ f₁
+ set g₂ : AlgebraNorm R (Algebra.adjoin R ({x} : Set S)) := AlgebraNorm.restriction _ f₂
+ have hg₁_pm : IsPowMul g₁ := IsPowMul.restriction _ hf₁_pm
+ have hg₂_pm : IsPowMul g₂ := IsPowMul.restriction _ hf₂_pm
+ let y : Algebra.adjoin R ({x} : Set S) := ⟨x, Algebra.self_mem_adjoin_singleton R x⟩
+ have hy : x = y.val := rfl
+ have h1 : f₁ y.val = g₁ y := rfl
+ have h2 : f₂ y.val = g₂ y := rfl
+ obtain ⟨C₁, C₂, hC₁_pos, hC₂_pos, hC⟩ := h_eq x
+ obtain ⟨hC₁, hC₂⟩ := forall_and.mp hC
+ rw [hy, h1, h2, eq_seminorms hg₁_pm hg₂_pm ⟨C₁, hC₁_pos, hC₁⟩ ⟨C₂, hC₂_pos, hC₂⟩]
diff --git a/Mathlib/Analysis/Normed/Ring/Seminorm.lean b/Mathlib/Analysis/Normed/Ring/Seminorm.lean
index 2f18c14fb0172..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`. -/
@@ -151,6 +151,26 @@ end Ring
end RingSeminorm
+/-- If `f` is a ring seminorm on `a`, then `∀ {n : ℕ}, n ≠ 0 → f (a ^ n) ≤ f a ^ n`. -/
+theorem map_pow_le_pow {F α : Type*} [Ring α] [FunLike F α ℝ] [RingSeminormClass F α ℝ] (f : F)
+ (a : α) : ∀ {n : ℕ}, n ≠ 0 → f (a ^ n) ≤ f a ^ n
+ | 0, h => absurd rfl h
+ | 1, _ => by simp only [pow_one, le_refl]
+ | n + 2, _ => by
+ simp only [pow_succ _ (n + 1)];
+ exact
+ le_trans (map_mul_le_mul f _ a)
+ (mul_le_mul_of_nonneg_right (map_pow_le_pow _ _ n.succ_ne_zero) (apply_nonneg f a))
+
+/-- If `f` is a ring seminorm on `a` with `f 1 ≤ 1`, then `∀ (n : ℕ), f (a ^ n) ≤ f a ^ n`. -/
+theorem map_pow_le_pow' {F α : Type*} [Ring α] [FunLike F α ℝ] [RingSeminormClass F α ℝ] {f : F}
+ (hf1 : f 1 ≤ 1) (a : α) : ∀ n : ℕ, f (a ^ n) ≤ f a ^ n
+ | 0 => by simp only [pow_zero, hf1]
+ | n + 1 => by
+ simp only [pow_succ _ n];
+ exact le_trans (map_mul_le_mul f _ a)
+ (mul_le_mul_of_nonneg_right (map_pow_le_pow' hf1 _ n) (apply_nonneg f a))
+
/-- The norm of a `NonUnitalSeminormedRing` as a `RingSeminorm`. -/
def normRingSeminorm (R : Type*) [NonUnitalSeminormedRing R] : RingSeminorm R :=
{ normAddGroupSeminorm R with
@@ -368,3 +388,46 @@ lemma MulRingNorm.apply_natAbs_eq {R : Type*} [Ring R] (x : ℤ) (f : MulRingNor
f x := by
obtain ⟨n, rfl | rfl⟩ := eq_nat_or_neg x <;>
simp only [natAbs_neg, natAbs_ofNat, cast_neg, cast_natCast, map_neg_eq_map]
+
+/-- The seminorm on a `SeminormedRing`, as a `RingSeminorm`. -/
+def SeminormedRing.toRingSeminorm (R : Type*) [SeminormedRing R] : RingSeminorm R where
+ toFun := norm
+ map_zero' := norm_zero
+ add_le' := norm_add_le
+ mul_le' := norm_mul_le
+ neg' := norm_neg
+
+/-- The norm on a `NormedRing`, as a `RingNorm`. -/
+@[simps]
+def NormedRing.toRingNorm (R : Type*) [NormedRing R] : RingNorm R where
+ toFun := norm
+ map_zero' := norm_zero
+ add_le' := norm_add_le
+ mul_le' := norm_mul_le
+ neg' := norm_neg
+ eq_zero_of_map_eq_zero' x hx := by rw [← norm_eq_zero]; exact hx
+
+@[simp]
+theorem NormedRing.toRingNorm_apply (R : Type*) [NormedRing R] (x : R) :
+ (NormedRing.toRingNorm R) x = ‖x‖ :=
+ rfl
+
+/-- The norm on a `NormedField`, as a `MulRingNorm`. -/
+def NormedField.toMulRingNorm (R : Type*) [NormedField R] : MulRingNorm R where
+ toFun := norm
+ map_zero' := norm_zero
+ map_one' := norm_one
+ add_le' := norm_add_le
+ 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/Ultra.lean b/Mathlib/Analysis/Normed/Ring/Ultra.lean
new file mode 100644
index 0000000000000..1e8016ac72edb
--- /dev/null
+++ b/Mathlib/Analysis/Normed/Ring/Ultra.lean
@@ -0,0 +1,78 @@
+/-
+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
+
+/-!
+# Ultrametric norms on rings where the norm of one is one
+
+This file contains results on the behavior of norms in ultrametric normed rings.
+The norm must send one to one.
+
+## Main results
+
+* `norm_intCast_le_one`:
+ the norm of the image of an integer in the ring is always less than or equal to one
+
+## Implementation details
+
+A `[NormedRing R]` only assumes a submultiplicative norm and does not have `[NormOneClass R]`.
+The weakest ring-like structure that has a bundled norm such that `‖1‖ = 1` is
+`[NormedDivisionRing K]`.
+Since the statements below hold in any context, we can state them
+in an unbundled fashion using `[NormOneClass R]`.
+In fact one can actually prove all these lemmas only assuming
+`{R : Type*} [SeminormedAddGroup R] [One R] [NormOneClass R] [IsUltrametricDist R]`.
+But one has to give the typeclass machinery a little help in order to get it to recognise that there
+is a coercion from `ℕ` or `ℤ` to `R`.
+Instead, we use weakest pre-existing typeclass that implies both
+`[SeminormedAddGroup R]` and `[AddGroupWithOne R]`, which is `[SeminormedRing R]`.
+
+## Tags
+
+ultrametric, nonarchimedean
+-/
+open Metric NNReal
+
+namespace IsUltrametricDist
+
+section NormOneClass
+
+variable {R : Type*} [SeminormedRing R] [NormOneClass R] [IsUltrametricDist R]
+
+lemma norm_add_one_le_max_norm_one (x : R) :
+ ‖x + 1‖ ≤ max ‖x‖ 1 := by
+ simpa only [le_max_iff, norm_one] using norm_add_le_max x 1
+
+lemma nnnorm_add_one_le_max_nnnorm_one (x : R) :
+ ‖x + 1‖₊ ≤ max ‖x‖₊ 1 :=
+ norm_add_one_le_max_norm_one _
+
+variable (R)
+lemma nnnorm_natCast_le_one (n : ℕ) :
+ ‖(n : R)‖₊ ≤ 1 := by
+ induction n with
+ | zero => simp only [Nat.cast_zero, nnnorm_zero, zero_le]
+ | succ n hn => simpa only [Nat.cast_add, Nat.cast_one, hn, max_eq_right] using
+ nnnorm_add_one_le_max_nnnorm_one (n : R)
+
+lemma norm_natCast_le_one (n : ℕ) :
+ ‖(n : R)‖ ≤ 1 :=
+ nnnorm_natCast_le_one R n
+
+lemma nnnorm_intCast_le_one (z : ℤ) :
+ ‖(z : R)‖₊ ≤ 1 := by
+ induction z <;>
+ simpa only [Int.ofNat_eq_coe, Int.cast_natCast, Int.cast_negSucc, Nat.cast_one, nnnorm_neg]
+ using nnnorm_natCast_le_one _ _
+
+lemma norm_intCast_le_one (z : ℤ) :
+ ‖(z : R)‖ ≤ 1 :=
+ nnnorm_intCast_le_one _ z
+
+end NormOneClass
+
+end IsUltrametricDist
diff --git a/Mathlib/Analysis/Normed/Ring/Units.lean b/Mathlib/Analysis/Normed/Ring/Units.lean
index a99777748c99d..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
@@ -14,12 +15,12 @@ normed ring (Banach algebras being a notable special case).
## Main results
-The constructions `Units.oneSub`, `Units.add`, and `Units.ofNearby` state, in varying forms, that
-perturbations of a unit are units. The latter two are not stated in their optimal form; more precise
-versions would use the spectral radius.
+The constructions `Units.add` and `Units.ofNearby` (based on `Units.oneSub` defined elsewhere)
+state, in varying forms, that perturbations of a unit are units. They are not stated
+in their optimal form; more precise versions would use the spectral radius.
-The first main result is `Units.isOpen`: the group of units of a complete normed ring is an open
-subset of the ring.
+The first main result is `Units.isOpen`: the group of units of a normed ring with summable
+geometric series is an open subset of the ring.
The function `Ring.inverse` (defined elsewhere), for a ring `R`, sends `a : R` to `a⁻¹` if `a` is a
unit and `0` if not. The other major results of this file (notably `NormedRing.inverse_add`,
@@ -31,21 +32,13 @@ noncomputable section
open Topology
-variable {R : Type*} [NormedRing R] [CompleteSpace R]
+variable {R : Type*} [NormedRing R] [HasSummableGeomSeries R]
namespace Units
-/-- In a complete normed ring, a perturbation of `1` by an element `t` of distance less than `1`
-from `1` is a unit. Here we construct its `Units` structure. -/
-@[simps val]
-def oneSub (t : R) (h : ‖t‖ < 1) : Rˣ where
- val := 1 - t
- inv := ∑' n : ℕ, t ^ n
- val_inv := mul_neg_geom_series t h
- inv_val := geom_series_mul_neg t h
-
-/-- In a complete normed ring, a perturbation of a unit `x` by an element `t` of distance less than
-`‖x⁻¹‖⁻¹` from `x` is a unit. Here we construct its `Units` structure. -/
+/-- In a normed ring with summable geometric series, a perturbation of a unit `x` by an
+element `t` of distance less than `‖x⁻¹‖⁻¹` from `x` is a unit.
+Here we construct its `Units` structure. -/
@[simps! val]
def add (x : Rˣ) (t : R) (h : ‖t‖ < ‖(↑x⁻¹ : R)‖⁻¹) : Rˣ :=
Units.copy -- to make `add_val` true definitionally, for convenience
@@ -59,13 +52,14 @@ def add (x : Rˣ) (t : R) (h : ‖t‖ < ‖(↑x⁻¹ : R)‖⁻¹) : Rˣ :=
_ = 1 := mul_inv_cancel₀ (ne_of_gt hpos)))
(x + t) (by simp [mul_add]) _ rfl
-/-- In a complete normed ring, an element `y` of distance less than `‖x⁻¹‖⁻¹` from `x` is a unit.
-Here we construct its `Units` structure. -/
+/-- In a normed ring with summable geometric series, an element `y` of distance less
+than `‖x⁻¹‖⁻¹` from `x` is a unit. Here we construct its `Units` structure. -/
@[simps! val]
def ofNearby (x : Rˣ) (y : R) (h : ‖y - x‖ < ‖(↑x⁻¹ : R)‖⁻¹) : Rˣ :=
(x.add (y - x : R) h).copy y (by simp) _ rfl
-/-- The group of units of a complete normed ring is an open subset of the ring. -/
+/-- The group of units of a normed ring with summable geometric series is an open subset
+of the ring. -/
protected theorem isOpen : IsOpen { x : R | IsUnit x } := by
nontriviality R
rw [Metric.isOpen_iff]
@@ -81,12 +75,12 @@ end Units
namespace nonunits
-/-- The `nonunits` in a complete normed ring are contained in the complement of the ball of radius
-`1` centered at `1 : R`. -/
+/-- The `nonunits` in a normed ring with summable geometric series are contained in the
+complement of the ball of radius `1` centered at `1 : R`. -/
theorem subset_compl_ball : nonunits R ⊆ (Metric.ball (1 : R) 1)ᶜ := fun x hx h₁ ↦ hx <|
sub_sub_self 1 x ▸ (Units.oneSub (1 - x) (by rwa [mem_ball_iff_norm'] at h₁)).isUnit
--- The `nonunits` in a complete normed ring are a closed set
+-- The `nonunits` in a normed ring with summable geometric series are a closed set
protected theorem isClosed : IsClosed (nonunits R) :=
Units.isOpen.isClosed_compl
@@ -114,7 +108,7 @@ theorem inverse_add (x : Rˣ) :
theorem inverse_one_sub_nth_order' (n : ℕ) {t : R} (ht : ‖t‖ < 1) :
inverse ((1 : R) - t) = (∑ i ∈ range n, t ^ i) + t ^ n * inverse (1 - t) :=
- have := NormedRing.summable_geometric_of_norm_lt_one t ht
+ have := _root_.summable_geometric_of_norm_lt_one ht
calc inverse (1 - t) = ∑' i : ℕ, t ^ i := inverse_one_sub t ht
_ = ∑ i ∈ range n, t ^ i + ∑' i : ℕ, t ^ (i + n) := (sum_add_tsum_nat_add _ this).symm
_ = (∑ i ∈ range n, t ^ i) + t ^ n * inverse (1 - t) := by
@@ -149,10 +143,10 @@ theorem inverse_one_sub_norm : (fun t : R => inverse (1 - t)) =O[𝓝 0] (fun _t
linarith
simp only [inverse_one_sub t ht', norm_one, mul_one, Set.mem_setOf_eq]
change ‖∑' n : ℕ, t ^ n‖ ≤ _
- have := NormedRing.tsum_geometric_of_norm_lt_one t ht'
+ 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
@@ -205,17 +199,20 @@ namespace Units
open MulOpposite Filter NormedRing
-/-- In a normed ring, 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'
+/-- 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 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
-/-- In a normed ring, the coercion from `Rˣ` (equipped with the induced topology from the
-embedding in `R × R`) to `R` is an open map. -/
+@[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
@@ -227,16 +224,18 @@ theorem eq_top_of_norm_lt_one (I : Ideal R) {x : R} (hxI : x ∈ I) (hx : ‖1 -
I.eq_top_iff_one.mpr <| by
simpa only [show u.inv * x = 1 by simp [u]] using I.mul_mem_left u.inv hxI
-/-- The `Ideal.closure` of a proper ideal in a complete normed ring is proper. -/
+/-- The `Ideal.closure` of a proper ideal in a normed ring with summable
+geometric series is proper. -/
theorem closure_ne_top (I : Ideal R) (hI : I ≠ ⊤) : I.closure ≠ ⊤ := by
have h := closure_minimal (coe_subset_nonunits hI) nonunits.isClosed
simpa only [I.closure.eq_top_iff_one, Ne] using mt (@h 1) one_not_mem_nonunits
-/-- The `Ideal.closure` of a maximal ideal in a complete normed ring is the ideal itself. -/
+/-- The `Ideal.closure` of a maximal ideal in a normed ring with summable
+geometric series is the ideal itself. -/
theorem IsMaximal.closure_eq {I : Ideal R} (hI : I.IsMaximal) : I.closure = I :=
(hI.eq_of_le (I.closure_ne_top hI.ne_top) subset_closure).symm
-/-- Maximal ideals in complete normed rings are closed. -/
+/-- Maximal ideals in normed rings with summable geometric series are closed. -/
instance IsMaximal.isClosed {I : Ideal R} [hI : I.IsMaximal] : IsClosed (I : Set R) :=
isClosed_of_closure_subset <| Eq.subset <| congr_arg ((↑) : Ideal R → Set R) hI.closure_eq
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/Connected.lean b/Mathlib/Analysis/NormedSpace/Connected.lean
index 64d98223dda5e..e14389a41de74 100644
--- a/Mathlib/Analysis/NormedSpace/Connected.lean
+++ b/Mathlib/Analysis/NormedSpace/Connected.lean
@@ -52,13 +52,11 @@ theorem Set.Countable.isPathConnected_compl_of_one_lt_rank
let c := (2 : ℝ)⁻¹ • (a + b)
let x := (2 : ℝ)⁻¹ • (b - a)
have Ia : c - x = a := by
- simp only [c, x, smul_add, smul_sub]
- abel_nf
- simp [← Int.cast_smul_eq_zsmul ℝ 2]
+ simp only [c, x]
+ module
have Ib : c + x = b := by
- simp only [c, x, smul_add, smul_sub]
- abel_nf
- simp [← Int.cast_smul_eq_zsmul ℝ 2]
+ simp only [c, x]
+ module
have x_ne_zero : x ≠ 0 := by simpa [x] using sub_ne_zero.2 hab.symm
obtain ⟨y, hy⟩ : ∃ y, LinearIndependent ℝ ![x, y] :=
exists_linearIndependent_pair_of_one_lt_rank h x_ne_zero
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/Extension.lean b/Mathlib/Analysis/NormedSpace/HahnBanach/Extension.lean
index b759259be866a..b158eee9c860d 100644
--- a/Mathlib/Analysis/NormedSpace/HahnBanach/Extension.lean
+++ b/Mathlib/Analysis/NormedSpace/HahnBanach/Extension.lean
@@ -62,13 +62,15 @@ section RCLike
open RCLike
-variable {𝕜 : Type*} [RCLike 𝕜] {E F : Type*}
+variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [IsRCLikeNormedField 𝕜] {E F : Type*}
[SeminormedAddCommGroup E] [NormedSpace 𝕜 E]
[NormedAddCommGroup F] [NormedSpace 𝕜 F]
-/-- **Hahn-Banach theorem** for continuous linear functions over `𝕜` satisfying `RCLike 𝕜`. -/
+/-- **Hahn-Banach theorem** for continuous linear functions over `𝕜`
+satisfying `IsRCLikeNormedField 𝕜`. -/
theorem exists_extension_norm_eq (p : Subspace 𝕜 E) (f : p →L[𝕜] 𝕜) :
∃ g : E →L[𝕜] 𝕜, (∀ x : p, g x = f x) ∧ ‖g‖ = ‖f‖ := by
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
letI : Module ℝ E := RestrictScalars.module ℝ 𝕜 E
letI : IsScalarTower ℝ 𝕜 E := RestrictScalars.isScalarTower _ _ _
letI : NormedSpace ℝ E := NormedSpace.restrictScalars _ 𝕜 _
@@ -105,12 +107,11 @@ theorem exists_extension_norm_eq (p : Subspace 𝕜 E) (f : p →L[𝕜] 𝕜) :
_ = ‖f‖ := by rw [reCLM_norm, one_mul]
· exact f.opNorm_le_bound g.extendTo𝕜.opNorm_nonneg fun x => h x ▸ g.extendTo𝕜.le_opNorm x
-open FiniteDimensional
+open Module
/-- Corollary of the **Hahn-Banach theorem**: if `f : p → F` is a continuous linear map
from a submodule of a normed space `E` over `𝕜`, `𝕜 = ℝ` or `𝕜 = ℂ`,
-with a finite dimensional range,
-then `f` admits an extension to a continuous linear map `E → F`.
+with a finite dimensional range, then `f` admits an extension to a continuous linear map `E → F`.
Note that contrary to the case `F = 𝕜`, see `exists_extension_norm_eq`,
we provide no estimates on the norm of the extension.
@@ -118,7 +119,8 @@ we provide no estimates on the norm of the extension.
lemma ContinuousLinearMap.exist_extension_of_finiteDimensional_range {p : Submodule 𝕜 E}
(f : p →L[𝕜] F) [FiniteDimensional 𝕜 (LinearMap.range f)] :
∃ g : E →L[𝕜] F, f = g.comp p.subtypeL := by
- set b := finBasis 𝕜 (LinearMap.range f)
+ letI : RCLike 𝕜 := IsRCLikeNormedField.rclike 𝕜
+ set b := Module.finBasis 𝕜 (LinearMap.range f)
set e := b.equivFunL
set fi := fun i ↦ (LinearMap.toContinuousLinearMap (b.coord i)).comp
(f.codRestrict _ <| LinearMap.mem_range_self _)
@@ -142,8 +144,6 @@ variable {E : Type u} [NormedAddCommGroup E] [NormedSpace 𝕜 E]
open ContinuousLinearEquiv Submodule
-open scoped Classical
-
theorem coord_norm' {x : E} (h : x ≠ 0) : ‖(‖x‖ : 𝕜) • coord 𝕜 x h‖ = 1 := by
#adaptation_note
/--
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/HahnBanach/Separation.lean b/Mathlib/Analysis/NormedSpace/HahnBanach/Separation.lean
index a054142703272..0cb8fc167da35 100644
--- a/Mathlib/Analysis/NormedSpace/HahnBanach/Separation.lean
+++ b/Mathlib/Analysis/NormedSpace/HahnBanach/Separation.lean
@@ -7,6 +7,7 @@ import Mathlib.Analysis.Convex.Cone.Extension
import Mathlib.Analysis.Convex.Gauge
import Mathlib.Topology.Algebra.Module.FiniteDimension
import Mathlib.Topology.Algebra.Module.LocallyConvex
+import Mathlib.Topology.Algebra.MulAction
import Mathlib.Analysis.RCLike.Basic
import Mathlib.Analysis.NormedSpace.Extend
@@ -210,10 +211,10 @@ end
namespace RCLike
-variable [RCLike 𝕜] [Module 𝕜 E] [ContinuousSMul 𝕜 E] [IsScalarTower ℝ 𝕜 E]
+variable [RCLike 𝕜] [Module 𝕜 E] [IsScalarTower ℝ 𝕜 E]
/--Real linear extension of continuous extension of `LinearMap.extendTo𝕜'` -/
-noncomputable def extendTo𝕜'ₗ : (E →L[ℝ] ℝ) →ₗ[ℝ] (E →L[𝕜] 𝕜) :=
+noncomputable def extendTo𝕜'ₗ [ContinuousConstSMul 𝕜 E]: (E →L[ℝ] ℝ) →ₗ[ℝ] (E →L[𝕜] 𝕜) :=
letI to𝕜 (fr : (E →L[ℝ] ℝ)) : (E →L[𝕜] 𝕜) :=
{ toLinearMap := LinearMap.extendTo𝕜' fr
cont := show Continuous fun x ↦ (fr x : 𝕜) - (I : 𝕜) * (fr ((I : 𝕜) • x) : 𝕜) by fun_prop }
@@ -223,16 +224,18 @@ noncomputable def extendTo𝕜'ₗ : (E →L[ℝ] ℝ) →ₗ[ℝ] (E →L[𝕜]
map_smul' := by intros; ext; simp [h, real_smul_eq_coe_mul]; ring }
@[simp]
-lemma re_extendTo𝕜'ₗ (g : E →L[ℝ] ℝ) (x : E) : re ((extendTo𝕜'ₗ g) x : 𝕜) = g x := by
+lemma re_extendTo𝕜'ₗ [ContinuousConstSMul 𝕜 E] (g : E →L[ℝ] ℝ) (x : E) : re ((extendTo𝕜'ₗ g) x : 𝕜)
+ = g x := by
have h g (x : E) : extendTo𝕜'ₗ g x = ((g x : 𝕜) - (I : 𝕜) * (g ((I : 𝕜) • x) : 𝕜)) := rfl
simp only [h , map_sub, ofReal_re, mul_re, I_re, zero_mul, ofReal_im, mul_zero,
sub_self, sub_zero]
-variable [TopologicalAddGroup E] [ContinuousSMul ℝ E]
+variable [TopologicalAddGroup E] [ContinuousSMul 𝕜 E]
theorem separate_convex_open_set {s : Set E}
(hs₀ : (0 : E) ∈ s) (hs₁ : Convex ℝ s) (hs₂ : IsOpen s) {x₀ : E} (hx₀ : x₀ ∉ s) :
∃ f : E →L[𝕜] 𝕜, re (f x₀) = 1 ∧ ∀ x ∈ s, re (f x) < 1 := by
+ have := IsScalarTower.continuousSMul (M := ℝ) (α := E) 𝕜
obtain ⟨g, hg⟩ := _root_.separate_convex_open_set hs₀ hs₁ hs₂ hx₀
use extendTo𝕜'ₗ g
simp only [re_extendTo𝕜'ₗ]
@@ -241,6 +244,7 @@ theorem separate_convex_open_set {s : Set E}
theorem geometric_hahn_banach_open (hs₁ : Convex ℝ s) (hs₂ : IsOpen s) (ht : Convex ℝ t)
(disj : Disjoint s t) : ∃ (f : E →L[𝕜] 𝕜) (u : ℝ), (∀ a ∈ s, re (f a) < u) ∧
∀ b ∈ t, u ≤ re (f b) := by
+ have := IsScalarTower.continuousSMul (M := ℝ) (α := E) 𝕜
obtain ⟨f, u, h⟩ := _root_.geometric_hahn_banach_open hs₁ hs₂ ht disj
use extendTo𝕜'ₗ f
simp only [re_extendTo𝕜'ₗ]
@@ -248,6 +252,7 @@ theorem geometric_hahn_banach_open (hs₁ : Convex ℝ s) (hs₂ : IsOpen s) (ht
theorem geometric_hahn_banach_open_point (hs₁ : Convex ℝ s) (hs₂ : IsOpen s) (disj : x ∉ s) :
∃ f : E →L[𝕜] 𝕜, ∀ a ∈ s, re (f a) < re (f x) := by
+ have := IsScalarTower.continuousSMul (M := ℝ) (α := E) 𝕜
obtain ⟨f, h⟩ := _root_.geometric_hahn_banach_open_point hs₁ hs₂ disj
use extendTo𝕜'ₗ f
simp only [re_extendTo𝕜'ₗ]
@@ -261,6 +266,7 @@ theorem geometric_hahn_banach_point_open (ht₁ : Convex ℝ t) (ht₂ : IsOpen
theorem geometric_hahn_banach_open_open (hs₁ : Convex ℝ s) (hs₂ : IsOpen s)
(ht₁ : Convex ℝ t) (ht₃ : IsOpen t) (disj : Disjoint s t) :
∃ (f : E →L[𝕜] 𝕜) (u : ℝ), (∀ a ∈ s, re (f a) < u) ∧ ∀ b ∈ t, u < re (f b) := by
+ have := IsScalarTower.continuousSMul (M := ℝ) (α := E) 𝕜
obtain ⟨f, u, h⟩ := _root_.geometric_hahn_banach_open_open hs₁ hs₂ ht₁ ht₃ disj
use extendTo𝕜'ₗ f
simp only [re_extendTo𝕜'ₗ]
@@ -271,6 +277,7 @@ variable [LocallyConvexSpace ℝ E]
theorem geometric_hahn_banach_compact_closed (hs₁ : Convex ℝ s) (hs₂ : IsCompact s)
(ht₁ : Convex ℝ t) (ht₂ : IsClosed t) (disj : Disjoint s t) :
∃ (f : E →L[𝕜] 𝕜) (u v : ℝ), (∀ a ∈ s, re (f a) < u) ∧ u < v ∧ ∀ b ∈ t, v < re (f b) := by
+ have := IsScalarTower.continuousSMul (M := ℝ) (α := E) 𝕜
obtain ⟨g, u, v, h1⟩ := _root_.geometric_hahn_banach_compact_closed hs₁ hs₂ ht₁ ht₂ disj
use extendTo𝕜'ₗ g
simp only [re_extendTo𝕜'ₗ, exists_and_left]
diff --git a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean
index b061d733ac3ff..2b7591e8a0600 100644
--- a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean
+++ b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean
@@ -74,18 +74,50 @@ We use the following type variables in this file:
universe u v v' wE wE₁ wE' wG wG'
-/-- Applying a multilinear map to a vector is continuous in both coordinates. -/
-theorem ContinuousMultilinearMap.continuous_eval {𝕜 ι : Type*} {E : ι → Type*} {F : Type*}
+section continuous_eval
+
+variable {𝕜 ι : Type*} {E : ι → Type*} {F : Type*}
[NormedField 𝕜] [Finite ι] [∀ i, SeminormedAddCommGroup (E i)] [∀ i, NormedSpace 𝕜 (E i)]
- [TopologicalSpace F] [AddCommGroup F] [TopologicalAddGroup F] [Module 𝕜 F] :
- 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.prod_map continuous_id) fun (f, x) ↦ f.cont.continuousAt
- exact ⟨ball m 1, NormedSpace.isVonNBounded_of_isBounded _ isBounded_ball,
- ball_mem_nhds _ one_pos⟩
+ [TopologicalSpace F] [AddCommGroup F] [TopologicalAddGroup F] [Module 𝕜 F]
+
+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
+
+variable {G : Type*} [AddCommGroup G] [TopologicalSpace G] [Module 𝕜 G] [ContinuousConstSMul 𝕜 F]
+ (f : G →L[𝕜] ContinuousMultilinearMap 𝕜 E F)
+
+lemma continuous_uncurry_of_multilinear :
+ 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 :=
+ f.continuous_uncurry_of_multilinear.continuousOn
+
+lemma continuousAt_uncurry_of_multilinear {x} :
+ ContinuousAt (fun (p : G × (Π i, E i)) ↦ f p.1 p.2) x :=
+ f.continuous_uncurry_of_multilinear.continuousAt
+
+lemma continuousWithinAt_uncurry_of_multilinear {s x} :
+ ContinuousWithinAt (fun (p : G × (Π i, E i)) ↦ f p.1 p.2) s x :=
+ f.continuous_uncurry_of_multilinear.continuousWithinAt
+
+end ContinuousLinearMap
+
+end continuous_eval
section Seminorm
@@ -189,7 +221,6 @@ theorem norm_image_sub_le_of_bound' [DecidableEq ι] {C : ℝ} (hC : 0 ≤ C)
rw [B, A, ← f.map_sub]
apply le_trans (H _)
gcongr with j
- · exact fun j _ => norm_nonneg _
by_cases h : j = i
· rw [h]
simp
@@ -276,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
@@ -340,7 +371,7 @@ theorem isLeast_opNorm : IsLeast {c : ℝ | 0 ≤ c ∧ ∀ m, ‖f m‖ ≤ c *
@[deprecated (since := "2024-02-02")] alias isLeast_op_norm := isLeast_opNorm
theorem opNorm_nonneg : 0 ≤ ‖f‖ :=
- Real.sInf_nonneg _ fun _ ⟨hx, _⟩ => hx
+ Real.sInf_nonneg fun _ ⟨hx, _⟩ => hx
@[deprecated (since := "2024-02-02")] alias op_norm_nonneg := opNorm_nonneg
@@ -391,7 +422,7 @@ theorem le_of_opNorm_le {C : ℝ} (h : ‖f‖ ≤ C) : ‖f m‖ ≤ C * ∏ i,
variable (f)
theorem ratio_le_opNorm : (‖f m‖ / ∏ i, ‖m i‖) ≤ ‖f‖ :=
- div_le_of_nonneg_of_le_mul (by positivity) (opNorm_nonneg _) (f.le_opNorm m)
+ div_le_of_le_mul₀ (by positivity) (opNorm_nonneg _) (f.le_opNorm m)
@[deprecated (since := "2024-02-02")] alias ratio_le_op_norm := ratio_le_opNorm
@@ -620,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
@@ -701,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 _) _)
@@ -748,7 +779,7 @@ theorem norm_mkPiAlgebraFin_succ_le : ‖ContinuousMultilinearMap.mkPiAlgebraFin
simp only [ContinuousMultilinearMap.mkPiAlgebraFin_apply, one_mul, List.ofFn_eq_map,
Fin.prod_univ_def, Multiset.map_coe, Multiset.prod_coe]
refine (List.norm_prod_le' ?_).trans_eq ?_
- · rw [Ne, List.map_eq_nil, List.finRange_eq_nil]
+ · rw [Ne, List.map_eq_nil_iff, List.finRange_eq_nil]
exact Nat.succ_ne_zero _
rw [List.map_map, Function.comp_def]
@@ -764,6 +795,12 @@ theorem norm_mkPiAlgebraFin_zero : ‖ContinuousMultilinearMap.mkPiAlgebraFin
· convert ratio_le_opNorm (ContinuousMultilinearMap.mkPiAlgebraFin 𝕜 0 A) fun _ => (1 : A)
simp
+theorem norm_mkPiAlgebraFin_le :
+ ‖ContinuousMultilinearMap.mkPiAlgebraFin 𝕜 n A‖ ≤ max 1 ‖(1 : A)‖ := by
+ cases n
+ · exact norm_mkPiAlgebraFin_zero.le.trans (le_max_right _ _)
+ · exact (norm_mkPiAlgebraFin_le_of_pos (Nat.zero_lt_succ _)).trans (le_max_left _ _)
+
@[simp]
theorem norm_mkPiAlgebraFin [NormOneClass A] :
‖ContinuousMultilinearMap.mkPiAlgebraFin 𝕜 n A‖ = 1 := by
@@ -839,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]
@@ -868,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
@@ -1241,7 +1278,6 @@ lemma norm_iteratedFDerivComponent_le {α : Type*} [Fintype α]
_ ≤ ‖f‖ * ∏ _i : {a : ι // a ∉ s}, ‖x‖ := by
gcongr
· exact MultilinearMap.mkContinuousMultilinear_norm_le _ (norm_nonneg _) _
- · exact fun _ _ ↦ norm_nonneg _
· exact norm_le_pi_norm _ _
_ = ‖f‖ * ‖x‖ ^ (Fintype.card {a : ι // a ∉ s}) := by rw [prod_const, card_univ]
_ = ‖f‖ * ‖x‖ ^ (Fintype.card ι - Fintype.card α) := by simp [Fintype.card_congr e]
diff --git a/Mathlib/Analysis/NormedSpace/Multilinear/Curry.lean b/Mathlib/Analysis/NormedSpace/Multilinear/Curry.lean
index 888c0aecdb488..3e81916160893 100644
--- a/Mathlib/Analysis/NormedSpace/Multilinear/Curry.lean
+++ b/Mathlib/Analysis/NormedSpace/Multilinear/Curry.lean
@@ -162,53 +162,49 @@ the space of continuous linear maps from `E 0` to the space of continuous multil
`continuousMultilinearCurryLeftEquiv 𝕜 E E₂`. The algebraic version (without topology) is given
in `multilinearCurryLeftEquiv 𝕜 E E₂`.
-The direct and inverse maps are given by `f.uncurryLeft` and `f.curryLeft`. Use these
+The direct and inverse maps are given by `f.curryLeft` and `f.uncurryLeft`. Use these
unless you need the full framework of linear isometric equivs. -/
def continuousMultilinearCurryLeftEquiv :
- (Ei 0 →L[𝕜] ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei i.succ) G) ≃ₗᵢ[𝕜]
- ContinuousMultilinearMap 𝕜 Ei G :=
+ ContinuousMultilinearMap 𝕜 Ei G ≃ₗᵢ[𝕜]
+ Ei 0 →L[𝕜] ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei i.succ) G :=
LinearIsometryEquiv.ofBounds
- { toFun := ContinuousLinearMap.uncurryLeft
- map_add' := fun f₁ f₂ => by
- ext m
- rfl
- map_smul' := fun c f => by
- ext m
- rfl
- invFun := ContinuousMultilinearMap.curryLeft
- left_inv := ContinuousLinearMap.curry_uncurryLeft
- right_inv := ContinuousMultilinearMap.uncurry_curryLeft }
+ { toFun := ContinuousMultilinearMap.curryLeft
+ map_add' := fun _ _ => rfl
+ map_smul' := fun _ _ => rfl
+ invFun := ContinuousLinearMap.uncurryLeft
+ left_inv := ContinuousMultilinearMap.uncurry_curryLeft
+ right_inv := ContinuousLinearMap.curry_uncurryLeft }
(fun f => by
simp only [LinearEquiv.coe_mk]
- exact MultilinearMap.mkContinuous_norm_le _ (norm_nonneg f) _)
+ exact LinearMap.mkContinuous_norm_le _ (norm_nonneg f) _)
(fun f => by
simp only [LinearEquiv.coe_symm_mk]
- exact LinearMap.mkContinuous_norm_le _ (norm_nonneg f) _)
+ exact MultilinearMap.mkContinuous_norm_le _ (norm_nonneg f) _)
variable {𝕜 Ei G}
@[simp]
theorem continuousMultilinearCurryLeftEquiv_apply
- (f : Ei 0 →L[𝕜] ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei i.succ) G) (v : ∀ i, Ei i) :
- continuousMultilinearCurryLeftEquiv 𝕜 Ei G f v = f (v 0) (tail v) :=
+ (f : ContinuousMultilinearMap 𝕜 Ei G) (x : Ei 0) (v : Π i : Fin n, Ei i.succ) :
+ continuousMultilinearCurryLeftEquiv 𝕜 Ei G f x v = f (cons x v) :=
rfl
@[simp]
-theorem continuousMultilinearCurryLeftEquiv_symm_apply (f : ContinuousMultilinearMap 𝕜 Ei G)
- (x : Ei 0) (v : ∀ i : Fin n, Ei i.succ) :
- (continuousMultilinearCurryLeftEquiv 𝕜 Ei G).symm f x v = f (cons x v) :=
+theorem continuousMultilinearCurryLeftEquiv_symm_apply
+ (f : Ei 0 →L[𝕜] ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei i.succ) G) (v : Π i, Ei i) :
+ (continuousMultilinearCurryLeftEquiv 𝕜 Ei G).symm f v = f (v 0) (tail v) :=
rfl
@[simp]
theorem ContinuousMultilinearMap.curryLeft_norm (f : ContinuousMultilinearMap 𝕜 Ei G) :
‖f.curryLeft‖ = ‖f‖ :=
- (continuousMultilinearCurryLeftEquiv 𝕜 Ei G).symm.norm_map f
+ (continuousMultilinearCurryLeftEquiv 𝕜 Ei G).norm_map f
@[simp]
theorem ContinuousLinearMap.uncurryLeft_norm
(f : Ei 0 →L[𝕜] ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei i.succ) G) :
‖f.uncurryLeft‖ = ‖f‖ :=
- (continuousMultilinearCurryLeftEquiv 𝕜 Ei G).norm_map f
+ (continuousMultilinearCurryLeftEquiv 𝕜 Ei G).symm.norm_map f
/-! #### Right currying -/
@@ -279,27 +275,25 @@ space of continuous linear maps on `Ei (last n)`, by separating the last variabl
isomorphism as a continuous linear equiv in `continuousMultilinearCurryRightEquiv 𝕜 Ei G`.
The algebraic version (without topology) is given in `multilinearCurryRightEquiv 𝕜 Ei G`.
-The direct and inverse maps are given by `f.uncurryRight` and `f.curryRight`. Use these
+The direct and inverse maps are given by `f.curryRight` and `f.uncurryRight`. Use these
unless you need the full framework of linear isometric equivs.
-/
def continuousMultilinearCurryRightEquiv :
- ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei <| castSucc i) (Ei (last n) →L[𝕜] G) ≃ₗᵢ[𝕜]
- ContinuousMultilinearMap 𝕜 Ei G :=
+ ContinuousMultilinearMap 𝕜 Ei G ≃ₗᵢ[𝕜]
+ ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei <| castSucc i) (Ei (last n) →L[𝕜] G) :=
LinearIsometryEquiv.ofBounds
- { toFun := ContinuousMultilinearMap.uncurryRight
- map_add' := fun f₁ f₂ => by
- ext m
- rfl
- map_smul' := fun c f => by
- ext m
- rfl
- invFun := ContinuousMultilinearMap.curryRight
- left_inv := ContinuousMultilinearMap.curry_uncurryRight
- right_inv := ContinuousMultilinearMap.uncurry_curryRight } (fun f => by
- simp only [uncurryRight, LinearEquiv.coe_mk]
- exact MultilinearMap.mkContinuous_norm_le _ (norm_nonneg f) _) fun f => by
- simp only [curryRight, LinearEquiv.coe_symm_mk]
- exact MultilinearMap.mkContinuous_norm_le _ (norm_nonneg f) _
+ { toFun := ContinuousMultilinearMap.curryRight
+ map_add' := fun _ _ => rfl
+ map_smul' := fun _ _ => rfl
+ invFun := ContinuousMultilinearMap.uncurryRight
+ left_inv := ContinuousMultilinearMap.uncurry_curryRight
+ right_inv := ContinuousMultilinearMap.curry_uncurryRight }
+ (fun f => by
+ simp only [curryRight, LinearEquiv.coe_mk]
+ exact MultilinearMap.mkContinuous_norm_le _ (norm_nonneg f) _)
+ (fun f => by
+ simp only [uncurryRight, LinearEquiv.coe_symm_mk]
+ exact MultilinearMap.mkContinuous_norm_le _ (norm_nonneg f) _)
variable (n G')
@@ -310,47 +304,48 @@ isomorphism as a continuous linear equiv in `continuousMultilinearCurryRightEqui
For a version allowing dependent types, see `continuousMultilinearCurryRightEquiv`. When there
are no dependent types, use the primed version as it helps Lean a lot for unification.
-The direct and inverse maps are given by `f.uncurryRight` and `f.curryRight`. Use these
+The direct and inverse maps are given by `f.curryRight` and `f.uncurryRight`. Use these
unless you need the full framework of linear isometric equivs. -/
-def continuousMultilinearCurryRightEquiv' : (G[×n]→L[𝕜] G →L[𝕜] G') ≃ₗᵢ[𝕜] G[×n.succ]→L[𝕜] G' :=
+def continuousMultilinearCurryRightEquiv' : (G[×n.succ]→L[𝕜] G') ≃ₗᵢ[𝕜] G[×n]→L[𝕜] G →L[𝕜] G' :=
continuousMultilinearCurryRightEquiv 𝕜 (fun _ => G) G'
variable {n 𝕜 G Ei G'}
@[simp]
theorem continuousMultilinearCurryRightEquiv_apply
- (f : ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei <| castSucc i) (Ei (last n) →L[𝕜] G))
- (v : ∀ i, Ei i) : (continuousMultilinearCurryRightEquiv 𝕜 Ei G) f v = f (init v) (v (last n)) :=
+ (f : ContinuousMultilinearMap 𝕜 Ei G) (v : Π i : Fin n, Ei <| castSucc i) (x : Ei (last n)) :
+ continuousMultilinearCurryRightEquiv 𝕜 Ei G f v x = f (snoc v x) :=
rfl
@[simp]
-theorem continuousMultilinearCurryRightEquiv_symm_apply (f : ContinuousMultilinearMap 𝕜 Ei G)
- (v : ∀ i : Fin n, Ei <| castSucc i) (x : Ei (last n)) :
- (continuousMultilinearCurryRightEquiv 𝕜 Ei G).symm f v x = f (snoc v x) :=
+theorem continuousMultilinearCurryRightEquiv_symm_apply
+ (f : ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei <| castSucc i) (Ei (last n) →L[𝕜] G))
+ (v : Π i, Ei i) :
+ (continuousMultilinearCurryRightEquiv 𝕜 Ei G).symm f v = f (init v) (v (last n)) :=
rfl
@[simp]
-theorem continuousMultilinearCurryRightEquiv_apply' (f : G[×n]→L[𝕜] G →L[𝕜] G')
- (v : Fin (n + 1) → G) :
- continuousMultilinearCurryRightEquiv' 𝕜 n G G' f v = f (init v) (v (last n)) :=
+theorem continuousMultilinearCurryRightEquiv_apply'
+ (f : G[×n.succ]→L[𝕜] G') (v : Fin n → G) (x : G) :
+ continuousMultilinearCurryRightEquiv' 𝕜 n G G' f v x = f (snoc v x) :=
rfl
@[simp]
-theorem continuousMultilinearCurryRightEquiv_symm_apply' (f : G[×n.succ]→L[𝕜] G')
- (v : Fin n → G) (x : G) :
- (continuousMultilinearCurryRightEquiv' 𝕜 n G G').symm f v x = f (snoc v x) :=
+theorem continuousMultilinearCurryRightEquiv_symm_apply'
+ (f : G[×n]→L[𝕜] G →L[𝕜] G') (v : Fin (n + 1) → G) :
+ (continuousMultilinearCurryRightEquiv' 𝕜 n G G').symm f v = f (init v) (v (last n)) :=
rfl
@[simp]
theorem ContinuousMultilinearMap.curryRight_norm (f : ContinuousMultilinearMap 𝕜 Ei G) :
‖f.curryRight‖ = ‖f‖ :=
- (continuousMultilinearCurryRightEquiv 𝕜 Ei G).symm.norm_map f
+ (continuousMultilinearCurryRightEquiv 𝕜 Ei G).norm_map f
@[simp]
theorem ContinuousMultilinearMap.uncurryRight_norm
(f : ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei <| castSucc i) (Ei (last n) →L[𝕜] G)) :
‖f.uncurryRight‖ = ‖f‖ :=
- (continuousMultilinearCurryRightEquiv 𝕜 Ei G).norm_map f
+ (continuousMultilinearCurryRightEquiv 𝕜 Ei G).symm.norm_map f
/-!
#### Currying with `0` variables
@@ -365,63 +360,57 @@ derivatives, we register this isomorphism. -/
section
/-- Associating to a continuous multilinear map in `0` variables the unique value it takes. -/
-def ContinuousMultilinearMap.uncurry0 (f : ContinuousMultilinearMap 𝕜 (fun _ : Fin 0 => G) G') :
+def ContinuousMultilinearMap.curry0 (f : ContinuousMultilinearMap 𝕜 (fun _ : Fin 0 => G) G') :
G' :=
f 0
-variable (𝕜 G)
-
+variable (𝕜 G) in
/-- Associating to an element `x` of a vector space `E₂` the continuous multilinear map in `0`
variables taking the (unique) value `x` -/
-def ContinuousMultilinearMap.curry0 (x : G') : G[×0]→L[𝕜] G' :=
+def ContinuousMultilinearMap.uncurry0 (x : G') : G[×0]→L[𝕜] G' :=
ContinuousMultilinearMap.constOfIsEmpty 𝕜 _ x
-variable {G}
-
+variable (𝕜) in
@[simp]
-theorem ContinuousMultilinearMap.curry0_apply (x : G') (m : Fin 0 → G) :
- ContinuousMultilinearMap.curry0 𝕜 G x m = x :=
+theorem ContinuousMultilinearMap.uncurry0_apply (x : G') (m : Fin 0 → G) :
+ ContinuousMultilinearMap.uncurry0 𝕜 G x m = x :=
rfl
-variable {𝕜}
-
@[simp]
-theorem ContinuousMultilinearMap.uncurry0_apply (f : G[×0]→L[𝕜] G') : f.uncurry0 = f 0 :=
+theorem ContinuousMultilinearMap.curry0_apply (f : G[×0]→L[𝕜] G') : f.curry0 = f 0 :=
rfl
@[simp]
-theorem ContinuousMultilinearMap.apply_zero_curry0 (f : G[×0]→L[𝕜] G') {x : Fin 0 → G} :
- ContinuousMultilinearMap.curry0 𝕜 G (f x) = f := by
+theorem ContinuousMultilinearMap.apply_zero_uncurry0 (f : G[×0]→L[𝕜] G') {x : Fin 0 → G} :
+ ContinuousMultilinearMap.uncurry0 𝕜 G (f x) = f := by
ext m
simp [Subsingleton.elim x m]
theorem ContinuousMultilinearMap.uncurry0_curry0 (f : G[×0]→L[𝕜] G') :
- ContinuousMultilinearMap.curry0 𝕜 G f.uncurry0 = f := by simp
-
-variable (𝕜 G)
+ ContinuousMultilinearMap.uncurry0 𝕜 G f.curry0 = f := by simp
+variable (𝕜 G) in
theorem ContinuousMultilinearMap.curry0_uncurry0 (x : G') :
- (ContinuousMultilinearMap.curry0 𝕜 G x).uncurry0 = x :=
+ (ContinuousMultilinearMap.uncurry0 𝕜 G x).curry0 = x :=
rfl
+variable (𝕜 G) in
@[simp]
-theorem ContinuousMultilinearMap.curry0_norm (x : G') :
- ‖ContinuousMultilinearMap.curry0 𝕜 G x‖ = ‖x‖ :=
+theorem ContinuousMultilinearMap.uncurry0_norm (x : G') :
+ ‖ContinuousMultilinearMap.uncurry0 𝕜 G x‖ = ‖x‖ :=
norm_constOfIsEmpty _ _ _
-variable {𝕜 G}
-
@[simp]
theorem ContinuousMultilinearMap.fin0_apply_norm (f : G[×0]→L[𝕜] G') {x : Fin 0 → G} :
‖f x‖ = ‖f‖ := by
obtain rfl : x = 0 := Subsingleton.elim _ _
refine le_antisymm (by simpa using f.le_opNorm 0) ?_
- have : ‖ContinuousMultilinearMap.curry0 𝕜 G f.uncurry0‖ ≤ ‖f.uncurry0‖ :=
+ have : ‖ContinuousMultilinearMap.uncurry0 𝕜 G f.curry0‖ ≤ ‖f.curry0‖ :=
ContinuousMultilinearMap.opNorm_le_bound _ (norm_nonneg _) fun m => by
- simp [-ContinuousMultilinearMap.apply_zero_curry0]
+ simp [-ContinuousMultilinearMap.apply_zero_uncurry0]
simpa [-Matrix.zero_empty] using this
-theorem ContinuousMultilinearMap.uncurry0_norm (f : G[×0]→L[𝕜] G') : ‖f.uncurry0‖ = ‖f‖ := by simp
+theorem ContinuousMultilinearMap.curry0_norm (f : G[×0]→L[𝕜] G') : ‖f.curry0‖ = ‖f‖ := by simp
variable (𝕜 G G')
@@ -431,13 +420,13 @@ maps in `0` variables with values in this normed space.
The direct and inverse maps are `uncurry0` and `curry0`. Use these unless you need the full
framework of linear isometric equivs. -/
def continuousMultilinearCurryFin0 : (G[×0]→L[𝕜] G') ≃ₗᵢ[𝕜] G' where
- toFun f := ContinuousMultilinearMap.uncurry0 f
- invFun f := ContinuousMultilinearMap.curry0 𝕜 G f
+ toFun f := ContinuousMultilinearMap.curry0 f
+ invFun f := ContinuousMultilinearMap.uncurry0 𝕜 G f
map_add' _ _ := rfl
map_smul' _ _ := rfl
left_inv := ContinuousMultilinearMap.uncurry0_curry0
right_inv := ContinuousMultilinearMap.curry0_uncurry0 𝕜 G
- norm_map' := ContinuousMultilinearMap.uncurry0_norm
+ norm_map' := ContinuousMultilinearMap.curry0_norm
variable {𝕜 G G'}
@@ -461,7 +450,7 @@ variable (𝕜 G G')
/-- Continuous multilinear maps from `G^1` to `G'` are isomorphic with continuous linear maps from
`G` to `G'`. -/
def continuousMultilinearCurryFin1 : (G[×1]→L[𝕜] G') ≃ₗᵢ[𝕜] G →L[𝕜] G' :=
- (continuousMultilinearCurryRightEquiv 𝕜 (fun _ : Fin 1 => G) G').symm.trans
+ (continuousMultilinearCurryRightEquiv 𝕜 (fun _ : Fin 1 => G) G').trans
(continuousMultilinearCurryFin0 𝕜 G (G →L[𝕜] G'))
variable {𝕜 G G'}
@@ -571,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')
@@ -579,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 ?_
@@ -614,3 +601,58 @@ theorem curryFinFinset_apply_const (hk : s.card = k) (hl : sᶜ.card = l) (f : G
end
end ContinuousMultilinearMap
+
+namespace ContinuousLinearMap
+
+variable {F G : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
+ [NormedAddCommGroup G] [NormedSpace 𝕜 G]
+
+/-- Given a linear map into continuous multilinear maps
+`B : G →L[𝕜] ContinuousMultilinearMap 𝕜 E F`, one can not always uncurry it as `G` and `E` might
+live in a different universe. However, one can always lift it to a continuous multilinear map
+on `(G × (Π i, E i)) ^ (1 + n)`, which maps `(v_0, ..., v_n)` to `B (g_0) (u_1, ..., u_n)` where
+`g_0` is the `G`-coordinate of `v_0` and `u_i` is the `E_i` coordinate of `v_i`. -/
+noncomputable def continuousMultilinearMapOption (B : G →L[𝕜] ContinuousMultilinearMap 𝕜 E F) :
+ ContinuousMultilinearMap 𝕜 (fun (_ : Option ι) ↦ (G × (Π i, E i))) F :=
+ MultilinearMap.mkContinuous
+ { toFun := fun p ↦ B (p none).1 (fun i ↦ (p i).2 i)
+ map_add' := by
+ intro inst v j x y
+ match j with
+ | none => simp
+ | some j =>
+ classical
+ have B z : (fun i ↦ (Function.update v (some j) z (some i)).2 i) =
+ Function.update (fun (i : ι) ↦ (v i).2 i) j (z.2 j) := by
+ ext i
+ rcases eq_or_ne i j with rfl | hij
+ · simp
+ · simp [hij]
+ simp [B]
+ map_smul' := by
+ intro inst v j c x
+ match j with
+ | none => simp
+ | some j =>
+ classical
+ have B z : (fun i ↦ (Function.update v (some j) z (some i)).2 i) =
+ Function.update (fun (i : ι) ↦ (v i).2 i) j (z.2 j) := by
+ ext i
+ rcases eq_or_ne i j with rfl | hij
+ · simp
+ · simp [hij]
+ simp [B] } (‖B‖) <| by
+ intro b
+ simp only [MultilinearMap.coe_mk, Fintype.prod_option]
+ apply (ContinuousMultilinearMap.le_opNorm _ _).trans
+ rw [← mul_assoc]
+ gcongr with i _
+ · apply (B.le_opNorm _).trans
+ gcongr
+ exact norm_fst_le _
+ · exact (norm_le_pi_norm _ _).trans (norm_snd_le _)
+
+lemma continuousMultilinearMapOption_apply_eq_self (B : G →L[𝕜] ContinuousMultilinearMap 𝕜 E F)
+ (a : G) (v : Π i, E i) : B.continuousMultilinearMapOption (fun _ ↦ (a, v)) = B a v := rfl
+
+end ContinuousLinearMap
diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm/Basic.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/Basic.lean
index 7c3c4398246cc..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‖)
@@ -174,7 +174,7 @@ theorem opNorm_neg (f : E →SL[σ₁₂] F) : ‖-f‖ = ‖f‖ := by simp onl
@[deprecated (since := "2024-02-02")] alias op_norm_neg := opNorm_neg
theorem opNorm_nonneg (f : E →SL[σ₁₂] F) : 0 ≤ ‖f‖ :=
- Real.sInf_nonneg _ fun _ ↦ And.left
+ Real.sInf_nonneg fun _ ↦ And.left
@[deprecated (since := "2024-02-02")] alias op_norm_nonneg := opNorm_nonneg
@@ -227,7 +227,7 @@ theorem opNorm_le_iff {f : E →SL[σ₁₂] F} {M : ℝ} (hMp : 0 ≤ M) :
@[deprecated (since := "2024-02-02")] alias op_norm_le_iff := opNorm_le_iff
theorem ratio_le_opNorm : ‖f x‖ / ‖x‖ ≤ ‖f‖ :=
- div_le_of_nonneg_of_le_mul (norm_nonneg _) f.opNorm_nonneg (le_opNorm _ _)
+ div_le_of_le_mul₀ (norm_nonneg _) f.opNorm_nonneg (le_opNorm _ _)
@[deprecated (since := "2024-02-02")] alias ratio_le_op_norm := ratio_le_opNorm
@@ -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/Bilinear.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean
index 1d70cb3750159..61f5199b50531 100644
--- a/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean
+++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean
@@ -409,6 +409,54 @@ theorem map_add_add (f : E →L[𝕜] Fₗ →L[𝕜] Gₗ) (x x' : E) (y y' : F
simp only [map_add, add_apply, coe_deriv₂, add_assoc]
abel
+/-- The norm of the tensor product of a scalar linear map and of an element of a normed space
+is the product of the norms. -/
+@[simp]
+theorem norm_smulRight_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRight c f‖ = ‖c‖ * ‖f‖ := by
+ refine le_antisymm ?_ ?_
+ · refine opNorm_le_bound _ (mul_nonneg (norm_nonneg _) (norm_nonneg _)) fun x => ?_
+ calc
+ ‖c x • f‖ = ‖c x‖ * ‖f‖ := norm_smul _ _
+ _ ≤ ‖c‖ * ‖x‖ * ‖f‖ := mul_le_mul_of_nonneg_right (le_opNorm _ _) (norm_nonneg _)
+ _ = ‖c‖ * ‖f‖ * ‖x‖ := by ring
+ · obtain hf | hf := (norm_nonneg f).eq_or_gt
+ · simp [hf]
+ · rw [← le_div_iff₀ hf]
+ refine opNorm_le_bound _ (div_nonneg (norm_nonneg _) (norm_nonneg f)) fun x => ?_
+ rw [div_mul_eq_mul_div, le_div_iff₀ hf]
+ calc
+ ‖c x‖ * ‖f‖ = ‖c x • f‖ := (norm_smul _ _).symm
+ _ = ‖smulRight c f x‖ := rfl
+ _ ≤ ‖smulRight c f‖ * ‖x‖ := le_opNorm _ _
+
+/-- The non-negative norm of the tensor product of a scalar linear map and of an element of a normed
+space is the product of the non-negative norms. -/
+@[simp]
+theorem nnnorm_smulRight_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRight c f‖₊ = ‖c‖₊ * ‖f‖₊ :=
+ NNReal.eq <| c.norm_smulRight_apply f
+
+variable (𝕜 E Fₗ) in
+/-- `ContinuousLinearMap.smulRight` as a continuous trilinear map:
+`smulRightL (c : E →L[𝕜] 𝕜) (f : F) (x : E) = c x • f`. -/
+def smulRightL : (E →L[𝕜] 𝕜) →L[𝕜] Fₗ →L[𝕜] E →L[𝕜] Fₗ :=
+ LinearMap.mkContinuous₂
+ { toFun := smulRightₗ
+ map_add' := fun c₁ c₂ => by
+ ext x
+ simp only [add_smul, coe_smulRightₗ, add_apply, smulRight_apply, LinearMap.add_apply]
+ map_smul' := fun m c => by
+ ext x
+ dsimp
+ rw [smul_smul] }
+ 1 fun c x => by
+ simp only [coe_smulRightₗ, one_mul, norm_smulRight_apply, LinearMap.coe_mk, AddHom.coe_mk,
+ le_refl]
+
+
+@[simp]
+theorem norm_smulRightL_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRightL 𝕜 E Fₗ c f‖ = ‖c‖ * ‖f‖ :=
+ norm_smulRight_apply c f
+
end ContinuousLinearMap
end SemiNormed
diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm/Completeness.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/Completeness.lean
index b4e87ed65eb32..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ₗ`. -/
@@ -190,7 +189,7 @@ def extend : Fₗ →SL[σ₁₂] F :=
have cont := (uniformContinuous_uniformly_extend h_e h_dense f.uniformContinuous).continuous
-- extension of `f` agrees with `f` on the domain of the embedding `e`
have eq := uniformly_extend_of_ind h_e h_dense f.uniformContinuous
- { toFun := (h_e.denseInducing h_dense).extend f
+ { toFun := (h_e.isDenseInducing h_dense).extend f
map_add' := by
refine h_dense.induction_on₂ ?_ ?_
· exact isClosed_eq (cont.comp continuous_add)
@@ -208,10 +207,10 @@ def extend : Fₗ →SL[σ₁₂] F :=
exact ContinuousLinearMap.map_smulₛₗ _ _ _
cont }
--- Porting note: previously `(h_e.denseInducing h_dense)` was inferred.
+-- Porting note: previously `(h_e.isDenseInducing h_dense)` was inferred.
@[simp]
theorem extend_eq (x : E) : extend f e h_dense h_e (e x) = f x :=
- DenseInducing.extend_eq (h_e.denseInducing h_dense) f.cont _
+ IsDenseInducing.extend_eq (h_e.isDenseInducing h_dense) f.cont _
theorem extend_unique (g : Fₗ →SL[σ₁₂] F) (H : g.comp e = f) : extend f e h_dense h_e = g :=
ContinuousLinearMap.coeFn_injective <|
@@ -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 (uniformEmbedding_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/NNNorm.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/NNNorm.lean
index 7461f70c18dfc..020de596c8f44 100644
--- a/Mathlib/Analysis/NormedSpace/OperatorNorm/NNNorm.lean
+++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/NNNorm.lean
@@ -156,7 +156,7 @@ theorem exists_lt_apply_of_lt_opNNNorm {𝕜 𝕜₂ E F : Type*} [NormedAddComm
obtain ⟨k, hk₁, hk₂⟩ := NormedField.exists_lt_nnnorm_lt 𝕜 hy
refine ⟨k • y, (nnnorm_smul k y).symm ▸ (NNReal.lt_inv_iff_mul_lt hy').1 hk₂, ?_⟩
have : ‖σ₁₂ k‖₊ = ‖k‖₊ := Subtype.ext RingHomIsometric.is_iso
- rwa [map_smulₛₗ f, nnnorm_smul, ← NNReal.div_lt_iff hfy, div_eq_mul_inv, this]
+ rwa [map_smulₛₗ f, nnnorm_smul, ← div_lt_iff₀ hfy.bot_lt, div_eq_mul_inv, this]
@[deprecated (since := "2024-02-02")]
alias exists_lt_apply_of_lt_op_nnnorm := exists_lt_apply_of_lt_opNNNorm
diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean
index d07b5ac33cae4..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
@@ -165,6 +166,15 @@ theorem norm_toContinuousLinearMap_comp [RingHomIsometric σ₁₂] (f : F →
opNorm_ext (f.toContinuousLinearMap.comp g) g fun x => by
simp only [norm_map, coe_toContinuousLinearMap, coe_comp', Function.comp_apply]
+/-- Composing on the left with a linear isometry gives a linear isometry between spaces of
+continuous linear maps. -/
+def postcomp [RingHomIsometric σ₁₂] [RingHomIsometric σ₁₃] (a : F →ₛₗᵢ[σ₂₃] G) :
+ (E →SL[σ₁₂] F) →ₛₗᵢ[σ₂₃] (E →SL[σ₁₃] G) where
+ toFun f := a.toContinuousLinearMap.comp f
+ map_add' f g := by simp
+ map_smul' c f := by simp
+ norm_map' f := by simp [a.norm_toContinuousLinearMap_comp]
+
end LinearIsometry
end
@@ -172,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'] {σ₂' : 𝕜₂' →+* 𝕜₂} {σ₂'' : 𝕜₂ →+* 𝕜₂'} {σ₂₃' : 𝕜₂' →+* 𝕜₃}
@@ -200,58 +210,6 @@ theorem opNorm_comp_linearIsometryEquiv (f : F →SL[σ₂₃] G) (g : F' ≃ₛ
@[deprecated (since := "2024-02-02")]
alias op_norm_comp_linearIsometryEquiv := opNorm_comp_linearIsometryEquiv
-/-- The norm of the tensor product of a scalar linear map and of an element of a normed space
-is the product of the norms. -/
-@[simp]
-theorem norm_smulRight_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRight c f‖ = ‖c‖ * ‖f‖ := by
- refine le_antisymm ?_ ?_
- · refine opNorm_le_bound _ (mul_nonneg (norm_nonneg _) (norm_nonneg _)) fun x => ?_
- calc
- ‖c x • f‖ = ‖c x‖ * ‖f‖ := norm_smul _ _
- _ ≤ ‖c‖ * ‖x‖ * ‖f‖ := mul_le_mul_of_nonneg_right (le_opNorm _ _) (norm_nonneg _)
- _ = ‖c‖ * ‖f‖ * ‖x‖ := by ring
- · by_cases h : f = 0
- · simp [h]
- · have : 0 < ‖f‖ := norm_pos_iff.2 h
- rw [← le_div_iff₀ this]
- refine opNorm_le_bound _ (div_nonneg (norm_nonneg _) (norm_nonneg f)) fun x => ?_
- rw [div_mul_eq_mul_div, le_div_iff₀ this]
- calc
- ‖c x‖ * ‖f‖ = ‖c x • f‖ := (norm_smul _ _).symm
- _ = ‖smulRight c f x‖ := rfl
- _ ≤ ‖smulRight c f‖ * ‖x‖ := le_opNorm _ _
-
-/-- The non-negative norm of the tensor product of a scalar linear map and of an element of a normed
-space is the product of the non-negative norms. -/
-@[simp]
-theorem nnnorm_smulRight_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRight c f‖₊ = ‖c‖₊ * ‖f‖₊ :=
- NNReal.eq <| c.norm_smulRight_apply f
-
-variable (𝕜 E Fₗ)
-
-
-/-- `ContinuousLinearMap.smulRight` as a continuous trilinear map:
-`smulRightL (c : E →L[𝕜] 𝕜) (f : F) (x : E) = c x • f`. -/
-def smulRightL : (E →L[𝕜] 𝕜) →L[𝕜] Fₗ →L[𝕜] E →L[𝕜] Fₗ :=
- LinearMap.mkContinuous₂
- { toFun := smulRightₗ
- map_add' := fun c₁ c₂ => by
- ext x
- simp only [add_smul, coe_smulRightₗ, add_apply, smulRight_apply, LinearMap.add_apply]
- map_smul' := fun m c => by
- ext x
- dsimp
- rw [smul_smul] }
- 1 fun c x => by
- simp only [coe_smulRightₗ, one_mul, norm_smulRight_apply, LinearMap.coe_mk, AddHom.coe_mk,
- le_refl]
-
-variable {𝕜 E Fₗ}
-
-@[simp]
-theorem norm_smulRightL_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRightL 𝕜 E Fₗ c f‖ = ‖c‖ * ‖f‖ :=
- norm_smulRight_apply c f
-
@[simp]
theorem norm_smulRightL (c : E →L[𝕜] 𝕜) [Nontrivial Fₗ] : ‖smulRightL 𝕜 E Fₗ c‖ = ‖c‖ :=
ContinuousLinearMap.homothety_norm _ c.norm_smulRight_apply
@@ -272,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
@@ -282,7 +239,7 @@ end Submodule
namespace ContinuousLinearEquiv
-variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂] [NontriviallyNormedField 𝕜₃]
+variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂]
[NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] {σ₁₂ : 𝕜 →+* 𝕜₂} {σ₂₁ : 𝕜₂ →+* 𝕜} [RingHomInvPair σ₁₂ σ₂₁]
[RingHomInvPair σ₂₁ σ₁₂]
@@ -365,33 +322,30 @@ protected theorem NormedSpace.equicontinuous_TFAE : List.TFAE
BddAbove (Set.range (‖f ·‖)),
(⨆ i, (‖f i‖₊ : ENNReal)) < ⊤ ] := by
-- `1 ↔ 2 ↔ 3` follows from `uniformEquicontinuous_of_equicontinuousAt_zero`
- tfae_have 1 → 3
- · exact uniformEquicontinuous_of_equicontinuousAt_zero f
- tfae_have 3 → 2
- · exact UniformEquicontinuous.equicontinuous
- tfae_have 2 → 1
- · exact fun H ↦ H 0
+ tfae_have 1 → 3 := uniformEquicontinuous_of_equicontinuousAt_zero f
+ tfae_have 3 → 2 := UniformEquicontinuous.equicontinuous
+ tfae_have 2 → 1 := fun H ↦ H 0
-- `4 ↔ 5 ↔ 6 ↔ 7 ↔ 8 ↔ 9` is morally trivial, we just have to use a lot of rewriting
-- and `congr` lemmas
- tfae_have 4 ↔ 5
- · rw [exists_ge_and_iff_exists]
+ tfae_have 4 ↔ 5 := by
+ rw [exists_ge_and_iff_exists]
exact fun C₁ C₂ hC ↦ forall₂_imp fun i x ↦ le_trans' <| by gcongr
- tfae_have 5 ↔ 7
- · refine exists_congr (fun C ↦ and_congr_right fun hC ↦ forall_congr' fun i ↦ ?_)
+ tfae_have 5 ↔ 7 := by
+ refine exists_congr (fun C ↦ and_congr_right fun hC ↦ forall_congr' fun i ↦ ?_)
rw [ContinuousLinearMap.opNorm_le_iff hC]
- tfae_have 7 ↔ 8
- · simp_rw [bddAbove_iff_exists_ge (0 : ℝ), Set.forall_mem_range]
- tfae_have 6 ↔ 8
- · simp_rw [bddAbove_def, Set.forall_mem_range]
- tfae_have 8 ↔ 9
- · rw [ENNReal.iSup_coe_lt_top, ← NNReal.bddAbove_coe, ← Set.range_comp]
+ tfae_have 7 ↔ 8 := by
+ simp_rw [bddAbove_iff_exists_ge (0 : ℝ), Set.forall_mem_range]
+ tfae_have 6 ↔ 8 := by
+ simp_rw [bddAbove_def, Set.forall_mem_range]
+ tfae_have 8 ↔ 9 := by
+ rw [ENNReal.iSup_coe_lt_top, ← NNReal.bddAbove_coe, ← Set.range_comp]
rfl
-- `3 ↔ 4` is the interesting part of the result. It is essentially a combination of
-- `WithSeminorms.uniformEquicontinuous_iff_exists_continuous_seminorm` which turns
-- equicontinuity into existence of some continuous seminorm and
-- `Seminorm.bound_of_continuous_normedSpace` which characterize such seminorms.
- tfae_have 3 ↔ 4
- · refine ((norm_withSeminorms 𝕜₂ F).uniformEquicontinuous_iff_exists_continuous_seminorm _).trans
+ tfae_have 3 ↔ 4 := by
+ refine ((norm_withSeminorms 𝕜₂ F).uniformEquicontinuous_iff_exists_continuous_seminorm _).trans
?_
rw [forall_const]
constructor
diff --git a/Mathlib/Analysis/NormedSpace/PiTensorProduct/InjectiveSeminorm.lean b/Mathlib/Analysis/NormedSpace/PiTensorProduct/InjectiveSeminorm.lean
index 1ddd022c490b2..299585582989c 100644
--- a/Mathlib/Analysis/NormedSpace/PiTensorProduct/InjectiveSeminorm.lean
+++ b/Mathlib/Analysis/NormedSpace/PiTensorProduct/InjectiveSeminorm.lean
@@ -211,8 +211,7 @@ theorem injectiveSeminorm_le_projectiveSeminorm :
existsi PUnit, inferInstance, inferInstance
ext x
simp only [Seminorm.zero_apply, Seminorm.comp_apply, coe_normSeminorm]
- have heq : toDualContinuousMultilinearMap PUnit x = 0 := by ext _
- rw [heq, norm_zero]
+ rw [Subsingleton.elim (toDualContinuousMultilinearMap PUnit x) 0, norm_zero]
· intro p hp
simp only [Set.mem_setOf_eq] at hp
obtain ⟨G, _, _, h⟩ := hp
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/Pointwise.lean b/Mathlib/Analysis/NormedSpace/Pointwise.lean
index bb061dfe9e186..866ca33561073 100644
--- a/Mathlib/Analysis/NormedSpace/Pointwise.lean
+++ b/Mathlib/Analysis/NormedSpace/Pointwise.lean
@@ -78,7 +78,7 @@ theorem smul_ball {c : 𝕜} (hc : c ≠ 0) (x : E) (r : ℝ) : c • ball x r =
ext y
rw [mem_smul_set_iff_inv_smul_mem₀ hc]
conv_lhs => rw [← inv_smul_smul₀ hc x]
- simp [← div_eq_inv_mul, div_lt_iff (norm_pos_iff.2 hc), mul_comm _ r, dist_smul₀]
+ simp [← div_eq_inv_mul, div_lt_iff₀ (norm_pos_iff.2 hc), mul_comm _ r, dist_smul₀]
theorem smul_unitBall {c : 𝕜} (hc : c ≠ 0) : c • ball (0 : E) (1 : ℝ) = ball (0 : E) ‖c‖ := by
rw [_root_.smul_ball hc, smul_zero, mul_one]
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/RieszLemma.lean b/Mathlib/Analysis/NormedSpace/RieszLemma.lean
index 415a55f95a3f4..553d89feaaa42 100644
--- a/Mathlib/Analysis/NormedSpace/RieszLemma.lean
+++ b/Mathlib/Analysis/NormedSpace/RieszLemma.lean
@@ -50,7 +50,7 @@ theorem riesz_lemma {F : Subspace 𝕜 E} (hFc : IsClosed (F : Set E)) (hF : ∃
simp only [r', max_lt_iff, hr, true_and]
norm_num
have hlt : 0 < r' := lt_of_lt_of_le (by norm_num) (le_max_right r 2⁻¹)
- have hdlt : d < d / r' := (lt_div_iff hlt).mpr ((mul_lt_iff_lt_one_right hdp).2 hr')
+ have hdlt : d < d / r' := (lt_div_iff₀ hlt).mpr ((mul_lt_iff_lt_one_right hdp).2 hr')
obtain ⟨y₀, hy₀F, hxy₀⟩ : ∃ y ∈ F, dist x y < d / r' := (Metric.infDist_lt_iff hFn).mp hdlt
have x_ne_y₀ : x - y₀ ∉ F := by
by_contra h
@@ -63,7 +63,7 @@ theorem riesz_lemma {F : Subspace 𝕜 E} (hFc : IsClosed (F : Set E)) (hF : ∃
r * ‖x - y₀‖ ≤ r' * ‖x - y₀‖ := by gcongr; apply le_max_left
_ < d := by
rw [← dist_eq_norm]
- exact (lt_div_iff' hlt).1 hxy₀
+ exact (lt_div_iff₀' hlt).1 hxy₀
_ ≤ dist x (y₀ + y) := Metric.infDist_le_dist_of_mem hy₀y
_ = ‖x - y₀ - y‖ := by rw [sub_sub, dist_eq_norm]
@@ -82,7 +82,7 @@ theorem riesz_lemma_of_norm_lt {c : 𝕜} (hc : 1 < ‖c‖) {R : ℝ} (hR : ‖
∃ x₀ : E, ‖x₀‖ ≤ R ∧ ∀ y ∈ F, 1 ≤ ‖x₀ - y‖ := by
have Rpos : 0 < R := (norm_nonneg _).trans_lt hR
have : ‖c‖ / R < 1 := by
- rw [div_lt_iff Rpos]
+ rw [div_lt_iff₀ Rpos]
simpa using hR
rcases riesz_lemma hFc hF this with ⟨x, xF, hx⟩
have x0 : x ≠ 0 := fun H => by simp [H] at xF
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 a1db140c6f1f2..bf6d91625d9e7 100644
--- a/Mathlib/Analysis/ODE/PicardLindelof.lean
+++ b/Mathlib/Analysis/ODE/PicardLindelof.lean
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov, Winston Yin
-/
import Mathlib.Analysis.SpecialFunctions.Integrals
+import Mathlib.Topology.Algebra.Order.Floor
import Mathlib.Topology.MetricSpace.Contracting
/-!
@@ -80,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 :=
@@ -169,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
@@ -216,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 _ _
@@ -301,7 +305,7 @@ section
theorem exists_contracting_iterate :
∃ (N : ℕ) (K : _), ContractingWith K (FunSpace.next : v.FunSpace → v.FunSpace)^[N] := by
- rcases ((Real.tendsto_pow_div_factorial_atTop (v.L * v.tDist)).eventually
+ rcases ((FloorSemiring.tendsto_pow_div_factorial_atTop (v.L * v.tDist)).eventually
(gt_mem_nhds zero_lt_one)).exists with ⟨N, hN⟩
have : (0 : ℝ) ≤ (v.L * v.tDist) ^ N / N ! :=
div_nonneg (pow_nonneg (mul_nonneg v.L.2 v.tDist_nonneg) _) (Nat.cast_nonneg _)
diff --git a/Mathlib/Analysis/Oscillation.lean b/Mathlib/Analysis/Oscillation.lean
index 16bc8089b08b1..a9e4ec628acf0 100644
--- a/Mathlib/Analysis/Oscillation.lean
+++ b/Mathlib/Analysis/Oscillation.lean
@@ -3,8 +3,9 @@ Copyright (c) 2024 James Sundstrom. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: James Sundstrom
-/
-import Mathlib.Topology.EMetricSpace.Diam
+import Mathlib.Data.ENNReal.Real
import Mathlib.Order.WellFoundedSet
+import Mathlib.Topology.EMetricSpace.Diam
/-!
# Oscillation
@@ -51,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 ?_)
@@ -106,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 6b1fde6df52ee..a0365a83cfc7b 100644
--- a/Mathlib/Analysis/PSeries.lean
+++ b/Mathlib/Analysis/PSeries.lean
@@ -63,7 +63,7 @@ theorem le_sum_schlomilch' (hf : ∀ ⦃m n⦄, 0 < m → m ≤ n → f n ≤ f
theorem le_sum_condensed' (hf : ∀ ⦃m n⦄, 0 < m → m ≤ n → f n ≤ f m) (n : ℕ) :
(∑ k ∈ Ico 1 (2 ^ n), f k) ≤ ∑ k ∈ range n, 2 ^ k • f (2 ^ k) := by
convert le_sum_schlomilch' hf (fun n => pow_pos zero_lt_two n)
- (fun m n hm => pow_le_pow_right one_le_two hm) n using 2
+ (fun m n hm => pow_right_mono₀ one_le_two hm) n using 2
simp [pow_succ, mul_two, two_mul]
theorem le_sum_schlomilch (hf : ∀ ⦃m n⦄, 0 < m → m ≤ n → f n ≤ f m) (h_pos : ∀ n, 0 < u n)
@@ -98,7 +98,7 @@ theorem sum_schlomilch_le' (hf : ∀ ⦃m n⦄, 1 < m → m ≤ n → f n ≤ f
theorem sum_condensed_le' (hf : ∀ ⦃m n⦄, 1 < m → m ≤ n → f n ≤ f m) (n : ℕ) :
(∑ k ∈ range n, 2 ^ k • f (2 ^ (k + 1))) ≤ ∑ k ∈ Ico 2 (2 ^ n + 1), f k := by
convert sum_schlomilch_le' hf (fun n => pow_pos zero_lt_two n)
- (fun m n hm => pow_le_pow_right one_le_two hm) n using 2
+ (fun m n hm => pow_right_mono₀ one_le_two hm) n using 2
simp [pow_succ, mul_two, two_mul]
theorem sum_schlomilch_le {C : ℕ} (hf : ∀ ⦃m n⦄, 1 < m → m ≤ n → f n ≤ f m) (h_pos : ∀ n, 0 < u n)
@@ -162,8 +162,8 @@ theorem tsum_schlomilch_le {C : ℕ} (hf : ∀ ⦃m n⦄, 1 < m → m ≤ n →
le_trans ?_
(add_le_add_left
(mul_le_mul_of_nonneg_left (ENNReal.sum_le_tsum <| Finset.Ico (u 0 + 1) (u n + 1)) ?_) _)
- simpa using Finset.sum_schlomilch_le hf h_pos h_nonneg hu h_succ_diff n
- exact zero_le _
+ · simpa using Finset.sum_schlomilch_le hf h_pos h_nonneg hu h_succ_diff n
+ · exact zero_le _
theorem tsum_condensed_le (hf : ∀ ⦃m n⦄, 1 < m → m ≤ n → f n ≤ f m) :
(∑' k : ℕ, 2 ^ k * f (2 ^ k)) ≤ f 1 + 2 * ∑' k, f k := by
@@ -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]
@@ -401,7 +401,7 @@ theorem sum_Ioo_inv_sq_le (k n : ℕ) : (∑ i ∈ Ioo k n, (i ^ 2 : α)⁻¹)
apply sum_le_sum_of_subset_of_nonneg
· intro x hx
simp only [mem_Ioo] at hx
- simp only [hx, hx.2.le, mem_Ioc, le_max_iff, or_true_iff, and_self_iff]
+ simp only [hx, hx.2.le, mem_Ioc, le_max_iff, or_true, and_self_iff]
· intro i _hi _hident
positivity
_ ≤ ((k + 1 : α) ^ 2)⁻¹ + ∑ i ∈ Ioc k.succ (max (k + 1) n), ((i : α) ^ 2)⁻¹ := by
@@ -416,7 +416,7 @@ theorem sum_Ioo_inv_sq_le (k n : ℕ) : (∑ i ∈ Ioo k n, (i ^ 2 : α)⁻¹)
have A : (1 : α) ≤ k + 1 := by simp only [le_add_iff_nonneg_left, Nat.cast_nonneg]
simp_rw [← one_div]
gcongr
- simpa using pow_le_pow_right A one_le_two
+ simpa using pow_right_mono₀ A one_le_two
_ = 2 / (k + 1) := by ring
end
diff --git a/Mathlib/Analysis/Quaternion.lean b/Mathlib/Analysis/Quaternion.lean
index 0991d3a5949c9..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] }
@@ -195,9 +195,9 @@ theorem continuous_im : Continuous fun q : ℍ => q.im := by
simpa only [← sub_self_re] using continuous_id.sub (continuous_coe.comp continuous_re)
instance : CompleteSpace ℍ :=
- haveI : UniformEmbedding linearIsometryEquivTuple.toLinearEquiv.toEquiv.symm :=
- linearIsometryEquivTuple.toContinuousLinearEquiv.symm.uniformEmbedding
- (completeSpace_congr this).1 (by infer_instance)
+ haveI : IsUniformEmbedding linearIsometryEquivTuple.toLinearEquiv.toEquiv.symm :=
+ linearIsometryEquivTuple.toContinuousLinearEquiv.symm.isUniformEmbedding
+ (completeSpace_congr this).1 inferInstance
section infinite_sum
diff --git a/Mathlib/Analysis/RCLike/Basic.lean b/Mathlib/Analysis/RCLike/Basic.lean
index c90ea8c4d556d..0600c19d1b79e 100644
--- a/Mathlib/Analysis/RCLike/Basic.lean
+++ b/Mathlib/Analysis/RCLike/Basic.lean
@@ -4,10 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Frédéric Dupuis
-/
import Mathlib.Algebra.Algebra.Field
+import Mathlib.Algebra.BigOperators.Balance
+import Mathlib.Algebra.Order.BigOperators.Expect
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 ℂ
@@ -36,10 +39,11 @@ 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 scoped ComplexConjugate
+open Fintype
+open scoped BigOperators ComplexConjugate
section
@@ -234,6 +238,17 @@ theorem norm_ofReal (r : ℝ) : ‖(r : K)‖ = |r| :=
instance (priority := 100) charZero_rclike : CharZero K :=
(RingHom.charZero_iff (algebraMap ℝ K).injective).1 inferInstance
+@[rclike_simps, norm_cast]
+lemma ofReal_expect {α : Type*} (s : Finset α) (f : α → ℝ) : 𝔼 i ∈ s, f i = 𝔼 i ∈ s, (f i : K) :=
+ map_expect (algebraMap ..) ..
+
+@[norm_cast]
+lemma ofReal_balance {ι : Type*} [Fintype ι] (f : ι → ℝ) (i : ι) :
+ ((balance f i : ℝ) : K) = balance ((↑) ∘ f) i := map_balance (algebraMap ..) ..
+
+@[simp] lemma ofReal_comp_balance {ι : Type*} [Fintype ι] (f : ι → ℝ) :
+ ofReal ∘ balance f = balance (ofReal ∘ f : ι → K) := funext <| ofReal_balance _
+
/-! ### The imaginary unit, `I` -/
/-- The imaginary unit. -/
@@ -248,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]
@@ -284,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 :=
@@ -317,16 +332,14 @@ open List in
/-- There are several equivalent ways to say that a number `z` is in fact a real number. -/
theorem is_real_TFAE (z : K) : TFAE [conj z = z, ∃ r : ℝ, (r : K) = z, ↑(re z) = z, im z = 0] := by
tfae_have 1 → 4
- · intro h
+ | h => by
rw [← @ofReal_inj K, im_eq_conj_sub, h, sub_self, mul_zero, zero_div,
ofReal_zero]
tfae_have 4 → 3
- · intro h
+ | h => by
conv_rhs => rw [← re_add_im z, h, ofReal_zero, zero_mul, add_zero]
- tfae_have 3 → 2
- · exact fun h => ⟨_, h⟩
- tfae_have 2 → 1
- · exact fun ⟨r, hr⟩ => hr ▸ conj_ofReal _
+ tfae_have 3 → 2 := fun h => ⟨_, h⟩
+ tfae_have 2 → 1 := fun ⟨r, hr⟩ => hr ▸ conj_ofReal _
tfae_finish
theorem conj_eq_iff_real {z : K} : conj z = z ↔ ∃ r : ℝ, z = (r : K) :=
@@ -382,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 _
@@ -397,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
@@ -454,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' _
@@ -494,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
@@ -607,13 +620,23 @@ variable (K) in
lemma nnnorm_nsmul [NormedAddCommGroup E] [NormedSpace K E] (n : ℕ) (x : E) :
‖n • x‖₊ = n • ‖x‖₊ := by simpa [Nat.cast_smul_eq_nsmul] using nnnorm_smul (n : K) x
+section NormedField
+variable [NormedField E] [CharZero E] [NormedSpace K E]
+include K
+
variable (K) in
-lemma norm_nnqsmul [NormedField E] [CharZero E] [NormedSpace K E] (q : ℚ≥0) (x : E) :
- ‖q • x‖ = q • ‖x‖ := by simpa [NNRat.cast_smul_eq_nnqsmul] using norm_smul (q : K) x
+lemma norm_nnqsmul (q : ℚ≥0) (x : E) : ‖q • x‖ = q • ‖x‖ := by
+ simpa [NNRat.cast_smul_eq_nnqsmul] using norm_smul (q : K) x
variable (K) in
-lemma nnnorm_nnqsmul [NormedField E] [CharZero E] [NormedSpace K E] (q : ℚ≥0) (x : E) :
- ‖q • x‖₊ = q • ‖x‖₊ := by simpa [NNRat.cast_smul_eq_nnqsmul] using nnnorm_smul (q : K) x
+lemma nnnorm_nnqsmul (q : ℚ≥0) (x : E) : ‖q • x‖₊ = q • ‖x‖₊ := by
+ simpa [NNRat.cast_smul_eq_nnqsmul] using nnnorm_smul (q : K) x
+
+@[bound]
+lemma norm_expect_le {ι : Type*} {s : Finset ι} {f : ι → E} : ‖𝔼 i ∈ s, f i‖ ≤ 𝔼 i ∈ s, ‖f i‖ :=
+ Finset.le_expect_of_subadditive norm_zero norm_add_le fun _ _ ↦ by rw [norm_nnqsmul K]
+
+end NormedField
theorem mul_self_norm (z : K) : ‖z‖ * ‖z‖ = normSq z := by rw [normSq_eq_def', sq]
@@ -650,11 +673,11 @@ open IsAbsoluteValue
theorem abs_re_div_norm_le_one (z : K) : |re z / ‖z‖| ≤ 1 := by
rw [abs_div, abs_norm]
- exact div_le_one_of_le (abs_re_le_norm _) (norm_nonneg _)
+ exact div_le_one_of_le₀ (abs_re_le_norm _) (norm_nonneg _)
theorem abs_im_div_norm_le_one (z : K) : |im z / ‖z‖| ≤ 1 := by
rw [abs_div, abs_norm]
- exact div_le_one_of_le (abs_im_le_norm _) (norm_nonneg _)
+ exact div_le_one_of_le₀ (abs_im_le_norm _) (norm_nonneg _)
theorem norm_I_of_ne_zero (hI : (I : K) ≠ 0) : ‖(I : K)‖ = 1 := by
rw [← mul_self_inj_of_nonneg (norm_nonneg I) zero_le_one, one_mul, ← norm_mul,
@@ -671,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)
@@ -703,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]
@@ -836,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)
@@ -849,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
@@ -1058,3 +1095,64 @@ lemma map_neg_eq_conj [AddCommGroup G] (ψ : AddChar G K) (x : G) : ψ (-x) = co
rw [map_neg_eq_inv, inv_apply_eq_conj]
end AddChar
+
+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 where
+ out : ∃ h : RCLike 𝕜, hk = h.toNormedField
+
+instance (priority := 100) (𝕜 : Type*) [h : RCLike 𝕜] : IsRCLikeNormedField 𝕜 := ⟨⟨h, rfl⟩⟩
+
+/-- A copy of an `RCLike` field in which the `NormedField` field is adjusted to be become defeq
+to a propeq one. -/
+noncomputable def RCLike.copy_of_normedField {𝕜 : Type*} (h : RCLike 𝕜) (hk : NormedField 𝕜)
+ (h'' : hk = h.toNormedField) : RCLike 𝕜 where
+ __ := hk
+ toPartialOrder := h.toPartialOrder
+ toDecidableEq := h.toDecidableEq
+ complete := by subst h''; exact h.complete
+ lt_norm_lt := by subst h''; exact h.lt_norm_lt
+ -- star fields
+ star := (@StarMul.toInvolutiveStar _ (_) (@StarRing.toStarMul _ (_) h.toStarRing)).star
+ star_involutive := by subst h''; exact h.star_involutive
+ star_mul := by subst h''; exact h.star_mul
+ star_add := by subst h''; exact h.star_add
+ -- algebra fields
+ smul := (@Algebra.toSMul _ _ _ (_) (@NormedAlgebra.toAlgebra _ _ _ (_) h.toNormedAlgebra)).smul
+ toFun := @Algebra.toRingHom _ _ _ (_) (@NormedAlgebra.toAlgebra _ _ _ (_) h.toNormedAlgebra)
+ map_one' := by subst h''; exact h.map_one'
+ map_mul' := by subst h''; exact h.map_mul'
+ map_zero' := by subst h''; exact h.map_zero'
+ map_add' := by subst h''; exact h.map_add'
+ commutes' := by subst h''; exact h.commutes'
+ smul_def' := by subst h''; exact h.smul_def'
+ norm_smul_le := by subst h''; exact h.norm_smul_le
+ -- RCLike fields
+ re := by subst h''; exact h.re
+ im := by subst h''; exact h.im
+ I := h.I
+ I_re_ax := by subst h''; exact h.I_re_ax
+ I_mul_I_ax := by subst h''; exact h.I_mul_I_ax
+ re_add_im_ax := by subst h''; exact h.re_add_im_ax
+ ofReal_re_ax := by subst h''; exact h.ofReal_re_ax
+ ofReal_im_ax := by subst h''; exact h.ofReal_im_ax
+ mul_re_ax := by subst h''; exact h.mul_re_ax
+ mul_im_ax := by subst h''; exact h.mul_im_ax
+ conj_re_ax := by subst h''; exact h.conj_re_ax
+ conj_im_ax := by subst h''; exact h.conj_im_ax
+ conj_I_ax := by subst h''; exact h.conj_I_ax
+ norm_sq_eq_def_ax := by subst h''; exact h.norm_sq_eq_def_ax
+ mul_im_I_ax := by subst h''; exact h.mul_im_I_ax
+ le_iff_re_im := by subst h''; exact h.le_iff_re_im
+
+/-- Given a normed field `𝕜` satisfying `IsRCLikeNormedField 𝕜`, build an associated `RCLike 𝕜`
+structure on `𝕜` which is definitionally compatible with the given normed field structure. -/
+noncomputable def IsRCLikeNormedField.rclike (𝕜 : Type*)
+ [hk : NormedField 𝕜] [h : IsRCLikeNormedField 𝕜] : RCLike 𝕜 := by
+ choose p hp using h.out
+ exact p.copy_of_normedField hk hp
+
+end
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 46659a1b853cf..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
@@ -495,7 +491,7 @@ noncomputable instance instSupSet : SupSet (Seminorm 𝕜 E) where
if h : BddAbove ((↑) '' s : Set (E → ℝ)) then
{ toFun := ⨆ p : s, ((p : Seminorm 𝕜 E) : E → ℝ)
map_zero' := by
- rw [iSup_apply, ← @Real.ciSup_const_zero s]
+ rw [iSup_apply, ← @Real.iSup_const_zero s]
congr!
rename_i _ _ _ i
exact map_zero i.1
@@ -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]
@@ -658,7 +654,7 @@ theorem ball_smul (p : Seminorm 𝕜 E) {c : NNReal} (hc : 0 < c) (r : ℝ) (x :
(c • p).ball x r = p.ball x (r / c) := by
ext
rw [mem_ball, mem_ball, smul_apply, NNReal.smul_def, smul_eq_mul, mul_comm,
- lt_div_iff (NNReal.coe_pos.mpr hc)]
+ lt_div_iff₀ (NNReal.coe_pos.mpr hc)]
theorem closedBall_smul (p : Seminorm 𝕜 E) {c : NNReal} (hc : 0 < c) (r : ℝ) (x : E) :
(c • p).closedBall x r = p.closedBall x (r / c) := by
@@ -815,14 +811,14 @@ theorem closedBall_finset_sup (p : ι → Seminorm 𝕜 E) (s : Finset ι) (x :
@[simp]
theorem ball_eq_emptyset (p : Seminorm 𝕜 E) {x : E} {r : ℝ} (hr : r ≤ 0) : p.ball x r = ∅ := by
ext
- rw [Seminorm.mem_ball, Set.mem_empty_iff_false, iff_false_iff, not_lt]
+ rw [Seminorm.mem_ball, Set.mem_empty_iff_false, iff_false, not_lt]
exact hr.trans (apply_nonneg p _)
@[simp]
theorem closedBall_eq_emptyset (p : Seminorm 𝕜 E) {x : E} {r : ℝ} (hr : r < 0) :
p.closedBall x r = ∅ := by
ext
- rw [Seminorm.mem_closedBall, Set.mem_empty_iff_false, iff_false_iff, not_le]
+ rw [Seminorm.mem_closedBall, Set.mem_empty_iff_false, iff_false, not_le]
exact hr.trans_le (apply_nonneg _ _)
theorem closedBall_smul_ball (p : Seminorm 𝕜 E) {r₁ : ℝ} (hr₁ : r₁ ≠ 0) (r₂ : ℝ) :
@@ -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
@@ -899,7 +894,7 @@ theorem smul_ball_zero {p : Seminorm 𝕜 E} {k : 𝕜} {r : ℝ} (hk : k ≠ 0)
k • p.ball 0 r = p.ball 0 (‖k‖ * r) := by
ext
rw [mem_smul_set_iff_inv_smul_mem₀ hk, p.mem_ball_zero, p.mem_ball_zero, map_smul_eq_mul,
- norm_inv, ← div_eq_inv_mul, div_lt_iff (norm_pos_iff.2 hk), mul_comm]
+ norm_inv, ← div_eq_inv_mul, div_lt_iff₀ (norm_pos_iff.2 hk), mul_comm]
theorem smul_closedBall_subset {p : Seminorm 𝕜 E} {k : 𝕜} {r : ℝ} :
k • p.closedBall 0 r ⊆ p.closedBall 0 (‖k‖ * r) := by
@@ -952,7 +947,7 @@ protected theorem absorbent_closedBall (hpr : p x < r) : Absorbent 𝕜 (closedB
theorem smul_ball_preimage (p : Seminorm 𝕜 E) (y : E) (r : ℝ) (a : 𝕜) (ha : a ≠ 0) :
(a • ·) ⁻¹' p.ball y r = p.ball (a⁻¹ • y) (r / ‖a‖) :=
Set.ext fun _ => by
- rw [mem_preimage, mem_ball, mem_ball, lt_div_iff (norm_pos_iff.mpr ha), mul_comm, ←
+ rw [mem_preimage, mem_ball, mem_ball, lt_div_iff₀ (norm_pos_iff.mpr ha), mul_comm, ←
map_smul_eq_mul p, smul_sub, smul_inv_smul₀ ha]
end NormedField
@@ -1047,7 +1042,7 @@ theorem continuousAt_zero' [TopologicalSpace E] [ContinuousConstSMul 𝕜 E] {p
obtain ⟨k, hk₀, hk⟩ : ∃ k : 𝕜, 0 < ‖k‖ ∧ ‖k‖ * r < ε := by
rcases le_or_lt r 0 with hr | hr
· use 1; simpa using hr.trans_lt hε
- · simpa [lt_div_iff hr] using exists_norm_lt 𝕜 (div_pos hε hr)
+ · simpa [lt_div_iff₀ hr] using exists_norm_lt 𝕜 (div_pos hε hr)
rw [← set_smul_mem_nhds_zero_iff (norm_pos_iff.1 hk₀), smul_closedBall_zero hk₀] at hp
exact mem_of_superset hp <| p.closedBall_mono hk.le
@@ -1184,13 +1179,13 @@ lemma rescale_to_shell_zpow (p : Seminorm 𝕜 E) {c : 𝕜} (hc : 1 < ‖c‖)
refine ⟨-(n+1), ?_, ?_, ?_, ?_⟩
· show c ^ (-(n + 1)) ≠ 0; exact zpow_ne_zero _ (norm_pos_iff.1 cpos)
· show p ((c ^ (-(n + 1))) • x) < ε
- rw [map_smul_eq_mul, zpow_neg, norm_inv, ← div_eq_inv_mul, div_lt_iff cnpos, mul_comm,
+ rw [map_smul_eq_mul, zpow_neg, norm_inv, ← div_eq_inv_mul, div_lt_iff₀ cnpos, mul_comm,
norm_zpow]
- exact (div_lt_iff εpos).1 (hn.2)
+ exact (div_lt_iff₀ εpos).1 (hn.2)
· 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 66d2388a494f1..a38081bf15582 100644
--- a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean
@@ -1,12 +1,13 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
+import Mathlib.Algebra.Order.Field.Power
import Mathlib.Analysis.SpecificLimits.Basic
import Mathlib.RingTheory.Polynomial.Bernstein
-import Mathlib.Topology.ContinuousFunction.Polynomial
-import Mathlib.Topology.ContinuousFunction.Compact
+import Mathlib.Topology.ContinuousMap.Polynomial
+import Mathlib.Topology.ContinuousMap.Compact
/-!
# Bernstein approximations and Weierstrass' theorem
@@ -101,8 +102,8 @@ local postfix:90 "/ₙ" => z
theorem probability (n : ℕ) (x : I) : (∑ k : Fin (n + 1), bernstein n k x) = 1 := by
have := bernsteinPolynomial.sum ℝ n
apply_fun fun p => Polynomial.aeval (x : ℝ) p at this
- simp? [AlgHom.map_sum, Finset.sum_range] at this says
- simp only [Finset.sum_range, map_sum, Polynomial.coe_aeval_eq_eval, map_one] at this
+ simp? [map_sum, Finset.sum_range] at this says
+ simp only [Finset.sum_range, map_sum, Polynomial.coe_aeval_eq_eval, Polynomial.eval_one] at this
exact this
theorem variance {n : ℕ} (h : 0 < (n : ℝ)) (x : I) :
@@ -115,9 +116,10 @@ theorem variance {n : ℕ} (h : 0 < (n : ℝ)) (x : I) :
conv_rhs => rw [div_mul_cancel₀ _ h']
have := bernsteinPolynomial.variance ℝ n
apply_fun fun p => Polynomial.aeval (x : ℝ) p at this
- simp? [AlgHom.map_sum, Finset.sum_range, ← Polynomial.natCast_mul] at this says
- simp only [nsmul_eq_mul, Finset.sum_range, map_sum, map_mul, map_pow, map_sub, map_natCast,
- Polynomial.aeval_X, Polynomial.coe_aeval_eq_eval, map_one] at this
+ simp? [map_sum, Finset.sum_range, ← Polynomial.natCast_mul] at this says
+ simp only [nsmul_eq_mul, Finset.sum_range, map_sum, Polynomial.coe_aeval_eq_eval,
+ Polynomial.eval_mul, Polynomial.eval_pow, Polynomial.eval_sub, Polynomial.eval_natCast,
+ Polynomial.eval_X, Polynomial.eval_one] at this
convert this using 1
· congr 1; funext k
rw [mul_comm _ (n : ℝ), mul_comm _ (n : ℝ), ← mul_assoc, ← mul_assoc]
@@ -251,9 +253,7 @@ theorem bernsteinApproximation_uniform (f : C(I, ℝ)) :
_ = ε / 2 * ∑ k ∈ S, bernstein n k x := by rw [Finset.mul_sum]
-- In this step we increase the sum over `S` back to a sum over all of `Fin (n+1)`,
-- so that we can use `bernstein.probability`.
- _ ≤ ε / 2 * ∑ k : Fin (n + 1), bernstein n k x := by
- gcongr
- exact Finset.sum_le_univ_sum_of_nonneg fun k => bernstein_nonneg
+ _ ≤ ε / 2 * ∑ k : Fin (n + 1), bernstein n k x := by gcongr; exact S.subset_univ
_ = ε / 2 := by rw [bernstein.probability, mul_one]
· -- We now turn to working on `Sᶜ`: we control the difference term just using `‖f‖`,
-- and then insert a `δ^(-2) * (x - k/n)^2` factor
@@ -270,9 +270,7 @@ theorem bernsteinApproximation_uniform (f : C(I, ℝ)) :
exact le_of_mem_S_compl m
-- Again enlarging the sum from `Sᶜ` to all of `Fin (n+1)`
_ ≤ 2 * ‖f‖ * ∑ k : Fin (n + 1), δ ^ (-2 : ℤ) * ((x : ℝ) - k/ₙ) ^ 2 * bernstein n k x := by
- gcongr
- refine Finset.sum_le_univ_sum_of_nonneg fun k => ?_
- positivity
+ gcongr; exact Sᶜ.subset_univ
_ = 2 * ‖f‖ * δ ^ (-2 : ℤ) * ∑ k : Fin (n + 1), ((x : ℝ) - k/ₙ) ^ 2 * bernstein n k x := by
conv_rhs =>
rw [mul_assoc, Finset.mul_sum]
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/Analytic.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean
index 18ea3db3671d5..d717114a27b82 100644
--- a/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean
@@ -11,7 +11,7 @@ import Mathlib.Analysis.SpecialFunctions.Complex.LogDeriv
/-!
# Various complex special functions are analytic
-`exp`, `log`, and `cpow` are analytic, since they are differentiable.
+`log`, and `cpow` are analytic, since they are differentiable.
-/
open Complex Set
@@ -20,22 +20,6 @@ open scoped Topology
variable {E : Type} [NormedAddCommGroup E] [NormedSpace ℂ E]
variable {f g : E → ℂ} {z : ℂ} {x : E} {s : Set E}
-/-- `exp` is entire -/
-theorem analyticOn_cexp : AnalyticOn ℂ exp univ := by
- rw [analyticOn_univ_iff_differentiable]; exact differentiable_exp
-
-/-- `exp` is analytic at any point -/
-theorem analyticAt_cexp : AnalyticAt ℂ exp z :=
- analyticOn_cexp z (mem_univ _)
-
-/-- `exp ∘ f` is analytic -/
-theorem AnalyticAt.cexp (fa : AnalyticAt ℂ f x) : AnalyticAt ℂ (fun z ↦ exp (f z)) x :=
- analyticAt_cexp.comp fa
-
-/-- `exp ∘ f` is analytic -/
-theorem AnalyticOn.cexp (fs : AnalyticOn ℂ f s) : AnalyticOn ℂ (fun z ↦ exp (f z)) s :=
- fun z n ↦ analyticAt_cexp.comp (fs z n)
-
/-- `log` is analytic away from nonpositive reals -/
theorem analyticAt_clog (m : z ∈ slitPlane) : AnalyticAt ℂ log z := by
rw [analyticAt_iff_eventually_differentiableAt]
@@ -48,21 +32,40 @@ theorem AnalyticAt.clog (fa : AnalyticAt ℂ f x) (m : f x ∈ slitPlane) :
AnalyticAt ℂ (fun z ↦ log (f z)) x :=
(analyticAt_clog m).comp fa
+theorem AnalyticWithinAt.clog (fa : AnalyticWithinAt ℂ f s x) (m : f x ∈ slitPlane) :
+ AnalyticWithinAt ℂ (fun z ↦ log (f z)) s x :=
+ (analyticAt_clog m).comp_analyticWithinAt fa
+
/-- `log` is analytic away from nonpositive reals -/
+theorem AnalyticOnNhd.clog (fs : AnalyticOnNhd ℂ f s) (m : ∀ z ∈ s, f z ∈ slitPlane) :
+ AnalyticOnNhd ℂ (fun z ↦ log (f z)) s :=
+ fun z n ↦ (analyticAt_clog (m z n)).comp (fs z n)
+
theorem AnalyticOn.clog (fs : AnalyticOn ℂ f s) (m : ∀ z ∈ s, f z ∈ slitPlane) :
AnalyticOn ℂ (fun z ↦ log (f z)) s :=
- fun z n ↦ (analyticAt_clog (m z n)).comp (fs z n)
+ fun z n ↦ (analyticAt_clog (m z n)).analyticWithinAt.comp (fs z n) m
/-- `f z ^ g z` is analytic if `f z` is not a nonpositive real -/
-theorem AnalyticAt.cpow (fa : AnalyticAt ℂ f x) (ga : AnalyticAt ℂ g x)
- (m : f x ∈ slitPlane) : AnalyticAt ℂ (fun z ↦ f z ^ g z) x := by
- have e : (fun z ↦ f z ^ g z) =ᶠ[𝓝 x] fun z ↦ exp (log (f z) * g z) := by
- filter_upwards [(fa.continuousAt.eventually_ne (slitPlane_ne_zero m))]
+theorem AnalyticWithinAt.cpow (fa : AnalyticWithinAt ℂ f s x) (ga : AnalyticWithinAt ℂ g s x)
+ (m : f x ∈ slitPlane) : AnalyticWithinAt ℂ (fun z ↦ f z ^ g z) s x := by
+ have e : (fun z ↦ f z ^ g z) =ᶠ[𝓝[insert x s] x] fun z ↦ exp (log (f z) * g z) := by
+ filter_upwards [(fa.continuousWithinAt_insert.eventually_ne (slitPlane_ne_zero m))]
intro z fz
simp only [fz, cpow_def, if_false]
- rw [analyticAt_congr e]
+ apply AnalyticWithinAt.congr_of_eventuallyEq_insert _ e
exact ((fa.clog m).mul ga).cexp
+/-- `f z ^ g z` is analytic if `f z` is not a nonpositive real -/
+theorem AnalyticAt.cpow (fa : AnalyticAt ℂ f x) (ga : AnalyticAt ℂ g x)
+ (m : f x ∈ slitPlane) : AnalyticAt ℂ (fun z ↦ f z ^ g z) x := by
+ rw [← analyticWithinAt_univ] at fa ga ⊢
+ exact fa.cpow ga m
+
+/-- `f z ^ g z` is analytic if `f z` avoids nonpositive reals -/
+theorem AnalyticOnNhd.cpow (fs : AnalyticOnNhd ℂ f s) (gs : AnalyticOnNhd ℂ g s)
+ (m : ∀ z ∈ s, f z ∈ slitPlane) : AnalyticOnNhd ℂ (fun z ↦ f z ^ g z) s :=
+ fun z n ↦ (fs z n).cpow (gs z n) (m z n)
+
/-- `f z ^ g z` is analytic if `f z` avoids nonpositive reals -/
theorem AnalyticOn.cpow (fs : AnalyticOn ℂ f s) (gs : AnalyticOn ℂ g s)
(m : ∀ z ∈ s, f z ∈ slitPlane) : AnalyticOn ℂ (fun z ↦ f z ^ g z) s :=
diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Arctan.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Arctan.lean
index d9d625ead931a..d5bc0c1f1b5ba 100644
--- a/Mathlib/Analysis/SpecialFunctions/Complex/Arctan.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Complex/Arctan.lean
@@ -73,7 +73,7 @@ theorem arctan_tan {z : ℂ} (h₀ : z ≠ π / 2) (h₁ : -(π / 2) < z.re) (h
rw [← exp_mul_I, ← exp_mul_I, ← exp_sub, show z * I - -z * I = 2 * (I * z) by ring, log_exp,
show -I / 2 * (2 * (I * z)) = -(I * I) * z by ring, I_mul_I, neg_neg, one_mul]
all_goals norm_num
- · rwa [← div_lt_iff' two_pos, neg_div]
+ · rwa [← div_lt_iff₀' two_pos, neg_div]
· rwa [← le_div_iff₀' two_pos]
@[simp, norm_cast]
diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean
index 94901e3540e4f..0086e643a19b8 100644
--- a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean
@@ -172,7 +172,7 @@ theorem arg_mul_real {r : ℝ} (hr : 0 < r) (x : ℂ) : arg (x * r) = arg x :=
theorem arg_eq_arg_iff {x y : ℂ} (hx : x ≠ 0) (hy : y ≠ 0) :
arg x = arg y ↔ (abs y / abs x : ℂ) * x = y := by
simp only [ext_abs_arg_iff, map_mul, map_div₀, abs_ofReal, abs_abs,
- div_mul_cancel₀ _ (abs.ne_zero hx), eq_self_iff_true, true_and_iff]
+ div_mul_cancel₀ _ (abs.ne_zero hx), eq_self_iff_true, true_and]
rw [← ofReal_div, arg_real_mul]
exact div_pos (abs.pos hy) (abs.pos hx)
@@ -322,28 +322,28 @@ lemma image_exp_Ioc_eq_sphere : (fun θ : ℝ ↦ exp (θ * I)) '' Set.Ioc (-π)
theorem arg_le_pi_div_two_iff {z : ℂ} : arg z ≤ π / 2 ↔ 0 ≤ re z ∨ im z < 0 := by
rcases le_or_lt 0 (re z) with hre | hre
- · simp only [hre, arg_of_re_nonneg hre, Real.arcsin_le_pi_div_two, true_or_iff]
- simp only [hre.not_le, false_or_iff]
+ · simp only [hre, arg_of_re_nonneg hre, Real.arcsin_le_pi_div_two, true_or]
+ simp only [hre.not_le, false_or]
rcases le_or_lt 0 (im z) with him | him
· simp only [him.not_lt]
- rw [iff_false_iff, not_le, arg_of_re_neg_of_im_nonneg hre him, ← sub_lt_iff_lt_add, half_sub,
+ rw [iff_false, not_le, arg_of_re_neg_of_im_nonneg hre him, ← sub_lt_iff_lt_add, half_sub,
Real.neg_pi_div_two_lt_arcsin, neg_im, neg_div, neg_lt_neg_iff, div_lt_one, ←
_root_.abs_of_nonneg him, abs_im_lt_abs]
exacts [hre.ne, abs.pos <| ne_of_apply_ne re hre.ne]
· simp only [him]
- rw [iff_true_iff, arg_of_re_neg_of_im_neg hre him]
+ rw [iff_true, arg_of_re_neg_of_im_neg hre him]
exact (sub_le_self _ Real.pi_pos.le).trans (Real.arcsin_le_pi_div_two _)
theorem neg_pi_div_two_le_arg_iff {z : ℂ} : -(π / 2) ≤ arg z ↔ 0 ≤ re z ∨ 0 ≤ im z := by
rcases le_or_lt 0 (re z) with hre | hre
- · simp only [hre, arg_of_re_nonneg hre, Real.neg_pi_div_two_le_arcsin, true_or_iff]
- simp only [hre.not_le, false_or_iff]
+ · simp only [hre, arg_of_re_nonneg hre, Real.neg_pi_div_two_le_arcsin, true_or]
+ simp only [hre.not_le, false_or]
rcases le_or_lt 0 (im z) with him | him
· simp only [him]
- rw [iff_true_iff, arg_of_re_neg_of_im_nonneg hre him]
+ rw [iff_true, arg_of_re_neg_of_im_nonneg hre him]
exact (Real.neg_pi_div_two_le_arcsin _).trans (le_add_of_nonneg_right Real.pi_pos.le)
· simp only [him.not_le]
- rw [iff_false_iff, not_le, arg_of_re_neg_of_im_neg hre him, sub_lt_iff_lt_add', ←
+ rw [iff_false, not_le, arg_of_re_neg_of_im_neg hre him, sub_lt_iff_lt_add', ←
sub_eq_add_neg, sub_half, Real.arcsin_lt_pi_div_two, div_lt_one, neg_im, ← abs_of_neg him,
abs_im_lt_abs]
exacts [hre.ne, abs.pos <| ne_of_apply_ne re hre.ne]
@@ -367,7 +367,7 @@ lemma arg_lt_pi_div_two_iff {z : ℂ} : arg z < π / 2 ↔ 0 < re z ∨ im z < 0
@[simp]
theorem abs_arg_le_pi_div_two_iff {z : ℂ} : |arg z| ≤ π / 2 ↔ 0 ≤ re z := by
rw [abs_le, arg_le_pi_div_two_iff, neg_pi_div_two_le_arg_iff, ← or_and_left, ← not_le,
- and_not_self_iff, or_false_iff]
+ and_not_self_iff, or_false]
@[simp]
theorem abs_arg_lt_pi_div_two_iff {z : ℂ} : |arg z| < π / 2 ↔ 0 < re z ∨ z = 0 := by
@@ -597,8 +597,8 @@ 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), ←
- Function.comp.assoc]
+ (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
rwa [continuousAt_update_of_ne (neg_ne_zero.2 h)] at this
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 2986597856fcc..27a9142d793a9 100644
--- a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean
+++ b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean
@@ -7,7 +7,7 @@ Authors: Frédéric Dupuis
import Mathlib.Analysis.Normed.Algebra.Spectrum
import Mathlib.Analysis.SpecialFunctions.Exponential
import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unital
-import Mathlib.Topology.ContinuousFunction.StarOrdered
+import Mathlib.Topology.ContinuousMap.StarOrdered
/-!
# The exponential and logarithm based on the continuous functional calculus
@@ -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 d9317023529a2..bd9a8f4a616de 100644
--- a/Mathlib/Analysis/SpecialFunctions/Exp.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Exp.lean
@@ -263,7 +263,7 @@ theorem tendsto_exp_div_pow_atTop (n : ℕ) : Tendsto (fun x => exp x / x ^ n) a
eventually_atTop.1
((tendsto_pow_const_div_const_pow_of_one_lt n (one_lt_exp_iff.2 zero_lt_one)).eventually
(gt_mem_nhds this))
- simp only [← exp_nat_mul, mul_one, div_lt_iff, exp_pos, ← div_eq_inv_mul] at hN
+ simp only [← exp_nat_mul, mul_one, div_lt_iff₀, exp_pos, ← div_eq_inv_mul] at hN
refine ⟨N, trivial, fun x hx => ?_⟩
rw [Set.mem_Ioi] at hx
have hx₀ : 0 < x := (Nat.cast_nonneg N).trans_lt hx
@@ -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/ExpDeriv.lean b/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean
index 31ff5558fe80a..8506d9e055ab1 100644
--- a/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean
+++ b/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean
@@ -6,6 +6,7 @@ Authors: Chris Hughes, Abhimanyu Pallavi Sudhir, Jean Lo, Calle Sönne
import Mathlib.Analysis.Complex.RealDeriv
import Mathlib.Analysis.Calculus.ContDiff.RCLike
import Mathlib.Analysis.Calculus.IteratedDeriv.Lemmas
+import Mathlib.Analysis.SpecialFunctions.Exponential
/-!
# Complex and real exponential
@@ -24,6 +25,41 @@ open scoped Topology
/-! ## `Complex.exp` -/
+section
+
+open Complex
+
+variable {E : Type} [NormedAddCommGroup E] [NormedSpace ℂ E]
+variable {f g : E → ℂ} {z : ℂ} {x : E} {s : Set E}
+
+/-- `exp` is entire -/
+theorem analyticOnNhd_cexp : AnalyticOnNhd ℂ exp univ := by
+ rw [Complex.exp_eq_exp_ℂ]
+ exact fun x _ ↦ NormedSpace.exp_analytic x
+
+theorem analyticOn_cexp : AnalyticOn ℂ exp univ := analyticOnNhd_cexp.analyticOn
+
+/-- `exp` is analytic at any point -/
+theorem analyticAt_cexp : AnalyticAt ℂ exp z :=
+ analyticOnNhd_cexp z (mem_univ _)
+
+/-- `exp ∘ f` is analytic -/
+theorem AnalyticAt.cexp (fa : AnalyticAt ℂ f x) : AnalyticAt ℂ (fun z ↦ exp (f z)) x :=
+ analyticAt_cexp.comp fa
+
+theorem AnalyticWithinAt.cexp (fa : AnalyticWithinAt ℂ f s x) :
+ AnalyticWithinAt ℂ (fun z ↦ exp (f z)) s x :=
+ analyticAt_cexp.comp_analyticWithinAt fa
+
+/-- `exp ∘ f` is analytic -/
+theorem AnalyticOnNhd.cexp (fs : AnalyticOnNhd ℂ f s) : AnalyticOnNhd ℂ (fun z ↦ exp (f z)) s :=
+ fun z n ↦ analyticAt_cexp.comp (fs z n)
+
+theorem AnalyticOn.cexp (fs : AnalyticOn ℂ f s) : AnalyticOn ℂ (fun z ↦ exp (f z)) s :=
+ analyticOnNhd_cexp.comp_analyticOn fs (mapsTo_univ _ _)
+
+end
+
namespace Complex
variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [NormedAlgebra 𝕜 ℂ]
@@ -52,17 +88,8 @@ theorem iter_deriv_exp : ∀ n : ℕ, deriv^[n] exp = exp
| 0 => rfl
| n + 1 => by rw [iterate_succ_apply, deriv_exp, iter_deriv_exp n]
-theorem contDiff_exp : ∀ {n}, ContDiff 𝕜 n exp := by
- -- Porting note: added `@` due to `∀ {n}` weirdness above
- refine @(contDiff_all_iff_nat.2 fun n => ?_)
- have : ContDiff ℂ (↑n) exp := by
- induction n with
- | zero => exact contDiff_zero.2 continuous_exp
- | succ n ihn =>
- rw [contDiff_succ_iff_deriv]
- use differentiable_exp
- rwa [deriv_exp]
- exact this.restrict_scalars 𝕜
+theorem contDiff_exp {n : ℕ∞} : ContDiff 𝕜 n exp :=
+ analyticOnNhd_cexp.restrictScalars.contDiff
theorem hasStrictDerivAt_exp (x : ℂ) : HasStrictDerivAt exp (exp x) x :=
contDiff_exp.contDiffAt.hasStrictDerivAt' (hasDerivAt_exp x) le_rfl
@@ -156,12 +183,44 @@ theorem iteratedDeriv_cexp_const_mul (n : ℕ) (c : ℂ) :
(iteratedDeriv n fun s : ℂ => exp (c * s)) = fun s => c ^ n * exp (c * s) := by
rw [iteratedDeriv_const_mul contDiff_exp, iteratedDeriv_eq_iterate, iter_deriv_exp]
-
/-! ## `Real.exp` -/
-namespace Real
+section
+
+open Real
+
+variable {x : ℝ} {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {f : E → ℝ} {s : Set E}
+
+/-- `exp` is entire -/
+theorem analyticOnNhd_rexp : AnalyticOnNhd ℝ exp univ := by
+ rw [Real.exp_eq_exp_ℝ]
+ exact fun x _ ↦ NormedSpace.exp_analytic x
+
+theorem analyticOn_rexp : AnalyticOn ℝ exp univ := analyticOnNhd_rexp.analyticOn
+
+/-- `exp` is analytic at any point -/
+theorem analyticAt_rexp : AnalyticAt ℝ exp x :=
+ analyticOnNhd_rexp x (mem_univ _)
-variable {x y z : ℝ}
+/-- `exp ∘ f` is analytic -/
+theorem AnalyticAt.rexp {x : E} (fa : AnalyticAt ℝ f x) : AnalyticAt ℝ (fun z ↦ exp (f z)) x :=
+ analyticAt_rexp.comp fa
+
+theorem AnalyticWithinAt.rexp {x : E} (fa : AnalyticWithinAt ℝ f s x) :
+ AnalyticWithinAt ℝ (fun z ↦ exp (f z)) s x :=
+ analyticAt_rexp.comp_analyticWithinAt fa
+
+/-- `exp ∘ f` is analytic -/
+theorem AnalyticOnNhd.rexp {s : Set E} (fs : AnalyticOnNhd ℝ f s) :
+ AnalyticOnNhd ℝ (fun z ↦ exp (f z)) s :=
+ fun z n ↦ analyticAt_rexp.comp (fs z n)
+
+theorem AnalyticOn.rexp (fs : AnalyticOn ℝ f s) : AnalyticOn ℝ (fun z ↦ exp (f z)) s :=
+ analyticOnNhd_rexp.comp_analyticOn fs (mapsTo_univ _ _)
+
+end
+
+namespace Real
theorem hasStrictDerivAt_exp (x : ℝ) : HasStrictDerivAt exp (exp x) x :=
(Complex.hasStrictDerivAt_exp x).real_of_complex
@@ -169,12 +228,12 @@ theorem hasStrictDerivAt_exp (x : ℝ) : HasStrictDerivAt exp (exp x) x :=
theorem hasDerivAt_exp (x : ℝ) : HasDerivAt exp (exp x) x :=
(Complex.hasDerivAt_exp x).real_of_complex
-theorem contDiff_exp {n} : ContDiff ℝ n exp :=
+theorem contDiff_exp {n : ℕ∞} : ContDiff ℝ n exp :=
Complex.contDiff_exp.real_of_complex
theorem differentiable_exp : Differentiable ℝ exp := fun x => (hasDerivAt_exp x).differentiableAt
-theorem differentiableAt_exp : DifferentiableAt ℝ exp x :=
+theorem differentiableAt_exp {x : ℝ} : DifferentiableAt ℝ exp x :=
differentiable_exp x
@[simp]
diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean
index c12393d6b86df..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,10 +475,9 @@ 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
- rw [← ofReal_cpow (le_of_lt ht), RCLike.ofReal_mul]
- rfl
+ simp_rw [← ofReal_cpow ht.le, RCLike.ofReal_mul, coe_algebraMap]
open Lean.Meta Qq Mathlib.Meta.Positivity in
/-- The `positivity` extension which identifies expressions of the form `Gamma a`. -/
@@ -607,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 5b9cac12afe16..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
@@ -183,11 +184,11 @@ theorem betaIntegral_recurrence {u v : ℂ} (hu : 0 < re u) (hv : 0 < re v) :
have int_ev := intervalIntegral.integral_eq_sub_of_hasDerivAt_of_le zero_le_one hc hder h_int
have hF0 : F 0 = 0 := by
simp only [F, mul_eq_zero, ofReal_zero, cpow_eq_zero_iff, eq_self_iff_true, Ne,
- true_and_iff, sub_zero, one_cpow, one_ne_zero, or_false_iff]
+ true_and, sub_zero, one_cpow, one_ne_zero, or_false]
contrapose! hu; rw [hu, zero_re]
have hF1 : F 1 = 0 := by
simp only [F, mul_eq_zero, ofReal_one, one_cpow, one_ne_zero, sub_self, cpow_eq_zero_iff,
- eq_self_iff_true, Ne, true_and_iff, false_or_iff]
+ eq_self_iff_true, Ne, true_and, false_or]
contrapose! hv; rw [hv, zero_re]
rw [hF0, hF1, sub_zero, intervalIntegral.integral_sub, intervalIntegral.integral_const_mul,
intervalIntegral.integral_const_mul] at int_ev
@@ -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
@@ -328,7 +329,7 @@ theorem approx_Gamma_integral_tendsto_Gamma_integral {s : ℂ} (hs : 0 < re s) :
exact rpow_nonneg (le_of_lt hx) _
· rw [indicator_of_mem (mem_Ioc.mpr ⟨mem_Ioi.mp hx, hxn⟩), norm_mul, Complex.norm_eq_abs,
Complex.abs_of_nonneg
- (pow_nonneg (sub_nonneg.mpr <| div_le_one_of_le hxn <| by positivity) _),
+ (pow_nonneg (sub_nonneg.mpr <| div_le_one_of_le₀ hxn <| by positivity) _),
Complex.norm_eq_abs, abs_cpow_eq_rpow_re_of_pos hx, sub_re, one_re,
mul_le_mul_right (rpow_pos_of_pos hx _)]
exact one_sub_div_pow_le_exp_neg hxn
@@ -407,7 +408,7 @@ theorem Gamma_mul_Gamma_one_sub (z : ℂ) : Gamma z * Gamma (1 - z) = π / sin (
rw [hs, div_zero]
rw [← neg_eq_zero, ← Complex.sin_neg, ← mul_neg, Complex.sin_eq_zero_iff, mul_comm] at hs
obtain ⟨k, hk⟩ := hs
- rw [mul_eq_mul_right_iff, eq_false (ofReal_ne_zero.mpr pi_pos.ne'), or_false_iff,
+ rw [mul_eq_mul_right_iff, eq_false (ofReal_ne_zero.mpr pi_pos.ne'), or_false,
neg_eq_iff_eq_neg] at hk
rw [hk]
cases k
@@ -547,13 +548,13 @@ theorem Gamma_mul_Gamma_add_half (s : ℂ) :
convert congr_arg Inv.inv (congr_fun this s) using 1
· rw [mul_inv, inv_inv, inv_inv]
· rw [div_eq_mul_inv, mul_inv, mul_inv, inv_inv, inv_inv, ← cpow_neg, neg_sub]
- have h1 : AnalyticOn ℂ (fun z : ℂ => (Gamma z)⁻¹ * (Gamma (z + 1 / 2))⁻¹) univ := by
- refine DifferentiableOn.analyticOn ?_ isOpen_univ
+ have h1 : AnalyticOnNhd ℂ (fun z : ℂ => (Gamma z)⁻¹ * (Gamma (z + 1 / 2))⁻¹) univ := by
+ refine DifferentiableOn.analyticOnNhd ?_ isOpen_univ
refine (differentiable_one_div_Gamma.mul ?_).differentiableOn
exact differentiable_one_div_Gamma.comp (differentiable_id.add (differentiable_const _))
- have h2 : AnalyticOn ℂ
+ have h2 : AnalyticOnNhd ℂ
(fun z => (Gamma (2 * z))⁻¹ * (2 : ℂ) ^ (2 * z - 1) / ↑(√π)) univ := by
- refine DifferentiableOn.analyticOn ?_ isOpen_univ
+ refine DifferentiableOn.analyticOnNhd ?_ isOpen_univ
refine (Differentiable.mul ?_ (differentiable_const _)).differentiableOn
apply Differentiable.mul
· exact differentiable_one_div_Gamma.comp (differentiable_id'.const_mul _)
@@ -563,7 +564,7 @@ theorem Gamma_mul_Gamma_add_half (s : ℂ) :
rw [tendsto_nhdsWithin_iff]; constructor
· exact tendsto_nhdsWithin_of_tendsto_nhds continuous_ofReal.continuousAt
· exact eventually_nhdsWithin_iff.mpr (Eventually.of_forall fun t ht => ofReal_ne_one.mpr ht)
- refine AnalyticOn.eq_of_frequently_eq h1 h2 (h3.frequently ?_)
+ refine AnalyticOnNhd.eq_of_frequently_eq h1 h2 (h3.frequently ?_)
refine ((Eventually.filter_mono nhdsWithin_le_nhds) ?_).frequently
refine (eventually_gt_nhds zero_lt_one).mp (Eventually.of_forall fun t ht => ?_)
rw [← mul_inv, Gamma_ofReal, (by norm_num : (t : ℂ) + 1 / 2 = ↑(t + 1 / 2)), Gamma_ofReal, ←
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/FourierTransform.lean b/Mathlib/Analysis/SpecialFunctions/Gaussian/FourierTransform.lean
index ea572b4ce3c4e..89db8290e3687 100644
--- a/Mathlib/Analysis/SpecialFunctions/Gaussian/FourierTransform.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Gaussian/FourierTransform.lean
@@ -332,18 +332,18 @@ theorem integral_cexp_neg_mul_sq_norm_add_of_euclideanSpace
theorem integral_cexp_neg_mul_sq_norm_add
(hb : 0 < b.re) (c : ℂ) (w : V) :
∫ v : V, cexp (- b * ‖v‖^2 + c * ⟪w, v⟫) =
- (π / b) ^ (FiniteDimensional.finrank ℝ V / 2 : ℂ) * cexp (c ^ 2 * ‖w‖^2 / (4 * b)) := by
+ (π / b) ^ (Module.finrank ℝ V / 2 : ℂ) * cexp (c ^ 2 * ‖w‖^2 / (4 * b)) := by
let e := (stdOrthonormalBasis ℝ V).repr.symm
rw [← e.measurePreserving.integral_comp e.toHomeomorph.measurableEmbedding]
convert integral_cexp_neg_mul_sq_norm_add_of_euclideanSpace
hb c (e.symm w) <;> simp [LinearIsometryEquiv.inner_map_eq_flip]
theorem integral_cexp_neg_mul_sq_norm (hb : 0 < b.re) :
- ∫ v : V, cexp (- b * ‖v‖^2) = (π / b) ^ (FiniteDimensional.finrank ℝ V / 2 : ℂ) := by
+ ∫ v : V, cexp (- b * ‖v‖^2) = (π / b) ^ (Module.finrank ℝ V / 2 : ℂ) := by
simpa using integral_cexp_neg_mul_sq_norm_add hb 0 (0 : V)
theorem integral_rexp_neg_mul_sq_norm {b : ℝ} (hb : 0 < b) :
- ∫ v : V, rexp (- b * ‖v‖^2) = (π / b) ^ (FiniteDimensional.finrank ℝ V / 2 : ℝ) := by
+ ∫ v : V, rexp (- b * ‖v‖^2) = (π / b) ^ (Module.finrank ℝ V / 2 : ℝ) := by
rw [← ofReal_inj]
convert integral_cexp_neg_mul_sq_norm (show 0 < (b : ℂ).re from hb) (V := V)
· change ofRealLI (∫ (v : V), rexp (-b * ‖v‖ ^ 2)) = ∫ (v : V), cexp (-↑b * ↑‖v‖ ^ 2)
@@ -354,7 +354,7 @@ theorem integral_rexp_neg_mul_sq_norm {b : ℝ} (hb : 0 < b) :
theorem _root_.fourierIntegral_gaussian_innerProductSpace' (hb : 0 < b.re) (x w : V) :
𝓕 (fun v ↦ cexp (- b * ‖v‖^2 + 2 * π * Complex.I * ⟪x, v⟫)) w =
- (π / b) ^ (FiniteDimensional.finrank ℝ V / 2 : ℂ) * cexp (-π ^ 2 * ‖x - w‖ ^ 2 / b) := by
+ (π / b) ^ (Module.finrank ℝ V / 2 : ℂ) * cexp (-π ^ 2 * ‖x - w‖ ^ 2 / b) := by
simp only [neg_mul, fourierIntegral_eq', ofReal_neg, ofReal_mul, ofReal_ofNat,
smul_eq_mul, ← Complex.exp_add, real_inner_comm w]
convert integral_cexp_neg_mul_sq_norm_add hb (2 * π * Complex.I) (x - w) using 3 with v
@@ -367,7 +367,7 @@ theorem _root_.fourierIntegral_gaussian_innerProductSpace' (hb : 0 < b.re) (x w
theorem _root_.fourierIntegral_gaussian_innerProductSpace (hb : 0 < b.re) (w : V) :
𝓕 (fun v ↦ cexp (- b * ‖v‖^2)) w =
- (π / b) ^ (FiniteDimensional.finrank ℝ V / 2 : ℂ) * cexp (-π ^ 2 * ‖w‖^2 / b) := by
+ (π / b) ^ (Module.finrank ℝ V / 2 : ℂ) * cexp (-π ^ 2 * ‖w‖^2 / b) := by
simpa using fourierIntegral_gaussian_innerProductSpace' hb 0 w
end InnerProductSpace
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 ca08532bc9736..f1b7032f2b0b7 100644
--- a/Mathlib/Analysis/SpecialFunctions/Integrals.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Integrals.lean
@@ -33,7 +33,7 @@ integrate, integration, integrable, integrability
-/
-open Real Nat Set Finset
+open Real Set Finset
open scoped Real Interval
@@ -43,7 +43,7 @@ namespace intervalIntegral
open MeasureTheory
-variable {f : ℝ → ℝ} {μ ν : Measure ℝ} [IsLocallyFiniteMeasure μ] (c d : ℝ)
+variable {f : ℝ → ℝ} {μ : Measure ℝ} [IsLocallyFiniteMeasure μ] (c d : ℝ)
/-! ### Interval integrability -/
@@ -115,16 +115,16 @@ 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_iff] at h
+ rw [eq_false h2, or_false] at h
rcases lt_or_eq_of_le h with (h' | h')
· -- Easy case #2: 0 < re r -- again use continuity
exact (Complex.continuous_ofReal_cpow_const h').intervalIntegrable _ _
-- 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]
@@ -580,8 +578,9 @@ theorem integral_mul_rpow_one_add_sq {t : ℝ} (ht : t ≠ -1) :
end RpowCpow
-/-! ### Integral of `sin x ^ n` -/
+open Nat
+/-! ### Integral of `sin x ^ n` -/
theorem integral_sin_pow_aux :
(∫ x in a..b, sin x ^ (n + 2)) =
diff --git a/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean b/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean
index 79be49beb847d..52481419b2ca5 100644
--- a/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean
+++ b/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean
@@ -27,7 +27,7 @@ noncomputable section
open scoped NNReal Filter Topology ENNReal
-open Asymptotics Filter Set Real MeasureTheory FiniteDimensional
+open Asymptotics Filter Set Real MeasureTheory Module
variable {E : Type*} [NormedAddCommGroup E]
@@ -85,7 +85,7 @@ theorem finite_integral_rpow_sub_one_pow_aux {r : ℝ} (n : ℕ) (hnr : (n : ℝ
refine IntegrableOn.setLIntegral_lt_top ?_
rw [← intervalIntegrable_iff_integrableOn_Ioc_of_le zero_le_one]
apply intervalIntegral.intervalIntegrable_rpow'
- rwa [neg_lt_neg_iff, inv_mul_lt_iff' hr, one_mul]
+ rwa [neg_lt_neg_iff, inv_mul_lt_iff₀' hr, one_mul]
variable [MeasurableSpace E] [BorelSpace E] {μ : Measure E} [μ.IsAddHaarMeasure]
@@ -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/Base.lean b/Mathlib/Analysis/SpecialFunctions/Log/Base.lean
index 23dedfcd33066..f7fafb38f92f6 100644
--- a/Mathlib/Analysis/SpecialFunctions/Log/Base.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Log/Base.lean
@@ -423,7 +423,7 @@ lemma Real.induction_Ico_mul {P : ℝ → Prop} (x₀ r : ℝ) (hr : 1 < r) (hx
intro x hx
have hx' : 0 < x / x₀ := div_pos (hx₀.trans_le hx) hx₀
refine this ⌊logb r (x / x₀)⌋₊ x ?_
- rw [mem_Ico, ← div_lt_iff hx₀, ← rpow_natCast, ← logb_lt_iff_lt_rpow hr hx', Nat.cast_add,
+ rw [mem_Ico, ← div_lt_iff₀ hx₀, ← rpow_natCast, ← logb_lt_iff_lt_rpow hr hx', Nat.cast_add,
Nat.cast_one]
exact ⟨hx, Nat.lt_floor_add_one _⟩
intro n
diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean
index 4698f6d30f954..ccc7141a90155 100644
--- a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean
@@ -281,17 +281,27 @@ theorem log_le_sub_one_of_pos {x : ℝ} (hx : 0 < x) : log x ≤ x - 1 := by
lemma one_sub_inv_le_log_of_pos (hx : 0 < x) : 1 - x⁻¹ ≤ log x := by
simpa [add_comm] using log_le_sub_one_of_pos (inv_pos.2 hx)
+/-- See `Real.log_le_sub_one_of_pos` for the stronger version when `x ≠ 0`. -/
+lemma log_le_self (hx : 0 ≤ x) : log x ≤ x := by
+ obtain rfl | hx := hx.eq_or_lt
+ · simp
+ · exact (log_le_sub_one_of_pos hx).trans (by linarith)
+
+/-- See `Real.one_sub_inv_le_log_of_pos` for the stronger version when `x ≠ 0`. -/
+lemma neg_inv_le_log (hx : 0 ≤ x) : -x⁻¹ ≤ log x := by
+ rw [neg_le, ← log_inv]; exact log_le_self <| inv_nonneg.2 hx
+
/-- Bound for `|log x * x|` in the interval `(0, 1]`. -/
theorem abs_log_mul_self_lt (x : ℝ) (h1 : 0 < x) (h2 : x ≤ 1) : |log x * x| < 1 := by
have : 0 < 1 / x := by simpa only [one_div, inv_pos] using h1
replace := log_le_sub_one_of_pos this
replace : log (1 / x) < 1 / x := by linarith
- rw [log_div one_ne_zero h1.ne', log_one, zero_sub, lt_div_iff h1] at this
+ rw [log_div one_ne_zero h1.ne', log_one, zero_sub, lt_div_iff₀ h1] at this
have aux : 0 ≤ -log x * x := by
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/ENNRealLog.lean b/Mathlib/Analysis/SpecialFunctions/Log/ENNRealLog.lean
index 0028886a44787..68243cfc4a5e8 100644
--- a/Mathlib/Analysis/SpecialFunctions/Log/ENNRealLog.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Log/ENNRealLog.lean
@@ -51,24 +51,20 @@ noncomputable def log (x : ℝ≥0∞) : EReal :=
@[simp]
lemma log_ofReal (x : ℝ) : log (ENNReal.ofReal x) = if x ≤ 0 then ⊥ else ↑(Real.log x) := by
simp only [log, ENNReal.none_eq_top, ENNReal.ofReal_ne_top, IsEmpty.forall_iff,
- ENNReal.ofReal_eq_zero, EReal.coe_ennreal_ofReal]
+ ENNReal.ofReal_eq_zero, EReal.coe_ennreal_ofReal, if_false]
split_ifs with h_nonpos
· rfl
- · trivial
- · rw [ENNReal.toReal_ofReal]
- exact (not_le.mp h_nonpos).le
+ · rw [ENNReal.toReal_ofReal (not_le.mp h_nonpos).le]
lemma log_ofReal_of_pos {x : ℝ} (hx : 0 < x) : log (ENNReal.ofReal x) = Real.log x := by
- rw [log_ofReal, if_neg]
- exact not_le.mpr hx
+ rw [log_ofReal, if_neg hx.not_le]
theorem log_pos_real {x : ℝ≥0∞} (h : x ≠ 0) (h' : x ≠ ⊤) :
log x = Real.log (ENNReal.toReal x) := by simp [log, h, h']
theorem log_pos_real' {x : ℝ≥0∞} (h : 0 < x.toReal) :
log x = Real.log (ENNReal.toReal x) := by
- simp [log, Ne.symm (ne_of_lt (ENNReal.toReal_pos_iff.1 h).1),
- ne_of_lt (ENNReal.toReal_pos_iff.1 h).2]
+ simp [log, (ENNReal.toReal_pos_iff.1 h).1.ne', (ENNReal.toReal_pos_iff.1 h).2.ne]
theorem log_of_nnreal {x : ℝ≥0} (h : x ≠ 0) :
log (x : ℝ≥0∞) = Real.log x := by simp [log, h]
@@ -85,19 +81,19 @@ theorem log_strictMono : StrictMono log := by
· rcases ENNReal.trichotomy y with (rfl | rfl | y_real)
· exfalso; exact lt_irrefl 0 h
· simp
- · simp [Ne.symm (ne_of_lt (ENNReal.toReal_pos_iff.1 y_real).1),
- ne_of_lt (ENNReal.toReal_pos_iff.1 y_real).2, EReal.bot_lt_coe]
- · exfalso; exact (ne_top_of_lt h) (Eq.refl ⊤)
- · simp only [Ne.symm (ne_of_lt (ENNReal.toReal_pos_iff.1 x_real).1),
- ne_of_lt (ENNReal.toReal_pos_iff.1 x_real).2]
+ · simp [(ENNReal.toReal_pos_iff.1 y_real).1.ne',
+ (ENNReal.toReal_pos_iff.1 y_real).2.ne, EReal.bot_lt_coe]
+ · exfalso; exact not_top_lt h
+ · simp only [(ENNReal.toReal_pos_iff.1 x_real).1.ne',
+ (ENNReal.toReal_pos_iff.1 x_real).2.ne, if_false]
rcases ENNReal.trichotomy y with (rfl | rfl | y_real)
· exfalso; rw [← ENNReal.bot_eq_zero] at h; exact not_lt_bot h
· simp
- · simp only [Ne.symm (ne_of_lt (ENNReal.toReal_pos_iff.1 y_real).1), ↓reduceIte,
- ne_of_lt (ENNReal.toReal_pos_iff.1 y_real).2, EReal.coe_lt_coe_iff]
+ · simp only [(ENNReal.toReal_pos_iff.1 y_real).1.ne', ↓reduceIte,
+ (ENNReal.toReal_pos_iff.1 y_real).2.ne, EReal.coe_lt_coe_iff]
apply Real.log_lt_log x_real
- exact (ENNReal.toReal_lt_toReal (ne_of_lt (ENNReal.toReal_pos_iff.1 x_real).2)
- (ne_of_lt (ENNReal.toReal_pos_iff.1 y_real).2)).2 h
+ exact (ENNReal.toReal_lt_toReal (ENNReal.toReal_pos_iff.1 x_real).2.ne
+ (ENNReal.toReal_pos_iff.1 y_real).2.ne).2 h
theorem log_monotone : Monotone log := log_strictMono.monotone
@@ -112,14 +108,14 @@ theorem log_surjective : Function.Surjective log := by
use ENNReal.ofReal (Real.exp y.toReal)
have exp_y_pos := not_le_of_lt (Real.exp_pos y.toReal)
simp only [log, ofReal_eq_zero, exp_y_pos, ↓reduceIte, ofReal_ne_top,
- ENNReal.toReal_ofReal (le_of_lt (Real.exp_pos y.toReal)), Real.log_exp y.toReal]
- exact EReal.coe_toReal (ne_of_lt y_ntop) (Ne.symm (ne_of_lt y_nbot))
+ ENNReal.toReal_ofReal (Real.exp_pos y.toReal).le, Real.log_exp y.toReal]
+ exact EReal.coe_toReal y_ntop.ne y_nbot.ne'
theorem log_bijective : Function.Bijective log := ⟨log_injective, log_surjective⟩
@[simp]
theorem log_eq_iff {x y : ℝ≥0∞} : log x = log y ↔ x = y :=
- Iff.intro (@log_injective x y) (fun h ↦ by rw [h])
+ log_injective.eq_iff
@[simp] theorem log_eq_bot_iff {x : ℝ≥0∞} : log x = ⊥ ↔ x = 0 := log_zero ▸ @log_eq_iff x 0
@@ -158,13 +154,13 @@ theorem log_mul_add {x y : ℝ≥0∞} : log (x * y) = log x + log y := by
· simp
· rw [log_pos_real' y_real, ENNReal.top_mul', EReal.top_add_coe, log_eq_top_iff]
simp only [ite_eq_right_iff, zero_ne_top, imp_false]
- exact Ne.symm (ne_of_lt (ENNReal.toReal_pos_iff.1 y_real).1)
+ exact (ENNReal.toReal_pos_iff.1 y_real).1.ne'
· rw [log_pos_real' x_real]
rcases ENNReal.trichotomy y with (rfl | rfl | y_real)
· simp
- · simp [Ne.symm (ne_of_lt (ENNReal.toReal_pos_iff.1 x_real).1)]
+ · simp [(ENNReal.toReal_pos_iff.1 x_real).1.ne']
· rw_mod_cast [log_pos_real', log_pos_real' y_real, ENNReal.toReal_mul]
- · exact Real.log_mul (Ne.symm (ne_of_lt x_real)) (Ne.symm (ne_of_lt y_real))
+ · exact Real.log_mul x_real.ne' y_real.ne'
rw [toReal_mul]
positivity
@@ -172,24 +168,20 @@ theorem log_pow {x : ℝ≥0∞} {n : ℕ} : log (x ^ n) = n * log x := by
cases' Nat.eq_zero_or_pos n with n_zero n_pos
· simp [n_zero, pow_zero x]
rcases ENNReal.trichotomy x with (rfl | rfl | x_real)
- · rw [zero_pow (Ne.symm (ne_of_lt n_pos)), log_zero, EReal.mul_bot_of_pos (Nat.cast_pos'.2 n_pos)]
+ · rw [zero_pow n_pos.ne', log_zero, EReal.mul_bot_of_pos (Nat.cast_pos'.2 n_pos)]
· rw [ENNReal.top_pow n_pos, log_top, EReal.mul_top_of_pos (Nat.cast_pos'.2 n_pos)]
· replace x_real := ENNReal.toReal_pos_iff.1 x_real
- have x_ne_zero := Ne.symm (LT.lt.ne x_real.1)
- have x_ne_top := LT.lt.ne x_real.2
- simp only [log, pow_eq_zero_iff', x_ne_zero, false_and, ↓reduceIte, pow_eq_top_iff, x_ne_top,
- toReal_pow, Real.log_pow, EReal.coe_mul]
- rfl
+ simp only [log, pow_eq_zero_iff', x_real.1.ne', false_and, ↓reduceIte, pow_eq_top_iff,
+ x_real.2.ne, toReal_pow, Real.log_pow, EReal.coe_mul, EReal.coe_coe_eq_natCast]
theorem log_rpow {x : ℝ≥0∞} {y : ℝ} : log (x ^ y) = y * log x := by
rcases lt_trichotomy y 0 with (y_neg | rfl | y_pos)
· rcases ENNReal.trichotomy x with (rfl | rfl | x_real)
- · simp only [ENNReal.zero_rpow_def y, not_lt_of_lt y_neg, ne_of_lt y_neg, log_top, log_zero]
- exact Eq.symm (EReal.coe_mul_bot_of_neg y_neg)
- · rw [ENNReal.top_rpow_of_neg y_neg, log_zero, log_top]
- exact Eq.symm (EReal.coe_mul_top_of_neg y_neg)
- · have x_ne_zero := Ne.symm (LT.lt.ne (ENNReal.toReal_pos_iff.1 x_real).1)
- have x_ne_top := LT.lt.ne (ENNReal.toReal_pos_iff.1 x_real).2
+ · simp only [ENNReal.zero_rpow_def y, not_lt_of_lt y_neg, y_neg.ne, if_false, log_top,
+ log_zero, EReal.coe_mul_bot_of_neg y_neg]
+ · rw [ENNReal.top_rpow_of_neg y_neg, log_zero, log_top, EReal.coe_mul_top_of_neg y_neg]
+ · have x_ne_zero := (ENNReal.toReal_pos_iff.1 x_real).1.ne'
+ have x_ne_top := (ENNReal.toReal_pos_iff.1 x_real).2.ne
simp only [log, rpow_eq_zero_iff, x_ne_zero, false_and, x_ne_top, or_self, ↓reduceIte,
rpow_eq_top_iff]
norm_cast
@@ -198,8 +190,8 @@ theorem log_rpow {x : ℝ≥0∞} {y : ℝ} : log (x ^ y) = y * log x := by
· rcases ENNReal.trichotomy x with (rfl | rfl | x_real)
· rw [ENNReal.zero_rpow_of_pos y_pos, log_zero, EReal.mul_bot_of_pos]; norm_cast
· rw [ENNReal.top_rpow_of_pos y_pos, log_top, EReal.mul_top_of_pos]; norm_cast
- · have x_ne_zero := Ne.symm (LT.lt.ne (ENNReal.toReal_pos_iff.1 x_real).1)
- have x_ne_top := LT.lt.ne (ENNReal.toReal_pos_iff.1 x_real).2
+ · have x_ne_zero := (ENNReal.toReal_pos_iff.1 x_real).1.ne'
+ have x_ne_top := (ENNReal.toReal_pos_iff.1 x_real).2.ne
simp only [log, rpow_eq_zero_iff, x_ne_zero, false_and, x_ne_top, or_self, ↓reduceIte,
rpow_eq_top_iff]
norm_cast
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 e11dde25a0bad..46513cef6be86 100644
--- a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean
+++ b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean
@@ -39,12 +39,12 @@ def polarCoord : PartialHomeomorph (ℝ × ℝ) (ℝ × ℝ) where
· simpa using hr
· right
simp at hr
- simpa only [ne_of_gt hr, Ne, mem_setOf_eq, mul_eq_zero, false_or_iff,
+ simpa only [ne_of_gt hr, Ne, mem_setOf_eq, mul_eq_zero, false_or,
sin_eq_zero_iff_of_lt_of_lt hθ.1 hθ.2] using h'θ
map_source' := by
rintro ⟨x, y⟩ hxy
simp only [prod_mk_mem_set_prod_eq, mem_Ioi, sqrt_pos, mem_Ioo, Complex.neg_pi_lt_arg,
- true_and_iff, Complex.arg_lt_pi_iff]
+ true_and, Complex.arg_lt_pi_iff]
constructor
· cases' hxy with hxy hxy
· dsimp at hxy; linarith [sq_pos_of_ne_zero hxy.ne', sq_nonneg y]
@@ -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/Complex.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Complex.lean
index 9a2469906a661..c9a10865fd507 100644
--- a/Mathlib/Analysis/SpecialFunctions/Pow/Complex.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Pow/Complex.lean
@@ -175,7 +175,7 @@ lemma cpow_ofNat_mul' {x : ℂ} {n : ℕ} [n.AtLeastTwo] (hlt : -π < OfNat.ofNa
lemma pow_cpow_nat_inv {x : ℂ} {n : ℕ} (h₀ : n ≠ 0) (hlt : -(π / n) < x.arg) (hle : x.arg ≤ π / n) :
(x ^ n) ^ (n⁻¹ : ℂ) = x := by
rw [← cpow_nat_mul', mul_inv_cancel₀ (Nat.cast_ne_zero.2 h₀), cpow_one]
- · rwa [← div_lt_iff' (Nat.cast_pos.2 h₀.bot_lt), neg_div]
+ · rwa [← div_lt_iff₀' (Nat.cast_pos.2 h₀.bot_lt), neg_div]
· rwa [← le_div_iff₀' (Nat.cast_pos.2 h₀.bot_lt)]
lemma pow_cpow_ofNat_inv {x : ℂ} {n : ℕ} [n.AtLeastTwo] (hlt : -(π / OfNat.ofNat n) < x.arg)
diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean
index 529dea6298d19..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
@@ -332,8 +336,7 @@ theorem continuousAt_ofReal_cpow (x : ℝ) (y : ℂ) (h : 0 < y.re ∨ x ≠ 0)
ContinuousAt (fun p => (p.1 : ℂ) ^ p.2 : ℝ × ℂ → ℂ) (x, y) := by
rcases lt_trichotomy (0 : ℝ) x with (hx | rfl | hx)
· -- x > 0 : easy case
- have : ContinuousAt (fun p => ⟨↑p.1, p.2⟩ : ℝ × ℂ → ℂ × ℂ) (x, y) :=
- continuous_ofReal.continuousAt.prod_map continuousAt_id
+ have : ContinuousAt (fun p => ⟨↑p.1, p.2⟩ : ℝ × ℂ → ℂ × ℂ) (x, y) := by fun_prop
refine (continuousAt_cpow (Or.inl ?_)).comp this
rwa [ofReal_re]
· -- x = 0 : reduce to continuousAt_cpow_zero_of_re_pos
@@ -341,15 +344,13 @@ theorem continuousAt_ofReal_cpow (x : ℝ) (y : ℂ) (h : 0 < y.re ∨ x ≠ 0)
rw [ofReal_zero]
apply continuousAt_cpow_zero_of_re_pos
tauto
- have B : ContinuousAt (fun p => ⟨↑p.1, p.2⟩ : ℝ × ℂ → ℂ × ℂ) ⟨0, y⟩ :=
- continuous_ofReal.continuousAt.prod_map continuousAt_id
+ have B : ContinuousAt (fun p => ⟨↑p.1, p.2⟩ : ℝ × ℂ → ℂ × ℂ) ⟨0, y⟩ := by fun_prop
exact A.comp_of_eq B rfl
· -- x < 0 : difficult case
suffices ContinuousAt (fun p => (-(p.1 : ℂ)) ^ p.2 * exp (π * I * p.2) : ℝ × ℂ → ℂ) (x, y) by
refine this.congr (eventually_of_mem (prod_mem_nhds (Iio_mem_nhds hx) univ_mem) ?_)
exact fun p hp => (ofReal_cpow_of_nonpos (le_of_lt hp.1) p.2).symm
- have A : ContinuousAt (fun p => ⟨-↑p.1, p.2⟩ : ℝ × ℂ → ℂ × ℂ) (x, y) :=
- ContinuousAt.prod_map continuous_ofReal.continuousAt.neg continuousAt_id
+ have A : ContinuousAt (fun p => ⟨-↑p.1, p.2⟩ : ℝ × ℂ → ℂ × ℂ) (x, y) := by fun_prop
apply ContinuousAt.mul
· refine (continuousAt_cpow (Or.inl ?_)).comp A
rwa [neg_re, ofReal_re, neg_pos]
@@ -394,7 +395,7 @@ theorem eventually_pow_one_div_le (x : ℝ≥0) {y : ℝ≥0} (hy : 1 < y) :
refine eventually_atTop.2 ⟨m + 1, fun n hn => ?_⟩
simp only [one_div]
simpa only [NNReal.rpow_inv_le_iff (Nat.cast_pos.2 <| m.succ_pos.trans_le hn),
- NNReal.rpow_natCast] using hm.le.trans (pow_le_pow_right hy.le (m.le_succ.trans hn))
+ NNReal.rpow_natCast] using hm.le.trans (pow_right_mono₀ hy.le (m.le_succ.trans hn))
end NNReal
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 e826c5461f294..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
@@ -666,7 +666,7 @@ theorem mul_rpow_eq_ite (x y : ℝ≥0∞) (z : ℝ) :
induction y
· rw [ne_eq, coe_eq_zero] at hx0
cases' hz with hz hz <;> simp [*]
- simp only [*, false_and_iff, and_false_iff, false_or_iff, if_false]
+ simp only [*, if_false]
norm_cast at *
rw [← coe_rpow_of_ne_zero (mul_ne_zero hx0 hy0), NNReal.mul_rpow]
norm_cast
diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean
index 6a7ea43f88beb..a2e922b310ba9 100644
--- a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean
@@ -166,6 +166,22 @@ theorem abs_rpow_le_exp_log_mul (x y : ℝ) : |x ^ y| ≤ exp (log x * y) := by
· by_cases hy : y = 0 <;> simp [hx, hy, zero_le_one]
· rw [rpow_def_of_pos (abs_pos.2 hx), log_abs]
+lemma rpow_inv_log (hx₀ : 0 < x) (hx₁ : x ≠ 1) : x ^ (log x)⁻¹ = exp 1 := by
+ rw [rpow_def_of_pos hx₀, mul_inv_cancel₀]
+ exact log_ne_zero.2 ⟨hx₀.ne', hx₁, (hx₀.trans' <| by norm_num).ne'⟩
+
+/-- See `Real.rpow_inv_log` for the equality when `x ≠ 1` is strictly positive. -/
+lemma rpow_inv_log_le_exp_one : x ^ (log x)⁻¹ ≤ exp 1 := by
+ calc
+ _ ≤ |x ^ (log x)⁻¹| := le_abs_self _
+ _ ≤ |x| ^ (log x)⁻¹ := abs_rpow_le_abs_rpow ..
+ rw [← log_abs]
+ obtain hx | hx := (abs_nonneg x).eq_or_gt
+ · simp [hx]
+ · rw [rpow_def_of_pos hx]
+ gcongr
+ exact mul_inv_le_one
+
theorem norm_rpow_of_nonneg {x y : ℝ} (hx_nonneg : 0 ≤ x) : ‖x ^ y‖ = ‖x‖ ^ y := by
simp_rw [Real.norm_eq_abs]
exact abs_rpow_of_nonneg hx_nonneg
@@ -512,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
@@ -576,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) :
@@ -807,7 +823,7 @@ theorem rpow_le_one_iff_of_pos (hx : 0 < x) : x ^ y ≤ 1 ↔ 1 ≤ x ∧ y ≤
/-- Bound for `|log x * x ^ t|` in the interval `(0, 1]`, for positive real `t`. -/
theorem abs_log_mul_self_rpow_lt (x t : ℝ) (h1 : 0 < x) (h2 : x ≤ 1) (ht : 0 < t) :
|log x * x ^ t| < 1 / t := by
- rw [lt_div_iff ht]
+ rw [lt_div_iff₀ ht]
have := abs_log_mul_self_lt (x ^ t) (rpow_pos_of_pos h1 t) (rpow_le_one h1.le h2 ht.le)
rwa [log_rpow h1, mul_assoc, abs_mul, abs_of_pos ht, mul_comm] at this
@@ -981,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
@@ -1024,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 0ff3d40698098..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 806f844aeaaeb..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]
@@ -204,7 +202,7 @@ theorem cos_eq_iff_coe_eq_or_eq_neg {θ ψ : ℝ} :
constructor
· intro Hcos
rw [← sub_eq_zero, cos_sub_cos, mul_eq_zero, mul_eq_zero, neg_eq_zero,
- eq_false (two_ne_zero' ℝ), false_or_iff, sin_eq_zero_iff, sin_eq_zero_iff] at Hcos
+ eq_false (two_ne_zero' ℝ), false_or, sin_eq_zero_iff, sin_eq_zero_iff] at Hcos
rcases Hcos with (⟨n, hn⟩ | ⟨n, hn⟩)
· right
rw [eq_div_iff_mul_eq (two_ne_zero' ℝ), ← sub_eq_iff_eq_add] at hn
@@ -252,7 +250,7 @@ theorem cos_sin_inj {θ ψ : ℝ} (Hcos : cos θ = cos ψ) (Hsin : sin θ = sin
rw [eq_neg_iff_add_eq_zero, hs] at hc
obtain ⟨n, hn⟩ : ∃ n, n • _ = _ := QuotientAddGroup.leftRel_apply.mp (Quotient.exact' hc)
rw [← neg_one_mul, add_zero, ← sub_eq_zero, zsmul_eq_mul, ← mul_assoc, ← sub_mul, mul_eq_zero,
- eq_false (ne_of_gt pi_pos), or_false_iff, sub_neg_eq_add, ← Int.cast_zero, ← Int.cast_one,
+ eq_false (ne_of_gt pi_pos), or_false, sub_neg_eq_add, ← Int.cast_zero, ← Int.cast_one,
← Int.cast_ofNat, ← Int.cast_mul, ← Int.cast_add, Int.cast_inj] at hn
have : (n * 2 + 1) % (2 : ℤ) = 0 % (2 : ℤ) := congr_arg (· % (2 : ℤ)) hn
rw [add_comm, Int.add_mul_emod_self] at this
@@ -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]
@@ -554,7 +550,7 @@ theorem nsmul_toReal_eq_mul {n : ℕ} (h : n ≠ 0) {θ : Angle} :
(n • θ).toReal = n * θ.toReal ↔ θ.toReal ∈ Set.Ioc (-π / n) (π / n) := by
nth_rw 1 [← coe_toReal θ]
have h' : 0 < (n : ℝ) := mod_cast Nat.pos_of_ne_zero h
- rw [← coe_nsmul, nsmul_eq_mul, toReal_coe_eq_self_iff, Set.mem_Ioc, div_lt_iff' h',
+ rw [← coe_nsmul, nsmul_eq_mul, toReal_coe_eq_self_iff, Set.mem_Ioc, div_lt_iff₀' h',
le_div_iff₀' h']
theorem two_nsmul_toReal_eq_two_mul {θ : Angle} :
@@ -585,7 +581,7 @@ theorem two_nsmul_toReal_eq_two_mul_sub_two_pi {θ : Angle} :
rw [← coe_nsmul, two_nsmul, ← two_mul, toReal_coe_eq_self_sub_two_pi_iff, Set.mem_Ioc]
exact
⟨fun h => by linarith, fun h =>
- ⟨(div_lt_iff' (zero_lt_two' ℝ)).1 h, by linarith [pi_pos, toReal_le_pi θ]⟩⟩
+ ⟨(div_lt_iff₀' (zero_lt_two' ℝ)).1 h, by linarith [pi_pos, toReal_le_pi θ]⟩⟩
theorem two_zsmul_toReal_eq_two_mul_sub_two_pi {θ : Angle} :
((2 : ℤ) • θ).toReal = 2 * θ.toReal - 2 * π ↔ π / 2 < θ.toReal := by
@@ -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 2ea81c6afbe95..6919f9dcbb728 100644
--- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean
@@ -208,7 +208,7 @@ lemma arctan_add_arctan_lt_pi_div_two {x y : ℝ} (h : x * y < 1) : arctan x + a
cases' le_or_lt y 0 with hy hy
· rw [← add_zero (π / 2), ← arctan_zero]
exact add_lt_add_of_lt_of_le (arctan_lt_pi_div_two _) (tanOrderIso.symm.monotone hy)
- · rw [← lt_div_iff hy, ← inv_eq_one_div] at h
+ · rw [← lt_div_iff₀ hy, ← inv_eq_one_div] at h
replace h : arctan x < arctan y⁻¹ := tanOrderIso.symm.strictMono h
rwa [arctan_inv_of_pos hy, lt_tsub_iff_right] at h
@@ -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 c31a03b44e31f..4c002f27c027e 100644
--- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean
@@ -3,6 +3,7 @@ Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes, Abhimanyu Pallavi Sudhir, Jean Lo, Calle Sönne, Benjamin Davidson
-/
+import Mathlib.Algebra.QuadraticDiscriminant
import Mathlib.Analysis.SpecialFunctions.Exp
import Mathlib.Tactic.Positivity.Core
import Mathlib.Algebra.Ring.NegOnePow
@@ -279,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
@@ -362,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
@@ -501,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]
@@ -517,13 +514,13 @@ theorem cos_eq_one_iff (x : ℝ) : cos x = 1 ↔ ∃ n : ℤ, (n : ℝ) * (2 *
(Int.emod_two_eq_zero_or_one n).elim
(fun hn0 => by
rwa [← mul_assoc, ← @Int.cast_two ℝ, ← Int.cast_mul,
- Int.ediv_mul_cancel ((Int.dvd_iff_emod_eq_zero _ _).2 hn0)])
+ Int.ediv_mul_cancel (Int.dvd_iff_emod_eq_zero.2 hn0)])
fun hn1 => by
rw [← Int.emod_add_ediv n 2, hn1, Int.cast_add, Int.cast_one, add_mul, one_mul, add_comm,
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 :=
@@ -661,7 +658,7 @@ theorem sqrtTwoAddSeries_monotone_left {x y : ℝ} (h : x ≤ y) :
theorem cos_pi_over_two_pow : ∀ n : ℕ, cos (π / 2 ^ (n + 1)) = sqrtTwoAddSeries 0 n / 2
| 0 => by simp
| n + 1 => by
- have A : (1 : ℝ) < 2 ^ (n + 1) := one_lt_pow one_lt_two n.succ_ne_zero
+ have A : (1 : ℝ) < 2 ^ (n + 1) := one_lt_pow₀ one_lt_two n.succ_ne_zero
have B : π / 2 ^ (n + 1) < π := div_lt_self pi_pos A
have C : 0 < π / 2 ^ (n + 1) := by positivity
rw [pow_succ, div_mul_eq_div_div, cos_half, cos_pi_over_two_pow n, sqrtTwoAddSeries,
@@ -690,7 +687,7 @@ theorem sin_pi_over_two_pow_succ (n : ℕ) :
exact (sqrtTwoAddSeries_lt_two _).le
refine mul_nonneg (sin_nonneg_of_nonneg_of_le_pi ?_ ?_) zero_le_two
· positivity
- · exact div_le_self pi_pos.le <| one_le_pow_of_one_le one_le_two _
+ · exact div_le_self pi_pos.le <| one_le_pow₀ one_le_two
@[simp]
theorem cos_pi_div_four : cos (π / 4) = √2 / 2 := by
@@ -795,6 +792,49 @@ theorem sin_pi_div_three : sin (π / 3) = √3 / 2 := by
congr
ring
+theorem quadratic_root_cos_pi_div_five :
+ letI c := cos (π / 5)
+ 4 * c ^ 2 - 2 * c - 1 = 0 := by
+ set θ := π / 5 with hθ
+ set c := cos θ
+ set s := sin θ
+ suffices 2 * c = 4 * c ^ 2 - 1 by simp [this]
+ have hs : s ≠ 0 := by
+ rw [ne_eq, sin_eq_zero_iff, hθ]
+ push_neg
+ intro n hn
+ replace hn : n * 5 = 1 := by field_simp [mul_comm _ π, mul_assoc] at hn; norm_cast at hn
+ rcases Int.mul_eq_one_iff_eq_one_or_neg_one.mp hn with ⟨_, h⟩ | ⟨_, h⟩ <;> norm_num at h
+ suffices s * (2 * c) = s * (4 * c ^ 2 - 1) from mul_left_cancel₀ hs this
+ calc s * (2 * c) = 2 * s * c := by rw [← mul_assoc, mul_comm 2]
+ _ = sin (2 * θ) := by rw [sin_two_mul]
+ _ = sin (π - 2 * θ) := by rw [sin_pi_sub]
+ _ = sin (2 * θ + θ) := by congr; field_simp [hθ]; linarith
+ _ = sin (2 * θ) * c + cos (2 * θ) * s := sin_add (2 * θ) θ
+ _ = 2 * s * c * c + cos (2 * θ) * s := by rw [sin_two_mul]
+ _ = 2 * s * c * c + (2 * c ^ 2 - 1) * s := by rw [cos_two_mul]
+ _ = s * (2 * c * c) + s * (2 * c ^ 2 - 1) := by linarith
+ _ = s * (4 * c ^ 2 - 1) := by linarith
+
+open Polynomial in
+theorem Polynomial.isRoot_cos_pi_div_five :
+ (4 • X ^ 2 - 2 • X - C 1 : ℝ[X]).IsRoot (cos (π / 5)) := by
+ simpa using quadratic_root_cos_pi_div_five
+
+/-- The cosine of `π / 5` is `(1 + √5) / 4`. -/
+@[simp]
+theorem cos_pi_div_five : cos (π / 5) = (1 + √5) / 4 := by
+ set c := cos (π / 5)
+ have : 4 * (c * c) + (-2) * c + (-1) = 0 := by
+ rw [← sq, neg_mul, ← sub_eq_add_neg, ← sub_eq_add_neg]
+ exact quadratic_root_cos_pi_div_five
+ have hd : discrim 4 (-2) (-1) = (2 * √5) * (2 * √5) := by norm_num [discrim, mul_mul_mul_comm]
+ rcases (quadratic_eq_zero_iff (by norm_num) hd c).mp this with h | h
+ · field_simp [h]; linarith
+ · absurd (show 0 ≤ c from cos_nonneg_of_mem_Icc <| by constructor <;> linarith [pi_pos.le])
+ rw [not_le, h]
+ exact div_neg_of_neg_of_pos (by norm_num [lt_sqrt]) (by positivity)
+
end CosDivSq
/-- `Real.sin` as an `OrderIso` between `[-(π / 2), π / 2]` and `[-1, 1]`. -/
diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean
index e0595d589e11d..f3a9858bddf37 100644
--- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean
@@ -173,11 +173,9 @@ theorem lt_tan {x : ℝ} (h1 : 0 < x) (h2 : x < π / 2) : x < tan x := by
let U := Ico 0 (π / 2)
have intU : interior U = Ioo 0 (π / 2) := interior_Ico
have half_pi_pos : 0 < π / 2 := div_pos pi_pos two_pos
- have cos_pos : ∀ {y : ℝ}, y ∈ U → 0 < cos y := by
- intro y hy
+ have cos_pos {y : ℝ} (hy : y ∈ U) : 0 < cos y := by
exact cos_pos_of_mem_Ioo (Ico_subset_Ioo_left (neg_lt_zero.mpr half_pi_pos) hy)
- have sin_pos : ∀ {y : ℝ}, y ∈ interior U → 0 < sin y := by
- intro y hy
+ have sin_pos {y : ℝ} (hy : y ∈ interior U) : 0 < sin y := by
rw [intU] at hy
exact sin_pos_of_mem_Ioo (Ioo_subset_Ioo_right (div_le_self pi_pos.le one_le_two) hy)
have tan_cts_U : ContinuousOn tan U := by
@@ -186,8 +184,7 @@ theorem lt_tan {x : ℝ} (h1 : 0 < x) (h2 : x < π / 2) : x < tan x := by
simp only [mem_setOf_eq]
exact (cos_pos hz).ne'
have tan_minus_id_cts : ContinuousOn (fun y : ℝ => tan y - y) U := tan_cts_U.sub continuousOn_id
- have deriv_pos : ∀ y : ℝ, y ∈ interior U → 0 < deriv (fun y' : ℝ => tan y' - y') y := by
- intro y hy
+ have deriv_pos (y : ℝ) (hy : y ∈ interior U) : 0 < deriv (fun y' : ℝ => tan y' - y') y := by
have := cos_pos (interior_subset hy)
simp only [deriv_tan_sub_id y this.ne', one_div, gt_iff_lt, sub_pos]
norm_cast
@@ -195,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/Complex.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Complex.lean
index ece140bac4b05..34180b091bfb1 100644
--- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Complex.lean
+++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Complex.lean
@@ -172,7 +172,7 @@ theorem cos_eq_iff_quadratic {z w : ℂ} :
theorem cos_surjective : Function.Surjective cos := by
intro x
- obtain ⟨w, w₀, hw⟩ : ∃ w ≠ 0, 1 * w * w + -2 * x * w + 1 = 0 := by
+ obtain ⟨w, w₀, hw⟩ : ∃ w ≠ 0, 1 * (w * w) + -2 * x * w + 1 = 0 := by
rcases exists_quadratic_eq_zero one_ne_zero
⟨_, (cpow_nat_inv_pow _ two_ne_zero).symm.trans <| pow_two _⟩ with
⟨w, hw⟩
diff --git a/Mathlib/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 5b3478e93056c..e06aef0a9c56a 100644
--- a/Mathlib/Analysis/SpecificLimits/Basic.lean
+++ b/Mathlib/Analysis/SpecificLimits/Basic.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel, Johannes Hölzl, Yury Kudryashov, Patrick Massot
-/
import Mathlib.Algebra.GeomSum
-import Mathlib.Order.Filter.Archimedean
+import Mathlib.Order.Filter.AtTopBot.Archimedean
import Mathlib.Order.Iterate
import Mathlib.Topology.Algebra.Algebra
import Mathlib.Topology.Algebra.InfiniteSum.Real
@@ -114,12 +114,59 @@ 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 -/
theorem tendsto_add_one_pow_atTop_atTop_of_pos [LinearOrderedSemiring α] [Archimedean α] {r : α}
(h : 0 < r) : Tendsto (fun n : ℕ ↦ (r + 1) ^ n) atTop atTop :=
- tendsto_atTop_atTop_of_monotone' (fun _ _ ↦ pow_le_pow_right <| le_add_of_nonneg_left h.le) <|
+ tendsto_atTop_atTop_of_monotone' (pow_right_mono₀ <| le_add_of_nonneg_left h.le) <|
not_bddAbove_iff.2 fun _ ↦ Set.exists_range_iff.2 <| add_one_pow_unbounded_of_pos _ h
theorem tendsto_pow_atTop_atTop_of_one_lt [LinearOrderedRing α] [Archimedean α] {r : α}
@@ -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
@@ -252,7 +299,7 @@ protected theorem ENNReal.tendsto_pow_atTop_nhds_top_iff {r : ℝ≥0∞} :
specialize h_tends (Ioi_mem_nhds one_lt_top)
simp only [Filter.mem_map, mem_atTop_sets, ge_iff_le, Set.mem_preimage, Set.mem_Ioi] at h_tends
obtain ⟨n, hn⟩ := h_tends
- exact lt_irrefl _ <| lt_of_lt_of_le (hn n le_rfl) <| pow_le_one n (zero_le _) r_le_one
+ exact lt_irrefl _ <| lt_of_lt_of_le (hn n le_rfl) <| pow_le_one₀ (zero_le _) r_le_one
· intro r_gt_one
have obs := @Tendsto.inv ℝ≥0∞ ℕ _ _ _ (fun n ↦ (r⁻¹)^n) atTop 0
simp only [ENNReal.tendsto_pow_atTop_nhds_zero_iff, inv_zero] at obs
@@ -360,7 +407,7 @@ theorem ENNReal.tsum_geometric (r : ℝ≥0∞) : ∑' n : ℕ, r ^ n = (1 - r)
(ENNReal.exists_nat_gt (lt_top_iff_ne_top.1 ha)).imp fun n hn ↦ lt_of_lt_of_le hn ?_
calc
(n : ℝ≥0∞) = ∑ i ∈ range n, 1 := by rw [sum_const, nsmul_one, card_range]
- _ ≤ ∑ i ∈ range n, r ^ i := by gcongr; apply one_le_pow_of_one_le' hr
+ _ ≤ ∑ i ∈ range n, r ^ i := by gcongr; apply one_le_pow₀ hr
theorem ENNReal.tsum_geometric_add_one (r : ℝ≥0∞) : ∑' n : ℕ, r ^ (n + 1) = r * (1 - r)⁻¹ := by
simp only [_root_.pow_succ', ENNReal.tsum_mul_left, ENNReal.tsum_geometric]
@@ -513,7 +560,7 @@ theorem summable_one_div_pow_of_le {m : ℝ} {f : ℕ → ℕ} (hm : 1 < m) (fi
(summable_geometric_of_lt_one (one_div_nonneg.mpr (zero_le_one.trans hm.le))
((one_div_lt (zero_lt_one.trans hm) zero_lt_one).mpr (one_div_one.le.trans_lt hm)))
rw [div_pow, one_pow]
- refine (one_div_le_one_div ?_ ?_).mpr (pow_le_pow_right hm.le (fi a)) <;>
+ refine (one_div_le_one_div ?_ ?_).mpr (pow_right_mono₀ hm.le (fi a)) <;>
exact pow_pos (zero_lt_one.trans hm) _
/-! ### Positive sequences with small sums on countable types -/
diff --git a/Mathlib/Analysis/SpecificLimits/FloorPow.lean b/Mathlib/Analysis/SpecificLimits/FloorPow.lean
index 0916d04a949a1..6d020f15e36d5 100644
--- a/Mathlib/Analysis/SpecificLimits/FloorPow.lean
+++ b/Mathlib/Analysis/SpecificLimits/FloorPow.lean
@@ -195,8 +195,7 @@ theorem tendsto_div_of_monotone_of_tendsto_div_floor_pow (u : ℕ → ℝ) (l :
have H : ∀ n : ℕ, (0 : ℝ) < ⌊c k ^ n⌋₊ := by
intro n
refine zero_lt_one.trans_le ?_
- simp only [Real.rpow_natCast, Nat.one_le_cast, Nat.one_le_floor_iff,
- one_le_pow_of_one_le (cone k).le n]
+ simp only [Real.rpow_natCast, Nat.one_le_cast, Nat.one_le_floor_iff, one_le_pow₀ (cone k).le]
have A :
Tendsto (fun n : ℕ => (⌊c k ^ (n + 1)⌋₊ : ℝ) / c k ^ (n + 1) * c k / (⌊c k ^ n⌋₊ / c k ^ n))
atTop (𝓝 (1 * c k / 1)) := by
@@ -217,27 +216,27 @@ 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_le_pow_right 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
+ 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_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
- simp only [hi.1, mem_Ico, and_true_iff]
+ simp only [hi.1, mem_Ico, and_true]
apply Nat.floor_le_of_le
apply le_of_lt
- rw [div_lt_iff (Real.log_pos hc), ← Real.log_pow]
+ rw [div_lt_iff₀ (Real.log_pos hc), ← Real.log_pow]
exact Real.log_lt_log hj hi.2
_ = ∑ i ∈ Ico ⌊Real.log j / Real.log c⌋₊ N, (c⁻¹ ^ 2) ^ i := by
congr 1 with i
@@ -258,7 +257,7 @@ theorem sum_div_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : ℝ} (hc
field_simp [(Real.log_pos hc).ne']
ring
rw [Real.rpow_sub A, I]
- have : c ^ 2 - 1 ≠ 0 := (sub_pos.2 (one_lt_pow hc two_ne_zero)).ne'
+ have : c ^ 2 - 1 ≠ 0 := (sub_pos.2 (one_lt_pow₀ hc two_ne_zero)).ne'
field_simp [hj.ne', (zero_lt_one.trans hc).ne']
ring
_ ≤ c ^ 3 * (c - 1)⁻¹ / j ^ 2 := by gcongr
@@ -271,28 +270,27 @@ theorem mul_pow_le_nat_floor_pow {c : ℝ} (hc : 1 < c) (i : ℕ) : (1 - c⁻¹)
(1 - c⁻¹) * c ^ i = c ^ i - c ^ i * c⁻¹ := by ring
_ ≤ c ^ i - 1 := by
gcongr
- simpa only [← div_eq_mul_inv, one_le_div cpos, pow_one] using le_self_pow hc.le hi
+ simpa only [← div_eq_mul_inv, one_le_div cpos, pow_one] using le_self_pow₀ hc.le hi
_ ≤ ⌊c ^ i⌋₊ := (Nat.sub_one_lt_floor _).le
/-- 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
refine zero_lt_one.trans_le ?_
- simp only [Nat.le_floor, one_le_pow_of_one_le, hc.le, Nat.one_le_cast, Nat.cast_one]
+ simp only [Nat.le_floor, one_le_pow₀, hc.le, Nat.one_le_cast, Nat.cast_one]
· exact sq_pos_of_pos (pow_pos cpos _)
rw [one_mul, ← mul_pow]
gcongr
diff --git a/Mathlib/Analysis/SpecificLimits/Normed.lean b/Mathlib/Analysis/SpecificLimits/Normed.lean
index c46af42ab84e6..0486eff13103d 100644
--- a/Mathlib/Analysis/SpecificLimits/Normed.lean
+++ b/Mathlib/Analysis/SpecificLimits/Normed.lean
@@ -4,14 +4,15 @@ 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
import Mathlib.Analysis.SpecificLimits.Basic
import Mathlib.Data.List.TFAE
import Mathlib.Data.Nat.Choose.Bounds
-import Mathlib.Order.Filter.ModEq
+import Mathlib.Order.Filter.AtTopBot.ModEq
import Mathlib.RingTheory.Polynomial.Pochhammer
import Mathlib.Tactic.NoncommRing
@@ -20,74 +21,16 @@ import Mathlib.Tactic.NoncommRing
This file contains important specific limit computations in (semi-)normed groups/rings/spaces, as
well as such computations in `ℝ` when the natural proof passes through a fact about normed spaces.
-
-/
-
noncomputable section
-open scoped Classical
-open Set Function Filter Finset Metric Asymptotics
-
-open scoped Classical
-open Topology Nat uniformity NNReal ENNReal
-
-variable {α : Type*} {β : Type*} {ι : Type*}
+open Set Function Filter Finset Metric Asymptotics Topology Nat NNReal ENNReal
-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₂
@@ -130,52 +73,43 @@ theorem TFAE_exists_lt_isLittleO_pow (f : ℕ → ℝ) (R : ℝ) :
fun x hx ↦ ⟨(neg_lt_zero.2 (hx.1.trans_lt hx.2)).trans_le hx.1, hx.2⟩
have B : Ioo 0 R ⊆ Ioo (-R) R := Subset.trans Ioo_subset_Ico_self A
-- First we prove that 1-4 are equivalent using 2 → 3 → 4, 1 → 3, and 2 → 1
- tfae_have 1 → 3
- · exact fun ⟨a, ha, H⟩ ↦ ⟨a, ha, H.isBigO⟩
- tfae_have 2 → 1
- · exact fun ⟨a, ha, H⟩ ↦ ⟨a, B ha, H⟩
+ tfae_have 1 → 3 := fun ⟨a, ha, H⟩ ↦ ⟨a, ha, H.isBigO⟩
+ tfae_have 2 → 1 := fun ⟨a, ha, H⟩ ↦ ⟨a, B ha, H⟩
tfae_have 3 → 2
- · rintro ⟨a, ha, H⟩
+ | ⟨a, ha, H⟩ => by
rcases exists_between (abs_lt.2 ha) with ⟨b, hab, hbR⟩
exact ⟨b, ⟨(abs_nonneg a).trans_lt hab, hbR⟩,
H.trans_isLittleO (isLittleO_pow_pow_of_abs_lt_left (hab.trans_le (le_abs_self b)))⟩
- tfae_have 2 → 4
- · exact fun ⟨a, ha, H⟩ ↦ ⟨a, ha, H.isBigO⟩
- tfae_have 4 → 3
- · exact fun ⟨a, ha, H⟩ ↦ ⟨a, B ha, H⟩
+ tfae_have 2 → 4 := fun ⟨a, ha, H⟩ ↦ ⟨a, ha, H.isBigO⟩
+ tfae_have 4 → 3 := fun ⟨a, ha, H⟩ ↦ ⟨a, B ha, H⟩
-- Add 5 and 6 using 4 → 6 → 5 → 3
tfae_have 4 → 6
- · rintro ⟨a, ha, H⟩
+ | ⟨a, ha, H⟩ => by
rcases bound_of_isBigO_nat_atTop H with ⟨C, hC₀, hC⟩
refine ⟨a, ha, C, hC₀, fun n ↦ ?_⟩
simpa only [Real.norm_eq_abs, abs_pow, abs_of_nonneg ha.1.le] using hC (pow_ne_zero n ha.1.ne')
- tfae_have 6 → 5
- · exact fun ⟨a, ha, C, H₀, H⟩ ↦ ⟨a, ha.2, C, Or.inl H₀, H⟩
+ tfae_have 6 → 5 := fun ⟨a, ha, C, H₀, H⟩ ↦ ⟨a, ha.2, C, Or.inl H₀, H⟩
tfae_have 5 → 3
- · rintro ⟨a, ha, C, h₀, H⟩
+ | ⟨a, ha, C, h₀, H⟩ => by
rcases sign_cases_of_C_mul_pow_nonneg fun n ↦ (abs_nonneg _).trans (H n) with (rfl | ⟨hC₀, ha₀⟩)
· obtain rfl : f = 0 := by
ext n
simpa using H n
- simp only [lt_irrefl, false_or_iff] at h₀
+ simp only [lt_irrefl, false_or] at h₀
exact ⟨0, ⟨neg_lt_zero.2 h₀, h₀⟩, isBigO_zero _ _⟩
exact ⟨a, A ⟨ha₀, ha⟩,
isBigO_of_le' _ fun n ↦ (H n).trans <| mul_le_mul_of_nonneg_left (le_abs_self _) hC₀.le⟩
-- Add 7 and 8 using 2 → 8 → 7 → 3
tfae_have 2 → 8
- · rintro ⟨a, ha, H⟩
+ | ⟨a, ha, H⟩ => by
refine ⟨a, ha, (H.def zero_lt_one).mono fun n hn ↦ ?_⟩
rwa [Real.norm_eq_abs, Real.norm_eq_abs, one_mul, abs_pow, abs_of_pos ha.1] at hn
- tfae_have 8 → 7
- · exact fun ⟨a, ha, H⟩ ↦ ⟨a, ha.2, H⟩
+ tfae_have 8 → 7 := fun ⟨a, ha, H⟩ ↦ ⟨a, ha.2, H⟩
tfae_have 7 → 3
- · rintro ⟨a, ha, H⟩
+ | ⟨a, ha, H⟩ => by
have : 0 ≤ a := nonneg_of_eventually_pow_nonneg (H.mono fun n ↦ (abs_nonneg _).trans)
refine ⟨a, A ⟨this, ha⟩, IsBigO.of_bound 1 ?_⟩
simpa only [Real.norm_eq_abs, one_mul, abs_pow, abs_of_nonneg this]
- -- Porting note: used to work without explicitly having 6 → 7
- tfae_have 6 → 7
- · exact fun h ↦ tfae_8_to_7 <| tfae_2_to_8 <| tfae_3_to_2 <| tfae_5_to_3 <| tfae_6_to_5 h
tfae_finish
/-- For any natural `k` and a real `r > 1` we have `n ^ k = o(r ^ n)` as `n → ∞`. -/
@@ -212,7 +146,7 @@ theorem isLittleO_pow_const_mul_const_pow_const_pow_of_norm_lt {R : Type*} [Norm
have A : (fun n ↦ (n : R) ^ k : ℕ → R) =o[atTop] fun n ↦ (r₂ / ‖r₁‖) ^ n :=
isLittleO_pow_const_const_pow_of_one_lt k ((one_lt_div h0).2 h)
suffices (fun n ↦ r₁ ^ n) =O[atTop] fun n ↦ ‖r₁‖ ^ n by
- simpa [div_mul_cancel₀ _ (pow_pos h0 _).ne'] using A.mul_isBigO this
+ simpa [div_mul_cancel₀ _ (pow_pos h0 _).ne', div_pow] using A.mul_isBigO this
exact IsBigO.of_bound 1 (by simpa using eventually_norm_pow_le r₁)
theorem tendsto_pow_const_div_const_pow_of_one_lt (k : ℕ) {r : ℝ} (hr : 1 < r) :
@@ -225,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'
@@ -264,6 +198,113 @@ alias tendsto_pow_atTop_nhds_0_of_abs_lt_1 := tendsto_pow_atTop_nhds_zero_of_abs
/-! ### Geometric series -/
+/-- 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 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]
+ {x : K} (h : ‖x‖ < 1) : Summable (fun n ↦ x ^ n) :=
+ HasSummableGeomSeries.summable_geometric_of_norm_lt_one x h
+
+instance {R : Type*} [NormedRing R] [CompleteSpace R] : HasSummableGeomSeries R := by
+ constructor
+ intro x hx
+ have h1 : Summable fun n : ℕ ↦ ‖x‖ ^ n := summable_geometric_of_lt_one (norm_nonneg _) hx
+ exact h1.of_norm_bounded_eventually_nat _ (eventually_norm_pow_le x)
+
+section HasSummableGeometricSeries
+
+variable {R : Type*} [NormedRing R]
+
+open NormedSpace
+
+/-- Bound for the sum of a geometric series in a normed ring. This formula does not assume that the
+normed ring satisfies the axiom `‖1‖ = 1`. -/
+theorem tsum_geometric_le_of_norm_lt_one (x : R) (h : ‖x‖ < 1) :
+ ‖∑' n : ℕ, x ^ n‖ ≤ ‖(1 : R)‖ - 1 + (1 - ‖x‖)⁻¹ := by
+ by_cases hx : Summable (fun n ↦ x ^ n)
+ · rw [tsum_eq_zero_add hx]
+ simp only [_root_.pow_zero]
+ refine le_trans (norm_add_le _ _) ?_
+ have : ‖∑' b : ℕ, (fun n ↦ x ^ (n + 1)) b‖ ≤ (1 - ‖x‖)⁻¹ - 1 := by
+ refine tsum_of_norm_bounded ?_ fun b ↦ norm_pow_le' _ (Nat.succ_pos b)
+ convert (hasSum_nat_add_iff' 1).mpr (hasSum_geometric_of_lt_one (norm_nonneg x) h)
+ simp
+ linarith
+ · simp [tsum_eq_zero_of_not_summable hx]
+ nontriviality R
+ have : 1 ≤ ‖(1 : R)‖ := one_le_norm_one R
+ have : 0 ≤ (1 - ‖x‖) ⁻¹ := inv_nonneg.2 (by linarith)
+ linarith
+
+variable [HasSummableGeomSeries R]
+
+@[deprecated (since := "2024-01-31")]
+alias NormedRing.tsum_geometric_of_norm_lt_1 := tsum_geometric_le_of_norm_lt_one
+
+@[deprecated (since := "2024-07-27")]
+alias NormedRing.tsum_geometric_of_norm_lt_one := tsum_geometric_le_of_norm_lt_one
+
+theorem geom_series_mul_neg (x : R) (h : ‖x‖ < 1) : (∑' i : ℕ, x ^ i) * (1 - x) = 1 := by
+ have := (summable_geometric_of_norm_lt_one h).hasSum.mul_right (1 - x)
+ refine tendsto_nhds_unique this.tendsto_sum_nat ?_
+ have : Tendsto (fun n : ℕ ↦ 1 - x ^ n) atTop (𝓝 1) := by
+ simpa using tendsto_const_nhds.sub (tendsto_pow_atTop_nhds_zero_of_norm_lt_one h)
+ convert← this
+ rw [← geom_sum_mul_neg, Finset.sum_mul]
+
+theorem mul_neg_geom_series (x : R) (h : ‖x‖ < 1) : (1 - x) * ∑' i : ℕ, x ^ i = 1 := by
+ have := (summable_geometric_of_norm_lt_one h).hasSum.mul_left (1 - x)
+ refine tendsto_nhds_unique this.tendsto_sum_nat ?_
+ have : Tendsto (fun n : ℕ ↦ 1 - x ^ n) atTop (𝓝 1) := by
+ simpa using tendsto_const_nhds.sub (tendsto_pow_atTop_nhds_zero_of_norm_lt_one h)
+ convert← this
+ rw [← mul_neg_geom_sum, Finset.mul_sum]
+
+theorem geom_series_succ (x : R) (h : ‖x‖ < 1) : ∑' i : ℕ, x ^ (i + 1) = ∑' i : ℕ, x ^ i - 1 := by
+ rw [eq_sub_iff_add_eq, tsum_eq_zero_add (summable_geometric_of_norm_lt_one h),
+ pow_zero, add_comm]
+
+theorem geom_series_mul_shift (x : R) (h : ‖x‖ < 1) :
+ x * ∑' i : ℕ, x ^ i = ∑' i : ℕ, x ^ (i + 1) := by
+ simp_rw [← (summable_geometric_of_norm_lt_one h).tsum_mul_left, ← _root_.pow_succ']
+
+theorem geom_series_mul_one_add (x : R) (h : ‖x‖ < 1) :
+ (1 + x) * ∑' i : ℕ, x ^ i = 2 * ∑' i : ℕ, x ^ i - 1 := by
+ rw [add_mul, one_mul, geom_series_mul_shift x h, geom_series_succ x h, two_mul, add_sub_assoc]
+
+/-- In a normed ring with summable geometric series, a perturbation of `1` by an element `t`
+of distance less than `1` from `1` is a unit. Here we construct its `Units` structure. -/
+@[simps val]
+def Units.oneSub (t : R) (h : ‖t‖ < 1) : Rˣ where
+ val := 1 - t
+ inv := ∑' n : ℕ, t ^ n
+ val_inv := mul_neg_geom_series t h
+ inv_val := geom_series_mul_neg t h
+
+theorem geom_series_eq_inverse (x : R) (h : ‖x‖ < 1) :
+ ∑' i, x ^ i = Ring.inverse (1 - x) := by
+ change (Units.oneSub x h) ⁻¹ = Ring.inverse (1 - x)
+ rw [← Ring.inverse_unit]
+ rfl
+
+theorem hasSum_geom_series_inverse (x : R) (h : ‖x‖ < 1) :
+ HasSum (fun i ↦ x ^ i) (Ring.inverse (1 - x)) := by
+ convert (summable_geometric_of_norm_lt_one h).hasSum
+ exact (geom_series_eq_inverse x h).symm
+
+lemma isUnit_one_sub_of_norm_lt_one {x : R} (h : ‖x‖ < 1) : IsUnit (1 - x) :=
+ ⟨Units.oneSub x h, rfl⟩
+
+end HasSummableGeometricSeries
+
+@[deprecated (since := "2024-01-31")]
+alias NormedRing.summable_geometric_of_norm_lt_1 := summable_geometric_of_norm_lt_one
+
+@[deprecated (since := "2024-07-27")]
+alias NormedRing.summable_geometric_of_norm_lt_one := summable_geometric_of_norm_lt_one
section Geometric
@@ -282,8 +323,8 @@ theorem hasSum_geometric_of_norm_lt_one (h : ‖ξ‖ < 1) : HasSum (fun n : ℕ
@[deprecated (since := "2024-01-31")]
alias hasSum_geometric_of_norm_lt_1 := hasSum_geometric_of_norm_lt_one
-theorem summable_geometric_of_norm_lt_one (h : ‖ξ‖ < 1) : Summable fun n : ℕ ↦ ξ ^ n :=
- ⟨_, hasSum_geometric_of_norm_lt_one h⟩
+instance : HasSummableGeomSeries K :=
+ ⟨fun _ h ↦ (hasSum_geometric_of_norm_lt_one h).summable⟩
@[deprecated (since := "2024-01-31")]
alias summable_geometric_of_norm_lt_1 := summable_geometric_of_norm_lt_one
@@ -331,7 +372,9 @@ end Geometric
section MulGeometric
-theorem summable_norm_mul_geometric_of_norm_lt_one {R : Type*} [NormedRing R] {k : ℕ} {r : R}
+variable {R : Type*} [NormedRing R] {𝕜 : Type*} [NormedDivisionRing 𝕜]
+
+theorem summable_norm_mul_geometric_of_norm_lt_one {k : ℕ} {r : R}
(hr : ‖r‖ < 1) {u : ℕ → ℕ} (hu : (fun n ↦ (u n : ℝ)) =O[atTop] (fun n ↦ (↑(n ^ k) : ℝ))) :
Summable fun n : ℕ ↦ ‖(u n * r ^ n : R)‖ := by
rcases exists_between hr with ⟨r', hrr', h⟩
@@ -346,35 +389,29 @@ theorem summable_norm_mul_geometric_of_norm_lt_one {R : Type*} [NormedRing R] {k
apply (norm_mul_le _ _).trans
have : ‖(u n : R)‖ * ‖r ^ n‖ ≤ (u n * ‖(1 : R)‖) * ‖r‖ ^ n := by
gcongr; exact norm_cast_le (u n)
- exact this.trans_eq (by ring)
+ exact this.trans (le_of_eq (by ring))
_ =O[atTop] fun n ↦ ↑(n ^ k) * ‖r‖ ^ n := hu.mul (isBigO_refl _ _)
_ =O[atTop] fun n ↦ r' ^ n := by
simp only [cast_pow]
exact (isLittleO_pow_const_mul_const_pow_const_pow_of_norm_lt k hrr').isBigO
-theorem summable_norm_pow_mul_geometric_of_norm_lt_one {R : Type*} [NormedRing R] (k : ℕ) {r : R}
+theorem summable_norm_pow_mul_geometric_of_norm_lt_one (k : ℕ) {r : R}
(hr : ‖r‖ < 1) : Summable fun n : ℕ ↦ ‖((n : R) ^ k * r ^ n : R)‖ := by
simp only [← cast_pow]
exact summable_norm_mul_geometric_of_norm_lt_one (k := k) (u := fun n ↦ n ^ k) hr
(isBigO_refl _ _)
-theorem summable_norm_geometric_of_norm_lt_one {R : Type*} [NormedRing R] {r : R}
+theorem summable_norm_geometric_of_norm_lt_one {r : R}
(hr : ‖r‖ < 1) : Summable fun n : ℕ ↦ ‖(r ^ n : R)‖ := by
simpa using summable_norm_pow_mul_geometric_of_norm_lt_one 0 hr
-@[deprecated (since := "2024-01-31")]
-alias summable_norm_pow_mul_geometric_of_norm_lt_1 := summable_norm_pow_mul_geometric_of_norm_lt_one
+variable [HasSummableGeomSeries R]
-variable {𝕜 : Type*} [NormedDivisionRing 𝕜]
-
-/-- The sum of `(n+k).choose k * r^n` is `1/(1-r)^{k+1}`.
-See also `PowerSeries.invOneSubPow_val_eq_mk_choose_add` for the corresponding statement in formal
-power series, without summability arguments. -/
-lemma hasSum_choose_mul_geometric_of_norm_lt_one
- (k : ℕ) {r : 𝕜} (hr : ‖r‖ < 1) :
- HasSum (fun n ↦ (n + k).choose k * r ^ n) (1 / (1 - r) ^ (k + 1)) := by
+lemma hasSum_choose_mul_geometric_of_norm_lt_one'
+ (k : ℕ) {r : R} (hr : ‖r‖ < 1) :
+ HasSum (fun n ↦ (n + k).choose k * r ^ n) (Ring.inverse (1 - r) ^ (k + 1)) := by
induction k with
- | zero => simpa using hasSum_geometric_of_norm_lt_one hr
+ | zero => simpa using hasSum_geom_series_inverse r hr
| succ k ih =>
have I1 : Summable (fun (n : ℕ) ↦ ‖(n + k).choose k * r ^ n‖) := by
apply summable_norm_mul_geometric_of_norm_lt_one (k := k) hr
@@ -387,34 +424,42 @@ lemma hasSum_choose_mul_geometric_of_norm_lt_one
_ ≤ (2 * n) ^ k := Nat.choose_le_pow _ _
_ = 2 ^ k * n ^ k := Nat.mul_pow 2 n k
convert hasSum_sum_range_mul_of_summable_norm' I1 ih.summable
- (summable_norm_geometric_of_norm_lt_one hr) (summable_geometric_of_norm_lt_one hr) using 1
- · ext n
- have : ∑ i ∈ Finset.range (n + 1), ↑((i + k).choose k) * r ^ i * r ^ (n - i) =
+ (summable_norm_geometric_of_norm_lt_one hr) (summable_geometric_of_norm_lt_one hr) with n
+ · have : ∑ i ∈ Finset.range (n + 1), ↑((i + k).choose k) * r ^ i * r ^ (n - i) =
∑ i ∈ Finset.range (n + 1), ↑((i + k).choose k) * r ^ n := by
apply Finset.sum_congr rfl (fun i hi ↦ ?_)
simp only [Finset.mem_range] at hi
rw [mul_assoc, ← pow_add, show i + (n - i) = n by omega]
- simp_rw [this, ← sum_mul, ← Nat.cast_sum, sum_range_add_choose n k, add_assoc]
- · rw [ih.tsum_eq, (hasSum_geometric_of_norm_lt_one hr).tsum_eq, pow_succ]
- simp only [one_div, ← mul_inv_rev, ← pow_succ, ← _root_.pow_succ']
+ simp [this, ← sum_mul, ← Nat.cast_sum, sum_range_add_choose n k, add_assoc]
+ · rw [ih.tsum_eq, (hasSum_geom_series_inverse r hr).tsum_eq, pow_succ]
-lemma summable_choose_mul_geometric_of_norm_lt_one (k : ℕ) {r : 𝕜} (hr : ‖r‖ < 1) :
+lemma summable_choose_mul_geometric_of_norm_lt_one (k : ℕ) {r : R} (hr : ‖r‖ < 1) :
Summable (fun n ↦ (n + k).choose k * r ^ n) :=
- (hasSum_choose_mul_geometric_of_norm_lt_one k hr).summable
+ (hasSum_choose_mul_geometric_of_norm_lt_one' k hr).summable
+
+lemma tsum_choose_mul_geometric_of_norm_lt_one' (k : ℕ) {r : R} (hr : ‖r‖ < 1) :
+ ∑' n, (n + k).choose k * r ^ n = (Ring.inverse (1 - r)) ^ (k + 1) :=
+ (hasSum_choose_mul_geometric_of_norm_lt_one' k hr).tsum_eq
+
+lemma hasSum_choose_mul_geometric_of_norm_lt_one
+ (k : ℕ) {r : 𝕜} (hr : ‖r‖ < 1) :
+ HasSum (fun n ↦ (n + k).choose k * r ^ n) (1 / (1 - r) ^ (k + 1)) := by
+ convert hasSum_choose_mul_geometric_of_norm_lt_one' k hr
+ simp
lemma tsum_choose_mul_geometric_of_norm_lt_one (k : ℕ) {r : 𝕜} (hr : ‖r‖ < 1) :
- ∑' n, (n + k).choose k * r ^ n = 1 / (1 - r) ^ (k + 1) :=
+ ∑' n, (n + k).choose k * r ^ n = 1/ (1 - r) ^ (k + 1) :=
(hasSum_choose_mul_geometric_of_norm_lt_one k hr).tsum_eq
-lemma summable_descFactorial_mul_geometric_of_norm_lt_one (k : ℕ) {r : 𝕜} (hr : ‖r‖ < 1) :
+lemma summable_descFactorial_mul_geometric_of_norm_lt_one (k : ℕ) {r : R} (hr : ‖r‖ < 1) :
Summable (fun n ↦ (n + k).descFactorial k * r ^ n) := by
- convert (summable_choose_mul_geometric_of_norm_lt_one k hr).mul_left (k.factorial : 𝕜)
+ convert (summable_choose_mul_geometric_of_norm_lt_one k hr).mul_left (k.factorial : R)
using 2 with n
simp [← mul_assoc, descFactorial_eq_factorial_mul_choose (n + k) k]
open Polynomial in
-theorem summable_pow_mul_geometric_of_norm_lt_one (k : ℕ) {r : 𝕜} (hr : ‖r‖ < 1) :
- Summable (fun n ↦ (n : 𝕜) ^ k * r ^ n : ℕ → 𝕜) := by
+theorem summable_pow_mul_geometric_of_norm_lt_one (k : ℕ) {r : R} (hr : ‖r‖ < 1) :
+ Summable (fun n ↦ (n : R) ^ k * r ^ n : ℕ → R) := by
refine Nat.strong_induction_on k fun k hk => ?_
obtain ⟨a, ha⟩ : ∃ (a : ℕ → ℕ), ∀ n, (n + k).descFactorial k
= n ^ k + ∑ i ∈ range k, a i * n ^ i := by
@@ -439,37 +484,50 @@ theorem summable_pow_mul_geometric_of_norm_lt_one (k : ℕ) {r : 𝕜} (hr : ‖
ext n
simp [ha n, add_mul, sum_mul]
+@[deprecated (since := "2024-01-31")]
+alias summable_norm_pow_mul_geometric_of_norm_lt_1 := summable_norm_pow_mul_geometric_of_norm_lt_one
+
@[deprecated (since := "2024-01-31")]
alias summable_pow_mul_geometric_of_norm_lt_1 := summable_pow_mul_geometric_of_norm_lt_one
-/-- If `‖r‖ < 1`, then `∑' n : ℕ, n * r ^ n = r / (1 - r) ^ 2`, `HasSum` version. -/
-theorem hasSum_coe_mul_geometric_of_norm_lt_one
- {r : 𝕜} (hr : ‖r‖ < 1) : HasSum (fun n ↦ n * r ^ n : ℕ → 𝕜) (r / (1 - r) ^ 2) := by
- have A : HasSum (fun (n : ℕ) ↦ (n + 1) * r ^ n) (1 / (1 - r) ^ 2) := by
- convert hasSum_choose_mul_geometric_of_norm_lt_one 1 hr with n
+/-- If `‖r‖ < 1`, then `∑' n : ℕ, n * r ^ n = r / (1 - r) ^ 2`, `HasSum` version in a general ring
+with summable geometric series. For a version in a field, using division instead of `Ring.inverse`,
+see `hasSum_coe_mul_geometric_of_norm_lt_one`. -/
+theorem hasSum_coe_mul_geometric_of_norm_lt_one'
+ {x : R} (h : ‖x‖ < 1) :
+ HasSum (fun n ↦ n * x ^ n : ℕ → R) (x * (Ring.inverse (1 - x)) ^ 2) := by
+ have A : HasSum (fun (n : ℕ) ↦ (n + 1) * x ^ n) (Ring.inverse (1 - x) ^ 2) := by
+ convert hasSum_choose_mul_geometric_of_norm_lt_one' 1 h with n
simp
- have B : HasSum (fun (n : ℕ) ↦ r ^ n) ((1 - r) ⁻¹) := hasSum_geometric_of_norm_lt_one hr
+ have B : HasSum (fun (n : ℕ) ↦ x ^ n) (Ring.inverse (1 - x)) := hasSum_geom_series_inverse x h
convert A.sub B using 1
· ext n
simp [add_mul]
· symm
- calc 1 / (1 - r) ^ 2 - (1 - r) ⁻¹
- _ = 1 / (1 - r) ^ 2 - ((1 - r) * (1 - r) ⁻¹) * (1 - r) ⁻¹ := by
- rw [mul_inv_cancel₀, one_mul]
- intro h
- simp only [sub_eq_zero] at h
- simp [← h] at hr
- _ = r / (1 - r) ^ 2 := by
- simp only [one_div, mul_assoc, ← mul_inv_rev]
- rw [inv_eq_one_div, inv_eq_one_div, ← pow_two, _root_.sub_mul, one_mul, mul_div, mul_one]
- abel
+ calc Ring.inverse (1 - x) ^ 2 - Ring.inverse (1 - x)
+ _ = Ring.inverse (1 - x) ^ 2 - ((1 - x) * Ring.inverse (1 - x)) * Ring.inverse (1 - x) := by
+ simp [Ring.mul_inverse_cancel (1 - x) (isUnit_one_sub_of_norm_lt_one h)]
+ _ = x * Ring.inverse (1 - x) ^ 2 := by noncomm_ring
+
+/-- If `‖r‖ < 1`, then `∑' n : ℕ, n * r ^ n = r / (1 - r) ^ 2`, version in a general ring with
+summable geometric series. For a version in a field, using division instead of `Ring.inverse`,
+see `tsum_coe_mul_geometric_of_norm_lt_one`. -/
+theorem tsum_coe_mul_geometric_of_norm_lt_one'
+ {r : 𝕜} (hr : ‖r‖ < 1) : (∑' n : ℕ, n * r ^ n : 𝕜) = r * Ring.inverse (1 - r) ^ 2 :=
+ (hasSum_coe_mul_geometric_of_norm_lt_one' hr).tsum_eq
+
+/-- If `‖r‖ < 1`, then `∑' n : ℕ, n * r ^ n = r / (1 - r) ^ 2`, `HasSum` version. -/
+theorem hasSum_coe_mul_geometric_of_norm_lt_one {r : 𝕜} (hr : ‖r‖ < 1) :
+ HasSum (fun n ↦ n * r ^ n : ℕ → 𝕜) (r / (1 - r) ^ 2) := by
+ convert hasSum_coe_mul_geometric_of_norm_lt_one' hr using 1
+ simp [div_eq_mul_inv]
@[deprecated (since := "2024-01-31")]
alias hasSum_coe_mul_geometric_of_norm_lt_1 := hasSum_coe_mul_geometric_of_norm_lt_one
/-- If `‖r‖ < 1`, then `∑' n : ℕ, n * r ^ n = r / (1 - r) ^ 2`. -/
-theorem tsum_coe_mul_geometric_of_norm_lt_one
- {r : 𝕜} (hr : ‖r‖ < 1) : (∑' n : ℕ, n * r ^ n : 𝕜) = r / (1 - r) ^ 2 :=
+theorem tsum_coe_mul_geometric_of_norm_lt_one {r : 𝕜} (hr : ‖r‖ < 1) :
+ (∑' n : ℕ, n * r ^ n : 𝕜) = r / (1 - r) ^ 2 :=
(hasSum_coe_mul_geometric_of_norm_lt_one hr).tsum_eq
@[deprecated (since := "2024-01-31")]
@@ -553,67 +611,6 @@ lemma exists_norm_le_of_cauchySeq (h : CauchySeq fun n ↦ ∑ k ∈ range n, f
end SummableLeGeometric
-section NormedRingGeometric
-
-variable {R : Type*} [NormedRing R] [CompleteSpace R]
-
-open NormedSpace
-
-/-- A geometric series in a complete normed ring is summable.
-Proved above (same name, different namespace) for not-necessarily-complete normed fields. -/
-theorem NormedRing.summable_geometric_of_norm_lt_one (x : R) (h : ‖x‖ < 1) :
- Summable fun n : ℕ ↦ x ^ n :=
- have h1 : Summable fun n : ℕ ↦ ‖x‖ ^ n := summable_geometric_of_lt_one (norm_nonneg _) h
- h1.of_norm_bounded_eventually_nat _ (eventually_norm_pow_le x)
-@[deprecated (since := "2024-01-31")]
-alias NormedRing.summable_geometric_of_norm_lt_1 := NormedRing.summable_geometric_of_norm_lt_one
-
-/-- Bound for the sum of a geometric series in a normed ring. This formula does not assume that the
-normed ring satisfies the axiom `‖1‖ = 1`. -/
-theorem NormedRing.tsum_geometric_of_norm_lt_one (x : R) (h : ‖x‖ < 1) :
- ‖∑' n : ℕ, x ^ n‖ ≤ ‖(1 : R)‖ - 1 + (1 - ‖x‖)⁻¹ := by
- rw [tsum_eq_zero_add (summable_geometric_of_norm_lt_one x h)]
- simp only [_root_.pow_zero]
- refine le_trans (norm_add_le _ _) ?_
- have : ‖∑' b : ℕ, (fun n ↦ x ^ (n + 1)) b‖ ≤ (1 - ‖x‖)⁻¹ - 1 := by
- refine tsum_of_norm_bounded ?_ fun b ↦ norm_pow_le' _ (Nat.succ_pos b)
- convert (hasSum_nat_add_iff' 1).mpr (hasSum_geometric_of_lt_one (norm_nonneg x) h)
- simp
- linarith
-
-@[deprecated (since := "2024-01-31")]
-alias NormedRing.tsum_geometric_of_norm_lt_1 := NormedRing.tsum_geometric_of_norm_lt_one
-
-theorem geom_series_mul_neg (x : R) (h : ‖x‖ < 1) : (∑' i : ℕ, x ^ i) * (1 - x) = 1 := by
- have := (NormedRing.summable_geometric_of_norm_lt_one x h).hasSum.mul_right (1 - x)
- refine tendsto_nhds_unique this.tendsto_sum_nat ?_
- have : Tendsto (fun n : ℕ ↦ 1 - x ^ n) atTop (𝓝 1) := by
- simpa using tendsto_const_nhds.sub (tendsto_pow_atTop_nhds_zero_of_norm_lt_one h)
- convert← this
- rw [← geom_sum_mul_neg, Finset.sum_mul]
-
-theorem mul_neg_geom_series (x : R) (h : ‖x‖ < 1) : ((1 - x) * ∑' i : ℕ, x ^ i) = 1 := by
- have := (NormedRing.summable_geometric_of_norm_lt_one x h).hasSum.mul_left (1 - x)
- refine tendsto_nhds_unique this.tendsto_sum_nat ?_
- have : Tendsto (fun n : ℕ ↦ 1 - x ^ n) atTop (𝓝 1) := by
- simpa using tendsto_const_nhds.sub (tendsto_pow_atTop_nhds_zero_of_norm_lt_one h)
- convert← this
- rw [← mul_neg_geom_sum, Finset.mul_sum]
-
-theorem geom_series_succ (x : R) (h : ‖x‖ < 1) : ∑' i : ℕ, x ^ (i + 1) = ∑' i : ℕ, x ^ i - 1 := by
- rw [eq_sub_iff_add_eq, tsum_eq_zero_add (NormedRing.summable_geometric_of_norm_lt_one x h),
- pow_zero, add_comm]
-
-theorem geom_series_mul_shift (x : R) (h : ‖x‖ < 1) :
- x * ∑' i : ℕ, x ^ i = ∑' i : ℕ, x ^ (i + 1) := by
- simp_rw [← (NormedRing.summable_geometric_of_norm_lt_one _ h).tsum_mul_left, ← _root_.pow_succ']
-
-theorem geom_series_mul_one_add (x : R) (h : ‖x‖ < 1) :
- (1 + x) * ∑' i : ℕ, x ^ i = 2 * ∑' i : ℕ, x ^ i - 1 := by
- rw [add_mul, one_mul, geom_series_mul_shift x h, geom_series_succ x h, two_mul, add_sub_assoc]
-
-end NormedRingGeometric
-
/-! ### Summability tests based on comparison with geometric series -/
theorem summable_of_ratio_norm_eventually_le {α : Type*} [SeminormedAddCommGroup α]
@@ -860,6 +857,8 @@ theorem Real.summable_pow_div_factorial (x : ℝ) : Summable (fun n ↦ x ^ n /
norm_div, Real.norm_natCast, Nat.cast_succ]
_ ≤ ‖x‖ / (⌊‖x‖⌋₊ + 1) * ‖x ^ n / (n !)‖ := by gcongr
+@[deprecated "`Real.tendsto_pow_div_factorial_atTop` has been deprecated, use
+`FloorSemiring.tendsto_pow_div_factorial_atTop` instead" (since := "2024-10-05")]
theorem Real.tendsto_pow_div_factorial_atTop (x : ℝ) :
Tendsto (fun n ↦ x ^ n / n ! : ℕ → ℝ) atTop (𝓝 0) :=
(Real.summable_pow_div_factorial x).tendsto_atTop_zero
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 10867220bdf25..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.Order.Filter.AtTopBot.Archimedean
import Mathlib.Topology.Instances.Real
-import Mathlib.Order.Filter.Archimedean
/-!
# Convergence of subadditive sequences
diff --git a/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean b/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean
index 6486b7bbab466..4bf4e8678ab11 100644
--- a/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean
+++ b/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean
@@ -1,11 +1,10 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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/Basic.lean b/Mathlib/CategoryTheory/Abelian/Basic.lean
index b7e4dbcf98889..cc0db03e5a10b 100644
--- a/Mathlib/CategoryTheory/Abelian/Basic.lean
+++ b/Mathlib/CategoryTheory/Abelian/Basic.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Johan Commelin, Scott Morrison
+Authors: Markus Himmel, Johan Commelin, Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Constructions.Pullbacks
import Mathlib.CategoryTheory.Preadditive.Biproducts
diff --git a/Mathlib/CategoryTheory/Abelian/Exact.lean b/Mathlib/CategoryTheory/Abelian/Exact.lean
index 85352b81dbb61..04967ba6b7f80 100644
--- a/Mathlib/CategoryTheory/Abelian/Exact.lean
+++ b/Mathlib/CategoryTheory/Abelian/Exact.lean
@@ -169,25 +169,19 @@ section
open List in
theorem Abelian.tfae_mono {X Y : C} (f : X ⟶ Y) (Z : C) :
TFAE [Mono f, kernel.ι f = 0, (ShortComplex.mk (0 : Z ⟶ X) f zero_comp).Exact] := by
- tfae_have 2 → 1
- · exact mono_of_kernel_ι_eq_zero _
+ tfae_have 2 → 1 := mono_of_kernel_ι_eq_zero _
tfae_have 1 → 2
- · intro
- rw [← cancel_mono f, kernel.condition, zero_comp]
- tfae_have 3 ↔ 1
- · exact ShortComplex.exact_iff_mono _ (by simp)
+ | _ => by rw [← cancel_mono f, kernel.condition, zero_comp]
+ tfae_have 3 ↔ 1 := ShortComplex.exact_iff_mono _ (by simp)
tfae_finish
open List in
theorem Abelian.tfae_epi {X Y : C} (f : X ⟶ Y) (Z : C ) :
TFAE [Epi f, cokernel.π f = 0, (ShortComplex.mk f (0 : Y ⟶ Z) comp_zero).Exact] := by
- tfae_have 2 → 1
- · exact epi_of_cokernel_π_eq_zero _
+ tfae_have 2 → 1 := epi_of_cokernel_π_eq_zero _
tfae_have 1 → 2
- · intro
- rw [← cancel_epi f, cokernel.condition, comp_zero]
- tfae_have 3 ↔ 1
- · exact ShortComplex.exact_iff_epi _ (by simp)
+ | _ => by rw [← cancel_epi f, cokernel.condition, comp_zero]
+ tfae_have 3 ↔ 1 := ShortComplex.exact_iff_epi _ (by simp)
tfae_finish
end
diff --git a/Mathlib/CategoryTheory/Abelian/Ext.lean b/Mathlib/CategoryTheory/Abelian/Ext.lean
index 63698a865b338..223c0b659b3b2 100644
--- a/Mathlib/CategoryTheory/Abelian/Ext.lean
+++ b/Mathlib/CategoryTheory/Abelian/Ext.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Adam Topaz
+Authors: Kim Morrison, Adam Topaz
-/
import Mathlib.Algebra.Category.ModuleCat.Abelian
import Mathlib.Algebra.Homology.Opposite
diff --git a/Mathlib/CategoryTheory/Abelian/FunctorCategory.lean b/Mathlib/CategoryTheory/Abelian/FunctorCategory.lean
index b3b746622ceed..8178bfae61ecf 100644
--- a/Mathlib/CategoryTheory/Abelian/FunctorCategory.lean
+++ b/Mathlib/CategoryTheory/Abelian/FunctorCategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Abelian.Basic
import Mathlib.CategoryTheory.Preadditive.FunctorCategory
diff --git a/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean b/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean
new file mode 100644
index 0000000000000..84eda8c006ac2
--- /dev/null
+++ b/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean
@@ -0,0 +1,128 @@
+/-
+Copyright (c) 2023 Adam Topaz. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Isaac Hernando, Coleton Kotch, Adam Topaz
+-/
+
+import Mathlib.CategoryTheory.Limits.Constructions.Filtered
+import Mathlib.CategoryTheory.Limits.Shapes.Biproducts
+import Mathlib.CategoryTheory.Limits.Preserves.FunctorCategory
+
+/-!
+
+# Grothendieck Axioms
+
+This file defines some of the Grothendieck Axioms for abelian categories, and proves
+basic facts about them.
+
+## Definitions
+
+- `AB4` -- an abelian category satisfies `AB4` provided that coproducts are exact.
+- `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.
+A comparison with Grothendieck's original formulation of the properties can be found in the
+comments of the linked Stacks page.
+Exactness as the preservation of short exact sequences is introduced in
+`CategoryTheory.Abelian.Exact`.
+
+## Projects
+
+- Add additional axioms, especially define Grothendieck categories.
+- Prove that `AB5` implies `AB4`.
+
+## References
+* [Stacks: Grothendieck's AB conditions](https://stacks.math.columbia.edu/tag/079A)
+
+-/
+
+namespace CategoryTheory
+
+open Limits
+
+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.
+-/
+class AB4 [HasCoproducts C] where
+ /-- Exactness of coproducts stated as `colim : (Discrete α ⥤ C) ⥤ C` preserving limits. -/
+ preservesFiniteLimits (α : Type v) :
+ PreservesFiniteLimits (colim (J := Discrete α) (C := C))
+
+attribute [instance] AB4.preservesFiniteLimits
+
+/-- A category `C` which has products is said to have `AB4Star` (in literature `AB4*`)
+provided that products are exact. -/
+class AB4Star [HasProducts C] where
+ /-- Exactness of products stated as `lim : (Discrete α ⥤ C) ⥤ C` preserving colimits. -/
+ preservesFiniteColimits (α : Type v) :
+ PreservesFiniteColimits (lim (J := Discrete α) (C := C))
+
+attribute [instance] AB4Star.preservesFiniteColimits
+
+/--
+A category `C` which has filtered colimits is said to have `AB5` provided that
+filtered colimits are exact.
+-/
+class AB5 [HasFilteredColimits C] where
+ /-- Exactness of filtered colimits stated as `colim : (J ⥤ C) ⥤ C` on filtered `J`
+ preserving limits. -/
+ preservesFiniteLimits (J : Type v) [SmallCategory J] [IsFiltered J] :
+ PreservesFiniteLimits (colim (J := J) (C := C))
+
+attribute [instance] AB5.preservesFiniteLimits
+
+/--
+A category `C` which has cofiltered limits is said to have `AB5Star` (in literature `AB5*`)
+provided that cofiltered limits are exact.
+-/
+class AB5Star [HasCofilteredLimits C] where
+ /-- Exactness of cofiltered limits stated as `lim : (J ⥤ C) ⥤ C` on cofiltered `J`
+ preserving colimits. -/
+ preservesFiniteColimits (J : Type v) [SmallCategory J] [IsCofiltered J] :
+ PreservesFiniteColimits (lim (J := J) (C := C))
+
+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 58a0dcda3e32b..1bed70213ca90 100644
--- a/Mathlib/CategoryTheory/Abelian/Images.lean
+++ b/Mathlib/CategoryTheory/Abelian/Images.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Scott Morrison
+Authors: Markus Himmel, Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Shapes.Kernels
@@ -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 a7565550d51fd..1473b0ef27413 100644
--- a/Mathlib/CategoryTheory/Abelian/InjectiveResolution.lean
+++ b/Mathlib/CategoryTheory/Abelian/InjectiveResolution.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2022 Jujian Zhang. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Jujian Zhang, Scott Morrison
+Authors: Jujian Zhang, Kim Morrison
-/
import Mathlib.CategoryTheory.Preadditive.InjectiveResolution
import Mathlib.Algebra.Homology.HomotopyCategory
@@ -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/LeftDerived.lean b/Mathlib/CategoryTheory/Abelian/LeftDerived.lean
index be9b3ab46d0c2..f9333349b110b 100644
--- a/Mathlib/CategoryTheory/Abelian/LeftDerived.lean
+++ b/Mathlib/CategoryTheory/Abelian/LeftDerived.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Riccardo Brasca, Adam Topaz, Jujian Zhang, Joël Riou
+Authors: Kim Morrison, Riccardo Brasca, Adam Topaz, Jujian Zhang, Joël Riou
-/
import Mathlib.Algebra.Homology.Additive
import Mathlib.CategoryTheory.Abelian.ProjectiveResolution
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 6c2747ade568d..d0af389e041d3 100644
--- a/Mathlib/CategoryTheory/Abelian/Opposite.lean
+++ b/Mathlib/CategoryTheory/Abelian/Opposite.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Abelian.Basic
import Mathlib.CategoryTheory.Preadditive.Opposite
@@ -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/ProjectiveResolution.lean b/Mathlib/CategoryTheory/Abelian/ProjectiveResolution.lean
index 854dacb44ab3e..b46ed6087d1b3 100644
--- a/Mathlib/CategoryTheory/Abelian/ProjectiveResolution.lean
+++ b/Mathlib/CategoryTheory/Abelian/ProjectiveResolution.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2022 Jujian Zhang. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Scott Morrison, Jakob von Raumer, Joël Riou
+Authors: Markus Himmel, Kim Morrison, Jakob von Raumer, Joël Riou
-/
import Mathlib.CategoryTheory.Preadditive.ProjectiveResolution
import Mathlib.Algebra.Homology.HomotopyCategory
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/Abelian/RightDerived.lean b/Mathlib/CategoryTheory/Abelian/RightDerived.lean
index 2c12f1e56530f..8cf24315d8930 100644
--- a/Mathlib/CategoryTheory/Abelian/RightDerived.lean
+++ b/Mathlib/CategoryTheory/Abelian/RightDerived.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2022 Jujian Zhang. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Jujian Zhang, Scott Morrison, Joël Riou
+Authors: Jujian Zhang, Kim Morrison, Joël Riou
-/
import Mathlib.Algebra.Homology.Additive
import Mathlib.CategoryTheory.Abelian.InjectiveResolution
diff --git a/Mathlib/CategoryTheory/Abelian/Transfer.lean b/Mathlib/CategoryTheory/Abelian/Transfer.lean
index 9e05999b3184a..5a3c93413c248 100644
--- a/Mathlib/CategoryTheory/Abelian/Transfer.lean
+++ b/Mathlib/CategoryTheory/Abelian/Transfer.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Abelian.Basic
import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Kernels
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 6bb76fb19fe02..6d43fa6f5d71a 100644
--- a/Mathlib/CategoryTheory/Adjunction/Basic.lean
+++ b/Mathlib/CategoryTheory/Adjunction/Basic.lean
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Reid Barton, Johan Commelin, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Equivalence
+import Mathlib.CategoryTheory.Yoneda
/-!
# Adjunctions between functors
@@ -13,7 +14,9 @@ import Mathlib.CategoryTheory.Equivalence
We provide various useful constructors:
* `mkOfHomEquiv`
-* `mkOfUnitCounit`
+* `mk'`: construct an adjunction from the data of a hom set equivalence, unit and counit natural
+ transformations together with proofs of the equalities `homEquiv_unit` and `homEquiv_counit`
+ relating them to each other.
* `leftAdjointOfEquiv` / `rightAdjointOfEquiv`
construct a left/right adjoint of a given functor given the action on objects and
the relevant equivalence of morphism spaces.
@@ -29,6 +32,44 @@ adjoint can be obtained as `F.rightAdjoint`.
`toEquivalence` upgrades an adjunction to an equivalence,
given witnesses that the unit and counit are pointwise isomorphisms.
Conversely `Equivalence.toAdjunction` recovers the underlying adjunction from an equivalence.
+
+## Overview of the directory `CategoryTheory.Adjunction`
+
+* Adjoint lifting theorems are in the directory `Lifting`.
+* The file `AdjointFunctorTheorems` proves the adjoint functor theorems.
+* The file `Comma` shows that for a functor `G : D ⥤ C` the data of an initial object in each
+ `StructuredArrow` category on `G` is equivalent to a left adjoint to `G`, as well as the dual.
+* The file `Evaluation` shows that products and coproducts are adjoint to evaluation of functors.
+* The file `FullyFaithful` characterizes when adjoints are full or faithful in terms of the unit
+ and counit.
+* The file `Limits` proves that left adjoints preserve colimits and right adjoints preserve limits.
+* The file `Mates` establishes the bijection between the 2-cells
+ ```
+ L₁ R₁
+ C --→ D C ←-- D
+ G ↓ ↗ ↓ H G ↓ ↘ ↓ H
+ E --→ F E ←-- F
+ L₂ R₂
+ ```
+ where `L₁ ⊣ R₁` and `L₂ ⊣ R₂`. Specializing to a pair of adjoints `L₁ L₂ : C ⥤ D`,
+ `R₁ R₂ : D ⥤ C`, it provides equivalences `(L₂ ⟶ L₁) ≃ (R₁ ⟶ R₂)` and `(L₂ ≅ L₁) ≃ (R₁ ≅ R₂)`.
+* The file `Opposites` contains constructions to relate adjunctions of functors to adjunctions of
+ their opposites.
+* The file `Reflective` defines reflective functors, i.e. fully faithful right adjoints. Note that
+ many facts about reflective functors are proved in the earlier file `FullyFaithful`.
+* The file `Restrict` defines the restriction of an adjunction along fully faithful functors.
+* The file `Triple` proves that in an adjoint triple, the left adjoint is fully faithful if and
+ only if the right adjoint is.
+* The file `Unique` proves uniqueness of adjoints.
+* The file `Whiskering` proves that functors `F : D ⥤ E` and `G : E ⥤ D` with an adjunction
+ `F ⊣ G`, induce adjunctions between the functor categories `C ⥤ D` and `C ⥤ E`,
+ and the functor categories `E ⥤ C` and `D ⥤ C`.
+
+## Other files related to adjunctions
+
+* The file `CategoryTheory.Monad.Adjunction` develops the basic relationship between adjunctions
+ and (co)monads. There it is also shown that given an adjunction `L ⊣ R` and an isomorphism
+ `L ⋙ R ≅ 𝟭 C`, the unit is an isomorphism, and similarly for the counit.
-/
@@ -47,26 +88,30 @@ variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D]
/-- `F ⊣ G` represents the data of an adjunction between two functors
`F : C ⥤ D` and `G : D ⥤ C`. `F` is the left adjoint and `G` is the right adjoint.
-To construct an `adjunction` between two functors, it's often easier to instead use the
-constructors `mkOfHomEquiv` or `mkOfUnitCounit`. To construct a left adjoint,
-there are also constructors `leftAdjointOfEquiv` and `adjunctionOfEquivLeft` (as
-well as their duals) which can be simpler in practice.
+We use the unit-counit definition of an adjunction. There is a constructor `Adjunction.mk'`
+which constructs an adjunction from the data of a hom set equivalence, a unit, and a counit,
+together with proofs of the equalities `homEquiv_unit` and `homEquiv_counit` relating them to each
+other.
+
+There is also a constructor `Adjunction.mkOfHomEquiv` which constructs an adjunction from a natural
+hom set equivalence.
-Uniqueness of adjoints is shown in `CategoryTheory.Adjunction.Unique`.
+To construct adjoints to a given functor, there are constructors `leftAdjointOfEquiv` and
+`adjunctionOfEquivLeft` (as well as their duals).
See .
-/
structure Adjunction (F : C ⥤ D) (G : D ⥤ C) where
- /-- The equivalence between `Hom (F X) Y` and `Hom X (G Y)` coming from an adjunction -/
- homEquiv : ∀ X Y, (F.obj X ⟶ Y) ≃ (X ⟶ G.obj Y)
/-- The unit of an adjunction -/
unit : 𝟭 C ⟶ F.comp G
/-- The counit of an adjunction -/
counit : G.comp F ⟶ 𝟭 D
- /-- The relationship between the unit and hom set equivalence of an adjunction -/
- homEquiv_unit : ∀ {X Y f}, (homEquiv X Y) f = unit.app X ≫ G.map f := by aesop_cat
- /-- 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
+ /-- Equality of the composition of the unit and counit with the identity `F ⟶ FGF ⟶ F = 𝟙` -/
+ left_triangle_components (X : C) :
+ F.map (unit.app X) ≫ counit.app (F.obj X) = 𝟙 (F.obj X) := by aesop_cat
+ /-- Equality of the composition of the unit and counit with the identity `G ⟶ GFG ⟶ G = 𝟙` -/
+ right_triangle_components (Y : D) :
+ unit.app (G.obj Y) ≫ G.map (counit.app Y) = 𝟙 (G.obj Y) := by aesop_cat
/-- The notation `F ⊣ G` stands for `Adjunction F G` representing that `F` is left adjoint to `G` -/
infixl:15 " ⊣ " => Adjunction
@@ -103,7 +148,36 @@ noncomputable def Adjunction.ofIsRightAdjoint (right : C ⥤ D) [right.IsRightAd
namespace Adjunction
-attribute [simp] homEquiv_unit homEquiv_counit
+attribute [reassoc (attr := simp)] left_triangle_components right_triangle_components
+
+/-- The hom set equivalence associated to an adjunction. -/
+@[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
+ invFun := fun g => F.map g ≫ adj.counit.app Y
+ left_inv := fun f => by
+ dsimp
+ rw [F.map_comp, assoc, ← Functor.comp_map, adj.counit.naturality, ← assoc]
+ simp
+ right_inv := fun g => by
+ 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
+
+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
@@ -173,29 +247,11 @@ theorem homEquiv_naturality_right_square_iff (f : X' ⟶ X) (g : X ⟶ G.obj Y')
@[simp]
theorem left_triangle : whiskerRight adj.unit F ≫ whiskerLeft F adj.counit = 𝟙 _ := by
- ext; dsimp
- rw [← adj.homEquiv_counit, Equiv.symm_apply_eq, adj.homEquiv_unit]
- simp
+ ext; simp
@[simp]
theorem right_triangle : whiskerLeft G adj.unit ≫ whiskerRight adj.counit G = 𝟙 _ := by
- ext; dsimp
- rw [← adj.homEquiv_unit, ← Equiv.eq_symm_apply, adj.homEquiv_counit]
- simp
-
-variable (X Y)
-
-@[reassoc (attr := simp)]
-theorem left_triangle_components :
- F.map (adj.unit.app X) ≫ adj.counit.app (F.obj X) = 𝟙 (F.obj X) :=
- congr_arg (fun t : NatTrans _ (𝟭 C ⋙ F) => t.app X) adj.left_triangle
-
-@[reassoc (attr := simp)]
-theorem right_triangle_components :
- adj.unit.app (G.obj Y) ≫ G.map (adj.counit.app Y) = 𝟙 (G.obj Y) :=
- congr_arg (fun t : NatTrans _ (G ⋙ 𝟭 C) => t.app Y) adj.right_triangle
-
-variable {X Y}
+ ext; simp
@[reassoc (attr := simp)]
theorem counit_naturality {X Y : D} (f : X ⟶ Y) :
@@ -207,21 +263,35 @@ theorem unit_naturality {X Y : C} (f : X ⟶ Y) :
adj.unit.app X ≫ G.map (F.map f) = f ≫ adj.unit.app Y :=
(adj.unit.naturality f).symm
+lemma unit_comp_map_eq_iff {A : C} {B : D} (f : F.obj A ⟶ B) (g : A ⟶ G.obj B) :
+ adj.unit.app A ≫ G.map f = g ↔ f = F.map g ≫ adj.counit.app B :=
+ ⟨fun h => by simp [← h], fun h => by simp [h]⟩
+
+lemma eq_unit_comp_map_iff {A : C} {B : D} (f : F.obj A ⟶ B) (g : A ⟶ G.obj B) :
+ g = adj.unit.app A ≫ G.map f ↔ F.map g ≫ adj.counit.app B = f :=
+ ⟨fun h => by simp [h], fun h => by simp [← h]⟩
+
theorem homEquiv_apply_eq {A : C} {B : D} (f : F.obj A ⟶ B) (g : A ⟶ G.obj B) :
adj.homEquiv A B f = g ↔ f = (adj.homEquiv A B).symm g :=
- ⟨fun h => by
- cases h
- simp, fun h => by
- cases h
- simp⟩
+ unit_comp_map_eq_iff adj f g
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 :=
- ⟨fun h => by
- cases h
- simp, fun h => by
- cases h
- simp⟩
+ 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
@@ -229,6 +299,22 @@ end Adjunction
namespace Adjunction
+/--
+This is an auxiliary data structure useful for constructing adjunctions.
+See `Adjunction.mk'`. This structure won't typically be used anywhere else.
+-/
+structure CoreHomEquivUnitCounit (F : C ⥤ D) (G : D ⥤ C) where
+ /-- The equivalence between `Hom (F X) Y` and `Hom X (G Y)` coming from an adjunction -/
+ homEquiv : ∀ X Y, (F.obj X ⟶ Y) ≃ (X ⟶ G.obj Y)
+ /-- The unit of an adjunction -/
+ unit : 𝟭 C ⟶ F ⋙ G
+ /-- The counit of an adjunction -/
+ counit : G ⋙ F ⟶ 𝟭 D
+ /-- The relationship between the unit and hom set equivalence of an adjunction -/
+ homEquiv_unit : ∀ {X Y f}, (homEquiv X Y) f = unit.app X ≫ G.map f := by aesop_cat
+ /-- 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
+
/-- This is an auxiliary data structure useful for constructing adjunctions.
See `Adjunction.mkOfHomEquiv`.
This structure won't typically be used anywhere else.
@@ -297,11 +383,32 @@ 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
+`homEquiv_unit` and `homEquiv_counit` relating them to each other.
+-/
+@[simps]
+def mk' (adj : CoreHomEquivUnitCounit F G) : F ⊣ G where
+ unit := adj.unit
+ counit := adj.counit
+ left_triangle_components X := by
+ rw [← adj.homEquiv_counit, (adj.homEquiv _ _).symm_apply_eq]
+ simp
+ right_triangle_components Y := by
+ rw [← adj.homEquiv_unit, ← (adj.homEquiv _ _).eq_symm_apply]
+ simp
+
+lemma mk'_homEquiv (adj : CoreHomEquivUnitCounit F G) : (mk' adj).homEquiv = adj.homEquiv := by
+ ext; simp
+
/-- Construct an adjunction between `F` and `G` out of a natural bijection between each
`F.obj X ⟶ Y` and `X ⟶ G.obj Y`. -/
-@[simps]
+@[simps!]
def mkOfHomEquiv (adj : CoreHomEquiv F G) : F ⊣ G :=
- { adj with
+ mk' {
unit :=
{ app := fun X => (adj.homEquiv X (F.obj X)) (𝟙 (F.obj X))
naturality := by
@@ -312,38 +419,33 @@ def mkOfHomEquiv (adj : CoreHomEquiv F G) : F ⊣ G :=
naturality := by
intros
simp [← adj.homEquiv_naturality_left_symm, ← adj.homEquiv_naturality_right_symm] }
- 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] }
+ homEquiv := adj.homEquiv
+ 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
+ simp [mkOfHomEquiv, ← adj.homEquiv_naturality_right (𝟙 _) g]
/-- Construct an adjunction between functors `F` and `G` given a unit and counit for the adjunction
satisfying the triangle identities. -/
-
@[simps!]
-def mkOfUnitCounit (adj : CoreUnitCounit F G) : F ⊣ G :=
- { adj with
- homEquiv := fun X Y =>
- { toFun := fun f => adj.unit.app X ≫ G.map f
- invFun := fun g => F.map g ≫ adj.counit.app Y
- left_inv := fun f => by
- change F.map (_ ≫ _) ≫ _ = _
- rw [F.map_comp, assoc, ← Functor.comp_map, adj.counit.naturality, ← assoc]
- convert id_comp f
- have t := congrArg (fun (s : NatTrans (𝟭 C ⋙ F) (F ⋙ 𝟭 D)) => s.app X) adj.left_triangle
- dsimp at t
- simp only [id_comp] at t
- exact t
- right_inv := fun g => by
- change _ ≫ G.map (_ ≫ _) = _
- rw [G.map_comp, ← assoc, ← Functor.comp_map, ← adj.unit.naturality, assoc]
- convert comp_id g
- have t := congrArg (fun t : NatTrans (G ⋙ 𝟭 C) (𝟭 D ⋙ G) => t.app Y) adj.right_triangle
- dsimp at t
- simp only [id_comp] at t
- exact t } }
+def mkOfUnitCounit (adj : CoreUnitCounit F G) : F ⊣ G where
+ unit := adj.unit
+ counit := adj.counit
+ left_triangle_components X := by
+ have := adj.left_triangle
+ rw [NatTrans.ext_iff, funext_iff] at this
+ simpa [-CoreUnitCounit.left_triangle] using this X
+ right_triangle_components Y := by
+ have := adj.right_triangle
+ rw [NatTrans.ext_iff, funext_iff] at this
+ simpa [-CoreUnitCounit.right_triangle] using this Y
/-- The adjunction between the identity functor on a category and itself. -/
def id : 𝟭 C ⊣ 𝟭 C where
- homEquiv X Y := Equiv.refl _
unit := 𝟙 _
counit := 𝟙 _
@@ -379,6 +481,22 @@ def ofNatIsoRight {F : C ⥤ D} {G H : D ⥤ C} (adj : F ⊣ G) (iso : G ≅ H)
Adjunction.mkOfHomEquiv
{ homEquiv := fun X Y => (adj.homEquiv X Y).trans (equivHomsetRightOfNatIso iso) }
+/-- The isomorpism which an adjunction `F ⊣ G` induces on `G ⋙ yoneda`. This states that
+`Adjunction.homEquiv` is natural in both arguments. -/
+@[simps!]
+def compYonedaIso {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₁} D]
+ {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) :
+ G ⋙ yoneda ≅ yoneda ⋙ (whiskeringLeft _ _ _).obj F.op :=
+ NatIso.ofComponents fun X => NatIso.ofComponents fun Y => (adj.homEquiv Y.unop X).toIso.symm
+
+/-- The isomorpism which an adjunction `F ⊣ G` induces on `F.op ⋙ coyoneda`. This states that
+`Adjunction.homEquiv` is natural in both arguments. -/
+@[simps!]
+def compCoyonedaIso {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₁} D]
+ {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) :
+ F.op ⋙ coyoneda ≅ coyoneda ⋙ (whiskeringLeft _ _ _).obj G :=
+ NatIso.ofComponents fun X => NatIso.ofComponents fun Y => (adj.homEquiv X.unop Y).toIso
+
section
variable {E : Type u₃} [ℰ : Category.{v₃} E] {H : D ⥤ E} {I : E ⥤ D}
@@ -388,11 +506,12 @@ variable {E : Type u₃} [ℰ : Category.{v₃} E] {H : D ⥤ E} {I : E ⥤ D}
See .
-/
-def comp : F ⋙ H ⊣ I ⋙ G where
- homEquiv X Z := Equiv.trans (adj₂.homEquiv _ _) (adj₁.homEquiv _ _)
- unit := adj₁.unit ≫ (whiskerLeft F <| whiskerRight adj₂.unit G) ≫ (Functor.associator _ _ _).inv
- counit :=
- (Functor.associator _ _ _).hom ≫ (whiskerLeft I <| whiskerRight adj₁.counit H) ≫ adj₂.counit
+def comp : F ⋙ H ⊣ I ⋙ G :=
+ mk' {
+ homEquiv := fun _ _ ↦ Equiv.trans (adj₂.homEquiv _ _) (adj₁.homEquiv _ _)
+ unit := adj₁.unit ≫ (whiskerLeft F <| whiskerRight adj₂.unit G) ≫ (Functor.associator _ _ _).inv
+ counit :=
+ (Functor.associator _ _ _).hom ≫ (whiskerLeft I <| whiskerRight adj₁.counit H) ≫ adj₂.counit }
@[simp, reassoc]
lemma comp_unit_app (X : C) :
@@ -404,6 +523,10 @@ lemma comp_counit_app (X : E) :
(adj₁.comp adj₂).counit.app X = H.map (adj₁.counit.app (I.obj X)) ≫ adj₂.counit.app X := by
simp [Adjunction.comp]
+lemma comp_homEquiv : (adj₁.comp adj₂).homEquiv =
+ fun _ _ ↦ Equiv.trans (adj₂.homEquiv _ _) (adj₁.homEquiv _ _) :=
+ mk'_homEquiv _
+
end
section ConstructLeft
@@ -518,9 +641,10 @@ variable (e : C ≌ D)
/-- The adjunction given by an equivalence of categories. (To obtain the opposite adjunction,
simply use `e.symm.toAdjunction`. -/
-@[simps! unit counit]
-def toAdjunction : e.functor ⊣ e.inverse :=
- mkOfUnitCounit ⟨e.unit, e.counit, by ext; simp, by ext; simp⟩
+@[simps]
+def toAdjunction : e.functor ⊣ e.inverse where
+ unit := e.unit
+ counit := e.counit
lemma isLeftAdjoint_functor : e.functor.IsLeftAdjoint where
exists_rightAdjoint := ⟨_, ⟨e.toAdjunction⟩⟩
diff --git a/Mathlib/CategoryTheory/Adjunction/Comma.lean b/Mathlib/CategoryTheory/Adjunction/Comma.lean
index 07015c84df266..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) :
@@ -132,10 +135,7 @@ def mkInitialOfLeftAdjoint (h : F ⊣ G) (A : C) :
desc B := StructuredArrow.homMk ((h.homEquiv _ _).symm B.pt.hom)
uniq s m _ := by
apply StructuredArrow.ext
- dsimp
- -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
- erw [Equiv.eq_symm_apply, Adjunction.homEquiv_unit]
- apply StructuredArrow.w m
+ simp [← StructuredArrow.w m]
/-- Given a right adjoint to `F`, we can construct a terminal object in each costructured arrow
category on `F`. -/
@@ -144,9 +144,7 @@ def mkTerminalOfRightAdjoint (h : F ⊣ G) (A : D) :
lift B := CostructuredArrow.homMk (h.homEquiv _ _ B.pt.hom)
uniq s m _ := by
apply CostructuredArrow.ext
- dsimp
- rw [h.eq_homEquiv_apply, Adjunction.homEquiv_counit]
- exact CostructuredArrow.w m
+ simp [← CostructuredArrow.w m]
end
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 c1e9ac499f5a3..7c789d7c00fcf 100644
--- a/Mathlib/CategoryTheory/Adjunction/FullyFaithful.lean
+++ b/Mathlib/CategoryTheory/Adjunction/FullyFaithful.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Dagur Asgeirsson
+Authors: Kim Morrison, Dagur Asgeirsson
-/
import Mathlib.CategoryTheory.Adjunction.Basic
import Mathlib.CategoryTheory.MorphismProperty.Basic
@@ -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 e66f18e83e81d..f57ec0e073cee 100644
--- a/Mathlib/CategoryTheory/Adjunction/Limits.lean
+++ b/Mathlib/CategoryTheory/Adjunction/Limits.lean
@@ -74,10 +74,9 @@ def functorialityCounit :
app c := { hom := adj.counit.app c.pt }
/-- The functor `Cocones.functoriality K F : Cocone K ⥤ Cocone (K ⋙ F)` is a left adjoint. -/
-def functorialityAdjunction : Cocones.functoriality K F ⊣ functorialityRightAdjoint adj K :=
- mkOfUnitCounit
- { unit := functorialityUnit adj K
- counit := functorialityCounit adj K}
+def functorialityAdjunction : Cocones.functoriality K F ⊣ functorialityRightAdjoint adj K where
+ unit := functorialityUnit adj K
+ counit := functorialityCounit adj K
/-- A left adjoint preserves colimits.
@@ -91,6 +90,11 @@ def leftAdjointPreservesColimits : PreservesColimitsOfSize.{v, u} F where
@Equiv.unique _ _ (IsColimit.isoUniqueCoconeMorphism.hom hc _)
((adj.functorialityAdjunction _).homEquiv _ _) } }
+noncomputable
+instance colimPreservesColimits [HasColimitsOfShape J C] :
+ PreservesColimits (colim (J := J) (C := C)) :=
+ colimConstAdj.leftAdjointPreservesColimits
+
-- see Note [lower instance priority]
noncomputable instance (priority := 100) isEquivalencePreservesColimits
(E : C ⥤ D) [E.IsEquivalence] :
@@ -178,10 +182,9 @@ def functorialityCounit' :
app c := { hom := adj.counit.app c.pt }
/-- The functor `Cones.functoriality K G : Cone K ⥤ Cone (K ⋙ G)` is a right adjoint. -/
-def functorialityAdjunction' : functorialityLeftAdjoint adj K ⊣ Cones.functoriality K G :=
- mkOfUnitCounit
- { unit := functorialityUnit' adj K
- counit := functorialityCounit' adj K }
+def functorialityAdjunction' : functorialityLeftAdjoint adj K ⊣ Cones.functoriality K G where
+ unit := functorialityUnit' adj K
+ counit := functorialityCounit' adj K
/-- A right adjoint preserves limits.
@@ -195,6 +198,11 @@ def rightAdjointPreservesLimits : PreservesLimitsOfSize.{v, u} G where
@Equiv.unique _ _ (IsLimit.isoUniqueConeMorphism.hom hc _)
((adj.functorialityAdjunction' _).homEquiv _ _).symm } }
+noncomputable
+instance limPreservesLimits [HasLimitsOfShape J C] :
+ PreservesLimits (lim (J := J) (C := C)) :=
+ constLimAdj.rightAdjointPreservesLimits
+
-- see Note [lower instance priority]
noncomputable instance (priority := 100) isEquivalencePreservesLimits
(E : D ⥤ C) [E.IsEquivalence] :
@@ -288,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/Mates.lean b/Mathlib/CategoryTheory/Adjunction/Mates.lean
index 2e15c2012bd9e..ca344b3aa3796 100644
--- a/Mathlib/CategoryTheory/Adjunction/Mates.lean
+++ b/Mathlib/CategoryTheory/Adjunction/Mates.lean
@@ -13,11 +13,13 @@ import Mathlib.Tactic.ApplyFun
This file establishes the bijection between the 2-cells
+```
L₁ R₁
C --→ D C ←-- D
G ↓ ↗ ↓ H G ↓ ↘ ↓ H
E --→ F E ←-- F
L₂ R₂
+```
where `L₁ ⊣ R₁` and `L₂ ⊣ R₂`. The corresponding natural transformations are called mates.
@@ -206,8 +208,8 @@ theorem mateEquiv_hcomp
rightAdjointSquare.hcomp (mateEquiv adj₁ adj₂ α) (mateEquiv adj₃ adj₄ β) := by
unfold leftAdjointSquare.hcomp rightAdjointSquare.hcomp mateEquiv Adjunction.comp
ext c
- simp only [comp_obj, whiskerLeft_comp, whiskerLeft_twice, whiskerRight_comp, assoc,
- Equiv.coe_fn_mk, comp_app, whiskerLeft_app, whiskerRight_app, id_obj, associator_inv_app,
+ simp only [comp_obj, mk'_unit, whiskerLeft_comp, whiskerLeft_twice, mk'_counit, whiskerRight_comp,
+ assoc, Equiv.coe_fn_mk, comp_app, whiskerLeft_app, whiskerRight_app, id_obj, associator_inv_app,
Functor.comp_map, associator_hom_app, map_id, id_comp, whiskerRight_twice]
slice_rhs 2 4 =>
rw [← R₂.map_comp, ← R₂.map_comp, ← assoc, ← unit_naturality (adj₄)]
@@ -328,6 +330,7 @@ Furthermore, this bijection preserves (and reflects) isomorphisms, i.e. a transf
iff its image under the bijection is an iso, see eg `CategoryTheory.conjugateIsoEquiv`.
This is in contrast to the general case `mateEquiv` which does not in general have this property.
-/
+@[simps!]
def conjugateEquiv : (L₂ ⟶ L₁) ≃ (R₁ ⟶ R₂) :=
calc
(L₂ ⟶ L₁) ≃ _ := (Iso.homCongr L₂.leftUnitor L₁.rightUnitor).symm
@@ -401,6 +404,7 @@ variable [Category.{v₁} C] [Category.{v₂} D]
variable {L₁ L₂ L₃ : C ⥤ D} {R₁ R₂ R₃ : D ⥤ C}
variable (adj₁ : L₁ ⊣ R₁) (adj₂ : L₂ ⊣ R₂) (adj₃ : L₃ ⊣ R₃)
+@[simp]
theorem conjugateEquiv_comp (α : L₂ ⟶ L₁) (β : L₃ ⟶ L₂) :
conjugateEquiv adj₁ adj₂ α ≫ conjugateEquiv adj₂ adj₃ β =
conjugateEquiv adj₁ adj₃ (β ≫ α) := by
@@ -414,6 +418,7 @@ theorem conjugateEquiv_comp (α : L₂ ⟶ L₁) (β : L₃ ⟶ L₂) :
simp only [comp_id, id_comp, assoc, map_comp] at vcompd ⊢
rw [vcompd]
+@[simp]
theorem conjugateEquiv_symm_comp (α : R₁ ⟶ R₂) (β : R₂ ⟶ R₃) :
(conjugateEquiv adj₂ adj₃).symm β ≫ (conjugateEquiv adj₁ adj₂).symm α =
(conjugateEquiv adj₁ adj₃).symm (α ≫ β) := by
@@ -473,9 +478,16 @@ theorem conjugateEquiv_symm_of_iso (α : R₁ ⟶ R₂)
infer_instance
/-- Thus conjugation defines an equivalence between natural isomorphisms. -/
-noncomputable def conjugateIsoEquiv : (L₂ ≅ L₁) ≃ (R₁ ≅ R₂) where
- toFun α := asIso (conjugateEquiv adj₁ adj₂ α.hom)
- invFun β := asIso ((conjugateEquiv adj₁ adj₂).symm β.hom)
+@[simps]
+def conjugateIsoEquiv : (L₂ ≅ L₁) ≃ (R₁ ≅ R₂) where
+ toFun α := {
+ hom := conjugateEquiv adj₁ adj₂ α.hom
+ inv := conjugateEquiv adj₂ adj₁ α.inv
+ }
+ invFun β := {
+ hom := (conjugateEquiv adj₁ adj₂).symm β.hom
+ inv := (conjugateEquiv adj₂ adj₁).symm β.inv
+ }
left_inv := by aesop_cat
right_inv := by aesop_cat
@@ -505,11 +517,7 @@ theorem iterated_mateEquiv_conjugateEquiv (α : F₁ ⋙ L₂ ⟶ L₁ ⋙ F₂)
conjugateEquiv (adj₁.comp adj₄) (adj₃.comp adj₂) α := by
ext d
unfold conjugateEquiv mateEquiv Adjunction.comp
- simp only [comp_obj, Equiv.coe_fn_mk, whiskerLeft_comp, whiskerLeft_twice, whiskerRight_comp,
- assoc, comp_app, whiskerLeft_app, whiskerRight_app, id_obj, Functor.comp_map, Iso.homCongr_symm,
- Equiv.instTrans_trans, Equiv.trans_apply, Iso.homCongr_apply, Iso.symm_inv, Iso.symm_hom,
- rightUnitor_inv_app, associator_inv_app, leftUnitor_hom_app, map_id, associator_hom_app,
- Functor.id_map, comp_id, id_comp]
+ simp
theorem iterated_mateEquiv_conjugateEquiv_symm (α : U₂ ⋙ R₁ ⟶ R₂ ⋙ U₁) :
(mateEquiv adj₁ adj₂).symm ((mateEquiv adj₄ adj₃).symm α) =
diff --git a/Mathlib/CategoryTheory/Adjunction/Opposites.lean b/Mathlib/CategoryTheory/Adjunction/Opposites.lean
index b757cf23557da..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 :=
@@ -35,21 +37,17 @@ def adjointOfOpAdjointOp (F : C ⥤ D) (G : D ⥤ C) (h : G.op ⊣ F.op) : F ⊣
((h.homEquiv (Opposite.op Y) (Opposite.op X)).trans (opEquiv _ _)).symm.trans
(opEquiv _ _)
homEquiv_naturality_left_symm := by
- -- Porting note: This proof was handled by `obviously` in mathlib3.
- intros X' X Y f g
- dsimp [opEquiv]
- -- Porting note: Why is `erw` needed here?
- -- https://github.com/leanprover-community/mathlib4/issues/5164
- erw [homEquiv_unit, homEquiv_unit]
- simp
+ -- Porting note: This proof was handled by `obviously` in mathlib3. The only obstruction to
+ -- automation fully kicking in here is that the `@[simps]` lemmas of `opEquiv` and
+ -- `homEquiv` aren't firing.
+ intros
+ simp [opEquiv, homEquiv]
homEquiv_naturality_right := by
- -- Porting note: This proof was handled by `obviously` in mathlib3.
- intros X Y Y' f g
- dsimp [opEquiv]
- -- Porting note: Why is `erw` needed here?
- -- https://github.com/leanprover-community/mathlib4/issues/5164
- erw [homEquiv_counit, homEquiv_counit]
- simp }
+ -- Porting note: This proof was handled by `obviously` in mathlib3. The only obstruction to
+ -- automation fully kicking in here is that the `@[simps]` lemmas of `opEquiv` and
+ -- `homEquiv` aren't firing.
+ intros
+ simp [opEquiv, homEquiv] }
/-- If `G` is adjoint to `F.op` then `F` is adjoint to `G.unop`. -/
def adjointUnopOfAdjointOp (F : C ⥤ D) (G : Dᵒᵖ ⥤ Cᵒᵖ) (h : G ⊣ F.op) : F ⊣ G.unop :=
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 e433f14102099..af50916ad19c8 100644
--- a/Mathlib/CategoryTheory/Adjunction/Restrict.lean
+++ b/Mathlib/CategoryTheory/Adjunction/Restrict.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Adjunction.Basic
import Mathlib.CategoryTheory.HomCongr
@@ -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
@@ -69,6 +71,11 @@ lemma restrictFullyFaithful_homEquiv_apply {X : C} {Y : D} (f : L.obj X ⟶ Y) :
(adj.restrictFullyFaithful hiC hiD comm1 comm2).homEquiv X Y f =
hiC.preimage (adj.unit.app (iC.obj X) ≫ R'.map (comm1.hom.app X) ≫
R'.map (iD.map f) ≫ comm2.hom.app Y) := by
- simp [restrictFullyFaithful]
+ -- This proof was just `simp [restrictFullyFaithful]` before #16317
+ apply hiC.map_injective
+ simp only [homEquiv_apply, Functor.comp_obj, Functor.map_comp, map_restrictFullyFaithful_unit_app,
+ Functor.id_obj, assoc, Functor.FullyFaithful.map_preimage]
+ congr 2
+ exact (comm2.hom.naturality _).symm
end CategoryTheory.Adjunction
diff --git a/Mathlib/CategoryTheory/Adjunction/Triple.lean b/Mathlib/CategoryTheory/Adjunction/Triple.lean
index d8b28fd060834..d1ee7a410b19f 100644
--- a/Mathlib/CategoryTheory/Adjunction/Triple.lean
+++ b/Mathlib/CategoryTheory/Adjunction/Triple.lean
@@ -11,7 +11,7 @@ import Mathlib.CategoryTheory.Monad.Adjunction
This file concerns adjoint triples `F ⊣ G ⊣ H` of functors `F H : C ⥤ D`, `G : D ⥤ C`.
-Currently, the only result is that `F` is fully faithful if and only if `H` is fully faithful.
+Currently, the only result is that `F` is fully faithful if and only if `H` is fully faithful.
-/
namespace CategoryTheory.Adjunction
@@ -31,7 +31,7 @@ lemma isIso_unit_iff_isIso_counit : IsIso adj₁.unit ↔ IsIso adj₂.counit :=
exact adj₁.isIso_unit_of_iso (adjId.leftAdjointUniq id)
/--
-Given an adjoint triple `F ⊣ G ⊣ H`, the left adjoint `F` is fully faithful if and only if the
+Given an adjoint triple `F ⊣ G ⊣ H`, the left adjoint `F` is fully faithful if and only if the
right adjoint `H` is fully faithful.
-/
noncomputable def fullyFaithfulEquiv : F.FullyFaithful ≃ H.FullyFaithful where
diff --git a/Mathlib/CategoryTheory/Adjunction/Unique.lean b/Mathlib/CategoryTheory/Adjunction/Unique.lean
index e911b3e4dcb59..ec1dcbe176388 100644
--- a/Mathlib/CategoryTheory/Adjunction/Unique.lean
+++ b/Mathlib/CategoryTheory/Adjunction/Unique.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, Thomas Read, Andrew Yang, Dagur Asgeirsson, Joël Riou
-/
-import Mathlib.CategoryTheory.Adjunction.Basic
+import Mathlib.CategoryTheory.Adjunction.Mates
/-!
# Uniqueness of adjoints
@@ -11,9 +11,6 @@ import Mathlib.CategoryTheory.Adjunction.Basic
This file shows that adjoints are unique up to natural isomorphism.
## Main results
-* `Adjunction.natTransEquiv` and `Adjunction.natIsoEquiv` If `F ⊣ G` and `F' ⊣ G'` are adjunctions,
- then there are equivalences `(G ⟶ G') ≃ (F' ⟶ F)` and `(G ≅ G') ≃ (F' ≅ F)`.
-Everything else is deduced from this:
* `Adjunction.leftAdjointUniq` : If `F` and `F'` are both left adjoint to `G`, then they are
naturally isomorphic.
@@ -21,12 +18,6 @@ Everything else is deduced from this:
* `Adjunction.rightAdjointUniq` : If `G` and `G'` are both right adjoint to `F`, then they are
naturally isomorphic.
-## TODO
-
-There some overlap with the file `Adjunction.Mates`. In particular, `natTransEquiv` is just a
-special case of `mateEquiv`. However, before removing `natTransEquiv`, in favour of `mateEquiv`,
-the latter needs some more API lemmas such as `natTransEquiv_apply_app`, `natTransEquiv_id`, etc.
-in order to make automation work better in the rest of this file.
-/
open CategoryTheory
@@ -35,91 +26,12 @@ variable {C D : Type*} [Category C] [Category D]
namespace CategoryTheory.Adjunction
-/--
-If `F ⊣ G` and `F' ⊣ G'` are adjunctions, then giving a natural transformation `G ⟶ G'` is the
-same as giving a natural transformation `F' ⟶ F`.
--/
-@[simps]
-def natTransEquiv {F F' : C ⥤ D} {G G' : D ⥤ C} (adj1 : F ⊣ G) (adj2 : F' ⊣ G') :
- (G ⟶ G') ≃ (F' ⟶ F) where
- toFun f := {
- app := fun X ↦ F'.map ((adj1.unit ≫ whiskerLeft F f).app X) ≫ adj2.counit.app _
- naturality := by
- intro X Y g
- simp only [← Category.assoc, ← Functor.map_comp]
- erw [(adj1.unit ≫ (whiskerLeft F f)).naturality]
- simp
- }
- invFun f := {
- app := fun X ↦ adj2.unit.app (G.obj X) ≫ G'.map (f.app (G.obj X) ≫ adj1.counit.app X)
- naturality := by
- intro X Y g
- erw [← adj2.unit_naturality_assoc]
- simp only [← Functor.map_comp]
- simp
- }
- left_inv f := by
- ext X
- simp only [Functor.comp_obj, NatTrans.comp_app, Functor.id_obj, whiskerLeft_app,
- Functor.map_comp, Category.assoc, unit_naturality_assoc, right_triangle_components_assoc]
- erw [← f.naturality (adj1.counit.app X), ← Category.assoc]
- simp
- right_inv f := by
- ext
- simp
-
-@[simp]
-lemma natTransEquiv_id {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) :
- natTransEquiv adj adj (𝟙 _) = 𝟙 _ := by ext; simp
-
-@[simp]
-lemma natTransEquiv_id_symm {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) :
- (natTransEquiv adj adj).symm (𝟙 _) = 𝟙 _ := by ext; simp
-
-@[simp]
-lemma natTransEquiv_comp {F F' F'' : C ⥤ D} {G G' G'' : D ⥤ C}
- (adj1 : F ⊣ G) (adj2 : F' ⊣ G') (adj3 : F'' ⊣ G'') (f : G ⟶ G') (g : G' ⟶ G'') :
- natTransEquiv adj2 adj3 g ≫ natTransEquiv adj1 adj2 f = natTransEquiv adj1 adj3 (f ≫ g) := by
- apply (natTransEquiv adj1 adj3).symm.injective
- ext X
- simp only [natTransEquiv_symm_apply_app, Functor.comp_obj, NatTrans.comp_app,
- natTransEquiv_apply_app, Functor.id_obj, whiskerLeft_app, Functor.map_comp, Category.assoc,
- unit_naturality_assoc, right_triangle_components_assoc, Equiv.symm_apply_apply,
- ← g.naturality_assoc, ← g.naturality]
- simp only [← Category.assoc, unit_naturality, Functor.comp_obj, right_triangle_components,
- Category.comp_id, ← f.naturality, Category.id_comp]
-
-@[simp]
-lemma natTransEquiv_comp_symm {F F' F'' : C ⥤ D} {G G' G'' : D ⥤ C}
- (adj1 : F ⊣ G) (adj2 : F' ⊣ G') (adj3 : F'' ⊣ G'') (f : F' ⟶ F) (g : F'' ⟶ F') :
- (natTransEquiv adj1 adj2).symm f ≫ (natTransEquiv adj2 adj3).symm g =
- (natTransEquiv adj1 adj3).symm (g ≫ f) := by
- apply (natTransEquiv adj1 adj3).injective
- ext
- simp
-
-/--
-If `F ⊣ G` and `F' ⊣ G'` are adjunctions, then giving a natural isomorphism `G ≅ G'` is the
-same as giving a natural transformation `F' ≅ F`.
--/
-@[simps]
-def natIsoEquiv {F F' : C ⥤ D} {G G' : D ⥤ C} (adj1 : F ⊣ G) (adj2 : F' ⊣ G') :
- (G ≅ G') ≃ (F' ≅ F) where
- toFun i := {
- hom := natTransEquiv adj1 adj2 i.hom
- inv := natTransEquiv adj2 adj1 i.inv
- }
- invFun i := {
- hom := (natTransEquiv adj1 adj2).symm i.hom
- inv := (natTransEquiv adj2 adj1).symm i.inv }
- left_inv i := by simp
- right_inv i := by simp
+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' :=
- (natIsoEquiv adj1 adj2 (Iso.refl _)).symm
+ ((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]
@@ -141,9 +53,10 @@ theorem unit_leftAdjointUniq_hom_app
theorem leftAdjointUniq_hom_counit {F F' : C ⥤ D} {G : D ⥤ C} (adj1 : F ⊣ G) (adj2 : F' ⊣ G) :
whiskerLeft G (leftAdjointUniq adj1 adj2).hom ≫ adj2.counit = adj1.counit := by
ext x
- simp only [Functor.comp_obj, Functor.id_obj, leftAdjointUniq, Iso.symm_hom, natIsoEquiv_apply_inv,
- Iso.refl_inv, NatTrans.comp_app, whiskerLeft_app, natTransEquiv_apply_app, whiskerLeft_id',
- Category.comp_id, Category.assoc]
+ simp only [Functor.comp_obj, Functor.id_obj, leftAdjointUniq, Iso.symm_hom,
+ conjugateIsoEquiv_symm_apply_inv, Iso.refl_inv, NatTrans.comp_app, whiskerLeft_app,
+ conjugateEquiv_symm_apply_app, NatTrans.id_app, Functor.map_id, Category.id_comp,
+ Category.assoc]
rw [← adj1.counit_naturality, ← Category.assoc, ← F.map_comp]
simp
@@ -180,9 +93,8 @@ theorem leftAdjointUniq_refl {F : C ⥤ D} {G : D ⥤ C} (adj1 : F ⊣ G) :
/-- If `G` and `G'` are both right adjoint to `F`, then they are naturally isomorphic. -/
def rightAdjointUniq {F : C ⥤ D} {G G' : D ⥤ C} (adj1 : F ⊣ G) (adj2 : F ⊣ G') : G ≅ G' :=
- (natIsoEquiv adj1 adj2).symm (Iso.refl _)
+ 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
@@ -192,8 +104,8 @@ theorem homEquiv_symm_rightAdjointUniq_hom_app {F : C ⥤ D} {G G' : D ⥤ C} (a
theorem unit_rightAdjointUniq_hom_app {F : C ⥤ D} {G G' : D ⥤ C} (adj1 : F ⊣ G) (adj2 : F ⊣ G')
(x : C) : adj1.unit.app x ≫ (rightAdjointUniq adj1 adj2).hom.app (F.obj x) =
adj2.unit.app x := by
- simp only [Functor.id_obj, Functor.comp_obj, rightAdjointUniq, natIsoEquiv_symm_apply_hom,
- Iso.refl_hom, natTransEquiv_symm_apply_app, NatTrans.id_app, Category.id_comp]
+ simp only [Functor.id_obj, Functor.comp_obj, rightAdjointUniq, conjugateIsoEquiv_apply_hom,
+ Iso.refl_hom, conjugateEquiv_apply_app, NatTrans.id_app, Functor.map_id, Category.id_comp]
rw [← adj2.unit_naturality_assoc, ← G'.map_comp]
simp
@@ -243,4 +155,7 @@ theorem rightAdjointUniq_refl {F : C ⥤ D} {G : D ⥤ C} (adj1 : F ⊣ G) :
end Adjunction
+@[deprecated (since := "2024-10-07")] alias Adjunction.natTransEquiv := conjugateEquiv
+@[deprecated (since := "2024-10-07")] alias Adjunction.natIsoEquiv := conjugateIsoEquiv
+
end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Adjunction/Whiskering.lean b/Mathlib/CategoryTheory/Adjunction/Whiskering.lean
index 83f8ab2a242f4..0a174fd66170b 100644
--- a/Mathlib/CategoryTheory/Adjunction/Whiskering.lean
+++ b/Mathlib/CategoryTheory/Adjunction/Whiskering.lean
@@ -25,36 +25,28 @@ variable (C : Type*) {D E : Type*} [Category C] [Category D] [Category E] {F : D
`(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
- (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
- mkOfUnitCounit
- { unit :=
- { app := fun X =>
- (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
- naturality := by intros; ext; dsimp; simp }
- counit :=
- { app := fun X =>
- (Functor.associator _ _ _).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor _).hom
- naturality := by intros; ext; dsimp; simp }
- left_triangle := by ext; dsimp; simp
- right_triangle := by ext; dsimp; simp
- }
+ (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G where
+ unit :=
+ { app := fun X =>
+ (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
+ naturality := by intros; ext; dsimp; simp }
+ counit :=
+ { app := fun X =>
+ (Functor.associator _ _ _).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor _).hom
+ naturality := by intros; ext; dsimp; simp }
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
`(whiskeringLeft _ _ C).obj G ⊣ (whiskeringLeft _ _ C).obj F`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerLeft (adj : F ⊣ G) :
- (whiskeringLeft E D C).obj G ⊣ (whiskeringLeft D E C).obj F :=
- mkOfUnitCounit
- { unit :=
- { app := fun X =>
- (Functor.leftUnitor _).inv ≫ whiskerRight adj.unit X ≫ (Functor.associator _ _ _).hom
- naturality := by intros; ext; dsimp; simp }
- counit :=
- { app := fun X =>
- (Functor.associator _ _ _).inv ≫ whiskerRight adj.counit X ≫ (Functor.leftUnitor _).hom
- naturality := by intros; ext; dsimp; simp }
- left_triangle := by ext x; dsimp; simp [Category.id_comp, Category.comp_id, ← x.map_comp]
- right_triangle := by ext x; dsimp; simp [Category.id_comp, Category.comp_id, ← x.map_comp]
- }
+ (whiskeringLeft E D C).obj G ⊣ (whiskeringLeft D E C).obj F where
+ unit :=
+ { app := fun X =>
+ (Functor.leftUnitor _).inv ≫ whiskerRight adj.unit X ≫ (Functor.associator _ _ _).hom }
+ counit :=
+ { app := fun X =>
+ (Functor.associator _ _ _).inv ≫ whiskerRight adj.counit X ≫ (Functor.leftUnitor _).hom }
+ left_triangle_components X := by ext; simp [← X.map_comp]
+ right_triangle_components X := by ext; simp [← X.map_comp]
end CategoryTheory.Adjunction
diff --git a/Mathlib/CategoryTheory/Bicategory/Adjunction.lean b/Mathlib/CategoryTheory/Bicategory/Adjunction.lean
index ae25dba05c39c..1c3d1f82e0da8 100644
--- a/Mathlib/CategoryTheory/Bicategory/Adjunction.lean
+++ b/Mathlib/CategoryTheory/Bicategory/Adjunction.lean
@@ -3,7 +3,7 @@ Copyright (c) 2023 Yuma Mizuno. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yuma Mizuno
-/
-import Mathlib.Tactic.CategoryTheory.Coherence
+import Mathlib.Tactic.CategoryTheory.Bicategory.Basic
/-!
# Adjunctions in bicategories
@@ -19,18 +19,6 @@ identities. The 2-morphism `η` is called the unit and `ε` is called the counit
* `Bicategory.mkOfAdjointifyCounit`: construct an adjoint equivalence from 2-isomorphisms
`η : 𝟙 a ≅ f ≫ g` and `ε : g ≫ f ≅ 𝟙 b`, by upgrading `ε` to a counit.
-## Implementation notes
-
-The computation of 2-morphisms in the proof is done using `calc` blocks. Typically,
-the LHS and the RHS in each step of `calc` are related by simple rewriting up to associators
-and unitors. So the proof for each step should be of the form `rw [...]; coherence`. In practice,
-our proofs look like `rw [...]; simp [bicategoricalComp]; coherence`. The `simp` is not strictly
-necessary, but it speeds up the proof and allow us to avoid increasing the `maxHeartbeats`.
-The speedup is probably due to reducing the length of the expression e.g. by absorbing
-identity maps or applying the pentagon relation. Such a hack may not be necessary if the
-coherence tactic is improved. One possible way would be to perform such a simplification in the
-preprocessing of the coherence tactic.
-
## TODO
* `Bicategory.mkOfAdjointifyUnit`: construct an adjoint equivalence from 2-isomorphisms
@@ -58,7 +46,7 @@ a ------ ▸ a
b ------ ▸ b
```
-/
-def leftZigzag (η : 𝟙 a ⟶ f ≫ g) (ε : g ≫ f ⟶ 𝟙 b) :=
+abbrev leftZigzag (η : 𝟙 a ⟶ f ≫ g) (ε : g ≫ f ⟶ 𝟙 b) :=
η ▷ f ⊗≫ f ◁ ε
/-- The 2-morphism defined by the following pasting diagram:
@@ -70,7 +58,7 @@ def leftZigzag (η : 𝟙 a ⟶ f ≫ g) (ε : g ≫ f ⟶ 𝟙 b) :=
b ------ ▸ b
```
-/
-def rightZigzag (η : 𝟙 a ⟶ f ≫ g) (ε : g ≫ f ⟶ 𝟙 b) :=
+abbrev rightZigzag (η : 𝟙 a ⟶ f ≫ g) (ε : g ≫ f ⟶ 𝟙 b) :=
g ◁ η ⊗≫ ε ▷ g
theorem rightZigzag_idempotent_of_left_triangle
@@ -79,13 +67,13 @@ theorem rightZigzag_idempotent_of_left_triangle
dsimp only [rightZigzag]
calc
_ = g ◁ η ⊗≫ ((ε ▷ g ▷ 𝟙 a) ≫ (𝟙 b ≫ g) ◁ η) ⊗≫ ε ▷ g := by
- simp [bicategoricalComp]; coherence
+ bicategory
_ = 𝟙 _ ⊗≫ g ◁ (η ▷ 𝟙 a ≫ (f ≫ g) ◁ η) ⊗≫ (ε ▷ (g ≫ f) ≫ 𝟙 b ◁ ε) ▷ g ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; simp [bicategoricalComp]; coherence
+ rw [← whisker_exchange]; bicategory
_ = g ◁ η ⊗≫ g ◁ leftZigzag η ε ▷ g ⊗≫ ε ▷ g := by
- rw [← whisker_exchange, ← whisker_exchange]; simp [leftZigzag, bicategoricalComp]; coherence
+ rw [← whisker_exchange, ← whisker_exchange, leftZigzag]; bicategory
_ = g ◁ η ⊗≫ ε ▷ g := by
- rw [h]; simp [bicategoricalComp]; coherence
+ rw [h]; bicategory
/-- Adjunction between two 1-morphisms. -/
structure Adjunction (f : a ⟶ b) (g : b ⟶ a) where
@@ -104,14 +92,14 @@ namespace Adjunction
attribute [simp] left_triangle right_triangle
-attribute [local simp] leftZigzag rightZigzag
+-- attribute [local simp] leftZigzag rightZigzag
/-- Adjunction between identities. -/
def id (a : B) : 𝟙 a ⊣ 𝟙 a where
unit := (ρ_ _).inv
counit := (ρ_ _).hom
- left_triangle := by dsimp; coherence
- right_triangle := by dsimp; coherence
+ left_triangle := by bicategory_coherence
+ right_triangle := by bicategory_coherence
instance : Inhabited (Adjunction (𝟙 a) (𝟙 a)) :=
⟨id a⟩
@@ -137,13 +125,13 @@ theorem comp_left_triangle_aux (adj₁ : f₁ ⊣ g₁) (adj₂ : f₂ ⊣ g₂)
adj₁.unit ▷ (f₁ ≫ f₂) ⊗≫
f₁ ◁ (adj₂.unit ▷ (g₁ ≫ f₁) ≫ (f₂ ≫ g₂) ◁ adj₁.counit) ▷ f₂ ⊗≫
(f₁ ≫ f₂) ◁ adj₂.counit ⊗≫ 𝟙 _ := by
- simp [bicategoricalComp]; coherence
+ dsimp only [compUnit, compCounit]; bicategory
_ = 𝟙 _ ⊗≫
(leftZigzag adj₁.unit adj₁.counit) ▷ f₂ ⊗≫
f₁ ◁ (leftZigzag adj₂.unit adj₂.counit) ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; simp [bicategoricalComp]; coherence
+ rw [← whisker_exchange]; bicategory
_ = _ := by
- simp_rw [left_triangle]; simp [bicategoricalComp]
+ simp_rw [left_triangle]; bicategory
theorem comp_right_triangle_aux (adj₁ : f₁ ⊣ g₁) (adj₂ : f₂ ⊣ g₂) :
rightZigzag (compUnit adj₁ adj₂) (compCounit adj₁ adj₂) = (ρ_ _).hom ≫ (λ_ _).inv := by
@@ -152,13 +140,13 @@ theorem comp_right_triangle_aux (adj₁ : f₁ ⊣ g₁) (adj₂ : f₂ ⊣ g₂
(g₂ ≫ g₁) ◁ adj₁.unit ⊗≫
g₂ ◁ ((g₁ ≫ f₁) ◁ adj₂.unit ≫ adj₁.counit ▷ (f₂ ≫ g₂)) ▷ g₁ ⊗≫
adj₂.counit ▷ (g₂ ≫ g₁) ⊗≫ 𝟙 _ := by
- simp [bicategoricalComp]; coherence
+ dsimp only [compUnit, compCounit]; bicategory
_ = 𝟙 _ ⊗≫
g₂ ◁ (rightZigzag adj₁.unit adj₁.counit) ⊗≫
(rightZigzag adj₂.unit adj₂.counit) ▷ g₁ ⊗≫ 𝟙 _ := by
- rw [whisker_exchange]; simp [bicategoricalComp]; coherence
+ rw [whisker_exchange]; bicategory
_ = _ := by
- simp_rw [right_triangle]; simp [bicategoricalComp]
+ simp_rw [right_triangle]; bicategory
/-- Composition of adjunctions. -/
@[simps]
@@ -177,15 +165,13 @@ noncomputable section
variable (η : 𝟙 a ≅ f ≫ g) (ε : g ≫ f ≅ 𝟙 b)
/-- The isomorphism version of `leftZigzag`. -/
-def leftZigzagIso (η : 𝟙 a ≅ f ≫ g) (ε : g ≫ f ≅ 𝟙 b) :=
+abbrev leftZigzagIso (η : 𝟙 a ≅ f ≫ g) (ε : g ≫ f ≅ 𝟙 b) :=
whiskerRightIso η f ≪⊗≫ whiskerLeftIso f ε
/-- The isomorphism version of `rightZigzag`. -/
-def rightZigzagIso (η : 𝟙 a ≅ f ≫ g) (ε : g ≫ f ≅ 𝟙 b) :=
+abbrev rightZigzagIso (η : 𝟙 a ≅ f ≫ g) (ε : g ≫ f ≅ 𝟙 b) :=
whiskerLeftIso g η ≪⊗≫ whiskerRightIso ε g
-attribute [local simp] leftZigzagIso rightZigzagIso leftZigzag rightZigzag
-
@[simp]
theorem leftZigzagIso_hom : (leftZigzagIso η ε).hom = leftZigzag η.hom ε.hom :=
rfl
@@ -218,7 +204,7 @@ theorem right_triangle_of_left_triangle (h : leftZigzag η.hom ε.hom = (λ_ f).
rightZigzag η.hom ε.hom = (ρ_ g).hom ≫ (λ_ g).inv := by
rw [← cancel_epi (rightZigzag η.hom ε.hom ≫ (λ_ g).hom ≫ (ρ_ g).inv)]
calc
- _ = rightZigzag η.hom ε.hom ⊗≫ rightZigzag η.hom ε.hom := by coherence
+ _ = rightZigzag η.hom ε.hom ⊗≫ rightZigzag η.hom ε.hom := by bicategory
_ = rightZigzag η.hom ε.hom := rightZigzag_idempotent_of_left_triangle _ _ h
_ = _ := by simp
@@ -233,15 +219,15 @@ theorem adjointifyCounit_left_triangle (η : 𝟙 a ≅ f ≫ g) (ε : g ≫ f
calc
_ = 𝟙 _ ⊗≫ (η.hom ▷ (f ≫ 𝟙 b) ≫ (f ≫ g) ◁ f ◁ ε.inv) ⊗≫
f ◁ g ◁ η.inv ▷ f ⊗≫ f ◁ ε.hom := by
- simp [bicategoricalComp]; coherence
+ bicategory
_ = 𝟙 _ ⊗≫ f ◁ ε.inv ⊗≫ (η.hom ▷ (f ≫ g) ≫ (f ≫ g) ◁ η.inv) ▷ f ⊗≫ f ◁ ε.hom := by
- rw [← whisker_exchange η.hom (f ◁ ε.inv)]; simp [bicategoricalComp]; coherence
+ rw [← whisker_exchange η.hom (f ◁ ε.inv)]; bicategory
_ = 𝟙 _ ⊗≫ f ◁ ε.inv ⊗≫ (η.inv ≫ η.hom) ▷ f ⊗≫ f ◁ ε.hom := by
- rw [← whisker_exchange η.hom η.inv]; coherence
+ rw [← whisker_exchange η.hom η.inv]; bicategory
_ = 𝟙 _ ⊗≫ f ◁ (ε.inv ≫ ε.hom) := by
- rw [Iso.inv_hom_id]; simp [bicategoricalComp]
+ rw [Iso.inv_hom_id]; bicategory
_ = _ := by
- rw [Iso.inv_hom_id]; simp [bicategoricalComp]
+ rw [Iso.inv_hom_id]; bicategory
/-- Adjoint equivalences between two objects. -/
structure Equivalence (a b : B) where
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 1caa7d9c14e97..a231874f15b0d 100644
--- a/Mathlib/CategoryTheory/Bicategory/End.lean
+++ b/Mathlib/CategoryTheory/Bicategory/End.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Bicategory.Basic
import Mathlib.CategoryTheory.Monoidal.Category
@@ -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/Lax.lean b/Mathlib/CategoryTheory/Bicategory/Functor/Lax.lean
index 6c70477096688..f4333e8be9f1e 100644
--- a/Mathlib/CategoryTheory/Bicategory/Functor/Lax.lean
+++ b/Mathlib/CategoryTheory/Bicategory/Functor/Lax.lean
@@ -6,6 +6,7 @@ Authors: Calle Sönne
import Mathlib.CategoryTheory.Bicategory.Functor.Prelax
import Mathlib.Tactic.CategoryTheory.Slice
+import Mathlib.Tactic.CategoryTheory.ToApp
/-!
# Lax functors
@@ -86,36 +87,36 @@ namespace LaxFunctor
variable {B : Type u₁} [Bicategory.{w₁, v₁} B] {C : Type u₂} [Bicategory.{w₂, v₂} C]
-attribute [reassoc (attr := simp)]
+attribute [reassoc (attr := simp), to_app (attr := simp)]
mapComp_naturality_left mapComp_naturality_right map₂_associator
-attribute [simp, reassoc] map₂_leftUnitor map₂_rightUnitor
+attribute [simp, reassoc, to_app] map₂_leftUnitor map₂_rightUnitor
/-- The underlying prelax functor. -/
add_decl_doc LaxFunctor.toPrelaxFunctor
variable (F : LaxFunctor B C)
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_assoc_left {a b c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) :
F.mapComp f g ▷ F.map h ≫ F.mapComp (f ≫ g) h = (α_ (F.map f) (F.map g) (F.map h)).hom ≫
F.map f ◁ F.mapComp g h ≫ F.mapComp f (g ≫ h) ≫ F.map₂ (α_ f g h).inv := by
rw [← F.map₂_associator_assoc, ← F.map₂_comp]
simp only [Iso.hom_inv_id, PrelaxFunctor.map₂_id, comp_id]
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_assoc_right {a b c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) :
F.map f ◁ F.mapComp g h ≫ F.mapComp f (g ≫ h) =
(α_ (F.map f) (F.map g) (F.map h)).inv ≫ F.mapComp f g ▷ F.map h ≫
F.mapComp (f ≫ g) h ≫ F.map₂ (α_ f g h).hom := by
simp only [map₂_associator, Iso.inv_hom_id_assoc]
-@[reassoc]
+@[reassoc, to_app]
lemma map₂_leftUnitor_hom {a b : B} (f : a ⟶ b) :
(λ_ (F.map f)).hom = F.mapId a ▷ F.map f ≫ F.mapComp (𝟙 a) f ≫ F.map₂ (λ_ f).hom := by
rw [← PrelaxFunctor.map₂Iso_hom, ← assoc, ← Iso.comp_inv_eq, ← Iso.eq_inv_comp]
simp only [Functor.mapIso_inv, PrelaxFunctor.mapFunctor_map, map₂_leftUnitor]
-@[reassoc]
+@[reassoc, to_app]
lemma map₂_rightUnitor_hom {a b : B} (f : a ⟶ b) :
(ρ_ (F.map f)).hom = F.map f ◁ F.mapId b ≫ F.mapComp f (𝟙 b) ≫ F.map₂ (ρ_ f).hom := by
rw [← PrelaxFunctor.map₂Iso_hom, ← assoc, ← Iso.comp_inv_eq, ← Iso.eq_inv_comp]
@@ -147,7 +148,7 @@ def comp {D : Type u₃} [Bicategory.{w₃, v₃} D] (F : LaxFunctor B C) (G : L
map₂_associator := fun f g h => by
dsimp
slice_rhs 1 3 =>
- rw [whiskerLeft_comp, assoc, ← mapComp_naturality_right, ← map₂_associator_assoc]
+ rw [Bicategory.whiskerLeft_comp, assoc, ← mapComp_naturality_right, ← map₂_associator_assoc]
slice_rhs 3 5 =>
rw [← G.map₂_comp, ← G.map₂_comp, ← F.map₂_associator, G.map₂_comp, G.map₂_comp]
slice_lhs 1 3 =>
@@ -160,7 +161,7 @@ def comp {D : Type u₃} [Bicategory.{w₃, v₃} D] (F : LaxFunctor B C) (G : L
map₂_rightUnitor := fun f => by
dsimp
simp only [map₂_rightUnitor, PrelaxFunctor.map₂_comp, assoc, mapComp_naturality_right_assoc,
- whiskerLeft_comp]
+ Bicategory.whiskerLeft_comp]
/-- A structure on an Lax functor that promotes an Lax functor to a pseudofunctor.
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/Oplax.lean b/Mathlib/CategoryTheory/Bicategory/Functor/Oplax.lean
index 9ac27f09df99a..9cf82c77a5732 100644
--- a/Mathlib/CategoryTheory/Bicategory/Functor/Oplax.lean
+++ b/Mathlib/CategoryTheory/Bicategory/Functor/Oplax.lean
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yuma Mizuno
-/
import Mathlib.CategoryTheory.Bicategory.Functor.Prelax
+import Mathlib.Tactic.CategoryTheory.ToApp
/-!
# Oplax functors
@@ -84,9 +85,9 @@ initialize_simps_projections OplaxFunctor (+toPrelaxFunctor, -obj, -map, -map₂
namespace OplaxFunctor
-attribute [reassoc (attr := simp)]
+attribute [reassoc (attr := simp), to_app (attr := simp)]
mapComp_naturality_left mapComp_naturality_right map₂_associator
-attribute [simp, reassoc] map₂_leftUnitor map₂_rightUnitor
+attribute [simp, reassoc, to_app] map₂_leftUnitor map₂_rightUnitor
section
@@ -95,7 +96,7 @@ add_decl_doc OplaxFunctor.toPrelaxFunctor
variable (F : OplaxFunctor B C)
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_assoc_right {a b c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) :
F.mapComp f (g ≫ h) ≫ F.map f ◁ F.mapComp g h = F.map₂ (α_ f g h).inv ≫
F.mapComp (f ≫ g) h ≫ F.mapComp f g ▷ F.map h ≫
@@ -103,7 +104,7 @@ lemma mapComp_assoc_right {a b c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d
rw [← F.map₂_associator, ← F.map₂_comp_assoc]
simp
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_assoc_left {a b c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) :
F.mapComp (f ≫ g) h ≫ F.mapComp f g ▷ F.map h =
F.map₂ (α_ f g h).hom ≫ F.mapComp f (g ≫ h) ≫ F.map f ◁ F.mapComp g h
@@ -138,7 +139,7 @@ def comp (F : OplaxFunctor B C) (G : OplaxFunctor C D) : OplaxFunctor B D where
map₂_associator := fun f g h => by
dsimp
simp only [map₂_associator, ← PrelaxFunctor.map₂_comp_assoc, ← mapComp_naturality_right_assoc,
- whiskerLeft_comp, assoc]
+ Bicategory.whiskerLeft_comp, assoc]
simp only [map₂_associator, PrelaxFunctor.map₂_comp, mapComp_naturality_left_assoc,
comp_whiskerRight, assoc]
map₂_leftUnitor := fun f => by
@@ -148,7 +149,7 @@ def comp (F : OplaxFunctor B C) (G : OplaxFunctor C D) : OplaxFunctor B D where
map₂_rightUnitor := fun f => by
dsimp
simp only [map₂_rightUnitor, PrelaxFunctor.map₂_comp, mapComp_naturality_right_assoc,
- whiskerLeft_comp, assoc]
+ Bicategory.whiskerLeft_comp, assoc]
/-- A structure on an oplax functor that promotes an oplax functor to a pseudofunctor.
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/Functor/Pseudofunctor.lean b/Mathlib/CategoryTheory/Bicategory/Functor/Pseudofunctor.lean
index 20e57f3061b67..7ec881a92dc67 100644
--- a/Mathlib/CategoryTheory/Bicategory/Functor/Pseudofunctor.lean
+++ b/Mathlib/CategoryTheory/Bicategory/Functor/Pseudofunctor.lean
@@ -94,7 +94,7 @@ initialize_simps_projections Pseudofunctor (+toPrelaxFunctor, -obj, -map, -map
namespace Pseudofunctor
-attribute [simp, reassoc]
+attribute [simp, reassoc, to_app]
map₂_whisker_left map₂_whisker_right map₂_associator map₂_left_unitor map₂_right_unitor
section
@@ -168,35 +168,35 @@ section
variable (F : Pseudofunctor B C) {a b : B}
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_assoc_right_hom {c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) :
(F.mapComp f (g ≫ h)).hom ≫ F.map f ◁ (F.mapComp g h).hom = F.map₂ (α_ f g h).inv ≫
(F.mapComp (f ≫ g) h).hom ≫ (F.mapComp f g).hom ▷ F.map h ≫
(α_ (F.map f) (F.map g) (F.map h)).hom :=
F.toOplax.mapComp_assoc_right _ _ _
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_assoc_left_hom {c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) :
(F.mapComp (f ≫ g) h).hom ≫ (F.mapComp f g).hom ▷ F.map h =
F.map₂ (α_ f g h).hom ≫ (F.mapComp f (g ≫ h)).hom ≫ F.map f ◁ (F.mapComp g h).hom
≫ (α_ (F.map f) (F.map g) (F.map h)).inv :=
F.toOplax.mapComp_assoc_left _ _ _
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_assoc_right_inv {c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) :
F.map f ◁ (F.mapComp g h).inv ≫ (F.mapComp f (g ≫ h)).inv =
(α_ (F.map f) (F.map g) (F.map h)).inv ≫ (F.mapComp f g).inv ▷ F.map h ≫
(F.mapComp (f ≫ g) h).inv ≫ F.map₂ (α_ f g h).hom :=
F.toLax.mapComp_assoc_right _ _ _
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_assoc_left_inv {c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) :
(F.mapComp f g).inv ▷ F.map h ≫ (F.mapComp (f ≫ g) h).inv =
(α_ (F.map f) (F.map g) (F.map h)).hom ≫ F.map f ◁ (F.mapComp g h).inv ≫
(F.mapComp f (g ≫ h)).inv ≫ F.map₂ (α_ f g h).inv :=
F.toLax.mapComp_assoc_left _ _ _
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_id_left_hom (f : a ⟶ b) : (F.mapComp (𝟙 a) f).hom =
F.map₂ (λ_ f).hom ≫ (λ_ (F.map f)).inv ≫ (F.mapId a).inv ▷ F.map f := by
simp
@@ -205,7 +205,7 @@ lemma mapComp_id_left (f : a ⟶ b) : (F.mapComp (𝟙 a) f) = F.map₂Iso (λ_
(λ_ (F.map f)).symm ≪≫ (whiskerRightIso (F.mapId a) (F.map f)).symm :=
Iso.ext <| F.mapComp_id_left_hom f
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_id_left_inv (f : a ⟶ b) : (F.mapComp (𝟙 a) f).inv =
(F.mapId a).hom ▷ F.map f ≫ (λ_ (F.map f)).hom ≫ F.map₂ (λ_ f).inv := by
simp [mapComp_id_left]
@@ -214,17 +214,17 @@ lemma whiskerRightIso_mapId (f : a ⟶ b) : whiskerRightIso (F.mapId a) (F.map f
(F.mapComp (𝟙 a) f).symm ≪≫ F.map₂Iso (λ_ f) ≪≫ (λ_ (F.map f)).symm := by
simp [mapComp_id_left]
-@[reassoc]
+@[reassoc, to_app]
lemma whiskerRight_mapId_hom (f : a ⟶ b) : (F.mapId a).hom ▷ F.map f =
(F.mapComp (𝟙 a) f).inv ≫ F.map₂ (λ_ f).hom ≫ (λ_ (F.map f)).inv := by
simp [whiskerRightIso_mapId]
-@[reassoc]
+@[reassoc, to_app]
lemma whiskerRight_mapId_inv (f : a ⟶ b) : (F.mapId a).inv ▷ F.map f =
(λ_ (F.map f)).hom ≫ F.map₂ (λ_ f).inv ≫ (F.mapComp (𝟙 a) f).hom := by
simpa using congrArg (·.inv) (F.whiskerRightIso_mapId f)
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_id_right_hom (f : a ⟶ b) : (F.mapComp f (𝟙 b)).hom =
F.map₂ (ρ_ f).hom ≫ (ρ_ (F.map f)).inv ≫ F.map f ◁ (F.mapId b).inv := by
simp
@@ -233,7 +233,7 @@ lemma mapComp_id_right (f : a ⟶ b) : (F.mapComp f (𝟙 b)) = F.map₂Iso (ρ_
(ρ_ (F.map f)).symm ≪≫ (whiskerLeftIso (F.map f) (F.mapId b)).symm :=
Iso.ext <| F.mapComp_id_right_hom f
-@[reassoc]
+@[reassoc, to_app]
lemma mapComp_id_right_inv (f : a ⟶ b) : (F.mapComp f (𝟙 b)).inv =
F.map f ◁ (F.mapId b).hom ≫ (ρ_ (F.map f)).hom ≫ F.map₂ (ρ_ f).inv := by
simp [mapComp_id_right]
@@ -242,12 +242,12 @@ lemma whiskerLeftIso_mapId (f : a ⟶ b) : whiskerLeftIso (F.map f) (F.mapId b)
(F.mapComp f (𝟙 b)).symm ≪≫ F.map₂Iso (ρ_ f) ≪≫ (ρ_ (F.map f)).symm := by
simp [mapComp_id_right]
-@[reassoc]
+@[reassoc, to_app]
lemma whiskerLeft_mapId_hom (f : a ⟶ b) : F.map f ◁ (F.mapId b).hom =
(F.mapComp f (𝟙 b)).inv ≫ F.map₂ (ρ_ f).hom ≫ (ρ_ (F.map f)).inv := by
simp [whiskerLeftIso_mapId]
-@[reassoc]
+@[reassoc, to_app]
lemma whiskerLeft_mapId_inv (f : a ⟶ b) : F.map f ◁ (F.mapId b).inv =
(ρ_ (F.map f)).hom ≫ F.map₂ (ρ_ f).inv ≫ (F.mapComp f (𝟙 b)).hom := by
simpa using congrArg (·.inv) (F.whiskerLeftIso_mapId f)
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/Adjunction.lean b/Mathlib/CategoryTheory/Bicategory/Kan/Adjunction.lean
index f35b3606bbc88..ac3e11be6fb37 100644
--- a/Mathlib/CategoryTheory/Bicategory/Kan/Adjunction.lean
+++ b/Mathlib/CategoryTheory/Bicategory/Kan/Adjunction.lean
@@ -29,8 +29,6 @@ similar results for right Kan extensions and right Kan lifts.
namespace CategoryTheory
-open Mathlib.Tactic.BicategoryCoherence bicategoricalComp
-
namespace Bicategory
universe w v u
@@ -49,11 +47,13 @@ def Adjunction.isAbsoluteLeftKan {f : a ⟶ b} {u : b ⟶ a} (adj : f ⊣ u) :
(𝟙 _ ⊗≫ u ◁ s.unit ⊗≫ adj.counit ▷ s.extension ⊗≫ 𝟙 _ : u ≫ h ⟶ s.extension) <|
calc _
_ = 𝟙 _ ⊗≫ (adj.unit ▷ _ ≫ _ ◁ s.unit) ⊗≫ f ◁ adj.counit ▷ s.extension ⊗≫ 𝟙 _ := by
- simp [bicategoricalComp]
+ dsimp only [whisker_extension, StructuredArrow.mk_right, whisker_unit,
+ StructuredArrow.mk_hom_eq_self]
+ bicategory
_ = 𝟙 _ ⊗≫ s.unit ⊗≫ leftZigzag adj.unit adj.counit ▷ s.extension ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange, leftZigzag]; simp [bicategoricalComp]
+ rw [← whisker_exchange]; bicategory
_ = s.unit := by
- rw [adj.left_triangle]; simp [bicategoricalComp]) <| by
+ rw [adj.left_triangle]; bicategory) <| by
intro s τ₀
ext
/- We need to specify the type of `τ` to use the notation `⊗≫`. -/
@@ -62,13 +62,13 @@ def Adjunction.isAbsoluteLeftKan {f : a ⟶ b} {u : b ⟶ a} (adj : f ⊣ u) :
simpa [bicategoricalComp] using LeftExtension.w τ₀
calc τ
_ = 𝟙 _ ⊗≫ rightZigzag adj.unit adj.counit ▷ h ⊗≫ τ ⊗≫ 𝟙 _ := by
- rw [adj.right_triangle]; simp [bicategoricalComp]
+ rw [adj.right_triangle]; bicategory
_ = 𝟙 _ ⊗≫ u ◁ adj.unit ▷ h ⊗≫ (adj.counit ▷ _ ≫ _ ◁ τ) ⊗≫ 𝟙 _ := by
- rw [rightZigzag]; simp [bicategoricalComp]
+ rw [rightZigzag]; bicategory
_ = 𝟙 _ ⊗≫ u ◁ (adj.unit ▷ h ⊗≫ f ◁ τ) ⊗≫ adj.counit ▷ s.extension ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; simp [bicategoricalComp]
+ rw [← whisker_exchange]; bicategory
_ = _ := by
- rw [hτ]; simp [bicategoricalComp]
+ rw [hτ]; dsimp only [StructuredArrow.homMk_right]
/-- A left Kan extension of the identity along `f` such that `f` commutes with is a right adjoint
to `f`. The unit of this adjoint is given by the unit of the Kan extension. -/
@@ -86,13 +86,13 @@ def LeftExtension.IsKan.adjunction {f : a ⟶ b} {t : LeftExtension f (𝟙 a)}
apply H.hom_ext
calc _
_ = 𝟙 _ ⊗≫ t.unit ⊗≫ f ◁ rightZigzag t.unit ε ⊗≫ 𝟙 _ := by
- simp [bicategoricalComp]
+ bicategory
_ = 𝟙 _ ⊗≫ (t.unit ▷ _ ≫ _ ◁ t.unit) ⊗≫ f ◁ ε ▷ t.extension ⊗≫ 𝟙 _ := by
- rw [rightZigzag]; simp [bicategoricalComp]
+ rw [rightZigzag]; bicategory
_ = 𝟙 _ ⊗≫ t.unit ⊗≫ (t.unit ▷ f ⊗≫ f ◁ ε) ▷ t.extension ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; simp [bicategoricalComp]
+ rw [← whisker_exchange]; bicategory
_ = _ := by
- rw [← leftZigzag, Hε]; simp [bicategoricalComp] }
+ rw [← leftZigzag, Hε]; bicategory }
/-- For an adjuntion `f ⊣ u`, `u` is a left Kan extension of the identity along `f`.
The unit of this Kan extension is given by the unit of the adjunction. -/
@@ -106,14 +106,11 @@ theorem isLeftAdjoint_TFAE (f : a ⟶ b) :
HasAbsLeftKanExtension f (𝟙 a),
∃ _ : HasLeftKanExtension f (𝟙 a), Lan.CommuteWith f (𝟙 a) f] := by
tfae_have 1 → 2
- · intro h
- exact IsAbsKan.hasAbsLeftKanExtension (Adjunction.ofIsLeftAdjoint f).isAbsoluteLeftKan
+ | h => IsAbsKan.hasAbsLeftKanExtension (Adjunction.ofIsLeftAdjoint f).isAbsoluteLeftKan
tfae_have 2 → 3
- · intro h
- exact ⟨inferInstance, inferInstance⟩
+ | h => ⟨inferInstance, inferInstance⟩
tfae_have 3 → 1
- · intro ⟨h, h'⟩
- exact .mk <| (lanIsKan f (𝟙 a)).adjunction <| Lan.CommuteWith.isKan f (𝟙 a) f
+ | ⟨h, h'⟩ => .mk <| (lanIsKan f (𝟙 a)).adjunction <| Lan.CommuteWith.isKan f (𝟙 a) f
tfae_finish
end LeftExtension
@@ -130,11 +127,13 @@ def Adjunction.isAbsoluteLeftKanLift {f : a ⟶ b} {u : b ⟶ a} (adj : f ⊣ u)
(𝟙 _ ⊗≫ s.unit ▷ f ⊗≫ s.lift ◁ adj.counit ⊗≫ 𝟙 _ : h ≫ f ⟶ s.lift) <|
calc _
_ = 𝟙 _ ⊗≫ (_ ◁ adj.unit ≫ s.unit ▷ _) ⊗≫ s.lift ◁ adj.counit ▷ u ⊗≫ 𝟙 _ := by
- simp [bicategoricalComp]
+ dsimp only [whisker_lift, StructuredArrow.mk_right, whisker_unit,
+ StructuredArrow.mk_hom_eq_self]
+ bicategory
_ = s.unit ⊗≫ s.lift ◁ (rightZigzag adj.unit adj.counit) ⊗≫ 𝟙 _ := by
- rw [whisker_exchange, rightZigzag]; simp [bicategoricalComp]
+ rw [whisker_exchange, rightZigzag]; bicategory
_ = s.unit := by
- rw [adj.right_triangle]; simp [bicategoricalComp]) <| by
+ rw [adj.right_triangle]; bicategory) <| by
intro s τ₀
ext
/- We need to specify the type of `τ` to use the notation `⊗≫`. -/
@@ -142,13 +141,13 @@ def Adjunction.isAbsoluteLeftKanLift {f : a ⟶ b} {u : b ⟶ a} (adj : f ⊣ u)
have hτ : h ◁ adj.unit ⊗≫ τ ▷ u = s.unit := by simpa [bicategoricalComp] using LeftLift.w τ₀
calc τ
_ = 𝟙 _ ⊗≫ h ◁ leftZigzag adj.unit adj.counit ⊗≫ τ ⊗≫ 𝟙 _ := by
- rw [adj.left_triangle]; simp [bicategoricalComp]
+ rw [adj.left_triangle]; bicategory
_ = 𝟙 _ ⊗≫ h ◁ adj.unit ▷ f ⊗≫ (_ ◁ adj.counit ≫ τ ▷ _) ⊗≫ 𝟙 _ := by
- rw [leftZigzag]; simp [bicategoricalComp]
+ rw [leftZigzag]; bicategory
_ = 𝟙 _ ⊗≫ (h ◁ adj.unit ⊗≫ τ ▷ u) ▷ f ⊗≫ s.lift ◁ adj.counit ⊗≫ 𝟙 _ := by
- rw [whisker_exchange]; simp [bicategoricalComp]
+ rw [whisker_exchange]; bicategory
_ = _ := by
- rw [hτ]; simp [bicategoricalComp]
+ rw [hτ]; dsimp only [StructuredArrow.homMk_right]
/-- A left Kan lift of the identity along `u` such that `u` commutes with is a left adjoint
to `u`. The unit of this adjoint is given by the unit of the Kan lift. -/
@@ -165,13 +164,13 @@ def LeftLift.IsKan.adjunction {u : b ⟶ a} {t : LeftLift u (𝟙 a)}
apply H.hom_ext
calc _
_ = 𝟙 _ ⊗≫ t.unit ⊗≫ leftZigzag t.unit ε ▷ u ⊗≫ 𝟙 _ := by
- simp [bicategoricalComp]
+ bicategory
_ = 𝟙 _ ⊗≫ (_ ◁ t.unit ≫ t.unit ▷ _) ⊗≫ t.lift ◁ ε ▷ u ⊗≫ 𝟙 _ := by
- rw [leftZigzag]; simp [bicategoricalComp]
+ rw [leftZigzag]; bicategory
_ = 𝟙 _ ⊗≫ t.unit ⊗≫ t.lift ◁ (u ◁ t.unit ⊗≫ ε ▷ u) ⊗≫ 𝟙 _ := by
- rw [whisker_exchange]; simp [bicategoricalComp]
+ rw [whisker_exchange]; bicategory
_ = _ := by
- rw [← rightZigzag, Hε]; simp [bicategoricalComp]
+ rw [← rightZigzag, Hε]; bicategory
right_triangle := Hε }
/-- For an adjuntion `f ⊣ u`, `f` is a left Kan lift of the identity along `u`.
@@ -186,14 +185,11 @@ theorem isRightAdjoint_TFAE (u : b ⟶ a) :
HasAbsLeftKanLift u (𝟙 a),
∃ _ : HasLeftKanLift u (𝟙 a), LanLift.CommuteWith u (𝟙 a) u] := by
tfae_have 1 → 2
- · intro h
- exact IsAbsKan.hasAbsLeftKanLift (Adjunction.ofIsRightAdjoint u).isAbsoluteLeftKanLift
+ | h => IsAbsKan.hasAbsLeftKanLift (Adjunction.ofIsRightAdjoint u).isAbsoluteLeftKanLift
tfae_have 2 → 3
- · intro h
- exact ⟨inferInstance, inferInstance⟩
+ | h => ⟨inferInstance, inferInstance⟩
tfae_have 3 → 1
- · intro ⟨h, h'⟩
- exact .mk <| (lanLiftIsKan u (𝟙 a)).adjunction <| LanLift.CommuteWith.isKan u (𝟙 a) u
+ | ⟨h, h'⟩ => .mk <| (lanLiftIsKan u (𝟙 a)).adjunction <| LanLift.CommuteWith.isKan u (𝟙 a) u
tfae_finish
end LeftLift
@@ -210,18 +206,28 @@ def isKanOfWhiskerLeftAdjoint
.mk (fun s ↦
let k := s.extension
let θ := s.unit
- let τ : t.extension ⟶ k ≫ u := H.desc (.mk _ <| 𝟙 _ ⊗≫ g ◁ η' ⊗≫ θ ▷ u ⊗≫ 𝟙 _)
- let σ : t.extension ≫ h ⟶ k := H'.desc <| (.mk _ <| (ρ_ _).hom ≫ τ)
+ let sτ := LeftExtension.mk _ <| 𝟙 _ ⊗≫ g ◁ η' ⊗≫ θ ▷ u ⊗≫ 𝟙 _
+ let τ : t.extension ⟶ k ≫ u := H.desc sτ
+ let sσ := LeftLift.mk _ <| (ρ_ _).hom ≫ τ
+ let σ : t.extension ≫ h ⟶ k := H'.desc sσ
LeftExtension.homMk σ <| (H' g).hom_ext <| by
have Hσ : t.extension ◁ η' ⊗≫ σ ▷ u = 𝟙 _ ⊗≫ τ := by
simpa [bicategoricalComp] using (H' _).fac (.mk _ <| (ρ_ _).hom ≫ τ)
+ dsimp only [LeftLift.whisker_lift, StructuredArrow.mk_right, LeftLift.whisker_unit,
+ StructuredArrow.mk_hom_eq_self, whisker_extension, whisker_unit]
calc _
- _ = 𝟙 _ ⊗≫ (g ◁ η' ≫ t.unit ▷ (h ≫ u)) ⊗≫ f ◁ σ ▷ u ⊗≫ 𝟙 _ := by
- simp [bicategoricalComp]
- _ = 𝟙 _ ⊗≫ t.unit ▷ (𝟙 c) ⊗≫ f ◁ (t.extension ◁ η' ⊗≫ σ ▷ u) ⊗≫ 𝟙 _ := by
- rw [whisker_exchange]; simp [bicategoricalComp]
+ _ = (g ◁ η' ≫ t.unit ▷ (h ≫ u)) ⊗≫ f ◁ σ ▷ u ⊗≫ 𝟙 _ := by
+ bicategory
+ _ = t.unit ▷ (𝟙 c) ⊗≫ f ◁ (t.extension ◁ η' ⊗≫ σ ▷ u) ⊗≫ 𝟙 _ := by
+ rw [whisker_exchange]; bicategory
+ _ = (ρ_ g).hom ≫ t.unit ≫ f ◁ H.desc sτ ≫ (α_ f s.extension u).inv := by
+ rw [Hσ]
+ dsimp only [τ]
+ bicategory
_ = _ := by
- rw [Hσ]; simp [τ, bicategoricalComp]) <| by
+ rw [IsKan.fac_assoc]
+ dsimp only [StructuredArrow.mk_right, StructuredArrow.mk_hom_eq_self, sτ]
+ bicategory) <| by
intro s' τ₀'
let τ' : t.extension ≫ h ⟶ s'.extension := τ₀'.right
have Hτ' : t.unit ▷ h ⊗≫ f ◁ τ' = s'.unit := by simpa [bicategoricalComp] using τ₀'.w.symm
@@ -231,13 +237,20 @@ def isKanOfWhiskerLeftAdjoint
rw [(H' _).fac]
apply (cancel_epi (ρ_ _).inv).mp
apply H.hom_ext
+ dsimp only [LeftLift.whisker_lift, StructuredArrow.mk_right, LeftLift.whisker_unit,
+ StructuredArrow.mk_hom_eq_self]
+ let σs' := LeftExtension.mk (s'.extension ≫ u)
+ (𝟙 g ⊗≫ g ◁ η' ⊗≫ s'.unit ▷ u ⊗≫ 𝟙 (f ≫ s'.extension ≫ u))
calc _
_ = 𝟙 _ ⊗≫ (t.unit ▷ (𝟙 c) ≫ (f ≫ t.extension) ◁ η') ⊗≫ f ◁ τ' ▷ u := by
- simp [bicategoricalComp]
+ bicategory
_ = 𝟙 g ⊗≫ g ◁ η' ⊗≫ (t.unit ▷ h ⊗≫ f ◁ τ') ▷ u ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; simp [bicategoricalComp]
+ rw [← whisker_exchange]; bicategory
+ _ = t.unit ≫ f ◁ H.desc σs' := by
+ rw [Hτ', IsKan.fac]
+ dsimp only [StructuredArrow.mk_hom_eq_self, σs']
_ = _ := by
- rw [Hτ']; simp [bicategoricalComp]
+ bicategory
instance {f : a ⟶ b} {g : a ⟶ c} {x : B} {h : c ⟶ x} [IsLeftAdjoint h] [HasLeftKanExtension f g] :
Lan.CommuteWith f g h :=
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 5a1b8b335b237..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⟩
@@ -92,7 +92,7 @@ variable {a b c : B} {a' : C}
theorem whiskerLeft_naturality_naturality (f : a' ⟶ G.obj a) {g h : a ⟶ b} (β : g ⟶ h) :
f ◁ G.map₂ β ▷ θ.app b ≫ f ◁ θ.naturality h =
f ◁ θ.naturality g ≫ f ◁ θ.app a ◁ H.map₂ β := by
- simp_rw [← whiskerLeft_comp, naturality_naturality]
+ simp_rw [← Bicategory.whiskerLeft_comp, naturality_naturality]
@[reassoc (attr := simp)]
theorem whiskerRight_naturality_naturality {f g : a ⟶ b} (β : f ⟶ g) (h : G.obj b ⟶ a') :
@@ -107,7 +107,7 @@ theorem whiskerLeft_naturality_comp (f : a' ⟶ G.obj a) (g : a ⟶ b) (h : b
f ◁ (α_ _ _ _).hom ≫
f ◁ G.map g ◁ θ.naturality h ≫
f ◁ (α_ _ _ _).inv ≫ f ◁ θ.naturality g ▷ H.map h ≫ f ◁ (α_ _ _ _).hom := by
- simp_rw [← whiskerLeft_comp, naturality_comp]
+ simp_rw [← Bicategory.whiskerLeft_comp, naturality_comp]
@[reassoc (attr := simp)]
theorem whiskerRight_naturality_comp (f : a ⟶ b) (g : b ⟶ c) (h : G.obj c ⟶ a') :
@@ -125,7 +125,7 @@ theorem whiskerRight_naturality_comp (f : a ⟶ b) (g : b ⟶ c) (h : G.obj c
theorem whiskerLeft_naturality_id (f : a' ⟶ G.obj a) :
f ◁ θ.naturality (𝟙 a) ≫ f ◁ θ.app a ◁ H.mapId a =
f ◁ G.mapId a ▷ θ.app a ≫ f ◁ (λ_ (θ.app a)).hom ≫ f ◁ (ρ_ (θ.app a)).inv := by
- simp_rw [← whiskerLeft_comp, naturality_id]
+ simp_rw [← Bicategory.whiskerLeft_comp, naturality_id]
@[reassoc (attr := simp)]
theorem whiskerRight_naturality_id (f : G.obj a ⟶ a') :
@@ -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 [← 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 7619fce58c22c..5a01fd30b13ce 100644
--- a/Mathlib/CategoryTheory/Bicategory/SingleObj.lean
+++ b/Mathlib/CategoryTheory/Bicategory/SingleObj.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Bicategory.End
import Mathlib.CategoryTheory.Monoidal.Functor
@@ -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/Basic.lean b/Mathlib/CategoryTheory/Category/Basic.lean
index 4ca2259bf0998..d314808670795 100644
--- a/Mathlib/CategoryTheory/Category/Basic.lean
+++ b/Mathlib/CategoryTheory/Category/Basic.lean
@@ -1,12 +1,13 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison, Johannes Hölzl, Reid Barton
+Authors: Stephen Morgan, Kim Morrison, Johannes Hölzl, Reid Barton
-/
import Mathlib.CategoryTheory.Category.Init
import Mathlib.Combinatorics.Quiver.Basic
import Mathlib.Tactic.PPWithUniv
import Mathlib.Tactic.Common
+import Mathlib.Tactic.StacksAttribute
/-!
# Categories
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 3d4788b016f0d..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
@@ -133,6 +133,14 @@ lemma associator_inv_app {B C D E : Cat} (F : B ⟶ C) (G : C ⟶ D) (H : D ⟶
(α_ F G H).inv.app X = eqToHom (by simp) :=
rfl
+/-- The identity in the category of categories equals the identity functor.-/
+theorem id_eq_id (X : Cat) : 𝟙 X = 𝟭 X := rfl
+
+/-- Composition in the category of categories equals functor composition.-/
+theorem comp_eq_comp {X Y Z : Cat} (F : X ⟶ Y) (G : Y ⟶ Z) : F ≫ G = F ⋙ G := rfl
+
+@[simp] theorem of_α (C) [Category C] : (of C).α = C := rfl
+
/-- Functor that gets the set of objects of a category. It is not
called `forget`, because it is not a faithful functor. -/
def objects : Cat.{v, u} ⥤ Type u where
diff --git a/Mathlib/CategoryTheory/Category/Cat/Adjunction.lean b/Mathlib/CategoryTheory/Category/Cat/Adjunction.lean
index 55e17bc93bec4..229d0fbddea78 100644
--- a/Mathlib/CategoryTheory/Category/Cat/Adjunction.lean
+++ b/Mathlib/CategoryTheory/Category/Cat/Adjunction.lean
@@ -39,15 +39,16 @@ private def typeToCatObjectsAdjCounitApp : (Cat.objects ⋙ typeToCat).obj C ⥤
map := eqToHom ∘ Discrete.eq_of_hom
/-- `typeToCat : Type ⥤ Cat` is left adjoint to `Cat.objects : Cat ⥤ Type` -/
-def typeToCatObjectsAdj : typeToCat ⊣ Cat.objects where
- homEquiv := typeToCatObjectsAdjHomEquiv
- unit := { app:= fun _ ↦ Discrete.mk }
- counit := {
- app := typeToCatObjectsAdjCounitApp
- naturality := fun _ _ _ ↦ Functor.hext (fun _ ↦ rfl)
- (by intro ⟨_⟩ ⟨_⟩ f
- obtain rfl := Discrete.eq_of_hom f
- aesop_cat ) }
+def typeToCatObjectsAdj : typeToCat ⊣ Cat.objects :=
+ Adjunction.mk' {
+ homEquiv := typeToCatObjectsAdjHomEquiv
+ unit := { app:= fun _ ↦ Discrete.mk }
+ counit := {
+ app := typeToCatObjectsAdjCounitApp
+ naturality := fun _ _ _ ↦ Functor.hext (fun _ ↦ rfl)
+ (by intro ⟨_⟩ ⟨_⟩ f
+ obtain rfl := Discrete.eq_of_hom f
+ aesop_cat ) } }
/-- The connected components functor -/
def connectedComponents : Cat.{v, u} ⥤ Type u where
@@ -57,15 +58,20 @@ def connectedComponents : Cat.{v, u} ⥤ Type u where
map_comp _ _ := funext fun x ↦ (Quotient.exists_rep x).elim (fun _ h => by subst h; rfl)
/-- `typeToCat : Type ⥤ Cat` is right adjoint to `connectedComponents : Cat ⥤ Type` -/
-def connectedComponentsTypeToCatAdj : connectedComponents ⊣ typeToCat where
- homEquiv C X := ConnectedComponents.typeToCatHomEquiv C X
- unit := { app:= fun C ↦ ConnectedComponents.functorToDiscrete _ (𝟙 (connectedComponents.obj C)) }
- counit := {
- app := fun X => ConnectedComponents.liftFunctor _ (𝟙 typeToCat.obj X)
- naturality := fun _ _ _ =>
- funext (fun xcc => by
- obtain ⟨x,h⟩ := Quotient.exists_rep xcc
- aesop_cat) }
- homEquiv_counit := fun {C X G} => by funext cc;obtain ⟨_,_⟩ := Quotient.exists_rep cc; aesop_cat
+def connectedComponentsTypeToCatAdj : connectedComponents ⊣ typeToCat :=
+ Adjunction.mk' {
+ homEquiv := fun C X ↦ ConnectedComponents.typeToCatHomEquiv C X
+ unit :=
+ { app:= fun C ↦ ConnectedComponents.functorToDiscrete _ (𝟙 (connectedComponents.obj C)) }
+ counit := {
+ app := fun X => ConnectedComponents.liftFunctor _ (𝟙 typeToCat.obj X)
+ naturality := fun _ _ _ =>
+ funext (fun xcc => by
+ obtain ⟨x,h⟩ := Quotient.exists_rep xcc
+ aesop_cat) }
+ homEquiv_counit := fun {C X G} => by
+ funext cc
+ obtain ⟨_,_⟩ := Quotient.exists_rep cc
+ aesop_cat }
end CategoryTheory.Cat
diff --git a/Mathlib/CategoryTheory/Category/Cat/Limit.lean b/Mathlib/CategoryTheory/Category/Cat/Limit.lean
index 6b3e9d578c572..92300512f30e6 100644
--- a/Mathlib/CategoryTheory/Category/Cat/Limit.lean
+++ b/Mathlib/CategoryTheory/Category/Cat/Limit.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Category.Cat
import Mathlib.CategoryTheory.Limits.Types
@@ -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/GaloisConnection.lean b/Mathlib/CategoryTheory/Category/GaloisConnection.lean
index 41362d5292353..a79e29a39e4c2 100644
--- a/Mathlib/CategoryTheory/Category/GaloisConnection.lean
+++ b/Mathlib/CategoryTheory/Category/GaloisConnection.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison, Johannes Hölzl, Reid Barton
+Authors: Stephen Morgan, Kim Morrison, Johannes Hölzl, Reid Barton
-/
import Mathlib.CategoryTheory.Category.Preorder
import Mathlib.CategoryTheory.Adjunction.Basic
diff --git a/Mathlib/CategoryTheory/Category/Pairwise.lean b/Mathlib/CategoryTheory/Category/Pairwise.lean
index a8e795bdc19ac..7b800d357beb0 100644
--- a/Mathlib/CategoryTheory/Category/Pairwise.lean
+++ b/Mathlib/CategoryTheory/Category/Pairwise.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Order.CompleteLattice
import Mathlib.CategoryTheory.Category.Preorder
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/Preorder.lean b/Mathlib/CategoryTheory/Category/Preorder.lean
index f46afa90197a5..f2935460a2529 100644
--- a/Mathlib/CategoryTheory/Category/Preorder.lean
+++ b/Mathlib/CategoryTheory/Category/Preorder.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison, Johannes Hölzl, Reid Barton
+Authors: Stephen Morgan, Kim Morrison, Johannes Hölzl, Reid Barton
-/
import Mathlib.CategoryTheory.Equivalence
import Mathlib.CategoryTheory.EqToHom
diff --git a/Mathlib/CategoryTheory/Category/Quiv.lean b/Mathlib/CategoryTheory/Category/Quiv.lean
index 40f840da97067..b8ad841e24d51 100644
--- a/Mathlib/CategoryTheory/Category/Quiv.lean
+++ b/Mathlib/CategoryTheory/Category/Quiv.lean
@@ -1,20 +1,18 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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
The category of (bundled) quivers, and the free/forgetful adjunction between `Cat` and `Quiv`.
-
-/
-
universe v u
namespace CategoryTheory
@@ -51,6 +49,12 @@ def forget : Cat.{v, u} ⥤ Quiv.{v, u} where
obj C := Quiv.of C
map F := F.toPrefunctor
+/-- The identity in the category of quivers equals the identity prefunctor.-/
+theorem id_eq_id (X : Quiv) : 𝟙 X = 𝟭q X := rfl
+
+/-- Composition in the category of quivers equals prefunctor composition.-/
+theorem comp_eq_comp {X Y Z : Quiv} (F : X ⟶ Y) (G : Y ⟶ Z) : F ≫ G = F ⋙q G := rfl
+
end Quiv
namespace Cat
@@ -65,14 +69,14 @@ def free : Quiv.{v, u} ⥤ Cat.{max u v, u} where
map_comp := fun f g => F.mapPath_comp f g }
map_id V := by
change (show Paths V ⥤ _ from _) = _
- ext; swap
- · apply eq_conj_eqToHom
+ ext
· rfl
+ · exact eq_conj_eqToHom _
map_comp {U _ _} F G := by
change (show Paths U ⥤ _ from _) = _
- ext; swap
- · apply eq_conj_eqToHom
+ ext
· rfl
+ · exact eq_conj_eqToHom _
end Cat
@@ -105,9 +109,9 @@ def adj : Cat.free ⊣ Quiv.forget :=
exact Category.id_comp _ }
homEquiv_naturality_left_symm := fun {V _ _} f g => by
change (show Paths V ⥤ _ from _) = _
- ext; swap
- · apply eq_conj_eqToHom
- · rfl }
+ ext
+ · rfl
+ · apply eq_conj_eqToHom }
end Quiv
diff --git a/Mathlib/CategoryTheory/Category/ReflQuiv.lean b/Mathlib/CategoryTheory/Category/ReflQuiv.lean
new file mode 100644
index 0000000000000..f26afec53930b
--- /dev/null
+++ b/Mathlib/CategoryTheory/Category/ReflQuiv.lean
@@ -0,0 +1,251 @@
+/-
+Copyright (c) 2024 Mario Carneiro and Emily Riehl. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Mario Carneiro, Emily Riehl
+-/
+import Mathlib.Combinatorics.Quiver.ReflQuiver
+import Mathlib.CategoryTheory.Category.Cat
+import Mathlib.CategoryTheory.Category.Quiv
+
+/-!
+# The category of refl quivers
+
+The category `ReflQuiv` of (bundled) reflexive quivers, and the free/forgetful adjunction between
+`Cat` and `ReflQuiv`.
+-/
+
+namespace CategoryTheory
+universe v u
+
+/-- Category of refl quivers. -/
+@[nolint checkUnivs]
+def ReflQuiv :=
+ Bundled ReflQuiver.{v + 1, u}
+
+namespace ReflQuiv
+
+instance : CoeSort ReflQuiv (Type u) where coe := Bundled.α
+
+instance (C : ReflQuiv.{v, u}) : ReflQuiver.{v + 1, u} C := C.str
+
+/-- The underlying quiver of a reflexive quiver.-/
+def toQuiv (C : ReflQuiv.{v, u}) : Quiv.{v, u} := Quiv.of C.α
+
+/-- Construct a bundled `ReflQuiv` from the underlying type and the typeclass. -/
+def of (C : Type u) [ReflQuiver.{v + 1} C] : ReflQuiv.{v, u} := Bundled.of C
+
+instance : Inhabited ReflQuiv := ⟨ReflQuiv.of (Discrete default)⟩
+
+@[simp] theorem of_val (C : Type u) [ReflQuiver C] : (ReflQuiv.of C) = C := rfl
+
+/-- Category structure on `ReflQuiv` -/
+instance category : LargeCategory.{max v u} ReflQuiv.{v, u} where
+ Hom C D := ReflPrefunctor C D
+ id C := ReflPrefunctor.id C
+ comp F G := ReflPrefunctor.comp F G
+
+theorem id_eq_id (X : ReflQuiv) : 𝟙 X = 𝟭rq X := rfl
+theorem comp_eq_comp {X Y Z : ReflQuiv} (F : X ⟶ Y) (G : Y ⟶ Z) : F ≫ G = F ⋙rq G := rfl
+
+/-- The forgetful functor from categories to quivers. -/
+@[simps]
+def forget : Cat.{v, u} ⥤ ReflQuiv.{v, u} where
+ obj C := ReflQuiv.of C
+ map F := F.toReflPrefunctor
+
+theorem forget_faithful {C D : Cat.{v, u}} (F G : C ⥤ D)
+ (hyp : forget.map F = forget.map G) : F = G := by
+ cases F; cases G; cases hyp; rfl
+
+theorem forget.Faithful : Functor.Faithful (forget) where
+ map_injective := fun hyp ↦ forget_faithful _ _ hyp
+
+/-- The forgetful functor from categories to quivers. -/
+@[simps]
+def forgetToQuiv : ReflQuiv.{v, u} ⥤ Quiv.{v, u} where
+ obj V := Quiv.of V
+ map F := F.toPrefunctor
+
+theorem forgetToQuiv_faithful {V W : ReflQuiv} (F G : V ⥤rq W)
+ (hyp : forgetToQuiv.map F = forgetToQuiv.map G) : F = G := by
+ cases F; cases G; cases hyp; rfl
+
+theorem forgetToQuiv.Faithful : Functor.Faithful (forgetToQuiv) where
+ map_injective := fun hyp ↦ forgetToQuiv_faithful _ _ hyp
+
+theorem forget_forgetToQuiv : forget ⋙ forgetToQuiv = Quiv.forget := rfl
+
+end ReflQuiv
+
+namespace ReflPrefunctor
+
+/-- A refl prefunctor can be promoted to a functor if it respects composition.-/
+def toFunctor {C D : Cat} (F : (ReflQuiv.of C) ⟶ (ReflQuiv.of D))
+ (hyp : ∀ {X Y Z : ↑C} (f : X ⟶ Y) (g : Y ⟶ Z),
+ F.map (CategoryStruct.comp (obj := C) f g) =
+ CategoryStruct.comp (obj := D) (F.map f) (F.map g)) : C ⥤ D where
+ obj := F.obj
+ map := F.map
+ map_id := F.map_id
+ map_comp := hyp
+
+end ReflPrefunctor
+
+namespace Cat
+
+/-- The hom relation that identifies the specified reflexivity arrows with the nil paths.-/
+inductive FreeReflRel {V} [ReflQuiver V] : (X Y : Paths V) → (f g : X ⟶ Y) → Prop
+ | mk {X : V} : FreeReflRel X X (Quiver.Hom.toPath (𝟙rq X)) .nil
+
+/-- A reflexive quiver generates a free category, defined as as quotient of the free category
+on its underlying quiver (called the "path category") by the hom relation that uses the specified
+reflexivity arrows as the identity arrows. -/
+def FreeRefl (V) [ReflQuiver V] :=
+ Quotient (C := Cat.free.obj (Quiv.of V)) (FreeReflRel (V := V))
+
+instance (V) [ReflQuiver V] : Category (FreeRefl V) :=
+ inferInstanceAs (Category (Quotient _))
+
+/-- The quotient functor associated to a quotient category defines a natural map from the free
+category on the underlying quiver of a refl quiver to the free category on the reflexive quiver.-/
+def FreeRefl.quotientFunctor (V) [ReflQuiver V] : Cat.free.obj (Quiv.of V) ⥤ FreeRefl V :=
+ Quotient.functor (C := Cat.free.obj (Quiv.of V)) (FreeReflRel (V := V))
+
+/-- This is a specialization of `Quotient.lift_unique'` rather than `Quotient.lift_unique`, hence
+the prime in the name.-/
+theorem FreeRefl.lift_unique' {V} [ReflQuiver V] {D} [Category D] (F₁ F₂ : FreeRefl V ⥤ D)
+ (h : quotientFunctor V ⋙ F₁ = quotientFunctor V ⋙ F₂) :
+ F₁ = F₂ :=
+ Quotient.lift_unique' (C := Cat.free.obj (Quiv.of V)) (FreeReflRel (V := V)) _ _ h
+
+/-- The functor sending a reflexive quiver to the free category it generates, a quotient of
+its path category.-/
+@[simps!]
+def freeRefl : ReflQuiv.{v, u} ⥤ Cat.{max u v, u} where
+ obj V := Cat.of (FreeRefl V)
+ map f := Quotient.lift _ ((by exact Cat.free.map f.toPrefunctor) ⋙ FreeRefl.quotientFunctor _)
+ (fun X Y f g hfg => by
+ apply Quotient.sound
+ cases hfg
+ simp [ReflPrefunctor.map_id]
+ constructor)
+ map_id X := by
+ dsimp
+ refine (Quotient.lift_unique _ _ _ _ ((Functor.comp_id _).trans <|
+ (Functor.id_comp _).symm.trans ?_)).symm
+ congr 1
+ exact (free.map_id X.toQuiv).symm
+ map_comp {X Y Z} f g := by
+ dsimp
+ apply (Quotient.lift_unique _ _ _ _ _).symm
+ have : free.map (f ≫ g).toPrefunctor =
+ free.map (X := X.toQuiv) (Y := Y.toQuiv) f.toPrefunctor ⋙
+ free.map (X := Y.toQuiv) (Y := Z.toQuiv) g.toPrefunctor := by
+ show _ = _ ≫ _
+ rw [← Functor.map_comp]; rfl
+ rw [this, Functor.assoc]
+ show _ ⋙ _ ⋙ _ = _
+ rw [← Functor.assoc, Quotient.lift_spec, Functor.assoc, FreeRefl.quotientFunctor,
+ Quotient.lift_spec]
+
+theorem freeRefl_naturality {X Y} [ReflQuiver X] [ReflQuiver Y] (f : X ⥤rq Y) :
+ free.map (X := Quiv.of X) (Y := Quiv.of Y) f.toPrefunctor ⋙
+ FreeRefl.quotientFunctor ↑Y =
+ FreeRefl.quotientFunctor ↑X ⋙ freeRefl.map (X := ReflQuiv.of X) (Y := ReflQuiv.of Y) f := by
+ simp only [free_obj, FreeRefl.quotientFunctor, freeRefl, ReflQuiv.of_val]
+ rw [Quotient.lift_spec]
+
+/-- We will make use of the natural quotient map from the free category on the underlying
+quiver of a refl quiver to the free category on the reflexive quiver.-/
+def freeReflNatTrans : ReflQuiv.forgetToQuiv ⋙ Cat.free ⟶ freeRefl where
+ app V := FreeRefl.quotientFunctor V
+ naturality _ _ f := freeRefl_naturality f
+
+end Cat
+
+namespace ReflQuiv
+open Category Functor
+
+/-- The unit components are defined as the composite of the corresponding unit component for the
+adjunction between categories and quivers with the map underlying the quotient functor.-/
+@[simps! toPrefunctor obj map]
+def adj.unit.app (V : ReflQuiv.{max u v, u}) : V ⥤rq forget.obj (Cat.freeRefl.obj V) where
+ toPrefunctor := Quiv.adj.unit.app (V.toQuiv) ⋙q
+ Quiv.forget.map (Cat.FreeRefl.quotientFunctor V)
+ map_id := fun _ => Quotient.sound _ ⟨⟩
+
+/-- This is used in the proof of both triangle equalities.-/
+theorem adj.unit.component_eq (V : ReflQuiv.{max u v, u}) :
+ forgetToQuiv.map (adj.unit.app V) = Quiv.adj.unit.app (V.toQuiv) ≫
+ Quiv.forget.map (Y := Cat.of _) (Cat.FreeRefl.quotientFunctor V) := rfl
+
+/-- The counit components are defined using the universal property of the quotient
+from the corresponding counit component for the adjunction between categories and quivers.-/
+@[simps!]
+def adj.counit.app (C : Cat) : Cat.freeRefl.obj (forget.obj C) ⥤ C := by
+ fapply Quotient.lift
+ · exact Quiv.adj.counit.app C
+ · intro x y f g rel
+ cases rel
+ unfold Quiv.adj
+ simp only [Adjunction.mkOfHomEquiv_counit_app, Equiv.coe_fn_symm_mk,
+ Quiv.lift_map, Prefunctor.mapPath_toPath, composePath_toPath]
+ rfl
+
+/-- The counit of `ReflQuiv.adj` is closely related to the counit of `Quiv.adj`.-/
+@[simp]
+theorem adj.counit.component_eq (C : Cat) :
+ Cat.FreeRefl.quotientFunctor C ⋙ adj.counit.app C =
+ Quiv.adj.counit.app C := rfl
+
+/-- The counit of `ReflQuiv.adj` is closely related to the counit of `Quiv.adj`. For ease of use,
+we introduce primed version for unbundled categories.-/
+@[simp]
+theorem adj.counit.component_eq' (C) [Category C] :
+ Cat.FreeRefl.quotientFunctor C ⋙ adj.counit.app (Cat.of C) =
+ Quiv.adj.counit.app (Cat.of C) := rfl
+
+/--
+The adjunction between forming the free category on a reflexive quiver, and forgetting a category
+to a reflexive quiver.
+-/
+nonrec def adj : Cat.freeRefl.{max u v, u} ⊣ ReflQuiv.forget :=
+ Adjunction.mkOfUnitCounit {
+ unit := {
+ app := adj.unit.app
+ naturality := fun V W f ↦ by exact rfl
+ }
+ counit := {
+ app := adj.counit.app
+ naturality := fun C D F ↦ Quotient.lift_unique' _ _ _ (Quiv.adj.counit.naturality F)
+ }
+ left_triangle := by
+ ext V
+ apply Cat.FreeRefl.lift_unique'
+ simp only [id_obj, Cat.free_obj, comp_obj, Cat.freeRefl_obj_α, NatTrans.comp_app,
+ forget_obj, whiskerRight_app, associator_hom_app, whiskerLeft_app, id_comp,
+ NatTrans.id_app']
+ rw [Cat.id_eq_id, Cat.comp_eq_comp]
+ simp only [Cat.freeRefl_obj_α, Functor.comp_id]
+ rw [← Functor.assoc, ← Cat.freeRefl_naturality, Functor.assoc]
+ dsimp [Cat.freeRefl]
+ rw [adj.counit.component_eq' (Cat.FreeRefl V)]
+ conv =>
+ enter [1, 1, 2]
+ apply (Quiv.comp_eq_comp (X := Quiv.of _) (Y := Quiv.of _) (Z := Quiv.of _) ..).symm
+ rw [Cat.free.map_comp]
+ show (_ ⋙ ((Quiv.forget ⋙ Cat.free).map (X := Cat.of _) (Y := Cat.of _)
+ (Cat.FreeRefl.quotientFunctor V))) ⋙ _ = _
+ rw [Functor.assoc, ← Cat.comp_eq_comp]
+ conv => enter [1, 2]; apply Quiv.adj.counit.naturality
+ rw [Cat.comp_eq_comp, ← Functor.assoc, ← Cat.comp_eq_comp]
+ conv => enter [1, 1]; apply Quiv.adj.left_triangle_components V.toQuiv
+ exact Functor.id_comp _
+ right_triangle := by
+ ext C
+ exact forgetToQuiv_faithful _ _ (Quiv.adj.right_triangle_components C)
+ }
+
+end ReflQuiv
+
+end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Category/RelCat.lean b/Mathlib/CategoryTheory/Category/RelCat.lean
index 48f8c610da96b..ae907547bf19b 100644
--- a/Mathlib/CategoryTheory/Category/RelCat.lean
+++ b/Mathlib/CategoryTheory/Category/RelCat.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Uni Marx
+Authors: Kim Morrison, Uni Marx
-/
import Mathlib.CategoryTheory.Iso
import Mathlib.CategoryTheory.EssentialImage
@@ -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/Cartesian.lean b/Mathlib/CategoryTheory/Closed/Cartesian.lean
index 7b0e2bfb8884d..e25efebbe63d0 100644
--- a/Mathlib/CategoryTheory/Closed/Cartesian.lean
+++ b/Mathlib/CategoryTheory/Closed/Cartesian.lean
@@ -205,10 +205,10 @@ theorem eq_curry_iff (f : A ⨯ Y ⟶ X) (g : Y ⟶ A ⟹ X) : g = curry f ↔ u
-- I don't think these two should be simp.
theorem uncurry_eq (g : Y ⟶ A ⟹ X) : uncurry g = Limits.prod.map (𝟙 A) g ≫ (exp.ev A).app X :=
- Adjunction.homEquiv_counit _
+ rfl
theorem curry_eq (g : A ⨯ Y ⟶ X) : curry g = (exp.coev A).app Y ≫ (exp A).map g :=
- Adjunction.homEquiv_unit _
+ rfl
theorem uncurry_id_eq_ev (A X : C) [Exponentiable A] : uncurry (𝟙 (A ⟹ X)) = (exp.ev A).app X := by
rw [uncurry_eq, prod.map_id_id, id_comp]
@@ -226,21 +226,15 @@ end CartesianClosed
open CartesianClosed
-/-- Show that the exponential of the terminal object is isomorphic to itself, i.e. `X^1 ≅ X`.
+/-- The exponential with the terminal object is naturally isomorphic to the identity. The typeclass
+argument is explicit: any instance can be used.-/
+def expTerminalNatIso [Exponentiable (⊤_ C)] : 𝟭 C ≅ exp (⊤_ C) :=
+ MonoidalClosed.unitNatIso (C := C)
-The typeclass argument is explicit: any instance can be used.
--/
+/-- The exponential of any object with the terminal object is isomorphic to itself, i.e. `X^1 ≅ X`.
+The typeclass argument is explicit: any instance can be used.-/
def expTerminalIsoSelf [Exponentiable (⊤_ C)] : (⊤_ C) ⟹ X ≅ X :=
- Yoneda.ext ((⊤_ C) ⟹ X) X
- (fun {Y} f => (Limits.prod.leftUnitor Y).inv ≫ CartesianClosed.uncurry f)
- (fun {Y} f => CartesianClosed.curry ((Limits.prod.leftUnitor Y).hom ≫ f))
- (fun g => by
- rw [curry_eq_iff, Iso.hom_inv_id_assoc])
- (fun g => by simp)
- (fun f g => by
- -- Porting note: `rw` is a bit brittle here, requiring the `dsimp` rule cancellation.
- dsimp [-prod.leftUnitor_inv]
- rw [uncurry_natural_left, prod.leftUnitor_inv_naturality_assoc f])
+ (expTerminalNatIso.app X).symm
/-- The internal element which points at the given morphism. -/
def internalizeHom (f : A ⟶ Y) : ⊤_ C ⟶ A ⟹ Y :=
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 96%
rename from Mathlib/CategoryTheory/Closed/FunctorCategory.lean
rename to Mathlib/CategoryTheory/Closed/FunctorCategory/Groupoid.lean
index 49176e1f107a3..a304a8071b6d1 100644
--- a/Mathlib/CategoryTheory/Closed/FunctorCategory.lean
+++ b/Mathlib/CategoryTheory/Closed/FunctorCategory/Groupoid.lean
@@ -62,9 +62,8 @@ closed in the functor category `F : D ⥤ C` with the pointwise monoidal structu
instance closed (F : D ⥤ C) : Closed F where
rightAdj := closedIhom F
adj :=
- Adjunction.mkOfUnitCounit
- { unit := closedUnit F
- counit := closedCounit F }
+ { unit := closedUnit F
+ counit := closedCounit F }
/-- If `C` is a monoidal closed category and `D` is groupoid, then the functor category `D ⥤ C`,
with the pointwise monoidal structure, is monoidal closed. -/
diff --git a/Mathlib/CategoryTheory/Closed/FunctorToTypes.lean b/Mathlib/CategoryTheory/Closed/FunctorToTypes.lean
new file mode 100644
index 0000000000000..35a8c0eccbad2
--- /dev/null
+++ b/Mathlib/CategoryTheory/Closed/FunctorToTypes.lean
@@ -0,0 +1,68 @@
+/-
+Copyright (c) 2024 Jack McKoen. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Jack McKoen
+-/
+import Mathlib.CategoryTheory.Functor.FunctorHom
+import Mathlib.CategoryTheory.Closed.Monoidal
+
+/-!
+# Functors to Type are closed.
+
+Show that `C ⥤ Type max w v u` is monoidal closed for `C` a category in `Type u` with morphisms in
+`Type v`, and `w` an arbitrary universe.
+
+## TODO
+It should be shown that `C ⥤ Type max w v u` is cartesian closed.
+
+-/
+
+
+universe w v' v u u'
+
+open CategoryTheory Functor MonoidalCategory
+
+namespace CategoryTheory.FunctorToTypes
+
+variable {C : Type u} [Category.{v} C] {D : Type u'} [Category.{v'} D]
+
+variable (F : C ⥤ Type max w v u)
+
+/-- When `F G H : C ⥤ Type max w v u`, we have `(G ⟶ F.functorHom H) ≃ (F ⊗ G ⟶ H)`. -/
+@[simps!]
+def functorHomEquiv (G H : C ⥤ Type max w v u) : (G ⟶ F.functorHom H) ≃ (F ⊗ G ⟶ H) :=
+ (Functor.functorHomEquiv F H G).trans (homObjEquiv F H G)
+
+/-- Given a morphism `f : G ⟶ H`, an object `c : C`, and an element of `(F.functorHom G).obj c`,
+construct an element of `(F.functorHom H).obj c`. -/
+@[simps]
+def rightAdj_map {F G H : C ⥤ Type max w v u} (f : G ⟶ H) (c : C) (a : (F.functorHom G).obj c) :
+ (F.functorHom H).obj c where
+ app d b := a.app d b ≫ f.app d
+ naturality g h := by
+ have := a.naturality g h
+ change (F.map g ≫ a.app _ (h ≫ g)) ≫ _ = _
+ aesop
+
+/-- A right adjoint of `tensorLeft F`. -/
+@[simps!]
+def rightAdj : (C ⥤ Type max w v u) ⥤ C ⥤ Type max w v u where
+ obj G := F.functorHom G
+ map f := { app := rightAdj_map f }
+
+/-- The adjunction `tensorLeft F ⊣ rightAdj F`. -/
+def adj : tensorLeft F ⊣ rightAdj F where
+ unit := {
+ app := fun G ↦ (functorHomEquiv F G _).2 (𝟙 _)
+ naturality := fun G H f ↦ by
+ dsimp [rightAdj]
+ ext _
+ simp [FunctorToTypes.naturality] }
+ counit := { app := fun G ↦ functorHomEquiv F _ G (𝟙 _) }
+
+instance closed : Closed F where
+ adj := adj F
+
+instance monoidalClosed : MonoidalClosed (C ⥤ Type max w v u) where
+
+end CategoryTheory.FunctorToTypes
diff --git a/Mathlib/CategoryTheory/Closed/Ideal.lean b/Mathlib/CategoryTheory/Closed/Ideal.lean
index 9fd9a5396913e..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_homEquiv_apply, Adjunction.homEquiv_unit, 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,9 +217,10 @@ 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, Functor.FullyFaithful.map_preimage,
- comp_id, comp_id, comp_id, comp_id, comp_id,
- comp_id, Adjunction.homEquiv_naturality_right, ← assoc, curry_natural_right _ (i.map g),
+ 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,
unitCompPartialBijective_natural, uncurry_natural_right, assoc]
diff --git a/Mathlib/CategoryTheory/Closed/Monoidal.lean b/Mathlib/CategoryTheory/Closed/Monoidal.lean
index e28b77954b24f..fd270e7d51120 100644
--- a/Mathlib/CategoryTheory/Closed/Monoidal.lean
+++ b/Mathlib/CategoryTheory/Closed/Monoidal.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Monoidal.Functor
import Mathlib.CategoryTheory.Adjunction.Limits
@@ -175,11 +175,11 @@ theorem eq_curry_iff (f : A ⊗ Y ⟶ X) (g : Y ⟶ A ⟶[C] X) : g = curry f
Adjunction.eq_homEquiv_apply (ihom.adjunction A) f g
-- I don't think these two should be simp.
-theorem uncurry_eq (g : Y ⟶ A ⟶[C] X) : uncurry g = (A ◁ g) ≫ (ihom.ev A).app X :=
- Adjunction.homEquiv_counit _
+theorem uncurry_eq (g : Y ⟶ A ⟶[C] X) : uncurry g = (A ◁ g) ≫ (ihom.ev A).app X := by
+ rfl
theorem curry_eq (g : A ⊗ Y ⟶ X) : curry g = (ihom.coev A).app Y ≫ (ihom A).map g :=
- Adjunction.homEquiv_unit _
+ rfl
theorem curry_injective : Function.Injective (curry : (A ⊗ Y ⟶ X) → (Y ⟶ A ⟶[C] X)) :=
(Closed.adj.homEquiv _ _).injective
@@ -196,6 +196,10 @@ theorem curry_id_eq_coev : curry (𝟙 _) = (ihom.coev A).app X := by
rw [curry_eq, (ihom A).map_id (A ⊗ _)]
apply comp_id
+/-- The internal hom out of the unit is naturally isomorphic to the identity functor.-/
+def unitNatIso [Closed (𝟙_ C)] : 𝟭 C ≅ ihom (𝟙_ C) :=
+ conjugateIsoEquiv (Adjunction.id (C := C)) (ihom.adjunction (𝟙_ C))
+ (leftUnitorNatIso C)
section Pre
variable {A B}
@@ -266,7 +270,14 @@ theorem ofEquiv_curry_def {X Y Z : C} (f : X ⊗ Y ⟶ Z) :
adj.homEquiv Y ((ihom (F.obj X)).obj (F.obj Z))
(MonoidalClosed.curry (adj.toEquivalence.symm.toAdjunction.homEquiv (F.obj X ⊗ F.obj Y) Z
((Iso.compInverseIso (H := adj.toEquivalence)
- (MonoidalFunctor.commTensorLeft F X)).hom.app Y ≫ f))) :=
+ (MonoidalFunctor.commTensorLeft F X)).hom.app Y ≫ f))) := by
+ -- This whole proof used to be `rfl` before #16317.
+ change ((adj.comp ((ihom.adjunction (F.obj X)).comp
+ adj.toEquivalence.symm.toAdjunction)).ofNatIsoLeft _).homEquiv _ _ _ = _
+ dsimp only [Adjunction.ofNatIsoLeft]
+ rw [Adjunction.mkOfHomEquiv_homEquiv]
+ dsimp
+ rw [Adjunction.comp_homEquiv, Adjunction.comp_homEquiv]
rfl
/-- Suppose we have a monoidal equivalence `F : C ≌ D`, with `D` monoidal closed. We can pull the
@@ -280,10 +291,102 @@ theorem ofEquiv_uncurry_def {X Y Z : C} :
((Iso.compInverseIso (H := adj.toEquivalence)
(MonoidalFunctor.commTensorLeft F X)).inv.app Y) ≫
(adj.toEquivalence.symm.toAdjunction.homEquiv _ _).symm
- (MonoidalClosed.uncurry ((adj.homEquiv _ _).symm f)) :=
- fun _ => rfl
+ (MonoidalClosed.uncurry ((adj.homEquiv _ _).symm f)) := by
+ intro f
+ -- This whole proof used to be `rfl` before #16317.
+ change (((adj.comp ((ihom.adjunction (F.obj X)).comp
+ adj.toEquivalence.symm.toAdjunction)).ofNatIsoLeft _).homEquiv _ _).symm _ = _
+ dsimp only [Adjunction.ofNatIsoLeft]
+ rw [Adjunction.mkOfHomEquiv_homEquiv]
+ dsimp
+ rw [Adjunction.comp_homEquiv, Adjunction.comp_homEquiv]
+ rfl
+
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 e1b0ffa01b4f2..ec79009ce8968 100644
--- a/Mathlib/CategoryTheory/Closed/Types.lean
+++ b/Mathlib/CategoryTheory/Closed/Types.lean
@@ -32,10 +32,9 @@ section CartesianClosed
/-- The adjunction `Limits.Types.binaryProductFunctor.obj X ⊣ coyoneda.obj (Opposite.op X)`
for any `X : Type v₁`. -/
def Types.binaryProductAdjunction (X : Type v₁) :
- Limits.Types.binaryProductFunctor.obj X ⊣ coyoneda.obj (Opposite.op X) :=
- Adjunction.mkOfUnitCounit
- { unit := { app := fun Z (z : Z) x => ⟨x, z⟩ }
- counit := { app := fun Z xf => xf.2 xf.1 } }
+ Limits.Types.binaryProductFunctor.obj X ⊣ coyoneda.obj (Opposite.op X) where
+ unit := { app := fun Z (z : Z) x => ⟨x, z⟩ }
+ 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 eb69db1cc53a2..fba99256f7078 100644
--- a/Mathlib/CategoryTheory/CofilteredSystem.lean
+++ b/Mathlib/CategoryTheory/CofilteredSystem.lean
@@ -3,11 +3,7 @@ Copyright (c) 2022 Kyle Miller, Adam Topaz, Rémi Bottinelli, Junyan Xu. All rig
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kyle Miller, Adam Topaz, Rémi Bottinelli, Junyan Xu
-/
-import Mathlib.CategoryTheory.Filtered.Basic
-import Mathlib.Data.Set.Finite
-import Mathlib.Data.Set.Subsingleton
import Mathlib.Topology.Category.TopCat.Limits.Konig
-import Mathlib.Tactic.AdaptationNote
/-!
# Cofiltered systems
@@ -276,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
@@ -351,7 +347,7 @@ theorem eventually_injective [Nonempty J] [Finite F.sections] :
refine ⟨fn.argmin Nat.lt_wfRel.wf,
fun i f => ((Fintype.bijective_iff_surjective_and_card _).2
⟨Fsur f, le_antisymm ?_ (Fintype.card_le_of_surjective _ <| Fsur f)⟩).1⟩
- rw [← Nat.sub_sub_self (card_le i), tsub_le_iff_tsub_le]
+ rw [← Nat.sub_le_sub_iff_left (card_le i)]
apply fn.argmin_le
end FiniteCofilteredSystem
diff --git a/Mathlib/CategoryTheory/CommSq.lean b/Mathlib/CategoryTheory/CommSq.lean
index ecb323faed1c4..fedadf5d16091 100644
--- a/Mathlib/CategoryTheory/CommSq.lean
+++ b/Mathlib/CategoryTheory/CommSq.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Joël Riou
+Authors: Kim Morrison, Joël Riou
-/
import Mathlib.CategoryTheory.Comma.Arrow
@@ -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 892745edf3a95..654d109cac4f1 100644
--- a/Mathlib/CategoryTheory/Comma/Basic.lean
+++ b/Mathlib/CategoryTheory/Comma/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johan Commelin, Bhavik Mehta
+Authors: Kim Morrison, Johan Commelin, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Iso
import Mathlib.CategoryTheory.Functor.Category
@@ -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 7a62b01614f0a..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,14 +57,14 @@ 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]
theorem id_left (U : Over X) : CommaMorphism.left (𝟙 U) = 𝟙 U.left :=
rfl
-@[simp]
+@[simp, reassoc]
theorem comp_left (a b c : Over X) (f : a ⟶ b) (g : b ⟶ c) : (f ≫ g).left = f.left ≫ g.left :=
rfl
@@ -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 91%
rename from Mathlib/CategoryTheory/Comma/StructuredArrow.lean
rename to Mathlib/CategoryTheory/Comma/StructuredArrow/Basic.lean
index 9dff431f80860..7e4231ecc0c06 100644
--- a/Mathlib/CategoryTheory/Comma/StructuredArrow.lean
+++ b/Mathlib/CategoryTheory/Comma/StructuredArrow/Basic.lean
@@ -1,13 +1,11 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Adam Topaz, Scott Morrison
+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
@@ -889,4 +869,71 @@ def costructuredArrowOpEquivalence (F : C ⥤ D) (d : D) :
apply CommaMorphism.ext <;>
dsimp [StructuredArrow.isoMk, StructuredArrow.homMk, Comma.isoMk]; simp
+section Pre
+
+variable {E : Type u₃} [Category.{v₃} E] (F : C ⥤ D) {G : D ⥤ E} {e : E}
+
+/-- The functor establishing the equivalence `StructuredArrow.preEquivalence`. -/
+@[simps!]
+def StructuredArrow.preEquivalence.functor (f : StructuredArrow e G) :
+ StructuredArrow f (pre e F G) ⥤ StructuredArrow f.right F where
+ obj g := mk g.hom.right
+ map φ := homMk φ.right.right <| by
+ have := w φ
+ simp only [Functor.const_obj_obj] at this ⊢
+ rw [← this, comp_right]
+ simp
+
+/-- The inverse functor establishing the equivalence `StructuredArrow.preEquivalence`. -/
+@[simps!]
+def StructuredArrow.preEquivalence.inverse (f : StructuredArrow e G) :
+ StructuredArrow f.right F ⥤ StructuredArrow f (pre e F G) where
+ obj g := mk
+ (Y := mk (Y := g.right)
+ (f.hom ≫ (G.map g.hom : G.obj f.right ⟶ (F ⋙ G).obj g.right)))
+ (homMk g.hom)
+ map φ := homMk <| homMk φ.right <| by
+ simp only [Functor.const_obj_obj, Functor.comp_obj, mk_right, mk_left, mk_hom_eq_self,
+ Functor.comp_map, Category.assoc, ← w φ, Functor.map_comp]
+
+/-- A structured arrow category on a `StructuredArrow.pre e F G` functor is equivalent to the
+structured arrow category on F -/
+def StructuredArrow.preEquivalence (f : StructuredArrow e G) :
+ StructuredArrow f (pre e F G) ≌ StructuredArrow f.right F where
+ functor := StructuredArrow.preEquivalence.functor F f
+ inverse := StructuredArrow.preEquivalence.inverse F f
+ unitIso := NatIso.ofComponents (fun _ => isoMk (isoMk (Iso.refl _)))
+ counitIso := NatIso.ofComponents (fun _ => isoMk (Iso.refl _))
+
+/-- The functor establishing the equivalence `CostructuredArrow.preEquivalence`. -/
+@[simps!]
+def CostructuredArrow.preEquivalence.functor (f : CostructuredArrow G e) :
+ CostructuredArrow (pre F G e) f ⥤ CostructuredArrow F f.left where
+ obj g := mk g.hom.left
+ map φ := homMk φ.left.left <| by
+ have := w φ
+ simp only [Functor.const_obj_obj] at this ⊢
+ rw [← this, comp_left]
+ simp
+
+/-- The inverse functor establishing the equivalence `CostructuredArrow.preEquivalence`. -/
+@[simps!]
+def CostructuredArrow.preEquivalence.inverse (f : CostructuredArrow G e) :
+ CostructuredArrow F f.left ⥤ CostructuredArrow (pre F G e) f where
+ obj g := mk (Y := mk (Y := g.left) (G.map g.hom ≫ f.hom)) (homMk g.hom)
+ map φ := homMk <| homMk φ.left <| by
+ simp only [Functor.const_obj_obj, Functor.comp_obj, mk_left, Functor.comp_map, mk_hom_eq_self,
+ ← w φ, Functor.map_comp, Category.assoc]
+
+/-- A costructured arrow category on a `CostructuredArrow.pre F G e` functor is equivalent to the
+costructured arrow category on F -/
+def CostructuredArrow.preEquivalence (f : CostructuredArrow G e) :
+ CostructuredArrow (pre F G e) f ≌ CostructuredArrow F f.left where
+ functor := CostructuredArrow.preEquivalence.functor F f
+ inverse := CostructuredArrow.preEquivalence.inverse F f
+ unitIso := NatIso.ofComponents (fun _ => isoMk (isoMk (Iso.refl _)))
+ counitIso := NatIso.ofComponents (fun _ => isoMk (Iso.refl _))
+
+end Pre
+
end CategoryTheory
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/Basic.lean b/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean
index 8ee159d8afb77..38882d4e9f448 100644
--- a/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean
+++ b/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johannes Hölzl, Reid Barton, Sean Leather, Yury Kudryashov
+Authors: Kim Morrison, Johannes Hölzl, Reid Barton, Sean Leather, Yury Kudryashov
-/
import Mathlib.CategoryTheory.Types
@@ -76,7 +76,7 @@ instance : HasCoeToSort X := ConcreteCategory.hasCoeToSort X
-/
def ConcreteCategory.hasCoeToSort (C : Type u) [Category.{v} C] [ConcreteCategory.{w} C] :
CoeSort C (Type w) where
- coe := fun X => (forget C).obj X
+ coe X := (forget C).obj X
section
diff --git a/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean b/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean
index 365a1c9c6a877..1fe01ebf2d14a 100644
--- a/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean
+++ b/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johannes Hölzl, Reid Barton, Sean Leather
+Authors: Kim Morrison, Johannes Hölzl, Reid Barton, Sean Leather
-/
import Mathlib.Init
import Batteries.Tactic.Lint.Misc
@@ -22,7 +22,7 @@ universe u v
namespace CategoryTheory
-variable {c d : Type u → Type v} {α : Type u}
+variable {c d : Type u → Type v}
/-- `Bundled` is a type bundled with a type class instance for that type. Only
the type class is exposed as a parameter. -/
diff --git a/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean b/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean
index 201557ff6bf23..9c4cd7abf9e84 100644
--- a/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean
+++ b/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Yury Kudryashov
+Authors: Kim Morrison, Yury Kudryashov
-/
import Mathlib.CategoryTheory.ConcreteCategory.Basic
import Mathlib.CategoryTheory.ConcreteCategory.Bundled
@@ -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/ConcreteCategory/ReflectsIso.lean b/Mathlib/CategoryTheory/ConcreteCategory/ReflectsIso.lean
index 4bd471e67da9a..69e90e646f526 100644
--- a/Mathlib/CategoryTheory/ConcreteCategory/ReflectsIso.lean
+++ b/Mathlib/CategoryTheory/ConcreteCategory/ReflectsIso.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.ConcreteCategory.Basic
import Mathlib.CategoryTheory.Functor.ReflectsIso
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/ConnectedComponents.lean b/Mathlib/CategoryTheory/ConnectedComponents.lean
index cc86ae90a2167..0d205fcbb0170 100644
--- a/Mathlib/CategoryTheory/ConnectedComponents.lean
+++ b/Mathlib/CategoryTheory/ConnectedComponents.lean
@@ -7,7 +7,6 @@ import Mathlib.Data.List.Chain
import Mathlib.CategoryTheory.IsConnected
import Mathlib.CategoryTheory.Sigma.Basic
import Mathlib.CategoryTheory.FullSubcategory
-import Mathlib.Data.List.Infix
/-!
# Connected components of a category
diff --git a/Mathlib/CategoryTheory/Core.lean b/Mathlib/CategoryTheory/Core.lean
index e124cbff9a5bc..46edfe5dbabf7 100644
--- a/Mathlib/CategoryTheory/Core.lean
+++ b/Mathlib/CategoryTheory/Core.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Control.EquivFunctor
import Mathlib.CategoryTheory.Groupoid
@@ -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 324755f59b43d..a4cb04addaf1f 100644
--- a/Mathlib/CategoryTheory/DifferentialObject.lean
+++ b/Mathlib/CategoryTheory/DifferentialObject.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Basic
import Mathlib.Data.Int.Cast.Defs
@@ -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 3c5a2e2c0acd1..1d28f0410aa9e 100644
--- a/Mathlib/CategoryTheory/DiscreteCategory.lean
+++ b/Mathlib/CategoryTheory/DiscreteCategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison, Floris van Doorn
+Authors: Stephen Morgan, Kim Morrison, Floris van Doorn
-/
import Mathlib.CategoryTheory.EqToHom
import Mathlib.CategoryTheory.Pi.Basic
@@ -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 d5fda0bbb9e35..7d85416b30755 100644
--- a/Mathlib/CategoryTheory/Elements.lean
+++ b/Mathlib/CategoryTheory/Elements.lean
@@ -1,11 +1,10 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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/Elementwise.lean b/Mathlib/CategoryTheory/Elementwise.lean
index 3619c79b713f1..06fe4ef41ec18 100644
--- a/Mathlib/CategoryTheory/Elementwise.lean
+++ b/Mathlib/CategoryTheory/Elementwise.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Tactic.CategoryTheory.Elementwise
import Mathlib.CategoryTheory.ConcreteCategory.Basic
diff --git a/Mathlib/CategoryTheory/Endofunctor/Algebra.lean b/Mathlib/CategoryTheory/Endofunctor/Algebra.lean
index 0ba3c1ced4604..1b53aa148eb3a 100644
--- a/Mathlib/CategoryTheory/Endofunctor/Algebra.lean
+++ b/Mathlib/CategoryTheory/Endofunctor/Algebra.lean
@@ -1,9 +1,9 @@
/-
Copyright (c) 2022 Joseph Hua. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta, Johan Commelin, Reid Barton, Robert Y. Lewis, Joseph Hua
+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 30f789b4ad257..0ab626814ae99 100644
--- a/Mathlib/CategoryTheory/Endomorphism.lean
+++ b/Mathlib/CategoryTheory/Endomorphism.lean
@@ -1,11 +1,11 @@
/-
Copyright (c) 2019 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Yury Kudryashov, Scott Morrison, Simon Hudon
+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 325790ef8b742..36747f57c3e68 100644
--- a/Mathlib/CategoryTheory/Enriched/Basic.lean
+++ b/Mathlib/CategoryTheory/Enriched/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Types.Symmetric
import Mathlib.CategoryTheory.Monoidal.Types.Coyoneda
@@ -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 a9cd25cb109d7..8c8f738cc3b9f 100644
--- a/Mathlib/CategoryTheory/EpiMono.lean
+++ b/Mathlib/CategoryTheory/EpiMono.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2019 Reid Barton. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Scott Morrison
+Authors: Reid Barton, Kim Morrison
-/
import Mathlib.CategoryTheory.Opposites
import Mathlib.CategoryTheory.Groupoid
@@ -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/EqToHom.lean b/Mathlib/CategoryTheory/EqToHom.lean
index 2c70a5bfcb94d..1a0622b180b50 100644
--- a/Mathlib/CategoryTheory/EqToHom.lean
+++ b/Mathlib/CategoryTheory/EqToHom.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Reid Barton. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Scott Morrison
+Authors: Reid Barton, Kim Morrison
-/
import Mathlib.CategoryTheory.Opposites
@@ -51,6 +51,18 @@ theorem eqToHom_trans {X Y Z : C} (p : X = Y) (q : Y = Z) :
cases q
simp
+/-- Two morphisms are conjugate via eqToHom if and only if they are heterogeneously equal.
+Note this used to be in the Functor namespace, where it doesn't belong. -/
+theorem conj_eqToHom_iff_heq {W X Y Z : C} (f : W ⟶ X) (g : Y ⟶ Z) (h : W = Y) (h' : X = Z) :
+ f = eqToHom h ≫ g ≫ eqToHom h'.symm ↔ HEq f g := by
+ cases h
+ cases h'
+ simp
+
+theorem conj_eqToHom_iff_heq' {C} [Category C] {W X Y Z : C}
+ (f : W ⟶ X) (g : Y ⟶ Z) (h : W = Y) (h' : Z = X) :
+ f = eqToHom h ≫ g ≫ eqToHom h' ↔ HEq f g := conj_eqToHom_iff_heq _ _ _ h'.symm
+
theorem comp_eqToHom_iff {X Y Y' : C} (p : Y = Y') (f : X ⟶ Y) (g : X ⟶ Y') :
f ≫ eqToHom p = g ↔ f = g ≫ eqToHom p.symm :=
{ mp := fun h => h ▸ by simp
@@ -61,6 +73,41 @@ theorem eqToHom_comp_iff {X X' Y : C} (p : X = X') (f : X ⟶ Y) (g : X' ⟶ Y)
{ mp := fun h => h ▸ by simp
mpr := fun h => h ▸ by simp [whisker_eq _ h] }
+theorem eqToHom_comp_heq {C} [Category C] {W X Y : C}
+ (f : Y ⟶ X) (h : W = Y) : HEq (eqToHom h ≫ f) f := by
+ rw [← conj_eqToHom_iff_heq _ _ h rfl, eqToHom_refl, Category.comp_id]
+
+@[simp] theorem eqToHom_comp_heq_iff {C} [Category C] {W X Y Z Z' : C}
+ (f : Y ⟶ X) (g : Z ⟶ Z') (h : W = Y) :
+ HEq (eqToHom h ≫ f) g ↔ HEq f g :=
+ ⟨(eqToHom_comp_heq ..).symm.trans, (eqToHom_comp_heq ..).trans⟩
+
+@[simp] theorem heq_eqToHom_comp_iff {C} [Category C] {W X Y Z Z' : C}
+ (f : Y ⟶ X) (g : Z ⟶ Z') (h : W = Y) :
+ HEq g (eqToHom h ≫ f) ↔ HEq g f :=
+ ⟨(·.trans (eqToHom_comp_heq ..)), (·.trans (eqToHom_comp_heq ..).symm)⟩
+
+theorem comp_eqToHom_heq {C} [Category C] {X Y Z : C}
+ (f : X ⟶ Y) (h : Y = Z) : HEq (f ≫ eqToHom h) f := by
+ rw [← conj_eqToHom_iff_heq' _ _ rfl h, eqToHom_refl, Category.id_comp]
+
+@[simp] theorem comp_eqToHom_heq_iff {C} [Category C] {W X Y Z Z' : C}
+ (f : X ⟶ Y) (g : Z ⟶ Z') (h : Y = W) :
+ HEq (f ≫ eqToHom h) g ↔ HEq f g :=
+ ⟨(comp_eqToHom_heq ..).symm.trans, (comp_eqToHom_heq ..).trans⟩
+
+@[simp] theorem heq_comp_eqToHom_iff {C} [Category C] {W X Y Z Z' : C}
+ (f : X ⟶ Y) (g : Z ⟶ Z') (h : Y = W) :
+ HEq g (f ≫ eqToHom h) ↔ HEq g f :=
+ ⟨(·.trans (comp_eqToHom_heq ..)), (·.trans (comp_eqToHom_heq ..).symm)⟩
+
+theorem heq_comp {C} [Category C] {X Y Z X' Y' Z' : C}
+ {f : X ⟶ Y} {g : Y ⟶ Z} {f' : X' ⟶ Y'} {g' : Y' ⟶ Z'}
+ (eq1 : X = X') (eq2 : Y = Y') (eq3 : Z = Z')
+ (H1 : HEq f f') (H2 : HEq g g') :
+ HEq (f ≫ g) (f' ≫ g') := by
+ cases eq1; cases eq2; cases eq3; cases H1; cases H2; rfl
+
variable {β : Sort*}
/-- We can push `eqToHom` to the left through families of morphisms. -/
@@ -197,13 +244,6 @@ lemma ext_of_iso {F G : C ⥤ D} (e : F ≅ G) (hobj : ∀ X, F.obj X = G.obj X)
rw [← cancel_mono (e.hom.app Y), e.hom.naturality f, happ, happ, Category.assoc,
Category.assoc, eqToHom_trans, eqToHom_refl, Category.comp_id])
-/-- Two morphisms are conjugate via eqToHom if and only if they are heterogeneously equal. -/
-theorem conj_eqToHom_iff_heq {W X Y Z : C} (f : W ⟶ X) (g : Y ⟶ Z) (h : W = Y) (h' : X = Z) :
- f = eqToHom h ≫ g ≫ eqToHom h'.symm ↔ HEq f g := by
- cases h
- cases h'
- simp
-
/-- Proving equality between functors using heterogeneous equality. -/
theorem hext {F G : C ⥤ D} (h_obj : ∀ X, F.obj X = G.obj X)
(h_map : ∀ (X Y) (f : X ⟶ Y), HEq (F.map f) (G.map f)) : F = G :=
diff --git a/Mathlib/CategoryTheory/Equivalence.lean b/Mathlib/CategoryTheory/Equivalence.lean
index 6e8a5e55a7204..f6f45ef4bd954 100644
--- a/Mathlib/CategoryTheory/Equivalence.lean
+++ b/Mathlib/CategoryTheory/Equivalence.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Tim Baumann, Stephen Morgan, Scott Morrison, Floris van Doorn
+Authors: Tim Baumann, Stephen Morgan, Kim Morrison, Floris van Doorn
-/
import Mathlib.CategoryTheory.Functor.FullyFaithful
import Mathlib.CategoryTheory.FullSubcategory
@@ -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/EssentiallySmall.lean b/Mathlib/CategoryTheory/EssentiallySmall.lean
index 88de842c58417..d3d3eb2c323fb 100644
--- a/Mathlib/CategoryTheory/EssentiallySmall.lean
+++ b/Mathlib/CategoryTheory/EssentiallySmall.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Category.ULift
import Mathlib.CategoryTheory.Skeletal
diff --git a/Mathlib/CategoryTheory/Extensive.lean b/Mathlib/CategoryTheory/Extensive.lean
index 887e41f0debb8..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
@@ -527,7 +527,7 @@ instance FinitaryPreExtensive.hasPullbacks_of_inclusions [FinitaryPreExtensive C
{α : Type*} (f : X ⟶ Z) {Y : (a : α) → C} (i : (a : α) → Y a ⟶ Z) [Finite α]
[hi : IsIso (Sigma.desc i)] (a : α) : HasPullback f (i a) := by
apply FinitaryPreExtensive.hasPullbacks_of_is_coproduct (c := Cofan.mk Z i)
- exact @IsColimit.ofPointIso (t := Cofan.mk Z i) (P := _) hi
+ exact @IsColimit.ofPointIso (t := Cofan.mk Z i) (P := _) (i := hi)
lemma FinitaryPreExtensive.sigma_desc_iso [FinitaryPreExtensive C] {α : Type} [Finite α] {X : C}
{Z : α → C} (π : (a : α) → Z a ⟶ X) {Y : C} (f : Y ⟶ X) (hπ : IsIso (Sigma.desc π)) :
@@ -536,7 +536,7 @@ lemma FinitaryPreExtensive.sigma_desc_iso [FinitaryPreExtensive C] {α : Type} [
change IsIso (this.coconePointUniqueUpToIso (getColimitCocone _).2).inv
infer_instance
let this : IsColimit (Cofan.mk X π) := by
- refine @IsColimit.ofPointIso (t := Cofan.mk X π) (P := coproductIsCoproduct Z) ?_
+ refine @IsColimit.ofPointIso (t := Cofan.mk X π) (P := coproductIsCoproduct Z) (i := ?_)
convert hπ
simp [coproductIsCoproduct]
refine (FinitaryPreExtensive.isUniversal_finiteCoproducts this
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/Cartesian.lean b/Mathlib/CategoryTheory/FiberedCategory/Cartesian.lean
index c2f4a20e934c0..b6f222bcedcbc 100644
--- a/Mathlib/CategoryTheory/FiberedCategory/Cartesian.lean
+++ b/Mathlib/CategoryTheory/FiberedCategory/Cartesian.lean
@@ -119,6 +119,7 @@ lemma map_self : IsCartesian.map p f φ φ = 𝟙 a := by
/-- The canonical isomorphism between the domains of two cartesian morphisms
lying over the same object. -/
+@[simps]
noncomputable def domainUniqueUpToIso {a' : 𝒳} (φ' : a' ⟶ b) [IsCartesian p f φ'] : a' ≅ a where
hom := IsCartesian.map p f φ φ'
inv := IsCartesian.map p f φ' φ
@@ -131,6 +132,14 @@ noncomputable def domainUniqueUpToIso {a' : 𝒳} (φ' : a' ⟶ b) [IsCartesian
apply IsCartesian.ext p (p.map φ) φ
simp only [assoc, fac, id_comp]
+instance domainUniqueUpToIso_inv_isHomLift {a' : 𝒳} (φ' : a' ⟶ b) [IsCartesian p f φ'] :
+ IsHomLift p (𝟙 R) (domainUniqueUpToIso p f φ φ').hom :=
+ domainUniqueUpToIso_hom p f φ φ' ▸ IsCartesian.map_isHomLift p f φ φ'
+
+instance domainUniqueUpToIso_hom_isHomLift {a' : 𝒳} (φ' : a' ⟶ b) [IsCartesian p f φ'] :
+ IsHomLift p (𝟙 R) (domainUniqueUpToIso p f φ φ').inv :=
+ domainUniqueUpToIso_inv p f φ φ' ▸ IsCartesian.map_isHomLift p f φ' φ
+
/-- Precomposing a cartesian morphism with an isomorphism lifting the identity is cartesian. -/
instance of_iso_comp {a' : 𝒳} (φ' : a' ≅ a) [IsHomLift p (𝟙 R) φ'.hom] :
IsCartesian p f (φ'.hom ≫ φ) where
@@ -351,15 +360,34 @@ lemma isIso_of_base_isIso (φ : a ⟶ b) [IsStronglyCartesian p f φ] [IsIso f]
end
+section
+
+variable {R R' S : 𝒮} {a a' b : 𝒳} {f : R ⟶ S} {f' : R' ⟶ S} {g : R' ≅ R}
+
/-- The canonical isomorphism between the domains of two strongly cartesian morphisms lying over
isomorphic objects. -/
-noncomputable def domainIsoOfBaseIso {R R' S : 𝒮} {a a' b : 𝒳} {f : R ⟶ S} {f' : R' ⟶ S}
- {g : R' ≅ R} (h : f' = g.hom ≫ f) (φ : a ⟶ b) (φ' : a' ⟶ b) [IsStronglyCartesian p f φ]
- [IsStronglyCartesian p f' φ'] : a' ≅ a where
+@[simps]
+noncomputable def domainIsoOfBaseIso (h : f' = g.hom ≫ f) (φ : a ⟶ b) (φ' : a' ⟶ b)
+ [IsStronglyCartesian p f φ] [IsStronglyCartesian p f' φ'] : a' ≅ a where
hom := map p f φ h φ'
- inv := by
- convert map p f' φ' (congrArg (g.inv ≫ ·) h.symm) φ
+ inv :=
+ haveI : p.IsHomLift ((fun x ↦ g.inv ≫ x) (g.hom ≫ f)) φ := by
+ simpa using IsCartesian.toIsHomLift
+ map p f' φ' (congrArg (g.inv ≫ ·) h.symm) φ
+
+instance domainUniqueUpToIso_inv_isHomLift (h : f' = g.hom ≫ f) (φ : a ⟶ b) (φ' : a' ⟶ b)
+ [IsStronglyCartesian p f φ] [IsStronglyCartesian p f' φ'] :
+ IsHomLift p g.hom (domainIsoOfBaseIso p h φ φ').hom :=
+ domainIsoOfBaseIso_hom p h φ φ' ▸ IsStronglyCartesian.map_isHomLift p f φ h φ'
+
+instance domainUniqueUpToIso_hom_isHomLift (h : f' = g.hom ≫ f) (φ : a ⟶ b) (φ' : a' ⟶ b)
+ [IsStronglyCartesian p f φ] [IsStronglyCartesian p f' φ'] :
+ IsHomLift p g.inv (domainIsoOfBaseIso p h φ φ').inv := by
+ haveI : p.IsHomLift ((fun x ↦ g.inv ≫ x) (g.hom ≫ f)) φ := by
simpa using IsCartesian.toIsHomLift
+ simpa using IsStronglyCartesian.map_isHomLift p f' φ' (congrArg (g.inv ≫ ·) h.symm) φ
+
+end
end IsStronglyCartesian
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/Fibered.lean b/Mathlib/CategoryTheory/FiberedCategory/Fibered.lean
index c3342d615089e..b826fc429e660 100644
--- a/Mathlib/CategoryTheory/FiberedCategory/Fibered.lean
+++ b/Mathlib/CategoryTheory/FiberedCategory/Fibered.lean
@@ -17,6 +17,15 @@ This file defines what it means for a functor `p : 𝒳 ⥤ 𝒮` to be (pre)fib
- `IsPreFibered p` expresses `𝒳` is fibered over `𝒮` via a functor `p : 𝒳 ⥤ 𝒮`, as in SGA VI.6.1.
This means that any morphism in the base `𝒮` can be lifted to a cartesian morphism in `𝒳`.
+- `IsFibered p` expresses `𝒳` is fibered over `𝒮` via a functor `p : 𝒳 ⥤ 𝒮`, as in SGA VI.6.1.
+This means that it is prefibered, and that the composition of any two cartesian morphisms is
+cartesian.
+
+In the literature one often sees the notion of a fibered category defined as the existence of
+strongly cartesian morphisms lying over any given morphism in the base. This is equivalent to the
+notion above, and we give an alternate constructor `IsFibered.of_exists_isCartesian'` for
+constructing a fibered category this way.
+
## Implementation
The constructor of `IsPreFibered` is called `exists_isCartesian'`. The reason for the prime is that
@@ -47,7 +56,18 @@ protected lemma IsPreFibered.exists_isCartesian (p : 𝒳 ⥤ 𝒮) [p.IsPreFibe
(ha : p.obj a = S) (f : R ⟶ S) : ∃ (b : 𝒳) (φ : b ⟶ a), IsCartesian p f φ := by
subst ha; exact IsPreFibered.exists_isCartesian' f
-namespace IsPreFibered
+/-- Definition of a fibered category.
+
+See SGA 1 VI.6.1. -/
+class Functor.IsFibered (p : 𝒳 ⥤ 𝒮) extends IsPreFibered p : Prop where
+ comp {R S T : 𝒮} (f : R ⟶ S) (g : S ⟶ T) {a b c : 𝒳} (φ : a ⟶ b) (ψ : b ⟶ c)
+ [IsCartesian p f φ] [IsCartesian p g ψ] : IsCartesian p (f ≫ g) (φ ≫ ψ)
+
+instance (p : 𝒳 ⥤ 𝒮) [p.IsFibered] {R S T : 𝒮} (f : R ⟶ S) (g : S ⟶ T) {a b c : 𝒳} (φ : a ⟶ b)
+ (ψ : b ⟶ c) [IsCartesian p f φ] [IsCartesian p g ψ] : IsCartesian p (f ≫ g) (φ ≫ ψ) :=
+ IsFibered.comp f g φ ψ
+
+namespace Functor.IsPreFibered
open IsCartesian
@@ -70,6 +90,97 @@ instance pullbackMap.IsCartesian : IsCartesian p f (pullbackMap ha f) :=
lemma pullbackObj_proj : p.obj (pullbackObj ha f) = R :=
domain_eq p f (pullbackMap ha f)
-end IsPreFibered
+end Functor.IsPreFibered
+
+namespace Functor.IsFibered
+
+open IsCartesian IsPreFibered
+
+/-- In a fibered category, any cartesian morphism is strongly cartesian. -/
+instance isStronglyCartesian_of_isCartesian (p : 𝒳 ⥤ 𝒮) [p.IsFibered] {R S : 𝒮} (f : R ⟶ S)
+ {a b : 𝒳} (φ : a ⟶ b) [p.IsCartesian f φ] : p.IsStronglyCartesian f φ where
+ universal_property' g φ' hφ' := by
+ -- Let `ψ` be a cartesian arrow lying over `g`
+ let ψ := pullbackMap (domain_eq p f φ) g
+ -- Let `τ` be the map induced by the universal property of `ψ ≫ φ`.
+ let τ := IsCartesian.map p (g ≫ f) (ψ ≫ φ) φ'
+ use τ ≫ ψ
+ -- It is easily verified that `τ ≫ ψ` lifts `g` and `τ ≫ ψ ≫ φ = φ'`
+ refine ⟨⟨inferInstance, by simp only [assoc, IsCartesian.fac, τ]⟩, ?_⟩
+ -- It remains to check that `τ ≫ ψ` is unique.
+ -- So fix another lift `π` of `g` satisfying `π ≫ φ = φ'`.
+ intro π ⟨hπ, hπ_comp⟩
+ -- Write `π` as `π = τ' ≫ ψ` for some `τ'` induced by the universal property of `ψ`.
+ rw [← fac p g ψ π]
+ -- It remains to show that `τ' = τ`. This follows again from the universal property of `ψ`.
+ congr 1
+ apply map_uniq
+ rwa [← assoc, IsCartesian.fac]
+
+/-- In a category which admits strongly cartesian pullbacks, any cartesian morphism is
+strongly cartesian. This is a helper-lemma for the fact that admitting strongly cartesian pullbacks
+implies being fibered. -/
+lemma isStronglyCartesian_of_exists_isCartesian (p : 𝒳 ⥤ 𝒮) (h : ∀ (a : 𝒳) (R : 𝒮)
+ (f : R ⟶ p.obj a), ∃ (b : 𝒳) (φ : b ⟶ a), IsStronglyCartesian p f φ) {R S : 𝒮} (f : R ⟶ S)
+ {a b : 𝒳} (φ : a ⟶ b) [p.IsCartesian f φ] : p.IsStronglyCartesian f φ := by
+ constructor
+ intro c g φ' hφ'
+ subst_hom_lift p f φ; clear a b R S
+ -- Let `ψ` be a cartesian arrow lying over `g`
+ obtain ⟨a', ψ, hψ⟩ := h _ _ (p.map φ)
+ -- Let `τ' : c ⟶ a'` be the map induced by the universal property of `ψ`
+ let τ' := IsStronglyCartesian.map p (p.map φ) ψ (f':= g ≫ p.map φ) rfl φ'
+ -- Let `Φ : a' ≅ a` be natural isomorphism induced between `φ` and `ψ`.
+ let Φ := domainUniqueUpToIso p (p.map φ) φ ψ
+ -- The map induced by `φ` will be `τ' ≫ Φ.hom`
+ use τ' ≫ Φ.hom
+ -- It is easily verified that `τ' ≫ Φ.hom` lifts `g` and `τ' ≫ Φ.hom ≫ φ = φ'`
+ refine ⟨⟨by simp only [Φ]; infer_instance, ?_⟩, ?_⟩
+ · simp [τ', Φ, IsStronglyCartesian.map_uniq p (p.map φ) ψ rfl φ']
+ -- It remains to check that it is unique. This follows from the universal property of `ψ`.
+ intro π ⟨hπ, hπ_comp⟩
+ rw [← Iso.comp_inv_eq]
+ apply IsStronglyCartesian.map_uniq p (p.map φ) ψ rfl φ'
+ simp [hπ_comp, Φ]
+
+/-- Alternate constructor for `IsFibered`, a functor `p : 𝒳 ⥤ 𝒴` is fibered if any diagram of the
+form
+```
+ a
+ -
+ |
+ v
+R --f--> p(a)
+```
+admits a strongly cartesian lift `b ⟶ a` of `f`. -/
+lemma of_exists_isStronglyCartesian {p : 𝒳 ⥤ 𝒮}
+ (h : ∀ (a : 𝒳) (R : 𝒮) (f : R ⟶ p.obj a),
+ ∃ (b : 𝒳) (φ : b ⟶ a), IsStronglyCartesian p f φ) :
+ IsFibered p where
+ exists_isCartesian' := by
+ intro a R f
+ obtain ⟨b, φ, hφ⟩ := h a R f
+ refine ⟨b, φ, inferInstance⟩
+ comp := fun R S T f g {a b c} φ ψ _ _ =>
+ have : p.IsStronglyCartesian f φ := isStronglyCartesian_of_exists_isCartesian p h _ _
+ have : p.IsStronglyCartesian g ψ := isStronglyCartesian_of_exists_isCartesian p h _ _
+ inferInstance
+
+/-- Given a diagram
+```
+ a
+ -
+ |
+ v
+T --g--> R --f--> S
+```
+we have an isomorphism `T ×_S a ≅ T ×_R (R ×_S a)` -/
+noncomputable def pullbackPullbackIso {p : 𝒳 ⥤ 𝒮} [IsFibered p]
+ {R S T : 𝒮} {a : 𝒳} (ha : p.obj a = S) (f : R ⟶ S) (g : T ⟶ R) :
+ pullbackObj ha (g ≫ f) ≅ pullbackObj (pullbackObj_proj ha f) g :=
+ domainUniqueUpToIso p (g ≫ f) (pullbackMap (pullbackObj_proj ha f) g ≫ pullbackMap ha f)
+ (pullbackMap ha (g ≫ f))
+
+end Functor.IsFibered
end CategoryTheory
diff --git a/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean b/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean
index f98c7a397dccd..5d64e6e16c258 100644
--- a/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean
+++ b/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean
@@ -52,7 +52,7 @@ class Functor.IsHomLift {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) :
cond : IsHomLiftAux p f φ
/-- `subst_hom_lift p f φ` tries to substitute `f` with `p(φ)` by using `p.IsHomLift f φ` -/
-macro "subst_hom_lift" p:ident f:ident φ:ident : tactic =>
+macro "subst_hom_lift" p:term:max f:term:max φ:term:max : tactic =>
`(tactic| obtain ⟨⟩ := Functor.IsHomLift.cond (p := $p) (f := $f) (φ := $φ))
/-- For any arrow `φ : a ⟶ b` in `𝒳`, `φ` lifts the arrow `p.map φ` in the base `𝒮`-/
@@ -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
@@ -142,7 +146,7 @@ instance comp_lift_id_left {a b c : 𝒳} {S T : 𝒮} (f : S ⟶ T) (ψ : b ⟶
lemma comp_lift_id_left' {a b c : 𝒳} (R : 𝒮) (φ : a ⟶ b) [p.IsHomLift (𝟙 R) φ]
{S T : 𝒮} (f : S ⟶ T) (ψ : b ⟶ c) [p.IsHomLift f ψ] : p.IsHomLift f (φ ≫ ψ) := by
obtain rfl : R = S := by rw [← codomain_eq p (𝟙 R) φ, domain_eq p f ψ]
- simpa using inferInstanceAs (p.IsHomLift (𝟙 R ≫ f) (φ ≫ ψ))
+ infer_instance
lemma eqToHom_domain_lift_id {p : 𝒳 ⥤ 𝒮} {a b : 𝒳} (hab : a = b) {R : 𝒮} (hR : p.obj a = R) :
p.IsHomLift (𝟙 R) (eqToHom hab) := by
@@ -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 f4da1d923d0e6..16dc0ee0d321c 100644
--- a/Mathlib/CategoryTheory/Filtered/Basic.lean
+++ b/Mathlib/CategoryTheory/Filtered/Basic.lean
@@ -1,15 +1,9 @@
/-
Copyright (c) 2019 Reid Barton. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Scott Morrison
+Authors: Reid Barton, Kim Morrison
-/
-import Mathlib.CategoryTheory.FinCategory.Basic
-import Mathlib.CategoryTheory.Limits.Cones
import Mathlib.CategoryTheory.Limits.Shapes.FiniteLimits
-import Mathlib.CategoryTheory.Adjunction.Basic
-import Mathlib.CategoryTheory.Category.Preorder
-import Mathlib.CategoryTheory.Category.ULift
-import Mathlib.CategoryTheory.PEmpty
/-!
# Filtered categories
@@ -546,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/Filtered/Final.lean b/Mathlib/CategoryTheory/Filtered/Final.lean
index 73d630e449fad..23d7d5c9ec781 100644
--- a/Mathlib/CategoryTheory/Filtered/Final.lean
+++ b/Mathlib/CategoryTheory/Filtered/Final.lean
@@ -20,10 +20,11 @@ final can be restated. We show:
if `StructuredArrow d F` is connected for all `d : D`.
* Under categories of objects of filtered categories are filtered and their forgetful functors
are final.
-
-Additionally, we show that if `D` is a filtered category and `F : C ⥤ D` is fully faithful and
-satisfies the additional condition that for every `d : D` there is an object `c : D` and a morphism
-`d ⟶ F.obj c`, then `C` is filtered and `F` is final.
+* If `D` is a filtered category and `F : C ⥤ D` is fully faithful and satisfies the additional
+ condition that for every `d : D` there is an object `c : D` and a morphism `d ⟶ F.obj c`, then
+ `C` is filtered and `F` is final.
+* Finality and initiality of diagonal functors `diag : C ⥤ C × C` and of projection functors
+ of (co)structured arrow categories.
## References
@@ -264,11 +265,36 @@ theorem Functor.initial_iff_isCofiltered_costructuredArrow [IsCofilteredOrEmpty
rw [initial_iff_of_isCofiltered]
exact fun h => isCofiltered_costructuredArrow_of_isCofiltered_of_exists F h.1 h.2
+/-- If `C` is filtered, then the structured arrow category on the diagonal functor `C ⥤ C × C`
+is filtered as well. -/
+instance [IsFiltered C] (X : C × C) : IsFiltered (StructuredArrow X (diag C)) := by
+ haveI : ∀ Y, IsFiltered (StructuredArrow Y (Under.forget X.1)) := by
+ rw [← final_iff_isFiltered_structuredArrow (Under.forget X.1)]
+ infer_instance
+ apply IsFiltered.of_equivalence (StructuredArrow.ofDiagEquivalence X).symm
+
+/-- The diagonal functor on any filtered category is final. -/
+instance Functor.final_diag_of_isFiltered [IsFiltered C] : Final (Functor.diag C) :=
+ final_of_isFiltered_structuredArrow _
+
+/-- If `C` is cofiltered, then the costructured arrow category on the diagonal functor `C ⥤ C × C`
+is cofiltered as well. -/
+instance [IsCofiltered C] (X : C × C) : IsCofiltered (CostructuredArrow (diag C) X) := by
+ haveI : ∀ Y, IsCofiltered (CostructuredArrow (Over.forget X.1) Y) := by
+ rw [← initial_iff_isCofiltered_costructuredArrow (Over.forget X.1)]
+ infer_instance
+ apply IsCofiltered.of_equivalence (CostructuredArrow.ofDiagEquivalence X).symm
+
+/-- The diagonal functor on any cofiltered category is initial. -/
+instance Functor.initial_diag_of_isFiltered [IsCofiltered C] : Initial (Functor.diag C) :=
+ initial_of_isCofiltered_costructuredArrow _
+
end LocallySmall
+variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D]
+
/-- If `C` is filtered, then every functor `F : C ⥤ Discrete PUnit` is final. -/
-theorem Functor.final_of_isFiltered_of_pUnit {C : Type u₁} [Category.{v₁} C]
- [IsFiltered C] (F : C ⥤ Discrete PUnit) :
+theorem Functor.final_of_isFiltered_of_pUnit [IsFiltered C] (F : C ⥤ Discrete PUnit) :
Final F := by
refine final_of_exists_of_isFiltered F (fun _ => ?_) (fun {_} {c} _ _ => ?_)
· use Classical.choice IsFiltered.nonempty
@@ -277,8 +303,7 @@ theorem Functor.final_of_isFiltered_of_pUnit {C : Type u₁} [Category.{v₁} C]
apply Subsingleton.elim
/-- If `C` is cofiltered, then every functor `F : C ⥤ Discrete PUnit` is initial. -/
-theorem Functor.initial_of_isCofiltered_pUnit {C : Type u₁} [Category.{v₁} C]
- [IsCofiltered C] (F : C ⥤ Discrete PUnit) :
+theorem Functor.initial_of_isCofiltered_pUnit [IsCofiltered C] (F : C ⥤ Discrete PUnit) :
Initial F := by
refine initial_of_exists_of_isCofiltered F (fun _ => ?_) (fun {_} {c} _ _ => ?_)
· use Classical.choice IsCofiltered.nonempty
@@ -286,4 +311,20 @@ theorem Functor.initial_of_isCofiltered_pUnit {C : Type u₁} [Category.{v₁} C
· use c; use 𝟙 c
apply Subsingleton.elim
+/-- The functor `StructuredArrow.proj : StructuredArrow Y T ⥤ C` is final if `T : C ⥤ D` is final
+and `C` is filtered. -/
+instance StructuredArrow.final_proj_of_isFiltered [IsFilteredOrEmpty C]
+ (T : C ⥤ D) [Final T] (Y : D) : Final (StructuredArrow.proj Y T) := by
+ refine ⟨fun X => ?_⟩
+ rw [isConnected_iff_of_equivalence (ofStructuredArrowProjEquivalence T Y X)]
+ exact (final_comp (Under.forget X) T).out _
+
+/-- The functor `CostructuredArrow.proj : CostructuredArrow Y T ⥤ C` is initial if `T : C ⥤ D` is
+initial and `C` is cofiltered. -/
+instance CostructuredArrow.initial_proj_of_isCofiltered [IsCofilteredOrEmpty C]
+ (T : C ⥤ D) [Initial T] (Y : D) : Initial (CostructuredArrow.proj T Y) := by
+ refine ⟨fun X => ?_⟩
+ rw [isConnected_iff_of_equivalence (ofCostructuredArrowProjEquivalence T Y X)]
+ exact (initial_comp (Over.forget X) T).out _
+
end CategoryTheory
diff --git a/Mathlib/CategoryTheory/FinCategory/AsType.lean b/Mathlib/CategoryTheory/FinCategory/AsType.lean
index 9d42330a17b22..dafd99f417b23 100644
--- a/Mathlib/CategoryTheory/FinCategory/AsType.lean
+++ b/Mathlib/CategoryTheory/FinCategory/AsType.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Data.Fintype.Card
import Mathlib.CategoryTheory.FinCategory.Basic
@@ -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/FinCategory/Basic.lean b/Mathlib/CategoryTheory/FinCategory/Basic.lean
index 4ae9b8ca21320..294cc5a1a352f 100644
--- a/Mathlib/CategoryTheory/FinCategory/Basic.lean
+++ b/Mathlib/CategoryTheory/FinCategory/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Data.Fintype.Basic
import Mathlib.CategoryTheory.DiscreteCategory
diff --git a/Mathlib/CategoryTheory/FintypeCat.lean b/Mathlib/CategoryTheory/FintypeCat.lean
index 618a4c72bae25..519fda3a21f04 100644
--- a/Mathlib/CategoryTheory/FintypeCat.lean
+++ b/Mathlib/CategoryTheory/FintypeCat.lean
@@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Bhavik Mehta, Adam Topaz
-/
import Mathlib.CategoryTheory.ConcreteCategory.Basic
-import Mathlib.CategoryTheory.FullSubcategory
+import Mathlib.CategoryTheory.Endomorphism
import Mathlib.CategoryTheory.Skeletal
-import Mathlib.Data.Fintype.Card
+import Mathlib.Data.Finite.Prod
/-!
# The category of finite types.
@@ -99,6 +99,15 @@ def equivEquivIso {A B : FintypeCat} : A ≃ B ≃ (A ≅ B) where
left_inv := by aesop_cat
right_inv := by aesop_cat
+instance (X Y : FintypeCat) : Finite (X ⟶ Y) :=
+ inferInstanceAs <| Finite (X → Y)
+
+instance (X Y : FintypeCat) : Finite (X ≅ Y) :=
+ Finite.of_injective _ (fun _ _ h ↦ Iso.ext h)
+
+instance (X : FintypeCat) : Finite (Aut X) :=
+ inferInstanceAs <| Finite (X ≅ X)
+
universe u
/--
@@ -189,5 +198,76 @@ lemma isSkeleton : IsSkeletonOf FintypeCat Skeleton Skeleton.incl where
skel := Skeleton.is_skeletal
eqv := by infer_instance
+section Universes
+
+universe v
+
+/-- If `u` and `v` are two arbitrary universes, we may construct a functor
+`uSwitch.{u, v} : FintypeCat.{u} ⥤ FintypeCat.{v}` by sending
+`X : FintypeCat.{u}` to `ULift.{v} (Fin (Fintype.card X))`. -/
+noncomputable def uSwitch : FintypeCat.{u} ⥤ FintypeCat.{v} where
+ obj X := FintypeCat.of <| ULift.{v} (Fin (Fintype.card X))
+ map {X Y} f x := ULift.up <| (Fintype.equivFin Y) (f ((Fintype.equivFin X).symm x.down))
+ map_comp {X Y Z} f g := by ext; simp
+
+/-- Switching the universe of an object `X : FintypeCat.{u}` does not change `X` up to equivalence
+of types. This is natural in the sense that it commutes with `uSwitch.map f` for
+any `f : X ⟶ Y` in `FintypeCat.{u}`. -/
+noncomputable def uSwitchEquiv (X : FintypeCat.{u}) :
+ uSwitch.{u, v}.obj X ≃ X :=
+ Equiv.ulift.trans (Fintype.equivFin X).symm
+
+lemma uSwitchEquiv_naturality {X Y : FintypeCat.{u}} (f : X ⟶ Y)
+ (x : uSwitch.{u, v}.obj X) :
+ f (X.uSwitchEquiv x) = Y.uSwitchEquiv (uSwitch.map f x) := by
+ simp only [uSwitch, uSwitchEquiv, Equiv.trans_apply]
+ erw [Equiv.ulift_apply, Equiv.ulift_apply]
+ simp only [Equiv.symm_apply_apply]
+
+lemma uSwitchEquiv_symm_naturality {X Y : FintypeCat.{u}} (f : X ⟶ Y) (x : X) :
+ uSwitch.map f (X.uSwitchEquiv.symm x) = Y.uSwitchEquiv.symm (f x) := by
+ rw [← Equiv.apply_eq_iff_eq_symm_apply, ← uSwitchEquiv_naturality f,
+ Equiv.apply_symm_apply]
+
+lemma uSwitch_map_uSwitch_map {X Y : FintypeCat.{u}} (f : X ⟶ Y) :
+ uSwitch.map (uSwitch.map f) =
+ (equivEquivIso ((uSwitch.obj X).uSwitchEquiv.trans X.uSwitchEquiv)).hom ≫
+ f ≫ (equivEquivIso ((uSwitch.obj Y).uSwitchEquiv.trans
+ Y.uSwitchEquiv)).inv := by
+ ext x
+ simp only [comp_apply, equivEquivIso_apply_hom, Equiv.trans_apply]
+ rw [uSwitchEquiv_naturality f, ← uSwitchEquiv_naturality]
+ rfl
+
+/-- `uSwitch.{u, v}` is an equivalence of categories with quasi-inverse `uSwitch.{v, u}`. -/
+noncomputable def uSwitchEquivalence : FintypeCat.{u} ≌ FintypeCat.{v} where
+ functor := uSwitch
+ inverse := uSwitch
+ unitIso := NatIso.ofComponents (fun X ↦ (equivEquivIso <|
+ (uSwitch.obj X).uSwitchEquiv.trans X.uSwitchEquiv).symm) <| by
+ simp [uSwitch_map_uSwitch_map]
+ counitIso := NatIso.ofComponents (fun X ↦ equivEquivIso <|
+ (uSwitch.obj X).uSwitchEquiv.trans X.uSwitchEquiv) <| by
+ simp [uSwitch_map_uSwitch_map]
+ functor_unitIso_comp X := by
+ ext x
+ simp [← uSwitchEquiv_naturality]
+
+instance : uSwitch.IsEquivalence :=
+ uSwitchEquivalence.isEquivalence_functor
+
+end Universes
end FintypeCat
+
+namespace FunctorToFintypeCat
+
+universe u v w
+
+variable {C : Type u} [Category.{v} C] (F G : C ⥤ FintypeCat.{w}) {X Y : C}
+
+lemma naturality (σ : F ⟶ G) (f : X ⟶ Y) (x : F.obj X) :
+ σ.app Y (F.map f x) = G.map f (σ.app X x) :=
+ congr_fun (σ.naturality f) x
+
+end FunctorToFintypeCat
diff --git a/Mathlib/CategoryTheory/FullSubcategory.lean b/Mathlib/CategoryTheory/FullSubcategory.lean
index 8aa58d273b2d2..bf98131940b9e 100644
--- a/Mathlib/CategoryTheory/FullSubcategory.lean
+++ b/Mathlib/CategoryTheory/FullSubcategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Reid Barton
+Authors: Kim Morrison, Reid Barton
-/
import Mathlib.CategoryTheory.Functor.FullyFaithful
diff --git a/Mathlib/CategoryTheory/Functor/Basic.lean b/Mathlib/CategoryTheory/Functor/Basic.lean
index bff78cc031a50..4be276945c1e4 100644
--- a/Mathlib/CategoryTheory/Functor/Basic.lean
+++ b/Mathlib/CategoryTheory/Functor/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Tim Baumann, Stephen Morgan, Scott Morrison
+Authors: Tim Baumann, Stephen Morgan, Kim Morrison
-/
import Mathlib.CategoryTheory.Category.Basic
diff --git a/Mathlib/CategoryTheory/Functor/Category.lean b/Mathlib/CategoryTheory/Functor/Category.lean
index 654f3f72d8875..7a1687ae5667d 100644
--- a/Mathlib/CategoryTheory/Functor/Category.lean
+++ b/Mathlib/CategoryTheory/Functor/Category.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Tim Baumann, Stephen Morgan, Scott Morrison, Floris van Doorn
+Authors: Tim Baumann, Stephen Morgan, Kim Morrison, Floris van Doorn
-/
import Mathlib.CategoryTheory.NatTrans
import Mathlib.CategoryTheory.Iso
@@ -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 006504deb58b6..ba2d6a7b37e98 100644
--- a/Mathlib/CategoryTheory/Functor/Const.lean
+++ b/Mathlib/CategoryTheory/Functor/Const.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Opposites
@@ -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 caa5be9b7f6d8..5c8021e9a84c0 100644
--- a/Mathlib/CategoryTheory/Functor/Currying.lean
+++ b/Mathlib/CategoryTheory/Functor/Currying.lean
@@ -1,8 +1,9 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
+import Mathlib.CategoryTheory.EqToHom
import Mathlib.CategoryTheory.Products.Basic
/-!
@@ -90,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 c594f3a1805e1..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]
@@ -268,7 +268,7 @@ instance (adj : F ⊣ F') {X : C} {Y : D} (f : F.obj X ⟶ Y) [hf : Mono f] [F.R
Mono (adj.homEquiv _ _ f) :=
F.mono_of_mono_map <| by
rw [← (homEquiv adj X Y).symm_apply_apply f] at hf
- exact mono_of_mono_fac adj.homEquiv_counit.symm
+ exact mono_of_mono_fac (adj.homEquiv_counit _ _ _).symm
end CategoryTheory.Adjunction
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/FullyFaithful.lean b/Mathlib/CategoryTheory/Functor/FullyFaithful.lean
index cbc95c08b955f..82f3de969be51 100644
--- a/Mathlib/CategoryTheory/Functor/FullyFaithful.lean
+++ b/Mathlib/CategoryTheory/Functor/FullyFaithful.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.NatIso
import Mathlib.Logic.Equiv.Defs
diff --git a/Mathlib/CategoryTheory/Functor/FunctorHom.lean b/Mathlib/CategoryTheory/Functor/FunctorHom.lean
index af550df60805c..3f4312c687eaa 100644
--- a/Mathlib/CategoryTheory/Functor/FunctorHom.lean
+++ b/Mathlib/CategoryTheory/Functor/FunctorHom.lean
@@ -41,6 +41,7 @@ structure HomObj (A : C ⥤ Type w) where
/-- When `F`, `G`, and `A` are all functors `C ⥤ Type w`, then `HomObj F G A` is in
bijection with `F ⊗ A ⟶ G`. -/
+@[simps]
def homObjEquiv (F G A : C ⥤ Type w) : (HomObj F G A) ≃ (F ⊗ A ⟶ G) where
toFun a := ⟨fun X ⟨x, y⟩ ↦ a.app X y x, fun X Y f ↦ by
ext ⟨x, y⟩
@@ -87,6 +88,7 @@ def map {A' : C ⥤ Type w} (f : A' ⟶ A) (x : HomObj F G A) : HomObj F G A' wh
end HomObj
/-- The contravariant functor taking `A : C ⥤ Type w` to `HomObj F G A`, i.e. Hom(F ⊗ -, G). -/
+@[simps]
def homObjFunctor : (C ⥤ Type w)ᵒᵖ ⥤ Type max w v' u where
obj A := HomObj F G A.unop
map {A A'} f x :=
@@ -109,6 +111,7 @@ lemma functorHom_ext {X : C} {x y : (F.functorHom G).obj X}
HomObj.ext (by ext; apply h)
/-- The equivalence `(A ⟶ F.functorHom G) ≃ HomObj F G A`. -/
+@[simps]
def functorHomEquiv (A : C ⥤ Type max u v v') : (A ⟶ F.functorHom G) ≃ HomObj F G A where
toFun φ :=
{ app := fun X a ↦ (φ.app X a).app X (𝟙 _)
@@ -200,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/Functorial.lean b/Mathlib/CategoryTheory/Functor/Functorial.lean
index 7b9fadaad4f11..f55993471df00 100644
--- a/Mathlib/CategoryTheory/Functor/Functorial.lean
+++ b/Mathlib/CategoryTheory/Functor/Functorial.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Functor.Basic
diff --git a/Mathlib/CategoryTheory/Functor/Hom.lean b/Mathlib/CategoryTheory/Functor/Hom.lean
index 01f3ac9dd321f..225924cf02b07 100644
--- a/Mathlib/CategoryTheory/Functor/Hom.lean
+++ b/Mathlib/CategoryTheory/Functor/Hom.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Reid Barton. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Scott Morrison
+Authors: Reid Barton, Kim Morrison
-/
import Mathlib.CategoryTheory.Products.Basic
import Mathlib.CategoryTheory.Types
diff --git a/Mathlib/CategoryTheory/Functor/KanExtension/Adjunction.lean b/Mathlib/CategoryTheory/Functor/KanExtension/Adjunction.lean
index 57c9c1c9353e0..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,13 +198,35 @@ 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`. -/
noncomputable def ranAdjunction : (whiskeringLeft C D H).obj L ⊣ L.ran :=
Adjunction.mkOfHomEquiv
{ homEquiv := fun F G =>
- (homEquivOfIsRightKanExtension (α := L.ranCounit.app G) F).symm
+ (homEquivOfIsRightKanExtension (α := L.ranCounit.app G) _ F).symm
homEquiv_naturality_right := fun {F G₁ G₂} β f ↦
hom_ext_of_isRightKanExtension _ (L.ranCounit.app G₂) _ _ (by
ext X
@@ -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 cf9297f47d979..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
@@ -343,6 +391,27 @@ instance : (pointwiseLeftKanExtension L F).IsLeftKanExtension
instance : HasLeftKanExtension L F :=
HasLeftKanExtension.mk _ (pointwiseLeftKanExtensionUnit L F)
+/-- An auxiliary cocone used in the lemma `pointwiseLeftKanExtension_desc_app` -/
+@[simps]
+def costructuredArrowMapCocone (G : D ⥤ H) (α : F ⟶ L ⋙ G) (Y : D) :
+ Cocone (CostructuredArrow.proj L Y ⋙ F) where
+ pt := G.obj Y
+ ι := {
+ app := fun f ↦ α.app f.left ≫ G.map f.hom
+ naturality := by simp [← G.map_comp] }
+
+@[simp]
+lemma pointwiseLeftKanExtension_desc_app (G : D ⥤ H) (α : F ⟶ L ⋙ G) (Y : D) :
+ ((pointwiseLeftKanExtension L F).descOfIsLeftKanExtension (pointwiseLeftKanExtensionUnit L F)
+ G α |>.app Y) = colimit.desc _ (costructuredArrowMapCocone L F G α Y) := by
+ let β : L.pointwiseLeftKanExtension F ⟶ G :=
+ { app := fun Y ↦ colimit.desc _ (costructuredArrowMapCocone L F G α Y) }
+ have h : (pointwiseLeftKanExtension L F).descOfIsLeftKanExtension
+ (pointwiseLeftKanExtensionUnit L F) G α = β := by
+ apply hom_ext_of_isLeftKanExtension (α := pointwiseLeftKanExtensionUnit L F)
+ aesop
+ exact NatTrans.congr_app h Y
+
variable {F L}
/-- If `F` admits a pointwise left Kan extension along `L`, then any left Kan extension of `F`
@@ -421,6 +490,28 @@ instance : (pointwiseRightKanExtension L F).IsRightKanExtension
instance : HasRightKanExtension L F :=
HasRightKanExtension.mk _ (pointwiseRightKanExtensionCounit L F)
+/-- An auxiliary cocone used in the lemma `pointwiseRightKanExtension_lift_app` -/
+@[simps]
+def structuredArrowMapCone (G : D ⥤ H) (α : L ⋙ G ⟶ F) (Y : D) :
+ Cone (StructuredArrow.proj Y L ⋙ F) where
+ pt := G.obj Y
+ π := {
+ app := fun f ↦ G.map f.hom ≫ α.app f.right
+ naturality := by simp [← α.naturality, ← G.map_comp_assoc] }
+
+@[simp]
+lemma pointwiseRightKanExtension_lift_app (G : D ⥤ H) (α : L ⋙ G ⟶ F) (Y : D) :
+ ((pointwiseRightKanExtension L F).liftOfIsRightKanExtension
+ (pointwiseRightKanExtensionCounit L F) G α |>.app Y) =
+ limit.lift _ (structuredArrowMapCone L F G α Y) := by
+ let β : G ⟶ L.pointwiseRightKanExtension F :=
+ { app := fun Y ↦ limit.lift _ (structuredArrowMapCone L F G α Y) }
+ have h : (pointwiseRightKanExtension L F).liftOfIsRightKanExtension
+ (pointwiseRightKanExtensionCounit L F) G α = β := by
+ apply hom_ext_of_isRightKanExtension (α := pointwiseRightKanExtensionCounit L F)
+ aesop
+ exact NatTrans.congr_app h Y
+
variable {F L}
/-- If `F` admits a pointwise right Kan extension along `L`, then any right Kan extension of `F`
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/Action.lean b/Mathlib/CategoryTheory/Galois/Action.lean
new file mode 100644
index 0000000000000..fbf5fbd2f2b86
--- /dev/null
+++ b/Mathlib/CategoryTheory/Galois/Action.lean
@@ -0,0 +1,89 @@
+/-
+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.Galois.Examples
+import Mathlib.CategoryTheory.Galois.Prorepresentability
+
+/-!
+
+# Induced functor to finite `Aut F`-sets
+
+Any (fiber) functor `F : C ⥤ FintypeCat` factors via the forgetful functor
+from finite `Aut F`-sets to finite sets. In this file we collect basic properties
+of the induced functor `H : C ⥤ Action FintypeCat (MonCat.of (Aut F))`.
+
+See `Mathlib.CategoryTheory.Galois.Full` for the proof that `H` is (faithfully) full.
+
+-/
+
+universe u v
+
+namespace CategoryTheory
+
+namespace PreGaloisCategory
+
+open Limits Functor
+
+variable {C : Type u} [Category.{v} C] (F : C ⥤ FintypeCat.{u})
+
+/-- Any (fiber) functor `F : C ⥤ FintypeCat` naturally factors via
+the forgetful functor from `Action FintypeCat (MonCat.of (Aut F))` to `FintypeCat`. -/
+def functorToAction : C ⥤ Action FintypeCat.{u} (MonCat.of (Aut F)) where
+ obj X := Action.FintypeCat.ofMulAction (Aut F) (F.obj X)
+ map f := {
+ hom := F.map f
+ comm := fun g ↦ symm <| g.hom.naturality f
+ }
+
+lemma functorToAction_comp_forget₂_eq : functorToAction F ⋙ forget₂ _ FintypeCat = F := rfl
+
+@[simp]
+lemma functorToAction_map {X Y : C} (f : X ⟶ Y) : ((functorToAction F).map f).hom = F.map f :=
+ rfl
+
+instance (X : C) : MulAction (Aut X) ((functorToAction F).obj X).V :=
+ inferInstanceAs <| MulAction (Aut X) (F.obj X)
+
+variable [GaloisCategory C] [FiberFunctor F]
+
+instance (X : C) [IsGalois X] : MulAction.IsPretransitive (Aut X) ((functorToAction F).obj X).V :=
+ isPretransitive_of_isGalois F X
+
+instance : Functor.Faithful (functorToAction F) :=
+ have : Functor.Faithful (functorToAction F ⋙ forget₂ _ FintypeCat) :=
+ inferInstanceAs <| Functor.Faithful F
+ Functor.Faithful.of_comp (functorToAction F) (forget₂ _ FintypeCat)
+
+instance : PreservesMonomorphisms (functorToAction F) :=
+ have : PreservesMonomorphisms (functorToAction F ⋙ forget₂ _ FintypeCat) :=
+ inferInstanceAs <| PreservesMonomorphisms F
+ preservesMonomorphisms_of_preserves_of_reflects (functorToAction F) (forget₂ _ FintypeCat)
+
+instance : ReflectsMonomorphisms (functorToAction F) := reflectsMonomorphisms_of_faithful _
+
+instance : Functor.ReflectsIsomorphisms (functorToAction F) where
+ reflects f _ :=
+ have : IsIso (F.map f) := (forget₂ _ FintypeCat).map_isIso ((functorToAction F).map f)
+ isIso_of_reflects_iso f F
+
+noncomputable instance : PreservesFiniteCoproducts (functorToAction F) :=
+ ⟨fun J _ ↦ Action.preservesColimitsOfShapeOfPreserves (functorToAction F)
+ (inferInstanceAs <| PreservesColimitsOfShape (Discrete J) F)⟩
+
+noncomputable instance : PreservesFiniteProducts (functorToAction F) :=
+ ⟨fun J _ ↦ Action.preservesLimitsOfShapeOfPreserves (functorToAction F)
+ (inferInstanceAs <| PreservesLimitsOfShape (Discrete J) F)⟩
+
+noncomputable instance (G : Type*) [Group G] [Finite G] :
+ PreservesColimitsOfShape (SingleObj G) (functorToAction F) :=
+ Action.preservesColimitsOfShapeOfPreserves _ <|
+ inferInstanceAs <| PreservesColimitsOfShape (SingleObj G) F
+
+instance : PreservesIsConnected (functorToAction F) :=
+ ⟨fun {X} _ ↦ FintypeCat.Action.isConnected_of_transitive (Aut F) (F.obj X)⟩
+
+end PreGaloisCategory
+
+end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Galois/Basic.lean b/Mathlib/CategoryTheory/Galois/Basic.lean
index 60874987826dd..131a2e864a5bb 100644
--- a/Mathlib/CategoryTheory/Galois/Basic.lean
+++ b/Mathlib/CategoryTheory/Galois/Basic.lean
@@ -3,16 +3,14 @@ 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.FintypeCat
import Mathlib.CategoryTheory.Limits.Constructions.LimitsOfProductsAndEqualizers
import Mathlib.CategoryTheory.Limits.FintypeCat
import Mathlib.CategoryTheory.Limits.MonoCoprod
-import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Terminal
-import Mathlib.CategoryTheory.Limits.Shapes.Types
import Mathlib.CategoryTheory.Limits.Shapes.ConcreteCategory
import Mathlib.CategoryTheory.Limits.Shapes.Diagonal
import Mathlib.CategoryTheory.SingleObj
import Mathlib.Data.Finite.Card
+import Mathlib.Logic.Equiv.TransferInstance
/-!
# Definition and basic properties of Galois categories
@@ -41,7 +39,7 @@ as this is not needed for the proof of the fundamental theorem on Galois categor
-/
-universe u₁ u₂ v₁ v₂ w
+universe u₁ u₂ v₁ v₂ w t
namespace CategoryTheory
@@ -117,6 +115,11 @@ instance : HasBinaryProducts C := hasBinaryProducts_of_hasTerminal_and_pullbacks
instance : HasEqualizers C := hasEqualizers_of_hasPullbacks_and_binary_products
+-- A `PreGaloisCategory` has quotients by finite groups in arbitrary universes. -/
+instance {G : Type*} [Group G] [Finite G] : HasColimitsOfShape (SingleObj G) C := by
+ obtain ⟨G', hg, hf, ⟨e⟩⟩ := Finite.exists_type_univ_nonempty_mulEquiv G
+ exact Limits.hasColimitsOfShape_of_equivalence e.toSingleObjEquiv.symm
+
end
namespace FiberFunctor
@@ -136,11 +139,17 @@ noncomputable instance : ReflectsColimitsOfShape (Discrete PEmpty.{1}) F :=
noncomputable instance : PreservesFiniteLimits F :=
preservesFiniteLimitsOfPreservesTerminalAndPullbacks F
+/-- Fiber functors preserve quotients by finite groups in arbitrary universes. -/
+noncomputable instance {G : Type*} [Group G] [Finite G] :
+ PreservesColimitsOfShape (SingleObj G) F := by
+ choose G' hg hf he using Finite.exists_type_univ_nonempty_mulEquiv G
+ exact Limits.preservesColimitsOfShapeOfEquiv he.some.toSingleObjEquiv.symm F
+
/-- Fiber functors reflect monomorphisms. -/
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
@@ -157,6 +166,16 @@ instance : F.Faithful where
haveI : IsIso (equalizer.ι f g) := isIso_of_reflects_iso _ F
exact eq_of_epi_equalizer
+section
+
+/-- If `F` is a fiber functor and `E` is an equivalence between categories of finite types,
+then `F ⋙ E` is again a fiber functor. -/
+noncomputable def compRight (E : FintypeCat.{w} ⥤ FintypeCat.{t}) [E.IsEquivalence] :
+ FiberFunctor (F ⋙ E) where
+ preservesQuotientsByFiniteGroups _ := compPreservesColimitsOfShape F E
+
+end
+
end FiberFunctor
variable {C : Type u₁} [Category.{u₂, u₁} C]
@@ -172,6 +191,10 @@ lemma mulAction_def {X : C} (σ : Aut F) (x : F.obj X) :
σ • x = σ.hom.app X x :=
rfl
+lemma mulAction_naturality {X Y : C} (σ : Aut F) (f : X ⟶ Y) (x : F.obj X) :
+ σ • F.map f x = F.map f (σ • x) :=
+ FunctorToFintypeCat.naturality F F σ.hom f x
+
/-- An object that is neither initial or connected has a non-trivial subobject. -/
lemma has_non_trivial_subobject_of_not_isConnected_of_not_initial (X : C) (hc : ¬ IsConnected X)
(hi : IsInitial X → False) :
@@ -309,6 +332,15 @@ lemma surjective_of_nonempty_fiber_of_isConnected {X A : C} [Nonempty (F.obj X)]
have : Epi f := epi_of_nonempty_of_isConnected F f
exact surjective_on_fiber_of_epi F f
+/-- If `X : ι → C` is a finite family of objects with non-empty fiber, then
+also `∏ᶜ X` has non-empty fiber. -/
+instance nonempty_fiber_pi_of_nonempty_of_finite {ι : Type*} [Finite ι] (X : ι → C)
+ [∀ i, Nonempty (F.obj (X i))] : Nonempty (F.obj (∏ᶜ X)) := by
+ cases nonempty_fintype ι
+ let f (i : ι) : FintypeCat.{w} := F.obj (X i)
+ let i : F.obj (∏ᶜ X) ≅ ∏ᶜ f := PreservesProduct.iso F _
+ exact Nonempty.elim inferInstance fun x : (∏ᶜ f : FintypeCat.{w}) ↦ ⟨i.inv x⟩
+
section CardFiber
open ConcreteCategory
diff --git a/Mathlib/CategoryTheory/Galois/Decomposition.lean b/Mathlib/CategoryTheory/Galois/Decomposition.lean
index b9febf20bbfc8..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
@@ -308,6 +309,15 @@ lemma exists_hom_from_galois_of_connected (X : C) [IsConnected X] :
∃ (A : C) (_ : A ⟶ X), IsGalois A :=
exists_hom_from_galois_of_fiber_nonempty F X inferInstance
+/-- To check equality of natural transformations `F ⟶ G`, it suffices to check it on
+Galois objects. -/
+lemma natTrans_ext_of_isGalois {G : C ⥤ FintypeCat.{w}} {t s : F ⟶ G}
+ (h : ∀ (X : C) [IsGalois X], t.app X = s.app X) :
+ t = s := by
+ ext X x
+ obtain ⟨A, f, a, _, rfl⟩ := exists_hom_from_galois_of_fiber F X x
+ rw [FunctorToFintypeCat.naturality, FunctorToFintypeCat.naturality, h A]
+
end GaloisRep
end PreGaloisCategory
diff --git a/Mathlib/CategoryTheory/Galois/EssSurj.lean b/Mathlib/CategoryTheory/Galois/EssSurj.lean
new file mode 100644
index 0000000000000..06f9db4d4af8d
--- /dev/null
+++ b/Mathlib/CategoryTheory/Galois/EssSurj.lean
@@ -0,0 +1,263 @@
+/-
+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.Galois.Full
+import Mathlib.CategoryTheory.Galois.Topology
+import Mathlib.Topology.Algebra.OpenSubgroup
+
+/-!
+
+# Essential surjectivity of fiber functors
+
+Let `F : C ⥤ FintypeCat` be a fiber functor of a Galois category `C` and denote by
+`H` the induced functor `C ⥤ Action FintypeCat (Aut F)`.
+
+In this file we show that the essential image of `H` consists of the finite `Aut F`-sets where
+the `Aut F` action is continuous.
+
+## Main results
+
+- `exists_lift_of_quotient_openSubgroup`: If `U` is an open subgroup of `Aut F`, then
+ there exists an object `X` such that `F.obj X` is isomorphic to `Aut F ⧸ U` as
+ `Aut F`-sets.
+- `exists_lift_of_continuous`: If `X` is a finite, discrete `Aut F`-set, then
+ there exists an object `A` such that `F.obj A` is isomorphic to `X` as
+ `Aut F`-sets.
+
+## Strategy
+
+We first show that every finite, discrete `Aut F`-set `Y` has a decomposition into connected
+components and each connected component is of the form `Aut F ⧸ U` for an open subgroup `U`.
+Since `H` preserves finite coproducts, it hence suffices to treat the case `Y = Aut F ⧸ U`.
+For the case `Y = Aut F ⧸ U` we closely follow the second part of Stacks Project Tag 0BN4.
+
+-/
+
+noncomputable section
+
+universe u₁ u₂
+
+namespace CategoryTheory
+
+namespace PreGaloisCategory
+
+variable {C : Type u₁} [Category.{u₂} C] {F : C ⥤ FintypeCat.{u₁}}
+
+open Limits Functor
+
+variable [GaloisCategory C] [FiberFunctor F]
+
+variable {G : Type*} [Group G] [TopologicalSpace G] [TopologicalGroup G] [CompactSpace G]
+
+private local instance fintypeQuotient (H : OpenSubgroup (G)) :
+ Fintype (G ⧸ (H : Subgroup (G))) :=
+ have : Finite (G ⧸ H.toSubgroup) := H.toSubgroup.quotient_finite_of_isOpen H.isOpen'
+ Fintype.ofFinite _
+
+private local instance fintypeQuotientStabilizer {X : Type*} [MulAction G X]
+ [TopologicalSpace X] [ContinuousSMul G X] [DiscreteTopology X] (x : X) :
+ Fintype (G ⧸ (MulAction.stabilizer (G) x)) :=
+ fintypeQuotient ⟨MulAction.stabilizer (G) x, stabilizer_isOpen (G) x⟩
+
+/-- If `X` is a finite discrete `G`-set, it can be written as the finite disjoint union
+of quotients of the form `G ⧸ Uᵢ` for open subgroups `(Uᵢ)`. Note that this
+is simply the decomposition into orbits. -/
+lemma has_decomp_quotients (X : Action FintypeCat (MonCat.of G))
+ [TopologicalSpace X.V] [DiscreteTopology X.V] [ContinuousSMul G X.V] :
+ ∃ (ι : Type) (_ : Finite ι) (f : ι → OpenSubgroup (G)),
+ Nonempty ((∐ fun i ↦ G ⧸ₐ (f i).toSubgroup) ≅ X) := by
+ obtain ⟨ι, hf, f, u, hc⟩ := has_decomp_connected_components' X
+ letI (i : ι) : TopologicalSpace (f i).V := ⊥
+ haveI (i : ι) : DiscreteTopology (f i).V := ⟨rfl⟩
+ have (i : ι) : ContinuousSMul G (f i).V := ContinuousSMul.mk <| by
+ let r : f i ⟶ X := Sigma.ι f i ≫ u.hom
+ let r'' (p : G × (f i).V) : G × X.V := (p.1, r.hom p.2)
+ let q (p : G × X.V) : X.V := X.ρ p.1 p.2
+ let q' (p : G × (f i).V) : (f i).V := (f i).ρ p.1 p.2
+ have heq : q ∘ r'' = r.hom ∘ q' := by
+ ext (p : G × (f i).V)
+ exact (congr_fun (r.comm p.1) p.2).symm
+ have hrinj : Function.Injective r.hom :=
+ (ConcreteCategory.mono_iff_injective_of_preservesPullback r).mp <| mono_comp _ _
+ let t₁ : TopologicalSpace (G × (f i).V) := inferInstance
+ show @Continuous _ _ _ ⊥ q'
+ have : TopologicalSpace.induced r.hom inferInstance = ⊥ := by
+ rw [← le_bot_iff]
+ exact fun s _ ↦ ⟨r.hom '' s, ⟨isOpen_discrete (r.hom '' s), Set.preimage_image_eq s hrinj⟩⟩
+ rw [← this, continuous_induced_rng, ← heq]
+ exact Continuous.comp continuous_smul (by fun_prop)
+ have (i : ι) : ∃ (U : OpenSubgroup (G)), (Nonempty ((f i) ≅ G ⧸ₐ U.toSubgroup)) := by
+ obtain ⟨(x : (f i).V)⟩ := nonempty_fiber_of_isConnected (forget₂ _ _) (f i)
+ let U : OpenSubgroup (G) := ⟨MulAction.stabilizer (G) x, stabilizer_isOpen (G) x⟩
+ letI : Fintype (G ⧸ MulAction.stabilizer (G) x) := fintypeQuotient U
+ exact ⟨U, ⟨FintypeCat.isoQuotientStabilizerOfIsConnected (f i) x⟩⟩
+ choose g ui using this
+ exact ⟨ι, hf, g, ⟨(Sigma.mapIso (fun i ↦ (ui i).some)).symm ≪≫ u⟩⟩
+
+/-- If `X` is connected and `x` is in the fiber of `X`, `F.obj X` is isomorphic
+to the quotient of `Aut F` by the stabilizer of `x` as `Aut F`-sets. -/
+def fiberIsoQuotientStabilizer (X : C) [IsConnected X] (x : F.obj X) :
+ (functorToAction F).obj X ≅ Aut F ⧸ₐ MulAction.stabilizer (Aut F) x :=
+ haveI : IsConnected ((functorToAction F).obj X) := PreservesIsConnected.preserves
+ letI : Fintype (Aut F ⧸ MulAction.stabilizer (Aut F) x) := fintypeQuotientStabilizer x
+ FintypeCat.isoQuotientStabilizerOfIsConnected ((functorToAction F).obj X) x
+
+section
+
+open Action.FintypeCat
+
+variable (V : OpenSubgroup (Aut F)) {U : OpenSubgroup (Aut F)}
+ (h : Subgroup.Normal U.toSubgroup) {A : C} (u : (functorToAction F).obj A ≅ Aut F ⧸ₐ U.toSubgroup)
+
+/-
+
+### Strategy outline
+
+Let `A` be an object of `C` with fiber `Aut F`-isomorphic to `Aut F ⧸ U` for an open normal
+subgroup `U`. Then for any open subgroup `V` of `Aut F`, `V ⧸ (U ⊓ V)` acts on `A`. This
+induces the diagram `quotientDiag`. Now assume `U ≤ V`. Then we can also postcompose
+the diagram `quotientDiag` with `F`. The goal of this section is to compute that the colimit
+of this composed diagram is `Aut F ⧸ V`. Finally, we obtain `F.obj (A ⧸ V) ≅ Aut F ⧸ V` as
+`Aut F`-sets.
+-/
+
+private def quotientToEndObjectHom :
+ V.toSubgroup ⧸ Subgroup.subgroupOf U.toSubgroup V.toSubgroup →* End A :=
+ let ff : (functorToAction F).FullyFaithful := FullyFaithful.ofFullyFaithful (functorToAction F)
+ let e : End A ≃* End (Aut F ⧸ₐ U.toSubgroup) := (ff.mulEquivEnd A).trans (Iso.conj u)
+ e.symm.toMonoidHom.comp (quotientToEndHom V.toSubgroup U.toSubgroup)
+
+private lemma functorToAction_map_quotientToEndObjectHom
+ (m : SingleObj.star (V ⧸ Subgroup.subgroupOf U.toSubgroup V.toSubgroup) ⟶
+ SingleObj.star (V ⧸ Subgroup.subgroupOf U.toSubgroup V.toSubgroup)) :
+ (functorToAction F).map (quotientToEndObjectHom V h u m) =
+ u.hom ≫ quotientToEndHom V.toSubgroup U.toSubgroup m ≫ u.inv := by
+ simp [← cancel_epi u.inv, ← cancel_mono u.hom, ← Iso.conj_apply, quotientToEndObjectHom]
+
+@[simps!]
+private def quotientDiag : SingleObj (V.toSubgroup ⧸ Subgroup.subgroupOf U V) ⥤ C :=
+ SingleObj.functor (quotientToEndObjectHom V h u)
+
+variable {V} (hUinV : U ≤ V)
+
+@[simps]
+private def coconeQuotientDiag :
+ Cocone (quotientDiag V h u ⋙ functorToAction F) where
+ pt := Aut F ⧸ₐ V.toSubgroup
+ ι := SingleObj.natTrans (u.hom ≫ quotientToQuotientOfLE V.toSubgroup U.toSubgroup hUinV) <| by
+ intro (m : V ⧸ Subgroup.subgroupOf U V)
+ simp only [const_obj_obj, Functor.comp_map, const_obj_map, Category.comp_id]
+ rw [← cancel_epi (u.inv), Iso.inv_hom_id_assoc]
+ apply Action.hom_ext
+ ext (x : Aut F ⧸ U.toSubgroup)
+ induction' m, x using Quotient.inductionOn₂ with σ μ
+ suffices h : ⟦μ * σ⁻¹⟧ = ⟦μ⟧ by
+ simp only [quotientToQuotientOfLE_hom_mk, quotientDiag_map,
+ functorToAction_map_quotientToEndObjectHom V _ u]
+ simpa
+ apply Quotient.sound
+ apply (QuotientGroup.leftRel_apply).mpr
+ simp
+
+@[simps]
+private def coconeQuotientDiagDesc
+ (s : Cocone (quotientDiag V h u ⋙ functorToAction F)) :
+ (coconeQuotientDiag h u hUinV).pt ⟶ s.pt where
+ hom := Quotient.lift (fun σ ↦ (u.inv ≫ s.ι.app (SingleObj.star _)).hom ⟦σ⟧) <| fun σ τ hst ↦ by
+ let J' := quotientDiag V h u ⋙ functorToAction F
+ let m : End (SingleObj.star (V.toSubgroup ⧸ Subgroup.subgroupOf U V)) :=
+ ⟦⟨σ⁻¹ * τ, (QuotientGroup.leftRel_apply).mp hst⟩⟧
+ have h1 : J'.map m ≫ s.ι.app (SingleObj.star _) = s.ι.app (SingleObj.star _) := s.ι.naturality m
+ conv_rhs => rw [← h1]
+ have h2 : (J'.map m).hom (u.inv.hom ⟦τ⟧) = u.inv.hom ⟦σ⟧ := by
+ simp only [comp_obj, quotientDiag_obj, Functor.comp_map, quotientDiag_map, J',
+ functorToAction_map_quotientToEndObjectHom V h u m]
+ show (u.inv ≫ u.hom ≫ _ ≫ u.inv).hom ⟦τ⟧ = u.inv.hom ⟦σ⟧
+ simp [m]
+ simp only [← h2, const_obj_obj, Action.comp_hom, FintypeCat.comp_apply]
+ comm g := by
+ ext (x : Aut F ⧸ V.toSubgroup)
+ induction' x using Quotient.inductionOn with σ
+ simp only [const_obj_obj]
+ show (((Aut F ⧸ₐ U.toSubgroup).ρ g ≫ u.inv.hom) ≫ (s.ι.app (SingleObj.star _)).hom) ⟦σ⟧ =
+ ((s.ι.app (SingleObj.star _)).hom ≫ s.pt.ρ g) (u.inv.hom ⟦σ⟧)
+ have : ((functorToAction F).obj A).ρ g ≫ (s.ι.app (SingleObj.star _)).hom =
+ (s.ι.app (SingleObj.star _)).hom ≫ s.pt.ρ g :=
+ (s.ι.app (SingleObj.star _)).comm g
+ rw [← this, u.inv.comm g]
+ rfl
+
+/-- The constructed cocone `coconeQuotientDiag` on the diagram `quotientDiag` is colimiting. -/
+private def coconeQuotientDiagIsColimit :
+ IsColimit (coconeQuotientDiag h u hUinV) where
+ desc := coconeQuotientDiagDesc h u hUinV
+ fac s j := by
+ apply (cancel_epi u.inv).mp
+ apply Action.hom_ext
+ ext (x : Aut F ⧸ U.toSubgroup)
+ induction' x using Quotient.inductionOn with σ
+ simp
+ rfl
+ uniq s f hf := by
+ apply Action.hom_ext
+ ext (x : Aut F ⧸ V.toSubgroup)
+ induction' x using Quotient.inductionOn with σ
+ simp [← hf (SingleObj.star _)]
+
+end
+
+/-- For every open subgroup `V` of `Aut F`, there exists an `X : C` such that
+`F.obj X ≅ Aut F ⧸ V` as `Aut F`-sets. -/
+lemma exists_lift_of_quotient_openSubgroup (V : OpenSubgroup (Aut F)) :
+ ∃ (X : C), Nonempty ((functorToAction F).obj X ≅ Aut F ⧸ₐ V.toSubgroup) := by
+ obtain ⟨I, hf, hc, hi⟩ := exists_set_ker_evaluation_subset_of_isOpen F (one_mem V) V.isOpen'
+ haveI (X : I) : IsConnected X.val := hc X X.property
+ haveI (X : I) : Nonempty (F.obj X.val) := nonempty_fiber_of_isConnected F X
+ have hn : Nonempty (F.obj <| (∏ᶜ fun X : I => X)) := nonempty_fiber_pi_of_nonempty_of_finite F _
+ obtain ⟨A, f, hgal⟩ := exists_hom_from_galois_of_fiber_nonempty F (∏ᶜ fun X : I => X) hn
+ obtain ⟨a⟩ := nonempty_fiber_of_isConnected F A
+ let U : OpenSubgroup (Aut F) := ⟨MulAction.stabilizer (Aut F) a, stabilizer_isOpen (Aut F) a⟩
+ let u := fiberIsoQuotientStabilizer A a
+ have hUnormal : U.toSubgroup.Normal := stabilizer_normal_of_isGalois F A a
+ have h1 (σ : Aut F) (σinU : σ ∈ U) : σ.hom.app A = 𝟙 (F.obj A) := by
+ have hi : (Aut F ⧸ₐ MulAction.stabilizer (Aut F) a).ρ σ = 𝟙 _ := by
+ refine FintypeCat.hom_ext _ _ (fun x ↦ ?_)
+ induction' x using Quotient.inductionOn with τ
+ show ⟦σ * τ⟧ = ⟦τ⟧
+ apply Quotient.sound
+ apply (QuotientGroup.leftRel_apply).mpr
+ simp only [mul_inv_rev]
+ exact Subgroup.Normal.conj_mem hUnormal _ (Subgroup.inv_mem U.toSubgroup σinU) _
+ simp [← cancel_mono u.hom.hom, show σ.hom.app A ≫ u.hom.hom = _ from u.hom.comm σ, hi]
+ have h2 (σ : Aut F) (σinU : σ ∈ U) : ∀ X : I, σ.hom.app X = 𝟙 (F.obj X) := by
+ intro ⟨X, hX⟩
+ ext (x : F.obj X)
+ let p : A ⟶ X := f ≫ Pi.π (fun Z : I => (Z : C)) ⟨X, hX⟩
+ have : IsConnected X := hc X hX
+ obtain ⟨a, rfl⟩ := surjective_of_nonempty_fiber_of_isConnected F p x
+ simp only [FintypeCat.id_apply, FunctorToFintypeCat.naturality, h1 σ σinU]
+ have hUinV : (U : Set (Aut F)) ≤ V := fun u uinU ↦ hi u (h2 u uinU)
+ have := V.quotient_finite_of_isOpen' (U.subgroupOf V) V.isOpen (V.subgroupOf_isOpen U U.isOpen)
+ exact ⟨colimit (quotientDiag V hUnormal u),
+ ⟨preservesColimitIso (functorToAction F) (quotientDiag V hUnormal u) ≪≫
+ colimit.isoColimitCocone ⟨coconeQuotientDiag hUnormal u hUinV,
+ coconeQuotientDiagIsColimit hUnormal u hUinV⟩⟩⟩
+
+/--
+If `X` is a finite, discrete `Aut F`-set with continuous `Aut F`-action, then
+there exists `A : C` such that `F.obj A ≅ X` as `Aut F`-sets.
+-/
+@[stacks 0BN4 "Essential surjectivity part"]
+theorem exists_lift_of_continuous (X : Action FintypeCat (MonCat.of (Aut F)))
+ [TopologicalSpace X.V] [DiscreteTopology X.V] [ContinuousSMul (Aut F) X.V] :
+ ∃ A, Nonempty ((functorToAction F).obj A ≅ X) := by
+ obtain ⟨ι, hfin, f, ⟨u⟩⟩ := has_decomp_quotients X
+ choose g gu using (fun i ↦ exists_lift_of_quotient_openSubgroup (f i))
+ exact ⟨∐ g, ⟨PreservesCoproduct.iso (functorToAction F) g ≪≫
+ Sigma.mapIso (fun i ↦ (gu i).some) ≪≫ u⟩⟩
+
+end PreGaloisCategory
+
+end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Galois/Examples.lean b/Mathlib/CategoryTheory/Galois/Examples.lean
index f7b722ebca408..f52783a0ae08a 100644
--- a/Mathlib/CategoryTheory/Galois/Examples.lean
+++ b/Mathlib/CategoryTheory/Galois/Examples.lean
@@ -4,12 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Christian Merten
-/
import Mathlib.CategoryTheory.Galois.Basic
-import Mathlib.RepresentationTheory.Action.Basic
import Mathlib.RepresentationTheory.Action.Concrete
import Mathlib.RepresentationTheory.Action.Limits
-import Mathlib.CategoryTheory.Limits.FintypeCat
-import Mathlib.CategoryTheory.Limits.Shapes.Types
-import Mathlib.Logic.Equiv.TransferInstance
/-!
# Examples of Galois categories and fiber functors
@@ -25,10 +21,10 @@ universe u v w
namespace CategoryTheory
-namespace FintypeCat
-
open Limits Functor PreGaloisCategory
+namespace FintypeCat
+
/-- Complement of the image of a morphism `f : X ⟶ Y` in `FintypeCat`. -/
noncomputable def imageComplement {X Y : FintypeCat.{u}} (f : X ⟶ Y) :
FintypeCat.{u} := by
@@ -74,7 +70,7 @@ instance {X Y : Action FintypeCat (MonCat.of G)} (f : X ⟶ Y) :
/-- The category of finite sets has quotients by finite groups in arbitrary universes. -/
instance [Finite G] : HasColimitsOfShape (SingleObj G) FintypeCat.{w} := by
- obtain ⟨G', hg, hf, ⟨e⟩⟩ := Finite.exists_type_zero_nonempty_mulEquiv G
+ obtain ⟨G', hg, hf, ⟨e⟩⟩ := Finite.exists_type_univ_nonempty_mulEquiv G
exact Limits.hasColimitsOfShape_of_equivalence e.toSingleObjEquiv.symm
noncomputable instance : PreservesFiniteLimits (forget (Action FintypeCat (MonCat.of G))) := by
@@ -83,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
@@ -94,7 +90,11 @@ 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) :=
+ inferInstanceAs <| FiberFunctor (Action.forget FintypeCat (MonCat.of G))
/-- The category of finite `G`-sets is a `GaloisCategory`. -/
instance : GaloisCategory (Action FintypeCat (MonCat.of G)) where
@@ -149,6 +149,23 @@ theorem Action.isConnected_iff_transitive (X : Action FintypeCat (MonCat.of G))
IsConnected X ↔ MulAction.IsPretransitive G X.V :=
⟨fun _ ↦ pretransitive_of_isConnected G X, fun _ ↦ isConnected_of_transitive G X.V⟩
+variable {G}
+
+/-- If `X` is a connected `G`-set and `x` is an element of `X`, `X` is isomorphic
+to the quotient of `G` by the stabilizer of `x` as `G`-sets. -/
+noncomputable def isoQuotientStabilizerOfIsConnected (X : Action FintypeCat (MonCat.of G))
+ [IsConnected X] (x : X.V) [Fintype (G ⧸ (MulAction.stabilizer G x))] :
+ X ≅ G ⧸ₐ MulAction.stabilizer G x :=
+ haveI : MulAction.IsPretransitive G X.V := Action.pretransitive_of_isConnected G X
+ let e : X.V ≃ G ⧸ MulAction.stabilizer G x :=
+ (Equiv.Set.univ X.V).symm.trans <|
+ (Equiv.setCongr ((MulAction.orbit_eq_univ G x).symm)).trans <|
+ MulAction.orbitEquivQuotientStabilizer G x
+ Iso.symm <| Action.mkIso (FintypeCat.equivEquivIso e.symm) <| fun σ : G ↦ by
+ ext (a : G ⧸ MulAction.stabilizer G x)
+ obtain ⟨τ, rfl⟩ := Quotient.exists_rep a
+ exact mul_smul σ τ x
+
end FintypeCat
end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Galois/Full.lean b/Mathlib/CategoryTheory/Galois/Full.lean
new file mode 100644
index 0000000000000..4c09add2e62f9
--- /dev/null
+++ b/Mathlib/CategoryTheory/Galois/Full.lean
@@ -0,0 +1,129 @@
+/-
+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.Galois.Action
+
+/-!
+
+# Fiber functors are (faithfully) full
+
+Any (fiber) functor `F : C ⥤ FintypeCat` factors via the forgetful functor
+from finite `Aut F`-sets to finite sets. The induced functor
+`H : C ⥤ Action FintypeCat (MonCat.of (Aut F))` is faithfully full. The faithfulness
+follows easily from the faithfulness of `F`. In this file we show that `H` is also full.
+
+## Main results
+
+- `PreGaloisCategory.exists_lift_of_mono`: If `Y` is a sub-`Aut F`-set of `F.obj X`, there exists
+ a sub-object `Z` of `X` such that `F.obj Z ≅ Y` as `Aut F`-sets.
+- `PreGaloisCategory.functorToAction_full`: The induced functor `H` from above is full.
+
+The main input for this is that the induced functor `H : C ⥤ Action FintypeCat (MonCat.of (Aut F))`
+preserves connectedness, which translates to the fact that `Aut F` acts transitively on
+the fibers of connected objects.
+
+## Implementation details
+
+We only show this for small categories, because the preservation of connectedness result as it
+is currently in Mathlib is only shown for
+`(C : Type u₁) [Category.{u₂} C] (F : C ⥤ FintypeCat.{u₂})` and by the definition of `Action`,
+this forces `u₁ = u₂` for the definition of `functorToAction`. Mathematically there should
+be no obstruction to generalizing the results of this file to arbitrary universes.
+
+-/
+
+universe u v
+
+namespace CategoryTheory
+
+namespace PreGaloisCategory
+
+open Limits Functor
+
+variable {C : Type u} [Category.{v} C] (F : C ⥤ FintypeCat.{u}) [GaloisCategory C] [FiberFunctor F]
+
+/--
+Let `X` be an object of a Galois category with fiber functor `F` and `Y` a sub-`Aut F`-set
+of `F.obj X`, on which `Aut F` acts transitively (i.e. which is connected in the Galois category
+of finite `Aut F`-sets). Then there exists a connected sub-object `Z` of `X` and an isomorphism
+`Y ≅ F.obj X` as `Aut F`-sets such that the obvious triangle commutes.
+
+For a version without the connectedness assumption, see `exists_lift_of_mono`.
+-/
+lemma exists_lift_of_mono_of_isConnected (X : C) (Y : Action FintypeCat.{u} (MonCat.of (Aut F)))
+ (i : Y ⟶ (functorToAction F).obj X) [Mono i] [IsConnected Y] : ∃ (Z : C) (f : Z ⟶ X)
+ (u : Y ≅ (functorToAction F).obj Z),
+ IsConnected Z ∧ Mono f ∧ i = u.hom ≫ (functorToAction F).map f := by
+ obtain ⟨y⟩ := nonempty_fiber_of_isConnected (forget₂ _ FintypeCat) Y
+ obtain ⟨Z, f, z, hz, hc, hm⟩ := fiber_in_connected_component F X (i.hom y)
+ have : IsConnected ((functorToAction F).obj Z) := PreservesIsConnected.preserves
+ obtain ⟨u, hu⟩ := connected_component_unique
+ (forget₂ (Action FintypeCat (MonCat.of (Aut F))) FintypeCat) (B := (functorToAction F).obj Z)
+ y z i ((functorToAction F).map f) hz.symm
+ refine ⟨Z, f, u, hc, hm, ?_⟩
+ apply evaluation_injective_of_isConnected
+ (forget₂ (Action FintypeCat (MonCat.of (Aut F))) FintypeCat) Y ((functorToAction F).obj X) y
+ suffices h : i.hom y = F.map f z by simpa [hu]
+ exact hz.symm
+
+/--
+Let `X` be an object of a Galois category with fiber functor `F` and `Y` a sub-`Aut F`-set
+of `F.obj X`. Then there exists a sub-object `Z` of `X` and an isomorphism
+`Y ≅ F.obj X` as `Aut F`-sets such that the obvious triangle commutes.
+-/
+lemma exists_lift_of_mono (X : C) (Y : Action FintypeCat.{u} (MonCat.of (Aut F)))
+ (i : Y ⟶ (functorToAction F).obj X) [Mono i] : ∃ (Z : C) (f : Z ⟶ X)
+ (u : Y ≅ (functorToAction F).obj Z), Mono f ∧ u.hom ≫ (functorToAction F).map f = i := by
+ obtain ⟨ι, hf, f, t, hc⟩ := has_decomp_connected_components' Y
+ let i' (j : ι) : f j ⟶ (functorToAction F).obj X := Sigma.ι f j ≫ t.hom ≫ i
+ have (j : ι) : Mono (i' j) :=
+ have : Mono (Sigma.ι f j) := MonoCoprod.mono_ι f j
+ have : Mono (t.hom ≫ i) := mono_comp _ _
+ mono_comp _ _
+ choose gZ gf gu _ _ h using fun i ↦ exists_lift_of_mono_of_isConnected F X (f i) (i' i)
+ let is2 : (functorToAction F).obj (∐ gZ) ≅ ∐ fun i => (functorToAction F).obj (gZ i) :=
+ PreservesCoproduct.iso (functorToAction F) gZ
+ let u' : ∐ f ≅ ∐ fun i => (functorToAction F).obj (gZ i) := Sigma.mapIso gu
+ have heq : (functorToAction F).map (Sigma.desc gf) = (t.symm ≪≫ u' ≪≫ is2.symm).inv ≫ i := by
+ simp only [Iso.trans_inv, Iso.symm_inv, Category.assoc]
+ rw [← Iso.inv_comp_eq]
+ refine Sigma.hom_ext _ _ (fun j ↦ ?_)
+ suffices (functorToAction F).map (gf j) = (gu j).inv ≫ i' j by
+ simpa [is2, u']
+ simp only [h, Iso.inv_hom_id_assoc]
+ refine ⟨∐ gZ, Sigma.desc gf, t.symm ≪≫ u' ≪≫ is2.symm, ?_, by simp [heq]⟩
+ · exact mono_of_mono_map (functorToAction F) (heq ▸ mono_comp _ _)
+
+/-- The by a fiber functor `F : C ⥤ FintypeCat` induced functor `functorToAction F` to
+finite `Aut F`-sets is full. -/
+instance functorToAction_full : Functor.Full (functorToAction F) where
+ map_surjective {X Y} f := by
+ let u : (functorToAction F).obj X ⟶ (functorToAction F).obj X ⨯ (functorToAction F).obj Y :=
+ prod.lift (𝟙 _) f
+ let i : (functorToAction F).obj X ⟶ (functorToAction F).obj (X ⨯ Y) :=
+ u ≫ (PreservesLimitPair.iso (functorToAction F) X Y).inv
+ have : Mono i := by
+ have : Mono (u ≫ prod.fst) := prod.lift_fst (𝟙 _) f ▸ inferInstance
+ have : Mono u := mono_of_mono u prod.fst
+ apply mono_comp u _
+ obtain ⟨Z, g, v, _, hvgi⟩ := exists_lift_of_mono F (Limits.prod X Y)
+ ((functorToAction F).obj X) i
+ let ψ : Z ⟶ X := g ≫ prod.fst
+ have hgvi : (functorToAction F).map g = v.inv ≫ i := by simp [← hvgi]
+ have : IsIso ((functorToAction F).map ψ) := by
+ simp only [map_comp, hgvi, Category.assoc, ψ]
+ have : IsIso (i ≫ (functorToAction F).map prod.fst) := by
+ suffices h : IsIso (𝟙 ((functorToAction F).obj X)) by simpa [i, u]
+ infer_instance
+ apply IsIso.comp_isIso
+ have : IsIso ψ := isIso_of_reflects_iso ψ (functorToAction F)
+ use inv ψ ≫ g ≫ prod.snd
+ rw [← cancel_epi ((functorToAction F).map ψ)]
+ ext (z : F.obj Z)
+ simp [-FintypeCat.comp_apply, -Action.comp_hom, i, u, ψ, hgvi]
+
+end PreGaloisCategory
+
+end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Galois/GaloisObjects.lean b/Mathlib/CategoryTheory/Galois/GaloisObjects.lean
index 5196d8d135625..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
/-!
@@ -35,7 +36,7 @@ open Limits Functor
noncomputable instance {G : Type v} [Group G] [Finite G] :
PreservesColimitsOfShape (SingleObj G) FintypeCat.incl.{w} := by
- choose G' hg hf e using Finite.exists_type_zero_nonempty_mulEquiv G
+ choose G' hg hf e using Finite.exists_type_univ_nonempty_mulEquiv G
exact Limits.preservesColimitsOfShapeOfEquiv (Classical.choice e).toSingleObjEquiv.symm _
/-- A connected object `X` of `C` is Galois if the quotient `X / Aut X` is terminal. -/
@@ -95,6 +96,17 @@ instance isPretransitive_of_isGalois (X : C) [IsGalois X] :
rw [← isGalois_iff_pretransitive]
infer_instance
+lemma stabilizer_normal_of_isGalois (X : C) [IsGalois X] (x : F.obj X) :
+ Subgroup.Normal (MulAction.stabilizer (Aut F) x) where
+ conj_mem n ninstab g := by
+ rw [MulAction.mem_stabilizer_iff]
+ show g • n • (g⁻¹ • x) = x
+ have : ∃ (φ : Aut X), F.map φ.hom x = g⁻¹ • x :=
+ MulAction.IsPretransitive.exists_smul_eq x (g⁻¹ • x)
+ obtain ⟨φ, h⟩ := this
+ rw [← h, mulAction_naturality, ninstab, h]
+ simp
+
theorem evaluation_aut_surjective_of_isGalois (A : C) [IsGalois A] (a : F.obj A) :
Function.Surjective (fun f : Aut A ↦ F.map f.hom a) :=
MulAction.IsPretransitive.exists_smul_eq a
diff --git a/Mathlib/CategoryTheory/Galois/IsFundamentalgroup.lean b/Mathlib/CategoryTheory/Galois/IsFundamentalgroup.lean
new file mode 100644
index 0000000000000..0e137b3d0c354
--- /dev/null
+++ b/Mathlib/CategoryTheory/Galois/IsFundamentalgroup.lean
@@ -0,0 +1,288 @@
+/-
+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.Galois.Basic
+import Mathlib.CategoryTheory.Galois.Topology
+import Mathlib.CategoryTheory.Galois.Prorepresentability
+import Mathlib.Topology.Algebra.OpenSubgroup
+
+/-!
+
+# Universal property of fundamental group
+
+Let `C` be a Galois category with fiber functor `F`. While in informal mathematics, we tend to
+identify known groups from other contexts (e.g. the absolute Galois group of a field) with
+the automorphism group `Aut F` of certain fiber functors `F`, this causes friction in formalization.
+
+Hence, in this file we develop conditions when a topological group `G` is canonically isomorphic to
+the automorphism group `Aut F` of `F`. Consequently, the API for Galois categories and their fiber
+functors should be stated in terms of an abstract topological group `G` satisfying
+`IsFundamentalGroup` in the places where `Aut F` would appear.
+
+## Main definition
+
+Given a compact, topological group `G` with an action on `F.obj X` on each `X`, we say that
+`G` is a fundamental group of `F` (`IsFundamentalGroup F G`), if
+
+- `naturality`: the `G`-action on `F.obj X` is compatible with morphisms in `C`
+- `transitive_of_isGalois`: `G` acts transitively on `F.obj X` for all Galois objects `X : C`
+- `continuous_smul`: the action of `G` on `F.obj X` is continuous if `F.obj X` is equipped with the
+ discrete topology for all `X : C`.
+- `non_trivial': if `g : G` acts trivial on all `F.obj X`, then `g = 1`.
+
+Given this data, we define `toAut F G : G →* Aut F` in the natural way.
+
+## Main results
+
+- `toAut_bijective`: `toAut F G` is a group isomorphism given `IsFundamentalGroup F G`.
+- `toAut_isHomeomorph`: `toAut F G` is a homeomorphism given `IsFundamentalGroup F G`.
+
+## TODO
+
+- Develop further equivalent conditions, in particular, relate the condition `non_trivial` with
+ `G` being a `T2Space`.
+
+-/
+universe u₁ u₂ w
+
+namespace CategoryTheory
+
+namespace PreGaloisCategory
+
+open Limits Functor
+
+variable {C : Type u₁} [Category.{u₂} C] (F : C ⥤ FintypeCat.{w})
+
+section
+
+variable (G : Type*) [Group G] [∀ X, MulAction G (F.obj X)]
+
+/-- We say `G` acts naturally on the fibers of `F` if for every `f : X ⟶ Y`, the `G`-actions
+on `F.obj X` and `F.obj Y` are compatible with `F.map f`. -/
+class IsNaturalSMul : Prop where
+ naturality (g : G) {X Y : C} (f : X ⟶ Y) (x : F.obj X) : F.map f (g • x) = g • F.map f x
+
+variable {G} in
+@[simps!]
+private def isoOnObj (g : G) (X : C) : F.obj X ≅ F.obj X :=
+ FintypeCat.equivEquivIso <| {
+ toFun := fun x ↦ g • x
+ invFun := fun x ↦ g⁻¹ • x
+ left_inv := fun _ ↦ by simp
+ right_inv := fun _ ↦ by simp
+ }
+
+variable [IsNaturalSMul F G]
+
+/-- If `G` acts naturally on `F.obj X` for each `X : C`, this is the canonical
+group homomorphism into the automorphism group of `F`. -/
+def toAut : G →* Aut F where
+ toFun g := NatIso.ofComponents (isoOnObj F g) <| by
+ intro X Y f
+ ext
+ simp [IsNaturalSMul.naturality]
+ map_one' := by
+ ext
+ simp only [NatIso.ofComponents_hom_app, isoOnObj_hom, one_smul]
+ rfl
+ map_mul' := by
+ intro g h
+ ext X x
+ simp only [NatIso.ofComponents_hom_app, isoOnObj_hom, mul_smul]
+ rfl
+
+variable {G} in
+@[simp]
+lemma toAut_hom_app_apply (g : G) {X : C} (x : F.obj X) : (toAut F G g).hom.app X x = g • x :=
+ rfl
+
+/-- `toAut` is injective, if only the identity acts trivially on every fiber. -/
+lemma toAut_injective_of_non_trivial (h : ∀ (g : G), (∀ (X : C) (x : F.obj X), g • x = x) → g = 1) :
+ Function.Injective (toAut F G) := by
+ rw [← MonoidHom.ker_eq_bot_iff, eq_bot_iff]
+ intro g (hg : toAut F G g = 1)
+ refine h g (fun X x ↦ ?_)
+ have : (toAut F G g).hom.app X = 𝟙 (F.obj X) := by
+ rw [hg]
+ rfl
+ rw [← toAut_hom_app_apply, this, FintypeCat.id_apply]
+
+variable [GaloisCategory C] [FiberFunctor F]
+
+lemma toAut_continuous [TopologicalSpace G] [TopologicalGroup G]
+ [∀ (X : C), ContinuousSMul G (F.obj X)] :
+ Continuous (toAut F G) := by
+ apply continuous_of_continuousAt_one
+ rw [continuousAt_def, map_one]
+ intro A hA
+ obtain ⟨X, _, hX⟩ := ((nhds_one_has_basis_stabilizers F).mem_iff' A).mp hA
+ rw [mem_nhds_iff]
+ exact ⟨MulAction.stabilizer G X.pt, Set.preimage_mono (f := toAut F G) hX,
+ stabilizer_isOpen G X.pt, one_mem _⟩
+
+variable {G}
+
+lemma action_ext_of_isGalois {t : F ⟶ F} {X : C} [IsGalois X] {g : G} (x : F.obj X)
+ (hg : g • x = t.app X x) (y : F.obj X) : g • y = t.app X y := by
+ obtain ⟨φ, (rfl : F.map φ.hom y = x)⟩ := MulAction.exists_smul_eq (Aut X) y x
+ have : Function.Injective (F.map φ.hom) :=
+ ConcreteCategory.injective_of_mono_of_preservesPullback (F.map φ.hom)
+ apply this
+ rw [IsNaturalSMul.naturality, hg, FunctorToFintypeCat.naturality]
+
+variable (G)
+
+lemma toAut_surjective_isGalois (t : Aut F) (X : C) [IsGalois X]
+ [MulAction.IsPretransitive G (F.obj X)] :
+ ∃ (g : G), ∀ (x : F.obj X), g • x = t.hom.app X x := by
+ obtain ⟨a⟩ := nonempty_fiber_of_isConnected F X
+ obtain ⟨g, hg⟩ := MulAction.exists_smul_eq G a (t.hom.app X a)
+ exact ⟨g, action_ext_of_isGalois F _ hg⟩
+
+lemma toAut_surjective_isGalois_finite_family (t : Aut F) {ι : Type*} [Finite ι] (X : ι → C)
+ [∀ i, IsGalois (X i)] (h : ∀ (X : C) [IsGalois X], MulAction.IsPretransitive G (F.obj X)) :
+ ∃ (g : G), ∀ (i : ι) (x : F.obj (X i)), g • x = t.hom.app (X i) x := by
+ let x (i : ι) : F.obj (X i) := (nonempty_fiber_of_isConnected F (X i)).some
+ let P : C := ∏ᶜ X
+ letI : Fintype ι := Fintype.ofFinite ι
+ let is₁ : F.obj P ≅ ∏ᶜ fun i ↦ (F.obj (X i)) := PreservesProduct.iso F X
+ let is₂ : (∏ᶜ fun i ↦ F.obj (X i) : FintypeCat) ≃ ∀ i, F.obj (X i) :=
+ Limits.FintypeCat.productEquiv (fun i ↦ (F.obj (X i)))
+ let px : F.obj P := is₁.inv (is₂.symm x)
+ have hpx (i : ι) : F.map (Pi.π X i) px = x i := by
+ simp only [px, is₁, is₂, ← piComparison_comp_π, ← PreservesProduct.iso_hom]
+ simp only [FintypeCat.comp_apply, FintypeCat.inv_hom_id_apply,
+ FintypeCat.productEquiv_symm_comp_π_apply]
+ obtain ⟨A, f, a, _, hfa⟩ := exists_hom_from_galois_of_fiber F P px
+ obtain ⟨g, hg⟩ := toAut_surjective_isGalois F G t A
+ refine ⟨g, fun i y ↦ action_ext_of_isGalois F (x i) ?_ _⟩
+ rw [← hpx i, ← IsNaturalSMul.naturality, FunctorToFintypeCat.naturality,
+ ← hfa, FunctorToFintypeCat.naturality, ← IsNaturalSMul.naturality, hg]
+
+open Pointwise
+
+/-- If `G` is a compact, topological group that acts continuously and naturally on the
+fibers of `F`, `toAut F G` is surjective if and only if it acts transitively on the fibers
+of all Galois objects. This is the `if` direction. For the `only if` see
+`isPretransitive_of_surjective`. -/
+lemma toAut_surjective_of_isPretransitive [TopologicalSpace G] [TopologicalGroup G] [CompactSpace G]
+ [∀ (X : C), ContinuousSMul G (F.obj X)]
+ (h : ∀ (X : C) [IsGalois X], MulAction.IsPretransitive G (F.obj X)) :
+ Function.Surjective (toAut F G) := by
+ intro t
+ choose gi hgi using (fun X : PointedGaloisObject F ↦ toAut_surjective_isGalois F G t X)
+ let cl (X : PointedGaloisObject F) : Set G := gi X • MulAction.stabilizer G X.pt
+ let c : Set G := ⋂ i, cl i
+ have hne : c.Nonempty := by
+ rw [← Set.univ_inter c]
+ apply CompactSpace.isCompact_univ.inter_iInter_nonempty
+ · intro X
+ apply IsClosed.leftCoset
+ exact Subgroup.isClosed_of_isOpen _ (stabilizer_isOpen G X.pt)
+ · intro s
+ rw [Set.univ_inter]
+ obtain ⟨gs, hgs⟩ :=
+ toAut_surjective_isGalois_finite_family F G t (fun X : s ↦ X.val.obj) h
+ use gs
+ simp only [Set.mem_iInter]
+ intro X hXmem
+ rw [mem_leftCoset_iff, SetLike.mem_coe, MulAction.mem_stabilizer_iff, mul_smul,
+ hgs ⟨X, hXmem⟩, ← hgi X, inv_smul_smul]
+ obtain ⟨g, hg⟩ := hne
+ refine ⟨g, Iso.ext <| natTrans_ext_of_isGalois _ <| fun X _ ↦ ?_⟩
+ ext x
+ simp only [toAut_hom_app_apply]
+ have : g ∈ (gi ⟨X, x, inferInstance⟩ • MulAction.stabilizer G x : Set G) := by
+ simp only [Set.mem_iInter, c] at hg
+ exact hg _
+ obtain ⟨s, (hsmem : s • x = x), (rfl : gi ⟨X, x, inferInstance⟩ • s = _)⟩ := this
+ rw [smul_eq_mul, mul_smul, hsmem]
+ exact hgi ⟨X, x, inferInstance⟩ x
+
+/-- If `toAut F G` is surjective, then `G` acts transitively on the fibers of connected objects.
+For a converse see `toAut_surjective`. -/
+lemma isPretransitive_of_surjective (h : Function.Surjective (toAut F G)) (X : C)
+ [IsConnected X] : MulAction.IsPretransitive G (F.obj X) where
+ exists_smul_eq x y := by
+ obtain ⟨t, ht⟩ := MulAction.exists_smul_eq (Aut F) x y
+ obtain ⟨g, rfl⟩ := h t
+ exact ⟨g, ht⟩
+
+end
+
+section
+
+variable [GaloisCategory C]
+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 trivially acting element of `G`
+is the identity. -/
+class IsFundamentalGroup [TopologicalSpace G] [TopologicalGroup G] [CompactSpace G]
+ extends IsNaturalSMul F G : Prop where
+ transitive_of_isGalois (X : C) [IsGalois X] : MulAction.IsPretransitive G (F.obj X)
+ continuous_smul (X : C) : ContinuousSMul G (F.obj X)
+ non_trivial' (g : G) : (∀ (X : C) (x : F.obj X), g • x = x) → g = 1
+
+namespace IsFundamentalGroup
+
+attribute [instance] continuous_smul transitive_of_isGalois
+
+variable {G} [TopologicalSpace G] [TopologicalGroup G] [CompactSpace G] [IsFundamentalGroup F G]
+
+lemma non_trivial (g : G) (h : ∀ (X : C) (x : F.obj X), g • x = x) : g = 1 :=
+ IsFundamentalGroup.non_trivial' g h
+
+end IsFundamentalGroup
+
+variable [FiberFunctor F]
+
+/-- `Aut F` is a fundamental group for `F`. -/
+instance : IsFundamentalGroup F (Aut F) where
+ 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
+ ext X x
+ exact h X x
+
+variable [TopologicalSpace G] [TopologicalGroup G] [CompactSpace G] [IsFundamentalGroup F G]
+
+lemma toAut_bijective : Function.Bijective (toAut F G) where
+ left := toAut_injective_of_non_trivial F G IsFundamentalGroup.non_trivial'
+ right := toAut_surjective_of_isPretransitive F G IsFundamentalGroup.transitive_of_isGalois
+
+instance (X : C) [IsConnected X] : MulAction.IsPretransitive G (F.obj X) :=
+ isPretransitive_of_surjective F G (toAut_bijective F G).surjective X
+
+/-- If `G` is the fundamental group for `F`, it is isomorphic to `Aut F` as groups and
+this isomorphism is also a homeomorphism (see `toAutMulEquiv_isHomeomorph`). -/
+noncomputable def toAutMulEquiv : G ≃* Aut F :=
+ MulEquiv.ofBijective (toAut F G) (toAut_bijective F G)
+
+lemma toAut_isHomeomorph : IsHomeomorph (toAut F G) := by
+ rw [isHomeomorph_iff_continuous_bijective]
+ exact ⟨toAut_continuous F G, toAut_bijective F G⟩
+
+lemma toAutMulEquiv_isHomeomorph : IsHomeomorph (toAutMulEquiv F G) :=
+ toAut_isHomeomorph F G
+
+/-- If `G` is a fundamental group for `F`, it is canonically homeomorphic to `Aut F`. -/
+noncomputable def toAutHomeo : G ≃ₜ Aut F := (toAut_isHomeomorph F G).homeomorph
+
+variable {G}
+
+@[simp]
+lemma toAutMulEquiv_apply (g : G) : toAutMulEquiv F G g = toAut F G g := rfl
+
+@[simp]
+lemma toAutHomeo_apply (g : G) : toAutHomeo F G g = toAut F G g := rfl
+
+end
+
+end PreGaloisCategory
+
+end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Galois/Prorepresentability.lean b/Mathlib/CategoryTheory/Galois/Prorepresentability.lean
index ad4a6eb3b3032..fba4b027d12de 100644
--- a/Mathlib/CategoryTheory/Galois/Prorepresentability.lean
+++ b/Mathlib/CategoryTheory/Galois/Prorepresentability.lean
@@ -6,7 +6,6 @@ Authors: Christian Merten
import Mathlib.Algebra.Category.Grp.Limits
import Mathlib.CategoryTheory.CofilteredSystem
import Mathlib.CategoryTheory.Galois.Decomposition
-import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic
import Mathlib.CategoryTheory.Limits.IndYoneda
import Mathlib.CategoryTheory.Limits.Preserves.Ulift
@@ -34,6 +33,20 @@ groups of all Galois objects.
- `FiberFunctor.isPretransitive_of_isConnected`: The `Aut F` action on the fiber of a connected
object is transitive.
+## Implementation details
+
+The pro-representability statement and the isomorphism of `Aut F` with the limit over the
+automorphism groups of all Galois objects naturally forces `F` to take values in `FintypeCat.{u₂}`
+where `u₂` is the `Hom`-universe of `C`. Since this is used to show that `Aut F` acts
+transitively on `F.obj X` for connected `X`, we a priori only obtain this result for
+the mentioned specialized universe setup. To obtain the result for `F` taking values in an arbitrary
+`FintypeCat.{w}`, we postcompose with an equivalence `FintypeCat.{w} ≌ FintypeCat.{u₂}` and apply
+the specialized result.
+
+In the following the section `Specialized` is reserved for the setup where `F` takes values in
+`FintypeCat.{u₂}` and the section `General` contains results holding for `F` taking values in
+an arbitrary `FintypeCat.{w}`.
+
## References
* [lenstraGSchemes]: H. W. Lenstra. Galois theory for schemes.
@@ -49,9 +62,9 @@ namespace PreGaloisCategory
open Limits Functor
variable {C : Type u₁} [Category.{u₂} C] [GaloisCategory C]
-variable (F : C ⥤ FintypeCat.{u₂})
+
/-- A pointed Galois object is a Galois object with a fixed point of its fiber. -/
-structure PointedGaloisObject : Type (max u₁ u₂) where
+structure PointedGaloisObject (F : C ⥤ FintypeCat.{w}) : Type (max u₁ u₂ w) where
/-- The underlying object of `C`. -/
obj : C
/-- An element of the fiber of `obj`. -/
@@ -61,6 +74,10 @@ structure PointedGaloisObject : Type (max u₁ u₂) where
namespace PointedGaloisObject
+section General
+
+variable (F : C ⥤ FintypeCat.{w})
+
attribute [instance] isGalois
instance (X : PointedGaloisObject F) : CoeDep (PointedGaloisObject F) X C where
@@ -117,6 +134,12 @@ lemma incl_obj (A : PointedGaloisObject F) : (incl F).obj A = A :=
lemma incl_map {A B : PointedGaloisObject F} (f : A ⟶ B) : (incl F).map f = f.val :=
rfl
+end General
+
+section Specialized
+
+variable (F : C ⥤ FintypeCat.{u₂})
+
/-- `F ⋙ FintypeCat.incl` as a cocone over `(can F).op ⋙ coyoneda`.
This is a colimit cocone (see `PreGaloisCategory.isColimìt`) -/
def cocone : Cocone ((incl F).op ⋙ coyoneda) where
@@ -172,10 +195,16 @@ noncomputable def isColimit : IsColimit (cocone F) := by
instance : HasColimit ((incl F).op ⋙ coyoneda) where
exists_colimit := ⟨cocone F, isColimit F⟩
+end Specialized
+
end PointedGaloisObject
open PointedGaloisObject
+section Specialized
+
+variable (F : C ⥤ FintypeCat.{u₂})
+
/-- The diagram sending each pointed Galois object to its automorphism group
as an object of `C`. -/
@[simps]
@@ -344,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. -/
@@ -365,7 +394,7 @@ noncomputable def autMulEquivAutGalois : Aut F ≃* (AutGalois F)ᵐᵒᵖ where
right_inv t := by
simp only [MonoidHom.coe_comp, MonoidHom.coe_coe, Function.comp_apply, Aut.toEnd_apply]
exact (MulEquiv.eq_symm_apply (endMulEquivAutGalois F)).mp rfl
- map_mul' := by simp
+ map_mul' := by simp [map_mul]
lemma autMulEquivAutGalois_π (f : Aut F) (A : C) [IsGalois A] (a : F.obj A) :
F.map (AutGalois.π F { obj := A, pt := a } (autMulEquivAutGalois F f).unop).hom a =
@@ -393,8 +422,9 @@ theorem FiberFunctor.isPretransitive_of_isGalois (X : C) [IsGalois X] :
use (autMulEquivAutGalois F).symm ⟨a⟩
simpa [mulAction_def, ha]
-/-- The `Aut F` action on the fiber of a connected object is transitive. -/
-instance FiberFunctor.isPretransitive_of_isConnected (X : C) [IsConnected X] :
+/-- The `Aut F` action on the fiber of a connected object is transitive. For a version
+with less restrictive universe assumptions, see `FiberFunctor.isPretransitive_of_isConnected`. -/
+private instance FiberFunctor.isPretransitive_of_isConnected' (X : C) [IsConnected X] :
MulAction.IsPretransitive (Aut F) (F.obj X) := by
obtain ⟨A, f, hgal⟩ := exists_hom_from_galois_of_connected F X
have hs : Function.Surjective (F.map f) := surjective_of_nonempty_fiber_of_isConnected F f
@@ -408,6 +438,39 @@ instance FiberFunctor.isPretransitive_of_isConnected (X : C) [IsConnected X] :
show (F.map f ≫ σ.hom.app X) a = F.map f b
rw [σ.hom.naturality, FintypeCat.comp_apply, hσ]
+end Specialized
+
+section General
+
+variable (F : C ⥤ FintypeCat.{w}) [FiberFunctor F]
+
+/-- The `Aut F` action on the fiber of a connected object is transitive. -/
+instance FiberFunctor.isPretransitive_of_isConnected (X : C) [IsConnected X] :
+ MulAction.IsPretransitive (Aut F) (F.obj X) where
+ exists_smul_eq x y := by
+ let F' : C ⥤ FintypeCat.{u₂} := F ⋙ FintypeCat.uSwitch.{w, u₂}
+ letI : FiberFunctor F' := FiberFunctor.compRight _
+ let e (Y : C) : F'.obj Y ≃ F.obj Y := (F.obj Y).uSwitchEquiv
+ set x' : F'.obj X := (e X).symm x with hx'
+ set y' : F'.obj X := (e X).symm y with hy'
+ obtain ⟨g', (hg' : g'.hom.app X x' = y')⟩ := MulAction.exists_smul_eq (Aut F') x' y'
+ let gapp (Y : C) : F.obj Y ≅ F.obj Y := FintypeCat.equivEquivIso <|
+ (e Y).symm.trans <| (FintypeCat.equivEquivIso.symm (g'.app Y)).trans (e Y)
+ let g : F ≅ F := NatIso.ofComponents gapp <| fun {X Y} f ↦ by
+ ext x
+ simp only [FintypeCat.comp_apply, FintypeCat.equivEquivIso_apply_hom,
+ Equiv.trans_apply, FintypeCat.equivEquivIso_symm_apply_apply, Iso.app_hom, gapp, e]
+ erw [FintypeCat.uSwitchEquiv_naturality (F.map f)]
+ rw [← Functor.comp_map, ← FunctorToFintypeCat.naturality]
+ simp only [comp_obj, Functor.comp_map, F']
+ rw [FintypeCat.uSwitchEquiv_symm_naturality (F.map f)]
+ refine ⟨g, show (gapp X).hom x = y from ?_⟩
+ simp only [FintypeCat.equivEquivIso_apply_hom, Equiv.trans_apply,
+ FintypeCat.equivEquivIso_symm_apply_apply, Iso.app_hom, gapp]
+ rw [← hx', hg', hy', Equiv.apply_symm_apply]
+
+end General
+
end PreGaloisCategory
end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Galois/Topology.lean b/Mathlib/CategoryTheory/Galois/Topology.lean
new file mode 100644
index 0000000000000..c6d5daaba842b
--- /dev/null
+++ b/Mathlib/CategoryTheory/Galois/Topology.lean
@@ -0,0 +1,185 @@
+/-
+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.Galois.Prorepresentability
+import Mathlib.Topology.Algebra.Group.Basic
+
+/-!
+
+# Topology of fundamental group
+
+In this file we define a natural topology on the automorphism group of a functor
+`F : C ⥤ FintypeCat`: It is defined as the subspace topology induced by the natural
+embedding of `Aut F` into `∀ X, Aut (F.obj X)` where
+`Aut (F.obj X)` carries the discrete topology.
+
+## References
+
+- Stacks Project: Tag 0BMQ
+
+-/
+universe u₁ u₂ v₁ v₂ v w
+
+namespace CategoryTheory
+
+namespace PreGaloisCategory
+
+open Functor
+
+variable {C : Type u₁} [Category.{u₂} C] (F : C ⥤ FintypeCat.{w})
+
+/-- For a functor `F : C ⥤ FintypeCat`, the canonical embedding of `Aut F` into
+the product over `Aut (F.obj X)` for all objects `X`. -/
+def autEmbedding : Aut F →* ∀ X, Aut (F.obj X) :=
+ MonoidHom.mk' (fun σ X ↦ σ.app X) (fun _ _ ↦ rfl)
+
+@[simp]
+lemma autEmbedding_apply (σ : Aut F) (X : C) : autEmbedding F σ X = σ.app X :=
+ rfl
+
+lemma autEmbedding_injective : Function.Injective (autEmbedding F) := by
+ intro σ τ h
+ ext X x
+ have : σ.app X = τ.app X := congr_fun h X
+ rw [← Iso.app_hom, ← Iso.app_hom, this]
+
+/-- We put the discrete topology on `F.obj X`. -/
+scoped instance (X : C) : TopologicalSpace (F.obj X) := ⊥
+
+@[scoped instance]
+lemma obj_discreteTopology (X : C) : DiscreteTopology (F.obj X) := ⟨rfl⟩
+
+/-- We put the discrete topology on `Aut (F.obj X)`. -/
+scoped instance (X : C) : TopologicalSpace (Aut (F.obj X)) := ⊥
+
+@[scoped instance]
+lemma aut_discreteTopology (X : C) : DiscreteTopology (Aut (F.obj X)) := ⟨rfl⟩
+
+/-- `Aut F` is equipped with the by the embedding into `∀ X, Aut (F.obj X)` induced embedding. -/
+instance : TopologicalSpace (Aut F) :=
+ TopologicalSpace.induced (autEmbedding F) inferInstance
+
+/-- The image of `Aut F` in `∀ X, Aut (F.obj X)` are precisely the compatible families of
+automorphisms. -/
+lemma autEmbedding_range :
+ Set.range (autEmbedding F) =
+ ⋂ (f : Arrow C), { a | F.map f.hom ≫ (a f.right).hom = (a f.left).hom ≫ F.map f.hom } := by
+ 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 a (fun {X Y} f ↦ h ⟨X, Y, f⟩)
+ rfl
+
+/-- The image of `Aut F` in `∀ X, Aut (F.obj X)` is closed. -/
+lemma autEmbedding_range_isClosed : IsClosed (Set.range (autEmbedding F)) := by
+ rw [autEmbedding_range]
+ refine isClosed_iInter (fun f ↦ isClosed_eq (X := F.obj f.left → F.obj f.right) ?_ ?_)
+ · fun_prop
+ · fun_prop
+
+lemma autEmbedding_isClosedEmbedding : IsClosedEmbedding (autEmbedding F) where
+ eq_induced := rfl
+ inj := autEmbedding_injective F
+ isClosed_range := autEmbedding_range_isClosed 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) :=
+ (autEmbedding_isClosedEmbedding F).isEmbedding.isTotallyDisconnected_range.mp
+ (isTotallyDisconnected_of_totallyDisconnectedSpace _)
+
+instance : ContinuousMul (Aut F) :=
+ (autEmbedding_isClosedEmbedding F).isInducing.continuousMul (autEmbedding F)
+
+instance : ContinuousInv (Aut F) :=
+ (autEmbedding_isClosedEmbedding F).isInducing.continuousInv fun _ ↦ rfl
+
+instance : TopologicalGroup (Aut F) := ⟨⟩
+
+instance (X : C) : SMul (Aut (F.obj X)) (F.obj X) := ⟨fun σ a => σ.hom a⟩
+
+instance (X : C) : ContinuousSMul (Aut (F.obj X)) (F.obj X) := by
+ constructor
+ fun_prop
+
+instance continuousSMul_aut_fiber (X : C) : ContinuousSMul (Aut F) (F.obj X) where
+ continuous_smul := by
+ let g : Aut (F.obj X) × F.obj X → F.obj X := fun ⟨σ, x⟩ ↦ σ.hom x
+ let h (q : Aut F × F.obj X) : Aut (F.obj X) × F.obj X :=
+ ⟨((fun p ↦ p X) ∘ autEmbedding F) q.1, q.2⟩
+ show Continuous (g ∘ h)
+ fun_prop
+
+variable [GaloisCategory C] [FiberFunctor F]
+
+/--
+If `H` is an open subset of `Aut F` such that `1 ∈ H`, there exists a finite
+set `I` of connected objects of `C` such that every `σ : Aut F` that induces the identity
+on `F.obj X` for all `X ∈ I` is contained in `H`. In other words: The kernel
+of the evaluation map `Aut F →* ∏ X : I ↦ Aut (F.obj X)` is contained in `H`.
+-/
+lemma exists_set_ker_evaluation_subset_of_isOpen
+ {H : Set (Aut F)} (h1 : 1 ∈ H) (h : IsOpen H) :
+ ∃ (I : Set C) (_ : Fintype I), (∀ X ∈ I, IsConnected X) ∧
+ (∀ σ : Aut F, (∀ X : I, σ.hom.app X = 𝟙 (F.obj X)) → σ ∈ H) := by
+ obtain ⟨U, hUopen, rfl⟩ := isOpen_induced_iff.mp h
+ obtain ⟨I, u, ho, ha⟩ := isOpen_pi_iff.mp hUopen 1 h1
+ choose fι ff fc h4 h5 h6 using (fun X : I => has_decomp_connected_components X.val)
+ refine ⟨⋃ X, Set.range (ff X), Fintype.ofFinite _, ?_, ?_⟩
+ · rintro X ⟨A, ⟨Y, rfl⟩, hA2⟩
+ obtain ⟨i, rfl⟩ := hA2
+ exact h5 Y i
+ · refine fun σ h ↦ ha (fun X XinI ↦ ?_)
+ suffices h : autEmbedding F σ X = 1 by
+ rw [h]
+ exact (ho X XinI).right
+ have h : σ.hom.app X = 𝟙 (F.obj X) := by
+ have : Fintype (fι ⟨X, XinI⟩) := Fintype.ofFinite _
+ ext x
+ obtain ⟨⟨j⟩, a, ha : F.map _ a = x⟩ := Limits.FintypeCat.jointly_surjective
+ (Discrete.functor (ff ⟨X, XinI⟩) ⋙ F) _ (Limits.isColimitOfPreserves F (h4 ⟨X, XinI⟩)) x
+ rw [FintypeCat.id_apply, ← ha, FunctorToFintypeCat.naturality]
+ simp [h ⟨(ff _) j, ⟨Set.range (ff ⟨X, XinI⟩), ⟨⟨_, rfl⟩, ⟨j, rfl⟩⟩⟩⟩]
+ exact Iso.ext h
+
+open Limits
+
+/-- The stabilizers of points in the fibers of Galois objects form a neighbourhood basis
+of the identity in `Aut F`. -/
+lemma nhds_one_has_basis_stabilizers : (nhds (1 : Aut F)).HasBasis (fun _ ↦ True)
+ (fun X : PointedGaloisObject F ↦ MulAction.stabilizer (Aut F) X.pt) where
+ mem_iff' S := by
+ rw [mem_nhds_iff]
+ refine ⟨?_, ?_⟩
+ · intro ⟨U, hU, hUopen, hUone⟩
+ obtain ⟨I, _, hc, hmem⟩ := exists_set_ker_evaluation_subset_of_isOpen F hUone hUopen
+ let P : C := ∏ᶜ fun X : I ↦ X.val
+ obtain ⟨A, a, hgal, hbij⟩ := exists_galois_representative F P
+ refine ⟨⟨A, a, hgal⟩, trivial, ?_⟩
+ intro t (ht : t.hom.app A a = a)
+ apply hU
+ apply hmem
+ haveI (X : I) : IsConnected X.val := hc X.val X.property
+ haveI (X : I) : Nonempty (F.obj X.val) := nonempty_fiber_of_isConnected F X
+ intro X
+ ext x
+ simp only [FintypeCat.id_apply]
+ obtain ⟨z, rfl⟩ :=
+ surjective_of_nonempty_fiber_of_isConnected F (Pi.π (fun X : I ↦ X.val) X) x
+ obtain ⟨f, rfl⟩ := hbij.surjective z
+ rw [FunctorToFintypeCat.naturality, FunctorToFintypeCat.naturality, ht]
+ · intro ⟨X, _, h⟩
+ exact ⟨MulAction.stabilizer (Aut F) X.pt, h, stabilizer_isOpen (Aut F) X.pt,
+ Subgroup.one_mem _⟩
+
+end PreGaloisCategory
+
+end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Generator.lean b/Mathlib/CategoryTheory/Generator.lean
index f4689ea78b469..91d5fd9417252 100644
--- a/Mathlib/CategoryTheory/Generator.lean
+++ b/Mathlib/CategoryTheory/Generator.lean
@@ -3,14 +3,10 @@ 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.Balanced
import Mathlib.CategoryTheory.Limits.EssentiallySmall
import Mathlib.CategoryTheory.Limits.Opposites
-import Mathlib.CategoryTheory.Limits.Shapes.ZeroMorphisms
import Mathlib.CategoryTheory.Subobject.Lattice
-import Mathlib.CategoryTheory.Subobject.WellPowered
import Mathlib.Data.Set.Opposite
-import Mathlib.Data.Set.Subsingleton
/-!
# Separating and detecting sets
@@ -399,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 :=
@@ -411,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 :=
@@ -423,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 :=
@@ -435,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 :=
@@ -513,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 fcee74c33d22f..b5344653826c9 100644
--- a/Mathlib/CategoryTheory/GradedObject.lean
+++ b/Mathlib/CategoryTheory/GradedObject.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Joël Riou
+Authors: Kim Morrison, Joël Riou
-/
import Mathlib.Algebra.Group.Int
import Mathlib.CategoryTheory.ConcreteCategory.Basic
@@ -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/Monoidal.lean b/Mathlib/CategoryTheory/GradedObject/Monoidal.lean
index 917484d456465..b005a034c6b49 100644
--- a/Mathlib/CategoryTheory/GradedObject/Monoidal.lean
+++ b/Mathlib/CategoryTheory/GradedObject/Monoidal.lean
@@ -325,7 +325,7 @@ lemma left_tensor_tensorObj₃_ext {j : I} {A : C} (Z : C)
(_ ◁ ιTensorObj₃ X₁ X₂ X₃ i₁ i₂ i₃ j h) ≫ f =
(_ ◁ ιTensorObj₃ X₁ X₂ X₃ i₁ i₂ i₃ j h) ≫ g) : f = g := by
refine (@isColimitOfPreserves C _ C _ _ _ _ ((curriedTensor C).obj Z) _
- (isColimitCofan₃MapBifunctorBifunctor₂₃MapObj (H := H) j) hZ).hom_ext ?_
+ (isColimitCofan₃MapBifunctorBifunctor₂₃MapObj (H := H) (j := j)) hZ).hom_ext ?_
intro ⟨⟨i₁, i₂, i₃⟩, hi⟩
exact h _ _ _ hi
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 60f2b56671b81..a6af93f1d5667 100644
--- a/Mathlib/CategoryTheory/Grothendieck.lean
+++ b/Mathlib/CategoryTheory/Grothendieck.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Sina Hazratpour
+Authors: Kim Morrison, Sina Hazratpour
-/
import Mathlib.CategoryTheory.Category.Cat
import Mathlib.CategoryTheory.Elements
@@ -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 7bf9c52f3bc73..a880d7c21b5a3 100644
--- a/Mathlib/CategoryTheory/Groupoid.lean
+++ b/Mathlib/CategoryTheory/Groupoid.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Reid Barton. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Scott Morrison, David Wärn
+Authors: Reid Barton, Kim Morrison, David Wärn
-/
import Mathlib.CategoryTheory.FullSubcategory
import Mathlib.CategoryTheory.Products.Basic
@@ -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 eb29d47f63cd5..7b6b62d4ce4c8 100644
--- a/Mathlib/CategoryTheory/Groupoid/FreeGroupoid.lean
+++ b/Mathlib/CategoryTheory/Groupoid/FreeGroupoid.lean
@@ -3,13 +3,8 @@ 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
-/
-import Mathlib.CategoryTheory.Category.Basic
-import Mathlib.CategoryTheory.Functor.Basic
import Mathlib.CategoryTheory.Groupoid
-import Mathlib.Tactic.NthRewrite
-import Mathlib.CategoryTheory.PathCategory
-import Mathlib.CategoryTheory.Quotient
-import Mathlib.Combinatorics.Quiver.Symmetric
+import Mathlib.CategoryTheory.PathCategory.Basic
/-!
# Free groupoid on a quiver
@@ -137,7 +132,7 @@ theorem of_eq :
section UniversalProperty
-variable {V' : Type u'} [Groupoid V'] (φ : V ⥤q V')
+variable {V' : Type u'} [Groupoid V']
/-- The lift of a prefunctor to a groupoid, to a functor from `FreeGroupoid V` -/
def lift (φ : V ⥤q V') : FreeGroupoid V ⥤ V' :=
diff --git a/Mathlib/CategoryTheory/Groupoid/Subgroupoid.lean b/Mathlib/CategoryTheory/Groupoid/Subgroupoid.lean
index 808563792a9e3..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γ⟩
@@ -540,8 +540,7 @@ theorem isTotallyDisconnected_iff :
S.IsTotallyDisconnected ↔ ∀ c d, (S.arrows c d).Nonempty → c = d := by
constructor
· rintro h c d ⟨f, fS⟩
- have := h ⟨c, mem_objs_of_src S fS⟩ ⟨d, mem_objs_of_tgt S fS⟩ ⟨f, fS⟩
- exact congr_arg Subtype.val this
+ exact congr_arg Subtype.val <| h ⟨c, mem_objs_of_src S fS⟩ ⟨d, mem_objs_of_tgt S fS⟩ ⟨f, fS⟩
· rintro h ⟨c, hc⟩ ⟨d, hd⟩ ⟨f, fS⟩
simp only [Subtype.mk_eq_mk]
exact h c d ⟨f, fS⟩
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 5294a89d8becb..6e0dd598bc818 100644
--- a/Mathlib/CategoryTheory/Iso.lean
+++ b/Mathlib/CategoryTheory/Iso.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Tim Baumann, Stephen Morgan, Scott Morrison, Floris van Doorn
+Authors: Tim Baumann, Stephen Morgan, Kim Morrison, Floris van Doorn
-/
import Mathlib.Tactic.CategoryTheory.Reassoc
@@ -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
@@ -355,7 +353,7 @@ theorem inv_id : inv (𝟙 X) = 𝟙 X := by
apply inv_eq_of_hom_inv_id
simp
-@[simp]
+@[simp, reassoc]
theorem inv_comp [IsIso f] [IsIso h] : inv (f ≫ h) = inv h ≫ inv f := by
apply inv_eq_of_hom_inv_id
simp
@@ -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/LiftingProperties/Basic.lean b/Mathlib/CategoryTheory/LiftingProperties/Basic.lean
index 034992348ba84..6b3ab2bd33ac2 100644
--- a/Mathlib/CategoryTheory/LiftingProperties/Basic.lean
+++ b/Mathlib/CategoryTheory/LiftingProperties/Basic.lean
@@ -41,7 +41,7 @@ class HasLiftingProperty : Prop where
sq_hasLift : ∀ {f : A ⟶ X} {g : B ⟶ Y} (sq : CommSq f i p g), sq.HasLift
instance (priority := 100) sq_hasLift_of_hasLiftingProperty {f : A ⟶ X} {g : B ⟶ Y}
- (sq : CommSq f i p g) [hip : HasLiftingProperty i p] : sq.HasLift := by apply hip.sq_hasLift
+ (sq : CommSq f i p g) [hip : HasLiftingProperty i p] : sq.HasLift := hip.sq_hasLift _
namespace HasLiftingProperty
diff --git a/Mathlib/CategoryTheory/Limits/ColimitLimit.lean b/Mathlib/CategoryTheory/Limits/ColimitLimit.lean
index 2628945db2029..23386c1aed4c1 100644
--- a/Mathlib/CategoryTheory/Limits/ColimitLimit.lean
+++ b/Mathlib/CategoryTheory/Limits/ColimitLimit.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Types
import Mathlib.CategoryTheory.Functor.Currying
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/ConcreteCategory/Basic.lean b/Mathlib/CategoryTheory/Limits/ConcreteCategory/Basic.lean
index 18cd6a039d479..2ecb02a4b57c2 100644
--- a/Mathlib/CategoryTheory/Limits/ConcreteCategory/Basic.lean
+++ b/Mathlib/CategoryTheory/Limits/ConcreteCategory/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Adam Topaz
+Authors: Kim Morrison, Adam Topaz
-/
import Mathlib.CategoryTheory.ConcreteCategory.Basic
import Mathlib.CategoryTheory.Limits.Preserves.Basic
@@ -27,7 +27,7 @@ section Limits
is corepresentable, then `(G ⋙ forget C).sections` is small. -/
lemma small_sections_of_hasLimit
{C : Type u} [Category.{v} C] [ConcreteCategory.{v} C]
- [(forget C).Corepresentable] {J : Type w} [Category.{t} J] (G : J ⥤ C) [HasLimit G] :
+ [(forget C).IsCorepresentable] {J : Type w} [Category.{t} J] (G : J ⥤ C) [HasLimit G] :
Small.{v} (G ⋙ forget C).sections := by
rw [← Types.hasLimit_iff_small_sections]
infer_instance
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 84e7ebc84d72c..6fee46c53e64c 100644
--- a/Mathlib/CategoryTheory/Limits/Cones.lean
+++ b/Mathlib/CategoryTheory/Limits/Cones.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison, Floris van Doorn
+Authors: Stephen Morgan, Kim Morrison, Floris van Doorn
-/
import Mathlib.CategoryTheory.Functor.Const
import Mathlib.CategoryTheory.DiscreteCategory
@@ -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 109be53d93b7b..e7e1a5ed68f8b 100644
--- a/Mathlib/CategoryTheory/Limits/Constructions/Filtered.lean
+++ b/Mathlib/CategoryTheory/Limits/Constructions/Filtered.lean
@@ -32,10 +32,12 @@ namespace CategoryTheory.Limits
namespace CoproductsFromFiniteFiltered
+variable [HasFiniteCoproducts C]
+
/-- If `C` has finite coproducts, a functor `Discrete α ⥤ C` lifts to a functor
`Finset (Discrete α) ⥤ C` by taking coproducts. -/
@[simps!]
-def liftToFinset [HasFiniteCoproducts C] (F : Discrete α ⥤ C) : Finset (Discrete α) ⥤ C where
+def liftToFinsetObj (F : Discrete α ⥤ C) : Finset (Discrete α) ⥤ C where
obj s := ∐ fun x : s => F.obj x
map {_ Y} h := Sigma.desc fun y =>
Sigma.ι (fun (x : { x // x ∈ Y }) => F.obj x) ⟨y, h.down.down y.2⟩
@@ -44,30 +46,39 @@ def liftToFinset [HasFiniteCoproducts C] (F : Discrete α ⥤ C) : Finset (Discr
taking the colimit of the diagram formed by the coproducts of finite sets over the indexing
type. -/
@[simps!]
-def liftToFinsetColimitCocone [HasFiniteCoproducts C] [HasFilteredColimitsOfSize.{w, w} C]
- (F : Discrete α ⥤ C) : ColimitCocone F where
+def liftToFinsetColimitCocone [HasFilteredColimitsOfSize.{w, w} C] (F : Discrete α ⥤ C) :
+ ColimitCocone F where
cocone :=
- { pt := colimit (liftToFinset F)
+ { pt := colimit (liftToFinsetObj F)
ι :=
Discrete.natTrans fun j =>
@Sigma.ι _ _ _ (fun x : ({j} : Finset (Discrete α)) => F.obj x) _ ⟨j, by simp⟩ ≫
- colimit.ι (liftToFinset F) {j} }
+ colimit.ι (liftToFinsetObj F) {j} }
isColimit :=
{ desc := fun s =>
- colimit.desc (liftToFinset F)
+ 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
- dsimp [liftToFinset]
+ dsimp [liftToFinsetObj]
apply colimit.hom_ext
rintro ⟨⟨j, hj⟩⟩
convert h j using 1
- · simp [← colimit.w (liftToFinset F) ⟨⟨Finset.singleton_subset_iff.2 hj⟩⟩]
+ · simp [← colimit.w (liftToFinsetObj F) ⟨⟨Finset.singleton_subset_iff.2 hj⟩⟩]
rfl
· aesop_cat }
+variable (C) (α)
+
+/-- The functor taking a functor `Discrete α ⥤ C` to a functor `Finset (Discrete α) ⥤ C` by taking
+coproducts. -/
+@[simps!]
+def liftToFinset : (Discrete α ⥤ C) ⥤ (Finset (Discrete α) ⥤ C) where
+ obj := liftToFinsetObj
+ map := fun β => { app := fun _ => Sigma.map (fun x => β.app x.val) }
+
end CoproductsFromFiniteFiltered
open CoproductsFromFiniteFiltered
@@ -91,4 +102,46 @@ theorem has_limits_of_finite_and_cofiltered [HasFiniteLimits C]
have : HasProducts.{w} C := hasProducts_of_finite_and_cofiltered
has_limits_of_hasEqualizers_and_products
+namespace CoproductsFromFiniteFiltered
+
+section
+
+variable [HasFiniteCoproducts C] [HasFilteredColimitsOfSize.{w, w} C]
+
+attribute [local instance] hasCoproducts_of_finite_and_filtered
+
+/-- Helper construction for `liftToFinsetColimIso`. -/
+@[reassoc]
+theorem liftToFinsetColimIso_aux (F : Discrete α ⥤ C) {J : Finset (Discrete α)} (j : J) :
+ Sigma.ι (F.obj ·.val) j ≫ colimit.ι (liftToFinsetObj F) J ≫
+ (colimit.isoColimitCocone (liftToFinsetColimitCocone F)).inv
+ = colimit.ι F j := by
+ simp [colimit.isoColimitCocone, IsColimit.coconePointUniqueUpToIso]
+
+/-- The `liftToFinset` functor, precomposed with forming a colimit, is a coproduct on the original
+functor. -/
+def liftToFinsetColimIso : liftToFinset C α ⋙ colim ≅ colim :=
+ NatIso.ofComponents
+ (fun F => Iso.symm <| colimit.isoColimitCocone (liftToFinsetColimitCocone F))
+ (fun β => by
+ simp only [Functor.comp_obj, colim_obj, Functor.comp_map, colim_map, Iso.symm_hom]
+ ext J
+ simp only [liftToFinset_obj_obj, liftToFinset_map_app]
+ ext j
+ simp only [liftToFinset, ι_colimMap_assoc, liftToFinsetObj_obj, Discrete.functor_obj_eq_as,
+ 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 824a394d211e9..bd52c4c1ea3b7 100644
--- a/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean
+++ b/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean
@@ -1,18 +1,15 @@
/-
Copyright (c) 2020 Bhavik Mehta. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Bhavik Mehta, Scott Morrison
+Authors: Bhavik Mehta, Kim Morrison
-/
+import Mathlib.CategoryTheory.Limits.Constructions.BinaryProducts
+import Mathlib.CategoryTheory.Limits.Constructions.Equalizers
+import Mathlib.CategoryTheory.Limits.Constructions.FiniteProductsOfBinaryProducts
+import Mathlib.CategoryTheory.Limits.Preserves.Finite
+import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Equalizers
import Mathlib.Data.Fintype.Prod
import Mathlib.Data.Fintype.Sigma
-import Mathlib.CategoryTheory.Limits.Shapes.Equalizers
-import Mathlib.CategoryTheory.Limits.Shapes.FiniteProducts
-import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Products
-import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Equalizers
-import Mathlib.CategoryTheory.Limits.Preserves.Finite
-import Mathlib.CategoryTheory.Limits.Constructions.FiniteProductsOfBinaryProducts
-import Mathlib.CategoryTheory.Limits.Constructions.Equalizers
-import Mathlib.CategoryTheory.Limits.Constructions.BinaryProducts
/-!
# Constructing limits from products and equalizers.
@@ -58,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] }
@@ -267,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/Constructions/ZeroObjects.lean b/Mathlib/CategoryTheory/Limits/Constructions/ZeroObjects.lean
index c67246dbd4d34..d978a5c54dda2 100644
--- a/Mathlib/CategoryTheory/Limits/Constructions/ZeroObjects.lean
+++ b/Mathlib/CategoryTheory/Limits/Constructions/ZeroObjects.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Shapes.ZeroMorphisms
import Mathlib.CategoryTheory.Limits.Constructions.BinaryProducts
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/Filtered.lean b/Mathlib/CategoryTheory/Limits/Filtered.lean
index 9917f097ee9bf..be5e2d3faf47f 100644
--- a/Mathlib/CategoryTheory/Limits/Filtered.lean
+++ b/Mathlib/CategoryTheory/Limits/Filtered.lean
@@ -77,6 +77,12 @@ class HasFilteredColimitsOfSize : Prop where
/-- For all filtered types of a size `w`, we have colimits -/
HasColimitsOfShape : ∀ (I : Type w) [Category.{w'} I] [IsFiltered I], HasColimitsOfShape I C
+/-- Class for having cofiltered limits. -/
+abbrev HasCofilteredLimits := HasCofilteredLimitsOfSize.{v, v} C
+
+/-- Class for having filtered colimits. -/
+abbrev HasFilteredColimits := HasFilteredColimitsOfSize.{v, v} C
+
end
instance (priority := 100) hasLimitsOfShape_of_has_cofiltered_limits
diff --git a/Mathlib/CategoryTheory/Limits/FilteredColimitCommutesFiniteLimit.lean b/Mathlib/CategoryTheory/Limits/FilteredColimitCommutesFiniteLimit.lean
index 4d3665564222e..70ea3b65e93a5 100644
--- a/Mathlib/CategoryTheory/Limits/FilteredColimitCommutesFiniteLimit.lean
+++ b/Mathlib/CategoryTheory/Limits/FilteredColimitCommutesFiniteLimit.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.ColimitLimit
import Mathlib.CategoryTheory.Limits.Preserves.FunctorCategory
@@ -112,7 +112,7 @@ theorem colimitLimitToLimitColimit_injective :
Finset.mem_union.mpr
(Or.inl
(by
- simp only [true_and_iff, Finset.mem_univ, eq_self_iff_true, exists_prop_of_true,
+ simp only [true_and, Finset.mem_univ, eq_self_iff_true, exists_prop_of_true,
Finset.mem_image, heq_iff_eq]
refine ⟨j, ?_⟩
simp only [heq_iff_eq] ))
@@ -122,7 +122,7 @@ theorem colimitLimitToLimitColimit_injective :
Finset.mem_union.mpr
(Or.inr
(by
- simp only [true_and_iff, Finset.mem_univ, eq_self_iff_true, exists_prop_of_true,
+ simp only [true_and, Finset.mem_univ, eq_self_iff_true, exists_prop_of_true,
Finset.mem_image, heq_iff_eq]
refine ⟨j, ?_⟩
simp only [heq_iff_eq]))
diff --git a/Mathlib/CategoryTheory/Limits/Final.lean b/Mathlib/CategoryTheory/Limits/Final.lean
index 96c97533ba899..2cd80eb36a4f4 100644
--- a/Mathlib/CategoryTheory/Limits/Final.lean
+++ b/Mathlib/CategoryTheory/Limits/Final.lean
@@ -1,15 +1,16 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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
@@ -813,4 +825,70 @@ theorem IsCofiltered.of_initial (F : C ⥤ D) [Initial F] [IsCofiltered C] : IsC
end Filtered
+section
+
+variable {C : Type u₁} [Category.{v₁} C]
+variable {D : Type u₂} [Category.{v₂} D]
+variable {E : Type u₃} [Category.{v₃} E]
+
+open Functor
+
+/-- The functor `StructuredArrow.pre X T S` is final if `T` is final. -/
+instance StructuredArrow.final_pre (T : C ⥤ D) [Final T] (S : D ⥤ E) (X : E) :
+ Final (pre X T S) := by
+ refine ⟨fun f => ?_⟩
+ rw [isConnected_iff_of_equivalence (StructuredArrow.preEquivalence T f)]
+ exact Final.out f.right
+
+/-- The functor `CostructuredArrow.pre X T S` is initial if `T` is initial. -/
+instance CostructuredArrow.initial_pre (T : C ⥤ D) [Initial T] (S : D ⥤ E) (X : E) :
+ Initial (CostructuredArrow.pre T S X) := by
+ refine ⟨fun f => ?_⟩
+ rw [isConnected_iff_of_equivalence (CostructuredArrow.preEquivalence T f)]
+ exact Initial.out f.left
+
+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 34a080b4ccb92..d856af586c75e 100644
--- a/Mathlib/CategoryTheory/Limits/FintypeCat.lean
+++ b/Mathlib/CategoryTheory/Limits/FintypeCat.lean
@@ -4,11 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Christian Merten
-/
import Mathlib.CategoryTheory.FintypeCat
-import Mathlib.CategoryTheory.Limits.Shapes.FiniteLimits
-import Mathlib.CategoryTheory.Limits.Types
-import Mathlib.CategoryTheory.Limits.Creates
import Mathlib.CategoryTheory.Limits.Preserves.Finite
-import Mathlib.Data.Finite.Basic
+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
@@ -60,6 +60,34 @@ noncomputable instance inclusionPreservesFiniteLimits :
noncomputable instance : PreservesFiniteLimits (forget FintypeCat) :=
FintypeCat.inclusionPreservesFiniteLimits
+/-- The categorical product of a finite family in `FintypeCat` is equivalent to the product
+as types. -/
+noncomputable def productEquiv {ι : Type*} [Finite ι] (X : ι → FintypeCat.{u}) :
+ (∏ᶜ X : FintypeCat) ≃ ∀ i, X i :=
+ letI : Fintype ι := Fintype.ofFinite _
+ haveI : Small.{u} ι :=
+ ⟨ULift (Fin (Fintype.card ι)), ⟨(Fintype.equivFin ι).trans Equiv.ulift.symm⟩⟩
+ let is₁ : FintypeCat.incl.obj (∏ᶜ fun i ↦ X i) ≅ (∏ᶜ fun i ↦ X i : Type u) :=
+ PreservesProduct.iso FintypeCat.incl (fun i ↦ X i)
+ let is₂ : (∏ᶜ fun i ↦ X i : Type u) ≅ Shrink.{u} (∀ i, X i) :=
+ Types.Small.productIso (fun i ↦ X i)
+ let e : (∀ i, X i) ≃ Shrink.{u} (∀ i, X i) := equivShrink _
+ (equivEquivIso.symm is₁).trans ((equivEquivIso.symm is₂).trans e.symm)
+
+@[simp]
+lemma productEquiv_apply {ι : Type*} [Finite ι] (X : ι → FintypeCat.{u})
+ (x : (∏ᶜ X : FintypeCat)) (i : ι) : productEquiv X x i = Pi.π X i x := by
+ simpa [productEquiv] using (elementwise_of% piComparison_comp_π FintypeCat.incl X i) x
+
+@[simp]
+lemma productEquiv_symm_comp_π_apply {ι : Type*} [Finite ι] (X : ι → FintypeCat.{u})
+ (x : ∀ i, X i) (i : ι) : Pi.π X i ((productEquiv X).symm x) = x i := by
+ rw [← productEquiv_apply, Equiv.apply_symm_apply]
+
+instance nonempty_pi_of_nonempty {ι : Type*} [Finite ι] (X : ι → FintypeCat.{u})
+ [∀ i, Nonempty (X i)] : Nonempty (∏ᶜ X : FintypeCat.{u}) :=
+ (Equiv.nonempty_congr <| productEquiv X).mpr inferInstance
+
/-- Any functor from a finite category to Types that only involves finite objects,
has a finite colimit. -/
noncomputable instance finiteColimitOfFiniteDiagram {J : Type} [SmallCategory J] [FinCategory J]
@@ -93,4 +121,10 @@ noncomputable instance inclusionPreservesFiniteColimits :
noncomputable instance : PreservesFiniteColimits (forget FintypeCat) :=
FintypeCat.inclusionPreservesFiniteColimits
+lemma jointly_surjective {J : Type*} [Category J] [FinCategory J]
+ (F : J ⥤ FintypeCat.{u}) (t : Cocone F) (h : IsColimit t) (x : t.pt) :
+ ∃ j y, t.ι.app j y = x :=
+ let hs := isColimitOfPreserves FintypeCat.incl.{u} h
+ Types.jointly_surjective (F ⋙ FintypeCat.incl) hs x
+
end CategoryTheory.Limits.FintypeCat
diff --git a/Mathlib/CategoryTheory/Limits/Fubini.lean b/Mathlib/CategoryTheory/Limits/Fubini.lean
index 3bd7d06ef9472..898d073faa5a4 100644
--- a/Mathlib/CategoryTheory/Limits/Fubini.lean
+++ b/Mathlib/CategoryTheory/Limits/Fubini.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.HasLimits
import Mathlib.CategoryTheory.Products.Basic
diff --git a/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean b/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean
index b212bc76981ba..86b8cb71e4d54 100644
--- a/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean
+++ b/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Functor.Currying
import Mathlib.CategoryTheory.Limits.Preserves.Limits
@@ -146,18 +146,23 @@ def combinedIsColimit (F : J ⥤ K ⥤ C) (c : ∀ k : K, ColimitCocone (F.flip.
noncomputable section
+instance functorCategoryHasLimit (F : J ⥤ K ⥤ C) [∀ k, HasLimit (F.flip.obj k)] : HasLimit F :=
+ HasLimit.mk
+ { cone := combineCones F fun _ => getLimitCone _
+ isLimit := combinedIsLimit _ _ }
+
instance functorCategoryHasLimitsOfShape [HasLimitsOfShape J C] : HasLimitsOfShape J (K ⥤ C) where
- has_limit F :=
- HasLimit.mk
- { cone := combineCones F fun _ => getLimitCone _
- isLimit := combinedIsLimit _ _ }
+ has_limit _ := inferInstance
+
+instance functorCategoryHasColimit (F : J ⥤ K ⥤ C) [∀ k, HasColimit (F.flip.obj k)] :
+ HasColimit F :=
+ HasColimit.mk
+ { cocone := combineCocones F fun _ => getColimitCocone _
+ isColimit := combinedIsColimit _ _ }
instance functorCategoryHasColimitsOfShape [HasColimitsOfShape J C] :
HasColimitsOfShape J (K ⥤ C) where
- has_colimit _ :=
- HasColimit.mk
- { cocone := combineCocones _ fun _ => getColimitCocone _
- isColimit := combinedIsColimit _ _ }
+ has_colimit _ := inferInstance
-- Porting note: previously Lean could see through the binders and infer_instance sufficed
instance functorCategoryHasLimitsOfSize [HasLimitsOfSize.{v₁, u₁} C] :
@@ -169,14 +174,20 @@ instance functorCategoryHasColimitsOfSize [HasColimitsOfSize.{v₁, u₁} C] :
HasColimitsOfSize.{v₁, u₁} (K ⥤ C) where
has_colimits_of_shape := fun _ _ => inferInstance
+instance hasLimitCompEvalution (F : J ⥤ K ⥤ C) (k : K) [HasLimit (F.flip.obj k)] :
+ HasLimit (F ⋙ (evaluation _ _).obj k) :=
+ hasLimitOfIso (F := F.flip.obj k) (Iso.refl _)
+
+instance evaluationPreservesLimit (F : J ⥤ K ⥤ C) [∀ k, HasLimit (F.flip.obj k)] (k : K) :
+ PreservesLimit F ((evaluation K C).obj k) :=
+ -- Porting note: added a let because X was not inferred
+ let X : (k : K) → LimitCone (F.flip.obj k) := fun k => getLimitCone (F.flip.obj k)
+ preservesLimitOfPreservesLimitCone (combinedIsLimit _ X) <|
+ IsLimit.ofIsoLimit (limit.isLimit _) (evaluateCombinedCones F X k).symm
+
instance evaluationPreservesLimitsOfShape [HasLimitsOfShape J C] (k : K) :
PreservesLimitsOfShape J ((evaluation K C).obj k) where
- preservesLimit {F} := by
- -- Porting note: added a let because X was not inferred
- let X : (k : K) → LimitCone (Prefunctor.obj (Functor.flip F).toPrefunctor k) :=
- fun k => getLimitCone (Prefunctor.obj (Functor.flip F).toPrefunctor k)
- exact preservesLimitOfPreservesLimitCone (combinedIsLimit _ _) <|
- IsLimit.ofIsoLimit (limit.isLimit _) (evaluateCombinedCones F X k).symm
+ preservesLimit := inferInstance
/-- If `F : J ⥤ K ⥤ C` is a functor into a functor category which has a limit,
then the evaluation of that limit at `k` is the limit of the evaluations of `F.obj j` at `k`.
@@ -225,14 +236,43 @@ 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 _)
+
+instance evaluationPreservesColimit (F : J ⥤ K ⥤ C) [∀ k, HasColimit (F.flip.obj k)] (k : K) :
+ PreservesColimit F ((evaluation K C).obj k) :=
+ -- Porting note: added a let because X was not inferred
+ let X : (k : K) → ColimitCocone (F.flip.obj k) := fun k => getColimitCocone (F.flip.obj k)
+ preservesColimitOfPreservesColimitCocone (combinedIsColimit _ X) <|
+ IsColimit.ofIsoColimit (colimit.isColimit _) (evaluateCombinedCocones F X k).symm
+
instance evaluationPreservesColimitsOfShape [HasColimitsOfShape J C] (k : K) :
PreservesColimitsOfShape J ((evaluation K C).obj k) where
- preservesColimit {F} := by
- -- Porting note: added a let because X was not inferred
- let X : (k : K) → ColimitCocone (Prefunctor.obj (Functor.flip F).toPrefunctor k) :=
- fun k => getColimitCocone (Prefunctor.obj (Functor.flip F).toPrefunctor k)
- refine preservesColimitOfPreservesColimitCocone (combinedIsColimit _ _) <|
- IsColimit.ofIsoColimit (colimit.isColimit _) (evaluateCombinedCocones F X k).symm
+ preservesColimit := inferInstance
/-- If `F : J ⥤ K ⥤ C` is a functor into a functor category which has a colimit,
then the evaluation of that colimit at `k` is the colimit of the evaluations of `F.obj j` at `k`.
@@ -285,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
@@ -382,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/FunctorToTypes.lean b/Mathlib/CategoryTheory/Limits/FunctorToTypes.lean
index 62eb96c6be392..ba9abc78c25d6 100644
--- a/Mathlib/CategoryTheory/Limits/FunctorToTypes.lean
+++ b/Mathlib/CategoryTheory/Limits/FunctorToTypes.lean
@@ -20,15 +20,20 @@ open CategoryTheory.Limits
universe w v₁ v₂ u₁ u₂
variable {J : Type u₁} [Category.{v₁} J] {K : Type u₂} [Category.{v₂} K]
-variable (F : J ⥤ K ⥤ TypeMax.{u₁, w})
+variable (F : J ⥤ K ⥤ Type w)
-theorem jointly_surjective (k : K) {t : Cocone F} (h : IsColimit t) (x : t.pt.obj k) :
- ∃ j y, x = (t.ι.app j).app k y := by
+theorem jointly_surjective (k : K) {t : Cocone F} (h : IsColimit t) (x : t.pt.obj k)
+ [∀ k, HasColimit (F.flip.obj k)] : ∃ j y, x = (t.ι.app j).app k y := by
let hev := isColimitOfPreserves ((evaluation _ _).obj k) h
obtain ⟨j, y, rfl⟩ := Types.jointly_surjective _ hev x
exact ⟨j, y, by simp⟩
-theorem jointly_surjective' (k : K) (x : (colimit F).obj k) : ∃ j y, x = (colimit.ι F j).app k y :=
+theorem jointly_surjective' [∀ k, HasColimit (F.flip.obj k)] (k : K) (x : (colimit F).obj k) :
+ ∃ j y, x = (colimit.ι F j).app k y :=
jointly_surjective _ _ (colimit.isColimit _) x
+theorem colimit.map_ι_apply [HasColimit F] (j : J) {k k' : K} {f : k ⟶ k'} {x} :
+ (colimit F).map f ((colimit.ι F j).app _ x) = (colimit.ι F j).app _ ((F.obj j).map f x) :=
+ congrFun ((colimit.ι F j).naturality _).symm _
+
end CategoryTheory.FunctorToTypes
diff --git a/Mathlib/CategoryTheory/Limits/HasLimits.lean b/Mathlib/CategoryTheory/Limits/HasLimits.lean
index 866e9a9ee1602..06940a016159d 100644
--- a/Mathlib/CategoryTheory/Limits/HasLimits.lean
+++ b/Mathlib/CategoryTheory/Limits/HasLimits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Mario Carneiro, Scott Morrison, Floris van Doorn
+Authors: Reid Barton, Mario Carneiro, Kim Morrison, Floris van Doorn
-/
import Mathlib.CategoryTheory.Limits.IsLimit
import Mathlib.CategoryTheory.Category.ULift
@@ -490,22 +490,15 @@ def limYoneda :
NatIso.ofComponents fun F => NatIso.ofComponents fun W => limit.homIso F (unop W)
/-- The constant functor and limit functor are adjoint to each other -/
-def constLimAdj : (const J : C ⥤ J ⥤ C) ⊣ lim where
- homEquiv c g :=
+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 _ ⟨_, 𝟙 _⟩ }
- counit := { app := fun g => { app := limit.π _ } }
- -- This used to be automatic before leanprover/lean4#2644
- homEquiv_unit := by
- -- Sad that aesop can no longer do this!
- intros
- dsimp
- ext
- simp
+ unit := { app := fun _ => limit.lift _ ⟨_, 𝟙 _⟩ }
+ counit := { app := fun g => { app := limit.π _ } } }
instance : IsRightAdjoint (lim : (J ⥤ C) ⥤ C) :=
⟨_, ⟨constLimAdj⟩⟩
@@ -546,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 [Adjunction.homEquiv_unit, 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
@@ -1029,15 +1022,15 @@ def colimCoyoneda : colim.op ⋙ coyoneda ⋙ (whiskeringRight _ _ _).obj uliftF
/-- The colimit functor and constant functor are adjoint to each other
-/
-def colimConstAdj : (colim : (J ⥤ C) ⥤ C) ⊣ const J where
- homEquiv f c :=
+def colimConstAdj : (colim : (J ⥤ C) ⥤ C) ⊣ const J := Adjunction.mk' {
+ homEquiv := fun f c ↦
{ toFun := fun g =>
{ app := fun _ => colimit.ι _ _ ≫ g }
invFun := fun g => colimit.desc _ ⟨_, g⟩
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 ff385b709488f..663c41495a819 100644
--- a/Mathlib/CategoryTheory/Limits/IsLimit.lean
+++ b/Mathlib/CategoryTheory/Limits/IsLimit.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Mario Carneiro, Scott Morrison, Floris van Doorn
+Authors: Reid Barton, Mario Carneiro, Kim Morrison, Floris van Doorn
-/
import Mathlib.CategoryTheory.Adjunction.Basic
import Mathlib.CategoryTheory.Limits.Cones
@@ -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 882daf68cd30e..4e07dc534469f 100644
--- a/Mathlib/CategoryTheory/Limits/Lattice.lean
+++ b/Mathlib/CategoryTheory/Limits/Lattice.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Justus Springer
+Authors: Kim Morrison, Justus Springer
-/
import Mathlib.Order.CompleteLattice
import Mathlib.Data.Finset.Lattice
@@ -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 55f267f9bdae5..f53eb0808b891 100644
--- a/Mathlib/CategoryTheory/Limits/Opposites.lean
+++ b/Mathlib/CategoryTheory/Limits/Opposites.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Floris van Doorn
+Authors: Kim Morrison, Floris van Doorn
-/
import Mathlib.CategoryTheory.Limits.Filtered
import Mathlib.CategoryTheory.Limits.Shapes.FiniteProducts
@@ -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/Pi.lean b/Mathlib/CategoryTheory/Limits/Pi.lean
index 605261fd6d113..eb68356542cfc 100644
--- a/Mathlib/CategoryTheory/Limits/Pi.lean
+++ b/Mathlib/CategoryTheory/Limits/Pi.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Pi.Basic
import Mathlib.CategoryTheory.Limits.HasLimits
diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean b/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean
index 803fcd12b6cc8..f5abc3a11449f 100644
--- a/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean
+++ b/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Reid Barton, Bhavik Mehta, Jakob von Raumer
+Authors: Kim Morrison, Reid Barton, Bhavik Mehta, Jakob von Raumer
-/
import Mathlib.CategoryTheory.Limits.HasLimits
@@ -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 1eb21050d5910..d1ad0cedcd3f6 100644
--- a/Mathlib/CategoryTheory/Limits/Preserves/Filtered.lean
+++ b/Mathlib/CategoryTheory/Limits/Preserves/Filtered.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Justus Springer
+Authors: Kim Morrison, Justus Springer
-/
import Mathlib.CategoryTheory.Limits.Preserves.Basic
import Mathlib.CategoryTheory.Filtered.Basic
@@ -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/Finite.lean b/Mathlib/CategoryTheory/Limits/Preserves/Finite.lean
index 87c35359a609f..eea8e1113af03 100644
--- a/Mathlib/CategoryTheory/Limits/Preserves/Finite.lean
+++ b/Mathlib/CategoryTheory/Limits/Preserves/Finite.lean
@@ -27,7 +27,7 @@ open CategoryTheory
namespace CategoryTheory.Limits
-- declare the `v`'s first; see `CategoryTheory.Category` for an explanation
-universe w w₂ v₁ v₂ v₃ u₁ u₂ u₃
+universe u w w₂ v₁ v₂ v₃ u₁ u₂ u₃
variable {C : Type u₁} [Category.{v₁} C]
variable {D : Type u₂} [Category.{v₂} D]
@@ -84,6 +84,11 @@ def compPreservesFiniteLimits (F : C ⥤ D) (G : D ⥤ E) [PreservesFiniteLimits
[PreservesFiniteLimits G] : PreservesFiniteLimits (F ⋙ G) :=
⟨fun _ _ _ => inferInstance⟩
+/-- Transfer preservation of finite limits along a natural isomorphism in the functor. -/
+def preservesFiniteLimitsOfNatIso {F G : C ⥤ D} (h : F ≅ G) [PreservesFiniteLimits F] :
+ PreservesFiniteLimits G where
+ preservesFiniteLimits _ _ _ := preservesLimitsOfShapeOfNatIso h
+
/- Porting note: adding this class because quantified classes don't behave well
[#2764](https://github.com/leanprover-community/mathlib4/pull/2764) -/
/-- A functor `F` preserves finite products if it preserves all from `Discrete J`
@@ -93,6 +98,12 @@ class PreservesFiniteProducts (F : C ⥤ D) where
attribute [instance] PreservesFiniteProducts.preserves
+noncomputable instance (priority := 100) (F : C ⥤ D) (J : Type u) [Finite J]
+ [PreservesFiniteProducts F] : PreservesLimitsOfShape (Discrete J) F := by
+ apply Nonempty.some
+ obtain ⟨n, ⟨e⟩⟩ := Finite.exists_equiv_fin J
+ exact ⟨preservesLimitsOfShapeOfEquiv (Discrete.equivalence e.symm) F⟩
+
instance compPreservesFiniteProducts (F : C ⥤ D) (G : D ⥤ E)
[PreservesFiniteProducts F] [PreservesFiniteProducts G] :
PreservesFiniteProducts (F ⋙ G) where
@@ -225,6 +236,11 @@ def compPreservesFiniteColimits (F : C ⥤ D) (G : D ⥤ E) [PreservesFiniteColi
[PreservesFiniteColimits G] : PreservesFiniteColimits (F ⋙ G) :=
⟨fun _ _ _ => inferInstance⟩
+/-- Transfer preservation of finite colimits along a natural isomorphism in the functor. -/
+def preservesFiniteColimitsOfNatIso {F G : C ⥤ D} (h : F ≅ G) [PreservesFiniteColimits F] :
+ PreservesFiniteColimits G where
+ preservesFiniteColimits _ _ _ := preservesColimitsOfShapeOfNatIso h
+
/- Porting note: adding this class because quantified classes don't behave well
[#2764](https://github.com/leanprover-community/mathlib4/pull/2764) -/
/-- A functor `F` preserves finite products if it preserves all from `Discrete J`
@@ -233,14 +249,15 @@ class PreservesFiniteCoproducts (F : C ⥤ D) where
/-- preservation of colimits indexed by `Discrete J` when `[Fintype J]` -/
preserves : ∀ (J : Type) [Fintype J], PreservesColimitsOfShape (Discrete J) F
-noncomputable instance (F : C ⥤ D) (J : Type*) [Finite J] [PreservesFiniteCoproducts F] :
- PreservesColimitsOfShape (Discrete J) F := by
+attribute [instance] PreservesFiniteCoproducts.preserves
+
+noncomputable instance (priority := 100) (F : C ⥤ D) (J : Type u) [Finite J]
+ [PreservesFiniteCoproducts F] : PreservesColimitsOfShape (Discrete J) F := by
apply Nonempty.some
obtain ⟨n, ⟨e⟩⟩ := Finite.exists_equiv_fin J
- have : PreservesColimitsOfShape (Discrete (Fin n)) F := PreservesFiniteCoproducts.preserves _
exact ⟨preservesColimitsOfShapeOfEquiv (Discrete.equivalence e.symm) F⟩
-noncomputable instance compPreservesFiniteCoproducts (F : C ⥤ D) (G : D ⥤ E)
+instance compPreservesFiniteCoproducts (F : C ⥤ D) (G : D ⥤ E)
[PreservesFiniteCoproducts F] [PreservesFiniteCoproducts G] :
PreservesFiniteCoproducts (F ⋙ G) where
preserves _ _ := inferInstance
@@ -248,7 +265,6 @@ noncomputable instance compPreservesFiniteCoproducts (F : C ⥤ D) (G : D ⥤ E)
noncomputable instance (F : C ⥤ D) [PreservesFiniteColimits F] : PreservesFiniteCoproducts F where
preserves _ _ := inferInstance
-
/--
A functor is said to reflect finite colimits, if it reflects all colimits of shape `J`,
where `J : Type` is a finite category.
diff --git a/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean b/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean
index 4b4cde050f773..23b061baf7be2 100644
--- a/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean
+++ b/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean
@@ -5,6 +5,7 @@ Authors: Bhavik Mehta
-/
import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic
import Mathlib.CategoryTheory.Limits.Preserves.Shapes.BinaryProducts
+import Mathlib.CategoryTheory.Limits.Preserves.Finite
import Mathlib.CategoryTheory.Limits.Yoneda
import Mathlib.CategoryTheory.Limits.Presheaf
@@ -28,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
@@ -36,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]
@@ -70,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]
@@ -104,4 +117,16 @@ noncomputable def preservesLimitOfLanPreservesLimit {C D : Type u} [SmallCategor
apply @preservesLimitsOfShapeOfReflectsOfPreserves _ _ _ _ _ _ _ _ F yoneda ?_
exact preservesLimitsOfShapeOfNatIso (Presheaf.compYonedaIsoYonedaCompLan F).symm
+/-- `F : C ⥤ D ⥤ E` preserves finite limits if it does for each `d : D`. -/
+def preservesFiniteLimitsOfEvaluation {D : Type*} [Category D] {E : Type*} [Category E]
+ (F : C ⥤ D ⥤ E) (h : ∀ d : D, PreservesFiniteLimits (F ⋙ (evaluation D E).obj d)) :
+ PreservesFiniteLimits F :=
+ ⟨fun J _ _ => preservesLimitsOfShapeOfEvaluation F J fun k => (h k).preservesFiniteLimits _⟩
+
+/-- `F : C ⥤ D ⥤ E` preserves finite limits if it does for each `d : D`. -/
+def preservesFiniteColimitsOfEvaluation {D : Type*} [Category D] {E : Type*} [Category E]
+ (F : C ⥤ D ⥤ E) (h : ∀ d : D, PreservesFiniteColimits (F ⋙ (evaluation D E).obj d)) :
+ PreservesFiniteColimits F :=
+ ⟨fun J _ _ => preservesColimitsOfShapeOfEvaluation F J fun k => (h k).preservesFiniteColimits _⟩
+
end CategoryTheory
diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Limits.lean b/Mathlib/CategoryTheory/Limits/Preserves/Limits.lean
index ad85619badaad..ac77b2c0bcd51 100644
--- a/Mathlib/CategoryTheory/Limits/Preserves/Limits.lean
+++ b/Mathlib/CategoryTheory/Limits/Preserves/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Limits.Preserves.Basic
@@ -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/BinaryProducts.lean b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/BinaryProducts.lean
index a0006f3d434ff..b72dd4a247aae 100644
--- a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/BinaryProducts.lean
+++ b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/BinaryProducts.lean
@@ -88,13 +88,13 @@ def PreservesLimitPair.iso : G.obj (X ⨯ Y) ≅ G.obj X ⨯ G.obj Y :=
theorem PreservesLimitPair.iso_hom : (PreservesLimitPair.iso G X Y).hom = prodComparison G X Y :=
rfl
-@[simp]
+@[simp, reassoc]
theorem PreservesLimitPair.iso_inv_fst :
(PreservesLimitPair.iso G X Y).inv ≫ G.map prod.fst = prod.fst := by
rw [← Iso.cancel_iso_hom_left (PreservesLimitPair.iso G X Y), ← Category.assoc, Iso.hom_inv_id]
simp
-@[simp]
+@[simp, reassoc]
theorem PreservesLimitPair.iso_inv_snd :
(PreservesLimitPair.iso G X Y).inv ≫ G.map prod.snd = prod.snd := by
rw [← Iso.cancel_iso_hom_left (PreservesLimitPair.iso G X Y), ← Category.assoc, Iso.hom_inv_id]
diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean
index 9a602e80dbec1..b6333a08c0d86 100644
--- a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean
+++ b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Shapes.Kernels
import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Zero
diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Products.lean b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Products.lean
index 4d54f0f91c9b6..9d1105f497bd6 100644
--- a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Products.lean
+++ b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Products.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison, Bhavik Mehta. All rights reserved.
+Copyright (c) 2020 Kim Morrison, Bhavik Mehta. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Limits.Shapes.Products
import Mathlib.CategoryTheory.Limits.Preserves.Basic
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 659bf465adea6..ca7b9175b9037 100644
--- a/Mathlib/CategoryTheory/Limits/Presheaf.lean
+++ b/Mathlib/CategoryTheory/Limits/Presheaf.lean
@@ -3,15 +3,11 @@ 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.ConeCategory
import Mathlib.CategoryTheory.Limits.Final
-import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic
import Mathlib.CategoryTheory.Limits.Over
-import Mathlib.CategoryTheory.Limits.Shapes.Terminal
-import Mathlib.CategoryTheory.Limits.Types
/-!
# Colimit of representables
@@ -78,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)) ⟶
@@ -206,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] }
@@ -564,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 160d8386ff9bc..3cf40588ccb09 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/BinaryProducts.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/BinaryProducts.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Comma.Over
import Mathlib.CategoryTheory.DiscreteCategory
@@ -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 a079c16da2b22..89b2d0b933bb6 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Jakob von Raumer
+Authors: Kim Morrison, Jakob von Raumer
-/
import Mathlib.CategoryTheory.Limits.Shapes.FiniteProducts
import Mathlib.CategoryTheory.Limits.Shapes.BinaryProducts
@@ -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
@@ -403,6 +401,14 @@ instance (priority := 100) hasFiniteCoproducts_of_hasFiniteBiproducts [HasFinite
HasFiniteCoproducts C where
out _ := ⟨fun _ => hasColimitOfIso Discrete.natIsoFunctor⟩
+instance (priority := 100) hasProductsOfShape_of_hasBiproductsOfShape [HasBiproductsOfShape J C] :
+ HasProductsOfShape J C where
+ has_limit _ := hasLimitOfIso Discrete.natIsoFunctor.symm
+
+instance (priority := 100) hasCoproductsOfShape_of_hasBiproductsOfShape [HasBiproductsOfShape J C] :
+ HasCoproductsOfShape J C where
+ has_colimit _ := hasColimitOfIso Discrete.natIsoFunctor
+
variable {C}
/-- The isomorphism between the specified limit and the specified colimit for
@@ -547,6 +553,17 @@ theorem biproduct.isoCoproduct_hom {f : J → C} [HasBiproduct f] :
(biproduct.isoCoproduct f).hom = biproduct.desc (Sigma.ι f) :=
biproduct.hom_ext' _ _ fun j => by simp [← Iso.eq_comp_inv]
+/-- If a category has biproducts of a shape `J`, its `colim` and `lim` functor on diagrams over `J`
+are isomorphic. -/
+@[simps!]
+def HasBiproductsOfShape.colimIsoLim [HasBiproductsOfShape J C] :
+ colim (J := Discrete J) (C := C) ≅ lim :=
+ NatIso.ofComponents (fun F => (Sigma.isoColimit F).symm ≪≫
+ (biproduct.isoCoproduct _).symm ≪≫ biproduct.isoProduct _ ≪≫ Pi.isoLimit F)
+ fun η => colimit.hom_ext fun ⟨i⟩ => limit.hom_ext fun ⟨j⟩ => by
+ by_cases h : i = j <;>
+ simp_all [h, Sigma.isoColimit, Pi.isoLimit, biproduct.ι_π, biproduct.ι_π_assoc]
+
theorem biproduct.map_eq_map' {f g : J → C} [HasBiproduct f] [HasBiproduct g] (p : ∀ b, f b ⟶ g b) :
biproduct.map p = biproduct.map' p := by
ext
@@ -737,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
@@ -840,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
@@ -879,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
@@ -1009,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] )
@@ -1023,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
@@ -1099,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 d1f39b75f730a..d16936f661fa4 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/ConcreteCategory.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/ConcreteCategory.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2023 Joël Riou. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Joël Riou, Scott Morrison, Adam Topaz
+Authors: Joël Riou, Kim Morrison, Adam Topaz
-/
import Mathlib.CategoryTheory.Limits.Preserves.Shapes.BinaryProducts
import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Products
@@ -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 499e8ff5ad36b..36a0a6e065433 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Markus Himmel
+Authors: Kim Morrison, Markus Himmel
-/
import Mathlib.CategoryTheory.EpiMono
import Mathlib.CategoryTheory.Limits.HasLimits
@@ -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 9cb33fc51bcc3..14a8a0a386b6a 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/FiniteLimits.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/FiniteLimits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.FinCategory.AsType
import Mathlib.CategoryTheory.Limits.Shapes.BinaryProducts
@@ -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/FiniteProducts.lean b/Mathlib/CategoryTheory/Limits/Shapes/FiniteProducts.lean
index a8fc25c47121c..76f92fb28042f 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/FiniteProducts.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/FiniteProducts.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Shapes.FiniteLimits
import Mathlib.CategoryTheory.Limits.Shapes.Products
diff --git a/Mathlib/CategoryTheory/Limits/Shapes/FunctorCategory.lean b/Mathlib/CategoryTheory/Limits/Shapes/FunctorCategory.lean
index 113f2c55cc2c3..0303e8d18d601 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/FunctorCategory.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/FunctorCategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Shapes.FiniteLimits
import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic
diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Images.lean b/Mathlib/CategoryTheory/Limits/Shapes/Images.lean
index 79301f40a8edc..fec3f30cad1ff 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Images.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Images.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Markus Himmel
+Authors: Kim Morrison, Markus Himmel
-/
import Mathlib.CategoryTheory.Limits.Shapes.Equalizers
import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Mono
@@ -81,8 +81,6 @@ attribute [reassoc (attr := simp)] MonoFactorisation.fac
attribute [instance] MonoFactorisation.m_mono
-attribute [instance] MonoFactorisation.m_mono
-
namespace MonoFactorisation
/-- The obvious factorisation of a monomorphism through itself. -/
@@ -758,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
@@ -832,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 ec4bee1404520..f03cd551569a5 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Markus Himmel
+Authors: Kim Morrison, Markus Himmel
-/
import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Zero
@@ -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/Basic.lean b/Mathlib/CategoryTheory/Limits/Shapes/NormalMono/Basic.lean
index 93dfec509e2d4..e16617bd21fec 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/NormalMono/Basic.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/NormalMono/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Limits.Shapes.RegularMono
import Mathlib.CategoryTheory.Limits.Shapes.Kernels
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 a614b5d85405d..fd6ac675d5b40 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Products.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Products.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Limits.HasLimits
import Mathlib.CategoryTheory.DiscreteCategory
@@ -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)
@@ -481,6 +487,50 @@ from a family of isomorphisms between the factors.
abbrev Sigma.mapIso {f g : β → C} [HasCoproductsOfShape β C] (p : ∀ b, f b ≅ g b) : ∐ f ≅ ∐ g :=
colim.mapIso (Discrete.natIso fun X => p X.as)
+section
+
+/- In this section, we provide some API for coproducts when we are given a functor
+`Discrete α ⥤ C` instead of a map `α → C`. -/
+
+variable (X : Discrete α ⥤ C) [HasCoproduct (fun j => X.obj (Discrete.mk j))]
+
+/-- A colimit cocone for `X : Discrete α ⥤ C` that is given
+by `∐ (fun j => X.obj (Discrete.mk j))`. -/
+@[simps]
+def Sigma.cocone : Cocone X where
+ pt := ∐ (fun j => X.obj (Discrete.mk j))
+ ι := Discrete.natTrans (fun _ => Sigma.ι (fun j ↦ X.obj ⟨j⟩) _)
+
+/-- The cocone `Sigma.cocone X` is a colimit cocone. -/
+def coproductIsCoproduct' :
+ IsColimit (Sigma.cocone X) where
+ desc s := Sigma.desc (fun j => s.ι.app ⟨j⟩)
+ fac s := by simp
+ uniq s m hm := by
+ dsimp
+ ext
+ simp only [colimit.ι_desc, Cofan.mk_pt, Cofan.mk_ι_app]
+ apply hm
+
+variable [HasColimit X]
+
+/-- The isomorphism `∐ (fun j => X.obj (Discrete.mk j)) ≅ colimit X`. -/
+def Sigma.isoColimit :
+ ∐ (fun j => X.obj (Discrete.mk j)) ≅ colimit X :=
+ IsColimit.coconePointUniqueUpToIso (coproductIsCoproduct' X) (colimit.isColimit X)
+
+@[reassoc (attr := simp)]
+lemma Sigma.ι_isoColimit_hom (j : α) :
+ Sigma.ι _ j ≫ (Sigma.isoColimit X).hom = colimit.ι _ (Discrete.mk j) :=
+ IsColimit.comp_coconePointUniqueUpToIso_hom (coproductIsCoproduct' X) _ _
+
+@[reassoc (attr := simp)]
+lemma Sigma.ι_isoColimit_inv (j : α) :
+ colimit.ι _ ⟨j⟩ ≫ (Sigma.isoColimit X).inv = Sigma.ι (fun j ↦ X.obj ⟨j⟩) _ :=
+ IsColimit.comp_coconePointUniqueUpToIso_inv _ _ _
+
+end
+
/-- Two products which differ by an equivalence in the indexing type,
and up to isomorphism in the factors, are isomorphic.
-/
@@ -617,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
@@ -638,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
@@ -666,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 b6008f36b9768..795528a7feb85 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Assoc.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Assoc.lean
@@ -1,5 +1,5 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andrew Yang
-/
@@ -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 665866bf2883a..ff8b0b942c59c 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/CommSq.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/CommSq.lean
@@ -1,14 +1,11 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Joël Riou, Calle Sönne
+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. -/
@@ -280,22 +284,22 @@ noncomputable def isoIsPullback (h : IsPullback fst snd f g) (h' : IsPullback fs
@[reassoc (attr := simp)]
theorem isoIsPullback_hom_fst (h : IsPullback fst snd f g) (h' : IsPullback fst' snd' f g) :
- (h.isoIsPullback h').hom ≫ fst' = fst :=
+ (h.isoIsPullback _ _ h').hom ≫ fst' = fst :=
IsLimit.conePointUniqueUpToIso_hom_comp h.isLimit h'.isLimit WalkingCospan.left
@[reassoc (attr := simp)]
theorem isoIsPullback_hom_snd (h : IsPullback fst snd f g) (h' : IsPullback fst' snd' f g) :
- (h.isoIsPullback h').hom ≫ snd' = snd :=
+ (h.isoIsPullback _ _ h').hom ≫ snd' = snd :=
IsLimit.conePointUniqueUpToIso_hom_comp h.isLimit h'.isLimit WalkingCospan.right
@[reassoc (attr := simp)]
theorem isoIsPullback_inv_fst (h : IsPullback fst snd f g) (h' : IsPullback fst' snd' f g) :
- (h.isoIsPullback h').inv ≫ fst = fst' := by
+ (h.isoIsPullback _ _ h').inv ≫ fst = fst' := by
simp only [Iso.inv_comp_eq, isoIsPullback_hom_fst]
@[reassoc (attr := simp)]
theorem isoIsPullback_inv_snd (h : IsPullback fst snd f g) (h' : IsPullback fst' snd' f g) :
- (h.isoIsPullback h').inv ≫ snd = snd' := by
+ (h.isoIsPullback _ _ h').inv ≫ snd = snd' := by
simp only [Iso.inv_comp_eq, isoIsPullback_hom_snd]
end
@@ -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) :=
@@ -468,22 +491,22 @@ noncomputable def isoIsPushout (h : IsPushout f g inl inr) (h' : IsPushout f g i
@[reassoc (attr := simp)]
theorem inl_isoIsPushout_hom (h : IsPushout f g inl inr) (h' : IsPushout f g inl' inr') :
- inl ≫ (h.isoIsPushout h').hom = inl' :=
+ inl ≫ (h.isoIsPushout _ _ h').hom = inl' :=
IsColimit.comp_coconePointUniqueUpToIso_hom h.isColimit h'.isColimit WalkingSpan.left
@[reassoc (attr := simp)]
theorem inr_isoIsPushout_hom (h : IsPushout f g inl inr) (h' : IsPushout f g inl' inr') :
- inr ≫ (h.isoIsPushout h').hom = inr' :=
+ inr ≫ (h.isoIsPushout _ _ h').hom = inr' :=
IsColimit.comp_coconePointUniqueUpToIso_hom h.isColimit h'.isColimit WalkingSpan.right
@[reassoc (attr := simp)]
theorem inl_isoIsPushout_inv (h : IsPushout f g inl inr) (h' : IsPushout f g inl' inr') :
- inl' ≫ (h.isoIsPushout h').inv = inl := by
+ inl' ≫ (h.isoIsPushout _ _ h').inv = inl := by
simp only [Iso.comp_inv_eq, inl_isoIsPushout_hom]
@[reassoc (attr := simp)]
theorem inr_isoIsPushout_inv (h : IsPushout f g inl inr) (h' : IsPushout f g inl' inr') :
- inr' ≫ (h.isoIsPushout h').inv = inr := by
+ inr' ≫ (h.isoIsPushout _ _ h').inv = inr := by
simp only [Iso.comp_inv_eq, inr_isoIsPushout_hom]
end
@@ -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/Cospan.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Cospan.lean
index dbd52eb783c0c..03f0894ee74ee 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Cospan.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Cospan.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Markus Himmel, Bhavik Mehta
+Authors: Kim Morrison, Markus Himmel, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Limits.Shapes.WidePullbacks
import Mathlib.CategoryTheory.Limits.Shapes.BinaryProducts
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 d832ed2573d16..7a97bde56f6a0 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/HasPullback.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/HasPullback.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Markus Himmel, Bhavik Mehta, Andrew Yang, Emily Riehl, Calle Sönne
+Authors: Kim Morrison, Markus Himmel, Bhavik Mehta, Andrew Yang, Emily Riehl, Calle Sönne
-/
import Mathlib.CategoryTheory.Limits.Shapes.Pullback.PullbackCone
@@ -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 0aec735dd25af..e55cb3b880356 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Iso.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Iso.lean
@@ -1,5 +1,5 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andrew Yang
-/
@@ -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 87a404f00fcb9..5b6bfbf8ab8b4 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Mono.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Mono.lean
@@ -1,5 +1,5 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Bhavik Mehta, Andrew Yang
-/
@@ -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/Pullback/Pasting.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Pasting.lean
index ddf8657ecc188..6790398f308af 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Pasting.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Pasting.lean
@@ -1,5 +1,5 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andrew Yang, Calle Sönne
-/
diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean
index 5c57de436f965..0c26846165918 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Markus Himmel, Bhavik Mehta, Andrew Yang, Emily Riehl, Calle Sönne
+Authors: Kim Morrison, Markus Himmel, Bhavik Mehta, Andrew Yang, Emily Riehl, Calle Sönne
-/
import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Cospan
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/RegularMono.lean b/Mathlib/CategoryTheory/Limits/Shapes/RegularMono.lean
index 36ef641c0374a..c568df46e30c4 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/RegularMono.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/RegularMono.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Limits.Shapes.Pullback.HasPullback
import Mathlib.CategoryTheory.Limits.Shapes.StrongEpi
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 c9f8914c57de7..d24c05e73cd2c 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Terminal.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Terminal.lean
@@ -1,12 +1,10 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+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 7718d1bc251fd..f0c5334a88559 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/Types.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/Types.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Types
import Mathlib.CategoryTheory.Limits.Shapes.Products
@@ -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 6aa46f0c5a128..baf5c502afa9e 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/ZeroMorphisms.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/ZeroMorphisms.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Pi.Basic
import Mathlib.CategoryTheory.Limits.Shapes.Products
@@ -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/Shapes/ZeroObjects.lean b/Mathlib/CategoryTheory/Limits/Shapes/ZeroObjects.lean
index d6dd788599bbf..54f3a9e56b996 100644
--- a/Mathlib/CategoryTheory/Limits/Shapes/ZeroObjects.lean
+++ b/Mathlib/CategoryTheory/Limits/Shapes/ZeroObjects.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johan Commelin
+Authors: Kim Morrison, Johan Commelin
-/
import Mathlib.CategoryTheory.Limits.Shapes.Terminal
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 a5e6378568b97..e278c77547635 100644
--- a/Mathlib/CategoryTheory/Limits/Types.lean
+++ b/Mathlib/CategoryTheory/Limits/Types.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Reid Barton
+Authors: Kim Morrison, Reid Barton
-/
import Mathlib.Data.TypeMax
import Mathlib.Logic.UnivLE
@@ -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/TypesFiltered.lean b/Mathlib/CategoryTheory/Limits/TypesFiltered.lean
index 3a9fd3a30e941..05dec6451b29c 100644
--- a/Mathlib/CategoryTheory/Limits/TypesFiltered.lean
+++ b/Mathlib/CategoryTheory/Limits/TypesFiltered.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Reid Barton
+Authors: Kim Morrison, Reid Barton
-/
import Mathlib.CategoryTheory.Limits.Types
import Mathlib.CategoryTheory.Filtered.Basic
diff --git a/Mathlib/CategoryTheory/Limits/Unit.lean b/Mathlib/CategoryTheory/Limits/Unit.lean
index 7b572e4455d15..21e52a45493b7 100644
--- a/Mathlib/CategoryTheory/Limits/Unit.lean
+++ b/Mathlib/CategoryTheory/Limits/Unit.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.PUnit
import Mathlib.CategoryTheory.Limits.HasLimits
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 8f2956bb7a8ef..ed9f8ff3d339e 100644
--- a/Mathlib/CategoryTheory/Limits/Yoneda.lean
+++ b/Mathlib/CategoryTheory/Limits/Yoneda.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic
import Mathlib.CategoryTheory.Limits.Types
@@ -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
@@ -193,7 +193,7 @@ namespace Functor
section Representable
-variable (F : Cᵒᵖ ⥤ Type v) [F.Representable] {J : Type*} [Category J]
+variable (F : Cᵒᵖ ⥤ Type v) [F.IsRepresentable] {J : Type*} [Category J]
noncomputable instance representablePreservesLimit (G : J ⥤ Cᵒᵖ) :
PreservesLimit G F :=
@@ -210,7 +210,7 @@ end Representable
section Corepresentable
-variable (F : C ⥤ Type v) [F.Corepresentable] {J : Type*} [Category J]
+variable (F : C ⥤ Type v) [F.IsCorepresentable] {J : Type*} [Category J]
noncomputable instance corepresentablePreservesLimit (G : J ⥤ C) :
PreservesLimit G F :=
diff --git a/Mathlib/CategoryTheory/Linear/Basic.lean b/Mathlib/CategoryTheory/Linear/Basic.lean
index 0a45ae4d24a02..b4d90d75d19a2 100644
--- a/Mathlib/CategoryTheory/Linear/Basic.lean
+++ b/Mathlib/CategoryTheory/Linear/Basic.lean
@@ -1,9 +1,10 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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 ed03809f158c5..2796d5a4a8b9b 100644
--- a/Mathlib/CategoryTheory/Linear/FunctorCategory.lean
+++ b/Mathlib/CategoryTheory/Linear/FunctorCategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Preadditive.FunctorCategory
import Mathlib.CategoryTheory.Linear.Basic
@@ -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/LinearFunctor.lean b/Mathlib/CategoryTheory/Linear/LinearFunctor.lean
index c2ef88551f038..0e58e65be5bae 100644
--- a/Mathlib/CategoryTheory/Linear/LinearFunctor.lean
+++ b/Mathlib/CategoryTheory/Linear/LinearFunctor.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Preadditive.AdditiveFunctor
import Mathlib.CategoryTheory.Linear.Basic
diff --git a/Mathlib/CategoryTheory/Linear/Yoneda.lean b/Mathlib/CategoryTheory/Linear/Yoneda.lean
index 7022906c6dc3a..ee468da7d7708 100644
--- a/Mathlib/CategoryTheory/Linear/Yoneda.lean
+++ b/Mathlib/CategoryTheory/Linear/Yoneda.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.ModuleCat.Basic
import Mathlib.CategoryTheory.Linear.Basic
@@ -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 fa27fe0d27eff..7c5e8d990bb5a 100644
--- a/Mathlib/CategoryTheory/Monad/Adjunction.lean
+++ b/Mathlib/CategoryTheory/Monad/Adjunction.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Adjunction.Reflective
import Mathlib.CategoryTheory.Monad.Algebra
@@ -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/Algebra.lean b/Mathlib/CategoryTheory/Monad/Algebra.lean
index 7997a3d8c91e9..3c17e5635d306 100644
--- a/Mathlib/CategoryTheory/Monad/Algebra.lean
+++ b/Mathlib/CategoryTheory/Monad/Algebra.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Monad.Basic
import Mathlib.CategoryTheory.Adjunction.Basic
diff --git a/Mathlib/CategoryTheory/Monad/Basic.lean b/Mathlib/CategoryTheory/Monad/Basic.lean
index d50e030211dde..9fe82e5aa7b80 100644
--- a/Mathlib/CategoryTheory/Monad/Basic.lean
+++ b/Mathlib/CategoryTheory/Monad/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta, Adam Topaz
+Authors: Kim Morrison, Bhavik Mehta, Adam Topaz
-/
import Mathlib.CategoryTheory.Functor.Category
import Mathlib.CategoryTheory.Functor.FullyFaithful
@@ -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 f447048e82490..11d531a830a9b 100644
--- a/Mathlib/CategoryTheory/Monad/Limits.lean
+++ b/Mathlib/CategoryTheory/Monad/Limits.lean
@@ -1,11 +1,11 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta, Jack McKoen
+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 a29f338d9a4d7..6182c9de23c17 100644
--- a/Mathlib/CategoryTheory/Monoidal/Bimod.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Bimod.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Oleksandr Manzyuk
+Authors: Kim Morrison, Oleksandr Manzyuk
-/
import Mathlib.CategoryTheory.Bicategory.Basic
import Mathlib.CategoryTheory.Monoidal.Mon_
@@ -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
@@ -201,13 +200,13 @@ noncomputable def actLeft : R.X ⊗ X P Q ⟶ X P Q :=
simp only [Category.assoc]
slice_lhs 1 2 => rw [associator_inv_naturality_middle]
slice_rhs 3 4 => rw [← comp_whiskerRight, middle_assoc, comp_whiskerRight]
- coherence)
+ monoidal)
(by
dsimp
slice_lhs 1 1 => rw [MonoidalCategory.whiskerLeft_comp]
slice_lhs 2 3 => rw [associator_inv_naturality_right]
slice_lhs 3 4 => rw [whisker_exchange]
- coherence))
+ monoidal))
theorem whiskerLeft_π_actLeft :
(R.X ◁ coequalizer.π _ _) ≫ actLeft P Q =
@@ -224,7 +223,7 @@ theorem one_act_left' : (R.one ▷ _) ≫ actLeft P Q = (λ_ _).hom := by
slice_lhs 1 2 => rw [associator_inv_naturality_left]
slice_lhs 2 3 => rw [← comp_whiskerRight, one_actLeft]
slice_rhs 1 2 => rw [leftUnitor_naturality]
- coherence
+ monoidal
theorem left_assoc' :
(R.mul ▷ _) ≫ actLeft P Q = (α_ R.X R.X _).hom ≫ (R.X ◁ actLeft P Q) ≫ actLeft P Q := by
@@ -240,7 +239,7 @@ theorem left_assoc' :
MonoidalCategory.whiskerLeft_comp, MonoidalCategory.whiskerLeft_comp]
slice_rhs 4 5 => rw [whiskerLeft_π_actLeft]
slice_rhs 3 4 => rw [associator_inv_naturality_middle]
- coherence
+ monoidal
end
@@ -484,7 +483,7 @@ theorem hom_left_act_hom' :
slice_rhs 3 4 => erw [TensorBimod.whiskerLeft_π_actLeft P (Q.tensorBimod L)]
slice_rhs 2 3 => erw [associator_inv_naturality_right]
slice_rhs 3 4 => erw [whisker_exchange]
- coherence
+ monoidal
theorem hom_right_act_hom' :
((P.tensorBimod Q).tensorBimod L).actRight ≫ hom P Q L =
@@ -510,7 +509,7 @@ theorem hom_right_act_hom' :
slice_rhs 3 4 =>
rw [← MonoidalCategory.whiskerLeft_comp, TensorBimod.π_tensor_id_actRight,
MonoidalCategory.whiskerLeft_comp, MonoidalCategory.whiskerLeft_comp]
- coherence
+ monoidal
/-- An auxiliary morphism for the definition of the underlying morphism of the inverse component of
the associator isomorphism. -/
@@ -529,7 +528,7 @@ noncomputable def invAux : P.X ⊗ (Q.tensorBimod L).X ⟶ ((P.tensorBimod Q).te
slice_rhs 1 2 => rw [MonoidalCategory.whiskerLeft_comp]
slice_rhs 2 3 => rw [associator_inv_naturality_right]
slice_rhs 3 4 => rw [whisker_exchange]
- coherence)
+ monoidal)
/-- The underlying morphism of the inverse component of the associator isomorphism. -/
noncomputable def inv :
@@ -550,7 +549,7 @@ noncomputable def inv :
MonoidalCategory.whiskerLeft_comp, MonoidalCategory.whiskerLeft_comp]
slice_rhs 4 6 => rw [id_tensor_π_preserves_coequalizer_inv_desc]
slice_rhs 3 4 => rw [associator_inv_naturality_middle]
- coherence)
+ monoidal)
theorem hom_inv_id : hom P Q L ≫ inv P Q L = 𝟙 _ := by
dsimp [hom, homAux, inv, invAux]
@@ -605,7 +604,7 @@ theorem hom_inv_id : hom P ≫ inv P = 𝟙 _ := by
slice_lhs 2 3 => rw [associator_inv_naturality_left]
slice_lhs 3 4 => rw [← comp_whiskerRight, Mon_.one_mul]
slice_rhs 1 2 => rw [Category.comp_id]
- coherence
+ monoidal
theorem inv_hom_id : inv P ≫ hom P = 𝟙 _ := by
dsimp [hom, inv]
@@ -659,7 +658,7 @@ theorem hom_inv_id : hom P ≫ inv P = 𝟙 _ := by
slice_lhs 2 3 => rw [associator_naturality_right]
slice_lhs 3 4 => rw [← MonoidalCategory.whiskerLeft_comp, Mon_.mul_one]
slice_rhs 1 2 => rw [Category.comp_id]
- coherence
+ monoidal
theorem inv_hom_id : inv P ≫ hom P = 𝟙 _ := by
dsimp [hom, inv]
@@ -764,7 +763,7 @@ theorem id_whiskerLeft_bimod {X Y : Mon_ C} {M N : Bimod X Y} (f : M ⟶ N) :
slice_rhs 3 4 => rw [associator_inv_naturality_left]
slice_rhs 4 5 => rw [← comp_whiskerRight, Mon_.one_mul]
have : (λ_ (X.X ⊗ N.X)).inv ≫ (α_ (𝟙_ C) X.X N.X).inv ≫ ((λ_ X.X).hom ▷ N.X) = 𝟙 _ := by
- coherence
+ monoidal
slice_rhs 2 4 => rw [this]
slice_rhs 1 2 => rw [Category.comp_id]
@@ -926,7 +925,7 @@ theorem pentagon_bimod {V W X Y Z : Mon_ C} (M : Bimod V W) (N : Bimod W X) (P :
rw [← whisker_exchange]
slice_rhs 3 5 => rw [π_tensor_id_preserves_coequalizer_inv_desc]
slice_rhs 2 3 => rw [associator_naturality_right]
- coherence
+ monoidal
theorem triangle_bimod {X Y Z : Mon_ C} (M : Bimod X Y) (N : Bimod Y Z) :
(associatorBimod M (regular Y) N).hom ≫ whiskerLeft M (leftUnitorBimod N).hom =
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 f0ba170eb47a1..ee91313dea7f3 100644
--- a/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean
@@ -1,12 +1,12 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Discrete
import Mathlib.CategoryTheory.Monoidal.NaturalTransformation
import Mathlib.CategoryTheory.Monoidal.Opposite
-import Mathlib.Tactic.CategoryTheory.Coherence
+import Mathlib.Tactic.CategoryTheory.Monoidal.Basic
import Mathlib.CategoryTheory.CommSq
/-!
@@ -153,7 +153,7 @@ theorem yang_baxter' (X Y Z : C) :
𝟙 _ ⊗≫ (X ◁ (β_ Y Z).hom ⊗≫ (β_ X Z).hom ▷ Y ⊗≫ Z ◁ (β_ X Y).hom) ⊗≫ 𝟙 _ := by
rw [← cancel_epi (α_ X Y Z).inv, ← cancel_mono (α_ Z Y X).hom]
convert yang_baxter X Y Z using 1
- all_goals coherence
+ all_goals monoidal
theorem yang_baxter_iso (X Y Z : C) :
(α_ X Y Z).symm ≪≫ whiskerRightIso (β_ X Y) Z ≪≫ α_ Y X Z ≪≫
@@ -256,20 +256,20 @@ I couldn't find a detailed proof in print, but this is discussed in:
"Tensor categories", vol 25, Mathematical Surveys and Monographs (2015), AMS.
-/
-variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory C] [BraidedCategory C]
+variable {C : Type u₁} [Category.{v₁} C] [MonoidalCategory C] [BraidedCategory C]
theorem braiding_leftUnitor_aux₁ (X : C) :
(α_ (𝟙_ C) (𝟙_ C) X).hom ≫
(𝟙_ C ◁ (β_ X (𝟙_ C)).inv) ≫ (α_ _ X _).inv ≫ ((λ_ X).hom ▷ _) =
((λ_ _).hom ▷ X) ≫ (β_ X (𝟙_ C)).inv := by
- coherence
+ monoidal
theorem braiding_leftUnitor_aux₂ (X : C) :
((β_ X (𝟙_ C)).hom ▷ 𝟙_ C) ≫ ((λ_ X).hom ▷ 𝟙_ C) = (ρ_ X).hom ▷ 𝟙_ C :=
calc
((β_ X (𝟙_ C)).hom ▷ 𝟙_ C) ≫ ((λ_ X).hom ▷ 𝟙_ C) =
((β_ X (𝟙_ C)).hom ▷ 𝟙_ C) ≫ (α_ _ _ _).hom ≫ (α_ _ _ _).inv ≫ ((λ_ X).hom ▷ 𝟙_ C) := by
- coherence
+ monoidal
_ = ((β_ X (𝟙_ C)).hom ▷ 𝟙_ C) ≫ (α_ _ _ _).hom ≫ (_ ◁ (β_ X _).hom) ≫
(_ ◁ (β_ X _).inv) ≫ (α_ _ _ _).inv ≫ ((λ_ X).hom ▷ 𝟙_ C) := by
simp
@@ -291,14 +291,14 @@ theorem braiding_rightUnitor_aux₁ (X : C) :
(α_ X (𝟙_ C) (𝟙_ C)).inv ≫
((β_ (𝟙_ C) X).inv ▷ 𝟙_ C) ≫ (α_ _ X _).hom ≫ (_ ◁ (ρ_ X).hom) =
(X ◁ (ρ_ _).hom) ≫ (β_ (𝟙_ C) X).inv := by
- coherence
+ monoidal
theorem braiding_rightUnitor_aux₂ (X : C) :
(𝟙_ C ◁ (β_ (𝟙_ C) X).hom) ≫ (𝟙_ C ◁ (ρ_ X).hom) = 𝟙_ C ◁ (λ_ X).hom :=
calc
(𝟙_ C ◁ (β_ (𝟙_ C) X).hom) ≫ (𝟙_ C ◁ (ρ_ X).hom) =
(𝟙_ C ◁ (β_ (𝟙_ C) X).hom) ≫ (α_ _ _ _).inv ≫ (α_ _ _ _).hom ≫ (𝟙_ C ◁ (ρ_ X).hom) := by
- coherence
+ monoidal
_ = (𝟙_ C ◁ (β_ (𝟙_ C) X).hom) ≫ (α_ _ _ _).inv ≫ ((β_ _ X).hom ▷ _) ≫
((β_ _ X).inv ▷ _) ≫ (α_ _ _ _).hom ≫ (𝟙_ C ◁ (ρ_ X).hom) := by
simp
@@ -324,7 +324,7 @@ theorem braiding_tensorUnit_left (X : C) : (β_ (𝟙_ C) X).hom = (λ_ X).hom
theorem braiding_inv_tensorUnit_left (X : C) : (β_ (𝟙_ C) X).inv = (ρ_ X).hom ≫ (λ_ X).inv := by
rw [Iso.inv_ext]
rw [braiding_tensorUnit_left]
- coherence
+ monoidal
@[reassoc]
theorem leftUnitor_inv_braiding (X : C) : (λ_ X).inv ≫ (β_ (𝟙_ C) X).hom = (ρ_ X).inv := by
@@ -343,7 +343,7 @@ theorem braiding_tensorUnit_right (X : C) : (β_ X (𝟙_ C)).hom = (ρ_ X).hom
theorem braiding_inv_tensorUnit_right (X : C) : (β_ X (𝟙_ C)).inv = (λ_ X).hom ≫ (ρ_ X).inv := by
rw [Iso.inv_ext]
rw [braiding_tensorUnit_right]
- coherence
+ monoidal
end
@@ -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)
@@ -455,8 +454,6 @@ def id : BraidedFunctor C C :=
instance : Inhabited (BraidedFunctor C C) :=
⟨id C⟩
-variable {C D E}
-
/-- The composition of braided monoidal functors. -/
@[simps!]
def comp (F : BraidedFunctor C D) (G : BraidedFunctor D E) : BraidedFunctor C E :=
@@ -465,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)
@@ -504,18 +500,21 @@ end CommMonoid
section Tensor
-/-- The strength of the tensor product functor from `C × C` to `C`. -/
-def tensor_μ (X Y : C × C) : (X.1 ⊗ X.2) ⊗ Y.1 ⊗ Y.2 ⟶ (X.1 ⊗ Y.1) ⊗ X.2 ⊗ Y.2 :=
- (α_ X.1 X.2 (Y.1 ⊗ Y.2)).hom ≫
- (X.1 ◁ (α_ X.2 Y.1 Y.2).inv) ≫
- (X.1 ◁ (β_ X.2 Y.1).hom ▷ Y.2) ≫
- (X.1 ◁ (α_ Y.1 X.2 Y.2).hom) ≫ (α_ X.1 Y.1 (X.2 ⊗ Y.2)).inv
+variable {C}
+
+/-- Swap the second and third objects in `(X₁ ⊗ X₂) ⊗ (Y₁ ⊗ Y₂)`. This is used to strength the
+tensor product functor from `C × C` to `C` as a monoidal functor. -/
+def tensor_μ (X₁ X₂ Y₁ Y₂ : C) : (X₁ ⊗ X₂) ⊗ Y₁ ⊗ Y₂ ⟶ (X₁ ⊗ Y₁) ⊗ X₂ ⊗ Y₂ :=
+ (α_ X₁ X₂ (Y₁ ⊗ Y₂)).hom ≫
+ (X₁ ◁ (α_ X₂ Y₁ Y₂).inv) ≫
+ (X₁ ◁ (β_ X₂ Y₁).hom ▷ Y₂) ≫
+ (X₁ ◁ (α_ Y₁ X₂ Y₂).hom) ≫ (α_ X₁ Y₁ (X₂ ⊗ Y₂)).inv
@[reassoc]
theorem tensor_μ_natural {X₁ X₂ Y₁ Y₂ U₁ U₂ V₁ V₂ : C} (f₁ : X₁ ⟶ Y₁) (f₂ : X₂ ⟶ Y₂) (g₁ : U₁ ⟶ V₁)
(g₂ : U₂ ⟶ V₂) :
- ((f₁ ⊗ f₂) ⊗ g₁ ⊗ g₂) ≫ tensor_μ C (Y₁, Y₂) (V₁, V₂) =
- tensor_μ C (X₁, X₂) (U₁, U₂) ≫ ((f₁ ⊗ g₁) ⊗ f₂ ⊗ g₂) := by
+ ((f₁ ⊗ f₂) ⊗ g₁ ⊗ g₂) ≫ tensor_μ Y₁ Y₂ V₁ V₂ =
+ tensor_μ X₁ X₂ U₁ U₂ ≫ ((f₁ ⊗ g₁) ⊗ f₂ ⊗ g₂) := by
dsimp only [tensor_μ]
simp_rw [← id_tensorHom, ← tensorHom_id]
slice_lhs 1 2 => rw [associator_naturality]
@@ -530,27 +529,27 @@ theorem tensor_μ_natural {X₁ X₂ Y₁ Y₂ U₁ U₂ V₁ V₂ : C} (f₁ :
@[reassoc]
theorem tensor_μ_natural_left {X₁ X₂ Y₁ Y₂ : C} (f₁ : X₁ ⟶ Y₁) (f₂ : X₂ ⟶ Y₂) (Z₁ Z₂ : C) :
- (f₁ ⊗ f₂) ▷ (Z₁ ⊗ Z₂) ≫ tensor_μ C (Y₁, Y₂) (Z₁, Z₂) =
- tensor_μ C (X₁, X₂) (Z₁, Z₂) ≫ (f₁ ▷ Z₁ ⊗ f₂ ▷ Z₂) := by
- convert tensor_μ_natural C f₁ f₂ (𝟙 Z₁) (𝟙 Z₂) using 1 <;> simp
+ (f₁ ⊗ f₂) ▷ (Z₁ ⊗ Z₂) ≫ tensor_μ Y₁ Y₂ Z₁ Z₂ =
+ tensor_μ X₁ X₂ Z₁ Z₂ ≫ (f₁ ▷ Z₁ ⊗ f₂ ▷ Z₂) := by
+ convert tensor_μ_natural f₁ f₂ (𝟙 Z₁) (𝟙 Z₂) using 1 <;> simp
@[reassoc]
theorem tensor_μ_natural_right (Z₁ Z₂ : C) {X₁ X₂ Y₁ Y₂ : C} (f₁ : X₁ ⟶ Y₁) (f₂ : X₂ ⟶ Y₂) :
- (Z₁ ⊗ Z₂) ◁ (f₁ ⊗ f₂) ≫ tensor_μ C (Z₁, Z₂) (Y₁, Y₂) =
- tensor_μ C (Z₁, Z₂) (X₁, X₂) ≫ (Z₁ ◁ f₁ ⊗ Z₂ ◁ f₂) := by
- convert tensor_μ_natural C (𝟙 Z₁) (𝟙 Z₂) f₁ f₂ using 1 <;> simp
+ (Z₁ ⊗ Z₂) ◁ (f₁ ⊗ f₂) ≫ tensor_μ Z₁ Z₂ Y₁ Y₂ =
+ tensor_μ Z₁ Z₂ X₁ X₂ ≫ (Z₁ ◁ f₁ ⊗ Z₂ ◁ f₂) := by
+ convert tensor_μ_natural (𝟙 Z₁) (𝟙 Z₂) f₁ f₂ using 1 <;> simp
@[reassoc]
theorem tensor_left_unitality (X₁ X₂ : C) :
(λ_ (X₁ ⊗ X₂)).hom =
((λ_ (𝟙_ C)).inv ▷ (X₁ ⊗ X₂)) ≫
- tensor_μ C (𝟙_ C, 𝟙_ C) (X₁, X₂) ≫ ((λ_ X₁).hom ⊗ (λ_ X₂).hom) := by
+ tensor_μ (𝟙_ C) (𝟙_ C) X₁ X₂ ≫ ((λ_ X₁).hom ⊗ (λ_ X₂).hom) := by
dsimp only [tensor_μ]
have :
((λ_ (𝟙_ C)).inv ▷ (X₁ ⊗ X₂)) ≫
(α_ (𝟙_ C) (𝟙_ C) (X₁ ⊗ X₂)).hom ≫ (𝟙_ C ◁ (α_ (𝟙_ C) X₁ X₂).inv) =
𝟙_ C ◁ (λ_ X₁).inv ▷ X₂ := by
- coherence
+ monoidal
slice_rhs 1 3 => rw [this]
clear this
slice_rhs 1 2 => rw [← MonoidalCategory.whiskerLeft_comp, ← comp_whiskerRight,
@@ -561,97 +560,92 @@ theorem tensor_left_unitality (X₁ X₂ : C) :
theorem tensor_right_unitality (X₁ X₂ : C) :
(ρ_ (X₁ ⊗ X₂)).hom =
((X₁ ⊗ X₂) ◁ (λ_ (𝟙_ C)).inv) ≫
- tensor_μ C (X₁, X₂) (𝟙_ C, 𝟙_ C) ≫ ((ρ_ X₁).hom ⊗ (ρ_ X₂).hom) := by
+ tensor_μ X₁ X₂ (𝟙_ C) (𝟙_ C) ≫ ((ρ_ X₁).hom ⊗ (ρ_ X₂).hom) := by
dsimp only [tensor_μ]
have :
((X₁ ⊗ X₂) ◁ (λ_ (𝟙_ C)).inv) ≫
(α_ X₁ X₂ (𝟙_ C ⊗ 𝟙_ C)).hom ≫ (X₁ ◁ (α_ X₂ (𝟙_ C) (𝟙_ C)).inv) =
(α_ X₁ X₂ (𝟙_ C)).hom ≫ (X₁ ◁ (ρ_ X₂).inv ▷ 𝟙_ C) := by
- coherence
+ monoidal
slice_rhs 1 3 => rw [this]
clear this
slice_rhs 2 3 => rw [← MonoidalCategory.whiskerLeft_comp, ← comp_whiskerRight,
rightUnitor_inv_braiding]
simp [tensorHom_id, id_tensorHom, tensorHom_def]
+@[reassoc]
theorem tensor_associativity (X₁ X₂ Y₁ Y₂ Z₁ Z₂ : C) :
- (tensor_μ C (X₁, X₂) (Y₁, Y₂) ▷ (Z₁ ⊗ Z₂)) ≫
- tensor_μ C (X₁ ⊗ Y₁, X₂ ⊗ Y₂) (Z₁, Z₂) ≫ ((α_ X₁ Y₁ Z₁).hom ⊗ (α_ X₂ Y₂ Z₂).hom) =
+ (tensor_μ X₁ X₂ Y₁ Y₂ ▷ (Z₁ ⊗ Z₂)) ≫
+ tensor_μ (X₁ ⊗ Y₁) (X₂ ⊗ Y₂) Z₁ Z₂ ≫ ((α_ X₁ Y₁ Z₁).hom ⊗ (α_ X₂ Y₂ Z₂).hom) =
(α_ (X₁ ⊗ X₂) (Y₁ ⊗ Y₂) (Z₁ ⊗ Z₂)).hom ≫
- ((X₁ ⊗ X₂) ◁ tensor_μ C (Y₁, Y₂) (Z₁, Z₂)) ≫ tensor_μ C (X₁, X₂) (Y₁ ⊗ Z₁, Y₂ ⊗ Z₂) := by
+ ((X₁ ⊗ X₂) ◁ tensor_μ Y₁ Y₂ Z₁ Z₂) ≫ tensor_μ X₁ X₂ (Y₁ ⊗ Z₁) (Y₂ ⊗ Z₂) := by
dsimp only [tensor_obj, prodMonoidal_tensorObj, tensor_μ]
- simp only [whiskerRight_tensor, comp_whiskerRight, whisker_assoc, assoc, Iso.inv_hom_id_assoc,
- tensor_whiskerLeft, braiding_tensor_left, MonoidalCategory.whiskerLeft_comp,
- braiding_tensor_right]
+ simp only [braiding_tensor_left, braiding_tensor_right]
calc
_ = 𝟙 _ ⊗≫
X₁ ◁ ((β_ X₂ Y₁).hom ▷ (Y₂ ⊗ Z₁) ≫ (Y₁ ⊗ X₂) ◁ (β_ Y₂ Z₁).hom) ▷ Z₂ ⊗≫
- X₁ ◁ Y₁ ◁ (β_ X₂ Z₁).hom ▷ Y₂ ▷ Z₂ ⊗≫ 𝟙 _ := by coherence
- _ = _ := by rw [← whisker_exchange]; coherence
-
--- We got a timeout if `reassoc` was at the declaration, so we put it here instead.
-attribute [reassoc] tensor_associativity
+ X₁ ◁ Y₁ ◁ (β_ X₂ Z₁).hom ▷ Y₂ ▷ Z₂ ⊗≫ 𝟙 _ := by monoidal
+ _ = _ := by rw [← whisker_exchange]; monoidal
/-- The tensor product functor from `C × C` to `C` as a monoidal functor. -/
@[simps!]
def tensorMonoidal : MonoidalFunctor (C × C) C :=
{ tensor C with
ε := (λ_ (𝟙_ C)).inv
- μ := tensor_μ C
+ μ := fun X Y ↦ tensor_μ X.1 X.2 Y.1 Y.2
μ_natural_left := fun f Z => by
-- `simpa` will be not needed when we define `μ_natural_left` in terms of the whiskerings.
- simpa using tensor_μ_natural_left C f.1 f.2 Z.1 Z.2
+ simpa using tensor_μ_natural_left f.1 f.2 Z.1 Z.2
μ_natural_right := fun Z f => by
- simpa using tensor_μ_natural_right C Z.1 Z.2 f.1 f.2
+ simpa using tensor_μ_natural_right Z.1 Z.2 f.1 f.2
associativity := fun X Y Z => by
- simpa using tensor_associativity C X.1 X.2 Y.1 Y.2 Z.1 Z.2
+ simpa using tensor_associativity X.1 X.2 Y.1 Y.2 Z.1 Z.2
left_unitality := fun ⟨X₁, X₂⟩ => by
- simpa using tensor_left_unitality C X₁ X₂
+ simpa using tensor_left_unitality X₁ X₂
right_unitality := fun ⟨X₁, X₂⟩ => by
- simpa using tensor_right_unitality C X₁ X₂
+ simpa using tensor_right_unitality X₁ X₂
μ_isIso := by dsimp [tensor_μ]; infer_instance }
@[reassoc]
theorem leftUnitor_monoidal (X₁ X₂ : C) :
(λ_ X₁).hom ⊗ (λ_ X₂).hom =
- tensor_μ C (𝟙_ C, X₁) (𝟙_ C, X₂) ≫ ((λ_ (𝟙_ C)).hom ▷ (X₁ ⊗ X₂)) ≫ (λ_ (X₁ ⊗ X₂)).hom := by
+ tensor_μ (𝟙_ C) X₁ (𝟙_ C) X₂ ≫ ((λ_ (𝟙_ C)).hom ▷ (X₁ ⊗ X₂)) ≫ (λ_ (X₁ ⊗ X₂)).hom := by
dsimp only [tensor_μ]
have :
(λ_ X₁).hom ⊗ (λ_ X₂).hom =
(α_ (𝟙_ C) X₁ (𝟙_ C ⊗ X₂)).hom ≫
(𝟙_ C ◁ (α_ X₁ (𝟙_ C) X₂).inv) ≫ (λ_ ((X₁ ⊗ 𝟙_ C) ⊗ X₂)).hom ≫ ((ρ_ X₁).hom ▷ X₂) := by
- coherence
+ monoidal
rw [this]; clear this
rw [← braiding_leftUnitor]
- dsimp only [tensor_obj, prodMonoidal_tensorObj]
- coherence
+ monoidal
@[reassoc]
theorem rightUnitor_monoidal (X₁ X₂ : C) :
(ρ_ X₁).hom ⊗ (ρ_ X₂).hom =
- tensor_μ C (X₁, 𝟙_ C) (X₂, 𝟙_ C) ≫ ((X₁ ⊗ X₂) ◁ (λ_ (𝟙_ C)).hom) ≫ (ρ_ (X₁ ⊗ X₂)).hom := by
+ tensor_μ X₁ (𝟙_ C) X₂ (𝟙_ C) ≫ ((X₁ ⊗ X₂) ◁ (λ_ (𝟙_ C)).hom) ≫ (ρ_ (X₁ ⊗ X₂)).hom := by
dsimp only [tensor_μ]
have :
(ρ_ X₁).hom ⊗ (ρ_ X₂).hom =
(α_ X₁ (𝟙_ C) (X₂ ⊗ 𝟙_ C)).hom ≫
(X₁ ◁ (α_ (𝟙_ C) X₂ (𝟙_ C)).inv) ≫ (X₁ ◁ (ρ_ (𝟙_ C ⊗ X₂)).hom) ≫ (X₁ ◁ (λ_ X₂).hom) := by
- coherence
+ monoidal
rw [this]; clear this
rw [← braiding_rightUnitor]
- dsimp only [tensor_obj, prodMonoidal_tensorObj]
- coherence
+ monoidal
theorem associator_monoidal (X₁ X₂ X₃ Y₁ Y₂ Y₃ : C) :
- tensor_μ C (X₁ ⊗ X₂, X₃) (Y₁ ⊗ Y₂, Y₃) ≫
- (tensor_μ C (X₁, X₂) (Y₁, Y₂) ▷ (X₃ ⊗ Y₃)) ≫ (α_ (X₁ ⊗ Y₁) (X₂ ⊗ Y₂) (X₃ ⊗ Y₃)).hom =
+ tensor_μ (X₁ ⊗ X₂) X₃ (Y₁ ⊗ Y₂) Y₃ ≫
+ (tensor_μ X₁ X₂ Y₁ Y₂ ▷ (X₃ ⊗ Y₃)) ≫ (α_ (X₁ ⊗ Y₁) (X₂ ⊗ Y₂) (X₃ ⊗ Y₃)).hom =
((α_ X₁ X₂ X₃).hom ⊗ (α_ Y₁ Y₂ Y₃).hom) ≫
- tensor_μ C (X₁, X₂ ⊗ X₃) (Y₁, Y₂ ⊗ Y₃) ≫ ((X₁ ⊗ Y₁) ◁ tensor_μ C (X₂, X₃) (Y₂, Y₃)) := by
+ tensor_μ X₁ (X₂ ⊗ X₃) Y₁ (Y₂ ⊗ Y₃) ≫ ((X₁ ⊗ Y₁) ◁ tensor_μ X₂ X₃ Y₂ Y₃) := by
dsimp only [tensor_μ]
calc
_ = 𝟙 _ ⊗≫ X₁ ◁ X₂ ◁ (β_ X₃ Y₁).hom ▷ Y₂ ▷ Y₃ ⊗≫
X₁ ◁ ((X₂ ⊗ Y₁) ◁ (β_ X₃ Y₂).hom ≫
- (β_ X₂ Y₁).hom ▷ (Y₂ ⊗ X₃)) ▷ Y₃ ⊗≫ 𝟙 _ := by simp; coherence
- _ = _ := by rw [whisker_exchange]; simp; coherence
+ (β_ X₂ Y₁).hom ▷ (Y₂ ⊗ X₃)) ▷ Y₃ ⊗≫ 𝟙 _ := by
+ rw [braiding_tensor_right]; monoidal
+ _ = _ := by rw [whisker_exchange, braiding_tensor_left]; monoidal
-- We got a timeout if `reassoc` was at the declaration, so we put it here instead.
attribute [reassoc] associator_monoidal
diff --git a/Mathlib/CategoryTheory/Monoidal/Braided/Opposite.lean b/Mathlib/CategoryTheory/Monoidal/Braided/Opposite.lean
index db18fda7de208..a4c907e15f044 100644
--- a/Mathlib/CategoryTheory/Monoidal/Braided/Opposite.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Braided/Opposite.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2024 Lean FRO LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Braided.Basic
import Mathlib.CategoryTheory.Monoidal.Opposite
@@ -23,13 +23,13 @@ namespace CategoryTheory.BraidedCategory
@[simp] lemma unop_tensor_μ {C : Type*} [Category C] [MonoidalCategory C]
[BraidedCategory C] (X Y W Z : Cᵒᵖ) :
- (tensor_μ Cᵒᵖ (X, W) (Y, Z)).unop = tensor_μ C (X.unop, Y.unop) (W.unop, Z.unop) := by
+ (tensor_μ X W Y Z).unop = tensor_μ X.unop Y.unop W.unop Z.unop := by
simp only [unop_tensorObj, tensor_μ, unop_comp, unop_inv_associator, unop_whiskerLeft,
unop_hom_associator, unop_whiskerRight, unop_hom_braiding, Category.assoc]
@[simp] lemma op_tensor_μ {C : Type*} [Category C] [MonoidalCategory C]
[BraidedCategory C] (X Y W Z : C) :
- (tensor_μ C (X, W) (Y, Z)).op = tensor_μ Cᵒᵖ (op X, op Y) (op W, op Z) := by
+ (tensor_μ X W Y Z).op = tensor_μ (op X) (op Y) (op W) (op Z) := by
simp only [op_tensorObj, tensor_μ, op_comp, op_inv_associator, op_whiskerLeft, op_hom_associator,
op_whiskerRight, op_hom_braiding, Category.assoc]
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/Category.lean b/Mathlib/CategoryTheory/Monoidal/Category.lean
index 19ccf8685ca18..d80764aa71802 100644
--- a/Mathlib/CategoryTheory/Monoidal/Category.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Category.lean
@@ -1,8 +1,9 @@
/-
Copyright (c) 2018 Michael Jendrusch. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Michael Jendrusch, Scott Morrison, Bhavik Mehta, Jakob von Raumer
+Authors: Michael Jendrusch, Kim Morrison, Bhavik Mehta, Jakob von Raumer
-/
+import Mathlib.CategoryTheory.EqToHom
import Mathlib.CategoryTheory.Functor.Trifunctor
import Mathlib.CategoryTheory.Products.Basic
diff --git a/Mathlib/CategoryTheory/Monoidal/Center.lean b/Mathlib/CategoryTheory/Monoidal/Center.lean
index 4d27a6af5c4be..3e6f4d3046f5a 100644
--- a/Mathlib/CategoryTheory/Monoidal/Center.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Center.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Braided.Basic
import Mathlib.CategoryTheory.Functor.ReflectsIso
@@ -137,19 +137,19 @@ def tensorObj (X Y : Center C) : Center C :=
X.1 ◁ (HalfBraiding.β Y.2 U).hom ▷ U' ⊗≫
(_ ◁ (HalfBraiding.β Y.2 U').hom ≫
(HalfBraiding.β X.2 U).hom ▷ _) ⊗≫
- U ◁ (HalfBraiding.β X.2 U').hom ▷ Y.1 ⊗≫ 𝟙 _ := by coherence
- _ = _ := by rw [whisker_exchange]; coherence
+ U ◁ (HalfBraiding.β X.2 U').hom ▷ Y.1 ⊗≫ 𝟙 _ := by monoidal
+ _ = _ := by rw [whisker_exchange]; monoidal
naturality := fun {U U'} f => by
dsimp only [Iso.trans_hom, whiskerLeftIso_hom, Iso.symm_hom, whiskerRightIso_hom]
calc
_ = 𝟙 _ ⊗≫
(X.1 ◁ (Y.1 ◁ f ≫ (HalfBraiding.β Y.2 U').hom)) ⊗≫
- (HalfBraiding.β X.2 U').hom ▷ Y.1 ⊗≫ 𝟙 _ := by coherence
+ (HalfBraiding.β X.2 U').hom ▷ Y.1 ⊗≫ 𝟙 _ := by monoidal
_ = 𝟙 _ ⊗≫
X.1 ◁ (HalfBraiding.β Y.2 U).hom ⊗≫
(X.1 ◁ f ≫ (HalfBraiding.β X.2 U').hom) ▷ Y.1 ⊗≫ 𝟙 _ := by
- rw [HalfBraiding.naturality]; coherence
- _ = _ := by rw [HalfBraiding.naturality]; coherence }⟩
+ rw [HalfBraiding.naturality]; monoidal
+ _ = _ := by rw [HalfBraiding.naturality]; monoidal }⟩
@[reassoc]
theorem whiskerLeft_comm (X : Center C) {Y₁ Y₂ : Center C} (f : Y₁ ⟶ Y₂) (U : C) :
@@ -160,12 +160,12 @@ theorem whiskerLeft_comm (X : Center C) {Y₁ Y₂ : Center C} (f : Y₁ ⟶ Y
calc
_ = 𝟙 _ ⊗≫
X.fst ◁ (f.f ▷ U ≫ (HalfBraiding.β Y₂.snd U).hom) ⊗≫
- (HalfBraiding.β X.snd U).hom ▷ Y₂.fst ⊗≫ 𝟙 _ := by coherence
+ (HalfBraiding.β X.snd U).hom ▷ Y₂.fst ⊗≫ 𝟙 _ := by monoidal
_ = 𝟙 _ ⊗≫
X.fst ◁ (HalfBraiding.β Y₁.snd U).hom ⊗≫
((X.fst ⊗ U) ◁ f.f ≫ (HalfBraiding.β X.snd U).hom ▷ Y₂.fst) ⊗≫ 𝟙 _ := by
- rw [f.comm]; coherence
- _ = _ := by rw [whisker_exchange]; coherence
+ rw [f.comm]; monoidal
+ _ = _ := by rw [whisker_exchange]; monoidal
/-- Auxiliary definition for the `MonoidalCategory` instance on `Center C`. -/
def whiskerLeft (X : Center C) {Y₁ Y₂ : Center C} (f : Y₁ ⟶ Y₂) :
@@ -182,12 +182,12 @@ theorem whiskerRight_comm {X₁ X₂ : Center C} (f : X₁ ⟶ X₂) (Y : Center
calc
_ = 𝟙 _ ⊗≫
(f.f ▷ (Y.fst ⊗ U) ≫ X₂.fst ◁ (HalfBraiding.β Y.snd U).hom) ⊗≫
- (HalfBraiding.β X₂.snd U).hom ▷ Y.fst ⊗≫ 𝟙 _ := by coherence
+ (HalfBraiding.β X₂.snd U).hom ▷ Y.fst ⊗≫ 𝟙 _ := by monoidal
_ = 𝟙 _ ⊗≫
X₁.fst ◁ (HalfBraiding.β Y.snd U).hom ⊗≫
(f.f ▷ U ≫ (HalfBraiding.β X₂.snd U).hom) ▷ Y.fst ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; coherence
- _ = _ := by rw [f.comm]; coherence
+ rw [← whisker_exchange]; monoidal
+ _ = _ := by rw [f.comm]; monoidal
/-- Auxiliary definition for the `MonoidalCategory` instance on `Center C`. -/
def whiskerRight {X₁ X₂ : Center C} (f : X₁ ⟶ X₂) (Y : Center C) :
@@ -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/CoherenceLemmas.lean b/Mathlib/CategoryTheory/Monoidal/CoherenceLemmas.lean
index 430680b7fe1cf..ef4ecbd8d3584 100644
--- a/Mathlib/CategoryTheory/Monoidal/CoherenceLemmas.lean
+++ b/Mathlib/CategoryTheory/Monoidal/CoherenceLemmas.lean
@@ -1,9 +1,9 @@
/-
Copyright (c) 2018 Michael Jendrusch. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Michael Jendrusch, Scott Morrison, Bhavik Mehta, Jakob von Raumer
+Authors: Michael Jendrusch, Kim Morrison, Bhavik Mehta, Jakob von Raumer
-/
-import Mathlib.Tactic.CategoryTheory.Coherence
+import Mathlib.Tactic.CategoryTheory.Monoidal.PureCoherence
/-!
# Lemmas which are consequences of monoidal coherence
@@ -26,47 +26,47 @@ variable {C : Type*} [Category C] [MonoidalCategory C]
@[reassoc]
theorem leftUnitor_tensor'' (X Y : C) :
(α_ (𝟙_ C) X Y).hom ≫ (λ_ (X ⊗ Y)).hom = (λ_ X).hom ⊗ 𝟙 Y := by
- coherence
+ monoidal_coherence
@[reassoc]
theorem leftUnitor_tensor' (X Y : C) :
(λ_ (X ⊗ Y)).hom = (α_ (𝟙_ C) X Y).inv ≫ ((λ_ X).hom ⊗ 𝟙 Y) := by
- coherence
+ monoidal_coherence
@[reassoc]
theorem leftUnitor_tensor_inv' (X Y : C) :
- (λ_ (X ⊗ Y)).inv = ((λ_ X).inv ⊗ 𝟙 Y) ≫ (α_ (𝟙_ C) X Y).hom := by coherence
+ (λ_ (X ⊗ Y)).inv = ((λ_ X).inv ⊗ 𝟙 Y) ≫ (α_ (𝟙_ C) X Y).hom := by monoidal_coherence
@[reassoc]
theorem id_tensor_rightUnitor_inv (X Y : C) : 𝟙 X ⊗ (ρ_ Y).inv = (ρ_ _).inv ≫ (α_ _ _ _).hom := by
- coherence
+ monoidal_coherence
@[reassoc]
theorem leftUnitor_inv_tensor_id (X Y : C) : (λ_ X).inv ⊗ 𝟙 Y = (λ_ _).inv ≫ (α_ _ _ _).inv := by
- coherence
+ monoidal_coherence
@[reassoc]
theorem pentagon_inv_inv_hom (W X Y Z : C) :
(α_ W (X ⊗ Y) Z).inv ≫ ((α_ W X Y).inv ⊗ 𝟙 Z) ≫ (α_ (W ⊗ X) Y Z).hom =
(𝟙 W ⊗ (α_ X Y Z).hom) ≫ (α_ W X (Y ⊗ Z)).inv := by
- coherence
+ monoidal_coherence
theorem unitors_equal : (λ_ (𝟙_ C)).hom = (ρ_ (𝟙_ C)).hom := by
- coherence
+ monoidal_coherence
theorem unitors_inv_equal : (λ_ (𝟙_ C)).inv = (ρ_ (𝟙_ C)).inv := by
- coherence
+ monoidal_coherence
@[reassoc]
theorem pentagon_hom_inv {W X Y Z : C} :
(α_ W X (Y ⊗ Z)).hom ≫ (𝟙 W ⊗ (α_ X Y Z).inv) =
(α_ (W ⊗ X) Y Z).inv ≫ ((α_ W X Y).hom ⊗ 𝟙 Z) ≫ (α_ W (X ⊗ Y) Z).hom := by
- coherence
+ monoidal_coherence
@[reassoc]
theorem pentagon_inv_hom (W X Y Z : C) :
(α_ (W ⊗ X) Y Z).inv ≫ ((α_ W X Y).hom ⊗ 𝟙 Z) =
(α_ W X (Y ⊗ Z)).hom ≫ (𝟙 W ⊗ (α_ X Y Z).inv) ≫ (α_ W (X ⊗ Y) Z).inv := by
- coherence
+ monoidal_coherence
end CategoryTheory.MonoidalCategory
diff --git a/Mathlib/CategoryTheory/Monoidal/CommMon_.lean b/Mathlib/CategoryTheory/Monoidal/CommMon_.lean
index 7eaef1920b0fc..95ff7663a6476 100644
--- a/Mathlib/CategoryTheory/Monoidal/CommMon_.lean
+++ b/Mathlib/CategoryTheory/Monoidal/CommMon_.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Braided.Basic
import Mathlib.CategoryTheory.Monoidal.Mon_
@@ -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 b58290d9ba93a..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]
@@ -59,9 +128,9 @@ def trivial : Comon_ C where
X := 𝟙_ C
counit := 𝟙 _
comul := (λ_ _).inv
- comul_assoc := by coherence
- counit_comul := by coherence
- comul_counit := by coherence
+ comul_assoc := by monoidal_coherence
+ counit_comul := by monoidal_coherence
+ comul_counit := by monoidal_coherence
instance : Inhabited (Comon_ C) :=
⟨trivial C⟩
@@ -243,13 +312,17 @@ Comonoid objects in a braided category form a monoidal category.
This definition is via transporting back and forth to monoids in the opposite category,
-/
-instance [BraidedCategory C] : MonoidalCategory (Comon_ C) :=
+@[simps!]
+instance monoidal [BraidedCategory C] : MonoidalCategory (Comon_ C) :=
Monoidal.transport (Comon_EquivMon_OpOp C).symm
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
@@ -260,7 +333,7 @@ the version provided in `tensorObj_comul` below.
-/
theorem tensorObj_comul' (A B : Comon_ C) :
(A ⊗ B).comul =
- (A.comul ⊗ B.comul) ≫ (tensor_μ Cᵒᵖ (op A.X, op B.X) (op A.X, op B.X)).unop := by
+ (A.comul ⊗ B.comul) ≫ (tensor_μ (op A.X) (op B.X) (op A.X) (op B.X)).unop := by
rfl
/--
@@ -269,7 +342,7 @@ the tensor product of the comultiplications followed by the tensor strength
(to shuffle the factors back into order).
-/
theorem tensorObj_comul (A B : Comon_ C) :
- (A ⊗ B).comul = (A.comul ⊗ B.comul) ≫ tensor_μ C (A.X, A.X) (B.X, B.X) := by
+ (A ⊗ B).comul = (A.comul ⊗ B.comul) ≫ tensor_μ A.X A.X B.X B.X := by
rw [tensorObj_comul']
congr
simp only [tensor_μ, unop_tensorObj, unop_op]
@@ -280,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 dbd834083cb6e..5cd7283da6587 100644
--- a/Mathlib/CategoryTheory/Monoidal/Discrete.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Discrete.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Hom.Defs
import Mathlib.CategoryTheory.DiscreteCategory
@@ -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/End.lean b/Mathlib/CategoryTheory/Monoidal/End.lean
index 52c8651d1e0ed..5a48831f3a044 100644
--- a/Mathlib/CategoryTheory/Monoidal/End.lean
+++ b/Mathlib/CategoryTheory/Monoidal/End.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Andrew Yang
+Authors: Kim Morrison, Andrew Yang
-/
import Mathlib.CategoryTheory.Monoidal.Functor
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 8bf05788f4dbd..4f367c8c6a40a 100644
--- a/Mathlib/CategoryTheory/Monoidal/Functor.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Functor.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Michael Jendrusch. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Michael Jendrusch, Scott Morrison, Bhavik Mehta
+Authors: Michael Jendrusch, Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Monoidal.Category
import Mathlib.CategoryTheory.Adjunction.FullyFaithful
@@ -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⟩
@@ -365,6 +386,22 @@ theorem map_whiskerLeft (X : C) {Y Z : C} (f : Y ⟶ Z) :
theorem map_whiskerRight {X Y : C} (f : X ⟶ Y) (Z : C) :
F.map (f ▷ Z) = inv (F.μ X Z) ≫ F.map f ▷ F.obj Z ≫ F.μ Y Z := by simp
+@[reassoc]
+theorem map_associator (X Y Z : C) :
+ F.map (α_ X Y Z).hom =
+ inv (F.μ (X ⊗ Y) Z) ≫ inv (F.μ X Y) ▷ F.obj Z ≫
+ (α_ (F.obj X) (F.obj Y) (F.obj Z)).hom ≫ F.obj X ◁ F.μ Y Z ≫ F.μ X (Y ⊗ Z) := by
+ rw [← inv_whiskerRight, ← IsIso.inv_comp_assoc, IsIso.eq_inv_comp]
+ simp
+
+@[reassoc]
+theorem map_associator_inv (X Y Z : C) :
+ F.map (α_ X Y Z).inv =
+ inv (F.μ X (Y ⊗ Z)) ≫ F.obj X ◁ inv (F.μ Y Z) ≫
+ (α_ (F.obj X) (F.obj Y) (F.obj Z)).inv ≫ F.μ X Y ▷ F.obj Z ≫ F.μ (X ⊗ Y) Z := by
+ rw [← inv_whiskerLeft, ← IsIso.inv_comp_assoc, IsIso.eq_inv_comp]
+ simp
+
@[reassoc]
theorem map_leftUnitor (X : C) :
F.map (λ_ X).hom = inv (F.μ (𝟙_ C) X) ≫ inv F.ε ▷ F.obj X ≫ (λ_ (F.obj X)).hom := by
@@ -441,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⟩
@@ -542,7 +579,7 @@ variable (C)
def diag : MonoidalFunctor C (C × C) :=
{ Functor.diag C with
ε := 𝟙 _
- μ := fun X Y => 𝟙 _ }
+ μ := fun _ _ => 𝟙 _ }
end MonoidalFunctor
diff --git a/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean
index 90286ae948670..e06040b2769af 100644
--- a/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean
+++ b/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Braided.Basic
import Mathlib.CategoryTheory.Functor.Category
@@ -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 26bd834c33628..652d56766ced5 100644
--- a/Mathlib/CategoryTheory/Monoidal/Functorial.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Functorial.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Functor
import Mathlib.CategoryTheory.Functor.Functorial
@@ -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 12419c19a3575..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.
@@ -223,7 +256,7 @@ theorem antipode_comul₂ (A : Hopf_ C) :
MonoidalCategory.whiskerRight_id, whiskerLeft_rightUnitor, Category.assoc, Iso.hom_inv_id_assoc,
Iso.inv_hom_id_assoc, whiskerLeft_inv_hom_assoc, antipode_right_assoc]
rw [rightUnitor_inv_naturality_assoc, tensorHom_def]
- coherence
+ monoidal
theorem antipode_comul (A : Hopf_ C) :
A.antipode ≫ A.X.comul.hom = A.X.comul.hom ≫ (β_ _ _).hom ≫ (A.antipode ⊗ A.antipode) := by
@@ -400,7 +433,7 @@ theorem mul_antipode₂ (A : Hopf_ C) :
slice_lhs 2 3 =>
rw [rightUnitor_naturality]
simp only [Mon_.tensorUnit_X]
- coherence
+ monoidal
theorem mul_antipode (A : Hopf_ C) :
A.X.X.mul ≫ A.antipode = (A.antipode ⊗ A.antipode) ≫ (β_ _ _).hom ≫ A.X.X.mul := by
diff --git a/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean
index 19c7811649daf..6678552572fca 100644
--- a/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.CommMon_
import Mathlib.CategoryTheory.Monoidal.Comon_
@@ -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/Limits.lean b/Mathlib/CategoryTheory/Monoidal/Internal/Limits.lean
index 8986e18168ceb..53ddce8988862 100644
--- a/Mathlib/CategoryTheory/Monoidal/Internal/Limits.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Internal/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Internal.FunctorCategory
import Mathlib.CategoryTheory.Monoidal.Limits
diff --git a/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean b/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean
index 25946bbd79708..65be75a189756 100644
--- a/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.ModuleCat.Monoidal.Basic
import Mathlib.Algebra.Category.AlgebraCat.Basic
@@ -45,24 +45,19 @@ instance Ring_of_Mon_ (A : Mon_ (ModuleCat.{u} R)) : Ring A.X :=
one := A.one (1 : R)
mul := fun x y => A.mul (x ⊗ₜ y)
one_mul := fun x => by
- have := LinearMap.congr_fun A.one_mul ((1 : R) ⊗ₜ x)
- convert this
+ convert LinearMap.congr_fun A.one_mul ((1 : R) ⊗ₜ x)
rw [MonoidalCategory.leftUnitor_hom_apply, one_smul]
mul_one := fun x => by
- have := LinearMap.congr_fun A.mul_one (x ⊗ₜ (1 : R))
- convert this
+ convert LinearMap.congr_fun A.mul_one (x ⊗ₜ (1 : R))
erw [MonoidalCategory.leftUnitor_hom_apply, one_smul]
mul_assoc := fun x y z => by
- have := LinearMap.congr_fun A.mul_assoc (x ⊗ₜ y ⊗ₜ z)
- convert this
+ convert LinearMap.congr_fun A.mul_assoc (x ⊗ₜ y ⊗ₜ z)
left_distrib := fun x y z => by
- have := A.mul.map_add (x ⊗ₜ y) (x ⊗ₜ z)
- convert this
+ convert A.mul.map_add (x ⊗ₜ y) (x ⊗ₜ z)
rw [← TensorProduct.tmul_add]
rfl
right_distrib := fun x y z => by
- have := A.mul.map_add (x ⊗ₜ z) (y ⊗ₜ z)
- convert this
+ convert A.mul.map_add (x ⊗ₜ z) (y ⊗ₜ z)
rw [← TensorProduct.add_tmul]
rfl
zero_mul := fun x => show A.mul _ = 0 by
@@ -93,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)
@@ -108,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]
@@ -121,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,
@@ -136,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
@@ -178,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 } })
@@ -201,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
@@ -226,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 1c8d1b2ee61fc..35b5ae5310477 100644
--- a/Mathlib/CategoryTheory/Monoidal/Internal/Types.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Internal/Types.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.MonCat.Basic
import Mathlib.CategoryTheory.Monoidal.CommMon_
@@ -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 4ddc2b63e9618..aaf3b03b9b353 100644
--- a/Mathlib/CategoryTheory/Monoidal/Limits.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Functorial
import Mathlib.CategoryTheory.Monoidal.FunctorCategory
@@ -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/Linear.lean b/Mathlib/CategoryTheory/Monoidal/Linear.lean
index f736296f7147d..d9c475fc8dc58 100644
--- a/Mathlib/CategoryTheory/Monoidal/Linear.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Linear.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Linear.LinearFunctor
import Mathlib.CategoryTheory.Monoidal.Preadditive
diff --git a/Mathlib/CategoryTheory/Monoidal/Mod_.lean b/Mathlib/CategoryTheory/Monoidal/Mod_.lean
index 79ddde1156f2d..ec6327ca22917 100644
--- a/Mathlib/CategoryTheory/Monoidal/Mod_.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Mod_.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Mon_
@@ -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 0279c6c4d67d2..52b4de6677a39 100644
--- a/Mathlib/CategoryTheory/Monoidal/Mon_.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Mon_.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Braided.Basic
import Mathlib.CategoryTheory.Monoidal.Discrete
@@ -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]
@@ -57,8 +128,8 @@ def trivial : Mon_ C where
X := 𝟙_ C
one := 𝟙 _
mul := (λ_ _).hom
- mul_assoc := by coherence
- mul_one := by coherence
+ mul_assoc := by monoidal_coherence
+ mul_one := by monoidal_coherence
instance : Inhabited (Mon_ C) :=
⟨trivial C⟩
@@ -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 }
@@ -350,30 +420,30 @@ variable [BraidedCategory C]
theorem Mon_tensor_one_mul (M N : Mon_ C) :
(((λ_ (𝟙_ C)).inv ≫ (M.one ⊗ N.one)) ▷ (M.X ⊗ N.X)) ≫
- tensor_μ C (M.X, N.X) (M.X, N.X) ≫ (M.mul ⊗ N.mul) =
+ tensor_μ M.X N.X M.X N.X ≫ (M.mul ⊗ N.mul) =
(λ_ (M.X ⊗ N.X)).hom := by
simp only [comp_whiskerRight_assoc]
slice_lhs 2 3 => rw [tensor_μ_natural_left]
slice_lhs 3 4 => rw [← tensor_comp, one_mul M, one_mul N]
symm
- exact tensor_left_unitality C M.X N.X
+ exact tensor_left_unitality M.X N.X
theorem Mon_tensor_mul_one (M N : Mon_ C) :
(M.X ⊗ N.X) ◁ ((λ_ (𝟙_ C)).inv ≫ (M.one ⊗ N.one)) ≫
- tensor_μ C (M.X, N.X) (M.X, N.X) ≫ (M.mul ⊗ N.mul) =
+ tensor_μ M.X N.X M.X N.X ≫ (M.mul ⊗ N.mul) =
(ρ_ (M.X ⊗ N.X)).hom := by
simp only [MonoidalCategory.whiskerLeft_comp_assoc]
slice_lhs 2 3 => rw [tensor_μ_natural_right]
slice_lhs 3 4 => rw [← tensor_comp, mul_one M, mul_one N]
symm
- exact tensor_right_unitality C M.X N.X
+ exact tensor_right_unitality M.X N.X
theorem Mon_tensor_mul_assoc (M N : Mon_ C) :
- ((tensor_μ C (M.X, N.X) (M.X, N.X) ≫ (M.mul ⊗ N.mul)) ▷ (M.X ⊗ N.X)) ≫
- tensor_μ C (M.X, N.X) (M.X, N.X) ≫ (M.mul ⊗ N.mul) =
+ ((tensor_μ M.X N.X M.X N.X ≫ (M.mul ⊗ N.mul)) ▷ (M.X ⊗ N.X)) ≫
+ tensor_μ M.X N.X M.X N.X ≫ (M.mul ⊗ N.mul) =
(α_ (M.X ⊗ N.X) (M.X ⊗ N.X) (M.X ⊗ N.X)).hom ≫
- ((M.X ⊗ N.X) ◁ (tensor_μ C (M.X, N.X) (M.X, N.X) ≫ (M.mul ⊗ N.mul))) ≫
- tensor_μ C (M.X, N.X) (M.X, N.X) ≫ (M.mul ⊗ N.mul) := by
+ ((M.X ⊗ N.X) ◁ (tensor_μ M.X N.X M.X N.X ≫ (M.mul ⊗ N.mul))) ≫
+ tensor_μ M.X N.X M.X N.X ≫ (M.mul ⊗ N.mul) := by
simp only [comp_whiskerRight_assoc, MonoidalCategory.whiskerLeft_comp_assoc]
slice_lhs 2 3 => rw [tensor_μ_natural_left]
slice_lhs 3 4 => rw [← tensor_comp, mul_assoc M, mul_assoc N, tensor_comp, tensor_comp]
@@ -382,12 +452,12 @@ theorem Mon_tensor_mul_assoc (M N : Mon_ C) :
simp
theorem mul_associator {M N P : Mon_ C} :
- (tensor_μ C (M.X ⊗ N.X, P.X) (M.X ⊗ N.X, P.X) ≫
- (tensor_μ C (M.X, N.X) (M.X, N.X) ≫ (M.mul ⊗ N.mul) ⊗ P.mul)) ≫
+ (tensor_μ (M.X ⊗ N.X) P.X (M.X ⊗ N.X) P.X ≫
+ (tensor_μ M.X N.X M.X N.X ≫ (M.mul ⊗ N.mul) ⊗ P.mul)) ≫
(α_ M.X N.X P.X).hom =
((α_ M.X N.X P.X).hom ⊗ (α_ M.X N.X P.X).hom) ≫
- tensor_μ C (M.X, N.X ⊗ P.X) (M.X, N.X ⊗ P.X) ≫
- (M.mul ⊗ tensor_μ C (N.X, P.X) (N.X, P.X) ≫ (N.mul ⊗ P.mul)) := by
+ tensor_μ M.X (N.X ⊗ P.X) M.X (N.X ⊗ P.X) ≫
+ (M.mul ⊗ tensor_μ N.X P.X N.X P.X ≫ (N.mul ⊗ P.mul)) := by
simp only [tensor_obj, prodMonoidal_tensorObj, Category.assoc]
slice_lhs 2 3 => rw [← Category.id_comp P.mul, tensor_comp]
slice_lhs 3 4 => rw [associator_naturality]
@@ -397,7 +467,7 @@ theorem mul_associator {M N P : Mon_ C} :
simp only [Category.assoc]
theorem mul_leftUnitor {M : Mon_ C} :
- (tensor_μ C (𝟙_ C, M.X) (𝟙_ C, M.X) ≫ ((λ_ (𝟙_ C)).hom ⊗ M.mul)) ≫ (λ_ M.X).hom =
+ (tensor_μ (𝟙_ C) M.X (𝟙_ C) M.X ≫ ((λ_ (𝟙_ C)).hom ⊗ M.mul)) ≫ (λ_ M.X).hom =
((λ_ M.X).hom ⊗ (λ_ M.X).hom) ≫ M.mul := by
rw [← Category.comp_id (λ_ (𝟙_ C)).hom, ← Category.id_comp M.mul, tensor_comp]
simp only [tensorHom_id, id_tensorHom]
@@ -406,7 +476,7 @@ theorem mul_leftUnitor {M : Mon_ C} :
simp only [Category.assoc, Category.id_comp]
theorem mul_rightUnitor {M : Mon_ C} :
- (tensor_μ C (M.X, 𝟙_ C) (M.X, 𝟙_ C) ≫ (M.mul ⊗ (λ_ (𝟙_ C)).hom)) ≫ (ρ_ M.X).hom =
+ (tensor_μ M.X (𝟙_ C) M.X (𝟙_ C) ≫ (M.mul ⊗ (λ_ (𝟙_ C)).hom)) ≫ (ρ_ M.X).hom =
((ρ_ M.X).hom ⊗ (ρ_ M.X).hom) ≫ M.mul := by
rw [← Category.id_comp M.mul, ← Category.comp_id (λ_ (𝟙_ C)).hom, tensor_comp]
simp only [tensorHom_id, id_tensorHom]
@@ -419,7 +489,7 @@ instance monMonoidalStruct : MonoidalCategoryStruct (Mon_ C) :=
let tensorObj (M N : Mon_ C) : Mon_ C :=
{ X := M.X ⊗ N.X
one := (λ_ (𝟙_ C)).inv ≫ (M.one ⊗ N.one)
- mul := tensor_μ C (M.X, N.X) (M.X, N.X) ≫ (M.mul ⊗ N.mul)
+ mul := tensor_μ M.X N.X M.X N.X ≫ (M.mul ⊗ N.mul)
one_mul := Mon_tensor_one_mul M N
mul_one := Mon_tensor_mul_one M N
mul_assoc := Mon_tensor_mul_assoc M N }
@@ -457,7 +527,7 @@ theorem tensorObj_one (X Y : Mon_ C) : (X ⊗ Y).one = (λ_ (𝟙_ C)).inv ≫ (
@[simp]
theorem tensorObj_mul (X Y : Mon_ C) :
- (X ⊗ Y).mul = tensor_μ C (X.X, Y.X) (X.X, Y.X) ≫ (X.mul ⊗ Y.mul) := rfl
+ (X ⊗ Y).mul = tensor_μ X.X Y.X X.X Y.X ≫ (X.mul ⊗ Y.mul) := rfl
@[simp]
theorem whiskerLeft_hom {X Y : Mon_ C} (f : X ⟶ Y) (Z : Mon_ C) :
@@ -492,18 +562,22 @@ theorem tensor_one (M N : Mon_ C) : (M ⊗ N).one = (λ_ (𝟙_ C)).inv ≫ (M.o
@[simp]
theorem tensor_mul (M N : Mon_ C) : (M ⊗ N).mul =
- tensor_μ C (M.X, N.X) (M.X, N.X) ≫ (M.mul ⊗ N.mul) := rfl
+ tensor_μ M.X N.X M.X N.X ≫ (M.mul ⊗ N.mul) := rfl
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
@@ -514,7 +588,7 @@ variable {C}
theorem one_braiding {X Y : Mon_ C} : (X ⊗ Y).one ≫ (β_ X.X Y.X).hom = (Y ⊗ X).one := by
simp only [monMonoidalStruct_tensorObj_X, tensor_one, Category.assoc,
BraidedCategory.braiding_naturality, braiding_tensorUnit_right, Iso.cancel_iso_inv_left]
- coherence
+ monoidal
end BraidedCategory
diff --git a/Mathlib/CategoryTheory/Monoidal/NaturalTransformation.lean b/Mathlib/CategoryTheory/Monoidal/NaturalTransformation.lean
index c10f52bc77441..eb01593defb37 100644
--- a/Mathlib/CategoryTheory/Monoidal/NaturalTransformation.lean
+++ b/Mathlib/CategoryTheory/Monoidal/NaturalTransformation.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Adjunction.FullyFaithful
import Mathlib.CategoryTheory.Monoidal.Functor
@@ -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]
@@ -190,8 +190,8 @@ def monoidalCounit :
have eq := h.counit.naturality F.ε
dsimp at 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]
+ ← 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
dsimp [monoidalUnit]
diff --git a/Mathlib/CategoryTheory/Monoidal/OfChosenFiniteProducts/Basic.lean b/Mathlib/CategoryTheory/Monoidal/OfChosenFiniteProducts/Basic.lean
index 3fc5f0c7ece26..9b23a5a2e1f1a 100644
--- a/Mathlib/CategoryTheory/Monoidal/OfChosenFiniteProducts/Basic.lean
+++ b/Mathlib/CategoryTheory/Monoidal/OfChosenFiniteProducts/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Simon Hudon
+Authors: Kim Morrison, Simon Hudon
-/
import Mathlib.CategoryTheory.Monoidal.Category
import Mathlib.CategoryTheory.Limits.Shapes.BinaryProducts
diff --git a/Mathlib/CategoryTheory/Monoidal/OfChosenFiniteProducts/Symmetric.lean b/Mathlib/CategoryTheory/Monoidal/OfChosenFiniteProducts/Symmetric.lean
index eeea00aadcc4d..cd1586181796e 100644
--- a/Mathlib/CategoryTheory/Monoidal/OfChosenFiniteProducts/Symmetric.lean
+++ b/Mathlib/CategoryTheory/Monoidal/OfChosenFiniteProducts/Symmetric.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Simon Hudon
+Authors: Kim Morrison, Simon Hudon
-/
import Mathlib.CategoryTheory.Monoidal.Braided.Basic
import Mathlib.CategoryTheory.Monoidal.OfChosenFiniteProducts.Basic
diff --git a/Mathlib/CategoryTheory/Monoidal/OfHasFiniteProducts.lean b/Mathlib/CategoryTheory/Monoidal/OfHasFiniteProducts.lean
index 043177863cb9e..9e49dda0d93bf 100644
--- a/Mathlib/CategoryTheory/Monoidal/OfHasFiniteProducts.lean
+++ b/Mathlib/CategoryTheory/Monoidal/OfHasFiniteProducts.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Simon Hudon
+Authors: Kim Morrison, Simon Hudon
-/
import Mathlib.CategoryTheory.Monoidal.Braided.Basic
import Mathlib.CategoryTheory.Limits.Preserves.Shapes.BinaryProducts
@@ -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 cecef27b955d5..e1d90560271b1 100644
--- a/Mathlib/CategoryTheory/Monoidal/Opposite.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Opposite.lean
@@ -1,9 +1,9 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
-import Mathlib.Tactic.CategoryTheory.Coherence
+import Mathlib.Tactic.CategoryTheory.Monoidal.PureCoherence
/-!
# Monoidal opposites
@@ -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
@@ -160,8 +160,8 @@ instance monoidalCategoryOp : MonoidalCategory Cᵒᵖ where
associator_naturality f g h := Quiver.Hom.unop_inj <| by simp
leftUnitor_naturality f := Quiver.Hom.unop_inj <| by simp
rightUnitor_naturality f := Quiver.Hom.unop_inj <| by simp
- triangle X Y := Quiver.Hom.unop_inj <| by dsimp; coherence
- pentagon W X Y Z := Quiver.Hom.unop_inj <| by dsimp; coherence
+ triangle X Y := Quiver.Hom.unop_inj <| by dsimp; monoidal_coherence
+ pentagon W X Y Z := Quiver.Hom.unop_inj <| by dsimp; monoidal_coherence
section OppositeLemmas
@@ -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
@@ -241,7 +241,7 @@ instance monoidalCategoryMop : MonoidalCategory Cᴹᵒᵖ where
rightUnitor_naturality f := Quiver.Hom.unmop_inj <| by simp
-- Porting note: Changed `by coherence` to `by simp` below
triangle X Y := Quiver.Hom.unmop_inj <| by simp
- pentagon W X Y Z := Quiver.Hom.unmop_inj <| by dsimp; coherence
+ pentagon W X Y Z := Quiver.Hom.unmop_inj <| by dsimp; monoidal_coherence
-- it would be nice if we could autogenerate all of these somehow
section MonoidalOppositeLemmas
diff --git a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean
index 429a44d694e4c..96881368dc909 100644
--- a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Preadditive.AdditiveFunctor
import Mathlib.CategoryTheory.Monoidal.Functor
@@ -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/Basic.lean b/Mathlib/CategoryTheory/Monoidal/Rigid/Basic.lean
index 9a2f2fa079c42..09afedcc3b9aa 100644
--- a/Mathlib/CategoryTheory/Monoidal/Rigid/Basic.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Rigid/Basic.lean
@@ -3,7 +3,7 @@ Copyright (c) 2021 Jakob von Raumer. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jakob von Raumer
-/
-import Mathlib.Tactic.CategoryTheory.Coherence
+import Mathlib.Tactic.CategoryTheory.Monoidal.Basic
import Mathlib.CategoryTheory.Closed.Monoidal
import Mathlib.Tactic.ApplyFun
@@ -113,11 +113,11 @@ lemma evaluation_coevaluation :
evaluation_coevaluation'
lemma coevaluation_evaluation'' :
- Y ◁ η_ X Y ⊗≫ ε_ X Y ▷ Y = ⊗𝟙 := by
+ Y ◁ η_ X Y ⊗≫ ε_ X Y ▷ Y = ⊗𝟙.hom := by
convert coevaluation_evaluation X Y <;> simp [monoidalComp]
lemma evaluation_coevaluation'' :
- η_ X Y ▷ X ⊗≫ X ◁ ε_ X Y = ⊗𝟙 := by
+ η_ X Y ▷ X ⊗≫ X ◁ ε_ X Y = ⊗𝟙.hom := by
convert evaluation_coevaluation X Y <;> simp [monoidalComp]
end ExactPairing
@@ -128,8 +128,8 @@ attribute [reassoc (attr := simp)] ExactPairing.evaluation_coevaluation
instance exactPairingUnit : ExactPairing (𝟙_ C) (𝟙_ C) where
coevaluation' := (ρ_ _).inv
evaluation' := (ρ_ _).hom
- coevaluation_evaluation' := by rw [← id_tensorHom, ← tensorHom_id]; coherence
- evaluation_coevaluation' := by rw [← id_tensorHom, ← tensorHom_id]; coherence
+ coevaluation_evaluation' := by monoidal_coherence
+ evaluation_coevaluation' := by monoidal_coherence
/-- A class of objects which have a right dual. -/
class HasRightDual (X : C) where
@@ -204,9 +204,9 @@ theorem rightAdjointMate_comp {X Y Z : C} [HasRightDual X] [HasRightDual Y] {f :
_ ◁ η_ X (Xᘁ) ≫ _ ◁ (f ⊗ g) ≫ (α_ (Yᘁ) Y Z).inv ≫ ε_ Y (Yᘁ) ▷ _ ≫ (λ_ Z).hom :=
calc
_ = 𝟙 _ ⊗≫ (Yᘁ : C) ◁ η_ X Xᘁ ≫ Yᘁ ◁ f ▷ Xᘁ ⊗≫ (ε_ Y Yᘁ ▷ Xᘁ ≫ 𝟙_ C ◁ g) ⊗≫ 𝟙 _ := by
- dsimp only [rightAdjointMate]; coherence
+ dsimp only [rightAdjointMate]; monoidal
_ = _ := by
- rw [← whisker_exchange, tensorHom_def]; coherence
+ rw [← whisker_exchange, tensorHom_def]; monoidal
theorem leftAdjointMate_comp {X Y Z : C} [HasLeftDual X] [HasLeftDual Y] {f : X ⟶ Y}
{g : (ᘁX) ⟶ Z} :
@@ -215,9 +215,9 @@ theorem leftAdjointMate_comp {X Y Z : C} [HasLeftDual X] [HasLeftDual Y] {f : X
η_ (ᘁX : C) X ▷ _ ≫ (g ⊗ f) ▷ _ ≫ (α_ _ _ _).hom ≫ _ ◁ ε_ _ _ ≫ (ρ_ _).hom :=
calc
_ = 𝟙 _ ⊗≫ η_ (ᘁX : C) X ▷ (ᘁY) ⊗≫ (ᘁX) ◁ f ▷ (ᘁY) ⊗≫ ((ᘁX) ◁ ε_ (ᘁY) Y ≫ g ▷ 𝟙_ C) ⊗≫ 𝟙 _ := by
- dsimp only [leftAdjointMate]; coherence
+ dsimp only [leftAdjointMate]; monoidal
_ = _ := by
- rw [whisker_exchange, tensorHom_def']; coherence
+ rw [whisker_exchange, tensorHom_def']; monoidal
/-- The composition of right adjoint mates is the adjoint mate of the composition. -/
@[reassoc]
@@ -231,14 +231,14 @@ theorem comp_rightAdjointMate {X Y Z : C} [HasRightDual X] [HasRightDual Y] [Has
calc
_ = 𝟙 _ ⊗≫ (η_ Y Yᘁ ▷ 𝟙_ C ≫ (Y ⊗ Yᘁ) ◁ η_ X Xᘁ) ⊗≫ Y ◁ Yᘁ ◁ f ▷ Xᘁ ⊗≫
Y ◁ ε_ Y Yᘁ ▷ Xᘁ ⊗≫ g ▷ Xᘁ ⊗≫ 𝟙 _ := by
- rw [tensorHom_def']; coherence
+ rw [tensorHom_def']; monoidal
_ = η_ X Xᘁ ⊗≫ (η_ Y Yᘁ ▷ (X ⊗ Xᘁ) ≫ (Y ⊗ Yᘁ) ◁ f ▷ Xᘁ) ⊗≫
Y ◁ ε_ Y Yᘁ ▷ Xᘁ ⊗≫ g ▷ Xᘁ ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; coherence
+ rw [← whisker_exchange]; monoidal
_ = η_ X Xᘁ ⊗≫ f ▷ Xᘁ ⊗≫ (η_ Y Yᘁ ▷ Y ⊗≫ Y ◁ ε_ Y Yᘁ) ▷ Xᘁ ⊗≫ g ▷ Xᘁ ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; coherence
+ rw [← whisker_exchange]; monoidal
_ = η_ X Xᘁ ≫ f ▷ Xᘁ ≫ g ▷ Xᘁ := by
- rw [evaluation_coevaluation'']; coherence
+ rw [evaluation_coevaluation'']; monoidal
/-- The composition of left adjoint mates is the adjoint mate of the composition. -/
@[reassoc]
@@ -252,14 +252,14 @@ theorem comp_leftAdjointMate {X Y Z : C} [HasLeftDual X] [HasLeftDual Y] [HasLef
calc
_ = 𝟙 _ ⊗≫ ((𝟙_ C) ◁ η_ (ᘁY) Y ≫ η_ (ᘁX) X ▷ ((ᘁY) ⊗ Y)) ⊗≫ (ᘁX) ◁ f ▷ (ᘁY) ▷ Y ⊗≫
(ᘁX) ◁ ε_ (ᘁY) Y ▷ Y ⊗≫ (ᘁX) ◁ g := by
- rw [tensorHom_def]; coherence
+ rw [tensorHom_def]; monoidal
_ = η_ (ᘁX) X ⊗≫ (((ᘁX) ⊗ X) ◁ η_ (ᘁY) Y ≫ ((ᘁX) ◁ f) ▷ ((ᘁY) ⊗ Y)) ⊗≫
(ᘁX) ◁ ε_ (ᘁY) Y ▷ Y ⊗≫ (ᘁX) ◁ g := by
- rw [whisker_exchange]; coherence
+ rw [whisker_exchange]; monoidal
_ = η_ (ᘁX) X ⊗≫ ((ᘁX) ◁ f) ⊗≫ (ᘁX) ◁ (Y ◁ η_ (ᘁY) Y ⊗≫ ε_ (ᘁY) Y ▷ Y) ⊗≫ (ᘁX) ◁ g := by
- rw [whisker_exchange]; coherence
+ rw [whisker_exchange]; monoidal
_ = η_ (ᘁX) X ≫ (ᘁX) ◁ f ≫ (ᘁX) ◁ g := by
- rw [coevaluation_evaluation'']; coherence
+ rw [coevaluation_evaluation'']; monoidal
/-- Given an exact pairing on `Y Y'`,
we get a bijection on hom-sets `(Y' ⊗ X ⟶ Z) ≃ (X ⟶ Y ⊗ Z)`
@@ -276,19 +276,19 @@ def tensorLeftHomEquiv (X Y Y' Z : C) [ExactPairing Y Y'] : (Y' ⊗ X ⟶ Z) ≃
left_inv f := by
calc
_ = 𝟙 _ ⊗≫ Y' ◁ η_ Y Y' ▷ X ⊗≫ ((Y' ⊗ Y) ◁ f ≫ ε_ Y Y' ▷ Z) ⊗≫ 𝟙 _ := by
- coherence
+ monoidal
_ = 𝟙 _ ⊗≫ (Y' ◁ η_ Y Y' ⊗≫ ε_ Y Y' ▷ Y') ▷ X ⊗≫ f := by
- rw [whisker_exchange]; coherence
+ rw [whisker_exchange]; monoidal
_ = f := by
- rw [coevaluation_evaluation'']; coherence
+ rw [coevaluation_evaluation'']; monoidal
right_inv f := by
calc
_ = 𝟙 _ ⊗≫ (η_ Y Y' ▷ X ≫ (Y ⊗ Y') ◁ f) ⊗≫ Y ◁ ε_ Y Y' ▷ Z ⊗≫ 𝟙 _ := by
- coherence
+ monoidal
_ = f ⊗≫ (η_ Y Y' ▷ Y ⊗≫ Y ◁ ε_ Y Y') ▷ Z ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; coherence
+ rw [← whisker_exchange]; monoidal
_ = f := by
- rw [evaluation_coevaluation'']; coherence
+ rw [evaluation_coevaluation'']; monoidal
/-- Given an exact pairing on `Y Y'`,
we get a bijection on hom-sets `(X ⊗ Y ⟶ Z) ≃ (X ⟶ Z ⊗ Y')`
@@ -300,19 +300,19 @@ def tensorRightHomEquiv (X Y Y' Z : C) [ExactPairing Y Y'] : (X ⊗ Y ⟶ Z) ≃
left_inv f := by
calc
_ = 𝟙 _ ⊗≫ X ◁ η_ Y Y' ▷ Y ⊗≫ (f ▷ (Y' ⊗ Y) ≫ Z ◁ ε_ Y Y') ⊗≫ 𝟙 _ := by
- coherence
+ monoidal
_ = 𝟙 _ ⊗≫ X ◁ (η_ Y Y' ▷ Y ⊗≫ Y ◁ ε_ Y Y') ⊗≫ f := by
- rw [← whisker_exchange]; coherence
+ rw [← whisker_exchange]; monoidal
_ = f := by
- rw [evaluation_coevaluation'']; coherence
+ rw [evaluation_coevaluation'']; monoidal
right_inv f := by
calc
_ = 𝟙 _ ⊗≫ (X ◁ η_ Y Y' ≫ f ▷ (Y ⊗ Y')) ⊗≫ Z ◁ ε_ Y Y' ▷ Y' ⊗≫ 𝟙 _ := by
- coherence
+ monoidal
_ = f ⊗≫ Z ◁ (Y' ◁ η_ Y Y' ⊗≫ ε_ Y Y' ▷ Y') ⊗≫ 𝟙 _ := by
- rw [whisker_exchange]; coherence
+ rw [whisker_exchange]; monoidal
_ = f := by
- rw [coevaluation_evaluation'']; coherence
+ rw [coevaluation_evaluation'']; monoidal
theorem tensorLeftHomEquiv_naturality {X Y Y' Z Z' : C} [ExactPairing Y Y'] (f : Y' ⊗ X ⟶ Z)
(g : Z ⟶ Z') :
@@ -387,10 +387,10 @@ theorem tensorLeftHomEquiv_symm_coevaluation_comp_whiskerLeft {Y Y' Z : C} [Exac
(f : Y' ⟶ Z) : (tensorLeftHomEquiv _ _ _ _).symm (η_ _ _ ≫ Y ◁ f) = (ρ_ _).hom ≫ f := by
calc
_ = Y' ◁ η_ Y Y' ⊗≫ ((Y' ⊗ Y) ◁ f ≫ ε_ Y Y' ▷ Z) ⊗≫ 𝟙 _ := by
- dsimp [tensorLeftHomEquiv]; coherence
+ dsimp [tensorLeftHomEquiv]; monoidal
_ = (Y' ◁ η_ Y Y' ⊗≫ ε_ Y Y' ▷ Y') ⊗≫ f := by
- rw [whisker_exchange]; coherence
- _ = _ := by rw [coevaluation_evaluation'']; coherence
+ rw [whisker_exchange]; monoidal
+ _ = _ := by rw [coevaluation_evaluation'']; monoidal
@[simp]
theorem tensorLeftHomEquiv_symm_coevaluation_comp_whiskerRight {X Y : C} [HasRightDual X]
@@ -411,22 +411,22 @@ theorem tensorRightHomEquiv_symm_coevaluation_comp_whiskerRight {Y Y' Z : C} [Ex
(f : Y ⟶ Z) : (tensorRightHomEquiv _ Y _ _).symm (η_ Y Y' ≫ f ▷ Y') = (λ_ _).hom ≫ f :=
calc
_ = η_ Y Y' ▷ Y ⊗≫ (f ▷ (Y' ⊗ Y) ≫ Z ◁ ε_ Y Y') ⊗≫ 𝟙 _ := by
- dsimp [tensorRightHomEquiv]; coherence
+ dsimp [tensorRightHomEquiv]; monoidal
_ = (η_ Y Y' ▷ Y ⊗≫ Y ◁ ε_ Y Y') ⊗≫ f := by
- rw [← whisker_exchange]; coherence
+ rw [← whisker_exchange]; monoidal
_ = _ := by
- rw [evaluation_coevaluation'']; coherence
+ rw [evaluation_coevaluation'']; monoidal
@[simp]
theorem tensorLeftHomEquiv_whiskerLeft_comp_evaluation {Y Z : C} [HasLeftDual Z] (f : Y ⟶ ᘁZ) :
(tensorLeftHomEquiv _ _ _ _) (Z ◁ f ≫ ε_ _ _) = f ≫ (ρ_ _).inv :=
calc
_ = 𝟙 _ ⊗≫ (η_ (ᘁZ : C) Z ▷ Y ≫ ((ᘁZ) ⊗ Z) ◁ f) ⊗≫ (ᘁZ) ◁ ε_ (ᘁZ) Z := by
- dsimp [tensorLeftHomEquiv]; coherence
+ dsimp [tensorLeftHomEquiv]; monoidal
_ = f ⊗≫ (η_ (ᘁZ) Z ▷ (ᘁZ) ⊗≫ (ᘁZ) ◁ ε_ (ᘁZ) Z) := by
- rw [← whisker_exchange]; coherence
+ rw [← whisker_exchange]; monoidal
_ = _ := by
- rw [evaluation_coevaluation'']; coherence
+ rw [evaluation_coevaluation'']; monoidal
@[simp]
theorem tensorLeftHomEquiv_whiskerRight_comp_evaluation {X Y : C} [HasLeftDual X] [HasLeftDual Y]
@@ -445,11 +445,11 @@ theorem tensorRightHomEquiv_whiskerRight_comp_evaluation {X Y : C} [HasRightDual
(tensorRightHomEquiv _ _ _ _) (f ▷ X ≫ ε_ X (Xᘁ)) = f ≫ (λ_ _).inv :=
calc
_ = 𝟙 _ ⊗≫ (Y ◁ η_ X Xᘁ ≫ f ▷ (X ⊗ Xᘁ)) ⊗≫ ε_ X Xᘁ ▷ Xᘁ := by
- dsimp [tensorRightHomEquiv]; coherence
+ dsimp [tensorRightHomEquiv]; monoidal
_ = f ⊗≫ (Xᘁ ◁ η_ X Xᘁ ⊗≫ ε_ X Xᘁ ▷ Xᘁ) := by
- rw [whisker_exchange]; coherence
+ rw [whisker_exchange]; monoidal
_ = _ := by
- rw [coevaluation_evaluation'']; coherence
+ rw [coevaluation_evaluation'']; monoidal
-- Next four lemmas passing `fᘁ` or `ᘁf` through (co)evaluations.
@[reassoc]
@@ -483,28 +483,26 @@ def exactPairingCongrLeft {X X' Y : C} [ExactPairing X' Y] (i : X ≅ X') : Exac
evaluation_coevaluation' :=
calc
_ = η_ X' Y ▷ X ⊗≫ (i.inv ▷ (Y ⊗ X) ≫ X ◁ (Y ◁ i.hom)) ⊗≫ X ◁ ε_ X' Y := by
- coherence
+ monoidal
_ = 𝟙 _ ⊗≫ (η_ X' Y ▷ X ≫ (X' ⊗ Y) ◁ i.hom) ⊗≫
(i.inv ▷ (Y ⊗ X') ≫ X ◁ ε_ X' Y) ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange]; coherence
+ rw [← whisker_exchange]; monoidal
_ = 𝟙 _ ⊗≫ i.hom ⊗≫ (η_ X' Y ▷ X' ⊗≫ X' ◁ ε_ X' Y) ⊗≫ i.inv ⊗≫ 𝟙 _ := by
- rw [← whisker_exchange, ← whisker_exchange]; coherence
+ rw [← whisker_exchange, ← whisker_exchange]; monoidal
_ = 𝟙 _ ⊗≫ (i.hom ≫ i.inv) ⊗≫ 𝟙 _ := by
- rw [evaluation_coevaluation'']; coherence
+ rw [evaluation_coevaluation'']; monoidal
_ = (λ_ X).hom ≫ (ρ_ X).inv := by
rw [Iso.hom_inv_id]
- -- coherence failed
- simp [monoidalComp]
+ monoidal
coevaluation_evaluation' := by
calc
_ = Y ◁ η_ X' Y ≫ Y ◁ (i.inv ≫ i.hom) ▷ Y ⊗≫ ε_ X' Y ▷ Y := by
- coherence
+ monoidal
_ = Y ◁ η_ X' Y ⊗≫ ε_ X' Y ▷ Y := by
- rw [Iso.inv_hom_id]; coherence
+ rw [Iso.inv_hom_id]; monoidal
_ = _ := by
rw [coevaluation_evaluation'']
- -- coherence failed
- simp [monoidalComp]
+ monoidal
/-- Transport an exact pairing across an isomorphism in the second argument. -/
def exactPairingCongrRight {X Y Y' : C} [ExactPairing X Y'] (i : Y ≅ Y') : ExactPairing X Y where
@@ -513,28 +511,26 @@ def exactPairingCongrRight {X Y Y' : C} [ExactPairing X Y'] (i : Y ≅ Y') : Exa
evaluation_coevaluation' := by
calc
_ = η_ X Y' ▷ X ⊗≫ X ◁ (i.inv ≫ i.hom) ▷ X ≫ X ◁ ε_ X Y' := by
- coherence
+ monoidal
_ = η_ X Y' ▷ X ⊗≫ X ◁ ε_ X Y' := by
- rw [Iso.inv_hom_id]; coherence
+ rw [Iso.inv_hom_id]; monoidal
_ = _ := by
rw [evaluation_coevaluation'']
- -- coherence failed
- simp [monoidalComp]
+ monoidal
coevaluation_evaluation' :=
calc
_ = Y ◁ η_ X Y' ⊗≫ (Y ◁ (X ◁ i.inv) ≫ i.hom ▷ (X ⊗ Y)) ⊗≫ ε_ X Y' ▷ Y := by
- coherence
+ monoidal
_ = 𝟙 _ ⊗≫ (Y ◁ η_ X Y' ≫ i.hom ▷ (X ⊗ Y')) ⊗≫
((Y' ⊗ X) ◁ i.inv ≫ ε_ X Y' ▷ Y) ⊗≫ 𝟙 _ := by
- rw [whisker_exchange]; coherence
+ rw [whisker_exchange]; monoidal
_ = 𝟙 _ ⊗≫ i.hom ⊗≫ (Y' ◁ η_ X Y' ⊗≫ ε_ X Y' ▷ Y') ⊗≫ i.inv ⊗≫ 𝟙 _ := by
- rw [whisker_exchange, whisker_exchange]; coherence
+ rw [whisker_exchange, whisker_exchange]; monoidal
_ = 𝟙 _ ⊗≫ (i.hom ≫ i.inv) ⊗≫ 𝟙 _ := by
- rw [coevaluation_evaluation'']; coherence
+ rw [coevaluation_evaluation'']; monoidal
_ = (ρ_ Y).hom ≫ (λ_ Y).inv := by
rw [Iso.hom_inv_id]
- -- coherence failed
- simp [monoidalComp]
+ monoidal
/-- Transport an exact pairing across isomorphisms. -/
def exactPairingCongr {X X' Y Y' : C} [ExactPairing X' Y'] (i : X ≅ X') (j : Y ≅ Y') :
diff --git a/Mathlib/CategoryTheory/Monoidal/Rigid/Braided.lean b/Mathlib/CategoryTheory/Monoidal/Rigid/Braided.lean
index be429c98c1740..6e6d9d68e265d 100644
--- a/Mathlib/CategoryTheory/Monoidal/Rigid/Braided.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Rigid/Braided.lean
@@ -25,13 +25,13 @@ private theorem coevaluation_evaluation_braided' [inst : ExactPairing X Y] :
/- Whitney trick transcribed: https://mathoverflow.net/a/162729/493261 -/
calc
_ = 𝟙 X ⊗≫ X ◁ η_ X Y ⊗≫ (X ◁ (β_ Y X).inv ⊗≫ (β_ X Y).hom ▷ X) ⊗≫ ε_ X Y ▷ X ⊗≫ 𝟙 X := by
- coherence
+ monoidal
_ = 𝟙 X ⊗≫ X ◁ η_ X Y ⊗≫ (𝟙 (X ⊗ X ⊗ Y) ⊗≫ (β_ X X).hom ▷ Y ⊗≫ X ◁ (β_ X Y).hom
⊗≫ (β_ Y X).inv ▷ X ⊗≫ Y ◁ (β_ X X).inv ⊗≫ 𝟙 ((Y ⊗ X) ⊗ X)) ⊗≫ ε_ X Y ▷ X ⊗≫ 𝟙 X := by
congr 3
- simp only [monoidalComp, MonoidalCoherence.assoc'_hom, MonoidalCoherence.whiskerRight_hom,
- MonoidalCoherence.refl_hom, whiskerRight_tensor, id_whiskerRight, id_comp, Iso.inv_hom_id,
- MonoidalCoherence.assoc_hom, comp_id]
+ simp only [monoidalComp, MonoidalCoherence.assoc'_iso, MonoidalCoherence.whiskerRight_iso,
+ MonoidalCoherence.refl_iso, whiskerRightIso_refl, Iso.refl_trans, Iso.symm_hom,
+ MonoidalCoherence.assoc_iso, Iso.trans_refl, comp_id, id_comp]
rw [← IsIso.eq_inv_comp]
repeat rw [← assoc]
iterate 5 rw [← IsIso.comp_inv_eq]
@@ -49,7 +49,7 @@ private theorem evaluation_coevaluation_braided' [inst : ExactPairing X Y] :
rw [Iso.eq_comp_inv, ← Iso.inv_comp_eq_id]
calc
_ = 𝟙 Y ⊗≫ η_ X Y ▷ Y ⊗≫ ((β_ Y X).inv ▷ Y ⊗≫ Y ◁ (β_ X Y).hom) ≫ Y ◁ ε_ X Y ⊗≫ 𝟙 Y := by
- coherence
+ monoidal
_ = 𝟙 Y ⊗≫ η_ X Y ▷ Y ⊗≫ (𝟙 ((X ⊗ Y) ⊗ Y) ⊗≫ X ◁ (β_ Y Y).hom ⊗≫ (β_ X Y).hom ▷ Y
⊗≫ Y ◁ (β_ Y X).inv ⊗≫ (β_ Y Y).inv ▷ X ⊗≫ 𝟙 (Y ⊗ Y ⊗ X)) ⊗≫ Y ◁ ε_ X Y ⊗≫ 𝟙 Y := by
congr 3
diff --git a/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean
index d458fd401af64..99fcf06d2a3da 100644
--- a/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Rigid.Basic
import Mathlib.CategoryTheory.Monoidal.FunctorCategory
@@ -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/Rigid/OfEquivalence.lean b/Mathlib/CategoryTheory/Monoidal/Rigid/OfEquivalence.lean
index 70e84ca5c9f1d..7eb07eb856049 100644
--- a/Mathlib/CategoryTheory/Monoidal/Rigid/OfEquivalence.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Rigid/OfEquivalence.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Rigid.Basic
diff --git a/Mathlib/CategoryTheory/Monoidal/Subcategory.lean b/Mathlib/CategoryTheory/Monoidal/Subcategory.lean
index bf51655e04ec4..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
@@ -198,15 +198,16 @@ instance fullMonoidalClosedSubcategory : MonoidalClosed (FullSubcategory P) wher
{ rightAdj := FullSubcategory.lift P (fullSubcategoryInclusion P ⋙ ihom X.1)
fun Y => prop_ihom X.2 Y.2
adj :=
- Adjunction.mkOfUnitCounit
{ 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 }
- left_triangle := by ext Y; simp [FullSubcategory.comp_def, FullSubcategory.id_def]
- right_triangle := by ext Y; simp [FullSubcategory.comp_def, FullSubcategory.id_def] } }
+ 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 ↦
+ by simp [FullSubcategory.comp_def, FullSubcategory.id_def] } }
@[simp]
theorem fullMonoidalClosedSubcategory_ihom_obj (X Y : FullSubcategory P) :
diff --git a/Mathlib/CategoryTheory/Monoidal/Tor.lean b/Mathlib/CategoryTheory/Monoidal/Tor.lean
index 4f9a2de2e1361..51db95353b832 100644
--- a/Mathlib/CategoryTheory/Monoidal/Tor.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Tor.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Abelian.LeftDerived
import Mathlib.CategoryTheory.Monoidal.Preadditive
diff --git a/Mathlib/CategoryTheory/Monoidal/Transport.lean b/Mathlib/CategoryTheory/Monoidal/Transport.lean
index dd5bd2ff741f2..bda1093a68af0 100644
--- a/Mathlib/CategoryTheory/Monoidal/Transport.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Transport.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.NaturalTransformation
@@ -87,7 +87,7 @@ The functor `F` must preserve all the data parts of the monoidal structure betwe
categories.
-/
-abbrev induced [MonoidalCategoryStruct D] (F : D ⥤ C) [F.Faithful]
+def induced [MonoidalCategoryStruct D] (F : D ⥤ C) [F.Faithful]
(fData : InducingFunctorData F) :
MonoidalCategory.{v₂} D where
tensorHom_def {X₁ Y₁ X₂ Y₂} f g := F.map_injective <| by
@@ -135,7 +135,7 @@ def fromInduced [MonoidalCategoryStruct D] (F : D ⥤ C) [F.Faithful]
/-- Transport a monoidal structure along an equivalence of (plain) categories.
-/
-@[simps]
+@[simps (config := .lemmasOnly)]
def transportStruct (e : C ≌ D) : MonoidalCategoryStruct.{v₂} D where
tensorObj X Y := e.functor.obj (e.inverse.obj X ⊗ e.inverse.obj Y)
whiskerLeft X _ _ f := e.functor.map (e.inverse.obj X ◁ e.inverse.map f)
@@ -144,22 +144,23 @@ def transportStruct (e : C ≌ D) : MonoidalCategoryStruct.{v₂} D where
tensorUnit := e.functor.obj (𝟙_ C)
associator X Y Z :=
e.functor.mapIso
- (((e.unitIso.app _).symm ⊗ Iso.refl _) ≪≫
+ (whiskerRightIso (e.unitIso.app _).symm _ ≪≫
α_ (e.inverse.obj X) (e.inverse.obj Y) (e.inverse.obj Z) ≪≫
- (Iso.refl _ ⊗ e.unitIso.app _))
+ whiskerLeftIso _ (e.unitIso.app _))
leftUnitor X :=
- e.functor.mapIso (((e.unitIso.app _).symm ⊗ Iso.refl _) ≪≫ λ_ (e.inverse.obj X)) ≪≫
+ e.functor.mapIso ((whiskerRightIso (e.unitIso.app _).symm _) ≪≫ λ_ (e.inverse.obj X)) ≪≫
e.counitIso.app _
rightUnitor X :=
- e.functor.mapIso ((Iso.refl _ ⊗ (e.unitIso.app _).symm) ≪≫ ρ_ (e.inverse.obj X)) ≪≫
+ e.functor.mapIso ((whiskerLeftIso _ (e.unitIso.app _).symm) ≪≫ ρ_ (e.inverse.obj X)) ≪≫
e.counitIso.app _
+attribute [local simp] transportStruct in
/-- Transport a monoidal structure along an equivalence of (plain) categories.
-/
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/Basic.lean b/Mathlib/CategoryTheory/Monoidal/Types/Basic.lean
index 77a4726af04a5..9904eee364779 100644
--- a/Mathlib/CategoryTheory/Monoidal/Types/Basic.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Types/Basic.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Michael Jendrusch. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Michael Jendrusch, Scott Morrison
+Authors: Michael Jendrusch, Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Functor
import Mathlib.CategoryTheory.ChosenFiniteProducts
diff --git a/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean b/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean
index 633d6872c7ad0..bcc39bf0542db 100644
--- a/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Michael Jendrusch. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Michael Jendrusch, Scott Morrison
+Authors: Michael Jendrusch, Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.Types.Basic
import Mathlib.CategoryTheory.Monoidal.CoherenceLemmas
@@ -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/Monoidal/Types/Symmetric.lean b/Mathlib/CategoryTheory/Monoidal/Types/Symmetric.lean
index 69248ef1f0384..93ceaacca659f 100644
--- a/Mathlib/CategoryTheory/Monoidal/Types/Symmetric.lean
+++ b/Mathlib/CategoryTheory/Monoidal/Types/Symmetric.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Michael Jendrusch. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Michael Jendrusch, Scott Morrison
+Authors: Michael Jendrusch, Kim Morrison
-/
import Mathlib.CategoryTheory.Monoidal.OfChosenFiniteProducts.Symmetric
import Mathlib.CategoryTheory.Monoidal.Types.Basic
diff --git a/Mathlib/CategoryTheory/MorphismProperty/Basic.lean b/Mathlib/CategoryTheory/MorphismProperty/Basic.lean
index ffeef6490f80e..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
/-!
@@ -13,8 +12,11 @@ import Mathlib.Order.CompleteBooleanAlgebra
We provide the basic framework for talking about properties of morphisms.
The following meta-property is defined
-* `RespectsIso`: `P` respects isomorphisms if `P f → P (e ≫ f)` and `P f → P (f ≫ e)`, where
- `e` is an isomorphism.
+* `RespectsLeft P Q`: `P` respects the property `Q` on the left if `P f → P (i ≫ f)` where
+ `i` satisfies `Q`.
+* `RespectsRight P Q`: `P` respects the property `Q` on the right if `P f → P (f ≫ i)` where
+ `i` satisfies `Q`.
+* `Respects`: `P` respects `Q` if `P` respects `Q` both on the left and on the right.
-/
@@ -93,22 +95,79 @@ lemma monotone_map (F : C ⥤ D) :
intro P Q h X Y f ⟨X', Y', f', hf', ⟨e⟩⟩
exact ⟨X', Y', f', h _ hf', ⟨e⟩⟩
-/-- A morphism property `RespectsIso` if it still holds when composed with an isomorphism -/
-class RespectsIso (P : MorphismProperty C) : Prop where
- precomp {X Y Z} (e : X ≅ Y) (f : Y ⟶ Z) (hf : P f) : P (e.hom ≫ f)
- postcomp {X Y Z} (e : Y ≅ Z) (f : X ⟶ Y) (hf : P f) : P (f ≫ e.hom)
+/-- A morphism property `P` satisfies `P.RespectsRight Q` if it is stable under post-composition
+with morphisms satisfying `Q`, i.e. whenever `P` holds for `f` and `Q` holds for `i` then `P`
+holds for `f ≫ i`. -/
+class RespectsRight (P Q : MorphismProperty C) : Prop where
+ postcomp {X Y Z : C} (i : Y ⟶ Z) (hi : Q i) (f : X ⟶ Y) (hf : P f) : P (f ≫ i)
-instance RespectsIso.op (P : MorphismProperty C) [h : RespectsIso P] : RespectsIso P.op :=
- ⟨fun e f hf => h.2 e.unop f.unop hf, fun e f hf => h.1 e.unop f.unop hf⟩
+/-- A morphism property `P` satisfies `P.RespectsLeft Q` if it is stable under
+pre-composition with morphisms satisfying `Q`, i.e. whenever `P` holds for `f`
+and `Q` holds for `i` then `P` holds for `i ≫ f`. -/
+class RespectsLeft (P Q : MorphismProperty C) : Prop where
+ precomp {X Y Z : C} (i : X ⟶ Y) (hi : Q i) (f : Y ⟶ Z) (hf : P f) : P (i ≫ f)
-instance RespectsIso.unop (P : MorphismProperty Cᵒᵖ) [h : RespectsIso P] : RespectsIso P.unop :=
- ⟨fun e f hf => h.2 e.op f.op hf, fun e f hf => h.1 e.op f.op hf⟩
+/-- A morphism property `P` satisfies `P.Respects Q` if it is stable under composition on the
+left and right by morphisms satisfying `Q`. -/
+class Respects (P Q : MorphismProperty C) extends P.RespectsLeft Q, P.RespectsRight Q : Prop where
-/-- The intersection of two isomorphism respecting morphism properties respects isomorphisms. -/
-instance RespectsIso.inf (P Q : MorphismProperty C) [RespectsIso P] [RespectsIso Q] :
- RespectsIso (P ⊓ Q) where
- precomp e f hf := ⟨RespectsIso.precomp e f hf.left, RespectsIso.precomp e f hf.right⟩
- postcomp e f hf := ⟨RespectsIso.postcomp e f hf.left, RespectsIso.postcomp e f hf.right⟩
+instance (P Q : MorphismProperty C) [P.RespectsLeft Q] [P.RespectsRight Q] : P.Respects Q where
+
+instance (P Q : MorphismProperty C) [P.RespectsLeft Q] : P.op.RespectsRight Q.op where
+ postcomp i hi f hf := RespectsLeft.precomp (Q := Q) i.unop hi f.unop hf
+
+instance (P Q : MorphismProperty C) [P.RespectsRight Q] : P.op.RespectsLeft Q.op where
+ precomp i hi f hf := RespectsRight.postcomp (Q := Q) i.unop hi f.unop hf
+
+instance RespectsLeft.inf (P₁ P₂ Q : MorphismProperty C) [P₁.RespectsLeft Q]
+ [P₂.RespectsLeft Q] : (P₁ ⊓ P₂).RespectsLeft Q where
+ precomp i hi f hf := ⟨precomp i hi f hf.left, precomp i hi f hf.right⟩
+
+instance RespectsRight.inf (P₁ P₂ Q : MorphismProperty C) [P₁.RespectsRight Q]
+ [P₂.RespectsRight Q] : (P₁ ⊓ P₂).RespectsRight Q where
+ postcomp i hi f hf := ⟨postcomp i hi f hf.left, postcomp i hi f hf.right⟩
+
+variable (C)
+
+/-- The `MorphismProperty C` satisfied by isomorphisms in `C`. -/
+def isomorphisms : MorphismProperty C := fun _ _ f => IsIso f
+
+/-- The `MorphismProperty C` satisfied by monomorphisms in `C`. -/
+def monomorphisms : MorphismProperty C := fun _ _ f => Mono f
+
+/-- The `MorphismProperty C` satisfied by epimorphisms in `C`. -/
+def epimorphisms : MorphismProperty C := fun _ _ f => Epi f
+
+section
+
+variable {C}
+
+/-- `P` respects isomorphisms, if it respects the morphism property `isomorphisms C`, i.e.
+it is stable under pre- and postcomposition with isomorphisms. -/
+abbrev RespectsIso (P : MorphismProperty C) : Prop := P.Respects (isomorphisms C)
+
+lemma RespectsIso.mk (P : MorphismProperty C)
+ (hprecomp : ∀ {X Y Z : C} (e : X ≅ Y) (f : Y ⟶ Z) (_ : P f), P (e.hom ≫ f))
+ (hpostcomp : ∀ {X Y Z : C} (e : Y ≅ Z) (f : X ⟶ Y) (_ : P f), P (f ≫ e.hom)) :
+ P.RespectsIso where
+ precomp e (_ : IsIso e) f hf := hprecomp (asIso e) f hf
+ postcomp e (_ : IsIso e) f hf := hpostcomp (asIso e) f hf
+
+lemma RespectsIso.precomp (P : MorphismProperty C) [P.RespectsIso] {X Y Z : C} (e : X ⟶ Y)
+ [IsIso e] (f : Y ⟶ Z) (hf : P f) : P (e ≫ f) :=
+ RespectsLeft.precomp (Q := isomorphisms C) e ‹IsIso e› f hf
+
+lemma RespectsIso.postcomp (P : MorphismProperty C) [P.RespectsIso] {X Y Z : C} (e : Y ⟶ Z)
+ [IsIso e] (f : X ⟶ Y) (hf : P f) : P (f ≫ e) :=
+ RespectsRight.postcomp (Q := isomorphisms C) e ‹IsIso e› f hf
+
+instance RespectsIso.op (P : MorphismProperty C) [RespectsIso P] : RespectsIso P.op where
+ precomp e (_ : IsIso e) f hf := postcomp P e.unop f.unop hf
+ postcomp e (_ : IsIso e) f hf := precomp P e.unop f.unop hf
+
+instance RespectsIso.unop (P : MorphismProperty Cᵒᵖ) [RespectsIso P] : RespectsIso P.unop where
+ precomp e (_ : IsIso e) f hf := postcomp P e.op f.op hf
+ postcomp e (_ : IsIso e) f hf := precomp P e.op f.op hf
/-- The closure by isomorphisms of a `MorphismProperty` -/
def isoClosure (P : MorphismProperty C) : MorphismProperty C :=
@@ -119,10 +178,10 @@ lemma le_isoClosure (P : MorphismProperty C) : P ≤ P.isoClosure :=
instance isoClosure_respectsIso (P : MorphismProperty C) :
RespectsIso P.isoClosure where
- precomp := fun e f ⟨_, _, f', hf', ⟨iso⟩⟩ => ⟨_, _, f', hf',
- ⟨Arrow.isoMk (asIso iso.hom.left ≪≫ e.symm) (asIso iso.hom.right) (by simp)⟩⟩
- postcomp := fun e f ⟨_, _, f', hf', ⟨iso⟩⟩ => ⟨_, _, f', hf',
- ⟨Arrow.isoMk (asIso iso.hom.left) (asIso iso.hom.right ≪≫ e) (by simp)⟩⟩
+ precomp := fun e (he : IsIso e) f ⟨_, _, f', hf', ⟨iso⟩⟩ => ⟨_, _, f', hf',
+ ⟨Arrow.isoMk (asIso iso.hom.left ≪≫ asIso (inv e)) (asIso iso.hom.right) (by simp)⟩⟩
+ postcomp := fun e (he : IsIso e) f ⟨_, _, f', hf', ⟨iso⟩⟩ => ⟨_, _, f', hf',
+ ⟨Arrow.isoMk (asIso iso.hom.left) (asIso iso.hom.right ≪≫ asIso e) (by simp)⟩⟩
lemma monotone_isoClosure : Monotone (isoClosure (C := C)) := by
intro P Q h X Y f ⟨X', Y', f', hf', ⟨e⟩⟩
@@ -130,32 +189,33 @@ lemma monotone_isoClosure : Monotone (isoClosure (C := C)) := by
theorem cancel_left_of_respectsIso (P : MorphismProperty C) [hP : RespectsIso P] {X Y Z : C}
(f : X ⟶ Y) (g : Y ⟶ Z) [IsIso f] : P (f ≫ g) ↔ P g :=
- ⟨fun h => by simpa using hP.1 (asIso f).symm (f ≫ g) h, hP.1 (asIso f) g⟩
+ ⟨fun h => by simpa using RespectsIso.precomp P (inv f) (f ≫ g) h, RespectsIso.precomp P f g⟩
theorem cancel_right_of_respectsIso (P : MorphismProperty C) [hP : RespectsIso P] {X Y Z : C}
(f : X ⟶ Y) (g : Y ⟶ Z) [IsIso g] : P (f ≫ g) ↔ P f :=
- ⟨fun h => by simpa using hP.2 (asIso g).symm (f ≫ g) h, hP.2 (asIso g) 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 :=
P.arrow_iso_iff e
theorem RespectsIso.of_respects_arrow_iso (P : MorphismProperty C)
- (hP : ∀ (f g : Arrow C) (_ : f ≅ g) (_ : P f.hom), P g.hom) : RespectsIso P := by
- constructor
- · intro X Y Z e f hf
- refine hP (Arrow.mk f) (Arrow.mk (e.hom ≫ f)) (Arrow.isoMk e.symm (Iso.refl _) ?_) hf
- dsimp
- simp only [Iso.inv_hom_id_assoc, Category.comp_id]
- · intro X Y Z e f hf
- refine hP (Arrow.mk f) (Arrow.mk (f ≫ e.hom)) (Arrow.isoMk (Iso.refl _) e ?_) hf
- dsimp
- simp only [Category.id_comp]
+ (hP : ∀ (f g : Arrow C) (_ : f ≅ g) (_ : P f.hom), P g.hom) : RespectsIso P where
+ precomp {X Y Z} e (he : IsIso e) f hf := by
+ refine hP (Arrow.mk f) (Arrow.mk (e ≫ f)) (Arrow.isoMk (asIso (inv e)) (Iso.refl _) ?_) hf
+ simp
+ postcomp {X Y Z} e (he : IsIso e) f hf := by
+ refine hP (Arrow.mk f) (Arrow.mk (f ≫ e)) (Arrow.isoMk (Iso.refl _) (asIso e) ?_) hf
+ simp
lemma isoClosure_eq_iff (P : MorphismProperty C) :
P.isoClosure = P ↔ P.RespectsIso := by
@@ -227,12 +287,11 @@ lemma map_map (P : MorphismProperty C) (F : C ⥤ D) {E : Type*} [Category E] (G
exact map_mem_map _ _ _ (map_mem_map _ _ _ hf)
instance RespectsIso.inverseImage (P : MorphismProperty D) [RespectsIso P] (F : C ⥤ D) :
- RespectsIso (P.inverseImage F) := by
- constructor
- all_goals
- intro X Y Z e f hf
- simpa [MorphismProperty.inverseImage, cancel_left_of_respectsIso,
- cancel_right_of_respectsIso] using hf
+ RespectsIso (P.inverseImage F) where
+ precomp {X Y Z} e (he : IsIso e) f hf := by
+ simpa [MorphismProperty.inverseImage, cancel_left_of_respectsIso] using hf
+ postcomp {X Y Z} e (he : IsIso e) f hf := by
+ simpa [MorphismProperty.inverseImage, cancel_right_of_respectsIso] using hf
lemma map_eq_of_iso (P : MorphismProperty C) {F G : C ⥤ D} (e : F ≅ G) :
P.map F = P.map G := by
@@ -275,17 +334,7 @@ lemma inverseImage_map_eq_of_isEquivalence
erw [((P.map F).inverseImage_equivalence_inverse_eq_map_functor (F.asEquivalence)), map_map,
P.map_eq_of_iso F.asEquivalence.unitIso.symm, map_id]
-
-variable (C)
-
-/-- The `MorphismProperty C` satisfied by isomorphisms in `C`. -/
-def isomorphisms : MorphismProperty C := fun _ _ f => IsIso f
-
-/-- The `MorphismProperty C` satisfied by monomorphisms in `C`. -/
-def monomorphisms : MorphismProperty C := fun _ _ f => Mono f
-
-/-- The `MorphismProperty C` satisfied by epimorphisms in `C`. -/
-def epimorphisms : MorphismProperty C := fun _ _ f => Epi f
+end
section
@@ -313,21 +362,21 @@ theorem epimorphisms.infer_property [hf : Epi f] : (epimorphisms C) f :=
end
instance RespectsIso.monomorphisms : RespectsIso (monomorphisms C) := by
- constructor <;>
+ apply RespectsIso.mk <;>
· intro X Y Z e f
simp only [monomorphisms.iff]
intro
apply mono_comp
instance RespectsIso.epimorphisms : RespectsIso (epimorphisms C) := by
- constructor <;>
+ apply RespectsIso.mk <;>
· intro X Y Z e f
simp only [epimorphisms.iff]
intro
apply epi_comp
instance RespectsIso.isomorphisms : RespectsIso (isomorphisms C) := by
- constructor <;>
+ apply RespectsIso.mk <;>
· intro X Y Z e f
simp only [isomorphisms.iff]
intro
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 056a5add8631c..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 :=
@@ -91,9 +108,9 @@ theorem StableUnderInverse.unop {P : MorphismProperty Cᵒᵖ} (h : StableUnderI
theorem respectsIso_of_isStableUnderComposition {P : MorphismProperty C}
[P.IsStableUnderComposition] (hP : isomorphisms C ≤ P) :
- RespectsIso P :=
- ⟨fun _ _ hf => P.comp_mem _ _ (hP _ (isomorphisms.infer_property _)) hf,
- fun _ _ hf => P.comp_mem _ _ hf (hP _ (isomorphisms.infer_property _))⟩
+ RespectsIso P := RespectsIso.mk _
+ (fun _ _ hf => P.comp_mem _ _ (hP _ (isomorphisms.infer_property _)) hf)
+ (fun _ _ hf => P.comp_mem _ _ hf (hP _ (isomorphisms.infer_property _)))
instance IsStableUnderComposition.inverseImage {P : MorphismProperty D} [P.IsStableUnderComposition]
(F : C ⥤ D) : (P.inverseImage F).IsStableUnderComposition where
@@ -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 e41f911a77318..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
@@ -225,7 +235,7 @@ theorem diagonal_iff {X Y : C} {f : X ⟶ Y} : P.diagonal f ↔ P (pullback.diag
Iff.rfl
instance RespectsIso.diagonal [P.RespectsIso] : P.diagonal.RespectsIso := by
- constructor
+ apply RespectsIso.mk
· introv H
rwa [diagonal_iff, pullback.diagonal_comp, P.cancel_left_of_respectsIso,
P.cancel_left_of_respectsIso, ← P.cancel_right_of_respectsIso _
@@ -260,7 +270,7 @@ def universally (P : MorphismProperty C) : MorphismProperty C := fun X Y f =>
∀ ⦃X' Y' : C⦄ (i₁ : X' ⟶ X) (i₂ : Y' ⟶ Y) (f' : X' ⟶ Y') (_ : IsPullback f' i₁ i₂ f), P f'
instance universally_respectsIso (P : MorphismProperty C) : P.universally.RespectsIso := by
- constructor
+ apply RespectsIso.mk
· intro X Y Z e f hf X' Z' i₁ i₂ f' H
have : IsPullback (𝟙 _) (i₁ ≫ e.hom) i₁ e.inv :=
IsPullback.of_horiz_isIso
diff --git a/Mathlib/CategoryTheory/MorphismProperty/Representable.lean b/Mathlib/CategoryTheory/MorphismProperty/Representable.lean
index ba9ba8a06a053..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), ?_⟩
@@ -280,12 +284,146 @@ instance isMultiplicative : IsMultiplicative F.relativelyRepresentable where
lemma stableUnderBaseChange : StableUnderBaseChange F.relativelyRepresentable := by
intro X Y Y' X' f g f' g' P₁ hg a h
refine ⟨hg.pullback (h ≫ f), hg.snd (h ≫ f), ?_, ?_⟩
- apply P₁.lift (hg.fst (h ≫ f)) (F.map (hg.snd (h ≫ f)) ≫ h) (by simpa using hg.w (h ≫ f))
- apply IsPullback.of_right' (hg.isPullback (h ≫ f)) P₁
+ · apply P₁.lift (hg.fst (h ≫ f)) (F.map (hg.snd (h ≫ f)) ≫ h) (by simpa using hg.w (h ≫ f))
+ · apply IsPullback.of_right' (hg.isPullback (h ≫ f)) P₁
instance respectsIso : RespectsIso F.relativelyRepresentable :=
(stableUnderBaseChange F).respectsIso
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/NatIso.lean b/Mathlib/CategoryTheory/NatIso.lean
index f90d1af88c7d0..2899c82c95db6 100644
--- a/Mathlib/CategoryTheory/NatIso.lean
+++ b/Mathlib/CategoryTheory/NatIso.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Tim Baumann, Stephen Morgan, Scott Morrison, Floris van Doorn
+Authors: Tim Baumann, Stephen Morgan, Kim Morrison, Floris van Doorn
-/
import Mathlib.CategoryTheory.Functor.Category
import Mathlib.CategoryTheory.Iso
diff --git a/Mathlib/CategoryTheory/NatTrans.lean b/Mathlib/CategoryTheory/NatTrans.lean
index 52013eb207f12..af2c4079f9b36 100644
--- a/Mathlib/CategoryTheory/NatTrans.lean
+++ b/Mathlib/CategoryTheory/NatTrans.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Tim Baumann, Stephen Morgan, Scott Morrison, Floris van Doorn
+Authors: Tim Baumann, Stephen Morgan, Kim Morrison, Floris van Doorn
-/
import Mathlib.Tactic.CategoryTheory.Reassoc
@@ -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/Noetherian.lean b/Mathlib/CategoryTheory/Noetherian.lean
index 1065af138e416..6b7a78e563ca6 100644
--- a/Mathlib/CategoryTheory/Noetherian.lean
+++ b/Mathlib/CategoryTheory/Noetherian.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Subobject.Lattice
import Mathlib.CategoryTheory.EssentiallySmall
diff --git a/Mathlib/CategoryTheory/Opposites.lean b/Mathlib/CategoryTheory/Opposites.lean
index 901fde4a2fdcc..8cb8e3e027660 100644
--- a/Mathlib/CategoryTheory/Opposites.lean
+++ b/Mathlib/CategoryTheory/Opposites.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison
+Authors: Stephen Morgan, Kim Morrison
-/
import Mathlib.CategoryTheory.Equivalence
@@ -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/PEmpty.lean b/Mathlib/CategoryTheory/PEmpty.lean
index 3f12752eb7f34..ee9546dc04437 100644
--- a/Mathlib/CategoryTheory/PEmpty.lean
+++ b/Mathlib/CategoryTheory/PEmpty.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.DiscreteCategory
diff --git a/Mathlib/CategoryTheory/PUnit.lean b/Mathlib/CategoryTheory/PUnit.lean
index 2f3d7472d33df..840d3c4759134 100644
--- a/Mathlib/CategoryTheory/PUnit.lean
+++ b/Mathlib/CategoryTheory/PUnit.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Functor.Const
import Mathlib.CategoryTheory.DiscreteCategory
@@ -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 126b988e6f0c5..5901349a1ccbd 100644
--- a/Mathlib/CategoryTheory/PathCategory.lean
+++ b/Mathlib/CategoryTheory/PathCategory/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott 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 caa1341b3caf6..477e2fe2a21e5 100644
--- a/Mathlib/CategoryTheory/Pi/Basic.lean
+++ b/Mathlib/CategoryTheory/Pi/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Simon Hudon, Scott Morrison
+Authors: Simon Hudon, Kim Morrison
-/
import Mathlib.CategoryTheory.EqToHom
import Mathlib.CategoryTheory.NatIso
@@ -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/AdditiveFunctor.lean b/Mathlib/CategoryTheory/Preadditive/AdditiveFunctor.lean
index 1a22be0cc03ff..0dd92b9817e6a 100644
--- a/Mathlib/CategoryTheory/Preadditive/AdditiveFunctor.lean
+++ b/Mathlib/CategoryTheory/Preadditive/AdditiveFunctor.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2021 Adam Topaz. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Adam Topaz, Scott Morrison
+Authors: Adam Topaz, Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.ExactFunctor
import Mathlib.CategoryTheory.Limits.Preserves.Finite
@@ -69,6 +69,8 @@ instance : Additive (𝟭 C) where
instance {E : Type*} [Category E] [Preadditive E] (G : D ⥤ E) [Functor.Additive G] :
Additive (F ⋙ G) where
+instance {J : Type*} [Category J] (j : J) : ((evaluation J C).obj j).Additive where
+
@[simp]
theorem map_neg {X Y : C} {f : X ⟶ Y} : F.map (-f) = -F.map f :=
(F.mapAddHom : (X ⟶ Y) →+ (F.obj X ⟶ F.obj Y)).map_neg _
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/Biproducts.lean b/Mathlib/CategoryTheory/Preadditive/Biproducts.lean
index 095fb3ea4d5cf..5b06f3702ea3b 100644
--- a/Mathlib/CategoryTheory/Preadditive/Biproducts.lean
+++ b/Mathlib/CategoryTheory/Preadditive/Biproducts.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Ext
import Mathlib.CategoryTheory.Limits.Shapes.Biproducts
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/HomOrthogonal.lean b/Mathlib/CategoryTheory/Preadditive/HomOrthogonal.lean
index 4ff63ae23affb..4dfeacbfed5e2 100644
--- a/Mathlib/CategoryTheory/Preadditive/HomOrthogonal.lean
+++ b/Mathlib/CategoryTheory/Preadditive/HomOrthogonal.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Linear.Basic
import Mathlib.CategoryTheory.Preadditive.Biproducts
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 4c932bdd5de89..8744f1317727f 100644
--- a/Mathlib/CategoryTheory/Preadditive/InjectiveResolution.lean
+++ b/Mathlib/CategoryTheory/Preadditive/InjectiveResolution.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2022 Jujian Zhang. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Jujian Zhang, Scott Morrison, Joël Riou
+Authors: Jujian Zhang, Kim Morrison, Joël Riou
-/
import Mathlib.Algebra.Homology.QuasiIso
import Mathlib.Algebra.Homology.ShortComplex.HomologicalComplex
@@ -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 8d93ea7d3ea5b..8ab0b6f6a6063 100644
--- a/Mathlib/CategoryTheory/Preadditive/Mat.lean
+++ b/Mathlib/CategoryTheory/Preadditive/Mat.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.BigOperators.Group.Finset
import Mathlib.Algebra.BigOperators.Pi
@@ -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
@@ -184,11 +183,11 @@ instance hasFiniteBiproducts : HasFiniteBiproducts (Mat_ C) where
ext x y
dsimp
simp_rw [dite_comp, comp_dite]
- simp only [ite_self, dite_eq_ite, dif_ctx_congr, Limits.comp_zero, Limits.zero_comp,
+ simp only [ite_self, dite_eq_ite, Limits.comp_zero, Limits.zero_comp,
eqToHom_trans, Finset.sum_congr]
erw [Finset.sum_sigma]
dsimp
- simp only [if_congr, if_true, dif_ctx_congr, Finset.sum_dite_irrel, Finset.mem_univ,
+ simp only [if_true, Finset.sum_dite_irrel, Finset.mem_univ,
Finset.sum_const_zero, Finset.sum_congr, Finset.sum_dite_eq']
split_ifs with h h'
· substs h 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/Opposite.lean b/Mathlib/CategoryTheory/Preadditive/Opposite.lean
index ccc1021d809aa..115a2764163aa 100644
--- a/Mathlib/CategoryTheory/Preadditive/Opposite.lean
+++ b/Mathlib/CategoryTheory/Preadditive/Opposite.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Adam Topaz, Johan Commelin, Joël Riou
+Authors: Kim Morrison, Adam Topaz, Johan Commelin, Joël Riou
-/
import Mathlib.CategoryTheory.Preadditive.AdditiveFunctor
import Mathlib.Logic.Equiv.TransferInstance
diff --git a/Mathlib/CategoryTheory/Preadditive/Projective.lean b/Mathlib/CategoryTheory/Preadditive/Projective.lean
index 6cf35147c2231..c593644a263b3 100644
--- a/Mathlib/CategoryTheory/Preadditive/Projective.lean
+++ b/Mathlib/CategoryTheory/Preadditive/Projective.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Scott Morrison
+Authors: Markus Himmel, Kim Morrison
-/
import Mathlib.CategoryTheory.Adjunction.FullyFaithful
import Mathlib.CategoryTheory.Adjunction.Limits
@@ -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 8d947ea5ca55e..51a7ef3dae857 100644
--- a/Mathlib/CategoryTheory/Preadditive/ProjectiveResolution.lean
+++ b/Mathlib/CategoryTheory/Preadditive/ProjectiveResolution.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Joël Riou
+Authors: Kim Morrison, Joël Riou
-/
import Mathlib.Algebra.Homology.QuasiIso
import Mathlib.Algebra.Homology.SingleHomology
@@ -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 5e012592ab269..9c571b370957f 100644
--- a/Mathlib/CategoryTheory/Preadditive/Schur.lean
+++ b/Mathlib/CategoryTheory/Preadditive/Schur.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Scott Morrison
+Authors: Markus Himmel, Kim Morrison
-/
import Mathlib.Algebra.Group.Ext
import Mathlib.CategoryTheory.Simple
@@ -66,11 +66,11 @@ 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 FiniteDimensional
+open Module
section
diff --git a/Mathlib/CategoryTheory/Preadditive/SingleObj.lean b/Mathlib/CategoryTheory/Preadditive/SingleObj.lean
index da6a0ed13304f..a2b5d1a38ddaf 100644
--- a/Mathlib/CategoryTheory/Preadditive/SingleObj.lean
+++ b/Mathlib/CategoryTheory/Preadditive/SingleObj.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Preadditive.Basic
import Mathlib.CategoryTheory.SingleObj
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/Preadditive/Yoneda/Injective.lean b/Mathlib/CategoryTheory/Preadditive/Yoneda/Injective.lean
index d50174be5c41c..778a344fe5bbd 100644
--- a/Mathlib/CategoryTheory/Preadditive/Yoneda/Injective.lean
+++ b/Mathlib/CategoryTheory/Preadditive/Yoneda/Injective.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Scott Morrison
+Authors: Markus Himmel, Kim Morrison
-/
import Mathlib.CategoryTheory.Preadditive.Yoneda.Basic
import Mathlib.CategoryTheory.Preadditive.Injective
diff --git a/Mathlib/CategoryTheory/Preadditive/Yoneda/Projective.lean b/Mathlib/CategoryTheory/Preadditive/Yoneda/Projective.lean
index 2434e2bdb0a20..3db3048dcfe74 100644
--- a/Mathlib/CategoryTheory/Preadditive/Yoneda/Projective.lean
+++ b/Mathlib/CategoryTheory/Preadditive/Yoneda/Projective.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Scott Morrison
+Authors: Markus Himmel, Kim Morrison
-/
import Mathlib.CategoryTheory.Preadditive.Yoneda.Basic
import Mathlib.CategoryTheory.Preadditive.Projective
diff --git a/Mathlib/CategoryTheory/Products/Associator.lean b/Mathlib/CategoryTheory/Products/Associator.lean
index 232fe7f3c5ea2..041ecf6548890 100644
--- a/Mathlib/CategoryTheory/Products/Associator.lean
+++ b/Mathlib/CategoryTheory/Products/Associator.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison
+Authors: Stephen Morgan, Kim Morrison
-/
import Mathlib.CategoryTheory.Products.Basic
diff --git a/Mathlib/CategoryTheory/Products/Basic.lean b/Mathlib/CategoryTheory/Products/Basic.lean
index 449595eab85d3..3abbf24a0925d 100644
--- a/Mathlib/CategoryTheory/Products/Basic.lean
+++ b/Mathlib/CategoryTheory/Products/Basic.lean
@@ -1,9 +1,8 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison
+Authors: Stephen Morgan, Kim Morrison
-/
-import Mathlib.CategoryTheory.EqToHom
import Mathlib.CategoryTheory.Functor.Const
import Mathlib.CategoryTheory.Opposites
import Mathlib.Data.Prod.Basic
@@ -46,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) :=
@@ -172,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`.
@@ -194,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
@@ -220,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
@@ -296,7 +300,44 @@ end Equivalence
/-- `F.flip` composed with evaluation is the same as evaluating `F`. -/
@[simps!]
def flipCompEvaluation (F : A ⥤ B ⥤ C) (a) : F.flip ⋙ (evaluation _ _).obj a ≅ F.obj a :=
- NatIso.ofComponents fun b => eqToIso rfl
+ NatIso.ofComponents fun b => Iso.refl _
+
+theorem flip_comp_evaluation (F : A ⥤ B ⥤ C) (a) : F.flip ⋙ (evaluation _ _).obj a = F.obj a :=
+ rfl
+
+/-- `F` composed with evaluation is the same as evaluating `F.flip`. -/
+@[simps!]
+def compEvaluation (F : A ⥤ B ⥤ C) (b) : F ⋙ (evaluation _ _).obj b ≅ F.flip.obj b :=
+ NatIso.ofComponents fun a => Iso.refl _
+
+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)
diff --git a/Mathlib/CategoryTheory/Products/Bifunctor.lean b/Mathlib/CategoryTheory/Products/Bifunctor.lean
index 70e02805ce5ac..a0d335eb00794 100644
--- a/Mathlib/CategoryTheory/Products/Bifunctor.lean
+++ b/Mathlib/CategoryTheory/Products/Bifunctor.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison
+Authors: Stephen Morgan, Kim Morrison
-/
import Mathlib.CategoryTheory.Products.Basic
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 d830b0b79c97d..889c3bf069f82 100644
--- a/Mathlib/CategoryTheory/Shift/Basic.lean
+++ b/Mathlib/CategoryTheory/Shift/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott 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/Simple.lean b/Mathlib/CategoryTheory/Simple.lean
index 3545546a51b0b..619a1bdfe7847 100644
--- a/Mathlib/CategoryTheory/Simple.lean
+++ b/Mathlib/CategoryTheory/Simple.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Scott Morrison
+Authors: Markus Himmel, Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Shapes.ZeroMorphisms
import Mathlib.CategoryTheory.Limits.Shapes.Kernels
diff --git a/Mathlib/CategoryTheory/Sites/Adjunction.lean b/Mathlib/CategoryTheory/Sites/Adjunction.lean
index ea5006f943253..334681a5529d0 100644
--- a/Mathlib/CategoryTheory/Sites/Adjunction.lean
+++ b/Mathlib/CategoryTheory/Sites/Adjunction.lean
@@ -84,8 +84,12 @@ lemma preservesSheafification_of_adjunction (adj : G ⊣ F) :
convert (((adj.whiskerRight Cᵒᵖ).homEquiv Q R).trans
(hf.homEquiv (R ⋙ F) ((sheafCompose J F).obj ⟨R, hR⟩).cond)).bijective
ext g X
- dsimp [Adjunction.whiskerRight, Adjunction.mkOfUnitCounit]
- simp
+ -- The rest of this proof was
+ -- `dsimp [Adjunction.whiskerRight, Adjunction.mkOfUnitCounit]; simp` before #16317.
+ dsimp
+ rw [← NatTrans.comp_app]
+ congr
+ exact Adjunction.homEquiv_naturality_left _ _ _
instance [G.IsLeftAdjoint] : J.PreservesSheafification G :=
preservesSheafification_of_adjunction J (Adjunction.ofIsLeftAdjoint G)
@@ -110,8 +114,7 @@ theorem adjunctionToTypes_unit_app_val {G : Type max v₁ u₁ ⥤ D} (adj : G
((adjunctionToTypes J adj).unit.app Y).val =
(adj.whiskerRight _).unit.app ((sheafOfTypesToPresheaf J).obj Y) ≫
whiskerRight (toSheafify J _) (forget D) := by
- dsimp [adjunctionToTypes, Adjunction.comp]
- simp
+ simp [adjunctionToTypes]
rfl
@[simp]
@@ -120,14 +123,8 @@ theorem adjunctionToTypes_counit_app_val {G : Type max v₁ u₁ ⥤ D} (adj : G
((adjunctionToTypes J adj).counit.app X).val =
sheafifyLift J ((Functor.associator _ _ _).hom ≫ (adj.whiskerRight _).counit.app _) X.2 := by
apply sheafifyLift_unique
- dsimp only [adjunctionToTypes, Adjunction.comp, NatTrans.comp_app,
- instCategorySheaf_comp_val, instCategorySheaf_id_val]
- rw [adjunction_counit_app_val]
- erw [Category.id_comp, sheafifyMap_sheafifyLift, toSheafify_sheafifyLift]
ext
- dsimp [sheafEquivSheafOfTypes, Equivalence.symm, Equivalence.toAdjunction,
- NatIso.ofComponents, Adjunction.whiskerRight, Adjunction.mkOfUnitCounit]
- simp
+ simp [adjunctionToTypes, sheafEquivSheafOfTypes, Equivalence.symm]
instance [(forget D).IsRightAdjoint] :
(sheafForget.{_, _, _, _, max u₁ v₁} (D := D) J).IsRightAdjoint :=
diff --git a/Mathlib/CategoryTheory/Sites/Canonical.lean b/Mathlib/CategoryTheory/Sites/Canonical.lean
index 9c6a4291a3191..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
@@ -203,7 +201,7 @@ theorem isSheaf_yoneda_obj (X : C) : Presieve.IsSheaf (canonicalTopology C) (yon
fun _ _ hS => sheaf_for_finestTopology _ (Set.mem_range_self _) _ hS
/-- A representable functor is a sheaf for the canonical topology. -/
-theorem isSheaf_of_representable (P : Cᵒᵖ ⥤ Type v) [P.Representable] :
+theorem isSheaf_of_isRepresentable (P : Cᵒᵖ ⥤ Type v) [P.IsRepresentable] :
Presieve.IsSheaf (canonicalTopology C) P :=
Presieve.isSheaf_iso (canonicalTopology C) P.reprW (isSheaf_yoneda_obj _)
@@ -224,9 +222,9 @@ theorem of_yoneda_isSheaf (J : GrothendieckTopology C)
apply h)
/-- If `J` is subcanonical, then any representable is a `J`-sheaf. -/
-theorem isSheaf_of_representable {J : GrothendieckTopology C} (hJ : Subcanonical J)
- (P : Cᵒᵖ ⥤ Type v) [P.Representable] : Presieve.IsSheaf J P :=
- Presieve.isSheaf_of_le _ hJ (Sheaf.isSheaf_of_representable P)
+theorem isSheaf_of_isRepresentable {J : GrothendieckTopology C} (hJ : Subcanonical J)
+ (P : Cᵒᵖ ⥤ Type v) [P.IsRepresentable] : Presieve.IsSheaf J P :=
+ Presieve.isSheaf_of_le _ hJ (Sheaf.isSheaf_of_isRepresentable P)
variable {J}
@@ -238,7 +236,7 @@ into the sheaf category.
def yoneda (hJ : Subcanonical J) : C ⥤ Sheaf J (Type v) where
obj X := ⟨CategoryTheory.yoneda.obj X, by
rw [isSheaf_iff_isSheaf_of_type]
- apply hJ.isSheaf_of_representable⟩
+ apply hJ.isSheaf_of_isRepresentable⟩
map f := ⟨CategoryTheory.yoneda.map f⟩
variable (hJ : Subcanonical J)
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/Coherent/SheafComparison.lean b/Mathlib/CategoryTheory/Sites/Coherent/SheafComparison.lean
index 7f2817071b11a..a20deb1ceff5d 100644
--- a/Mathlib/CategoryTheory/Sites/Coherent/SheafComparison.lean
+++ b/Mathlib/CategoryTheory/Sites/Coherent/SheafComparison.lean
@@ -85,7 +85,15 @@ lemma eq_induced : haveI := F.reflects_precoherent
instance : haveI := F.reflects_precoherent;
F.IsDenseSubsite (coherentTopology C) (coherentTopology D) where
- functorPushforward_mem_iff := by simp_rw [eq_induced F]; rfl
+ functorPushforward_mem_iff := by
+ rw [eq_induced F]
+ #adaptation_note
+ /--
+ This proof used to be `rfl`,
+ but has been temporarily broken by https://github.com/leanprover/lean4/pull/5329.
+ It can hopefully be restored after https://github.com/leanprover/lean4/pull/5359
+ -/
+ exact Iff.rfl
lemma coverPreserving : haveI := F.reflects_precoherent
CoverPreserving (coherentTopology _) (coherentTopology _) F :=
@@ -181,7 +189,15 @@ lemma eq_induced : haveI := F.reflects_preregular
instance : haveI := F.reflects_preregular;
F.IsDenseSubsite (regularTopology C) (regularTopology D) where
- functorPushforward_mem_iff := by simp_rw [eq_induced F]; rfl
+ functorPushforward_mem_iff := by
+ rw [eq_induced F]
+ #adaptation_note
+ /--
+ This proof used to be `rfl`,
+ but has been temporarily broken by https://github.com/leanprover/lean4/pull/5329.
+ It can hopefully be restored after https://github.com/leanprover/lean4/pull/5359
+ -/
+ exact Iff.rfl
lemma coverPreserving : haveI := F.reflects_preregular
CoverPreserving (regularTopology _) (regularTopology _) F :=
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 6e0ca7b270af8..a300122560b4c 100644
--- a/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean
+++ b/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean
@@ -25,13 +25,8 @@ it is an isomorphism.
* `Sheaf.isConstant_iff_of_equivalence` : The property of a sheaf of being constant is invariant
under equivalence of sheaf categories.
-* `Sheaf.isConstant_iff_forget` : Given a "forgetful" functor `U : D ⥤ B` a sheaf `F : Sheaf J D` is
+* `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
@@ -44,18 +39,17 @@ variable (D : Type*) [Category D]
/-- The constant presheaf functor is left adjoint to evaluation at a terminal object. -/
@[simps! unit_app counit_app_app]
noncomputable def constantPresheafAdj {T : C} (hT : IsTerminal T) :
- Functor.const Cᵒᵖ ⊣ (evaluation Cᵒᵖ D).obj (op T) :=
- Adjunction.mkOfUnitCounit {
- unit := (Functor.constCompEvaluationObj D (op T)).hom
- counit := {
- app := fun F => {
- app := fun ⟨X⟩ => F.map (IsTerminal.from hT X).op
- naturality := fun _ _ _ => by
- simp only [Functor.comp_obj, Functor.const_obj_obj, Functor.id_obj, Functor.const_obj_map,
- Category.id_comp, ← Functor.map_comp]
- congr
- simp }
- naturality := by intros; ext; simp /- Note: `aesop` works but is kind of slow -/ } }
+ Functor.const Cᵒᵖ ⊣ (evaluation Cᵒᵖ D).obj (op T) where
+ unit := (Functor.constCompEvaluationObj D (op T)).hom
+ counit := {
+ app := fun F => {
+ app := fun ⟨X⟩ => F.map (IsTerminal.from hT X).op
+ naturality := fun _ _ _ => by
+ simp only [Functor.comp_obj, Functor.const_obj_obj, Functor.id_obj, Functor.const_obj_map,
+ Category.id_comp, ← Functor.map_comp]
+ congr
+ simp }
+ naturality := by intros; ext; simp /- Note: `aesop` works but is kind of slow -/ }
variable [HasWeakSheafify J D]
@@ -178,7 +172,7 @@ variable {B : Type*} [Category B] (U : D ⥤ B) [HasWeakSheafify J B]
[J.PreservesSheafification U] [J.HasSheafCompose U] (F : Sheaf J D)
/--
-The constant sheaf functor commutes with `sheafCompose J U` up to isomorphism, provided that `U`
+The constant sheaf functor commutes with `sheafCompose J U` up to isomorphism, provided that `U`
preserves sheafification.
-/
noncomputable def constantCommuteCompose :
@@ -190,7 +184,7 @@ noncomputable def constantCommuteCompose :
lemma constantCommuteCompose_hom_app_val (X : D) : ((constantCommuteCompose J U).hom.app X).val =
(sheafifyComposeIso J U ((const Cᵒᵖ).obj X)).inv ≫ sheafifyMap J (constComp Cᵒᵖ X U).hom := rfl
-/-- The counit of `constantSheafAdj` factors through the isomorphism `constantCommuteCompose`. -/
+/-- The counit of `constantSheafAdj` factors through the isomorphism `constantCommuteCompose`. -/
lemma constantSheafAdj_counit_w {T : C} (hT : IsTerminal T) :
((constantCommuteCompose J U).hom.app (F.val.obj ⟨T⟩)) ≫
((constantSheafAdj J B hT).counit.app ((sheafCompose J U).obj F)) =
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 3e453496f9a9d..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,10 +260,21 @@ 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 ?_ _ _ ?_
- · rfl
+ · #adaptation_note
+ /--
+ This proof used to be `rfl`,
+ but has been temporarily broken by https://github.com/leanprover/lean4/pull/5329.
+ It can hopefully be restored after https://github.com/leanprover/lean4/pull/5359
+ -/
+ exact Iff.rfl
· exact _root_.isGLB_sInf _
/-- Construct a complete lattice from the `Inf`, but make the trivial and discrete topologies
@@ -317,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'⟩
@@ -349,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⟩
@@ -388,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 5d9ab1ddb8a9c..289d2db4e05a6 100644
--- a/Mathlib/CategoryTheory/Sites/LocallySurjective.lean
+++ b/Mathlib/CategoryTheory/Sites/LocallySurjective.lean
@@ -60,7 +60,7 @@ theorem imageSieve_whisker_forget {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) {U : C} (s
theorem imageSieve_app {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) {U : C} (s : F.obj (op U)) :
imageSieve f (f.app _ s) = ⊤ := by
ext V i
- simp only [Sieve.top_apply, iff_true_iff, imageSieve_apply]
+ simp only [Sieve.top_apply, iff_true, imageSieve_apply]
have := elementwise_of% (f.naturality i.op)
exact ⟨F.map i.op s, this s⟩
@@ -93,8 +93,8 @@ 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,
- Set.top_eq_univ, Set.mem_univ, iff_true_iff]
+ 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 _⟩⟩
theorem isLocallySurjective_iff_imagePresheaf_sheafify_eq_top' {F G : Cᵒᵖ ⥤ Type w} (f : F ⟶ G) :
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 0c06b432214bf..66591c5a8f117 100644
--- a/Mathlib/CategoryTheory/Sites/Sieves.lean
+++ b/Mathlib/CategoryTheory/Sites/Sieves.lean
@@ -3,11 +3,8 @@ 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.CategoryTheory.Comma.Over
-import Mathlib.CategoryTheory.Limits.Shapes.Pullback.HasPullback
-import Mathlib.CategoryTheory.Yoneda
import Mathlib.Data.Set.Lattice
-import Mathlib.Order.CompleteLattice
+import Mathlib.CategoryTheory.Limits.Shapes.Pullback.HasPullback
/-!
# Theory of sieves
@@ -134,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
@@ -148,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
@@ -271,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 _⟩
@@ -283,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₂]
@@ -298,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 _ _ => ⟨⟩ }
@@ -311,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
@@ -366,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]⟩
@@ -374,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⟩
@@ -474,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]
@@ -510,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) :
@@ -771,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 _ :=
@@ -810,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 3731eadbee58d..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 =>
@@ -118,7 +118,7 @@ theorem Subpresheaf.eq_top_iff_isIso : G = ⊤ ↔ IsIso G.ι := by
infer_instance
· intro H
ext U x
- apply iff_true_iff.mpr
+ apply (iff_of_eq (iff_true _)).mpr
rw [← IsIso.inv_hom_id_apply (G.ι.app U) x]
exact ((inv (G.ι.app U)) x).2
@@ -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 3260b8eb2fa9b..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
@@ -294,19 +294,17 @@ end
variable {C}
/-- An adjunction between thin categories gives an adjunction between their thin skeletons. -/
-def lowerAdjunction (R : D ⥤ C) (L : C ⥤ D) (h : L ⊣ R) : ThinSkeleton.map L ⊣ ThinSkeleton.map R :=
- Adjunction.mkOfUnitCounit
- { unit :=
- {
- app := fun X => by
- letI := isIsomorphicSetoid C
- exact Quotient.recOnSubsingleton X fun x => homOfLE ⟨h.unit.app x⟩ }
+def lowerAdjunction (R : D ⥤ C) (L : C ⥤ D) (h : L ⊣ R) :
+ ThinSkeleton.map L ⊣ ThinSkeleton.map R where
+ unit :=
+ { app := fun X => by
+ letI := isIsomorphicSetoid C
+ exact Quotient.recOnSubsingleton X fun x => homOfLE ⟨h.unit.app x⟩ }
-- TODO: make quotient.rec_on_subsingleton' so the letI isn't needed
- counit :=
- {
- app := fun X => by
- letI := isIsomorphicSetoid D
- exact Quotient.recOnSubsingleton X fun x => homOfLE ⟨h.counit.app x⟩ } }
+ counit :=
+ { app := fun X => by
+ letI := isIsomorphicSetoid D
+ exact Quotient.recOnSubsingleton X fun x => homOfLE ⟨h.counit.app x⟩ }
end ThinSkeleton
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 4e9947245dd1b..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₂ 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
@@ -148,7 +160,7 @@ attribute [simp, reassoc] natTrans_app_zero
def id : Hom iter₁ iter₁ where
natTrans := 𝟙 _
-variable {iter₁ iter₂ iter₃}
+variable {iter₁ iter₂}
-- Note: this is not made a global ext lemma because it is shown below
-- that the type of morphisms is a subsingleton.
@@ -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 076606a7a3d8f..3afc05fb08654 100644
--- a/Mathlib/CategoryTheory/Subobject/Basic.lean
+++ b/Mathlib/CategoryTheory/Subobject/Basic.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Bhavik Mehta. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Bhavik Mehta, Scott Morrison
+Authors: Bhavik Mehta, Kim Morrison
-/
import Mathlib.CategoryTheory.Subobject.MonoOver
import Mathlib.CategoryTheory.Skeletal
@@ -45,7 +45,7 @@ See also
## Notes
This development originally appeared in Bhavik Mehta's "Topos theory for Lean" repository,
-and was ported to mathlib by Scott Morrison.
+and was ported to mathlib by Kim Morrison.
### Implementation note
@@ -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/FactorThru.lean b/Mathlib/CategoryTheory/Subobject/FactorThru.lean
index 5ad249474de0f..d4f891f44b528 100644
--- a/Mathlib/CategoryTheory/Subobject/FactorThru.lean
+++ b/Mathlib/CategoryTheory/Subobject/FactorThru.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Bhavik Mehta, Scott Morrison
+Authors: Bhavik Mehta, Kim Morrison
-/
import Mathlib.CategoryTheory.Subobject.Basic
import Mathlib.CategoryTheory.Preadditive.Basic
diff --git a/Mathlib/CategoryTheory/Subobject/Lattice.lean b/Mathlib/CategoryTheory/Subobject/Lattice.lean
index 757a945d39a57..9fb683c1d2eaf 100644
--- a/Mathlib/CategoryTheory/Subobject/Lattice.lean
+++ b/Mathlib/CategoryTheory/Subobject/Lattice.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Bhavik Mehta, Scott Morrison
+Authors: Bhavik Mehta, Kim Morrison
-/
import Mathlib.CategoryTheory.Functor.Currying
import Mathlib.CategoryTheory.Subobject.FactorThru
diff --git a/Mathlib/CategoryTheory/Subobject/Limits.lean b/Mathlib/CategoryTheory/Subobject/Limits.lean
index 33f569c9bc1cc..32719bd80347c 100644
--- a/Mathlib/CategoryTheory/Subobject/Limits.lean
+++ b/Mathlib/CategoryTheory/Subobject/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Bhavik Mehta, Scott Morrison
+Authors: Bhavik Mehta, Kim Morrison
-/
import Mathlib.CategoryTheory.Subobject.Lattice
@@ -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 64cdb298ffa8e..85e334fd857b6 100644
--- a/Mathlib/CategoryTheory/Subobject/MonoOver.lean
+++ b/Mathlib/CategoryTheory/Subobject/MonoOver.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Bhavik Mehta. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Bhavik Mehta, Scott Morrison
+Authors: Bhavik Mehta, Kim Morrison
-/
import Mathlib.CategoryTheory.Adjunction.Over
import Mathlib.CategoryTheory.Adjunction.Reflective
@@ -28,7 +28,7 @@ and prove their basic properties and relationships.
## Notes
This development originally appeared in Bhavik Mehta's "Topos theory for Lean" repository,
-and was ported to mathlib by Scott Morrison.
+and was ported to mathlib by Kim Morrison.
-/
@@ -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 54ebdb2816d00..9cc556ebe11f3 100644
--- a/Mathlib/CategoryTheory/Subobject/Types.lean
+++ b/Mathlib/CategoryTheory/Subobject/Types.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Subobject.WellPowered
import Mathlib.CategoryTheory.Types
@@ -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/Subobject/WellPowered.lean b/Mathlib/CategoryTheory/Subobject/WellPowered.lean
index 0a78979b8a9d0..399d029fc1211 100644
--- a/Mathlib/CategoryTheory/Subobject/WellPowered.lean
+++ b/Mathlib/CategoryTheory/Subobject/WellPowered.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Subobject.Basic
import Mathlib.CategoryTheory.EssentiallySmall
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/Associator.lean b/Mathlib/CategoryTheory/Sums/Associator.lean
index 214fda16c81c1..52868ef851d64 100644
--- a/Mathlib/CategoryTheory/Sums/Associator.lean
+++ b/Mathlib/CategoryTheory/Sums/Associator.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Sums.Basic
diff --git a/Mathlib/CategoryTheory/Sums/Basic.lean b/Mathlib/CategoryTheory/Sums/Basic.lean
index 91a569cf79a16..661d3f9c715c1 100644
--- a/Mathlib/CategoryTheory/Sums/Basic.lean
+++ b/Mathlib/CategoryTheory/Sums/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Equivalence
@@ -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/Thin.lean b/Mathlib/CategoryTheory/Thin.lean
index e44b1c223c030..a2c9cb1099b9c 100644
--- a/Mathlib/CategoryTheory/Thin.lean
+++ b/Mathlib/CategoryTheory/Thin.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison, Bhavik Mehta. All rights reserved.
+Copyright (c) 2019 Kim Morrison, Bhavik Mehta. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Bhavik Mehta
+Authors: Kim Morrison, Bhavik Mehta
-/
import Mathlib.CategoryTheory.Functor.Category
import Mathlib.CategoryTheory.Iso
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 d78ec3c589a8f..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 :=
@@ -310,6 +305,6 @@ lemma isTriangulated_of_essSurj_mapComposableArrows_two
exact ⟨Octahedron.ofIso (e₁ := (e.app 0).symm) (e₂ := (e.app 1).symm) (e₃ := (e.app 2).symm)
(comm₁₂ := ComposableArrows.naturality' e.inv 0 1)
(comm₂₃ := ComposableArrows.naturality' e.inv 1 2)
- (H := (someOctahedron rfl h₁₂' h₂₃' h₁₃').map F) _ _ _ _ _⟩
+ (H := (someOctahedron rfl h₁₂' h₂₃' h₁₃').map F) ..⟩
end CategoryTheory
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/Subcategory.lean b/Mathlib/CategoryTheory/Triangulated/Subcategory.lean
index f4c688ba57647..22baf9e9ef9b8 100644
--- a/Mathlib/CategoryTheory/Triangulated/Subcategory.lean
+++ b/Mathlib/CategoryTheory/Triangulated/Subcategory.lean
@@ -152,16 +152,16 @@ lemma isoClosure_W : S.isoClosure.W = S.W := by
exact ⟨Z, g, h, mem, le_isoClosure _ _ hZ⟩
instance respectsIso_W : S.W.RespectsIso where
- precomp := by
- rintro X' X Y e f ⟨Z, g, h, mem, mem'⟩
- refine ⟨Z, g, h ≫ e.inv⟦(1 : ℤ)⟧', isomorphic_distinguished _ mem _ ?_, mem'⟩
- refine Triangle.isoMk _ _ e (Iso.refl _) (Iso.refl _) (by aesop_cat) (by aesop_cat) ?_
+ precomp {X' X Y} e (he : IsIso e) := by
+ rintro f ⟨Z, g, h, mem, mem'⟩
+ refine ⟨Z, g, h ≫ inv e⟦(1 : ℤ)⟧', isomorphic_distinguished _ mem _ ?_, mem'⟩
+ refine Triangle.isoMk _ _ (asIso e) (Iso.refl _) (Iso.refl _) (by aesop_cat) (by aesop_cat) ?_
dsimp
- simp only [assoc, ← Functor.map_comp, e.inv_hom_id, Functor.map_id, comp_id, id_comp]
- postcomp := by
- rintro X Y Y' e f ⟨Z, g, h, mem, mem'⟩
- refine ⟨Z, e.inv ≫ g, h, isomorphic_distinguished _ mem _ ?_, mem'⟩
- exact Triangle.isoMk _ _ (Iso.refl _) e.symm (Iso.refl _)
+ simp only [Functor.map_inv, assoc, IsIso.inv_hom_id, comp_id, id_comp]
+ postcomp {X Y Y'} e (he : IsIso e) := by
+ rintro f ⟨Z, g, h, mem, mem'⟩
+ refine ⟨Z, inv e ≫ g, h, isomorphic_distinguished _ mem _ ?_, mem'⟩
+ exact Triangle.isoMk _ _ (Iso.refl _) (asIso e).symm (Iso.refl _)
instance : S.W.ContainsIdentities := by
rw [← isoClosure_W]
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 b7cab7670d304..01484dc45c6dc 100644
--- a/Mathlib/CategoryTheory/Types.lean
+++ b/Mathlib/CategoryTheory/Types.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Stephen Morgan, Scott Morrison, Johannes Hölzl
+Authors: Stephen Morgan, Kim Morrison, Johannes Hölzl
-/
import Mathlib.CategoryTheory.EpiMono
import Mathlib.CategoryTheory.Functor.FullyFaithful
@@ -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/UnivLE.lean b/Mathlib/CategoryTheory/UnivLE.lean
index e6b8c95764011..0210136dcf7ea 100644
--- a/Mathlib/CategoryTheory/UnivLE.lean
+++ b/Mathlib/CategoryTheory/UnivLE.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.UnivLE
import Mathlib.CategoryTheory.EssentialImage
diff --git a/Mathlib/CategoryTheory/Whiskering.lean b/Mathlib/CategoryTheory/Whiskering.lean
index a674d50bcf341..50cc4f617eec0 100644
--- a/Mathlib/CategoryTheory/Whiskering.lean
+++ b/Mathlib/CategoryTheory/Whiskering.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Iso
import Mathlib.CategoryTheory.Functor.Category
@@ -113,6 +113,46 @@ def Functor.FullyFaithful.whiskeringRight {F : D ⥤ E} (hF : F.FullyFaithful)
simp only [map_comp, map_preimage]
apply f.naturality }
+theorem whiskeringLeft_obj_id : (whiskeringLeft C C E).obj (𝟭 _) = 𝟭 _ :=
+ rfl
+
+/-- The isomorphism between left-whiskering on the identity functor and the identity of the functor
+between the resulting functor categories. -/
+def whiskeringLeftObjIdIso : (whiskeringLeft C C E).obj (𝟭 _) ≅ 𝟭 _ :=
+ Iso.refl _
+
+theorem whiskeringLeft_obj_comp {D' : Type u₄} [Category.{v₄} D'] (F : C ⥤ D) (G : D ⥤ D') :
+ (whiskeringLeft C D' E).obj (F ⋙ G) =
+ (whiskeringLeft D D' E).obj G ⋙ (whiskeringLeft C D E).obj F :=
+ rfl
+
+/-- The isomorphism between left-whiskering on the composition of functors and the composition
+of two left-whiskering applications. -/
+def whiskeringLeftObjCompIso {D' : Type u₄} [Category.{v₄} D'] (F : C ⥤ D) (G : D ⥤ D') :
+ (whiskeringLeft C D' E).obj (F ⋙ G) ≅
+ (whiskeringLeft D D' E).obj G ⋙ (whiskeringLeft C D E).obj F :=
+ Iso.refl _
+
+theorem whiskeringRight_obj_id : (whiskeringRight E C C).obj (𝟭 _) = 𝟭 _ :=
+ rfl
+
+/-- The isomorphism between right-whiskering on the identity functor and the identity of the functor
+between the resulting functor categories. -/
+def wiskeringRightObjIdIso : (whiskeringRight E C C).obj (𝟭 _) ≅ 𝟭 _ :=
+ Iso.refl _
+
+theorem whiskeringRight_obj_comp {D' : Type u₄} [Category.{v₄} D'] (F : C ⥤ D) (G : D ⥤ D') :
+ (whiskeringRight E C D).obj F ⋙ (whiskeringRight E D D').obj G =
+ (whiskeringRight E C D').obj (F ⋙ G) :=
+ rfl
+
+/-- The isomorphism between right-whiskering on the composition of functors and the composition
+of two right-whiskering applications. -/
+def whiskeringRightObjCompIso {D' : Type u₄} [Category.{v₄} D'] (F : C ⥤ D) (G : D ⥤ D') :
+ (whiskeringRight E C D).obj F ⋙ (whiskeringRight E D D').obj G ≅
+ (whiskeringRight E C D').obj (F ⋙ G) :=
+ Iso.refl _
+
instance full_whiskeringRight_obj {F : D ⥤ E} [F.Faithful] [F.Full] :
((whiskeringRight C D E).obj F).Full :=
((Functor.FullyFaithful.ofFullyFaithful F).whiskeringRight C).full
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 f3cbf94ce4ae3..6f87fb13988bf 100644
--- a/Mathlib/CategoryTheory/Yoneda.lean
+++ b/Mathlib/CategoryTheory/Yoneda.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Functor.Hom
import Mathlib.CategoryTheory.Products.Basic
@@ -24,7 +24,7 @@ namespace CategoryTheory
open Opposite
-universe 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
@@ -153,97 +153,228 @@ end Coyoneda
namespace Functor
-/-- A functor `F : Cᵒᵖ ⥤ Type v₁` is representable if there is object `X` so `F ≅ yoneda.obj X`.
+/-- The data which expresses that a functor `F : Cᵒᵖ ⥤ Type v` is representable by `Y : C`. -/
+structure RepresentableBy (F : Cᵒᵖ ⥤ Type v) (Y : C) where
+ /-- the natural bijection `(X ⟶ Y) ≃ F.obj (op X)`. -/
+ homEquiv {X : C} : (X ⟶ Y) ≃ F.obj (op X)
+ homEquiv_comp {X X' : C} (f : X ⟶ X') (g : X' ⟶ Y) :
+ homEquiv (f ≫ g) = F.map f.op (homEquiv g)
+
+/-- If `F ≅ F'`, and `F` is representable, then `F'` is representable. -/
+def RepresentableBy.ofIso {F F' : Cᵒᵖ ⥤ Type v} {Y : C} (e : F.RepresentableBy Y) (e' : F ≅ F') :
+ F'.RepresentableBy Y where
+ homEquiv {X} := e.homEquiv.trans (e'.app _).toEquiv
+ homEquiv_comp {X X'} f g := by
+ dsimp
+ rw [e.homEquiv_comp]
+ apply congr_fun (e'.hom.naturality f.op)
+
+/-- The data which expresses that a functor `F : C ⥤ Type v` is corepresentable by `X : C`. -/
+structure CorepresentableBy (F : C ⥤ Type v) (X : C) where
+ /-- the natural bijection `(X ⟶ Y) ≃ F.obj Y`. -/
+ homEquiv {Y : C} : (X ⟶ Y) ≃ F.obj Y
+ homEquiv_comp {Y Y' : C} (g : Y ⟶ Y') (f : X ⟶ Y) :
+ homEquiv (f ≫ g) = F.map g (homEquiv f)
+
+/-- If `F ≅ F'`, and `F` is corepresentable, then `F'` is corepresentable. -/
+def CorepresentableBy.ofIso {F F' : C ⥤ Type v} {X : C} (e : F.CorepresentableBy X)
+ (e' : F ≅ F') :
+ F'.CorepresentableBy X where
+ homEquiv {X} := e.homEquiv.trans (e'.app _).toEquiv
+ homEquiv_comp {Y Y'} g f := by
+ dsimp
+ rw [e.homEquiv_comp]
+ apply congr_fun (e'.hom.naturality g)
+
+lemma RepresentableBy.homEquiv_eq {F : Cᵒᵖ ⥤ Type v} {Y : C} (e : F.RepresentableBy Y)
+ {X : C} (f : X ⟶ Y) :
+ e.homEquiv f = F.map f.op (e.homEquiv (𝟙 Y)) := by
+ conv_lhs => rw [← Category.comp_id f, e.homEquiv_comp]
+
+lemma CorepresentableBy.homEquiv_eq {F : C ⥤ Type v} {X : C} (e : F.CorepresentableBy X)
+ {Y : C} (f : X ⟶ Y) :
+ e.homEquiv f = F.map f (e.homEquiv (𝟙 X)) := by
+ conv_lhs => rw [← Category.id_comp f, e.homEquiv_comp]
+
+@[ext]
+lemma RepresentableBy.ext {F : Cᵒᵖ ⥤ Type v} {Y : C} {e e' : F.RepresentableBy Y}
+ (h : e.homEquiv (𝟙 Y) = e'.homEquiv (𝟙 Y)) : e = e' := by
+ have : ∀ {X : C} (f : X ⟶ Y), e.homEquiv f = e'.homEquiv f := fun {X} f ↦ by
+ rw [e.homEquiv_eq, e'.homEquiv_eq, h]
+ obtain ⟨e, he⟩ := e
+ obtain ⟨e', he'⟩ := e'
+ obtain rfl : @e = @e' := by ext; apply this
+ rfl
+
+@[ext]
+lemma CorepresentableBy.ext {F : C ⥤ Type v} {X : C} {e e' : F.CorepresentableBy X}
+ (h : e.homEquiv (𝟙 X) = e'.homEquiv (𝟙 X)) : e = e' := by
+ have : ∀ {Y : C} (f : X ⟶ Y), e.homEquiv f = e'.homEquiv f := fun {X} f ↦ by
+ rw [e.homEquiv_eq, e'.homEquiv_eq, h]
+ obtain ⟨e, he⟩ := e
+ obtain ⟨e', he'⟩ := e'
+ obtain rfl : @e = @e' := by ext; apply this
+ rfl
+
+/-- The obvious bijection `F.RepresentableBy Y ≃ (yoneda.obj Y ≅ F)`
+when `F : Cᵒᵖ ⥤ Type v₁` and `[Category.{v₁} C]`. -/
+def representableByEquiv {F : Cᵒᵖ ⥤ Type v₁} {Y : C} :
+ F.RepresentableBy Y ≃ (yoneda.obj Y ≅ F) where
+ toFun r := NatIso.ofComponents (fun _ ↦ r.homEquiv.toIso) (fun {X X'} f ↦ by
+ ext g
+ simp [r.homEquiv_comp])
+ invFun e :=
+ { homEquiv := (e.app _).toEquiv
+ homEquiv_comp := fun {X X'} f g ↦ congr_fun (e.hom.naturality f.op) g }
+ left_inv _ := rfl
+ right_inv _ := rfl
+
+/-- The isomorphism `yoneda.obj Y ≅ F` induced by `e : F.RepresentableBy Y`. -/
+def RepresentableBy.toIso {F : Cᵒᵖ ⥤ Type v₁} {Y : C} (e : F.RepresentableBy Y) :
+ yoneda.obj Y ≅ F :=
+ representableByEquiv e
+
+/-- The obvious bijection `F.CorepresentableBy X ≃ (yoneda.obj Y ≅ F)`
+when `F : C ⥤ Type v₁` and `[Category.{v₁} C]`. -/
+def corepresentableByEquiv {F : C ⥤ Type v₁} {X : C} :
+ F.CorepresentableBy X ≃ (coyoneda.obj (op X) ≅ F) where
+ toFun r := NatIso.ofComponents (fun _ ↦ r.homEquiv.toIso) (fun {X X'} f ↦ by
+ ext g
+ simp [r.homEquiv_comp])
+ invFun e :=
+ { homEquiv := (e.app _).toEquiv
+ homEquiv_comp := fun {X X'} f g ↦ congr_fun (e.hom.naturality f) g }
+ left_inv _ := rfl
+ right_inv _ := rfl
+
+/-- The isomorphism `coyoneda.obj (op X) ≅ F` induced by `e : F.CorepresentableBy X`. -/
+def CorepresentableBy.toIso {F : C ⥤ Type v₁} {X : C} (e : F.CorepresentableBy X) :
+ coyoneda.obj (op X) ≅ F :=
+ corepresentableByEquiv e
+
+/-- A functor `F : Cᵒᵖ ⥤ Type v` is representable if there is oan bject `Y` with a structure
+`F.RepresentableBy Y`, i.e. there is a natural bijection `(X ⟶ Y) ≃ F.obj (op X)`,
+which may also be rephrased as a natural isomorphism `yoneda.obj X ≅ F` when `Category.{v} C`.
See .
-/
-class Representable (F : Cᵒᵖ ⥤ Type v₁) : Prop where
- /-- `Hom(-,X) ≅ F` via `f` -/
- has_representation : ∃ (X : _), Nonempty (yoneda.obj X ≅ F)
+class IsRepresentable (F : Cᵒᵖ ⥤ Type v) : Prop where
+ has_representation : ∃ (Y : C), Nonempty (F.RepresentableBy Y)
+
+@[deprecated (since := "2024-10-03")] alias Representable := IsRepresentable
-instance {X : C} : Representable (yoneda.obj X) where has_representation := ⟨X, ⟨Iso.refl _⟩⟩
+lemma RepresentableBy.isRepresentable {F : Cᵒᵖ ⥤ Type v} {Y : C} (e : F.RepresentableBy Y) :
+ F.IsRepresentable where
+ has_representation := ⟨Y, ⟨e⟩⟩
+
+/-- Alternative constructure for `F.IsRepresentable`, which takes as an input an
+isomorphism `yoneda.obj X ≅ F`. -/
+lemma IsRepresentable.mk' {F : Cᵒᵖ ⥤ Type v₁} {X : C} (e : yoneda.obj X ≅ F) :
+ F.IsRepresentable :=
+ (representableByEquiv.symm e).isRepresentable
+
+instance {X : C} : IsRepresentable (yoneda.obj X) :=
+ IsRepresentable.mk' (Iso.refl _)
/-- A functor `F : C ⥤ Type v₁` is corepresentable if there is object `X` so `F ≅ coyoneda.obj X`.
See .
-/
-class Corepresentable (F : C ⥤ Type v₁) : Prop where
- /-- `Hom(X,-) ≅ F` via `f` -/
- has_corepresentation : ∃ (X : _), Nonempty (coyoneda.obj X ≅ F)
+class IsCorepresentable (F : C ⥤ Type v) : Prop where
+ has_corepresentation : ∃ (X : C), Nonempty (F.CorepresentableBy X)
+
+@[deprecated (since := "2024-10-03")] alias Corepresentable := IsCorepresentable
-instance {X : Cᵒᵖ} : Corepresentable (coyoneda.obj X) where
- has_corepresentation := ⟨X, ⟨Iso.refl _⟩⟩
+lemma CorepresentableBy.isCorepresentable {F : C ⥤ Type v} {X : C} (e : F.CorepresentableBy X) :
+ F.IsCorepresentable where
+ has_corepresentation := ⟨X, ⟨e⟩⟩
+
+/-- Alternative constructure for `F.IsCorepresentable`, which takes as an input an
+isomorphism `coyoneda.obj (op X) ≅ F`. -/
+lemma IsCorepresentable.mk' {F : C ⥤ Type v₁} {X : C} (e : coyoneda.obj (op X) ≅ F) :
+ F.IsCorepresentable :=
+ (corepresentableByEquiv.symm e).isCorepresentable
+
+instance {X : Cᵒᵖ} : IsCorepresentable (coyoneda.obj X) :=
+ IsCorepresentable.mk' (Iso.refl _)
-- instance : corepresentable (𝟭 (Type v₁)) :=
-- corepresentable_of_nat_iso (op punit) coyoneda.punit_iso
section Representable
-variable (F : Cᵒᵖ ⥤ Type v₁)
-variable [hF : F.Representable]
+variable (F : Cᵒᵖ ⥤ Type v) [hF : F.IsRepresentable]
/-- The representing object for the representable functor `F`. -/
-noncomputable def reprX : C := hF.has_representation.choose
+noncomputable def reprX : C :=
+ hF.has_representation.choose
-/-- An isomorphism between a representable `F` and a functor of the
-form `C(-, F.reprX)`. Note the components `F.reprW.app X`
-definitionally have type `(X.unop ⟶ F.repr_X) ≅ F.obj X`.
--/
-noncomputable def reprW : yoneda.obj F.reprX ≅ F :=
- Representable.has_representation.choose_spec.some
+/-- A chosen term in `F.RepresentableBy (reprX F)` when `F.IsRepresentable` holds. -/
+noncomputable def representableBy : F.RepresentableBy F.reprX :=
+ hF.has_representation.choose_spec.some
/-- The representing element for the representable functor `F`, sometimes called the universal
element of the functor.
-/
noncomputable def reprx : F.obj (op F.reprX) :=
- F.reprW.hom.app (op F.reprX) (𝟙 F.reprX)
+ F.representableBy.homEquiv (𝟙 _)
+
+/-- An isomorphism between a representable `F` and a functor of the
+form `C(-, F.reprX)`. Note the components `F.reprW.app X`
+definitionally have type `(X.unop ⟶ F.reprX) ≅ F.obj X`.
+-/
+noncomputable def reprW (F : Cᵒᵖ ⥤ Type v₁) [F.IsRepresentable] :
+ yoneda.obj F.reprX ≅ F := F.representableBy.toIso
-theorem reprW_app_hom (X : Cᵒᵖ) (f : unop X ⟶ F.reprX) :
- (F.reprW.app X).hom f = F.map f.op F.reprx := by
- simp only [yoneda_obj_obj, Iso.app_hom, op_unop, reprx, ← FunctorToTypes.naturality,
- yoneda_obj_map, unop_op, Quiver.Hom.unop_op, Category.comp_id]
+theorem reprW_hom_app (F : Cᵒᵖ ⥤ Type v₁) [F.IsRepresentable]
+ (X : Cᵒᵖ) (f : unop X ⟶ F.reprX) :
+ F.reprW.hom.app X f = F.map f.op F.reprx := by
+ apply RepresentableBy.homEquiv_eq
end Representable
section Corepresentable
-variable (F : C ⥤ Type v₁)
-variable [hF : F.Corepresentable]
+variable (F : C ⥤ Type v) [hF : F.IsCorepresentable]
/-- The representing object for the corepresentable functor `F`. -/
noncomputable def coreprX : C :=
- hF.has_corepresentation.choose.unop
+ hF.has_corepresentation.choose
-/-- An isomorphism between a corepresnetable `F` and a functor of the form
-`C(F.corepr X, -)`. Note the components `F.coreprW.app X`
-definitionally have type `F.corepr_X ⟶ X ≅ F.obj X`.
--/
-noncomputable def coreprW : coyoneda.obj (op F.coreprX) ≅ F :=
+/-- A chosen term in `F.CorepresentableBy (coreprX F)` when `F.IsCorepresentable` holds. -/
+noncomputable def corepresentableBy : F.CorepresentableBy F.coreprX :=
hF.has_corepresentation.choose_spec.some
/-- The representing element for the corepresentable functor `F`, sometimes called the universal
element of the functor.
-/
noncomputable def coreprx : F.obj F.coreprX :=
- F.coreprW.hom.app F.coreprX (𝟙 F.coreprX)
+ F.corepresentableBy.homEquiv (𝟙 _)
+
+/-- An isomorphism between a corepresentable `F` and a functor of the form
+`C(F.corepr X, -)`. Note the components `F.coreprW.app X`
+definitionally have type `F.corepr_X ⟶ X ≅ F.obj X`.
+-/
+noncomputable def coreprW (F : C ⥤ Type v₁) [F.IsCorepresentable] :
+ coyoneda.obj (op F.coreprX) ≅ F :=
+ F.corepresentableBy.toIso
-theorem coreprW_app_hom (X : C) (f : F.coreprX ⟶ X) :
- (F.coreprW.app X).hom f = F.map f F.coreprx := by
- simp only [coyoneda_obj_obj, unop_op, Iso.app_hom, coreprx, ← FunctorToTypes.naturality,
- coyoneda_obj_map, Category.id_comp]
+theorem coreprW_hom_app (F : C ⥤ Type v₁) [F.IsCorepresentable] (X : C) (f : F.coreprX ⟶ X) :
+ F.coreprW.hom.app X f = F.map f F.coreprx := by
+ apply CorepresentableBy.homEquiv_eq
end Corepresentable
end Functor
-theorem representable_of_natIso (F : Cᵒᵖ ⥤ Type v₁) {G} (i : F ≅ G) [F.Representable] :
- G.Representable :=
- { has_representation := ⟨F.reprX, ⟨F.reprW ≪≫ i⟩⟩ }
+theorem isRepresentable_of_natIso (F : Cᵒᵖ ⥤ Type v₁) {G} (i : F ≅ G) [F.IsRepresentable] :
+ G.IsRepresentable :=
+ (F.representableBy.ofIso i).isRepresentable
-theorem corepresentable_of_natIso (F : C ⥤ Type v₁) {G} (i : F ≅ G) [F.Corepresentable] :
- G.Corepresentable :=
- { has_corepresentation := ⟨op F.coreprX, ⟨F.coreprW ≪≫ i⟩⟩ }
+theorem corepresentable_of_natIso (F : C ⥤ Type v₁) {G} (i : F ≅ G) [F.IsCorepresentable] :
+ G.IsCorepresentable :=
+ (F.corepresentableBy.ofIso i).isCorepresentable
-instance : Functor.Corepresentable (𝟭 (Type v₁)) :=
+instance : Functor.IsCorepresentable (𝟭 (Type v₁)) :=
corepresentable_of_natIso (coyoneda.obj (op PUnit)) Coyoneda.punitIso
open Opposite
@@ -268,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
@@ -286,6 +417,7 @@ theorem yonedaEquiv_symm_app_apply {X : C} {F : Cᵒᵖ ⥤ Type v₁} (x : F.ob
(f : Y.unop ⟶ X) : (yonedaEquiv.symm x).app Y f = F.map f.op x :=
rfl
+/-- See also `yonedaEquiv_naturality'` for a more general version. -/
lemma yonedaEquiv_naturality {X Y : C} {F : Cᵒᵖ ⥤ Type v₁} (f : yoneda.obj X ⟶ F)
(g : Y ⟶ X) : F.map g.op (yonedaEquiv f) = yonedaEquiv (yoneda.map g ≫ f) := by
change (f.app (op X) ≫ F.map g.op) (𝟙 X) = f.app (op Y) (𝟙 Y ≫ g)
@@ -293,6 +425,9 @@ lemma yonedaEquiv_naturality {X Y : C} {F : Cᵒᵖ ⥤ Type v₁} (f : yoneda.o
dsimp
simp
+/-- Variant of `yonedaEquiv_naturality` with general `g`. This is technically strictly more general
+ than `yonedaEquiv_naturality`, but `yonedaEquiv_naturality` is sometimes preferable because it
+ can avoid the "motive is not type correct" error. -/
lemma yonedaEquiv_naturality' {X Y : Cᵒᵖ} {F : Cᵒᵖ ⥤ Type v₁} (f : yoneda.obj (unop X) ⟶ F)
(g : X ⟶ Y) : F.map g (yonedaEquiv f) = yonedaEquiv (yoneda.map g.unop ≫ f) :=
yonedaEquiv_naturality _ _
@@ -305,6 +440,18 @@ lemma yonedaEquiv_yoneda_map {X Y : C} (f : X ⟶ Y) : yonedaEquiv (yoneda.map f
rw [yonedaEquiv_apply]
simp
+/-- See also `map_yonedaEquiv'` for a more general version. -/
+lemma map_yonedaEquiv {X Y : C} {F : Cᵒᵖ ⥤ Type v₁} (f : yoneda.obj X ⟶ F)
+ (g : Y ⟶ X) : F.map g.op (yonedaEquiv f) = f.app (op Y) g := by
+ rw [yonedaEquiv_naturality, yonedaEquiv_comp, yonedaEquiv_yoneda_map]
+
+/-- Variant of `map_yonedaEquiv` with general `g`. This is technically strictly more general
+ than `map_yonedaEquiv`, but `map_yonedaEquiv` is sometimes preferable because it
+ can avoid the "motive is not type correct" error. -/
+lemma map_yonedaEquiv' {X Y : Cᵒᵖ} {F : Cᵒᵖ ⥤ Type v₁} (f : yoneda.obj (unop X) ⟶ F)
+ (g : X ⟶ Y) : F.map g (yonedaEquiv f) = f.app Y g.unop := by
+ rw [yonedaEquiv_naturality', yonedaEquiv_comp, yonedaEquiv_yoneda_map]
+
lemma yonedaEquiv_symm_map {X Y : Cᵒᵖ} (f : X ⟶ Y) {F : Cᵒᵖ ⥤ Type v₁} (t : F.obj X) :
yonedaEquiv.symm (F.map f t) = yoneda.map f.unop ≫ yonedaEquiv.symm t := by
obtain ⟨u, rfl⟩ := yonedaEquiv.surjective t
@@ -339,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 :=
@@ -359,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
@@ -377,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
@@ -392,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]
@@ -404,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
@@ -425,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]
@@ -437,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
@@ -448,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
@@ -481,6 +639,10 @@ lemma coyonedaEquiv_coyoneda_map {X Y : C} (f : X ⟶ Y) :
rw [coyonedaEquiv_apply]
simp
+lemma map_coyonedaEquiv {X Y : C} {F : C ⥤ Type v₁} (f : coyoneda.obj (op X) ⟶ F)
+ (g : X ⟶ Y) : F.map g (coyonedaEquiv f) = f.app Y g := by
+ rw [coyonedaEquiv_naturality, coyonedaEquiv_comp, coyonedaEquiv_coyoneda_map]
+
lemma coyonedaEquiv_symm_map {X Y : C} (f : X ⟶ Y) {F : C ⥤ Type v₁} (t : F.obj X) :
coyonedaEquiv.symm (F.map f t) = coyoneda.map f.op ≫ coyonedaEquiv.symm t := by
obtain ⟨u, rfl⟩ := coyonedaEquiv.surjective t
@@ -506,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 :=
@@ -526,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
@@ -544,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
@@ -558,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])
@@ -569,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
@@ -590,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]))
@@ -602,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
@@ -612,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) :
@@ -620,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 9b660a299371d..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
@@ -356,7 +354,7 @@ theorem three_le_nValue (hN : 64 ≤ N) : 3 ≤ nValue N := by
rw [rpow_natCast]
exact (cast_le.2 hN).trans' (by norm_num1)
apply lt_of_lt_of_le _ (log_le_log (rpow_pos_of_pos zero_lt_two _) this)
- rw [log_rpow zero_lt_two, ← div_lt_iff']
+ rw [log_rpow zero_lt_two, ← div_lt_iff₀']
· exact log_two_gt_d9.trans_le' (by norm_num1)
· norm_num1
@@ -459,7 +457,7 @@ theorem roth_lower_bound_explicit (hN : 4096 ≤ N) :
theorem exp_four_lt : exp 4 < 64 := by
rw [show (64 : ℝ) = 2 ^ ((6 : ℕ) : ℝ) by rw [rpow_natCast]; norm_num1,
- ← lt_log_iff_exp_lt (rpow_pos_of_pos zero_lt_two _), log_rpow zero_lt_two, ← div_lt_iff']
+ ← lt_log_iff_exp_lt (rpow_pos_of_pos zero_lt_two _), log_rpow zero_lt_two, ← div_lt_iff₀']
· exact log_two_gt_d9.trans_le' (by norm_num1)
· norm_num
diff --git a/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean b/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean
index dd03dd295ddc0..f374375f2d4a6 100644
--- a/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean
+++ b/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean
@@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies, Bhavik Mehta
-/
import Mathlib.Algebra.Order.Interval.Finset
+import Mathlib.Algebra.SMulWithZero
import Mathlib.Combinatorics.Additive.FreimanHom
-import Mathlib.Data.Set.Pointwise.SMul
import Mathlib.Order.Interval.Finset.Fin
/-!
@@ -43,7 +43,7 @@ the size of the biggest 3AP-free subset of `{0, ..., n - 1}`.
3AP-free, Salem-Spencer, Roth, arithmetic progression, average, three-free
-/
-open Finset Function Nat
+open Finset Function
open scoped Pointwise
variable {F α β 𝕜 E : Type*}
@@ -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 :=
- le_findGreatest (card_le_card h) ⟨s, h, rfl, hs⟩
+ #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 69eec794bef92..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
@@ -88,7 +87,7 @@ theorem corners_theorem (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound ε
rwa [mul_le_iff_le_one_left] at this
positivity
have := noAccidental hA
- rw [Nat.floor_lt' (by positivity), inv_pos_lt_iff_one_lt_mul'] at hG
+ rw [Nat.floor_lt' (by positivity), inv_lt_iff_one_lt_mul₀'] at hG
swap
· have : ε / 9 ≤ 1 := by linarith
positivity
@@ -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/Dissociation.lean b/Mathlib/Combinatorics/Additive/Dissociation.lean
index d7dfe231cee32..f22b05d75f55d 100644
--- a/Mathlib/Combinatorics/Additive/Dissociation.lean
+++ b/Mathlib/Combinatorics/Additive/Dissociation.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies
-/
import Mathlib.Algebra.BigOperators.Group.Finset
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Algebra.Group.Units.Equiv
import Mathlib.Data.Fintype.Card
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/ETransform.lean b/Mathlib/Combinatorics/Additive/ETransform.lean
index c146fce4176ae..d7a7e6ffdcbc2 100644
--- a/Mathlib/Combinatorics/Additive/ETransform.lean
+++ b/Mathlib/Combinatorics/Additive/ETransform.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.Data.Finset.Pointwise.Basic
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
/-!
# e-transforms
diff --git a/Mathlib/Combinatorics/Additive/Energy.lean b/Mathlib/Combinatorics/Additive/Energy.lean
index 02b6197b5c3cb..2cd35ab13760c 100644
--- a/Mathlib/Combinatorics/Additive/Energy.lean
+++ b/Mathlib/Combinatorics/Additive/Energy.lean
@@ -3,10 +3,10 @@ Copyright (c) 2022 Yaël Dillies, Ella Yu. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies, Ella Yu
-/
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
import Mathlib.Algebra.Order.BigOperators.Ring.Finset
import Mathlib.Data.Finset.Prod
import Mathlib.Data.Fintype.Prod
-import Mathlib.Data.Finset.Pointwise.Basic
/-!
# Additive energy
@@ -183,7 +183,7 @@ lemma mulEnergy_univ_left : Eₘ[univ, t] = Fintype.card α * t.card ^ 2 := by
rw [mul_right_cancel h.1]
rw [← card_image_of_injOn this]
congr with a
- simp only [mem_filter, mem_product, mem_univ, true_and_iff, mem_image, exists_prop,
+ simp only [mem_filter, mem_product, mem_univ, true_and, mem_image, exists_prop,
Prod.exists]
refine ⟨fun h => ⟨a.1.1 * a.2.2⁻¹, _, _, h.1, by simp [f, mul_right_comm, h.2]⟩, ?_⟩
rintro ⟨b, c, d, hcd, rfl⟩
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 c196e507f58bb..dc169558a2b3a 100644
--- a/Mathlib/Combinatorics/Additive/FreimanHom.lean
+++ b/Mathlib/Combinatorics/Additive/FreimanHom.lean
@@ -4,9 +4,11 @@ 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.Group.Pointwise.Set
+import Mathlib.Algebra.CharP.Basic
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
+import Mathlib.Algebra.Group.Submonoid.Defs
import Mathlib.Algebra.Order.BigOperators.Group.Multiset
+import Mathlib.Algebra.Order.Ring.Nat
import Mathlib.Data.ZMod.Defs
/-!
@@ -145,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. -/
@@ -153,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
@@ -233,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]
@@ -249,6 +251,11 @@ lemma isMulFreimanIso_empty : IsMulFreimanIso n (∅ : Set α) (∅ : Set β) f
map_prod_eq_map_prod s t _ _ _ _ := by
rw [← map_multiset_prod, ← map_multiset_prod, EquivLike.apply_eq_iff_eq]
+@[to_additive]
+lemma IsMulFreimanHom.subtypeVal {S : Type*} [SetLike S α] [SubmonoidClass S α] {s : S} :
+ IsMulFreimanHom n (univ : Set s) univ Subtype.val :=
+ MonoidHomClass.isMulFreimanHom (SubmonoidClass.subtype s) (mapsTo_univ ..)
+
end CommMonoid
section CancelCommMonoid
@@ -321,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]
@@ -329,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 125742993fc6a..94e3ef08335bd 100644
--- a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean
+++ b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean
@@ -3,12 +3,16 @@ Copyright (c) 2022 Yaël Dillies, George Shakan. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies, George Shakan
-/
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
+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.Data.Finset.Pointwise.Basic
+import Mathlib.Tactic.FieldSimp
import Mathlib.Tactic.GCongr
-import Mathlib.Algebra.Order.Field.Basic
-import Mathlib.Algebra.Order.Field.Rat
+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]
+
+section Group
+variable [Group G] {A B C : Finset G}
-variable {α : Type*} [CommGroup α] [DecidableEq α] {A B C : Finset α}
+/-! ### 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/Additive/RuzsaCovering.lean b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean
index 522ba740a3844..6e7183a4afdf7 100644
--- a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean
+++ b/Mathlib/Combinatorics/Additive/RuzsaCovering.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.Data.Finset.Pointwise.Basic
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
import Mathlib.SetTheory.Cardinal.Finite
/-!
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 1937c08a8c032..79f8392c7bf56 100644
--- a/Mathlib/Combinatorics/Configuration.lean
+++ b/Mathlib/Combinatorics/Configuration.lean
@@ -3,10 +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
-/
-import Mathlib.Algebra.Order.BigOperators.Group.Finset
import Mathlib.Combinatorics.Hall.Basic
-import Mathlib.Data.Fintype.BigOperators
-import Mathlib.SetTheory.Cardinal.Finite
+import Mathlib.Data.Matrix.Rank
+import Mathlib.LinearAlgebra.Projectivization.Constructions
/-!
# Configurations of Points and lines
@@ -118,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 l
+ 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,
@@ -146,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₃ ⊢
@@ -221,7 +220,7 @@ theorem HasLines.card_le [HasLines P L] [Fintype P] [Fintype L] :
_ < ∑ p, lineCount L p := by
obtain ⟨p, hp⟩ := not_forall.mp (mt (Fintype.card_le_of_surjective f) hc₂)
refine sum_lt_sum_of_subset (subset_univ _) (mem_univ p) ?_ ?_ fun p _ _ ↦ zero_le _
- · simpa only [Finset.mem_map, exists_prop, Finset.mem_univ, true_and_iff]
+ · simpa only [Finset.mem_map, exists_prop, Finset.mem_univ, true_and]
· rw [lineCount, Nat.card_eq_fintype_card, Fintype.card_pos_iff]
obtain ⟨l, _⟩ := @exists_line P L _ _ p
exact
@@ -262,7 +261,7 @@ theorem HasLines.lineCount_eq_pointCount [HasLines P L] [Fintype P] [Fintype L]
simp_rw [hf2, sum_const, Set.toFinset_card, ← Nat.card_eq_fintype_card]
change pointCount P l • _ = lineCount L (f l) • _
rw [hf2]
- all_goals simp_rw [s, Finset.mem_univ, true_and_iff, Set.mem_toFinset]; exact fun p => Iff.rfl
+ all_goals simp_rw [s, Finset.mem_univ, true_and, Set.mem_toFinset]; exact fun p => Iff.rfl
have step3 : ∑ i ∈ sᶜ, lineCount L i.1 = ∑ i ∈ sᶜ, pointCount P i.2 := by
rwa [← s.sum_add_sum_compl, ← s.sum_add_sum_compl, step2, add_left_cancel_iff] at step1
rw [← Set.toFinset_compl] at step3
@@ -462,4 +461,63 @@ theorem card_lines [Finite P] [Fintype L] : Fintype.card L = order P L ^ 2 + ord
end ProjectivePlane
+namespace ofField
+
+variable {K : Type*} [Field K]
+
+open scoped LinearAlgebra.Projectivization
+
+open Matrix Projectivization
+
+instance : Membership (ℙ K (Fin 3 → K)) (ℙ K (Fin 3 → K)) :=
+ ⟨Function.swap orthogonal⟩
+
+lemma mem_iff (v w : ℙ K (Fin 3 → K)) : v ∈ w ↔ orthogonal v w :=
+ Iff.rfl
+
+-- This lemma can't be moved to the crossProduct file due to heavy imports
+lemma crossProduct_eq_zero_of_dotProduct_eq_zero {a b c d : Fin 3 → K} (hac : dotProduct a c = 0)
+ (hbc : dotProduct b c = 0) (had : dotProduct a d = 0) (hbd : dotProduct b d = 0) :
+ crossProduct a b = 0 ∨ crossProduct c d = 0 := by
+ by_contra h
+ simp_rw [not_or, ← ne_eq, crossProduct_ne_zero_iff_linearIndependent] at h
+ let A : Matrix (Fin 2) (Fin 3) K := ![a, b]
+ let B : Matrix (Fin 2) (Fin 3) K := ![c, d]
+ have hAB : A * B.transpose = 0 := by
+ ext i j
+ fin_cases i <;> fin_cases j <;> assumption
+ replace hAB := rank_add_rank_le_card_of_mul_eq_zero hAB
+ rw [rank_transpose, h.1.rank_matrix, h.2.rank_matrix, Fintype.card_fin, Fintype.card_fin] at hAB
+ contradiction
+
+lemma eq_or_eq_of_orthogonal {a b c d : ℙ K (Fin 3 → K)} (hac : a.orthogonal c)
+ (hbc : b.orthogonal c) (had : a.orthogonal d) (hbd : b.orthogonal d) :
+ a = b ∨ c = d := by
+ induction' a with a ha
+ induction' b with b hb
+ induction' c with c hc
+ induction' d with d hd
+ rw [mk_eq_mk_iff_crossProduct_eq_zero, mk_eq_mk_iff_crossProduct_eq_zero]
+ exact crossProduct_eq_zero_of_dotProduct_eq_zero hac hbc had hbd
+
+instance : Nondegenerate (ℙ K (Fin 3 → K)) (ℙ K (Fin 3 → K)) :=
+ { exists_point := exists_not_orthogonal_self
+ exists_line := exists_not_self_orthogonal
+ eq_or_eq := eq_or_eq_of_orthogonal }
+
+noncomputable instance [DecidableEq K] : ProjectivePlane (ℙ K (Fin 3 → K)) (ℙ K (Fin 3 → K)) :=
+ { mkPoint := by
+ intro v w _
+ exact cross v w
+ mkPoint_ax := fun h ↦ ⟨cross_orthogonal_left h, cross_orthogonal_right h⟩
+ mkLine := by
+ intro v w _
+ exact cross v w
+ mkLine_ax := fun h ↦ ⟨orthogonal_cross_left h, orthogonal_cross_right h⟩
+ exists_config := by
+ refine ⟨mk K ![0, 1, 1] ?_, mk K ![1, 0, 0] ?_, mk K ![1, 0, 1] ?_, mk K ![1, 0, 0] ?_,
+ mk K ![0, 1, 0] ?_, mk K ![0, 0, 1] ?_, ?_⟩ <;> simp [mem_iff, orthogonal_mk] }
+
+end ofField
+
end Configuration
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 cf2bebdc3109c..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
@@ -54,7 +53,7 @@ of `n`.
blocks of `c`.
* `join_splitWrtComposition` states that splitting a list and then joining it gives back the
original list.
-* `joinSplitWrtComposition_join` states that joining a list of lists, and then splitting it back
+* `splitWrtComposition_join` states that joining a list of lists, and then splitting it back
according to the right composition, gives back the original list of lists.
We turn to the second viewpoint on compositions, that we realize as a finset of `Fin (n+1)`.
@@ -168,6 +167,12 @@ theorem blocks_pos' (i : ℕ) (h : i < c.length) : 0 < c.blocks[i] :=
theorem one_le_blocksFun (i : Fin c.length) : 1 ≤ c.blocksFun i :=
c.one_le_blocks (c.blocksFun_mem_blocks i)
+theorem blocksFun_le {n} (c : Composition n) (i : Fin c.length) :
+ c.blocksFun i ≤ n := by
+ have := c.blocks_sum
+ have := List.le_sum_of_mem (c.blocksFun_mem_blocks i)
+ simp_all
+
theorem length_le : c.length ≤ n := by
conv_rhs => rw [← c.blocks_sum]
exact length_le_sum_of_one_le _ fun i hi => c.one_le_blocks hi
@@ -801,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 542deff1911e1..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
@@ -39,14 +40,14 @@ namespace Finset
section Bipartite
-variable (r : α → β → Prop) (s : Finset α) (t : Finset β) (a a' : α) (b b' : β)
+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
@@ -58,7 +59,7 @@ theorem coe_bipartiteBelow : s.bipartiteBelow r b = ({a ∈ s | r a b} : Set α)
@[simp, norm_cast]
theorem coe_bipartiteAbove : t.bipartiteAbove r a = ({b ∈ t | r a b} : Set β) := coe_filter _ _
-variable {s t a a' b b'}
+variable {s t a b}
@[simp]
theorem mem_bipartiteBelow {a : α} : a ∈ s.bipartiteBelow r b ↔ a ∈ s ∧ r a b := mem_filter
@@ -66,24 +67,30 @@ 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] [DecidablePred (r a)] [∀ a, Decidable (r a b)] {m n : R}
+variable [OrderedSemiring R] {m n : R}
/-- **Double counting** argument.
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,27 +99,27 @@ 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
section StrictOrderedSemiring
variable [StrictOrderedSemiring R] (r : α → β → Prop) {s : Finset α} {t : Finset β}
- (a a' : α) (b b' : β) [DecidablePred (r a)] [∀ a, Decidable (r a b)] {m n : R}
+ (a b) {m n : R}
/-- **Double counting** argument.
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 ab393d095b11c..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
@@ -291,7 +290,7 @@ lemma count_take_firstReturn_add_one :
lemma count_D_lt_count_U_of_lt_firstReturn {i : ℕ} (hi : i < p.firstReturn) :
(p.toList.take (i + 1)).count D < (p.toList.take (i + 1)).count U := by
have ne := not_of_lt_findIdx hi
- rw [decide_eq_true_eq, ← ne_eq, getElem_range] at ne
+ rw [decide_eq_false_iff_not, ← ne_eq, getElem_range] at ne
exact lt_of_le_of_ne (p.count_D_le_count_U (i + 1)) ne.symm
@[simp]
@@ -307,7 +306,7 @@ lemma firstReturn_add : (p + q).firstReturn = if p = 0 then q.firstReturn else p
· intro j hj
rw [take_append_eq_append_take, show j + 1 - p.toList.length = 0 by omega,
take_zero, append_nil]
- exact (count_D_lt_count_U_of_lt_firstReturn hj).ne'
+ simpa using (count_D_lt_count_U_of_lt_firstReturn hj).ne'
· rw [length_range, u, length_append]
exact Nat.lt_add_right _ (firstReturn_lt_length h)
@@ -323,6 +322,7 @@ lemma firstReturn_nest : p.nest.firstReturn = p.toList.length + 1 := by
beq_iff_eq, reduceCtorEq, ite_false, take_append_eq_append_take,
show j - p.toList.length = 0 by omega, take_zero, append_nil]
have := p.count_D_le_count_U j
+ simp only [add_zero, decide_eq_false_iff_not, ne_eq]
omega
· simp_rw [length_range, u, length_append, length_cons]
exact Nat.lt_add_one _
@@ -405,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 babe5c7b82742..76bb5d7812114 100644
--- a/Mathlib/Combinatorics/HalesJewett.lean
+++ b/Mathlib/Combinatorics/HalesJewett.lean
@@ -4,10 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: David Wärn
-/
import Mathlib.Algebra.BigOperators.Group.Finset
-import Mathlib.Data.Countable.Small
import Mathlib.Data.Fintype.Option
-import Mathlib.Data.Fintype.Pi
-import Mathlib.Data.Fintype.Prod
import Mathlib.Data.Fintype.Shrink
import Mathlib.Data.Fintype.Sum
@@ -141,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
@@ -154,7 +151,7 @@ def reindex (l : Subspace η α ι) (eη : η ≃ η') (eα : α ≃ α') (eι :
protected lemma IsMono.reindex {eη : η ≃ η'} {eα : α ≃ α'} {eι : ι ≃ ι'} {C : (ι → α) → κ}
(hl : l.IsMono C) : (l.reindex eη eα eι).IsMono fun x ↦ C <| eα.symm ∘ x ∘ eι := by
- simp [reindex_isMono, Function.comp.assoc]; simpa [← Function.comp.assoc]
+ simp [reindex_isMono, Function.comp_assoc]; simpa [← Function.comp_assoc]
end Subspace
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 0a41f5051974a..25e45662baf0d 100644
--- a/Mathlib/Combinatorics/Hindman.lean
+++ b/Mathlib/Combinatorics/Hindman.lean
@@ -3,9 +3,10 @@ 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.StoneCech
-import Mathlib.Topology.Algebra.Semigroup
+import Mathlib.Algebra.BigOperators.Group.Finset
import Mathlib.Data.Stream.Init
+import Mathlib.Topology.Algebra.Semigroup
+import Mathlib.Topology.StoneCech
/-!
# Hindman's theorem on finite sums
@@ -65,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
@@ -223,7 +223,7 @@ theorem FP.mul_two {M} [Semigroup M] (a : Stream' M) (i j : ℕ) (ij : i < j) :
refine FP_drop_subset_FP _ i ?_
rw [← Stream'.head_drop]
apply FP.cons
- rcases le_iff_exists_add.mp (Nat.succ_le_of_lt ij) with ⟨d, hd⟩
+ rcases Nat.exists_eq_add_of_le (Nat.succ_le_of_lt ij) with ⟨d, hd⟩
-- Porting note: need to fix breakage of Set notation
change _ ∈ FP _
have := FP.singleton (a.drop i).tail d
@@ -245,7 +245,7 @@ theorem FP.finset_prod {M} [CommMonoid M] (a : Stream' M) (s : Finset ℕ) (hs :
refine Set.mem_of_subset_of_mem ?_ (ih _ (Finset.erase_ssubset <| s.min'_mem hs) h)
have : s.min' hs + 1 ≤ (s.erase (s.min' hs)).min' h :=
Nat.succ_le_of_lt (Finset.min'_lt_of_mem_erase_min' _ _ <| Finset.min'_mem _ _)
- cases' le_iff_exists_add.mp this with d hd
+ cases' Nat.exists_eq_add_of_le this with d hd
rw [hd, add_comm, ← Stream'.drop_drop]
apply FP_drop_subset_FP
diff --git a/Mathlib/Combinatorics/Optimization/ValuedCSP.lean b/Mathlib/Combinatorics/Optimization/ValuedCSP.lean
index eee23c4281a09..956feba606f04 100644
--- a/Mathlib/Combinatorics/Optimization/ValuedCSP.lean
+++ b/Mathlib/Combinatorics/Optimization/ValuedCSP.lean
@@ -134,7 +134,7 @@ lemma Function.HasMaxCutPropertyAt.rows_lt_aux
{r : Fin 2 → D} (rin : r ∈ (ω.tt ![![a, b], ![b, a]])) :
f ![a, b] < f r := by
rw [FractionalOperation.tt, Multiset.mem_map] at rin
- rw [show r = ![r 0, r 1] from List.ofFn_inj.mp rfl]
+ rw [show r = ![r 0, r 1] by simp [← List.ofFn_inj]]
apply lt_of_le_of_ne (mcf.right (r 0) (r 1)).left
intro equ
have asymm : r 0 ≠ r 1 := by
@@ -146,7 +146,7 @@ lemma Function.HasMaxCutPropertyAt.rows_lt_aux
apply asymm
obtain ⟨o, in_omega, rfl⟩ := rin
show o (fun j => ![![a, b], ![b, a]] j 0) = o (fun j => ![![a, b], ![b, a]] j 1)
- convert symmega ![a, b] ![b, a] (List.Perm.swap b a []) o in_omega using 2 <;>
+ convert symmega ![a, b] ![b, a] (by simp [List.Perm.swap]) o in_omega using 2 <;>
simp [Matrix.const_fin1_eq]
lemma Function.HasMaxCutProperty.forbids_commutativeFractionalPolymorphism
@@ -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 0000d08b93bfe..78d2fbdeef06a 100644
--- a/Mathlib/Combinatorics/Quiver/Basic.lean
+++ b/Mathlib/Combinatorics/Quiver/Basic.lean
@@ -1,7 +1,7 @@
/-
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, Scott Morrison
+Authors: David Wärn, Kim Morrison
-/
import Mathlib.Data.Opposite
@@ -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 5466770a184d0..39dbcf18bda83 100644
--- a/Mathlib/Combinatorics/Quiver/Path.lean
+++ b/Mathlib/Combinatorics/Quiver/Path.lean
@@ -1,10 +1,11 @@
/-
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, Scott Morrison
+Authors: David Wärn, Kim Morrison
-/
import Mathlib.Combinatorics.Quiver.Basic
import Mathlib.Logic.Lemmas
+import Batteries.Data.List.Basic
/-!
# Paths in quivers
@@ -71,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
@@ -138,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/Quiver/ReflQuiver.lean b/Mathlib/Combinatorics/Quiver/ReflQuiver.lean
new file mode 100644
index 0000000000000..b0f9c85ac7250
--- /dev/null
+++ b/Mathlib/Combinatorics/Quiver/ReflQuiver.lean
@@ -0,0 +1,131 @@
+/-
+Copyright (c) 2024 Mario Carneiro and Emily Riehl. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Mario Carneiro, Emily Riehl
+-/
+import Mathlib.Data.Set.Function
+import Mathlib.CategoryTheory.Category.Cat
+
+/-!
+# Reflexive Quivers
+
+This module defines reflexive quivers. A reflexive quiver, or "refl quiver" for short, extends
+a quiver with a specified endoarrow on each term in its type of objects.
+
+We also introduce morphisms between reflexive quivers, called reflexive prefunctors or "refl
+prefunctors" for short.
+
+Note: Currently Category does not extend ReflQuiver, although it could. (TODO: do this)
+-/
+namespace CategoryTheory
+universe v v₁ v₂ u u₁ u₂
+
+/-- A reflexive quiver extends a quiver with a specified arrow `id X : X ⟶ X` for each `X` in its
+type of objects. We denote these arrows by `id` since categories can be understood as an extension
+of refl quivers.
+-/
+class ReflQuiver (obj : Type u) extends Quiver.{v} obj : Type max u v where
+ /-- The identity morphism on an object. -/
+ id : ∀ X : obj, Hom X X
+
+/-- Notation for the identity morphism in a category. -/
+scoped notation "𝟙rq" => ReflQuiver.id -- type as \b1
+
+instance catToReflQuiver {C : Type u} [inst : Category.{v} C] : ReflQuiver.{v+1, u} C :=
+ { inst with }
+
+@[simp] theorem ReflQuiver.id_eq_id {C : Type*} [Category C] (X : C) : 𝟙rq X = 𝟙 X := rfl
+
+/-- A morphism of reflexive quivers called a `ReflPrefunctor`. -/
+structure ReflPrefunctor (V : Type u₁) [ReflQuiver.{v₁} V] (W : Type u₂) [ReflQuiver.{v₂} W]
+ extends Prefunctor V W where
+ /-- A functor preserves identity morphisms. -/
+ map_id : ∀ X : V, map (𝟙rq X) = 𝟙rq (obj X) := by aesop_cat
+
+namespace ReflPrefunctor
+
+-- These lemmas can not be `@[simp]` because after `whnfR` they have a variable on the LHS.
+-- Nevertheless they are sometimes useful when building functors.
+lemma mk_obj {V W : Type*} [ReflQuiver V] [ReflQuiver W] {obj : V → W} {map} {X : V} :
+ (Prefunctor.mk obj map).obj X = obj X := rfl
+
+lemma mk_map {V W : Type*} [ReflQuiver V] [ReflQuiver W] {obj : V → W} {map} {X Y : V} {f : X ⟶ Y} :
+ (Prefunctor.mk obj map).map f = map f := rfl
+
+/-- Proving equality between reflexive prefunctors. This isn't an extensionality lemma,
+ because usually you don't really want to do this. -/
+theorem ext {V : Type u} [ReflQuiver.{v₁} V] {W : Type u₂} [ReflQuiver.{v₂} W]
+ {F G : ReflPrefunctor V W}
+ (h_obj : ∀ X, F.obj X = G.obj X)
+ (h_map : ∀ (X Y : V) (f : X ⟶ Y),
+ F.map f = Eq.recOn (h_obj Y).symm (Eq.recOn (h_obj X).symm (G.map f))) : F = G := by
+ obtain ⟨⟨F_obj⟩⟩ := F
+ obtain ⟨⟨G_obj⟩⟩ := G
+ obtain rfl : F_obj = G_obj := (Set.eqOn_univ F_obj G_obj).mp fun _ _ ↦ h_obj _
+ congr
+ funext X Y f
+ simpa using h_map X Y f
+
+/-- The identity morphism between reflexive quivers. -/
+@[simps!]
+def id (V : Type*) [ReflQuiver V] : ReflPrefunctor V V where
+ __ := Prefunctor.id _
+ map_id _ := rfl
+
+instance (V : Type*) [ReflQuiver V] : Inhabited (ReflPrefunctor V V) :=
+ ⟨id V⟩
+
+/-- Composition of morphisms between reflexive quivers. -/
+@[simps!]
+def comp {U : Type*} [ReflQuiver U] {V : Type*} [ReflQuiver V] {W : Type*} [ReflQuiver W]
+ (F : ReflPrefunctor U V) (G : ReflPrefunctor V W) : ReflPrefunctor U W where
+ __ := F.toPrefunctor.comp G.toPrefunctor
+ map_id _ := by simp [F.map_id, G.map_id]
+
+@[simp]
+theorem comp_id {U V : Type*} [ReflQuiver U] [ReflQuiver V] (F : ReflPrefunctor U V) :
+ F.comp (id _) = F := rfl
+
+@[simp]
+theorem id_comp {U V : Type*} [ReflQuiver U] [ReflQuiver V] (F : ReflPrefunctor U V) :
+ (id _).comp F = F := rfl
+
+@[simp]
+theorem comp_assoc {U V W Z : Type*} [ReflQuiver U] [ReflQuiver V] [ReflQuiver W] [ReflQuiver Z]
+ (F : ReflPrefunctor U V) (G : ReflPrefunctor V W) (H : ReflPrefunctor W Z) :
+ (F.comp G).comp H = F.comp (G.comp H) := rfl
+
+/-- Notation for a prefunctor between reflexive quivers. -/
+infixl:50 " ⥤rq " => ReflPrefunctor
+
+/-- Notation for composition of reflexive prefunctors. -/
+infixl:60 " ⋙rq " => ReflPrefunctor.comp
+
+/-- Notation for the identity prefunctor on a reflexive quiver. -/
+notation "𝟭rq" => id
+
+theorem congr_map {U V : Type*} [Quiver U] [Quiver V] (F : U ⥤q V) {X Y : U} {f g : X ⟶ Y}
+ (h : f = g) : F.map f = F.map g := congrArg F.map h
+
+end ReflPrefunctor
+
+/-- A functor has an underlying refl prefunctor.-/
+def Functor.toReflPrefunctor {C D} [Category C] [Category D] (F : C ⥤ D) : C ⥤rq D := { F with }
+
+@[simp]
+theorem Functor.toReflPrefunctor_toPrefunctor {C D : Cat} (F : C ⥤ D) :
+ (Functor.toReflPrefunctor F).toPrefunctor = F.toPrefunctor := rfl
+
+namespace ReflQuiver
+open Opposite
+
+/-- `Vᵒᵖ` reverses the direction of all arrows of `V`. -/
+instance opposite {V} [ReflQuiver V] : ReflQuiver Vᵒᵖ where
+ id X := op (𝟙rq X.unop)
+
+instance discreteReflQuiver (V : Type u) : ReflQuiver.{u+1} (Discrete V) :=
+ { discreteCategory V with }
+
+end ReflQuiver
+
+end CategoryTheory
diff --git a/Mathlib/Combinatorics/Schnirelmann.lean b/Mathlib/Combinatorics/Schnirelmann.lean
index d56f44bd816ff..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,10 +193,10 @@ 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]
+ rw [div_lt_iff₀ (Nat.cast_pos.2 hn), ← div_lt_iff₀' hε, Nat.cast_add_one]
exact (Nat.lt_floor_add_one _).trans_le' <| by gcongr; simp [subset_iff]
/-- The Schnirelmann density of any finite set is `0`. -/
@@ -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 2c7b78ec4d1b5..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
@@ -219,7 +218,7 @@ lemma sum_collapse (h𝒜 : 𝒜 ⊆ (insert a u).powerset) (hu : a ∉ u) :
_ = ∑ s ∈ u.powerset ∩ 𝒜, f s + ∑ s ∈ u.powerset.image (insert a) ∩ 𝒜, f s := ?_
_ = ∑ s ∈ u.powerset ∩ 𝒜, f s + ∑ s ∈ ((insert a u).powerset \ u.powerset) ∩ 𝒜, f s := ?_
_ = ∑ s ∈ 𝒜, f s := ?_
- · rw [← sum_ite_mem, ← sum_ite_mem, sum_image, ← sum_add_distrib]
+ · rw [← Finset.sum_ite_mem, ← Finset.sum_ite_mem, sum_image, ← sum_add_distrib]
· exact sum_congr rfl fun s hs ↦ collapse_eq (not_mem_mono (mem_powerset.1 hs) hu) _ _
· exact (insert_erase_invOn.2.injOn).mono fun s hs ↦ not_mem_mono (mem_powerset.1 hs) hu
· congr with s
@@ -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 7fe6c323c2871..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]
@@ -79,5 +79,5 @@ theorem Finset.card_biUnion_le_of_intersecting (s : Finset ι) (f : ι → Finse
(ih _ (fun i hi ↦ (hf₁ _ <| subset_cons _ hi).2.2)
((card_le_card <| subset_cons _).trans hs)) _).trans ?_
rw [mul_tsub, two_mul, ← pow_succ',
- ← add_tsub_assoc_of_le (pow_le_pow_right' (one_le_two : (1 : ℕ) ≤ 2) tsub_le_self),
+ ← add_tsub_assoc_of_le (pow_right_mono₀ (one_le_two : (1 : ℕ) ≤ 2) tsub_le_self),
tsub_add_eq_add_tsub hs, card_cons, add_tsub_add_eq_tsub_right]
diff --git a/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean b/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean
index c038ae31aa350..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,15 +80,15 @@ 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
-- if j < k, k is our colex witness for t ∪ {j} < s
· refine Or.inr ⟨k, mem_of_mem_erase ‹_›, fun hk ↦ hkt <| mem_of_mem_insert_of_ne hk hjk.ne',
fun x hx ↦ ?_⟩
- simpa only [mem_insert, z hx, (hjk.trans hx).ne', mem_erase, Ne, false_or_iff,
+ simpa only [mem_insert, z hx, (hjk.trans hx).ne', mem_erase, Ne, false_or,
and_iff_right_iff_imp] using fun _ ↦ ((min'_le _ _ <| mem_of_mem_erase hks).trans_lt hx).ne'
-- if j = k, all of range k is in t so by sizes t ∪ {j} = s
refine Or.inl (eq_of_subset_of_card_le (fun a ha ↦ ?_) hcard.ge).symm
@@ -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,17 +141,17 @@ 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 _U _V ↦ And.decidable
+ fun _ _ ↦ inferInstanceAs (Decidable (_ ∧ _))
/-- Applying a good compression will decrease measure, keep cardinality, keep sizes and decrease
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 bc4f6f690c062..7e12901d9f2f6 100644
--- a/Mathlib/Combinatorics/SetFamily/Shadow.lean
+++ b/Mathlib/Combinatorics/SetFamily/Shadow.lean
@@ -75,7 +75,10 @@ theorem shadow_empty : ∂ (∅ : Finset (Finset α)) = ∅ :=
theorem shadow_singleton_empty : ∂ ({∅} : Finset (Finset α)) = ∅ :=
rfl
---TODO: Prove `∂ {{a}} = {∅}` quickly using `covers` and `GradeOrder`
+@[simp]
+theorem shadow_singleton (a : α) : ∂ {{a}} = {∅} := by
+ simp [shadow]
+
/-- The shadow is monotone. -/
@[mono]
theorem shadow_monotone : Monotone (shadow : Finset (Finset α) → Finset (Finset α)) := fun _ _ =>
@@ -94,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
@@ -106,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
@@ -124,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⟩
@@ -137,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]
@@ -206,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
@@ -219,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,
@@ -241,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⟩
@@ -254,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]
@@ -274,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 6efd8f20ec42e..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,14 +72,15 @@ 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 ↦ ?_
simp_rw [mem_biUnion, mem_powerset]
exact h.exists_superset
-lemma shatterer_mono (h : 𝒜 ⊆ ℬ) : 𝒜.shatterer ⊆ ℬ.shatterer :=
+@[gcongr] lemma shatterer_mono (h : 𝒜 ⊆ ℬ) : 𝒜.shatterer ⊆ ℬ.shatterer :=
fun _ ↦ by simpa using Shatters.mono_left h
lemma subset_shatterer (h : IsLowerSet (𝒜 : Set (Finset α))) : 𝒜 ⊆ 𝒜.shatterer :=
@@ -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]
@@ -181,7 +181,9 @@ lemma shatterer_compress_subset_shatterer (a : α) (𝒜 : Finset (Finset α)) :
/-- The Vapnik-Chervonenkis dimension of a set family is the maximal size of a set it shatters. -/
def vcDim (𝒜 : Finset (Finset α)) : ℕ := 𝒜.shatterer.sup card
-lemma Shatters.card_le_vcDim (hs : 𝒜.Shatters s) : s.card ≤ 𝒜.vcDim := le_sup <| mem_shatterer.2 hs
+@[gcongr] lemma vcDim_mono (h𝒜ℬ : 𝒜 ⊆ ℬ) : 𝒜.vcDim ≤ ℬ.vcDim := by unfold vcDim; gcongr
+
+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 :=
@@ -189,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/Acyclic.lean b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean
index 2cb9bcfec2287..9782814a525cc 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean
@@ -14,8 +14,8 @@ This module introduces *acyclic graphs* (a.k.a. *forests*) and *trees*.
## Main definitions
-* `SimpleGraph.IsAcyclic` is a predicate for a graph having no cyclic walks
-* `SimpleGraph.IsTree` is a predicate for a graph being a tree (a connected acyclic graph)
+* `SimpleGraph.IsAcyclic` is a predicate for a graph having no cyclic walks.
+* `SimpleGraph.IsTree` is a predicate for a graph being a tree (a connected acyclic graph).
## Main statements
@@ -114,7 +114,7 @@ theorem isAcyclic_of_path_unique (h : ∀ (v w : V) (p q : G.Path v w), p = q) :
cases c with
| nil => cases hc.2.1 rfl
| cons ha c' =>
- simp only [Walk.cons_isTrail_iff, Walk.support_cons, List.tail_cons, true_and_iff] at hc
+ simp only [Walk.cons_isTrail_iff, Walk.support_cons, List.tail_cons] at hc
specialize h _ _ ⟨c', by simp only [Walk.isPath_def, hc.2]⟩ (Path.singleton ha.symm)
rw [Path.singleton, Subtype.mk.injEq] at h
simp [h] at hc
@@ -132,7 +132,7 @@ theorem isTree_iff_existsUnique_path :
intro v w
let q := (hc v w).some.toPath
use q
- simp only [true_and_iff, Path.isPath]
+ simp only [true_and, Path.isPath]
intro p hp
specialize hu ⟨p, hp⟩ q
exact Subtype.ext_iff.mp hu
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 6aaf4e25f4463..40be1f3971a03 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean
@@ -15,13 +15,13 @@ This module defines simple graphs on a vertex type `V` as an irreflexive symmetr
## Main definitions
-* `SimpleGraph` is a structure for symmetric, irreflexive relations
+* `SimpleGraph` is a structure for symmetric, irreflexive relations.
-* `SimpleGraph.neighborSet` is the `Set` of vertices adjacent to a given vertex
+* `SimpleGraph.neighborSet` is the `Set` of vertices adjacent to a given vertex.
-* `SimpleGraph.commonNeighbors` is the intersection of the neighbor sets of two given vertices
+* `SimpleGraph.commonNeighbors` is the intersection of the neighbor sets of two given vertices.
-* `SimpleGraph.incidenceSet` is the `Set` of edges containing a given vertex
+* `SimpleGraph.incidenceSet` is the `Set` of edges containing a given vertex.
* `CompleteAtomicBooleanAlgebra` instance: Under the subgraph relation, `SimpleGraph` forms a
`CompleteAtomicBooleanAlgebra`. In other words, this is the complete lattice of spanning subgraphs
@@ -29,10 +29,10 @@ This module defines simple graphs on a vertex type `V` as an irreflexive symmetr
## TODO
-* This is the simplest notion of an unoriented graph. This should
- eventually fit into a more complete combinatorics hierarchy which
- includes multigraphs and directed graphs. We begin with simple graphs
- in order to start learning what the combinatorics hierarchy should
+* This is the simplest notion of an unoriented graph.
+ This should eventually fit into a more complete combinatorics hierarchy which includes
+ multigraphs and directed graphs.
+ We begin with simple graphs in order to start learning what the combinatorics hierarchy should
look like.
-/
@@ -68,9 +68,8 @@ macro (name := aesop_graph?) "aesop_graph?" c:Aesop.tactic_clause* : tactic =>
(rule_sets := [$(Lean.mkIdent `SimpleGraph):ident]))
/--
-A variant of `aesop_graph` which does not fail if it is unable to solve the
-goal. Use this only for exploration! Nonterminal Aesop is even worse than
-nonterminal `simp`.
+A variant of `aesop_graph` which does not fail if it is unable to solve the goal.
+Use this only for exploration! Nonterminal Aesop is even worse than nonterminal `simp`.
-/
macro (name := aesop_graph_nonterminal) "aesop_graph_nonterminal" c:Aesop.tactic_clause* : tactic =>
`(tactic|
@@ -123,6 +122,10 @@ instance {V : Type u} [Fintype V] [DecidableEq V] : Fintype (SimpleGraph V) wher
· ext
simp
+/-- There are finitely many simple graphs on a given finite type. -/
+instance SimpleGraph.instFinite {V : Type u} [Finite V] : Finite (SimpleGraph V) :=
+ .of_injective SimpleGraph.Adj fun _ _ ↦ SimpleGraph.ext
+
/-- Construct the simple graph induced by the given relation. It
symmetrizes the relation and makes it irreflexive. -/
def SimpleGraph.fromRel {V : Type u} (r : V → V → Prop) : SimpleGraph V where
@@ -234,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 :=
@@ -253,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 }
@@ -305,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]
@@ -352,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
@@ -515,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) :=
@@ -552,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 :=
@@ -573,12 +576,12 @@ theorem fromEdgeSet_edgeSet : fromEdgeSet G.edgeSet = G := by
@[simp]
theorem fromEdgeSet_empty : fromEdgeSet (∅ : Set (Sym2 V)) = ⊥ := by
ext v w
- simp only [fromEdgeSet_adj, Set.mem_empty_iff_false, false_and_iff, bot_adj]
+ simp only [fromEdgeSet_adj, Set.mem_empty_iff_false, false_and, bot_adj]
@[simp]
theorem fromEdgeSet_univ : fromEdgeSet (Set.univ : Set (Sym2 V)) = ⊤ := by
ext v w
- simp only [fromEdgeSet_adj, Set.mem_univ, true_and_iff, top_adj]
+ simp only [fromEdgeSet_adj, Set.mem_univ, true_and, top_adj]
@[simp]
theorem fromEdgeSet_inter (s t : Set (Sym2 V)) :
@@ -603,7 +606,7 @@ theorem fromEdgeSet_sdiff (s t : Set (Sym2 V)) :
theorem fromEdgeSet_mono {s t : Set (Sym2 V)} (h : s ⊆ t) : fromEdgeSet s ≤ fromEdgeSet t := by
rintro v w
simp (config := { contextual := true }) only [fromEdgeSet_adj, Ne, not_false_iff,
- and_true_iff, and_imp]
+ and_true, and_imp]
exact fun vws _ => h vws
@[simp] lemma disjoint_fromEdgeSet : Disjoint G (fromEdgeSet s) ↔ Disjoint G.edgeSet s := by
@@ -706,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 dabe8553d196a..99106b3256d7b 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean
@@ -3,7 +3,7 @@ Copyright (c) 2024 Iván Renison, Bhavik Mehta. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Iván Renison, Bhavik Mehta
-/
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Combinatorics.SimpleGraph.Hasse
/-!
@@ -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 8de6f50777720..fc597f6af613d 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Clique.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Clique.lean
@@ -10,8 +10,8 @@ import Mathlib.Data.Finset.Pairwise
/-!
# Graph cliques
-This file defines cliques in simple graphs. A clique is a set of vertices that are pairwise
-adjacent.
+This file defines cliques in simple graphs.
+A clique is a set of vertices that are pairwise adjacent.
## Main declarations
@@ -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
@@ -270,9 +270,9 @@ theorem not_cliqueFree_of_top_embedding {n : ℕ} (f : (⊤ : SimpleGraph (Fin n
¬G.CliqueFree n := by
simp only [CliqueFree, isNClique_iff, isClique_iff_induce_eq, not_forall, Classical.not_not]
use Finset.univ.map f.toEmbedding
- simp only [card_map, Finset.card_fin, eq_self_iff_true, and_true_iff]
+ simp only [card_map, Finset.card_fin, eq_self_iff_true, and_true]
ext ⟨v, hv⟩ ⟨w, hw⟩
- simp only [coe_map, Set.mem_image, coe_univ, Set.mem_univ, true_and_iff] at hv hw
+ simp only [coe_map, Set.mem_image, coe_univ, Set.mem_univ, true_and] at hv hw
obtain ⟨v', rfl⟩ := hv
obtain ⟨w', rfl⟩ := hw
simp only [coe_sort_coe, RelEmbedding.coe_toEmbedding, comap_adj, Function.Embedding.coe_subtype,
@@ -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/Coloring.lean b/Mathlib/Combinatorics/SimpleGraph/Coloring.lean
index e818705987f80..9d98315f91068 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Coloring.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Coloring.lean
@@ -13,11 +13,11 @@ import Mathlib.Data.Nat.Cast.Order.Ring
/-!
# Graph Coloring
-This module defines colorings of simple graphs (also known as proper
-colorings in the literature). A graph coloring is the attribution of
-"colors" to all of its vertices such that adjacent vertices have
-different colors. A coloring can be represented as a homomorphism into
-a complete graph, whose vertices represent the colors.
+This module defines colorings of simple graphs (also known as proper colorings in the literature).
+A graph coloring is the attribution of "colors" to all of its vertices such that adjacent vertices
+have different colors.
+A coloring can be represented as a homomorphism into a complete graph, whose vertices represent
+the colors.
## Main definitions
@@ -29,14 +29,12 @@ a complete graph, whose vertices represent the colors.
* `G.Colorable n` is the proposition that `G` is `n`-colorable, which
is whether there exists a coloring with at most *n* colors.
-* `G.chromaticNumber` is the minimal `n` such that `G` is
- `n`-colorable, or `⊤` if it cannot be colored with finitely many
- colors.
+* `G.chromaticNumber` is the minimal `n` such that `G` is `n`-colorable,
+ or `⊤` if it cannot be colored with finitely many colors.
(Cardinal-valued chromatic numbers are more niche, so we stick to `ℕ∞`.)
We write `G.chromaticNumber ≠ ⊤` to mean a graph is colorable with finitely many colors.
-* `C.colorClass c` is the set of vertices colored by `c : α` in the
- coloring `C : G.Coloring α`.
+* `C.colorClass c` is the set of vertices colored by `c : α` in the coloring `C : G.Coloring α`.
* `C.colorClasses` is the set containing all color classes.
diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean
index 15302f6c68c45..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 -/
@@ -41,7 +40,7 @@ theorem set_walk_self_length_zero_eq (u : V) : {p : G.Walk u u | p.length = 0} =
theorem set_walk_length_zero_eq_of_ne {u v : V} (h : u ≠ v) :
{p : G.Walk u v | p.length = 0} = ∅ := by
ext p
- simp only [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false_iff]
+ simp only [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false]
exact fun h' => absurd (Walk.eq_of_length_eq_zero h') h
theorem set_walk_length_succ_eq (u v : V) (n : ℕ) :
@@ -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
@@ -107,12 +106,36 @@ theorem coe_finsetWalkLength_eq (n : ℕ) (u v : V) :
variable {G}
-theorem Walk.mem_finsetWalkLength_iff_length_eq {n : ℕ} {u v : V} (p : G.Walk u v) :
+theorem mem_finsetWalkLength_iff {n : ℕ} {u v : V} {p : G.Walk u v} :
p ∈ G.finsetWalkLength n u v ↔ p.length = n :=
Set.ext_iff.mp (G.coe_finsetWalkLength_eq n u v) p
variable (G)
+/-- The `Finset` of walks from `u` to `v` with length less than `n`. See `finsetWalkLength` for
+context. In particular, we use this definition for `SimpleGraph.Path.instFintype`. --/
+def finsetWalkLengthLT (n : ℕ) (u v : V) : Finset (G.Walk u v) :=
+ (Finset.range n).disjiUnion
+ (fun l ↦ G.finsetWalkLength l u v)
+ (fun l _ l' _ hne _ hsl hsl' p hp ↦
+ have hl : p.length = l := mem_finsetWalkLength_iff.mp (hsl hp)
+ have hl' : p.length = l' := mem_finsetWalkLength_iff.mp (hsl' hp)
+ False.elim <| hne <| hl.symm.trans hl')
+
+open Finset in
+theorem coe_finsetWalkLengthLT_eq (n : ℕ) (u v : V) :
+ (G.finsetWalkLengthLT n u v : Set (G.Walk u v)) = {p : G.Walk u v | p.length < n} := by
+ ext p
+ simp [finsetWalkLengthLT, mem_coe, mem_disjiUnion, mem_finsetWalkLength_iff]
+
+variable {G}
+
+theorem mem_finsetWalkLengthLT_iff {n : ℕ} {u v : V} {p : G.Walk u v} :
+ p ∈ G.finsetWalkLengthLT n u v ↔ p.length < n :=
+ Set.ext_iff.mp (G.coe_finsetWalkLengthLT_eq n u v) p
+
+variable (G)
+
instance fintypeSetWalkLength (u v : V) (n : ℕ) : Fintype {p : G.Walk u v | p.length = n} :=
Fintype.ofFinset (G.finsetWalkLength n u v) fun p => by
rw [← Finset.mem_coe, coe_finsetWalkLength_eq]
@@ -128,18 +151,38 @@ 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]
+instance fintypeSetWalkLengthLT (u v : V) (n : ℕ) : Fintype {p : G.Walk u v | p.length < n} :=
+ Fintype.ofFinset (G.finsetWalkLengthLT n u v) fun p ↦ by
+ rw [← Finset.mem_coe, coe_finsetWalkLengthLT_eq]
+
+instance fintypeSubtypeWalkLengthLT (u v : V) (n : ℕ) : Fintype {p : G.Walk u v // p.length < n} :=
+ fintypeSetWalkLengthLT G u v n
+
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
- simp [Walk.mem_finsetWalkLength_iff_length_eq, and_comm]
+ Fintype.ofFinset {w ∈ G.finsetWalkLength n u v | w.IsPath} <| by
+ simp [mem_finsetWalkLength_iff, and_comm]
+
+instance fintypeSubtypePathLength (u v : V) (n : ℕ) :
+ Fintype {p : G.Walk u v // p.IsPath ∧ p.length = n} :=
+ fintypeSetPathLength G u v n
+
+instance fintypeSetPathLengthLT (u v : V) (n : ℕ) :
+ Fintype {p : G.Walk u v | p.IsPath ∧ p.length < n} :=
+ Fintype.ofFinset {w ∈ G.finsetWalkLengthLT n u v | w.IsPath} <| by
+ simp [mem_finsetWalkLengthLT_iff, and_comm]
+
+instance fintypeSubtypePathLengthLT (u v : V) (n : ℕ) :
+ Fintype {p : G.Walk u v // p.IsPath ∧ p.length < n} :=
+ fintypeSetPathLengthLT G u v n
end LocallyFinite
-section Finite
+section Fintype
variable [DecidableEq V] [Fintype V] [DecidableRel G.Adj]
@@ -149,7 +192,7 @@ theorem reachable_iff_exists_finsetWalkLength_nonempty (u v : V) :
· intro r
refine r.elim_path fun p => ?_
refine ⟨⟨_, p.isPath.length_lt⟩, p, ?_⟩
- simp [Walk.mem_finsetWalkLength_iff_length_eq]
+ simp [mem_finsetWalkLength_iff]
· rintro ⟨_, p, _⟩
exact ⟨p⟩
@@ -166,6 +209,14 @@ instance : Decidable G.Connected := by
rw [connected_iff, ← Finset.univ_nonempty_iff]
infer_instance
+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 },
+ fun _ _ h ↦ SetCoe.ext <| Subtype.mk.injEq .. ▸ h⟩
+ complete p := mem_map.mpr ⟨
+ ⟨p.val, ⟨p.prop, p.prop.length_lt⟩⟩,
+ ⟨mem_univ _, rfl⟩⟩
+
instance instDecidableMemSupp (c : G.ConnectedComponent) (v : V) : Decidable (v ∈ c.supp) :=
c.recOn (fun w ↦ decidable_of_iff (G.Reachable v w) <| by simp)
(fun _ _ _ _ ↦ Subsingleton.elim _ _)
@@ -179,20 +230,20 @@ lemma disjiUnion_supp_toFinset_eq_supp_toFinset {G' : SimpleGraph V} (h : G ≤
c'.supp.toFinset :=
Finset.coe_injective <| by simpa using ConnectedComponent.biUnion_supp_eq_supp h _
-lemma ConnectedComponent.odd_card_supp_iff_odd_subcomponents {G'}
+end Fintype
+
+lemma ConnectedComponent.odd_card_supp_iff_odd_subcomponents [Finite V] {G'}
(h : G ≤ G') (c' : ConnectedComponent G') :
Odd (Nat.card c'.supp) ↔ Odd (Nat.card
({c : ConnectedComponent G | c.supp ⊆ c'.supp ∧ Odd (Nat.card c.supp) })) := by
classical
- -- have := Fintype.ofFinite:
+ cases nonempty_fintype V
rw [Nat.card_eq_card_toFinset, ← disjiUnion_supp_toFinset_eq_supp_toFinset h]
simp only [Finset.card_disjiUnion, Set.toFinset_card]
rw [Finset.odd_sum_iff_odd_card_odd, Nat.card_eq_fintype_card, Fintype.card_ofFinset]
simp only [Nat.card_eq_fintype_card, Finset.filter_filter]
rfl
-end Finite
-
lemma odd_card_iff_odd_components [Finite V] : Odd (Nat.card V) ↔
Odd (Nat.card ({(c : ConnectedComponent G) | Odd (Nat.card c.supp)})) := by
classical
diff --git a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean
index 7a78571cb9edc..5904dc6245e9b 100644
--- a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean
@@ -6,7 +6,7 @@ Authors: Kyle Miller
import Mathlib.Algebra.BigOperators.Ring
import Mathlib.Combinatorics.SimpleGraph.Dart
import Mathlib.Combinatorics.SimpleGraph.Finite
-import Mathlib.Data.ZMod.Parity
+import Mathlib.Data.ZMod.Basic
/-!
# Degree-sum formula and handshaking lemma
@@ -49,9 +49,9 @@ 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_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
+ simp only [mem_image, true_and, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
constructor
· rintro rfl
exact ⟨_, d.adj, by ext <;> rfl⟩
@@ -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
@@ -121,17 +120,17 @@ theorem even_card_odd_degree_vertices [Fintype V] [DecidableRel G.Adj] :
convert h
exact ZMod.ne_zero_iff_odd.symm
· intro v
- simp only [true_and_iff, mem_filter, mem_univ, Ne]
+ simp only [true_and, mem_filter, mem_univ, Ne]
rw [ZMod.eq_zero_iff_even, ZMod.eq_one_iff_odd, ← Nat.not_even_iff_odd, imp_self]
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_iff, mem_filter, mem_univ]
+ simp only [true_and, mem_filter, mem_univ]
exact h
rwa [← card_pos, hg, ← two_mul, mul_pos_iff_of_pos_left] at hh
exact zero_lt_two
@@ -144,17 +143,17 @@ theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] [DecidableRe
rw [add_assoc, one_add_one_eq_two, ← Nat.mul_succ, ← two_mul]
congr
omega
- · simpa only [true_and_iff, mem_filter, mem_univ]
+ · simpa only [true_and, mem_filter, mem_univ]
theorem exists_ne_odd_degree_of_exists_odd_degree [Fintype V] [DecidableRel G.Adj] (v : V)
(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⟩
- simp only [true_and_iff, mem_filter, mem_univ, Ne] at hw
+ simp only [true_and, mem_filter, mem_univ, Ne] at hw
exact ⟨w, hw⟩
end SimpleGraph
diff --git a/Mathlib/Combinatorics/SimpleGraph/Density.lean b/Mathlib/Combinatorics/SimpleGraph/Density.lean
index 6f388c7ffd277..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,14 +113,14 @@ 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
apply div_nonneg <;> exact mod_cast Nat.zero_le _
theorem edgeDensity_le_one (s : Finset α) (t : Finset β) : edgeDensity r s t ≤ 1 := by
- apply div_le_one_of_le
+ apply div_le_one_of_le₀
· exact mod_cast card_interedges_le_mul r s t
· exact mod_cast Nat.zero_le _
@@ -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,33 +154,33 @@ 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]
- refine sub_nonneg_of_le (mul_le_one ?_ ?_ ?_)
- · exact div_le_one_of_le ((@Nat.cast_le ℚ).2 (card_le_card hs)) (Nat.cast_nonneg _)
+ refine sub_nonneg_of_le (mul_le_one₀ ?_ ?_ ?_)
+ · exact div_le_one_of_le₀ ((@Nat.cast_le ℚ).2 (card_le_card hs)) (Nat.cast_nonneg _)
· apply div_nonneg <;> exact mod_cast Nat.zero_le _
- · exact div_le_one_of_le ((@Nat.cast_le ℚ).2 (card_le_card ht)) (Nat.cast_nonneg _)
+ · exact div_le_one_of_le₀ ((@Nat.cast_le ℚ).2 (card_le_card ht)) (Nat.cast_nonneg _)
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 278ba02e0df80..e0611556ee07e 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean
@@ -92,27 +92,35 @@ theorem edgeFinset_inf [DecidableEq V] : (G₁ ⊓ G₂).edgeFinset = G₁.edgeF
theorem edgeFinset_sdiff [DecidableEq V] :
(G₁ \ G₂).edgeFinset = G₁.edgeFinset \ G₂.edgeFinset := by simp [edgeFinset]
-theorem edgeFinset_card : G.edgeFinset.card = Fintype.card G.edgeSet :=
+lemma disjoint_edgeFinset : Disjoint G₁.edgeFinset G₂.edgeFinset ↔ Disjoint G₁ G₂ := by
+ simp_rw [← Finset.disjoint_coe, coe_edgeFinset, disjoint_edgeSet]
+
+lemma edgeFinset_eq_empty : G.edgeFinset = ∅ ↔ G = ⊥ := by
+ rw [← edgeFinset_bot, edgeFinset_inj]
+
+lemma edgeFinset_nonempty : G.edgeFinset.Nonempty ↔ G ≠ ⊥ := by
+ rw [Finset.nonempty_iff_ne_empty, edgeFinset_eq_empty.ne]
+
+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)
@@ -134,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))
@@ -194,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 :=
@@ -231,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
@@ -242,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]
@@ -285,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
@@ -408,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 0cb730278bd98..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
/-!
@@ -36,7 +37,7 @@ lemma IsHamiltonian.map {H : SimpleGraph β} (f : G →g H) (hf : Bijective f) (
/-- A hamiltonian path visits every vertex. -/
@[simp] lemma IsHamiltonian.mem_support (hp : p.IsHamiltonian) (c : α) : c ∈ p.support := by
- simp only [← List.count_pos_iff_mem, hp _, Nat.zero_lt_one]
+ simp only [← List.count_pos_iff, hp _, Nat.zero_lt_one]
/-- Hamiltonian paths are paths. -/
lemma IsHamiltonian.isPath (hp : p.IsHamiltonian) : p.IsPath :=
@@ -45,13 +46,13 @@ lemma IsHamiltonian.isPath (hp : p.IsHamiltonian) : p.IsPath :=
/-- A path whose support contains every vertex is hamiltonian. -/
lemma IsPath.isHamiltonian_of_mem (hp : p.IsPath) (hp' : ∀ w, w ∈ p.support) :
p.IsHamiltonian := fun _ ↦
- le_antisymm (List.nodup_iff_count_le_one.1 hp.support_nodup _) (List.count_pos_iff_mem.2 (hp' _))
+ le_antisymm (List.nodup_iff_count_le_one.1 hp.support_nodup _) (List.count_pos_iff.2 (hp' _))
lemma IsPath.isHamiltonian_iff (hp : p.IsPath) : p.IsHamiltonian ↔ ∀ w, w ∈ p.support :=
⟨(·.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, 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 ec09c234563e3..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
@@ -125,10 +125,10 @@ theorem sum_incMatrix_apply_of_mem_edgeSet [Fintype α] :
intro a b h
rw [mem_edgeSet] at h
rw [← Nat.cast_two, ← card_pair h.ne]
- simp only [incMatrix_apply', sum_boole, mk'_mem_incidenceSet_iff, h, true_and_iff]
+ simp only [incMatrix_apply', sum_boole, mk'_mem_incidenceSet_iff, h]
congr 2
ext e
- simp only [mem_filter, mem_univ, true_and_iff, mem_insert, mem_singleton]
+ simp only [mem_filter, mem_univ, true_and, mem_insert, mem_singleton]
theorem sum_incMatrix_apply_of_not_mem_edgeSet [Fintype α] (h : e ∉ G.edgeSet) :
∑ a, G.incMatrix R a e = 0 :=
@@ -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/LapMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean
index 40f0ebf38db1e..e609a7dee3f0e 100644
--- a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean
@@ -189,8 +189,8 @@ end
/-- The number of connected components in `G` is the dimension of the nullspace its Laplacian. -/
theorem card_ConnectedComponent_eq_rank_ker_lapMatrix : Fintype.card G.ConnectedComponent =
- FiniteDimensional.finrank ℝ (LinearMap.ker (Matrix.toLin' (G.lapMatrix ℝ))) := by
+ Module.finrank ℝ (LinearMap.ker (Matrix.toLin' (G.lapMatrix ℝ))) := by
classical
- rw [FiniteDimensional.finrank_eq_card_basis (lapMatrix_ker_basis G)]
+ rw [Module.finrank_eq_card_basis (lapMatrix_ker_basis G)]
end SimpleGraph
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/Matching.lean b/Mathlib/Combinatorics/SimpleGraph/Matching.lean
index e273e25537184..862f0f20756a5 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Matching.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Matching.lean
@@ -193,9 +193,7 @@ namespace ConnectedComponent
section Finite
-variable [Fintype V]
-
-lemma even_card_of_isPerfectMatching [DecidableEq V] [DecidableRel G.Adj]
+lemma even_card_of_isPerfectMatching [Fintype V] [DecidableEq V] [DecidableRel G.Adj]
(c : ConnectedComponent G) (hM : M.IsPerfectMatching) :
Even (Fintype.card c.supp) := by
#adaptation_note
@@ -208,7 +206,8 @@ lemma even_card_of_isPerfectMatching [DecidableEq V] [DecidableRel G.Adj]
letI : DecidablePred fun x ↦ x ∈ (M.induce c.supp).verts := fun a ↦ G.instDecidableMemSupp c a
simpa using (hM.induce_connectedComponent_isMatching c).even_card
-lemma odd_matches_node_outside {u : Set V} {c : ConnectedComponent (Subgraph.deleteVerts ⊤ u).coe}
+lemma odd_matches_node_outside [Finite V] {u : Set V}
+ {c : ConnectedComponent (Subgraph.deleteVerts ⊤ u).coe}
(hM : M.IsPerfectMatching) (codd : Odd (Nat.card c.supp)) :
∃ᵉ (w ∈ u) (v : ((⊤ : G.Subgraph).deleteVerts u).verts), M.Adj v w ∧ v ∈ c.supp := by
by_contra! h
@@ -224,7 +223,6 @@ lemma odd_matches_node_outside {u : Set V} {c : ConnectedComponent (Subgraph.del
Subgraph.induce_adj, hwnu, not_false_eq_true, and_self, Subgraph.top_adj, M.adj_sub hw.1,
and_true] at hv' ⊢
trivial
-
apply Nat.not_even_iff_odd.2 codd
haveI : Fintype ↑(Subgraph.induce M (Subtype.val '' supp c)).verts := Fintype.ofFinite _
classical
@@ -254,9 +252,9 @@ lemma IsMatchingFree.mono {G G' : SimpleGraph V} (h : G ≤ G') (hmf : G'.IsMatc
simp only [Subgraph.map_verts, Hom.coe_ofLE, id_eq, Set.image_id']
exact hc.2 v
-lemma exists_maximal_isMatchingFree [Fintype V] [DecidableEq V]
- (h : G.IsMatchingFree) : ∃ Gmax : SimpleGraph V,
- G ≤ Gmax ∧ Gmax.IsMatchingFree ∧ ∀ G', G' > Gmax → ∃ M : Subgraph G', M.IsPerfectMatching := by
+lemma exists_maximal_isMatchingFree [Finite V] (h : G.IsMatchingFree) :
+ ∃ Gmax : SimpleGraph V, G ≤ Gmax ∧ Gmax.IsMatchingFree ∧
+ ∀ G', G' > Gmax → ∃ M : Subgraph G', M.IsPerfectMatching := by
simp_rw [← @not_forall_not _ Subgraph.IsPerfectMatching]
obtain ⟨Gmax, hGmax⟩ := Finite.exists_le_maximal h
exact ⟨Gmax, ⟨hGmax.1, ⟨hGmax.2.prop, fun _ h' ↦ hGmax.2.not_prop_of_gt h'⟩⟩⟩
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/Path.lean b/Mathlib/Combinatorics/SimpleGraph/Path.lean
index a094d7bce9012..f40c73152000a 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Path.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Path.lean
@@ -590,7 +590,7 @@ end Path
namespace Walk
variable {G} {p} {u v : V} {H : SimpleGraph V}
-variable (p : G.Walk u v)
+variable {p : G.Walk u v}
protected theorem IsPath.transfer (hp) (pp : p.IsPath) :
(p.transfer H hp).IsPath := by
@@ -1124,7 +1124,7 @@ theorem adj_and_reachable_delete_edges_iff_exists_cycle {v w : V} :
rw [Sym2.eq_swap]
intro h
cases hp (Walk.edges_toPath_subset p h)
- · simp only [Sym2.eq_swap, Walk.edges_cons, List.mem_cons, eq_self_iff_true, true_or_iff]
+ · simp only [Sym2.eq_swap, Walk.edges_cons, List.mem_cons, eq_self_iff_true, true_or]
· rintro ⟨u, c, hc, he⟩
refine ⟨c.adj_of_mem_edges he, ?_⟩
by_contra! hb
@@ -1143,7 +1143,7 @@ theorem isBridge_iff_adj_and_forall_cycle_not_mem {v w : V} : G.IsBridge s(v, w)
rw [← not_iff_not]
push_neg
rw [← adj_and_reachable_delete_edges_iff_exists_cycle]
- simp only [h, true_and_iff]
+ simp only [h, true_and]
theorem isBridge_iff_mem_and_forall_cycle_not_mem {e : Sym2 V} :
G.IsBridge e ↔ e ∈ G.edgeSet ∧ ∀ ⦃u : V⦄ (p : G.Walk u u), p.IsCycle → e ∉ p.edges :=
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 bd6d68eeeb2dd..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 :=
- (div_le_of_nonneg_of_le_mul (eps_pow_five_pos hPε).le (by positivity) hPε).trans <| by
+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ε)
+ (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_of_one_le (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)
@@ -175,8 +174,8 @@ theorem initialBound_pos : 0 < initialBound ε l :=
theorem hundred_lt_pow_initialBound_mul {ε : ℝ} (hε : 0 < ε) (l : ℕ) :
100 < ↑4 ^ initialBound ε l * ε ^ 5 := by
- rw [← rpow_natCast 4, ← div_lt_iff (pow_pos hε 5), lt_rpow_iff_log_lt _ zero_lt_four, ←
- div_lt_iff, initialBound, Nat.cast_max, Nat.cast_max]
+ rw [← rpow_natCast 4, ← div_lt_iff₀ (pow_pos hε 5), lt_rpow_iff_log_lt _ zero_lt_four, ←
+ div_lt_iff₀, initialBound, Nat.cast_max, Nat.cast_max]
· push_cast
exact lt_max_of_lt_right (lt_max_of_lt_right <| Nat.lt_floor_add_one _)
· exact log_pos (by norm_num)
@@ -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 4ffe166e5b4b8..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
@@ -114,47 +113,47 @@ private theorem card_nonuniformWitness_sdiff_biUnion_star (hV : V ∈ P.parts) (
rw [sum_const]
refine mul_le_mul_right' ?_ _
have t := card_filter_atomise_le_two_pow (s := U) hX
- refine t.trans (pow_le_pow_right (by norm_num) <| tsub_le_tsub_right ?_ _)
+ refine t.trans (pow_right_mono₀ (by norm_num) <| tsub_le_tsub_right ?_ _)
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
- _ ≤ 1 := div_le_one_of_le (pow_mul_m_le_card_part hP hU) (cast_nonneg _)
- _ ≤ ↑2 ^ P.parts.card * ε ^ 2 / 10 := by
+ _ = ↑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 * ε ^ 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
@@ -240,14 +239,14 @@ private theorem m_add_one_div_m_le_one_add [Nonempty α]
div_eq_mul_one_div _ (49 : ℝ), mul_div_left_comm (2 : ℝ), ← mul_sub_left_distrib, div_pow,
div_le_iff₀ (show (0 : ℝ) < ↑100 ^ 2 by norm_num), mul_assoc, sq]
refine mul_le_mul_of_nonneg_left ?_ (by sz_positivity)
- exact (pow_le_one 5 (by sz_positivity) hε₁).trans (by norm_num)
+ 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,10 +265,10 @@ 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)
+ refine div_le_one_of_le₀ ?_ (by positivity)
refine (mul_le_mul_of_nonneg_right (one_sub_le_m_div_m_add_one_sq hPα hPε) ?_).trans ?_
· exact mod_cast _root_.zero_le _
rw [sq, mul_mul_mul_comm, mul_comm ((m : ℝ) / _), mul_comm ((m : ℝ) / _)]
@@ -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)
+ 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 64284f427847f..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,18 +33,18 @@ 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 _
theorem energy_le_one : P.energy G ≤ 1 :=
- div_le_of_nonneg_of_le_mul (sq_nonneg _) zero_le_one <|
+ 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 d0c4c37b647fa..a5b1a55dfb92a 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean
@@ -32,21 +32,21 @@ 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⟩
- simp only [le_zero_iff, card_eq_zero, mem_biUnion, exists_prop, mem_filter, id, and_assoc,
- sdiff_eq_empty_iff_subset, subset_iff]
+ simp only [le_zero_iff, card_eq_zero, mem_biUnion, exists_prop, mem_filter, id,
+ and_assoc, sdiff_eq_empty_iff_subset, subset_iff]
exact fun x hx a ha =>
⟨{a}, mem_map_of_mem _ (P.le hx ha), singleton_subset_iff.2 ha, mem_singleton_self _⟩
-- Prove the case `m > 0` by strong induction on `s`
@@ -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 9e7da73f754a5..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]
@@ -93,7 +93,7 @@ private theorem distinctPairs_increment :
P.parts.offDiag.attach.biUnion (distinctPairs hP G ε) ⊆ (increment hP G ε).parts.offDiag := by
rintro ⟨Ui, Vj⟩
simp only [distinctPairs, increment, mem_offDiag, bind_parts, mem_biUnion, Prod.exists,
- exists_and_left, exists_prop, mem_product, mem_attach, true_and_iff, Subtype.exists, and_imp,
+ exists_and_left, exists_prop, mem_product, mem_attach, true_and, Subtype.exists, and_imp,
mem_offDiag, forall_exists_index, exists₂_imp, Ne]
refine fun U V hUV hUi hVj => ⟨⟨_, hUV.1, hUi⟩, ⟨_, hUV.2.1, hVj⟩, ?_⟩
rintro rfl
@@ -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 5e120205aeeb8..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,17 +126,17 @@ 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_le_pow_right (by norm_num) hP₂) <| by positivity)
+ (mul_le_mul_of_nonneg_right (pow_right_mono₀ (by norm_num) hP₂) <| by positivity)
have hi : (i : ℝ) ≤ 4 / ε ^ 5 := by
have hi : ε ^ 5 / 4 * ↑i ≤ 1 := hP₄.trans (mod_cast P.energy_le_one G)
rw [div_mul_eq_mul_div, div_le_iff₀ (show (0 : ℝ) < 4 by norm_num)] at hi
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 005b689effd65..6d9c7efcbf156 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean
@@ -7,7 +7,7 @@ import Mathlib.Algebra.BigOperators.Ring
import Mathlib.Combinatorics.SimpleGraph.Density
import Mathlib.Data.Nat.Cast.Order.Field
import Mathlib.Order.Partition.Equipartition
-import Mathlib.SetTheory.Ordinal.Basic
+import Mathlib.SetTheory.Cardinal.Basic
/-!
# Graph uniformity and uniform partitions
@@ -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,25 +265,24 @@ 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ε
· gcongr with UV hUV
obtain ⟨U, V⟩ := UV
simp [mk_mem_sparsePairs, ← card_interedges_div_card] at hUV
- refine ((div_lt_iff ?_).1 hUV.2.2.2).le
+ refine ((div_lt_iff₀ ?_).1 hUV.2.2.2).le
exact mul_pos (Nat.cast_pos.2 (P.nonempty_of_mem_parts hUV.1).card_pos)
(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 68777353d2638..9d6763e5a5474 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean
@@ -133,6 +133,9 @@ theorem coe_adj_sub (G' : Subgraph G) (u v : G'.verts) (h : G'.coe.Adj u v) : G.
protected theorem Adj.coe {H : G.Subgraph} {u v : V} (h : H.Adj u v) :
H.coe.Adj ⟨u, H.edge_vert h⟩ ⟨v, H.edge_vert h.symm⟩ := h
+instance (G : SimpleGraph V) (H : Subgraph G) [DecidableRel H.Adj] : DecidableRel H.coe.Adj :=
+ fun a b ↦ ‹DecidableRel H.Adj› _ _
+
/-- A subgraph is called a *spanning subgraph* if it contains all the vertices of `G`. -/
def IsSpanning (G' : Subgraph G) : Prop :=
∀ v : V, v ∈ G'.verts
@@ -156,6 +159,8 @@ theorem Adj.of_spanningCoe {G' : Subgraph G} {u v : G'.verts} (h : G'.spanningCo
G.Adj u v :=
G'.adj_sub h
+lemma spanningCoe_le (G' : G.Subgraph) : G'.spanningCoe ≤ G := fun _ _ ↦ G'.3
+
theorem spanningCoe_inj : G₁.spanningCoe = G₂.spanningCoe ↔ G₁.Adj = G₂.Adj := by
simp [Subgraph.spanningCoe]
@@ -209,15 +214,27 @@ theorem edgeSet_subset (G' : Subgraph G) : G'.edgeSet ⊆ G.edgeSet :=
Sym2.ind (fun _ _ ↦ G'.adj_sub)
@[simp]
-theorem mem_edgeSet {G' : Subgraph G} {v w : V} : s(v, w) ∈ G'.edgeSet ↔ G'.Adj v w := Iff.rfl
+protected lemma mem_edgeSet {G' : Subgraph G} {v w : V} : s(v, w) ∈ G'.edgeSet ↔ G'.Adj v w := .rfl
+
+@[simp] lemma edgeSet_coe {G' : G.Subgraph} : G'.coe.edgeSet = Sym2.map (↑) ⁻¹' G'.edgeSet := by
+ ext e; induction' e using Sym2.ind with a b; simp
-theorem mem_verts_if_mem_edge {G' : Subgraph G} {e : Sym2 V} {v : V} (he : e ∈ G'.edgeSet)
+lemma image_coe_edgeSet_coe (G' : G.Subgraph) : Sym2.map (↑) '' G'.coe.edgeSet = G'.edgeSet := by
+ rw [edgeSet_coe, Set.image_preimage_eq_iff]
+ rintro e he
+ induction' e using Sym2.ind with a b
+ rw [Subgraph.mem_edgeSet] at he
+ exact ⟨s(⟨a, edge_vert _ he⟩, ⟨b, edge_vert _ he.symm⟩), Sym2.map_pair_eq ..⟩
+
+theorem mem_verts_of_mem_edge {G' : Subgraph G} {e : Sym2 V} {v : V} (he : e ∈ G'.edgeSet)
(hv : v ∈ e) : v ∈ G'.verts := by
induction e
rcases Sym2.mem_iff.mp hv with (rfl | rfl)
· exact G'.edge_vert he
· exact G'.edge_vert (G'.symm he)
+@[deprecated (since := "2024-10-01")] alias mem_verts_if_mem_edge := mem_verts_of_mem_edge
+
/-- The `incidenceSet` is the set of edges incident to a given vertex. -/
def incidenceSet (G' : Subgraph G) (v : V) : Set (Sym2 V) := {e ∈ G'.edgeSet | v ∈ e}
@@ -377,6 +394,18 @@ theorem verts_iSup {f : ι → G.Subgraph} : (⨆ i, f i).verts = ⋃ i, (f i).v
@[simp]
theorem verts_iInf {f : ι → G.Subgraph} : (⨅ i, f i).verts = ⋂ i, (f i).verts := by simp [iInf]
+@[simp] lemma coe_bot : (⊥ : G.Subgraph).coe = ⊥ := rfl
+
+@[simp] lemma IsInduced.top : (⊤ : G.Subgraph).IsInduced := fun _ _ ↦ id
+
+/-- The graph isomorphism between the top element of `G.subgraph` and `G`. -/
+def topIso : (⊤ : G.Subgraph).coe ≃g G where
+ toFun := (↑)
+ invFun a := ⟨a, Set.mem_univ _⟩
+ left_inv _ := Subtype.eta ..
+ right_inv _ := rfl
+ map_rel_iff' := .rfl
+
theorem verts_spanningCoe_injective :
(fun G' : Subgraph G => (G'.verts, G'.spanningCoe)).Injective := by
intro G₁ G₂ h
@@ -405,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]) }
@@ -551,9 +580,12 @@ theorem _root_.Disjoint.edgeSet {H₁ H₂ : Subgraph G} (h : Disjoint H₁ H₂
Disjoint H₁.edgeSet H₂.edgeSet :=
disjoint_iff_inf_le.mpr <| by simpa using edgeSet_mono h.le_bot
+section map
+variable {G' : SimpleGraph W} {f : G →g G'}
+
/-- Graph homomorphisms induce a covariant function on subgraphs. -/
@[simps]
-protected def map {G' : SimpleGraph W} (f : G →g G') (H : G.Subgraph) : G'.Subgraph where
+protected def map (f : G →g G') (H : G.Subgraph) : G'.Subgraph where
verts := f '' H.verts
Adj := Relation.Map H.Adj f f
adj_sub := by
@@ -566,29 +598,26 @@ protected def map {G' : SimpleGraph W} (f : G →g G') (H : G.Subgraph) : G'.Sub
rintro _ _ ⟨u, v, h, rfl, rfl⟩
exact ⟨v, u, H.symm h, rfl, rfl⟩
-theorem map_monotone {G' : SimpleGraph W} (f : G →g G') : Monotone (Subgraph.map f) := by
- intro H H' h
+@[simp] lemma map_id (H : G.Subgraph) : H.map Hom.id = H := by ext <;> simp
+
+lemma map_comp {U : Type*} {G'' : SimpleGraph U} (H : G.Subgraph) (f : G →g G') (g : G' →g G'') :
+ H.map (g.comp f) = (H.map f).map g := by ext <;> simp [Subgraph.map]
+
+@[gcongr] lemma map_mono {H₁ H₂ : G.Subgraph} (hH : H₁ ≤ H₂) : H₁.map f ≤ H₂.map f := by
constructor
· intro
simp only [map_verts, Set.mem_image, forall_exists_index, and_imp]
rintro v hv rfl
- exact ⟨_, h.1 hv, rfl⟩
+ exact ⟨_, hH.1 hv, rfl⟩
· rintro _ _ ⟨u, v, ha, rfl, rfl⟩
- exact ⟨_, _, h.2 ha, rfl, rfl⟩
-
-theorem map_sup {G : SimpleGraph V} {G' : SimpleGraph W} (f : G →g G') {H H' : G.Subgraph} :
- (H ⊔ H').map f = H.map f ⊔ H'.map f := by
- ext1
- · simp only [Set.image_union, map_verts, verts_sup]
- · ext
- simp only [Relation.Map, map_adj, sup_adj]
- constructor
- · rintro ⟨a, b, h | h, rfl, rfl⟩
- · exact Or.inl ⟨_, _, h, rfl, rfl⟩
- · exact Or.inr ⟨_, _, h, rfl, rfl⟩
- · rintro (⟨a, b, h, rfl, rfl⟩ | ⟨a, b, h, rfl, rfl⟩)
- · exact ⟨_, _, Or.inl h, rfl, rfl⟩
- · exact ⟨_, _, Or.inr h, rfl, rfl⟩
+ exact ⟨_, _, hH.2 ha, rfl, rfl⟩
+
+lemma map_monotone : Monotone (Subgraph.map f) := fun _ _ ↦ map_mono
+
+theorem map_sup (f : G →g G') (H₁ H₂ : G.Subgraph) : (H₁ ⊔ H₂).map f = H₁.map f ⊔ H₂.map f := by
+ ext <;> simp [Set.image_union, map_adj, sup_adj, Relation.Map, or_and_right, exists_or]
+
+end map
/-- Graph homomorphisms induce a contravariant function on subgraphs. -/
@[simps]
@@ -606,7 +635,7 @@ theorem comap_monotone {G' : SimpleGraph W} (f : G →g G') : Monotone (Subgraph
simp only [comap_verts, Set.mem_preimage]
apply h.1
· intro v w
- simp (config := { contextual := true }) only [comap_adj, and_imp, true_and_iff]
+ simp (config := { contextual := true }) only [comap_adj, and_imp, true_and]
intro
apply h.2
@@ -615,7 +644,7 @@ theorem map_le_iff_le_comap {G' : SimpleGraph W} (f : G →g G') (H : G.Subgraph
refine ⟨fun h ↦ ⟨fun v hv ↦ ?_, fun v w hvw ↦ ?_⟩, fun h ↦ ⟨fun v ↦ ?_, fun v w ↦ ?_⟩⟩
· simp only [comap_verts, Set.mem_preimage]
exact h.1 ⟨v, hv, rfl⟩
- · simp only [H.adj_sub hvw, comap_adj, true_and_iff]
+ · simp only [H.adj_sub hvw, comap_adj, true_and]
exact h.2 ⟨v, w, hvw, rfl, rfl⟩
· simp only [map_verts, Set.mem_image, forall_exists_index, and_imp]
rintro w hw rfl
@@ -767,7 +796,7 @@ theorem eq_singletonSubgraph_iff_verts_eq (H : G.Subgraph) {v : V} :
refine ⟨fun h ↦ by rw [h, singletonSubgraph_verts], fun h ↦ ?_⟩
ext
· rw [h, singletonSubgraph_verts]
- · simp only [Prop.bot_eq_false, singletonSubgraph_adj, Pi.bot_apply, iff_false_iff]
+ · simp only [Prop.bot_eq_false, singletonSubgraph_adj, Pi.bot_apply, iff_false]
intro ha
have ha1 := ha.fst_mem
have ha2 := ha.snd_mem
@@ -784,7 +813,7 @@ theorem edgeSet_subgraphOfAdj {v w : V} (hvw : G.Adj v w) :
(G.subgraphOfAdj hvw).edgeSet = {s(v, w)} := by
ext e
refine e.ind ?_
- simp only [eq_comm, Set.mem_singleton_iff, Subgraph.mem_edgeSet, subgraphOfAdj_adj, iff_self_iff,
+ simp only [eq_comm, Set.mem_singleton_iff, Subgraph.mem_edgeSet, subgraphOfAdj_adj,
forall₂_true_iff]
lemma subgraphOfAdj_le_of_adj {v w : V} (H : G.Subgraph) (h : H.Adj v w) :
@@ -992,7 +1021,7 @@ theorem deleteEdges_le : G'.deleteEdges s ≤ G' := by
theorem deleteEdges_le_of_le {s s' : Set (Sym2 V)} (h : s ⊆ s') :
G'.deleteEdges s' ≤ G'.deleteEdges s := by
constructor <;> simp (config := { contextual := true }) only [deleteEdges_verts, deleteEdges_adj,
- true_and_iff, and_imp, subset_rfl]
+ true_and, and_imp, subset_rfl]
exact fun _ _ _ hs' hs ↦ hs' (h hs)
@[simp]
@@ -1044,7 +1073,7 @@ variable {G' G'' : G.Subgraph} {s s' : Set V}
theorem induce_mono (hg : G' ≤ G'') (hs : s ⊆ s') : G'.induce s ≤ G''.induce s' := by
constructor
· simp [hs]
- · simp (config := { contextual := true }) only [induce_adj, true_and_iff, and_imp]
+ · simp (config := { contextual := true }) only [induce_adj, and_imp]
intro v w hv hw ha
exact ⟨hs hv, hs hw, hg.2 ha⟩
@@ -1065,7 +1094,7 @@ theorem induce_self_verts : G'.induce G'.verts = G' := by
ext
· simp
· constructor <;>
- simp (config := { contextual := true }) only [induce_adj, imp_true_iff, and_true_iff]
+ simp (config := { contextual := true }) only [induce_adj, imp_true_iff, and_true]
exact fun ha ↦ ⟨G'.edge_vert ha, G'.edge_vert ha.symm⟩
lemma le_induce_top_verts : G' ≤ (⊤ : G.Subgraph).induce G'.verts :=
diff --git a/Mathlib/Combinatorics/SimpleGraph/Trails.lean b/Mathlib/Combinatorics/SimpleGraph/Trails.lean
index bf530ee6beb46..174a67d7b2b8d 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Trails.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Trails.lean
@@ -58,18 +58,18 @@ theorem IsTrail.even_countP_edges_iff {u v : V} {p : G.Walk u v} (ht : p.IsTrail
· rw [decide_eq_true_eq] at h
obtain (rfl | rfl) := h
· rw [Nat.even_add_one, ih]
- simp only [huv.ne, imp_false, Ne, not_false_iff, true_and_iff, not_forall,
- Classical.not_not, exists_prop, eq_self_iff_true, not_true, false_and_iff,
+ simp only [huv.ne, imp_false, Ne, not_false_iff, true_and, not_forall,
+ Classical.not_not, exists_prop, eq_self_iff_true, not_true, false_and,
and_iff_right_iff_imp]
rintro rfl rfl
exact G.loopless _ huv
· rw [Nat.even_add_one, ih, ← not_iff_not]
- simp only [huv.ne.symm, Ne, eq_self_iff_true, not_true, false_and_iff, not_forall,
- not_false_iff, exists_prop, and_true_iff, Classical.not_not, true_and_iff, iff_and_self]
+ simp only [huv.ne.symm, Ne, eq_self_iff_true, not_true, false_and, not_forall,
+ not_false_iff, exists_prop, and_true, Classical.not_not, true_and, iff_and_self]
rintro rfl
exact huv.ne
· rw [decide_eq_true_eq, not_or] at h
- simp only [h.1, h.2, not_false_iff, true_and_iff, add_zero, Ne] at ih ⊢
+ simp only [h.1, h.2, not_false_iff, true_and, add_zero, Ne] at ih ⊢
rw [ih]
constructor <;>
· rintro h' h'' rfl
diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean
index 62b63093df2d8..a5d36c33b508b 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean
@@ -133,18 +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 := And.decidable
+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 ?_
@@ -154,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]
@@ -164,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,
@@ -185,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
@@ -197,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
@@ -205,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) :
@@ -233,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
@@ -242,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
@@ -255,18 +256,18 @@ lemma FarFromTriangleFree.lt_half (hG : G.FarFromTriangleFree ε) : ε < 2⁻¹
by_contra! hε
refine lt_irrefl (ε * card α ^ 2) ?_
have hε₀ : 0 < ε := hε.trans_lt' (by norm_num)
- rw [inv_pos_le_iff_one_le_mul (zero_lt_two' 𝕜)] at hε
+ 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]
@@ -275,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 41df6e05b9aba..bff996c3fa38c 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean
@@ -29,27 +29,27 @@ 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) :
G.edgeDensity (badVertices G ε s t) t ≤ G.edgeDensity s t - ε := by
rw [edgeDensity_def]
push_cast
- refine div_le_of_nonneg_of_le_mul (by positivity) (sub_nonneg_of_le <| by linarith) ?_
+ refine div_le_of_le_mul₀ (by positivity) (sub_nonneg_of_le <| by linarith) ?_
rw [mul_comm]
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,24 +72,24 @@ 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
have hε := utu.pos.le
- refine le_trans ?_ (mul_le_of_nonneg_of_le_div (Nat.cast_nonneg _) (by positivity) this)
+ refine le_trans ?_ (mul_le_of_le_div₀ (Nat.cast_nonneg _) (by positivity) this)
refine Eq.trans_le ?_
(mul_le_mul_of_nonneg_left (mul_le_mul hY hZ (by positivity) (by positivity)) hε)
ring
@@ -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/SimpleGraph/Walk.lean b/Mathlib/Combinatorics/SimpleGraph/Walk.lean
index c86f6abe53427..e2c574948f9c0 100644
--- a/Mathlib/Combinatorics/SimpleGraph/Walk.lean
+++ b/Mathlib/Combinatorics/SimpleGraph/Walk.lean
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kyle Miller
-/
import Mathlib.Combinatorics.SimpleGraph.Maps
-import Mathlib.Data.List.Lemmas
/-!
@@ -189,10 +188,8 @@ lemma getVert_cons_succ {u v w n} (p : G.Walk v w) (h : G.Adj u v) :
lemma getVert_cons {u v w n} (p : G.Walk v w) (h : G.Adj u v) (hn : n ≠ 0) :
(p.cons h).getVert n = p.getVert (n - 1) := by
- obtain ⟨i, hi⟩ : ∃ (i : ℕ), i.succ = n := by
- use n - 1; exact Nat.succ_pred_eq_of_ne_zero hn
- rw [← hi]
- simp only [Nat.succ_eq_add_one, getVert_cons_succ, Nat.add_sub_cancel]
+ obtain ⟨n, rfl⟩ := Nat.exists_eq_add_one_of_ne_zero hn
+ rw [getVert_cons_succ, Nat.add_sub_cancel]
@[simp]
theorem cons_append {u v w x : V} (h : G.Adj u v) (p : G.Walk v w) (q : G.Walk w x) :
@@ -202,23 +199,21 @@ theorem cons_append {u v w x : V} (h : G.Adj u v) (p : G.Walk v w) (q : G.Walk w
theorem cons_nil_append {u v w : V} (h : G.Adj u v) (p : G.Walk v w) :
(cons h nil).append p = cons h p := rfl
+@[simp]
+theorem nil_append {u v : V} (p : G.Walk u v) : nil.append p = p :=
+ rfl
+
@[simp]
theorem append_nil {u v : V} (p : G.Walk u v) : p.append nil = p := by
induction p with
- | nil => rfl
+ | nil => rw [nil_append]
| cons _ _ ih => rw [cons_append, ih]
-@[simp]
-theorem nil_append {u v : V} (p : G.Walk u v) : nil.append p = p :=
- rfl
-
theorem append_assoc {u v w x : V} (p : G.Walk u v) (q : G.Walk v w) (r : G.Walk w x) :
p.append (q.append r) = (p.append q).append r := by
induction p with
- | nil => rfl
- | cons h p' ih =>
- dsimp only [append]
- rw [ih]
+ | nil => rw [nil_append, nil_append]
+ | cons h p' ih => rw [cons_append, cons_append, cons_append, ih]
@[simp]
theorem append_copy_copy {u v w u' v' w'} (p : G.Walk u v) (q : G.Walk v w)
@@ -513,7 +508,7 @@ theorem getLast_support {G : SimpleGraph V} {a b : V} (p : G.Walk a b) :
theorem tail_support_append {u v w : V} (p : G.Walk u v) (p' : G.Walk v w) :
(p.append p').support.tail = p.support.tail ++ p'.support.tail := by
- rw [support_append, List.tail_append_of_ne_nil _ _ (support_ne_nil _)]
+ rw [support_append, List.tail_append_of_ne_nil (support_ne_nil _)]
theorem support_eq_cons {u v : V} (p : G.Walk u v) : p.support = u :: p.support.tail := by
cases p <;> simp
@@ -560,7 +555,7 @@ theorem subset_support_append_left {V : Type u} {G : SimpleGraph V} {u v w : V}
theorem subset_support_append_right {V : Type u} {G : SimpleGraph V} {u v w : V}
(p : G.Walk u v) (q : G.Walk v w) : q.support ⊆ (p.append q).support := by
intro h
- simp (config := { contextual := true }) only [mem_support_append_iff, or_true_iff, imp_true_iff]
+ simp (config := { contextual := true }) only [mem_support_append_iff, or_true, imp_true_iff]
theorem coe_support {u v : V} (p : G.Walk u v) :
(p.support : Multiset V) = {u} + p.support.tail := by cases p <;> rfl
@@ -664,9 +659,8 @@ theorem head_darts_fst {G : SimpleGraph V} {a b : V} (p : G.Walk a b) (hp : p.da
theorem getLast_darts_snd {G : SimpleGraph V} {a b : V} (p : G.Walk a b) (hp : p.darts ≠ []) :
(p.darts.getLast hp).snd = b := by
rw [← List.getLast_map (f := fun x : G.Dart ↦ x.snd)]
- simp_rw [p.map_snd_darts, List.getLast_tail]
- exact p.getLast_support
- simpa
+ · simp_rw [p.map_snd_darts, List.getLast_tail, p.getLast_support]
+ · simpa
@[simp]
theorem edges_nil {u : V} : (nil : G.Walk u u).edges = [] := rfl
@@ -1201,7 +1195,7 @@ theorem map_injective_of_injective {f : G →g G'} (hinj : Function.Injective f)
| cons _ _ =>
simp only [map_cons, cons.injEq] at h
cases hinj h.1
- simp only [cons.injEq, heq_iff_eq, true_and_iff]
+ simp only [cons.injEq, heq_iff_eq, true_and]
apply ih
simpa using h.2
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 79b3e2892c891..7bb1431dc4004 100644
--- a/Mathlib/Combinatorics/Young/YoungDiagram.lean
+++ b/Mathlib/Combinatorics/Young/YoungDiagram.lean
@@ -67,7 +67,7 @@ namespace YoungDiagram
instance : SetLike YoungDiagram (ℕ × ℕ) where
-- Porting note (#11215): TODO: figure out how to do this correctly
- coe := fun y => y.cells
+ coe y := y.cells
coe_injective' μ ν h := by rwa [YoungDiagram.ext_iff, ← Finset.coe_inj]
@[simp]
@@ -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 ?_ ?_
@@ -436,7 +435,7 @@ theorem rowLens_length_ofRowLens {w : List ℕ} {hw : w.Sorted (· ≥ ·)} (hpo
(ofRowLens w hw).rowLens.length = w.length := by
simp only [length_rowLens, colLen, Nat.find_eq_iff, mem_cells, mem_ofRowLens,
lt_self_iff_false, IsEmpty.exists_iff, Classical.not_not]
- exact ⟨not_false, fun n hn => ⟨hn, hpos _ (List.getElem_mem _ _ hn)⟩⟩
+ exact ⟨not_false, fun n hn => ⟨hn, hpos _ (List.getElem_mem hn)⟩⟩
/-- The length of the `i`th row in `ofRowLens w hw` is the `i`th entry of `w` -/
theorem rowLen_ofRowLens {w : List ℕ} {hw : w.Sorted (· ≥ ·)} (i : Fin w.length) :
diff --git a/Mathlib/Computability/Ackermann.lean b/Mathlib/Computability/Ackermann.lean
index 1b60a716c05f3..ace0d47e3ed95 100644
--- a/Mathlib/Computability/Ackermann.lean
+++ b/Mathlib/Computability/Ackermann.lean
@@ -3,7 +3,6 @@ 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.Algebra.Order.Ring.Basic
import Mathlib.Computability.Primrec
import Mathlib.Tactic.Ring
import Mathlib.Tactic.Linarith
@@ -75,26 +74,26 @@ theorem ack_succ_succ (m n : ℕ) : ack (m + 1) (n + 1) = ack m (ack (m + 1) n)
@[simp]
theorem ack_one (n : ℕ) : ack 1 n = n + 2 := by
induction' n with n IH
- · rfl
+ · simp
· simp [IH]
@[simp]
theorem ack_two (n : ℕ) : ack 2 n = 2 * n + 3 := by
induction' n with n IH
- · rfl
+ · simp
· simpa [mul_succ]
-- Porting note: re-written to get rid of ack_three_aux
@[simp]
theorem ack_three (n : ℕ) : ack 3 n = 2 ^ (n + 3) - 3 := by
induction' n with n IH
- · rfl
+ · simp
· rw [ack_succ_succ, IH, ack_two, Nat.succ_add, Nat.pow_succ 2 (n + 3), mul_comm _ 2,
Nat.mul_sub_left_distrib, ← Nat.sub_add_comm, two_mul 3, Nat.add_sub_add_right]
have H : 2 * 3 ≤ 2 * 2 ^ 3 := by norm_num
apply H.trans
rw [_root_.mul_le_mul_left two_pos]
- exact pow_le_pow_right one_le_two (Nat.le_add_left 3 n)
+ exact pow_right_mono₀ one_le_two (Nat.le_add_left 3 n)
theorem ack_pos : ∀ m n, 0 < ack m n
| 0, n => by simp
@@ -176,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 65daa0a486dab..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
@@ -201,7 +201,7 @@ lemma eventually_atTop_nonneg_or_nonpos (hf : GrowsPolynomially f) :
have le_2n : max n₀ 2 ≤ (2 : ℝ)^n * max n₀ 2 := by
nth_rewrite 1 [← one_mul (max n₀ 2)]
gcongr
- exact one_le_pow_of_one_le (by norm_num : (1 : ℝ) ≤ 2) _
+ exact one_le_pow₀ (by norm_num : (1 : ℝ) ≤ 2)
have n₀_le_z : n₀ ≤ z := by
calc n₀ ≤ max n₀ 2 := by simp
_ ≤ (2 : ℝ)^n * max n₀ 2 := le_2n
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 6d113f0675c90..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
@@ -173,6 +172,15 @@ protected theorem not {p : α → Prop} (hp : ComputablePred p) : ComputablePred
simp only [Bool.not_eq_true]
cases f n <;> rfl⟩
+/-- The computable functions are closed under if-then-else definitions
+with computable predicates. -/
+theorem ite {f₁ f₂ : ℕ → ℕ} (hf₁ : Computable f₁) (hf₂ : Computable f₂)
+ {c : ℕ → Prop} [DecidablePred c] (hc : ComputablePred c) :
+ Computable fun k ↦ if c k then f₁ k else f₂ k := by
+ simp_rw [← Bool.cond_decide]
+ obtain ⟨inst, hc⟩ := hc
+ convert hc.cond hf₁ hf₂
+
theorem to_re {p : α → Prop} (hp : ComputablePred p) : RePred p := by
obtain ⟨f, hf, rfl⟩ := computable_iff.1 hp
unfold RePred
@@ -214,7 +222,7 @@ theorem rice₂ (C : Set Code) (H : ∀ cf cg, eval cf = eval cg → (cf ∈ C
(Partrec.nat_iff.1 <| eval_part.comp (const cg) Computable.id) ((hC _).1 fC),
fun h => by {
obtain rfl | rfl := h <;> simpa [ComputablePred, Set.mem_empty_iff_false] using
- ⟨⟨inferInstance⟩, Computable.const _⟩ }⟩
+ Computable.const _}⟩
/-- The Halting problem is recursively enumerable -/
theorem halting_problem_re (n) : RePred fun c => (eval c n).Dom :=
@@ -272,8 +280,6 @@ namespace Nat.Partrec'
open Mathlib.Vector Partrec Computable
-open Nat (Partrec')
-
open Nat.Partrec'
theorem to_part {n f} (pf : @Partrec' n f) : _root_.Partrec f := by
diff --git a/Mathlib/Computability/Language.lean b/Mathlib/Computability/Language.lean
index cc112e2e09266..4e40a3919b388 100644
--- a/Mathlib/Computability/Language.lean
+++ b/Mathlib/Computability/Language.lean
@@ -159,7 +159,7 @@ lemma mem_kstar_iff_exists_nonempty {x : List α} :
x ∈ l∗ ↔ ∃ S : List (List α), x = S.join ∧ ∀ y ∈ S, y ∈ l ∧ y ≠ [] := by
constructor
· rintro ⟨S, rfl, h⟩
- refine ⟨S.filter fun l ↦ !List.isEmpty l, by simp, fun y hy ↦ ?_⟩
+ refine ⟨S.filter fun l ↦ !List.isEmpty l, by simp [List.join_filter_not_isEmpty], fun y hy ↦ ?_⟩
-- Porting note: The previous code was:
-- rw [mem_filter, empty_iff_eq_nil] at hy
rw [mem_filter, Bool.not_eq_true', ← Bool.bool_iff_false, List.isEmpty_iff] at hy
@@ -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 83c17cd86fb12..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
@@ -170,7 +169,7 @@ private theorem encode_ofNatCode : ∀ n, encodeCode (ofNatCode n) = n
instance instDenumerable : Denumerable Code :=
mk'
⟨encodeCode, ofNatCode, fun c => by
- induction c <;> try {rfl} <;> simp [encodeCode, ofNatCode, Nat.div2_val, *],
+ induction c <;> simp [encodeCode, ofNatCode, Nat.div2_val, *],
encode_ofNatCode⟩
theorem encodeCode_eq : encode = encodeCode :=
@@ -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]
@@ -900,7 +899,7 @@ private theorem hG : Primrec G := by
Primrec.fst
private theorem evaln_map (k c n) :
- ((((List.range k)[n]?).map (evaln k c)).bind fun b => b) = evaln k c n := by
+ ((List.range k)[n]?.bind fun a ↦ evaln k c a) = evaln k c n := by
by_cases kn : n < k
· simp [List.getElem?_range kn]
· rw [List.getElem?_len_le]
@@ -937,7 +936,7 @@ theorem evaln_prim : Primrec fun a : (ℕ × Code) × ℕ => evaln a.1.1 a.1.2 a
(List.range n.unpair.1).map (evaln n.unpair.1 (ofNat Code n.unpair.2))) (k', c') n =
evaln k' c' n := by
intro k₁ c₁ n₁ hl
- simp [lup, List.getElem?_range hl, evaln_map, Bind.bind]
+ simp [lup, List.getElem?_range hl, evaln_map, Bind.bind, Option.bind_map]
cases' c with cf cg cf cg cf cg cf <;>
simp [evaln, nk, Bind.bind, Functor.map, Seq.seq, pure]
· cases' encode_lt_pair cf cg with lf lg
@@ -969,7 +968,7 @@ theorem evaln_prim : Primrec fun a : (ℕ × Code) × ℕ => evaln a.1.1 a.1.2 a
(Primrec.option_bind
(Primrec.list_get?.comp (this.comp (_root_.Primrec.const ())
(Primrec.encode_iff.2 Primrec.fst)) Primrec.snd) Primrec.snd.to₂).of_eq
- fun ⟨⟨k, c⟩, n⟩ => by simp [evaln_map]
+ fun ⟨⟨k, c⟩, n⟩ => by simp [evaln_map, Option.bind_map]
end
@@ -1015,4 +1014,15 @@ theorem fixed_point₂ {f : Code → ℕ →. ℕ} (hf : Partrec₂ f) : ∃ c :
end
+/-- There are only countably many partial recursive partial functions `ℕ →. ℕ`. -/
+instance : Countable {f : ℕ →. ℕ // _root_.Partrec f} := by
+ apply Function.Surjective.countable (f := fun c => ⟨eval c, eval_part.comp (.const c) .id⟩)
+ intro ⟨f, hf⟩; simpa using exists_code.1 hf
+
+/-- There are only countably many computable functions `ℕ → ℕ`. -/
+instance : Countable {f : ℕ → ℕ // Computable f} :=
+ @Function.Injective.countable {f : ℕ → ℕ // Computable f} {f : ℕ →. ℕ // _root_.Partrec f} _
+ (fun f => ⟨f.val, f.2⟩)
+ (fun _ _ h => Subtype.val_inj.1 (PFun.lift_injective (by simpa using h)))
+
end Nat.Partrec.Code
diff --git a/Mathlib/Computability/Primrec.lean b/Mathlib/Computability/Primrec.lean
index 967626fac3c92..3defa207c49ee 100644
--- a/Mathlib/Computability/Primrec.lean
+++ b/Mathlib/Computability/Primrec.lean
@@ -275,7 +275,7 @@ end Primcodable
namespace Primrec
-variable {α : Type*} {σ : Type*} [Primcodable α] [Primcodable σ]
+variable {α : Type*} [Primcodable α]
open Nat.Primrec
@@ -457,8 +457,8 @@ end Primrec₂
namespace Primrec
-variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} {σ : Type*}
-variable [Primcodable α] [Primcodable β] [Primcodable γ] [Primcodable δ] [Primcodable σ]
+variable {α : Type*} {β : Type*} {σ : Type*}
+variable [Primcodable α] [Primcodable β] [Primcodable σ]
theorem to₂ {f : α × β → σ} (hf : Primrec f) : Primrec₂ fun a b => f (a, b) :=
hf.of_eq fun _ => rfl
@@ -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
@@ -1088,8 +1080,7 @@ end Primrec
namespace Primcodable
-variable {α : Type*} {β : Type*}
-variable [Primcodable α] [Primcodable β]
+variable {α : Type*} [Primcodable α]
open Primrec
@@ -1098,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⟩
@@ -1139,8 +1130,8 @@ end Primcodable
namespace Primrec
-variable {α : Type*} {β : Type*} {γ : Type*} {σ : Type*}
-variable [Primcodable α] [Primcodable β] [Primcodable γ] [Primcodable σ]
+variable {α : Type*} {β : Type*} {σ : Type*}
+variable [Primcodable α] [Primcodable β] [Primcodable σ]
theorem subtype_val {p : α → Prop} [DecidablePred p] {hp : PrimrecPred p} :
haveI := Primcodable.subtype hp
@@ -1215,7 +1206,7 @@ theorem vector_get {n} : Primrec₂ (@Vector.get α n) :=
theorem list_ofFn :
∀ {n} {f : Fin n → α → σ}, (∀ i, Primrec (f i)) → Primrec fun a => List.ofFn fun i => f i a
- | 0, _, _ => const []
+ | 0, _, _ => by simp only [List.ofFn_zero]; exact const []
| n + 1, f, hf => by
simpa [List.ofFn_succ] using list_cons.comp (hf 0) (list_ofFn fun i => hf i.succ)
@@ -1356,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 32ee465296600..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 :=
@@ -370,7 +363,7 @@ private theorem le_antisymm {d₁ d₂ : ManyOneDegree} : d₁ ≤ d₂ → d₂
induction d₁ using ManyOneDegree.ind_on
induction d₂ using ManyOneDegree.ind_on
intro hp hq
- simp_all only [ManyOneEquiv, of_le_of, of_eq_of, true_and_iff]
+ simp_all only [ManyOneEquiv, of_le_of, of_eq_of, true_and]
private theorem le_trans {d₁ d₂ d₃ : ManyOneDegree} : d₁ ≤ d₂ → d₂ ≤ d₃ → d₁ ≤ d₃ := by
induction d₁ using ManyOneDegree.ind_on
diff --git a/Mathlib/Computability/RegularExpressions.lean b/Mathlib/Computability/RegularExpressions.lean
index 04ff068cce5f2..7835066c73ec1 100644
--- a/Mathlib/Computability/RegularExpressions.lean
+++ b/Mathlib/Computability/RegularExpressions.lean
@@ -306,7 +306,7 @@ theorem star_rmatch_iff (P : RegularExpression α) :
· exact ⟨[], [], by tauto⟩
· cases' t' with b t
· simp only [forall_eq_or_imp, List.mem_cons] at helem
- simp only [eq_self_iff_true, not_true, Ne, false_and_iff] at helem
+ simp only [eq_self_iff_true, not_true, Ne, false_and] at helem
simp only [List.join, List.cons_append, List.cons_eq_cons] at hsum
refine ⟨t, U.join, hsum.2, ?_, ?_⟩
· specialize helem (b :: t) (by simp)
@@ -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 59fb6a5cf5aed..440884be0810c 100644
--- a/Mathlib/Computability/TMToPartrec.lean
+++ b/Mathlib/Computability/TMToPartrec.lean
@@ -340,8 +340,8 @@ theorem exists_code {n} {f : Vector ℕ n →. ℕ} (hf : Nat.Partrec' f) :
have := PFun.mem_fix_iff.1 h2
simp only [hf, Part.bind_some] at this
split_ifs at this with h
- · simp only [List.headI_nil, List.headI_cons, exists_false, or_false_iff, Part.mem_some_iff,
- List.tail_cons, false_and_iff, Sum.inl.injEq, reduceCtorEq] at this
+ · simp only [List.headI_nil, List.headI_cons, exists_false, or_false, Part.mem_some_iff,
+ List.tail_cons, false_and, Sum.inl.injEq, reduceCtorEq] at this
subst this
exact ⟨_, ⟨h, @(hm)⟩, rfl⟩
· refine IH (n.succ::v.val) (by simp_all) _ rfl fun m h' => ?_
@@ -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'
@@ -1604,10 +1608,10 @@ def trStmts₁ : Λ' → Finset Λ'
theorem trStmts₁_trans {q q'} : q' ∈ trStmts₁ q → trStmts₁ q' ⊆ trStmts₁ q := by
induction q with
| move _ _ _ q q_ih => _ | clear _ _ q q_ih => _ | copy q q_ih => _ | push _ _ q q_ih => _
- | read q q_ih => _ | succ q q_ih => _ | pred q₁ q₂ q₁_ih q₂_ih => _ | ret => _
+ | read q q_ih => _ | succ q q_ih => _ | pred q₁ q₂ q₁_ih q₂_ih => _ | ret => _ <;>
all_goals
simp (config := { contextual := true }) only [trStmts₁, Finset.mem_insert, Finset.mem_union,
- or_imp, Finset.mem_singleton, Finset.Subset.refl, imp_true_iff, true_and_iff]
+ or_imp, Finset.mem_singleton, Finset.Subset.refl, imp_true_iff, true_and]
repeat exact fun h => Finset.Subset.trans (q_ih h) (Finset.subset_insert _ _)
· simp
intro s h x h'
@@ -1801,8 +1805,8 @@ theorem trStmts₁_supports {S q} (H₁ : (q : Λ').Supports S) (HS₁ : trStmts
have W := fun {q} => trStmts₁_self q
induction q with
| move _ _ _ q q_ih => _ | clear _ _ q q_ih => _ | copy q q_ih => _ | push _ _ q q_ih => _
- | read q q_ih => _ | succ q q_ih => _ | pred q₁ q₂ q₁_ih q₂_ih => _ | ret => _
- all_goals simp [trStmts₁, -Finset.singleton_subset_iff] at HS₁ ⊢
+ | read q q_ih => _ | succ q q_ih => _ | pred q₁ q₂ q₁_ih q₂_ih => _ | ret => _ <;>
+ simp [trStmts₁, -Finset.singleton_subset_iff] at HS₁ ⊢
any_goals
cases' Finset.insert_subset_iff.1 HS₁ with h₁ h₂
first | have h₃ := h₂ W | try simp [Finset.subset_iff] at h₂
diff --git a/Mathlib/Computability/TuringMachine.lean b/Mathlib/Computability/TuringMachine.lean
index 8ebbf88168bcd..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 : σ₁ → σ₂} :
@@ -1383,7 +1373,7 @@ theorem tr_supports {S : Finset Λ} (ss : TM1.Supports M S) :
cases' q' with q' v'
simp only [trStmts, Finset.mem_coe] at h₂ ⊢
rw [Finset.mem_product] at h₂ ⊢
- simp only [Finset.mem_univ, and_true_iff] at h₂ ⊢
+ simp only [Finset.mem_univ, and_true] at h₂ ⊢
cases q'; · exact Multiset.mem_cons_self _ _
simp only [tr, Option.mem_def] at h₁
have := TM1.stmts_supportsStmt ss h₂
@@ -1734,7 +1724,7 @@ theorem tr_supports [Inhabited Λ] {S : Finset Λ} (ss : Supports M S) :
cases d <;> simp only [trNormal, iterate, supportsStmt_move, IH]
| write f q IH =>
unfold writes at hw ⊢
- simp only [Finset.mem_image, Finset.mem_union, Finset.mem_univ, exists_prop, true_and_iff]
+ simp only [Finset.mem_image, Finset.mem_union, Finset.mem_univ, exists_prop, true_and]
at hw ⊢
replace IH := IH hs fun q hq ↦ hw q (Or.inr hq)
refine ⟨supportsStmt_read _ fun a _ s ↦ hw _ (Or.inl ⟨_, rfl⟩), fun q' hq ↦ ?_⟩
@@ -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
new file mode 100644
index 0000000000000..40b0e6e7d03a9
--- /dev/null
+++ b/Mathlib/Condensed/Discrete/LocallyConstant.lean
@@ -0,0 +1,427 @@
+/-
+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.Basic
+import Mathlib.Condensed.TopComparison
+import Mathlib.Topology.Category.CompHausLike.SigmaComparison
+import Mathlib.Topology.FiberPartition
+/-!
+
+# The sheaf of locally constant maps on `CompHausLike P`
+
+This file proves that under suitable conditions, the functor from the category of sets to the
+category of sheaves for the coherent topology on `CompHausLike P`, given by mapping a set to the
+sheaf of locally constant maps to it, is left adjoint to the "underlying set" functor (evaluation
+at the point).
+
+We apply this to prove that the constant sheaf functor into (light) condensed sets is isomorphic to
+the functor of sheaves of locally constant maps described above.
+
+## Proof sketch
+
+The hard part of this adjunction is to define the counit. Its components are defined as follows:
+
+Let `S : CompHausLike P` and let `Y` be a finite-product preserving presheaf on `CompHausLike P`
+(e.g. a sheaf for the coherent topology). We need to define a map `LocallyConstant S Y(*) ⟶ Y(S)`.
+Given a locally constant map `f : S → Y(*)`, let `S = S₁ ⊔ ⋯ ⊔ Sₙ` be the corresponding
+decomposition of `S` into the fibers. Let `yᵢ ∈ Y(*)` denote the value of `f` on `Sᵢ` and denote
+by `gᵢ` the canonical map `Y(*) → Y(Sᵢ)`. Our map then takes `f` to the image of
+`(g₁(y₁), ⋯, gₙ(yₙ))` under the isomorphism `Y(S₁) × ⋯ × Y(Sₙ) ≅ Y(S₁ ⊔ ⋯ ⊔ Sₙ) = Y(S)`.
+
+Now we need to prove that the counit is natural in `S : CompHausLike P` and
+`Y : Sheaf (coherentTopology (CompHausLike P)) (Type _)`. There are two key lemmas in all
+naturality proofs in this file (both lemmas are in the `CompHausLike.LocallyConstant` namespace):
+
+* `presheaf_ext`: given `S`, `Y` and `f : LocallyConstant S Y(*)` like above, another presheaf
+ `X`, and two elements `x y : X(S)`, to prove that `x = y` it suffices to prove that for every
+ inclusion map `ιᵢ : Sᵢ ⟶ S`, `X(ιᵢ)(x) = X(ιᵢ)(y)`.
+ Here it is important that we set everything up in such a way that the `Sᵢ` are literally subtypes
+ of `S`.
+
+* `incl_of_counitAppApp`: given `S`, `Y` and `f : LocallyConstant S Y(*)` like above, we have
+ `Y(ιᵢ)(ε_{S, Y}(f)) = gᵢ(yᵢ)` where `ε` denotes the counit and the other notation is like above.
+
+## Main definitions
+
+* `CompHausLike.LocallyConstant.functor`: the functor from the category of sets to the category of
+ sheaves for the coherent topology on `CompHausLike P`, which takes a set `X` to
+ `LocallyConstant - X`
+ - `CondensedSet.LocallyConstant.functor` is the above functor in the case of condensed sets.
+ - `LightCondSet.LocallyConstant.functor` is the above functor in the case of light condensed sets.
+
+* `CompHausLike.LocallyConstant.adjunction`: the functor described above is left adjoint to the
+ "underlying set" functor `(sheafSections _ _).obj ⟨CompHausLike.of P PUnit.{u+1}⟩`, which takes
+ a sheaf `X` to the set `X(*)`.
+
+* `CondensedSet.LocallyConstant.iso`: the functor `CondensedSet.LocallyConstant.functor` is
+ isomorphic to the functor `Condensed.discrete (Type _)` (the constant sheaf functor from sets to
+ condensed sets).
+
+* `LightCondSet.LocallyConstant.iso`: the functor `LightCondSet.LocallyConstant.functor` is
+ isomorphic to the functor `LightCondensed.discrete (Type _)` (the constant sheaf functor from sets
+ to light condensed sets).
+
+-/
+
+universe u w
+
+open CategoryTheory Limits LocallyConstant TopologicalSpace.Fiber Opposite Function Fiber
+
+attribute [local instance] ConcreteCategory.instFunLike
+
+variable {P : TopCat.{u} → Prop}
+
+namespace CompHausLike.LocallyConstant
+
+/--
+The functor from the category of sets to presheaves on `CompHausLike P` given by locally constant
+maps.
+-/
+@[simps]
+def functorToPresheaves : Type (max u w) ⥤ ((CompHausLike.{u} P)ᵒᵖ ⥤ Type max u w) where
+ obj X := {
+ obj := fun ⟨S⟩ ↦ LocallyConstant S X
+ map := fun f g ↦ g.comap f.unop }
+ 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
+topology
+-/
+@[simps]
+def locallyConstantIsoContinuousMap (Y X : Type*) [TopologicalSpace Y] :
+ LocallyConstant Y X ≅ C(Y, TopCat.discrete.obj X) :=
+ letI : TopologicalSpace X := ⊥
+ haveI : DiscreteTopology X := ⟨rfl⟩
+ { hom := fun f ↦ (f : C(Y, X))
+ inv := fun f ↦ ⟨f, (IsLocallyConstant.iff_continuous f).mpr f.2⟩ }
+
+section Adjunction
+
+variable [∀ (S : CompHausLike.{u} P) (p : S → Prop), HasProp P (Subtype p)]
+
+section
+
+variable {Q : CompHausLike.{u} P} {Z : Type max u w} (r : LocallyConstant Q Z) (a : Fiber r)
+
+/-- A fiber of a locally constant map as a `CompHausLike P`. -/
+def fiber : CompHausLike.{u} P := CompHausLike.of P a.val
+
+instance : HasProp P (fiber r a) := inferInstanceAs (HasProp P (Subtype _))
+
+/-- The inclusion map from a component of the coproduct induced by `f` into `S`. -/
+def sigmaIncl : fiber r a ⟶ Q := TopologicalSpace.Fiber.sigmaIncl _ a
+
+/-- The canonical map from the coproduct induced by `f` to `S` as an isomorphism in
+`CompHausLike P`. -/
+noncomputable def sigmaIso [HasExplicitFiniteCoproducts.{u} P] : (finiteCoproduct (fiber r)) ≅ Q :=
+ isoOfBijective (sigmaIsoHom r) ⟨sigmaIsoHom_inj r, sigmaIsoHom_surj r⟩
+
+lemma sigmaComparison_comp_sigmaIso [HasExplicitFiniteCoproducts.{u} P]
+ (X : (CompHausLike.{u} P)ᵒᵖ ⥤ Type max u w) :
+ (X.mapIso (sigmaIso r).op).hom ≫ sigmaComparison X (fun a ↦ (fiber r a).1) ≫
+ (fun g ↦ g a) = X.map (sigmaIncl r a).op := by
+ ext
+ simp only [Functor.mapIso_hom, Iso.op_hom, types_comp_apply, sigmaComparison, coe_of,
+ ← FunctorToTypes.map_comp_apply]
+ rfl
+
+end
+
+variable {S : CompHausLike.{u} P} {Y : (CompHausLike.{u} P)ᵒᵖ ⥤ Type max u w}
+ [HasProp P PUnit.{u+1}] (f : LocallyConstant S (Y.obj (op (CompHausLike.of P PUnit.{u+1}))))
+
+/-- The projection of the counit. -/
+noncomputable def counitAppAppImage : (a : Fiber f) → Y.obj ⟨fiber f a⟩ :=
+ fun a ↦ Y.map (CompHausLike.isTerminalPUnit.from _).op a.image
+
+/--
+The counit is defined as follows: given a locally constant map `f : S → Y(*)`, let
+`S = S₁ ⊔ ⋯ ⊔ Sₙ` be the corresponding decomposition of `S` into the fibers. We need to provide an
+element of `Y(S)`. It suffices to provide an element of `Y(Sᵢ)` for all `i`. Let `yᵢ ∈ Y(*)` denote
+the value of `f` on `Sᵢ`. Our desired element is the image of `yᵢ` under the canonical map
+`Y(*) → Y(Sᵢ)`.
+-/
+noncomputable def counitAppApp (S : CompHausLike.{u} P) (Y : (CompHausLike.{u} P)ᵒᵖ ⥤ Type max u w)
+ [PreservesFiniteProducts Y] [HasExplicitFiniteCoproducts.{u} P] :
+ LocallyConstant S (Y.obj (op (CompHausLike.of P PUnit.{u+1}))) ⟶ Y.obj ⟨S⟩ :=
+ fun r ↦ ((inv (sigmaComparison Y (fun a ↦ (fiber r a).1))) ≫
+ (Y.mapIso (sigmaIso r).op).inv) (counitAppAppImage r)
+
+-- This is the key lemma to prove naturality of the counit:
+/--
+To check equality of two elements of `X(S)`, it suffices to check equality after composing with
+each `X(S) → X(Sᵢ)`.
+-/
+lemma presheaf_ext (X : (CompHausLike.{u} P)ᵒᵖ ⥤ Type max u w)
+ [PreservesFiniteProducts X] (x y : X.obj ⟨S⟩)
+ [HasExplicitFiniteCoproducts.{u} P]
+ (h : ∀ (a : Fiber f), X.map (sigmaIncl f a).op x = X.map (sigmaIncl f a).op y) : x = y := by
+ apply injective_of_mono (X.mapIso (sigmaIso f).op).hom
+ apply injective_of_mono (sigmaComparison X (fun a ↦ (fiber f a).1))
+ ext a
+ specialize h a
+ rw [← sigmaComparison_comp_sigmaIso] at h
+ exact h
+
+lemma incl_of_counitAppApp [PreservesFiniteProducts Y] [HasExplicitFiniteCoproducts.{u} P]
+ (a : Fiber f) : Y.map (sigmaIncl f a).op (counitAppApp S Y f) = counitAppAppImage f a := by
+ rw [← sigmaComparison_comp_sigmaIso, Functor.mapIso_hom, Iso.op_hom, types_comp_apply]
+ simp only [counitAppApp, Functor.mapIso_inv, ← Iso.op_hom, types_comp_apply,
+ ← FunctorToTypes.map_comp_apply, Iso.inv_hom_id, FunctorToTypes.map_id_apply]
+ exact congrFun (inv_hom_id_apply (asIso (sigmaComparison Y (fun a ↦ (fiber f a).1)))
+ (counitAppAppImage f)) _
+
+variable {T : CompHausLike.{u} P} (g : T ⟶ S)
+
+/--
+This is an auxiliary definition, the details do not matter. What's important is that this map exists
+so that the lemma `incl_comap` works.
+-/
+def componentHom (a : Fiber (f.comap g)) :
+ fiber _ a ⟶ fiber _ (Fiber.mk f (g a.preimage)) where
+ toFun x := ⟨g x.val, by
+ simp only [Fiber.mk, Set.mem_preimage, Set.mem_singleton_iff]
+ convert map_eq_image _ _ x
+ exact map_preimage_eq_image_map _ _ a⟩
+ continuous_toFun := by exact Continuous.subtype_mk (g.continuous.comp continuous_subtype_val) _
+ -- term mode gives "unknown free variable" error.
+
+lemma incl_comap {S T : (CompHausLike P)ᵒᵖ}
+ (f : LocallyConstant S.unop (Y.obj (op (CompHausLike.of P PUnit.{u+1}))))
+ (g : S ⟶ T) (a : Fiber (f.comap g.unop)) :
+ g ≫ (sigmaIncl (f.comap g.unop) a).op =
+ (sigmaIncl f _).op ≫ (componentHom f g.unop a).op :=
+ rfl
+
+/-- The counit is natural in `S : CompHausLike P` -/
+@[simps!]
+noncomputable def counitApp [HasExplicitFiniteCoproducts.{u} P]
+ (Y : (CompHausLike.{u} P)ᵒᵖ ⥤ Type max u w) [PreservesFiniteProducts Y] :
+ (functorToPresheaves.obj (Y.obj (op (CompHausLike.of P PUnit.{u+1})))) ⟶ Y where
+ app := fun ⟨S⟩ ↦ counitAppApp S Y
+ naturality := by
+ intro S T g
+ ext f
+ apply presheaf_ext (f.comap g.unop)
+ intro a
+ simp only [op_unop, functorToPresheaves_obj_obj, types_comp_apply, functorToPresheaves_obj_map,
+ incl_of_counitAppApp, ← FunctorToTypes.map_comp_apply, incl_comap]
+ simp only [FunctorToTypes.map_comp_apply, incl_of_counitAppApp]
+ simp only [counitAppAppImage, ← FunctorToTypes.map_comp_apply, ← op_comp,
+ terminal.comp_from]
+ apply congrArg
+ exact image_eq_image_mk (g := g.unop) (a := a)
+
+variable (P) (X : TopCat.{max u w})
+ [HasExplicitFiniteCoproducts.{0} P] [HasExplicitPullbacks P]
+ (hs : ∀ ⦃X Y : CompHausLike P⦄ (f : X ⟶ Y), EffectiveEpi f → Function.Surjective f)
+
+/-- `locallyConstantIsoContinuousMap` is a natural isomorphism. -/
+noncomputable def functorToPresheavesIso (X : Type (max u w)) :
+ functorToPresheaves.{u, w}.obj X ≅ ((TopCat.discrete.obj X).toSheafCompHausLike P hs).val :=
+ NatIso.ofComponents (fun S ↦ locallyConstantIsoContinuousMap _ _)
+
+/-- `CompHausLike.LocallyConstant.functorToPresheaves` lands in sheaves. -/
+@[simps]
+def functor :
+ haveI := CompHausLike.preregular hs
+ Type (max u w) ⥤ Sheaf (coherentTopology (CompHausLike.{u} P)) (Type (max u w)) where
+ obj X := {
+ val := functorToPresheaves.{u, w}.obj X
+ cond := by
+ rw [Presheaf.isSheaf_of_iso_iff (functorToPresheavesIso P hs X)]
+ exact ((TopCat.discrete.obj X).toSheafCompHausLike P hs).cond }
+ map f := ⟨functorToPresheaves.{u, w}.map f⟩
+
+/--
+`CompHausLike.LocallyConstant.functor` is naturally isomorphic to the restriction of
+`topCatToSheafCompHausLike` to discrete topological spaces.
+-/
+noncomputable def functorIso :
+ functor.{u, w} P hs ≅ TopCat.discrete.{max w u} ⋙ topCatToSheafCompHausLike P hs :=
+ NatIso.ofComponents (fun X ↦ (fullyFaithfulSheafToPresheaf _ _).preimageIso
+ (functorToPresheavesIso P hs X))
+
+/-- The counit is natural in both `S : CompHausLike P` and
+`Y : Sheaf (coherentTopology (CompHausLike P)) (Type (max u w))` -/
+@[simps]
+noncomputable def counit [HasExplicitFiniteCoproducts.{u} P] : haveI := CompHausLike.preregular hs
+ (sheafSections _ _).obj ⟨CompHausLike.of P PUnit.{u+1}⟩ ⋙ functor.{u, w} P hs ⟶
+ 𝟭 (Sheaf (coherentTopology (CompHausLike.{u} P)) (Type (max u w))) where
+ app X := haveI := CompHausLike.preregular hs
+ ⟨counitApp X.val⟩
+ naturality X Y g := by
+ have := CompHausLike.preregular hs
+ apply Sheaf.hom_ext
+ simp only [functor, id_eq, eq_mpr_eq_cast, Functor.comp_obj, Functor.flip_obj_obj,
+ sheafToPresheaf_obj, Functor.id_obj, Functor.comp_map, Functor.flip_obj_map,
+ sheafToPresheaf_map, Sheaf.instCategorySheaf_comp_val, Functor.id_map]
+ ext S (f : LocallyConstant _ _)
+ simp only [FunctorToTypes.comp, counitApp_app]
+ apply presheaf_ext (f.map (g.val.app (op (CompHausLike.of P PUnit.{u+1}))))
+ intro a
+ simp only [op_unop, functorToPresheaves_map_app, incl_of_counitAppApp]
+ apply presheaf_ext (f.comap (sigmaIncl _ _))
+ intro b
+ simp only [counitAppAppImage, ← FunctorToTypes.map_comp_apply, ← op_comp, CompHausLike.coe_of,
+ map_apply, IsTerminal.comp_from, ← map_preimage_eq_image_map]
+ change (_ ≫ Y.val.map _) _ = (_ ≫ Y.val.map _) _
+ simp only [← g.val.naturality,
+ show sigmaIncl (f.comap (sigmaIncl (f.map _) a)) b ≫ sigmaIncl (f.map _) a =
+ (sigmaInclIncl f _ a b) ≫ sigmaIncl f (Fiber.mk f _) from rfl]
+ simp only [op_comp, Functor.map_comp, types_comp_apply, incl_of_counitAppApp]
+ simp only [counitAppAppImage, ← FunctorToTypes.map_comp_apply, ← op_comp, terminal.comp_from]
+ rw [mk_image]
+ change (X.val.map _ ≫ _) _ = (X.val.map _ ≫ _) _
+ simp only [g.val.naturality]
+ simp only [types_comp_apply]
+ have := map_preimage_eq_image (f := g.val.app _ ∘ f) (a := a)
+ simp only [Function.comp_apply] at this
+ rw [this]
+ apply congrArg
+ symm
+ convert (b.preimage).prop
+ exact (mem_iff_eq_image (g.val.app _ ∘ f) _ _).symm
+
+/--
+The unit of the adjunciton is given by mapping each element to the corresponding constant map.
+-/
+@[simps]
+def unit : 𝟭 _ ⟶ functor P hs ⋙ (sheafSections _ _).obj ⟨CompHausLike.of P PUnit.{u+1}⟩ where
+ 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 _ 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) ≫
+ ((counit P hs).app ((functor P hs).obj X)).val = 𝟙 (functorToPresheaves.obj X) := by
+ ext ⟨S⟩ (f : LocallyConstant _ X)
+ simp only [Functor.id_obj, Functor.comp_obj, FunctorToTypes.comp, NatTrans.id_app,
+ functorToPresheaves_obj_obj, types_id_apply]
+ simp only [counit, counitApp_app]
+ have := CompHausLike.preregular hs
+ apply presheaf_ext
+ (X := ((functor P hs).obj X).val) (Y := ((functor.{u, w} P hs).obj X).val)
+ (f.map ((unit P hs).app X))
+ intro a
+ erw [incl_of_counitAppApp]
+ simp only [functor_obj_val, functorToPresheaves_obj_obj, coe_of, Functor.id_obj,
+ counitAppAppImage, LocallyConstant.map_apply, functorToPresheaves_obj_map, Quiver.Hom.unop_op]
+ ext x
+ erw [← map_eq_image _ a x]
+ rfl
+
+/--
+`CompHausLike.LocallyConstant.functor` is left adjoint to the forgetful functor.
+-/
+@[simps]
+noncomputable def adjunction [HasExplicitFiniteCoproducts.{u} P] :
+ functor.{u, w} P hs ⊣ (sheafSections _ _).obj ⟨CompHausLike.of P PUnit.{u+1}⟩ where
+ unit := unit P hs
+ counit := counit P hs
+ left_triangle_components := by
+ intro X
+ simp only [Functor.comp_obj, Functor.id_obj, NatTrans.comp_app, Functor.flip_obj_obj,
+ sheafToPresheaf_obj, functor_obj_val, functorToPresheaves_obj_obj, coe_of, whiskerRight_app,
+ Functor.associator_hom_app, whiskerLeft_app, Category.id_comp, NatTrans.id_app']
+ apply Sheaf.hom_ext
+ rw [Sheaf.instCategorySheaf_comp_val, Sheaf.instCategorySheaf_id_val]
+ exact adjunction_left_triangle P hs X
+ right_triangle_components := by
+ intro X
+ ext (x : X.val.obj _)
+ simp only [Functor.comp_obj, Functor.id_obj, Functor.flip_obj_obj, sheafToPresheaf_obj,
+ FunctorToTypes.comp, whiskerLeft_app, unit_app, coe_of, Functor.associator_inv_app,
+ functor_obj_val, functorToPresheaves_obj_obj, types_id_apply, whiskerRight_app,
+ Functor.flip_obj_map, sheafToPresheaf_map, counit_app_val, counitApp_app, NatTrans.id_app']
+ have := CompHausLike.preregular hs
+ letI : PreservesFiniteProducts ((sheafToPresheaf (coherentTopology _) _).obj X) :=
+ inferInstanceAs (PreservesFiniteProducts (Sheaf.val _))
+ apply presheaf_ext ((unit P hs).app _ x)
+ intro a
+ erw [incl_of_counitAppApp]
+ simp only [sheafToPresheaf_obj, unit_app, coe_of, counitAppAppImage, coe_const]
+ erw [← map_eq_image _ a ⟨PUnit.unit, by simp [mem_iff_eq_image, ← map_preimage_eq_image]⟩]
+ rfl
+
+instance [HasExplicitFiniteCoproducts.{u} P] : IsIso (adjunction P hs).unit :=
+ inferInstanceAs (IsIso (unitIso P hs).hom)
+
+end Adjunction
+
+end CompHausLike.LocallyConstant
+
+section Condensed
+
+open Condensed CompHausLike
+
+namespace CondensedSet.LocallyConstant
+
+/-- The functor from sets to condensed sets given by locally constant maps into the set. -/
+abbrev functor : Type (u+1) ⥤ CondensedSet.{u} :=
+ CompHausLike.LocallyConstant.functor.{u, u+1} (P := fun _ ↦ True)
+ (hs := fun _ _ _ ↦ ((CompHaus.effectiveEpi_tfae _).out 0 2).mp)
+
+/--
+`CondensedSet.LocallyConstant.functor` is isomorphic to `Condensed.discrete`
+(by uniqueness of adjoints).
+-/
+noncomputable def iso : functor ≅ discrete (Type (u+1)) :=
+ (LocallyConstant.adjunction _ _).leftAdjointUniq (discreteUnderlyingAdj _)
+
+/-- `CondensedSet.LocallyConstant.functor` is fully faithful. -/
+noncomputable def functorFullyFaithful : functor.FullyFaithful :=
+ (LocallyConstant.adjunction.{u, u+1} _ _).fullyFaithfulLOfIsIsoUnit
+
+noncomputable instance : functor.Faithful := functorFullyFaithful.faithful
+
+noncomputable instance : functor.Full := functorFullyFaithful.full
+
+instance : (discrete (Type _)).Faithful := Functor.Faithful.of_iso iso
+
+noncomputable instance : (discrete (Type _)).Full := Functor.Full.of_iso iso
+
+end CondensedSet.LocallyConstant
+
+namespace LightCondSet.LocallyConstant
+
+/-- The functor from sets to light condensed sets given by locally constant maps into the set. -/
+abbrev functor : Type u ⥤ LightCondSet.{u} :=
+ CompHausLike.LocallyConstant.functor.{u, u}
+ (P := fun X ↦ TotallyDisconnectedSpace X ∧ SecondCountableTopology X)
+ (hs := fun _ _ _ ↦ (LightProfinite.effectiveEpi_iff_surjective _).mp)
+
+instance (S : LightProfinite.{u}) (p : S → Prop) :
+ HasProp (fun X ↦ TotallyDisconnectedSpace X ∧ SecondCountableTopology X) (Subtype p) :=
+ ⟨⟨(inferInstance : TotallyDisconnectedSpace (Subtype p)),
+ (inferInstance : SecondCountableTopology {s | p s})⟩⟩
+
+/--
+`LightCondSet.LocallyConstant.functor` is isomorphic to `LightCondensed.discrete`
+(by uniqueness of adjoints).
+-/
+noncomputable def iso : functor ≅ LightCondensed.discrete (Type u) :=
+ (LocallyConstant.adjunction _ _).leftAdjointUniq (LightCondensed.discreteUnderlyingAdj _)
+
+/-- `LightCondSet.LocallyConstant.functor` is fully faithful. -/
+noncomputable def functorFullyFaithful : functor.{u}.FullyFaithful :=
+ (LocallyConstant.adjunction _ _).fullyFaithfulLOfIsIsoUnit
+
+instance : functor.{u}.Faithful := functorFullyFaithful.faithful
+
+instance : LightCondSet.LocallyConstant.functor.Full := functorFullyFaithful.full
+
+instance : (LightCondensed.discrete (Type u)).Faithful := Functor.Faithful.of_iso iso.{u}
+
+instance : (LightCondensed.discrete (Type u)).Full := Functor.Full.of_iso iso.{u}
+
+end LightCondSet.LocallyConstant
+
+end Condensed
diff --git a/Mathlib/Condensed/Discrete/Module.lean b/Mathlib/Condensed/Discrete/Module.lean
new file mode 100644
index 0000000000000..5657c6d51579e
--- /dev/null
+++ b/Mathlib/Condensed/Discrete/Module.lean
@@ -0,0 +1,281 @@
+/-
+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.Sites.ConstantSheaf
+import Mathlib.Condensed.Discrete.LocallyConstant
+import Mathlib.Condensed.Light.Module
+import Mathlib.Condensed.Module
+import Mathlib.Topology.LocallyConstant.Algebra
+/-!
+
+# Discrete condensed `R`-modules
+
+This file provides the necessary API to prove that a condensed `R`-module is discrete if and only
+if the underlying condensed set is (both for light condensed and condensed).
+
+That is, it defines the functor `CondensedMod.LocallyConstant.functor` which takes an `R`-module to
+the condensed `R`-modules given by locally constant maps to it, and proves that this functor is
+naturally isomorphic to the constant sheaf functor (and the analogues for light condensed modules).
+-/
+
+universe w u
+
+open CategoryTheory LocallyConstant CompHausLike Functor Category Functor Opposite
+
+attribute [local instance] ConcreteCategory.instFunLike
+
+variable {P : TopCat.{u} → Prop}
+
+namespace CompHausLike.LocallyConstantModule
+
+variable (R : Type (max u w)) [Ring R]
+
+/--
+The functor from the category of `R`-modules to presheaves on `CompHausLike P` given by locally
+constant maps.
+-/
+@[simps]
+def functorToPresheaves : ModuleCat.{max u w} R ⥤ ((CompHausLike.{u} P)ᵒᵖ ⥤ ModuleCat R) where
+ obj X := {
+ obj := fun ⟨S⟩ ↦ ModuleCat.of R (LocallyConstant S X)
+ map := fun f ↦ comapₗ R f.unop }
+ map f := { app := fun S ↦ mapₗ R f }
+
+variable [HasExplicitFiniteCoproducts.{0} P] [HasExplicitPullbacks.{u} P]
+ (hs : ∀ ⦃X Y : CompHausLike P⦄ (f : X ⟶ Y), EffectiveEpi f → Function.Surjective f)
+
+/-- `CompHausLike.LocallyConstantModule.functorToPresheaves` lands in sheaves. -/
+@[simps]
+def functor : haveI := CompHausLike.preregular hs
+ ModuleCat R ⥤ Sheaf (coherentTopology (CompHausLike.{u} P)) (ModuleCat R) where
+ obj X := {
+ val := (functorToPresheaves.{w, u} R).obj X
+ cond := by
+ have := CompHausLike.preregular hs
+ apply Presheaf.isSheaf_coherent_of_hasPullbacks_of_comp
+ (s := CategoryTheory.forget (ModuleCat R))
+ exact ((CompHausLike.LocallyConstant.functor P hs).obj _).cond }
+ map f := ⟨(functorToPresheaves.{w, u} R).map f⟩
+
+end CompHausLike.LocallyConstantModule
+
+namespace CondensedMod.LocallyConstant
+
+open Condensed
+
+variable (R : Type (u+1)) [Ring R]
+
+/-- `functorToPresheaves` in the case of `CompHaus`. -/
+abbrev functorToPresheaves : ModuleCat.{u+1} R ⥤ (CompHaus.{u}ᵒᵖ ⥤ ModuleCat R) :=
+ CompHausLike.LocallyConstantModule.functorToPresheaves.{u+1, u} R
+
+/-- `functorToPresheaves` as a functor to condensed modules. -/
+abbrev functor : ModuleCat R ⥤ CondensedMod.{u} R :=
+ CompHausLike.LocallyConstantModule.functor.{u+1, u} R
+ (fun _ _ _ ↦ ((CompHaus.effectiveEpi_tfae _).out 0 2).mp)
+
+/-- Auxiliary definition for `functorIsoDiscrete`. -/
+noncomputable def functorIsoDiscreteAux₁ (M : ModuleCat.{u+1} R) :
+ M ≅ (ModuleCat.of R (LocallyConstant (CompHaus.of PUnit.{u+1}) M)) where
+ hom := constₗ R
+ inv := evalₗ R PUnit.unit
+
+/-- Auxiliary definition for `functorIsoDiscrete`. -/
+noncomputable def functorIsoDiscreteAux₂ (M : ModuleCat R) :
+ (discrete _).obj M ≅ (discrete _).obj
+ (ModuleCat.of R (LocallyConstant (CompHaus.of PUnit.{u+1}) M)) :=
+ (discrete _).mapIso (functorIsoDiscreteAux₁ R M)
+
+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 ?_
+ have : (constantSheaf (coherentTopology CompHaus) (Type (u + 1))).Faithful :=
+ inferInstanceAs (discrete _).Faithful
+ have : (constantSheaf (coherentTopology CompHaus) (Type (u + 1))).Full :=
+ inferInstanceAs (discrete _).Full
+ rw [← Sheaf.isConstant_iff_isIso_counit_app]
+ constructor
+ change _ ∈ (discrete _).essImage
+ rw [essImage_eq_of_natIso CondensedSet.LocallyConstant.iso.symm]
+ exact obj_mem_essImage CondensedSet.LocallyConstant.functor M
+
+/-- Auxiliary definition for `functorIsoDiscrete`. -/
+noncomputable def functorIsoDiscreteComponents (M : ModuleCat R) :
+ (discrete _).obj M ≅ (functor R).obj M :=
+ have : (Condensed.forget R).ReflectsIsomorphisms :=
+ inferInstanceAs (sheafCompose _ _).ReflectsIsomorphisms
+ have : IsIso ((discreteUnderlyingAdj (ModuleCat R)).counit.app ((functor R).obj M)) :=
+ isIso_of_reflects_iso _ (Condensed.forget R)
+ functorIsoDiscreteAux₂ R M ≪≫ asIso ((discreteUnderlyingAdj _).counit.app ((functor R).obj M))
+
+/--
+`CondensedMod.LocallyConstant.functor` is naturally isomorphic to the constant sheaf functor from
+`R`-modules to condensed `R`-modules.
+ -/
+noncomputable def functorIsoDiscrete : functor R ≅ discrete _ :=
+ NatIso.ofComponents (fun M ↦ (functorIsoDiscreteComponents R M).symm) fun f ↦ by
+ dsimp
+ rw [Iso.eq_inv_comp, ← Category.assoc, Iso.comp_inv_eq]
+ dsimp [functorIsoDiscreteComponents]
+ rw [assoc, ← Iso.eq_inv_comp,
+ ← (discreteUnderlyingAdj (ModuleCat R)).counit_naturality]
+ simp only [← assoc]
+ congr 1
+ rw [← Iso.comp_inv_eq]
+ apply Sheaf.hom_ext
+ simp [functorIsoDiscreteAux₂, ← Functor.map_comp]
+ rfl
+
+/--
+`CondensedMod.LocallyConstant.functor` is left adjoint to the forgetful functor from condensed
+`R`-modules to `R`-modules.
+-/
+noncomputable def adjunction : functor R ⊣ underlying (ModuleCat R) :=
+ Adjunction.ofNatIsoLeft (discreteUnderlyingAdj _) (functorIsoDiscrete R).symm
+
+/--
+`CondensedMod.LocallyConstant.functor` is fully faithful.
+-/
+noncomputable def fullyFaithfulFunctor : (functor R).FullyFaithful :=
+ (adjunction R).fullyFaithfulLOfCompIsoId
+ (NatIso.ofComponents fun M ↦ (functorIsoDiscreteAux₁ R _).symm)
+
+instance : (functor R).Faithful := (fullyFaithfulFunctor R).faithful
+
+instance : (functor R).Full := (fullyFaithfulFunctor R).full
+
+instance : (discrete (ModuleCat R)).Faithful :=
+ Functor.Faithful.of_iso (functorIsoDiscrete R)
+
+instance : (constantSheaf (coherentTopology CompHaus) (ModuleCat R)).Faithful :=
+ inferInstanceAs (discrete (ModuleCat R)).Faithful
+
+instance : (discrete (ModuleCat R)).Full :=
+ Functor.Full.of_iso (functorIsoDiscrete R)
+
+instance : (constantSheaf (coherentTopology CompHaus) (ModuleCat R)).Full :=
+ inferInstanceAs (discrete (ModuleCat R)).Full
+
+instance : (constantSheaf (coherentTopology CompHaus) (Type (u + 1))).Faithful :=
+ inferInstanceAs (discrete (Type (u + 1))).Faithful
+
+instance : (constantSheaf (coherentTopology CompHaus) (Type (u + 1))).Full :=
+ inferInstanceAs (discrete (Type (u + 1))).Full
+
+end CondensedMod.LocallyConstant
+
+namespace LightCondMod.LocallyConstant
+
+open LightCondensed
+
+variable (R : Type u) [Ring R]
+
+/-- `functorToPresheaves` in the case of `LightProfinite`. -/
+abbrev functorToPresheaves : ModuleCat.{u} R ⥤ (LightProfinite.{u}ᵒᵖ ⥤ ModuleCat R) :=
+ CompHausLike.LocallyConstantModule.functorToPresheaves.{u, u} R
+
+/-- `functorToPresheaves` as a functor to light condensed modules. -/
+abbrev functor : ModuleCat R ⥤ LightCondMod.{u} R :=
+ CompHausLike.LocallyConstantModule.functor.{u, u} R
+ (fun _ _ _ ↦ (LightProfinite.effectiveEpi_iff_surjective _).mp)
+
+/-- Auxiliary definition for `functorIsoDiscrete`. -/
+noncomputable def functorIsoDiscreteAux₁ (M : ModuleCat.{u} R) :
+ M ≅ (ModuleCat.of R (LocallyConstant (LightProfinite.of PUnit.{u+1}) M)) where
+ hom := constₗ R
+ inv := evalₗ R PUnit.unit
+
+/-- Auxiliary definition for `functorIsoDiscrete`. -/
+noncomputable def functorIsoDiscreteAux₂ (M : ModuleCat.{u} R) :
+ (discrete _).obj M ≅ (discrete _).obj
+ (ModuleCat.of R (LocallyConstant (LightProfinite.of PUnit.{u+1}) M)) :=
+ (discrete _).mapIso (functorIsoDiscreteAux₁ R M)
+
+-- Not stating this explicitly causes timeouts below.
+instance : HasSheafify (coherentTopology LightProfinite.{u}) (ModuleCat.{u} R) :=
+ inferInstance
+
+instance (M : ModuleCat R) :
+ IsIso ((LightCondensed.forget R).map
+ ((discreteUnderlyingAdj (ModuleCat R)).counit.app
+ ((functor R).obj M))) := by
+ dsimp [LightCondensed.forget, discreteUnderlyingAdj]
+ rw [← constantSheafAdj_counit_w]
+ refine IsIso.comp_isIso' inferInstance ?_
+ have : (constantSheaf (coherentTopology LightProfinite) (Type u)).Faithful :=
+ inferInstanceAs (discrete _).Faithful
+ have : (constantSheaf (coherentTopology LightProfinite) (Type u)).Full :=
+ inferInstanceAs (discrete _).Full
+ rw [← Sheaf.isConstant_iff_isIso_counit_app]
+ constructor
+ change _ ∈ (discrete _).essImage
+ rw [essImage_eq_of_natIso LightCondSet.LocallyConstant.iso.symm]
+ exact obj_mem_essImage LightCondSet.LocallyConstant.functor M
+
+/-- Auxiliary definition for `functorIsoDiscrete`. -/
+noncomputable def functorIsoDiscreteComponents (M : ModuleCat R) :
+ (discrete _).obj M ≅ (functor R).obj M :=
+ have : (LightCondensed.forget R).ReflectsIsomorphisms :=
+ inferInstanceAs (sheafCompose _ _).ReflectsIsomorphisms
+ have : IsIso ((discreteUnderlyingAdj (ModuleCat R)).counit.app ((functor R).obj M)) :=
+ isIso_of_reflects_iso _ (LightCondensed.forget R)
+ functorIsoDiscreteAux₂ R M ≪≫ asIso ((discreteUnderlyingAdj _).counit.app ((functor R).obj M))
+
+/--
+`LightCondMod.LocallyConstant.functor` is naturally isomorphic to the constant sheaf functor from
+`R`-modules to light condensed `R`-modules.
+ -/
+noncomputable def functorIsoDiscrete : functor R ≅ discrete _ :=
+ NatIso.ofComponents (fun M ↦ (functorIsoDiscreteComponents R M).symm) fun f ↦ by
+ dsimp
+ rw [Iso.eq_inv_comp, ← Category.assoc, Iso.comp_inv_eq]
+ dsimp [functorIsoDiscreteComponents]
+ rw [Category.assoc, ← Iso.eq_inv_comp,
+ ← (discreteUnderlyingAdj (ModuleCat R)).counit_naturality]
+ simp only [← assoc]
+ congr 1
+ rw [← Iso.comp_inv_eq]
+ apply Sheaf.hom_ext
+ simp [functorIsoDiscreteAux₂, ← Functor.map_comp]
+ rfl
+
+/--
+`LightCondMod.LocallyConstant.functor` is left adjoint to the forgetful functor from light condensed
+`R`-modules to `R`-modules.
+ -/
+noncomputable def adjunction : functor R ⊣ underlying (ModuleCat R) :=
+ Adjunction.ofNatIsoLeft (discreteUnderlyingAdj _) (functorIsoDiscrete R).symm
+
+/--
+`LightCondMod.LocallyConstant.functor` is fully faithful.
+-/
+noncomputable def fullyFaithfulFunctor : (functor R).FullyFaithful :=
+ (adjunction R).fullyFaithfulLOfCompIsoId
+ (NatIso.ofComponents fun M ↦ (functorIsoDiscreteAux₁ R _).symm)
+
+instance : (functor R).Faithful := (fullyFaithfulFunctor R).faithful
+
+instance : (functor R).Full := (fullyFaithfulFunctor R).full
+
+instance : (discrete.{u} (ModuleCat R)).Faithful := Functor.Faithful.of_iso (functorIsoDiscrete R)
+
+instance : (constantSheaf (coherentTopology LightProfinite.{u}) (ModuleCat.{u} R)).Faithful :=
+ inferInstanceAs (discrete.{u} (ModuleCat R)).Faithful
+
+instance : (discrete (ModuleCat.{u} R)).Full :=
+ Functor.Full.of_iso (functorIsoDiscrete R)
+
+instance : (constantSheaf (coherentTopology LightProfinite.{u}) (ModuleCat.{u} R)).Full :=
+ inferInstanceAs (discrete.{u} (ModuleCat.{u} R)).Full
+
+instance : (constantSheaf (coherentTopology LightProfinite) (Type u)).Faithful :=
+ inferInstanceAs (discrete (Type u)).Faithful
+
+instance : (constantSheaf (coherentTopology LightProfinite) (Type u)).Full :=
+ inferInstanceAs (discrete (Type u)).Full
+
+end LightCondMod.LocallyConstant
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 740982a3a7bad..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 ⟨_, _⟩
@@ -118,14 +111,13 @@ def topCatAdjunctionUnit (X : LightCondSet.{u}) : X ⟶ X.toTopCat.toLightCondSe
rfl }
/-- The adjunction `lightCondSetToTopCat ⊣ topCatToLightCondSet` -/
-noncomputable def topCatAdjunction : lightCondSetToTopCat.{u} ⊣ topCatToLightCondSet :=
- Adjunction.mkOfUnitCounit {
- unit := { app := topCatAdjunctionUnit }
- counit := { app := topCatAdjunctionCounit }
- left_triangle := by
- ext Y
- change Y.val.map (𝟙 _) _ = _
- simp }
+noncomputable def topCatAdjunction : lightCondSetToTopCat.{u} ⊣ topCatToLightCondSet where
+ unit := { app := topCatAdjunctionUnit }
+ counit := { app := topCatAdjunctionCounit }
+ left_triangle_components Y := by
+ ext
+ change Y.val.map (𝟙 _) _ = _
+ simp
instance (X : TopCat) : Epi (topCatAdjunction.counit.app X) := by
rw [TopCat.epi_iff_surjective]
diff --git a/Mathlib/Condensed/TopCatAdjunction.lean b/Mathlib/Condensed/TopCatAdjunction.lean
index d6794943e54a1..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 ⟨_, _⟩
@@ -119,14 +113,13 @@ def topCatAdjunctionUnit (X : CondensedSet.{u}) : X ⟶ X.toTopCat.toCondensedSe
rfl }
/-- The adjunction `condensedSetToTopCat ⊣ topCatToCondensedSet` -/
-noncomputable def topCatAdjunction : condensedSetToTopCat.{u} ⊣ topCatToCondensedSet :=
- Adjunction.mkOfUnitCounit {
- unit := { app := topCatAdjunctionUnit }
- counit := { app := topCatAdjunctionCounit }
- left_triangle := by
- ext Y
- change Y.val.map (𝟙 _) _ = _
- simp }
+noncomputable def topCatAdjunction : condensedSetToTopCat.{u} ⊣ topCatToCondensedSet where
+ unit := { app := topCatAdjunctionUnit }
+ counit := { app := topCatAdjunctionCounit }
+ left_triangle_components Y := by
+ ext
+ change Y.val.map (𝟙 _) _ = _
+ simp
instance (X : TopCat) : Epi (topCatAdjunction.counit.app X) := by
rw [TopCat.epi_iff_surjective]
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/Applicative.lean b/Mathlib/Control/Applicative.lean
index 87acbfcaf5833..3b6bb33ac8951 100644
--- a/Mathlib/Control/Applicative.lean
+++ b/Mathlib/Control/Applicative.lean
@@ -5,6 +5,7 @@ Authors: Simon Hudon
-/
import Mathlib.Algebra.Group.Defs
import Mathlib.Control.Functor
+import Mathlib.Control.Basic
/-!
# `applicative` instances
@@ -28,7 +29,7 @@ variable {α β γ σ : Type u}
theorem Applicative.map_seq_map (f : α → β → γ) (g : σ → β) (x : F α) (y : F σ) :
f <$> x <*> g <$> y = ((· ∘ g) ∘ f) <$> x <*> y := by
- simp [flip, functor_norm]
+ simp [flip, functor_norm, Function.comp_def]
theorem Applicative.pure_seq_eq_map' (f : α → β) : ((pure f : F (α → β)) <*> ·) = (f <$> ·) := by
ext; simp [functor_norm]
diff --git a/Mathlib/Control/Basic.lean b/Mathlib/Control/Basic.lean
index 0df3671f162c4..e6e6aa94abeee 100644
--- a/Mathlib/Control/Basic.lean
+++ b/Mathlib/Control/Basic.lean
@@ -18,12 +18,7 @@ variable {α β γ : Type u}
section Functor
-variable {f : Type u → Type v} [Functor f] [LawfulFunctor f]
-@[functor_norm]
-theorem Functor.map_map (m : α → β) (g : β → γ) (x : f α) : g <$> m <$> x = (g ∘ m) <$> x :=
- (comp_map _ _ _).symm
--- order of implicits
--- order of implicits
+attribute [functor_norm] Functor.map_map
end Functor
@@ -67,10 +62,6 @@ section Monad
variable {m : Type u → Type v} [Monad m] [LawfulMonad m]
-theorem map_bind (x : m α) {g : α → m β} {f : β → γ} :
- f <$> (x >>= g) = x >>= fun a => f <$> g a := by
- rw [← bind_pure_comp, bind_assoc]; simp [bind_pure_comp]
-
theorem seq_bind_eq (x : m α) {g : β → m γ} {f : α → β} :
f <$> x >>= g = x >>= g ∘ f :=
show bind (f <$> x) g = bind x (g ∘ f) by
@@ -214,8 +205,6 @@ class CommApplicative (m : Type u → Type v) [Applicative m] extends LawfulAppl
open Functor
-variable {m}
-
theorem CommApplicative.commutative_map {m : Type u → Type v} [h : Applicative m]
[CommApplicative m] {α β γ} (a : m α) (b : m β) {f : α → β → γ} :
f <$> a <*> b = flip f <$> b <*> a :=
diff --git a/Mathlib/Control/EquivFunctor.lean b/Mathlib/Control/EquivFunctor.lean
index 05e6050b3e91e..6b7e9c7c574e1 100644
--- a/Mathlib/Control/EquivFunctor.lean
+++ b/Mathlib/Control/EquivFunctor.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.Equiv.Defs
import Mathlib.Tactic.Convert
@@ -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 87b89a8ea37f9..62f3c1590452d 100644
--- a/Mathlib/Control/EquivFunctor/Instances.lean
+++ b/Mathlib/Control/EquivFunctor/Instances.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Data.Fintype.Basic
import Mathlib.Control.EquivFunctor
@@ -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.lean b/Mathlib/Control/Functor.lean
index 59ebe2553d456..305a88d2cc83f 100644
--- a/Mathlib/Control/Functor.lean
+++ b/Mathlib/Control/Functor.lean
@@ -3,7 +3,7 @@ Copyright (c) 2017 Simon Hudon. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Simon Hudon
-/
-import Mathlib.Control.Basic
+import Mathlib.Tactic.Attr.Register
import Mathlib.Data.Set.Defs
import Mathlib.Tactic.TypeStar
import Batteries.Tactic.Lint
@@ -181,7 +181,7 @@ protected theorem id_map : ∀ x : Comp F G α, Comp.map id x = x
protected theorem comp_map (g' : α → β) (h : β → γ) :
∀ x : Comp F G α, Comp.map (h ∘ g') x = Comp.map h (Comp.map g' x)
- | Comp.mk x => by simp [Comp.map, Comp.mk, Functor.map_comp_map, functor_norm]
+ | Comp.mk x => by simp [Comp.map, Comp.mk, Functor.map_comp_map, functor_norm, Function.comp_def]
-- Porting note: `Comp.mk` wasn't needed in mathlib3
instance lawfulFunctor : LawfulFunctor (Comp F G) where
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/Lawful.lean b/Mathlib/Control/Lawful.lean
index 769ec2655f4ec..f2cd84ab5da94 100644
--- a/Mathlib/Control/Lawful.lean
+++ b/Mathlib/Control/Lawful.lean
@@ -48,7 +48,7 @@ end StateT
namespace ExceptT
-variable {α β ε : Type u} {m : Type u → Type v} (x : ExceptT ε m α)
+variable {α ε : Type u} {m : Type u → Type v} (x : ExceptT ε m α)
-- Porting note: This is proven by proj reduction in Lean 3.
@[simp]
@@ -73,7 +73,6 @@ namespace ReaderT
section
-variable {ρ : Type u}
variable {m : Type u → Type v}
variable {α σ : Type u}
diff --git a/Mathlib/Control/LawfulFix.lean b/Mathlib/Control/LawfulFix.lean
index 90e5b963198d1..f22207cffe5c1 100644
--- a/Mathlib/Control/LawfulFix.lean
+++ b/Mathlib/Control/LawfulFix.lean
@@ -80,7 +80,7 @@ theorem mem_iff (a : α) (b : β a) : b ∈ Part.fix f a ↔ ∃ i, b ∈ approx
· rcases le_total i j with H | H <;> [skip; symm] <;> apply_assumption <;> assumption
replace hh := approx_mono f case _ _ hh
apply Part.mem_unique h₁ hh
- · simp only [fix_def' (⇑f) h₀, not_exists, false_iff_iff, not_mem_none]
+ · simp only [fix_def' (⇑f) h₀, not_exists, false_iff, not_mem_none]
simp only [dom_iff_mem, not_exists] at h₀
intro; apply h₀
@@ -167,10 +167,9 @@ theorem fix_eq_ωSup_of_ωScottContinuous (hc : ωScottContinuous g) : Part.fix
theorem fix_eq_of_ωScottContinuous (hc : ωScottContinuous g) :
Part.fix g = g (Part.fix g) := by
- rw [fix_eq_ωSup_of_ωScottContinuous, hc.map_ωSup]
+ rw [fix_eq_ωSup_of_ωScottContinuous hc, hc.map_ωSup]
apply le_antisymm
· apply ωSup_le_ωSup_of_le _
- exact hc
intro i
exists i
intro x
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/Random.lean b/Mathlib/Control/Random.lean
index 598d03e3d3880..c83ecbaba193b 100644
--- a/Mathlib/Control/Random.lean
+++ b/Mathlib/Control/Random.lean
@@ -28,7 +28,7 @@ defining objects that can be created randomly.
-/
-set_option autoImplicit true
+set_option autoImplicit true -- Note: this file uses `autoImplicit` pervasively
/-- A monad transformer to generate random objects using the generic generator type `g` -/
abbrev RandGT (g : Type) := StateT (ULift g)
diff --git a/Mathlib/Control/Traversable/Basic.lean b/Mathlib/Control/Traversable/Basic.lean
index e9103c5c55aa4..20827287d137a 100644
--- a/Mathlib/Control/Traversable/Basic.lean
+++ b/Mathlib/Control/Traversable/Basic.lean
@@ -6,6 +6,7 @@ Authors: Simon Hudon
import Mathlib.Data.Option.Defs
import Mathlib.Control.Functor
import Batteries.Data.List.Basic
+import Mathlib.Control.Basic
/-!
# Traversable type class
@@ -60,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
@@ -143,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
@@ -157,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]
@@ -203,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. -/
@@ -249,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/Equiv.lean b/Mathlib/Control/Traversable/Equiv.lean
index fbd1a7fcc724e..db32b26b14bb2 100644
--- a/Mathlib/Control/Traversable/Equiv.lean
+++ b/Mathlib/Control/Traversable/Equiv.lean
@@ -53,7 +53,7 @@ protected theorem id_map {α : Type u} (x : t' α) : Equiv.map eqv id x = x := b
protected theorem comp_map {α β γ : Type u} (g : α → β) (h : β → γ) (x : t' α) :
Equiv.map eqv (h ∘ g) x = Equiv.map eqv h (Equiv.map eqv g x) := by
- simpa [Equiv.map] using comp_map ..
+ simp [Equiv.map, Function.comp_def]
protected theorem lawfulFunctor : @LawfulFunctor _ (Equiv.functor eqv) :=
-- Porting note: why is `_inst` required here?
diff --git a/Mathlib/Control/Traversable/Instances.lean b/Mathlib/Control/Traversable/Instances.lean
index 9e4afad602947..a91d6a6202f43 100644
--- a/Mathlib/Control/Traversable/Instances.lean
+++ b/Mathlib/Control/Traversable/Instances.lean
@@ -32,7 +32,7 @@ theorem Option.id_traverse {α} (x : Option α) : Option.traverse (pure : α →
theorem Option.comp_traverse {α β γ} (f : β → F γ) (g : α → G β) (x : Option α) :
Option.traverse (Comp.mk ∘ (f <$> ·) ∘ g) x =
Comp.mk (Option.traverse f <$> Option.traverse g x) := by
- cases x <;> simp! [functor_norm] <;> rfl
+ cases x <;> (simp! [functor_norm] <;> rfl)
theorem Option.traverse_eq_map_id {α β} (f : α → β) (x : Option α) :
Option.traverse ((pure : _ → Id _) ∘ f) x = (pure : _ → Id _) (f <$> x) := by cases x <;> rfl
@@ -148,7 +148,7 @@ variable [LawfulApplicative G]
protected theorem comp_traverse {α β γ : Type u} (f : β → F γ) (g : α → G β) (x : σ ⊕ α) :
Sum.traverse (Comp.mk ∘ (f <$> ·) ∘ g) x =
Comp.mk.{u} (Sum.traverse f <$> Sum.traverse g x) := by
- cases x <;> simp! [Sum.traverse, map_id, functor_norm] <;> rfl
+ cases x <;> (simp! [Sum.traverse, map_id, functor_norm] <;> rfl)
protected theorem traverse_eq_map_id {α β} (f : α → β) (x : σ ⊕ α) :
Sum.traverse ((pure : _ → Id _) ∘ f) x = (pure : _ → Id _) (f <$> x) := by
diff --git a/Mathlib/Control/Traversable/Lemmas.lean b/Mathlib/Control/Traversable/Lemmas.lean
index 25ada54df0f22..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
@@ -56,7 +55,7 @@ def PureTransformation :
theorem pureTransformation_apply {α} (x : id α) : PureTransformation F x = pure x :=
rfl
-variable {F G} (x : t β)
+variable {F G}
-- Porting note: need to specify `m/F/G := Id` because `id` no longer has a `Monad` instance
theorem map_eq_traverse_id : map (f := t) f = traverse (m := Id) (pure ∘ f) :=
diff --git a/Mathlib/Control/ULift.lean b/Mathlib/Control/ULift.lean
index 785d0d187c5d7..2482e0095fe06 100644
--- a/Mathlib/Control/ULift.lean
+++ b/Mathlib/Control/ULift.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Jannis Limperg
+Authors: Kim Morrison, Jannis Limperg
-/
import Mathlib.Init
@@ -78,7 +78,7 @@ end PLift
namespace ULift
-variable {α : Type u} {β : Type v} {f : α → β}
+variable {α : Type u} {β : Type v}
/-- Functorial action. -/
protected def map (f : α → β) (a : ULift.{u'} α) : ULift.{v'} β := ULift.up.{v'} (f a.down)
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/Array/ExtractLemmas.lean b/Mathlib/Data/Array/ExtractLemmas.lean
index bc66fc0660fbc..b27b5245af41d 100644
--- a/Mathlib/Data/Array/ExtractLemmas.lean
+++ b/Mathlib/Data/Array/ExtractLemmas.lean
@@ -27,7 +27,7 @@ theorem extract_append_left {a b : Array α} {i j : Nat} (h : j ≤ a.size) :
· simp only [size_extract, size_append]
omega
· intro h1 h2 h3
- rw [get_extract, get_append_left, get_extract]
+ rw [getElem_extract, getElem_append_left, getElem_extract]
theorem extract_append_right {a b : Array α} {i j : Nat} (h : a.size ≤ i) :
(a ++ b).extract i j = b.extract (i - a.size) (j - a.size) := by
@@ -35,8 +35,8 @@ theorem extract_append_right {a b : Array α} {i j : Nat} (h : a.size ≤ i) :
· rw [size_extract, size_extract, size_append]
omega
· intro k hi h2
- rw [get_extract, get_extract,
- get_append_right (show size a ≤ i + k by omega)]
+ rw [getElem_extract, getElem_extract,
+ getElem_append_right (show size a ≤ i + k by omega)]
congr
omega
@@ -50,6 +50,6 @@ theorem extract_extract {s1 e2 e1 s2 : Nat} {a : Array α} (h : s1 + e2 ≤ e1)
· simp only [size_extract]
omega
· intro i h1 h2
- simp only [get_extract, Nat.add_assoc]
+ simp only [getElem_extract, Nat.add_assoc]
end Array
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/Basic.lean b/Mathlib/Data/Bool/Basic.lean
index 530942959a201..047c5c7807e38 100644
--- a/Mathlib/Data/Bool/Basic.lean
+++ b/Mathlib/Data/Bool/Basic.lean
@@ -3,9 +3,8 @@ Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Jeremy Avigad
-/
-import Batteries.Tactic.Init
+import Mathlib.Logic.Basic
import Mathlib.Logic.Function.Defs
-import Mathlib.Order.Defs
/-!
# Booleans
@@ -228,7 +227,10 @@ theorem ofNat_toNat (b : Bool) : ofNat (toNat b) = b := by
theorem injective_iff {α : Sort*} {f : Bool → α} : Function.Injective f ↔ f false ≠ f true :=
⟨fun Hinj Heq ↦ false_ne_true (Hinj Heq), fun H x y hxy ↦ by
cases x <;> cases y
- exacts [rfl, (H hxy).elim, (H hxy.symm).elim, rfl]⟩
+ · rfl
+ · exact (H hxy).elim
+ · exact (H hxy.symm).elim
+ · rfl⟩
/-- **Kaminski's Equation** -/
theorem apply_apply_apply (f : Bool → Bool) (x : Bool) : f (f (f x)) = f x := by
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 6483469eea3bc..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
@@ -442,6 +442,15 @@ lemma re_ofNat (n : ℕ) [n.AtLeastTwo] : (no_index (OfNat.ofNat n) : ℂ).re =
@[simp, norm_cast] lemma ratCast_re (q : ℚ) : (q : ℂ).re = q := rfl
@[simp, norm_cast] lemma ratCast_im (q : ℚ) : (q : ℂ).im = 0 := rfl
+lemma re_nsmul (n : ℕ) (z : ℂ) : (n • z).re = n • z.re := smul_re ..
+lemma im_nsmul (n : ℕ) (z : ℂ) : (n • z).im = n • z.im := smul_im ..
+lemma re_zsmul (n : ℤ) (z : ℂ) : (n • z).re = n • z.re := smul_re ..
+lemma im_zsmul (n : ℤ) (z : ℂ) : (n • z).im = n • z.im := smul_im ..
+@[simp] lemma re_nnqsmul (q : ℚ≥0) (z : ℂ) : (q • z).re = q • z.re := smul_re ..
+@[simp] lemma im_nnqsmul (q : ℚ≥0) (z : ℂ) : (q • z).im = q • z.im := smul_im ..
+@[simp] lemma re_qsmul (q : ℚ) (z : ℂ) : (q • z).re = q • z.re := smul_re ..
+@[simp] lemma im_qsmul (q : ℚ) (z : ℂ) : (q • z).im = q • z.im := smul_im ..
+
@[deprecated (since := "2024-04-17")]
alias rat_cast_im := ratCast_im
@@ -497,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 =>
@@ -528,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 _
@@ -562,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
@@ -611,22 +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 ofRealHom ..
+
+@[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 ofRealHom _
+
+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 ofRealHom ..
+
+@[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 ofRealHom ..
@[simp]
theorem I_sq : I ^ 2 = -1 := by rw [sq, I_mul_I]
@@ -644,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]
@@ -668,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]
@@ -705,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 43c85d7750bfa..02af83a94a767 100644
--- a/Mathlib/Data/Complex/BigOperators.lean
+++ b/Mathlib/Data/Complex/BigOperators.lean
@@ -3,32 +3,67 @@ Copyright (c) 2017 Kevin Buzzard. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kevin Buzzard, Mario Carneiro
-/
-import Mathlib.Algebra.BigOperators.Group.Finset
+import Mathlib.Algebra.BigOperators.Balance
import Mathlib.Data.Complex.Basic
/-!
# Finite sums and products of complex numbers
-
-/
+open Fintype
+open scoped BigOperators
+
namespace Complex
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 ofRealHom ..
+
+@[simp, norm_cast]
+lemma ofReal_balance [Fintype α] (f : α → ℝ) (a : α) :
+ ((balance f a : ℝ) : ℂ) = balance ((↑) ∘ f) a := by simp [balance]
+
+@[simp] lemma ofReal_comp_balance {ι : Type*} [Fintype ι] (f : ι → ℝ) :
+ ofReal ∘ balance f = balance (ofReal ∘ f : ι → ℂ) := funext <| ofReal_balance _
@[simp]
theorem re_sum (f : α → ℂ) : (∑ i ∈ s, f i).re = ∑ i ∈ s, (f i).re :=
map_sum reAddGroupHom f s
+@[simp]
+lemma re_expect (f : α → ℂ) : (𝔼 i ∈ s, f i).re = 𝔼 i ∈ s, (f i).re :=
+ map_expect (LinearMap.mk reAddGroupHom.toAddHom (by simp)) f s
+
+@[simp]
+lemma re_balance [Fintype α] (f : α → ℂ) (a : α) : re (balance f a) = balance (re ∘ f) a := by
+ simp [balance]
+
+@[simp] lemma re_comp_balance {ι : Type*} [Fintype ι] (f : ι → ℂ) :
+ re ∘ balance f = balance (re ∘ f) := funext <| re_balance _
+
@[simp]
theorem im_sum (f : α → ℂ) : (∑ i ∈ s, f i).im = ∑ i ∈ s, (f i).im :=
map_sum imAddGroupHom f s
+@[simp]
+lemma im_expect (f : α → ℂ) : (𝔼 i ∈ s, f i).im = 𝔼 i ∈ s, (f i).im :=
+ map_expect (LinearMap.mk imAddGroupHom.toAddHom (by simp)) f s
+
+@[simp]
+lemma im_balance [Fintype α] (f : α → ℂ) (a : α) : im (balance f a) = balance (im ∘ f) a := by
+ simp [balance]
+
+@[simp] lemma im_comp_balance {ι : Type*} [Fintype ι] (f : ι → ℂ) :
+ im ∘ balance f = balance (im ∘ f) := funext <| im_balance _
+
end Complex
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 c009cde85a7f2..e5502836c9e2e 100644
--- a/Mathlib/Data/Complex/Exponential.lean
+++ b/Mathlib/Data/Complex/Exponential.lean
@@ -28,7 +28,7 @@ theorem isCauSeq_abs_exp (z : ℂ) :
let ⟨n, hn⟩ := exists_nat_gt (abs z)
have hn0 : (0 : ℝ) < n := lt_of_le_of_lt (abs.nonneg _) hn
IsCauSeq.series_ratio_test n (abs z / n) (div_nonneg (abs.nonneg _) (le_of_lt hn0))
- (by rwa [div_lt_iff hn0, one_mul]) fun m hm => by
+ (by rwa [div_lt_iff₀ hn0, one_mul]) fun m hm => by
rw [abs_abs, abs_abs, Nat.factorial_succ, pow_succ', mul_comm m.succ, Nat.cast_mul, ← div_div,
mul_div_assoc, mul_div_right_comm, map_mul, map_div₀, abs_natCast]
gcongr
@@ -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
+ exact pow_le_one₀ (abs.nonneg _) hx
+ _ = 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
@@ -1334,9 +1332,9 @@ theorem cos_pos_of_le_one {x : ℝ} (hx : |x| ≤ 1) : 0 < cos x :=
(calc
|x| ^ 4 * (5 / 96) + x ^ 2 / 2 ≤ 1 * (5 / 96) + 1 / 2 := by
gcongr
- · exact pow_le_one _ (abs_nonneg _) hx
+ · exact pow_le_one₀ (abs_nonneg _) hx
· rw [sq, ← abs_mul_self, abs_mul]
- exact mul_le_one hx (abs_nonneg _) hx
+ exact mul_le_one₀ hx (abs_nonneg _) hx
_ < 1 := by norm_num)
_ ≤ cos x := sub_le_comm.1 (abs_sub_le_iff.1 (cos_bound hx)).2
@@ -1395,10 +1393,11 @@ 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
+ _ < 1 / (1 - x) := by rw [lt_div_iff₀] <;> nlinarith
theorem exp_bound_div_one_sub_of_interval {x : ℝ} (h1 : 0 ≤ x) (h2 : x < 1) :
Real.exp x ≤ 1 / (1 - x) := by
@@ -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/FiniteDimensional.lean b/Mathlib/Data/Complex/FiniteDimensional.lean
index 5fbde35674c53..f989ee2a1847c 100644
--- a/Mathlib/Data/Complex/FiniteDimensional.lean
+++ b/Mathlib/Data/Complex/FiniteDimensional.lean
@@ -15,12 +15,11 @@ This file contains the `FiniteDimensional ℝ ℂ` instance, as well as some res
(`finrank` and `Module.rank`).
-/
-open FiniteDimensional
+open Module
namespace Complex
-instance : FiniteDimensional ℝ ℂ :=
- of_fintype_basis basisOneI
+instance : FiniteDimensional ℝ ℂ := .of_fintype_basis basisOneI
@[simp]
theorem finrank_real_complex : finrank ℝ ℂ = 2 := by
@@ -50,8 +49,8 @@ theorem rank_real_of_complex (E : Type*) [AddCommGroup E] [Module ℂ E] :
simp only [Cardinal.lift_id']
theorem finrank_real_of_complex (E : Type*) [AddCommGroup E] [Module ℂ E] :
- FiniteDimensional.finrank ℝ E = 2 * FiniteDimensional.finrank ℂ E := by
- rw [← FiniteDimensional.finrank_mul_finrank ℝ ℂ E, Complex.finrank_real_complex]
+ Module.finrank ℝ E = 2 * Module.finrank ℂ E := by
+ rw [← Module.finrank_mul_finrank ℝ ℂ E, Complex.finrank_real_complex]
section Rational
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 f43e1f5666884..9e641fe376939 100644
--- a/Mathlib/Data/Complex/Order.lean
+++ b/Mathlib/Data/Complex/Order.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Data.Complex.Abs
@@ -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/Countable/Small.lean b/Mathlib/Data/Countable/Small.lean
index c41b36c6d5183..72387f0c4a096 100644
--- a/Mathlib/Data/Countable/Small.lean
+++ b/Mathlib/Data/Countable/Small.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.Small.Basic
import Mathlib.Data.Countable.Defs
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 460f8e07408e8..8cb45f7f31389 100644
--- a/Mathlib/Data/DFinsupp/Interval.lean
+++ b/Mathlib/Data/DFinsupp/Interval.lean
@@ -3,7 +3,7 @@ Copyright (c) 2021 Yaël Dillies. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies
-/
-import Mathlib.Data.Finset.Pointwise.Basic
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
import Mathlib.Data.Fintype.BigOperators
import Mathlib.Data.DFinsupp.Order
import Mathlib.Order.Interval.Finset.Basic
@@ -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 db1c8bc2bdd5f..767a61edb7f6b 100644
--- a/Mathlib/Data/DFinsupp/Order.lean
+++ b/Mathlib/Data/DFinsupp/Order.lean
@@ -44,7 +44,14 @@ lemma le_def : f ≤ g ↔ ∀ i, f i ≤ g i := Iff.rfl
def orderEmbeddingToFun : (Π₀ i, α i) ↪o ∀ i, α i where
toFun := DFunLike.coe
inj' := DFunLike.coe_injective
- map_rel_iff' := by rfl
+ map_rel_iff' :=
+ #adaptation_note
+ /--
+ This proof used to be `rfl`,
+ but has been temporarily broken by https://github.com/leanprover/lean4/pull/5329.
+ It can hopefully be restored after https://github.com/leanprover/lean4/pull/5359
+ -/
+ Iff.rfl
@[simp, norm_cast]
lemma coe_orderEmbeddingToFun : ⇑(orderEmbeddingToFun (α := α)) = DFunLike.coe := rfl
@@ -61,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
@@ -134,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 e10cffb7ca8e8..082f7478b3b5e 100644
--- a/Mathlib/Data/DFinsupp/WellFounded.lean
+++ b/Mathlib/Data/DFinsupp/WellFounded.lean
@@ -6,8 +6,8 @@ Authors: Junyan Xu
import Mathlib.Data.DFinsupp.Lex
import Mathlib.Order.GameAdd
import Mathlib.Order.Antisymmetrization
-import Mathlib.SetTheory.Ordinal.Basic
import Mathlib.Tactic.AdaptationNote
+import Mathlib.SetTheory.Cardinal.Basic
/-!
# Well-foundedness of the lexicographic and product orders on `DFinsupp` and `Pi`
@@ -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 e44228f3991d3..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 :=
@@ -711,8 +711,3 @@ def evalENNRealOfNNReal : PositivityExt where eval {u α} _zα _pα e := do
| _, _, _ => throwError "not ENNReal.ofNNReal"
end Mathlib.Meta.Positivity
-
-@[deprecated (since := "2023-12-23")] protected alias
-ENNReal.le_inv_smul_iff_of_pos := le_inv_smul_iff_of_pos
-@[deprecated (since := "2023-12-23")] protected alias
-ENNReal.inv_smul_le_iff_of_pos := inv_smul_le_iff_of_pos
diff --git a/Mathlib/Data/ENNReal/Inv.lean b/Mathlib/Data/ENNReal/Inv.lean
index d0e3217ac181c..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]
@@ -438,14 +441,33 @@ protected theorem half_lt_self (hz : a ≠ 0) (ht : a ≠ ∞) : a / 2 < a := by
protected theorem half_le_self : a / 2 ≤ a :=
le_add_self.trans_eq <| ENNReal.add_halves _
-theorem sub_half (h : a ≠ ∞) : a - a / 2 = a / 2 := by
- lift a to ℝ≥0 using h
- exact sub_eq_of_add_eq (mul_ne_top coe_ne_top <| by simp) (ENNReal.add_halves a)
+theorem sub_half (h : a ≠ ∞) : a - a / 2 = a / 2 := ENNReal.sub_eq_of_eq_add' h a.add_halves.symm
@[simp]
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
@@ -467,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] }
@@ -576,13 +598,13 @@ theorem Ioo_zero_top_eq_iUnion_Ico_zpow {y : ℝ≥0∞} (hy : 1 < y) (h'y : y
theorem zpow_le_of_le {x : ℝ≥0∞} (hx : 1 ≤ x) {a b : ℤ} (h : a ≤ b) : x ^ a ≤ x ^ b := by
induction' a with a a <;> induction' b with b b
· simp only [Int.ofNat_eq_coe, zpow_natCast]
- exact pow_le_pow_right hx (Int.le_of_ofNat_le_ofNat h)
+ exact pow_right_mono₀ hx (Int.le_of_ofNat_le_ofNat h)
· apply absurd h (not_le_of_gt _)
exact lt_of_lt_of_le (Int.negSucc_lt_zero _) (Int.ofNat_nonneg _)
· simp only [zpow_negSucc, Int.ofNat_eq_coe, zpow_natCast]
refine (ENNReal.inv_le_one.2 ?_).trans ?_ <;> exact one_le_pow_of_one_le' hx _
· simp only [zpow_negSucc, ENNReal.inv_le_inv]
- apply pow_le_pow_right hx
+ apply pow_right_mono₀ hx
simpa only [← Int.ofNat_le, neg_le_neg_iff, Int.ofNat_add, Int.ofNat_one, Int.negSucc_eq] using
h
@@ -603,5 +625,258 @@ protected theorem zpow_sub {x : ℝ≥0∞} (x_ne_zero : x ≠ 0) (x_ne_top : x
x ^ (m - n) = (x ^ m) * (x ^ n)⁻¹ := by
rw [sub_eq_add_neg, ENNReal.zpow_add x_ne_zero x_ne_top, ENNReal.zpow_neg x_ne_zero x_ne_top n]
+variable {ι κ : Sort*} {f g : ι → ℝ≥0∞} {s : Set ℝ≥0∞} {a : ℝ≥0∞}
+
+@[simp] lemma iSup_eq_zero : ⨆ i, f i = 0 ↔ ∀ i, f i = 0 := iSup_eq_bot
+
+@[simp] lemma iSup_zero_eq_zero : ⨆ _ : ι, (0 : ℝ≥0∞) = 0 := by simp
+
+lemma iSup_natCast : ⨆ n : ℕ, (n : ℝ≥0∞) = ∞ :=
+ (iSup_eq_top _).2 fun _b hb => ENNReal.exists_nat_gt (lt_top_iff_ne_top.1 hb)
+
+@[simp] lemma iSup_lt_eq_self (a : ℝ≥0∞) : ⨆ b, ⨆ _ : b < a, b = a := by
+ refine le_antisymm (iSup₂_le fun b hb ↦ hb.le) ?_
+ refine le_of_forall_lt fun c hca ↦ ?_
+ obtain ⟨d, hcd, hdb⟩ := exists_between hca
+ exact hcd.trans_le <| le_iSup₂_of_le d hdb le_rfl
+
+lemma isUnit_iff : IsUnit a ↔ a ≠ 0 ∧ a ≠ ∞ := by
+ refine ⟨fun ha ↦ ⟨ha.ne_zero, ?_⟩,
+ fun ha ↦ ⟨⟨a, a⁻¹, ENNReal.mul_inv_cancel ha.1 ha.2, ENNReal.inv_mul_cancel ha.1 ha.2⟩, rfl⟩⟩
+ obtain ⟨u, rfl⟩ := ha
+ rintro hu
+ have := congr($hu * u⁻¹)
+ norm_cast at this
+ simp [mul_inv_cancel] at this
+
+/-- Left multiplication by a nonzero finite `a` as an order isomorphism. -/
+@[simps! toEquiv apply symm_apply]
+def mulLeftOrderIso (a : ℝ≥0∞) (ha : IsUnit a) : ℝ≥0∞ ≃o ℝ≥0∞ where
+ toEquiv := ha.unit.mulLeft
+ map_rel_iff' := by simp [ENNReal.mul_le_mul_left, ha.ne_zero, (isUnit_iff.1 ha).2]
+
+/-- Right multiplication by a nonzero finite `a` as an order isomorphism. -/
+@[simps! toEquiv apply symm_apply]
+def mulRightOrderIso (a : ℝ≥0∞) (ha : IsUnit a) : ℝ≥0∞ ≃o ℝ≥0∞ where
+ toEquiv := ha.unit.mulRight
+ map_rel_iff' := by simp [ENNReal.mul_le_mul_right, ha.ne_zero, (isUnit_iff.1 ha).2]
+
+lemma mul_iSup (a : ℝ≥0∞) (f : ι → ℝ≥0∞) : a * ⨆ i, f i = ⨆ i, a * f i := by
+ by_cases hf : ∀ i, f i = 0
+ · simp [hf]
+ obtain rfl | ha₀ := eq_or_ne a 0
+ · simp
+ obtain rfl | ha := eq_or_ne a ∞
+ · obtain ⟨i, hi⟩ := not_forall.1 hf
+ simpa [iSup_eq_zero.not.2 hf, eq_comm (a := ⊤)] using le_iSup_of_le i (top_mul hi).ge
+ · exact (mulLeftOrderIso _ <| isUnit_iff.2 ⟨ha₀, ha⟩).map_iSup _
+
+lemma iSup_mul (f : ι → ℝ≥0∞) (a : ℝ≥0∞) : (⨆ i, f i) * a = ⨆ i, f i * a := by
+ simp [mul_comm, mul_iSup]
+
+lemma mul_sSup {a : ℝ≥0∞} : a * sSup s = ⨆ b ∈ s, a * b := by
+ simp only [sSup_eq_iSup, mul_iSup]
+
+lemma sSup_mul {a : ℝ≥0∞} : sSup s * a = ⨆ b ∈ s, b * a := by
+ simp only [sSup_eq_iSup, iSup_mul]
+
+lemma iSup_div (f : ι → ℝ≥0∞) (a : ℝ≥0∞) : iSup f / a = ⨆ i, f i / a := iSup_mul ..
+lemma sSup_div (s : Set ℝ≥0∞) (a : ℝ≥0∞) : sSup s / a = ⨆ b ∈ s, b / a := sSup_mul ..
+
+/-- Very general version for distributivity of multiplication over an infimum.
+
+See `ENNReal.mul_iInf_of_ne` for the special case assuming `a ≠ 0` and `a ≠ ∞`, and
+`ENNReal.mul_iInf` for the special case assuming `Nonempty ι`. -/
+lemma mul_iInf' (hinfty : a = ∞ → ⨅ i, f i = 0 → ∃ i, f i = 0) (h₀ : a = 0 → Nonempty ι) :
+ a * ⨅ i, f i = ⨅ i, a * f i := by
+ obtain rfl | ha₀ := eq_or_ne a 0
+ · simp [h₀ rfl]
+ obtain rfl | ha := eq_or_ne a ∞
+ · obtain ⟨i, hi⟩ | hf := em (∃ i, f i = 0)
+ · rw [(iInf_eq_bot _).2, (iInf_eq_bot _).2, bot_eq_zero, mul_zero] <;>
+ exact fun _ _↦ ⟨i, by simpa [hi]⟩
+ · rw [top_mul (mt (hinfty rfl) hf), eq_comm, iInf_eq_top]
+ exact fun i ↦ top_mul fun hi ↦ hf ⟨i, hi⟩
+ · exact (mulLeftOrderIso _ <| isUnit_iff.2 ⟨ha₀, ha⟩).map_iInf _
+
+/-- Very general version for distributivity of multiplication over an infimum.
+
+See `ENNReal.iInf_mul_of_ne` for the special case assuming `a ≠ 0` and `a ≠ ∞`, and
+`ENNReal.iInf_mul` for the special case assuming `Nonempty ι`. -/
+lemma iInf_mul' (hinfty : a = ∞ → ⨅ i, f i = 0 → ∃ i, f i = 0) (h₀ : a = 0 → Nonempty ι) :
+ (⨅ i, f i) * a = ⨅ i, f i * a := by simpa only [mul_comm a] using mul_iInf' hinfty h₀
+
+/-- If `a ≠ 0` and `a ≠ ∞`, then right multiplication by `a` maps infimum to infimum.
+
+See `ENNReal.mul_iInf'` for the general case, and `ENNReal.iInf_mul` for another special case that
+assumes `Nonempty ι` but does not require `a ≠ 0`, and `ENNReal`. -/
+lemma mul_iInf_of_ne (ha₀ : a ≠ 0) (ha : a ≠ ∞) : a * ⨅ i, f i = ⨅ i, a * f i :=
+ mul_iInf' (by simp [ha]) (by simp [ha₀])
+
+/-- If `a ≠ 0` and `a ≠ ∞`, then right multiplication by `a` maps infimum to infimum.
+
+See `ENNReal.iInf_mul'` for the general case, and `ENNReal.iInf_mul` for another special case that
+assumes `Nonempty ι` but does not require `a ≠ 0`. -/
+lemma iInf_mul_of_ne (ha₀ : a ≠ 0) (ha : a ≠ ∞) : (⨅ i, f i) * a = ⨅ i, f i * a :=
+ iInf_mul' (by simp [ha]) (by simp [ha₀])
+
+/-- See `ENNReal.mul_iInf'` for the general case, and `ENNReal.mul_iInf_of_ne` for another special
+case that assumes `a ≠ 0` but does not require `Nonempty ι`. -/
+lemma mul_iInf [Nonempty ι] (hinfty : a = ∞ → ⨅ i, f i = 0 → ∃ i, f i = 0) :
+ a * ⨅ i, f i = ⨅ i, a * f i := mul_iInf' hinfty fun _ ↦ ‹Nonempty ι›
+
+/-- See `ENNReal.iInf_mul'` for the general case, and `ENNReal.iInf_mul_of_ne` for another special
+case that assumes `a ≠ 0` but does not require `Nonempty ι`. -/
+lemma iInf_mul [Nonempty ι] (hinfty : a = ∞ → ⨅ i, f i = 0 → ∃ i, f i = 0) :
+ (⨅ i, f i) * a = ⨅ i, f i * a := iInf_mul' hinfty fun _ ↦ ‹Nonempty ι›
+
+/-- Very general version for distributivity of division over an infimum.
+
+See `ENNReal.iInf_div_of_ne` for the special case assuming `a ≠ 0` and `a ≠ ∞`, and
+`ENNReal.iInf_div` for the special case assuming `Nonempty ι`. -/
+lemma iInf_div' (hinfty : a = 0 → ⨅ i, f i = 0 → ∃ i, f i = 0) (h₀ : a = ∞ → Nonempty ι) :
+ (⨅ i, f i) / a = ⨅ i, f i / a := iInf_mul' (by simpa) (by simpa)
+
+/-- If `a ≠ 0` and `a ≠ ∞`, then division by `a` maps infimum to infimum.
+
+See `ENNReal.iInf_div'` for the general case, and `ENNReal.iInf_div` for another special case that
+assumes `Nonempty ι` but does not require `a ≠ ∞`. -/
+lemma iInf_div_of_ne (ha₀ : a ≠ 0) (ha : a ≠ ∞) : (⨅ i, f i) / a = ⨅ i, f i / a :=
+ iInf_div' (by simp [ha₀]) (by simp [ha])
+
+/-- See `ENNReal.iInf_div'` for the general case, and `ENNReal.iInf_div_of_ne` for another special
+case that assumes `a ≠ ∞` but does not require `Nonempty ι`. -/
+lemma iInf_div [Nonempty ι] (hinfty : a = 0 → ⨅ i, f i = 0 → ∃ i, f i = 0) :
+ (⨅ i, f i) / a = ⨅ i, f i / a := iInf_div' hinfty fun _ ↦ ‹Nonempty ι›
+
+lemma inv_iInf (f : ι → ℝ≥0∞) : (⨅ i, f i)⁻¹ = ⨆ i, (f i)⁻¹ := OrderIso.invENNReal.map_iInf _
+lemma inv_iSup (f : ι → ℝ≥0∞) : (⨆ i, f i)⁻¹ = ⨅ i, (f i)⁻¹ := OrderIso.invENNReal.map_iSup _
+
+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
+ refine le_antisymm ?_ <| iSup_le fun i ↦ add_le_add_left (le_iSup ..) _
+ refine add_le_of_le_tsub_left_of_le (le_iSup_of_le (Classical.arbitrary _) le_self_add) ?_
+ exact iSup_le fun i ↦ ENNReal.le_sub_of_add_le_left ha <| le_iSup (a + f ·) i
+
+lemma iSup_add [Nonempty ι] (f : ι → ℝ≥0∞) : (⨆ i, f i) + a = ⨆ i, f i + a := by
+ simp [add_comm, add_iSup]
+
+lemma add_biSup' {p : ι → Prop} (h : ∃ i, p i) (f : ι → ℝ≥0∞) :
+ a + ⨆ i, ⨆ _ : p i, f i = ⨆ i, ⨆ _ : p i, a + f i := by
+ haveI : Nonempty {i // p i} := nonempty_subtype.2 h
+ simp only [iSup_subtype', add_iSup]
+
+lemma biSup_add' {p : ι → Prop} (h : ∃ i, p i) (f : ι → ℝ≥0∞) :
+ (⨆ i, ⨆ _ : p i, f i) + a = ⨆ i, ⨆ _ : p i, f i + a := by simp only [add_comm, add_biSup' h]
+
+lemma add_biSup {ι : Type*} {s : Set ι} (hs : s.Nonempty) (f : ι → ℝ≥0∞) :
+ a + ⨆ i ∈ s, f i = ⨆ i ∈ s, a + f i := add_biSup' hs _
+
+lemma biSup_add {ι : Type*} {s : Set ι} (hs : s.Nonempty) (f : ι → ℝ≥0∞) :
+ (⨆ i ∈ s, f i) + a = ⨆ i ∈ s, f i + a := biSup_add' hs _
+
+lemma add_sSup (hs : s.Nonempty) : a + sSup s = ⨆ b ∈ s, a + b := by
+ rw [sSup_eq_iSup, add_biSup hs]
+
+lemma sSup_add (hs : s.Nonempty) : sSup s + a = ⨆ b ∈ s, b + a := by
+ rw [sSup_eq_iSup, biSup_add hs]
+
+lemma iSup_add_iSup_le [Nonempty ι] [Nonempty κ] {g : κ → ℝ≥0∞} (h : ∀ i j, f i + g j ≤ a) :
+ iSup f + iSup g ≤ a := by simp_rw [iSup_add, add_iSup]; exact iSup₂_le h
+
+lemma biSup_add_biSup_le' {p : ι → Prop} {q : κ → Prop} (hp : ∃ i, p i) (hq : ∃ j, q j)
+ {g : κ → ℝ≥0∞} (h : ∀ i, p i → ∀ j, q j → f i + g j ≤ a) :
+ (⨆ i, ⨆ _ : p i, f i) + ⨆ j, ⨆ _ : q j, g j ≤ a := by
+ simp_rw [biSup_add' hp, add_biSup' hq]
+ exact iSup₂_le fun i hi => iSup₂_le (h i hi)
+
+lemma biSup_add_biSup_le {ι κ : Type*} {s : Set ι} {t : Set κ} (hs : s.Nonempty) (ht : t.Nonempty)
+ {f : ι → ℝ≥0∞} {g : κ → ℝ≥0∞} {a : ℝ≥0∞} (h : ∀ i ∈ s, ∀ j ∈ t, f i + g j ≤ a) :
+ (⨆ i ∈ s, f i) + ⨆ j ∈ t, g j ≤ a := biSup_add_biSup_le' hs ht h
+
+lemma iSup_add_iSup (h : ∀ i j, ∃ k, f i + g j ≤ f k + g k) : iSup f + iSup g = ⨆ i, f i + g i := by
+ cases isEmpty_or_nonempty ι
+ · simp only [iSup_of_empty, bot_eq_zero, zero_add]
+ · refine le_antisymm ?_ (iSup_le fun a => add_le_add (le_iSup _ _) (le_iSup _ _))
+ refine iSup_add_iSup_le fun i j => ?_
+ rcases h i j with ⟨k, hk⟩
+ exact le_iSup_of_le k hk
+
+lemma iSup_add_iSup_of_monotone {ι : Type*} [Preorder ι] [IsDirected ι (· ≤ ·)] {f g : ι → ℝ≥0∞}
+ (hf : Monotone f) (hg : Monotone g) : iSup f + iSup g = ⨆ a, f a + g a :=
+ iSup_add_iSup fun i j ↦ (exists_ge_ge i j).imp fun _k ⟨hi, hj⟩ ↦ by gcongr <;> apply_rules
+
+lemma finsetSum_iSup {α ι : Type*} {s : Finset α} {f : α → ι → ℝ≥0∞}
+ (hf : ∀ i j, ∃ k, ∀ a, f a i ≤ f a k ∧ f a j ≤ f a k) :
+ ∑ a ∈ s, ⨆ i, f a i = ⨆ i, ∑ a ∈ s, f a i := by
+ induction' s using Finset.cons_induction with a s ha ihs
+ · simp
+ simp_rw [Finset.sum_cons, ihs]
+ refine iSup_add_iSup fun i j ↦ (hf i j).imp fun k hk ↦ ?_
+ gcongr
+ exacts [(hk a).1, (hk _).2]
+
+lemma finsetSum_iSup_of_monotone {α ι : Type*} [Preorder ι] [IsDirected ι (· ≤ ·)] {s : Finset α}
+ {f : α → ι → ℝ≥0∞} (hf : ∀ a, Monotone (f a)) : (∑ a ∈ s, iSup (f a)) = ⨆ n, ∑ a ∈ s, f a n :=
+ finsetSum_iSup fun i j ↦ (exists_ge_ge i j).imp fun _k ⟨hi, hj⟩ a ↦ ⟨hf a hi, hf a hj⟩
+
+@[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]
+
+lemma smul_sSup {R} [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] (s : Set ℝ≥0∞) (c : R) :
+ c • sSup s = ⨆ a ∈ s, c • a := by
+ simp_rw [← smul_one_mul c (sSup s), ENNReal.mul_sSup, smul_one_mul]
+
+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, 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) <|
+ add_le_of_le_tsub_right_of_le (iInf_le_of_le (Classical.arbitrary _) tsub_le_self) <|
+ iSup_le fun i ↦ ?_
+ rw [← sub_sub_cancel ha (h _)]
+ exact tsub_le_tsub_left (iInf_le (a - f ·) i) _
+
+-- TODO: Prove the two one-side versions
+lemma exists_lt_add_of_lt_add {x y z : ℝ≥0∞} (h : x < y + z) (hy : y ≠ 0) (hz : z ≠ 0) :
+ ∃ y' < y, ∃ z' < z, x < y' + z' := by
+ contrapose! h;
+ simpa using biSup_add_biSup_le' (by exact ⟨0, hy.bot_lt⟩) (by exact ⟨0, hz.bot_lt⟩) h
+
end Inv
end ENNReal
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 9f0b1dbbbddc3..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
@@ -256,6 +263,7 @@ section Cancel
-- Porting note (#11215): TODO: generalize to `WithTop`
/-- An element `a` is `AddLECancellable` if `a + b ≤ a + c` implies `b ≤ c` for all `b` and `c`.
This is true in `ℝ≥0∞` for all elements except `∞`. -/
+@[simp]
theorem addLECancellable_iff_ne {a : ℝ≥0∞} : AddLECancellable a ↔ a ≠ ∞ := by
constructor
· rintro h rfl
@@ -294,17 +302,21 @@ theorem sub_eq_sInf {a b : ℝ≥0∞} : a - b = sInf { d | a ≤ d + b } :=
le_antisymm (le_sInf fun _ h => tsub_le_iff_right.mpr h) <| sInf_le <| mem_setOf.2 le_tsub_add
/-- This is a special case of `WithTop.coe_sub` in the `ENNReal` namespace -/
-@[simp] theorem coe_sub : (↑(r - p) : ℝ≥0∞) = ↑r - ↑p := WithTop.coe_sub
+@[simp, norm_cast] theorem coe_sub : (↑(r - p) : ℝ≥0∞) = ↑r - ↑p := WithTop.coe_sub
/-- This is a special case of `WithTop.top_sub_coe` in the `ENNReal` namespace -/
@[simp] theorem top_sub_coe : ∞ - ↑r = ∞ := WithTop.top_sub_coe
+@[simp] lemma top_sub (ha : a ≠ ∞) : ∞ - a = ∞ := by lift a to ℝ≥0 using ha; exact top_sub_coe
+
/-- This is a special case of `WithTop.sub_top` in the `ENNReal` namespace -/
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]
@@ -314,15 +326,37 @@ theorem natCast_sub (m n : ℕ) : ↑(m - n) = (m - n : ℝ≥0∞) := by
@[deprecated (since := "2024-04-17")]
alias nat_cast_sub := natCast_sub
+/-- See `ENNReal.sub_eq_of_eq_add'` for a version assuming that `a = c + b` itself is finite rather
+than `b`. -/
protected theorem sub_eq_of_eq_add (hb : b ≠ ∞) : a = c + b → a - b = c :=
(cancel_of_ne hb).tsub_eq_of_eq_add
+/-- Weaker version of `ENNReal.sub_eq_of_eq_add` assuming that `a = c + b` itself is finite rather
+han `b`. -/
+protected lemma sub_eq_of_eq_add' (ha : a ≠ ∞) : a = c + b → a - b = c :=
+ (cancel_of_ne ha).tsub_eq_of_eq_add'
+
+/-- See `ENNReal.eq_sub_of_add_eq'` for a version assuming that `b = a + c` itself is finite rather
+than `c`. -/
protected theorem eq_sub_of_add_eq (hc : c ≠ ∞) : a + c = b → a = b - c :=
(cancel_of_ne hc).eq_tsub_of_add_eq
+/-- Weaker version of `ENNReal.eq_sub_of_add_eq` assuming that `b = a + c` itself is finite rather
+than `c`. -/
+protected lemma eq_sub_of_add_eq' (hb : b ≠ ∞) : a + c = b → a = b - c :=
+ (cancel_of_ne hb).eq_tsub_of_add_eq'
+
+/-- See `ENNReal.sub_eq_of_eq_add_rev'` for a version assuming that `a = b + c` itself is finite
+rather than `b`. -/
protected theorem sub_eq_of_eq_add_rev (hb : b ≠ ∞) : a = b + c → a - b = c :=
(cancel_of_ne hb).tsub_eq_of_eq_add_rev
+/-- Weaker version of `ENNReal.sub_eq_of_eq_add_rev` assuming that `a = b + c` itself is finite
+rather than `b`. -/
+protected lemma sub_eq_of_eq_add_rev' (ha : a ≠ ∞) : a = b + c → a - b = c :=
+ (cancel_of_ne ha).tsub_eq_of_eq_add_rev'
+
+@[deprecated ENNReal.sub_eq_of_eq_add (since := "2024-09-30")]
theorem sub_eq_of_add_eq (hb : b ≠ ∞) (hc : a + b = c) : c - b = a :=
ENNReal.sub_eq_of_eq_add hb hc.symm
@@ -338,7 +372,7 @@ protected theorem sub_add_eq_add_sub (hab : b ≤ a) (b_ne_top : b ≠ ∞) :
a - b + c = a + c - b := by
by_cases c_top : c = ∞
· simpa [c_top] using ENNReal.eq_sub_of_add_eq b_ne_top rfl
- refine (sub_eq_of_add_eq b_ne_top ?_).symm
+ refine ENNReal.eq_sub_of_add_eq b_ne_top ?_
simp only [add_assoc, add_comm c b]
simpa only [← add_assoc] using (add_left_inj c_top).mpr <| tsub_add_cancel_of_le hab
@@ -380,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 4b6df926ef130..bccf679b634a5 100644
--- a/Mathlib/Data/ENNReal/Real.lean
+++ b/Mathlib/Data/ENNReal/Real.lean
@@ -235,7 +235,7 @@ lemma ofNat_le_ofReal {n : ℕ} [n.AtLeastTwo] {p : ℝ} :
no_index (OfNat.ofNat n) ≤ ENNReal.ofReal p ↔ OfNat.ofNat n ≤ p :=
natCast_le_ofReal (NeZero.ne n)
-@[simp]
+@[simp, norm_cast]
lemma ofReal_le_natCast {r : ℝ} {n : ℕ} : ENNReal.ofReal r ≤ n ↔ r ≤ n :=
coe_le_coe.trans Real.toNNReal_le_natCast
@@ -508,6 +508,19 @@ theorem toReal_sSup (s : Set ℝ≥0∞) (hf : ∀ r ∈ s, r ≠ ∞) :
(sSup s).toReal = sSup (ENNReal.toReal '' s) := by
simp only [ENNReal.toReal, toNNReal_sSup s hf, NNReal.coe_sSup, Set.image_image]
+@[simp] lemma ofReal_iInf [Nonempty ι] (f : ι → ℝ) :
+ ENNReal.ofReal (⨅ i, f i) = ⨅ i, ENNReal.ofReal (f i) := by
+ obtain ⟨i, hi⟩ | h := em (∃ i, f i ≤ 0)
+ · rw [(iInf_eq_bot _).2 fun _ _ ↦ ⟨i, by simpa [ofReal_of_nonpos hi]⟩]
+ simp [Real.iInf_nonpos' ⟨i, hi⟩]
+ replace h i : 0 ≤ f i := le_of_not_le fun hi ↦ h ⟨i, hi⟩
+ refine eq_of_forall_le_iff fun a ↦ ?_
+ obtain rfl | ha := eq_or_ne a ∞
+ · simp
+ rw [le_iInf_iff, le_ofReal_iff_toReal_le ha, le_ciInf_iff ⟨0, by simpa [mem_lowerBounds]⟩]
+ · exact forall_congr' fun i ↦ (le_ofReal_iff_toReal_le ha (h _)).symm
+ · exact Real.iInf_nonneg h
+
theorem iInf_add : iInf f + a = ⨅ i, f i + a :=
le_antisymm (le_iInf fun _ => add_le_add (iInf_le _ _) <| le_rfl)
(tsub_le_iff_right.1 <| le_iInf fun _ => tsub_le_iff_right.2 <| iInf_le _ _)
@@ -528,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
@@ -545,51 +558,12 @@ theorem iInf_sum {α : Type*} {f : ι → α → ℝ≥0∞} {s : Finset α} [No
rw [Finset.forall_mem_cons] at hk
exact add_le_add hk.1.1 (Finset.sum_le_sum fun a ha => (hk.2 a ha).2)
-/-- If `x ≠ 0` and `x ≠ ∞`, then right multiplication by `x` maps infimum to infimum.
-See also `ENNReal.iInf_mul` that assumes `[Nonempty ι]` but does not require `x ≠ 0`. -/
-theorem iInf_mul_of_ne {ι} {f : ι → ℝ≥0∞} {x : ℝ≥0∞} (h0 : x ≠ 0) (h : x ≠ ∞) :
- iInf f * x = ⨅ i, f i * x :=
- le_antisymm mul_right_mono.map_iInf_le
- ((ENNReal.div_le_iff_le_mul (Or.inl h0) <| Or.inl h).mp <|
- le_iInf fun _ => (ENNReal.div_le_iff_le_mul (Or.inl h0) <| Or.inl h).mpr <| iInf_le _ _)
-
-/-- If `x ≠ ∞`, then right multiplication by `x` maps infimum over a nonempty type to infimum. See
-also `ENNReal.iInf_mul_of_ne` that assumes `x ≠ 0` but does not require `[Nonempty ι]`. -/
-theorem iInf_mul {ι} [Nonempty ι] {f : ι → ℝ≥0∞} {x : ℝ≥0∞} (h : x ≠ ∞) :
- iInf f * x = ⨅ i, f i * x := by
- by_cases h0 : x = 0
- · simp only [h0, mul_zero, iInf_const]
- · exact iInf_mul_of_ne h0 h
-
-/-- If `x ≠ ∞`, then left multiplication by `x` maps infimum over a nonempty type to infimum. See
-also `ENNReal.mul_iInf_of_ne` that assumes `x ≠ 0` but does not require `[Nonempty ι]`. -/
-theorem mul_iInf {ι} [Nonempty ι] {f : ι → ℝ≥0∞} {x : ℝ≥0∞} (h : x ≠ ∞) :
- x * iInf f = ⨅ i, x * f i := by simpa only [mul_comm] using iInf_mul h
-
-/-- If `x ≠ 0` and `x ≠ ∞`, then left multiplication by `x` maps infimum to infimum.
-See also `ENNReal.mul_iInf` that assumes `[Nonempty ι]` but does not require `x ≠ 0`. -/
-theorem mul_iInf_of_ne {ι} {f : ι → ℝ≥0∞} {x : ℝ≥0∞} (h0 : x ≠ 0) (h : x ≠ ∞) :
- x * iInf f = ⨅ i, x * f i := by simpa only [mul_comm] using iInf_mul_of_ne h0 h
-
-/-! `supr_mul`, `mul_supr` and variants are in `Topology.Instances.ENNReal`. -/
-
end iInf
section iSup
-
-@[simp]
-theorem iSup_eq_zero {ι : Sort*} {f : ι → ℝ≥0∞} : ⨆ i, f i = 0 ↔ ∀ i, f i = 0 :=
- iSup_eq_bot
-
-@[simp]
-theorem iSup_zero_eq_zero {ι : Sort*} : ⨆ _ : ι, (0 : ℝ≥0∞) = 0 := by simp
-
theorem sup_eq_zero {a b : ℝ≥0∞} : a ⊔ b = 0 ↔ a = 0 ∧ b = 0 :=
sup_eq_bot_iff
-theorem iSup_natCast : ⨆ n : ℕ, (n : ℝ≥0∞) = ∞ :=
- (iSup_eq_top _).2 fun _b hb => ENNReal.exists_nat_gt (lt_top_iff_ne_top.1 hb)
-
@[deprecated (since := "2024-04-05")] alias iSup_coe_nat := iSup_natCast
end iSup
diff --git a/Mathlib/Data/ENat/Basic.lean b/Mathlib/Data/ENat/Basic.lean
index f3f8caf0ecd44..83c5cd47708c2 100644
--- a/Mathlib/Data/ENat/Basic.lean
+++ b/Mathlib/Data/ENat/Basic.lean
@@ -45,20 +45,15 @@ instance : WellFoundedLT ℕ∞ := inferInstanceAs (WellFoundedLT (WithTop ℕ))
instance : CharZero ℕ∞ := inferInstanceAs (CharZero (WithTop ℕ))
instance : IsWellOrder ℕ∞ (· < ·) where
-instance : SuccAddOrder ℕ∞ := by
- constructor
- rintro (_ | _)
- · rfl
- · change ite .. = _
- simp
- rfl
-
variable {m n : ℕ∞}
/-- Lemmas about `WithTop` expect (and can output) `WithTop.some` but the normal form for coercion
`ℕ → ℕ∞` is `Nat.cast`. -/
@[simp] theorem some_eq_coe : (WithTop.some : ℕ → ℕ∞) = Nat.cast := rfl
+instance : SuccAddOrder ℕ∞ where
+ succ_eq_add_one x := by cases x <;> simp [SuccOrder.succ]
+
-- Porting note: `simp` and `norm_cast` can prove it
--@[simp, norm_cast]
theorem coe_zero : ((0 : ℕ) : ℕ∞) = 0 :=
@@ -180,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
@@ -264,4 +262,35 @@ theorem nat_induction {P : ℕ∞ → Prop} (a : ℕ∞) (h0 : P 0) (hsuc : ∀
· exact htop A
· exact A _
+lemma add_one_nat_le_withTop_of_lt {m : ℕ} {n : WithTop ℕ∞} (h : m < n) : (m + 1 : ℕ) ≤ n := by
+ match n with
+ | ⊤ => exact le_top
+ | (⊤ : ℕ∞) => exact WithTop.coe_le_coe.2 (OrderTop.le_top _)
+ | (n : ℕ) => simpa only [Nat.cast_le, ge_iff_le, Nat.cast_lt] using h
+
+@[simp] lemma coe_top_add_one : ((⊤ : ℕ∞) : WithTop ℕ∞) + 1 = (⊤ : ℕ∞) := rfl
+
+@[simp] lemma add_one_eq_coe_top_iff (n : WithTop ℕ∞) :
+ n + 1 = (⊤ : ℕ∞) ↔ n = (⊤ : ℕ∞) := by
+ match n with
+ | ⊤ => exact Iff.rfl
+ | (⊤ : ℕ∞) => exact Iff.rfl
+ | (n : ℕ) => norm_cast; simp only [coe_ne_top, iff_false, ne_eq]
+
+@[simp] lemma nat_ne_coe_top (n : ℕ) : (n : WithTop ℕ∞) ≠ (⊤ : ℕ∞) := ne_of_beq_false rfl
+
+lemma one_le_iff_ne_zero_withTop {n : WithTop ℕ∞} :
+ 1 ≤ n ↔ n ≠ 0 :=
+ ⟨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 aede754a4bba3..95384eac7bdcf 100644
--- a/Mathlib/Data/Fin/Basic.lean
+++ b/Mathlib/Data/Fin/Basic.lean
@@ -5,9 +5,11 @@ Authors: Robert Y. Lewis, Keeley Hoek
-/
import Mathlib.Algebra.NeZero
import Mathlib.Data.Nat.Defs
+import Mathlib.Data.Int.DivMod
import Mathlib.Logic.Embedding.Basic
import Mathlib.Logic.Equiv.Set
import Mathlib.Tactic.Common
+import Mathlib.Tactic.Attr.Register
/-!
# The finite type with `n` elements
@@ -169,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,
@@ -179,8 +181,10 @@ 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`. -/
protected theorem heq_ext_iff {k l : ℕ} (h : k = l) {i : Fin k} {j : Fin l} :
HEq i j ↔ (i : ℕ) = (j : ℕ) := by
subst h
@@ -188,6 +192,7 @@ protected theorem heq_ext_iff {k l : ℕ} (h : k = l) {i : Fin k} {j : Fin l} :
end coe
+
section Order
/-!
@@ -207,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. -/
@@ -237,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.
@@ -270,6 +271,12 @@ theorem pos_iff_ne_zero' [NeZero n] (a : Fin n) : 0 < a ↔ a ≠ 0 := by
@[simp] lemma cast_eq_self (a : Fin n) : cast rfl a = a := rfl
+@[simp] theorem cast_eq_zero {k l : ℕ} [NeZero k] [NeZero l]
+ (h : k = l) (x : Fin k) : Fin.cast h x = 0 ↔ x = 0 := by simp [← val_eq_val]
+
+lemma cast_injective {k l : ℕ} (h : k = l) : Injective (Fin.cast h) :=
+ fun a b hab ↦ by simpa [← val_eq_val] using hab
+
theorem rev_involutive : Involutive (rev : Fin n → Fin n) := rev_rev
/-- `Fin.rev` as an `Equiv.Perm`, the antitone involution `Fin n → Fin n` given by
@@ -324,6 +331,58 @@ theorem one_lt_last [NeZero n] : 1 < last (n + 1) := by
end Order
+/-! ### Coercions to `ℤ` and the `fin_omega` tactic. -/
+
+open Int
+
+theorem coe_int_sub_eq_ite {n : Nat} (u v : Fin n) :
+ ((u - v : Fin n) : Int) = if v ≤ u then (u - v : Int) else (u - v : Int) + n := by
+ rw [Fin.sub_def]
+ split
+ · rw [ofNat_emod, Int.emod_eq_sub_self_emod, Int.emod_eq_of_lt] <;> omega
+ · rw [ofNat_emod, Int.emod_eq_of_lt] <;> omega
+
+theorem coe_int_sub_eq_mod {n : Nat} (u v : Fin n) :
+ ((u - v : Fin n) : Int) = ((u : Int) - (v : Int)) % n := by
+ rw [coe_int_sub_eq_ite]
+ split
+ · rw [Int.emod_eq_of_lt] <;> omega
+ · rw [Int.emod_eq_add_self_emod, Int.emod_eq_of_lt] <;> omega
+
+theorem coe_int_add_eq_ite {n : Nat} (u v : Fin n) :
+ ((u + v : Fin n) : Int) = if (u + v : ℕ) < n then (u + v : Int) else (u + v : Int) - n := by
+ rw [Fin.add_def]
+ split
+ · rw [ofNat_emod, Int.emod_eq_of_lt] <;> omega
+ · rw [ofNat_emod, Int.emod_eq_sub_self_emod, Int.emod_eq_of_lt] <;> omega
+
+theorem coe_int_add_eq_mod {n : Nat} (u v : Fin n) :
+ ((u + v : Fin n) : Int) = ((u : Int) + (v : Int)) % n := by
+ rw [coe_int_add_eq_ite]
+ split
+ · rw [Int.emod_eq_of_lt] <;> omega
+ · rw [Int.emod_eq_sub_self_emod, Int.emod_eq_of_lt] <;> omega
+
+-- Write `a + b` as `if (a + b : ℕ) < n then (a + b : ℤ) else (a + b : ℤ) - n` and
+-- similarly `a - b` as `if (b : ℕ) ≤ a then (a - b : ℤ) else (a - b : ℤ) + n`.
+attribute [fin_omega] coe_int_sub_eq_ite coe_int_add_eq_ite
+
+-- Rewrite inequalities in `Fin` to inequalities in `ℕ`
+attribute [fin_omega] Fin.lt_iff_val_lt_val Fin.le_iff_val_le_val
+
+-- Rewrite `1 : Fin (n + 2)` to `1 : ℤ`
+attribute [fin_omega] val_one
+
+/--
+Preprocessor for `omega` to handle inequalities in `Fin`.
+Note that this involves a lot of case splitting, so may be slow.
+-/
+-- Further adjustment to the simp set can probably make this more powerful.
+-- Please experiment and PR updates!
+macro "fin_omega" : tactic => `(tactic|
+ { try simp only [fin_omega, ← Int.ofNat_lt, ← Int.ofNat_le] at *
+ omega })
+
section Add
/-!
@@ -347,20 +406,9 @@ 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)]
--- Porting note (#10618): removing `simp`, `simp` can prove it with AddCommMonoid instance
-protected theorem zero_add [NeZero n] (k : Fin n) : 0 + k = k := by
- simp [Fin.ext_iff, add_def, mod_eq_of_lt (is_lt k)]
-
-instance {a : ℕ} [NeZero n] : OfNat (Fin n) a where
- ofNat := Fin.ofNat' a n.pos_of_neZero
-
-instance inhabited (n : ℕ) [NeZero n] : Inhabited (Fin n) :=
- ⟨0⟩
-
instance inhabitedFinOneAdd (n : ℕ) : Inhabited (Fin (1 + n)) :=
haveI : NeZero (1 + n) := by rw [Nat.add_comm]; infer_instance
inferInstance
@@ -369,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 {h : 0 < n} [NeZero n] : (Fin.ofNat' 0 h : Fin n) = 0 := rfl
-@[simp] lemma ofNat'_one {h : 0 < n} [NeZero n] : (Fin.ofNat' 1 h : Fin n) = 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
@@ -389,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
@@ -415,7 +460,8 @@ in the same value. -/
-- Porting note: this is syntactically the same as `cast_val_of_lt`
-@[simp] lemma natCast_self (n : ℕ) [NeZero n] : (n : Fin n) = 0 := by ext; simp
+-- This is a special case of `CharP.cast_eq_zero` that doesn't require typeclass search
+@[simp high] lemma natCast_self (n : ℕ) [NeZero n] : (n : Fin n) = 0 := by ext; simp
@[deprecated (since := "2024-04-17")]
alias nat_cast_self := natCast_self
@@ -452,13 +498,6 @@ lemma natCast_strictMono (hbn : b ≤ n) (hab : a < b) : (a : Fin (n + 1)) < b :
end OfNatCoe
-@[simp]
-theorem one_eq_zero_iff [NeZero n] : (1 : Fin n) = 0 ↔ n = 1 := by
- obtain _ | _ | n := n <;> simp [Fin.ext_iff]
-
-@[simp]
-theorem zero_eq_one_iff [NeZero n] : (0 : Fin n) = 1 ↔ n = 1 := by rw [eq_comm, one_eq_zero_iff]
-
end Add
section Succ
@@ -514,10 +553,6 @@ This one instead uses a `NeZero n` typeclass hypothesis.
theorem le_zero_iff' {n : ℕ} [NeZero n] {k : Fin n} : k ≤ 0 ↔ k = 0 :=
⟨fun h => Fin.ext <| by rw [Nat.eq_zero_of_le_zero h]; rfl, by rintro rfl; exact Nat.le_refl _⟩
--- Move to Batteries?
-@[simp] theorem cast_refl {n : Nat} (h : n = n) :
- Fin.cast h = id := rfl
-
-- TODO: Move to Batteries
@[simp] lemma castLE_inj {hmn : m ≤ n} {a b : Fin m} : castLE hmn a = castLE hmn b ↔ a = b := by
simp [Fin.ext_iff]
@@ -588,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
@@ -637,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}
@@ -711,7 +750,7 @@ theorem castSucc_ne_zero_of_lt {p i : Fin n} (h : p < i) : castSucc i ≠ 0 := b
exact ((zero_le _).trans_lt h).ne'
theorem succ_ne_last_iff (a : Fin (n + 1)) : succ a ≠ last (n + 1) ↔ a ≠ last n :=
- not_iff_not.mpr <| succ_eq_last_succ a
+ not_iff_not.mpr <| succ_eq_last_succ
theorem succ_ne_last_of_lt {p i : Fin n} (h : i < p) : succ i ≠ last n := by
cases n
@@ -774,7 +813,7 @@ theorem le_pred_iff {j : Fin n} {i : Fin (n + 1)} (hi : i ≠ 0) : j ≤ pred i
rw [← succ_le_succ_iff, succ_pred]
theorem castSucc_pred_eq_pred_castSucc {a : Fin (n + 1)} (ha : a ≠ 0)
- (ha' := a.castSucc_ne_zero_iff.mpr ha) :
+ (ha' := castSucc_ne_zero_iff.mpr ha) :
(a.pred ha).castSucc = (castSucc a).pred ha' := rfl
theorem castSucc_pred_add_one_eq {a : Fin (n + 1)} (ha : a ≠ 0) :
@@ -1427,12 +1466,11 @@ theorem eq_zero (n : Fin 1) : n = 0 := Subsingleton.elim _ _
instance uniqueFinOne : Unique (Fin 1) where
uniq _ := Subsingleton.elim _ _
-@[simp]
+@[deprecated val_eq_zero (since := "2024-09-18")]
theorem coe_fin_one (a : Fin 1) : (a : ℕ) = 0 := by simp [Subsingleton.elim a 0]
-lemma eq_one_of_neq_zero (i : Fin 2) (hi : i ≠ 0) : i = 1 :=
- fin_two_eq_of_eq_zero_iff
- (by simpa only [one_eq_zero_iff, succ.injEq, iff_false, reduceCtorEq] using hi)
+lemma eq_one_of_neq_zero (i : Fin 2) (hi : i ≠ 0) : i = 1 := by
+ fin_omega
@[simp]
theorem coe_neg_one : ↑(-1 : Fin (n + 1)) = n := by
@@ -1445,15 +1483,7 @@ theorem last_sub (i : Fin (n + 1)) : last n - i = Fin.rev i :=
Fin.ext <| by rw [coe_sub_iff_le.2 i.le_last, val_last, val_rev, Nat.succ_sub_succ_eq_sub]
theorem add_one_le_of_lt {n : ℕ} {a b : Fin (n + 1)} (h : a < b) : a + 1 ≤ b := by
- cases' a with a ha
- cases' b with b hb
- cases n
- · simp only [Nat.zero_add, Nat.lt_one_iff] at ha hb
- simp [ha, hb]
- simp only [le_iff_val_le_val, val_add, lt_iff_val_lt_val, val_mk, val_one] at h ⊢
- rwa [Nat.mod_eq_of_lt, Nat.succ_le_iff]
- rw [Nat.succ_lt_succ_iff]
- exact h.trans_le (Nat.le_of_lt_succ hb)
+ cases n <;> fin_omega
theorem exists_eq_add_of_le {n : ℕ} {a b : Fin n} (h : a ≤ b) : ∃ k ≤ b, b = a + k := by
obtain ⟨k, hk⟩ : ∃ k : ℕ, (b : ℕ) = a + k := Nat.exists_eq_add_of_le h
@@ -1464,28 +1494,32 @@ theorem exists_eq_add_of_le {n : ℕ} {a b : Fin n} (h : a ≤ b) : ∃ k ≤ b,
theorem exists_eq_add_of_lt {n : ℕ} {a b : Fin (n + 1)} (h : a < b) :
∃ k < b, k + 1 ≤ b ∧ b = a + k + 1 := by
cases n
- · cases' a with a ha
- cases' b with b hb
- simp only [Nat.zero_add, Nat.lt_one_iff] at ha hb
- simp [ha, hb] at h
+ · omega
obtain ⟨k, hk⟩ : ∃ k : ℕ, (b : ℕ) = a + k + 1 := Nat.exists_eq_add_of_lt h
have hkb : k < b := by omega
- refine ⟨⟨k, hkb.trans b.is_lt⟩, hkb, ?_, ?_⟩
- · rw [Fin.le_iff_val_le_val, Fin.val_add_one]
- split_ifs <;> simp [Nat.succ_le_iff, hkb]
+ refine ⟨⟨k, hkb.trans b.is_lt⟩, hkb, by fin_omega, ?_⟩
simp [Fin.ext_iff, Fin.val_add, ← hk, Nat.mod_eq_of_lt b.is_lt]
lemma pos_of_ne_zero {n : ℕ} {a : Fin (n + 1)} (h : a ≠ 0) :
0 < a :=
Nat.pos_of_ne_zero (val_ne_of_ne h)
+lemma sub_succ_le_sub_of_le {n : ℕ} {u v : Fin (n + 2)} (h : u < v) : v - (u + 1) < v - u := by
+ fin_omega
+
end AddGroup
@[simp]
-theorem coe_ofNat_eq_mod (m n : ℕ) [NeZero m] :
+theorem coe_natCast_eq_mod (m n : ℕ) [NeZero m] :
((n : Fin m) : ℕ) = n % m :=
rfl
+-- See note [no_index around OfNat.ofNat]
+@[simp]
+theorem coe_ofNat_eq_mod (m n : ℕ) [NeZero m] :
+ ((no_index OfNat.ofNat n : Fin m) : ℕ) = OfNat.ofNat n % m :=
+ rfl
+
section Mul
/-!
@@ -1509,16 +1543,6 @@ protected theorem zero_mul' [NeZero n] (k : Fin n) : (0 : Fin n) * k = 0 := by
end Mul
-open Qq in
-instance toExpr (n : ℕ) : Lean.ToExpr (Fin n) where
- toTypeExpr := q(Fin $n)
- toExpr := match n with
- | 0 => finZeroElim
- | k + 1 => fun i => show Q(Fin $n) from
- have i : Q(Nat) := Lean.mkRawNatLit i -- raw literal to avoid ofNat-double-wrapping
- have : Q(NeZero $n) := haveI : $n =Q $k + 1 := ⟨⟩; by exact q(NeZero.succ)
- q(OfNat.ofNat $i)
-
end Fin
set_option linter.style.longFile 1700
diff --git a/Mathlib/Data/Fin/Tuple/Basic.lean b/Mathlib/Data/Fin/Tuple/Basic.lean
index 0f9f303f592bb..81cd43b8a59f1 100644
--- a/Mathlib/Data/Fin/Tuple/Basic.lean
+++ b/Mathlib/Data/Fin/Tuple/Basic.lean
@@ -93,13 +93,13 @@ example (α : Fin 0 → Sort u) : Unique (∀ i : Fin 0, α i) := by infer_insta
theorem tuple0_le {α : Fin 0 → Type*} [∀ i, Preorder (α i)] (f g : ∀ i, α i) : f ≤ g :=
finZeroElim
-variable {α : Fin (n + 1) → Type u} (x : α 0) (q : ∀ i, α i) (p : ∀ i : Fin n, α i.succ) (i : Fin n)
+variable {α : Fin (n + 1) → Sort u} (x : α 0) (q : ∀ i, α i) (p : ∀ i : Fin n, α i.succ) (i : Fin n)
(y : α i.succ) (z : α 0)
/-- The tail of an `n+1` tuple, i.e., its last `n` entries. -/
def tail (q : ∀ i, α i) : ∀ i : Fin n, α i.succ := fun i ↦ q i.succ
-theorem tail_def {n : ℕ} {α : Fin (n + 1) → Type*} {q : ∀ i, α i} :
+theorem tail_def {n : ℕ} {α : Fin (n + 1) → Sort*} {q : ∀ i, α i} :
(tail fun k : Fin (n + 1) ↦ q k) = fun k : Fin n ↦ q k.succ :=
rfl
@@ -117,7 +117,7 @@ theorem cons_succ : cons x p i.succ = p i := by simp [cons]
theorem cons_zero : cons x p 0 = x := by simp [cons]
@[simp]
-theorem cons_one {α : Fin (n + 2) → Type*} (x : α 0) (p : ∀ i : Fin n.succ, α i.succ) :
+theorem cons_one {α : Fin (n + 2) → Sort*} (x : α 0) (p : ∀ i : Fin n.succ, α i.succ) :
cons x p 1 = p 0 := by
rw [← cons_succ x p]; rfl
@@ -192,10 +192,10 @@ theorem consCases_cons {P : (∀ i : Fin n.succ, α i) → Sort v} (h : ∀ x₀
/-- Recurse on a tuple by splitting into `Fin.elim0` and `Fin.cons`. -/
@[elab_as_elim]
-def consInduction {α : Type*} {P : ∀ {n : ℕ}, (Fin n → α) → Sort v} (h0 : P Fin.elim0)
+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
@@ -254,7 +254,7 @@ theorem tail_update_succ : tail (update q i.succ y) = update (tail q) i y := by
simp [tail]
· simp [tail, (Fin.succ_injective n).ne h, h]
-theorem comp_cons {α : Type*} {β : Type*} (g : α → β) (y : α) (q : Fin n → α) :
+theorem comp_cons {α : Sort*} {β : Sort*} (g : α → β) (y : α) (q : Fin n → α) :
g ∘ cons y q = cons (g y) (g ∘ q) := by
ext j
by_cases h : j = 0
@@ -264,11 +264,15 @@ theorem comp_cons {α : Type*} {β : Type*} (g : α → β) (y : α) (q : Fin n
have : j'.succ = j := succ_pred j h
rw [← this, cons_succ, comp_apply, comp_apply, cons_succ]
-theorem comp_tail {α : Type*} {β : Type*} (g : α → β) (q : Fin n.succ → α) :
+theorem comp_tail {α : Sort*} {β : Sort*} (g : α → β) (q : Fin n.succ → α) :
g ∘ tail q = tail (g ∘ q) := by
ext j
simp [tail]
+section Preorder
+
+variable {α : Fin (n + 1) → Type*}
+
theorem le_cons [∀ i, Preorder (α i)] {x : α 0} {q : ∀ i, α i} {p : ∀ i : Fin n, α i.succ} :
q ≤ cons x p ↔ q 0 ≤ x ∧ tail q ≤ p :=
forall_fin_succ.trans <| and_congr Iff.rfl <| forall_congr' fun j ↦ by simp [tail]
@@ -281,33 +285,37 @@ theorem cons_le_cons [∀ i, Preorder (α i)] {x₀ y₀ : α 0} {x y : ∀ i :
cons x₀ x ≤ cons y₀ y ↔ x₀ ≤ y₀ ∧ x ≤ y :=
forall_fin_succ.trans <| and_congr_right' <| by simp only [cons_succ, Pi.le_def]
+end Preorder
+
theorem range_fin_succ {α} (f : Fin (n + 1) → α) :
Set.range f = insert (f 0) (Set.range (Fin.tail f)) :=
Set.ext fun _ ↦ exists_fin_succ.trans <| eq_comm.or Iff.rfl
@[simp]
-theorem range_cons {α : Type*} {n : ℕ} (x : α) (b : Fin n → α) :
+theorem range_cons {α} {n : ℕ} (x : α) (b : Fin n → α) :
Set.range (Fin.cons x b : Fin n.succ → α) = insert x (Set.range b) := by
rw [range_fin_succ, cons_zero, tail_cons]
section Append
+variable {α : Sort*}
+
/-- Append a tuple of length `m` to a tuple of length `n` to get a tuple of length `m + n`.
This is a non-dependent version of `Fin.add_cases`. -/
-def append {α : Type*} (a : Fin m → α) (b : Fin n → α) : Fin (m + n) → α :=
+def append (a : Fin m → α) (b : Fin n → α) : Fin (m + n) → α :=
@Fin.addCases _ _ (fun _ => α) a b
@[simp]
-theorem append_left {α : Type*} (u : Fin m → α) (v : Fin n → α) (i : Fin m) :
+theorem append_left (u : Fin m → α) (v : Fin n → α) (i : Fin m) :
append u v (Fin.castAdd n i) = u i :=
addCases_left _
@[simp]
-theorem append_right {α : Type*} (u : Fin m → α) (v : Fin n → α) (i : Fin n) :
+theorem append_right (u : Fin m → α) (v : Fin n → α) (i : Fin n) :
append u v (natAdd m i) = v i :=
addCases_right _
-theorem append_right_nil {α : Type*} (u : Fin m → α) (v : Fin n → α) (hv : n = 0) :
+theorem append_right_nil (u : Fin m → α) (v : Fin n → α) (hv : n = 0) :
append u v = u ∘ Fin.cast (by rw [hv, Nat.add_zero]) := by
refine funext (Fin.addCases (fun l => ?_) fun r => ?_)
· rw [append_left, Function.comp_apply]
@@ -316,11 +324,11 @@ theorem append_right_nil {α : Type*} (u : Fin m → α) (v : Fin n → α) (hv
· exact (Fin.cast hv r).elim0
@[simp]
-theorem append_elim0 {α : Type*} (u : Fin m → α) :
+theorem append_elim0 (u : Fin m → α) :
append u Fin.elim0 = u ∘ Fin.cast (Nat.add_zero _) :=
append_right_nil _ _ rfl
-theorem append_left_nil {α : Type*} (u : Fin m → α) (v : Fin n → α) (hu : m = 0) :
+theorem append_left_nil (u : Fin m → α) (v : Fin n → α) (hu : m = 0) :
append u v = v ∘ Fin.cast (by rw [hu, Nat.zero_add]) := by
refine funext (Fin.addCases (fun l => ?_) fun r => ?_)
· exact (Fin.cast hu l).elim0
@@ -329,11 +337,11 @@ theorem append_left_nil {α : Type*} (u : Fin m → α) (v : Fin n → α) (hu :
simp [hu]
@[simp]
-theorem elim0_append {α : Type*} (v : Fin n → α) :
+theorem elim0_append (v : Fin n → α) :
append Fin.elim0 v = v ∘ Fin.cast (Nat.zero_add _) :=
append_left_nil _ _ rfl
-theorem append_assoc {p : ℕ} {α : Type*} (a : Fin m → α) (b : Fin n → α) (c : Fin p → α) :
+theorem append_assoc {p : ℕ} (a : Fin m → α) (b : Fin n → α) (c : Fin p → α) :
append (append a b) c = append a (append b c) ∘ Fin.cast (Nat.add_assoc ..) := by
ext i
rw [Function.comp_apply]
@@ -348,7 +356,7 @@ theorem append_assoc {p : ℕ} {α : Type*} (a : Fin m → α) (b : Fin n → α
simp [← natAdd_natAdd]
/-- Appending a one-tuple to the left is the same as `Fin.cons`. -/
-theorem append_left_eq_cons {α : Type*} {n : ℕ} (x₀ : Fin 1 → α) (x : Fin n → α) :
+theorem append_left_eq_cons {n : ℕ} (x₀ : Fin 1 → α) (x : Fin n → α) :
Fin.append x₀ x = Fin.cons (x₀ 0) x ∘ Fin.cast (Nat.add_comm ..) := by
ext i
refine Fin.addCases ?_ ?_ i <;> clear i
@@ -360,21 +368,21 @@ theorem append_left_eq_cons {α : Type*} {n : ℕ} (x₀ : Fin 1 → α) (x : Fi
exact Fin.cons_succ _ _ _
/-- `Fin.cons` is the same as appending a one-tuple to the left. -/
-theorem cons_eq_append {α : Type*} (x : α) (xs : Fin n → α) :
+theorem cons_eq_append (x : α) (xs : Fin n → α) :
cons x xs = append (cons x Fin.elim0) xs ∘ Fin.cast (Nat.add_comm ..) := by
funext i; simp [append_left_eq_cons]
-@[simp] lemma append_cast_left {n m} {α : Type*} (xs : Fin n → α) (ys : Fin m → α) (n' : ℕ)
+@[simp] lemma append_cast_left {n m} (xs : Fin n → α) (ys : Fin m → α) (n' : ℕ)
(h : n' = n) :
Fin.append (xs ∘ Fin.cast h) ys = Fin.append xs ys ∘ (Fin.cast <| by rw [h]) := by
subst h; simp
-@[simp] lemma append_cast_right {n m} {α : Type*} (xs : Fin n → α) (ys : Fin m → α) (m' : ℕ)
+@[simp] lemma append_cast_right {n m} (xs : Fin n → α) (ys : Fin m → α) (m' : ℕ)
(h : m' = m) :
Fin.append xs (ys ∘ Fin.cast h) = Fin.append xs ys ∘ (Fin.cast <| by rw [h]) := by
subst h; simp
-lemma append_rev {m n} {α : Type*} (xs : Fin m → α) (ys : Fin n → α) (i : Fin (m + n)) :
+lemma append_rev {m n} (xs : Fin m → α) (ys : Fin n → α) (i : Fin (m + n)) :
append xs ys (rev i) = append (ys ∘ rev) (xs ∘ rev) (cast (Nat.add_comm ..) i) := by
rcases rev_surjective i with ⟨i, rfl⟩
rw [rev_rev]
@@ -382,39 +390,46 @@ lemma append_rev {m n} {α : Type*} (xs : Fin m → α) (ys : Fin n → α) (i :
· simp [rev_castAdd]
· simp [cast_rev, rev_addNat]
-lemma append_comp_rev {m n} {α : Type*} (xs : Fin m → α) (ys : Fin n → α) :
+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
+variable {α : Sort*}
+
/-- Repeat `a` `m` times. For example `Fin.repeat 2 ![0, 3, 7] = ![0, 3, 7, 0, 3, 7]`. -/
-- Porting note: removed @[simp]
-def «repeat» {α : Type*} (m : ℕ) (a : Fin n → α) : Fin (m * n) → α
+def «repeat» (m : ℕ) (a : Fin n → α) : Fin (m * n) → α
| i => a i.modNat
-- Porting note: added (leanprover/lean4#2042)
@[simp]
-theorem repeat_apply {α : Type*} (a : Fin n → α) (i : Fin (m * n)) :
+theorem repeat_apply (a : Fin n → α) (i : Fin (m * n)) :
Fin.repeat m a i = a i.modNat :=
rfl
@[simp]
-theorem repeat_zero {α : Type*} (a : Fin n → α) :
+theorem repeat_zero (a : Fin n → α) :
Fin.repeat 0 a = Fin.elim0 ∘ cast (Nat.zero_mul _) :=
funext fun x => (cast (Nat.zero_mul _) x).elim0
@[simp]
-theorem repeat_one {α : Type*} (a : Fin n → α) : Fin.repeat 1 a = a ∘ cast (Nat.one_mul _) := by
+theorem repeat_one (a : Fin n → α) : Fin.repeat 1 a = a ∘ cast (Nat.one_mul _) := by
generalize_proofs h
apply funext
rw [(Fin.rightInverse_cast h.symm).surjective.forall]
intro i
simp [modNat, Nat.mod_eq_of_lt i.is_lt]
-theorem repeat_succ {α : Type*} (a : Fin n → α) (m : ℕ) :
+theorem repeat_succ (a : Fin n → α) (m : ℕ) :
Fin.repeat m.succ a =
append a (Fin.repeat m a) ∘ cast ((Nat.succ_mul _ _).trans (Nat.add_comm ..)) := by
generalize_proofs h
@@ -425,7 +440,7 @@ theorem repeat_succ {α : Type*} (a : Fin n → α) (m : ℕ) :
· simp [modNat]
@[simp]
-theorem repeat_add {α : Type*} (a : Fin n → α) (m₁ m₂ : ℕ) : Fin.repeat (m₁ + m₂) a =
+theorem repeat_add (a : Fin n → α) (m₁ m₂ : ℕ) : Fin.repeat (m₁ + m₂) a =
append (Fin.repeat m₁ a) (Fin.repeat m₂ a) ∘ cast (Nat.add_mul ..) := by
generalize_proofs h
apply funext
@@ -434,11 +449,11 @@ theorem repeat_add {α : Type*} (a : Fin n → α) (m₁ m₂ : ℕ) : Fin.repea
· simp [modNat, Nat.mod_eq_of_lt l.is_lt]
· simp [modNat, Nat.add_mod]
-theorem repeat_rev {α : Type*} (a : Fin n → α) (k : Fin (m * n)) :
+theorem repeat_rev (a : Fin n → α) (k : Fin (m * n)) :
Fin.repeat m a k.rev = Fin.repeat m (a ∘ Fin.rev) k :=
congr_arg a k.modNat_rev
-theorem repeat_comp_rev {α} (a : Fin n → α) :
+theorem repeat_comp_rev (a : Fin n → α) :
Fin.repeat m a ∘ Fin.rev = Fin.repeat m (a ∘ Fin.rev) :=
funext <| repeat_rev a
@@ -456,14 +471,14 @@ several places. -/
-- Porting note: `i.castSucc` does not work like it did in Lean 3;
-- `(castSucc i)` must be used.
-variable {α : Fin (n + 1) → Type u} (x : α (last n)) (q : ∀ i, α i)
+variable {α : Fin (n + 1) → Sort*} (x : α (last n)) (q : ∀ i, α i)
(p : ∀ i : Fin n, α (castSucc i)) (i : Fin n) (y : α (castSucc i)) (z : α (last n))
/-- The beginning of an `n+1` tuple, i.e., its first `n` entries -/
def init (q : ∀ i, α i) (i : Fin n) : α (castSucc i) :=
q (castSucc i)
-theorem init_def {n : ℕ} {α : Fin (n + 1) → Type*} {q : ∀ i, α i} :
+theorem init_def {q : ∀ i, α i} :
(init fun k : Fin (n + 1) ↦ q k) = fun k : Fin n ↦ q (castSucc k) :=
rfl
@@ -485,21 +500,21 @@ theorem snoc_castSucc : snoc p x (castSucc i) = p i := by
convert cast_eq rfl (p i)
@[simp]
-theorem snoc_comp_castSucc {n : ℕ} {α : Sort _} {a : α} {f : Fin n → α} :
+theorem snoc_comp_castSucc {α : Sort*} {a : α} {f : Fin n → α} :
(snoc f a : Fin (n + 1) → α) ∘ castSucc = f :=
funext fun i ↦ by rw [Function.comp_apply, snoc_castSucc]
@[simp]
theorem snoc_last : snoc p x (last n) = x := by simp [snoc]
-lemma snoc_zero {α : Type*} (p : Fin 0 → α) (x : α) :
+lemma snoc_zero {α : Sort*} (p : Fin 0 → α) (x : α) :
Fin.snoc p x = fun _ ↦ x := by
ext y
have : Subsingleton (Fin (0 + 1)) := Fin.subsingleton_one
simp only [Subsingleton.elim y (Fin.last 0), snoc_last]
@[simp]
-theorem snoc_comp_nat_add {n m : ℕ} {α : Sort _} (f : Fin (m + n) → α) (a : α) :
+theorem snoc_comp_nat_add {n m : ℕ} {α : Sort*} (f : Fin (m + n) → α) (a : α) :
(snoc f a : Fin _ → α) ∘ (natAdd m : Fin (n + 1) → Fin (m + n + 1)) =
snoc (f ∘ natAdd m) a := by
ext i
@@ -510,13 +525,13 @@ theorem snoc_comp_nat_add {n m : ℕ} {α : Sort _} (f : Fin (m + n) → α) (a
rw [natAdd_castSucc, snoc_castSucc]
@[simp]
-theorem snoc_cast_add {α : Fin (n + m + 1) → Type*} (f : ∀ i : Fin (n + m), α (castSucc i))
+theorem snoc_cast_add {α : Fin (n + m + 1) → Sort*} (f : ∀ i : Fin (n + m), α (castSucc i))
(a : α (last (n + m))) (i : Fin n) : (snoc f a) (castAdd (m + 1) i) = f (castAdd m i) :=
dif_pos _
-- Porting note: Had to `unfold comp`
@[simp]
-theorem snoc_comp_cast_add {n m : ℕ} {α : Sort _} (f : Fin (n + m) → α) (a : α) :
+theorem snoc_comp_cast_add {n m : ℕ} {α : Sort*} (f : Fin (n + m) → α) (a : α) :
(snoc f a : Fin _ → α) ∘ castAdd (m + 1) = f ∘ castAdd m :=
funext (by unfold comp; exact snoc_cast_add _ _)
@@ -542,7 +557,7 @@ theorem snoc_update : snoc (update p i y) x = update (snoc p x) (castSucc i) y :
· simp [h, h']
· exact heq_of_cast_eq C2 rfl
rw [E1, E2]
- exact eq_rec_compose (Eq.trans C2.symm C1) C2 y
+ rfl
· have : ¬castLT j h = i := by
intro E
apply h'
@@ -587,14 +602,14 @@ theorem init_update_castSucc : init (update q (castSucc i) y) = update (init q)
/-- `tail` and `init` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
-theorem tail_init_eq_init_tail {β : Type*} (q : Fin (n + 2) → β) :
+theorem tail_init_eq_init_tail {β : Sort*} (q : Fin (n + 2) → β) :
tail (init q) = init (tail q) := by
ext i
simp [tail, init, castSucc_fin_succ]
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
-theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
+theorem cons_snoc_eq_snoc_cons {β : Sort*} (a : β) (q : Fin n → β) (b : β) :
@cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
ext i
by_cases h : i = 0
@@ -612,7 +627,7 @@ theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β)
rw [eq_last_of_not_lt h', succ_last]
simp
-theorem comp_snoc {α : Type*} {β : Type*} (g : α → β) (q : Fin n → α) (y : α) :
+theorem comp_snoc {α : Sort*} {β : Sort*} (g : α → β) (q : Fin n → α) (y : α) :
g ∘ snoc q y = snoc (g ∘ q) (g y) := by
ext j
by_cases h : j.val < n
@@ -621,7 +636,7 @@ theorem comp_snoc {α : Type*} {β : Type*} (g : α → β) (q : Fin n → α) (
simp
/-- Appending a one-tuple to the right is the same as `Fin.snoc`. -/
-theorem append_right_eq_snoc {α : Type*} {n : ℕ} (x : Fin n → α) (x₀ : Fin 1 → α) :
+theorem append_right_eq_snoc {α : Sort*} {n : ℕ} (x : Fin n → α) (x₀ : Fin 1 → α) :
Fin.append x x₀ = Fin.snoc x (x₀ 0) := by
ext i
refine Fin.addCases ?_ ?_ i <;> clear i
@@ -633,21 +648,21 @@ theorem append_right_eq_snoc {α : Type*} {n : ℕ} (x : Fin n → α) (x₀ : F
exact (@snoc_last _ (fun _ => α) _ _).symm
/-- `Fin.snoc` is the same as appending a one-tuple -/
-theorem snoc_eq_append {α : Type*} (xs : Fin n → α) (x : α) :
+theorem snoc_eq_append {α : Sort*} (xs : Fin n → α) (x : α) :
snoc xs x = append xs (cons x Fin.elim0) :=
(append_right_eq_snoc xs (cons x Fin.elim0)).symm
-theorem append_left_snoc {n m} {α : Type*} (xs : Fin n → α) (x : α) (ys : Fin m → α) :
+theorem append_left_snoc {n m} {α : Sort*} (xs : Fin n → α) (x : α) (ys : Fin m → α) :
Fin.append (Fin.snoc xs x) ys =
Fin.append xs (Fin.cons x ys) ∘ Fin.cast (Nat.succ_add_eq_add_succ ..) := by
rw [snoc_eq_append, append_assoc, append_left_eq_cons, append_cast_right]; rfl
-theorem append_right_cons {n m} {α : Type*} (xs : Fin n → α) (y : α) (ys : Fin m → α) :
+theorem append_right_cons {n m} {α : Sort*} (xs : Fin n → α) (y : α) (ys : Fin m → α) :
Fin.append xs (Fin.cons y ys) =
Fin.append (Fin.snoc xs y) ys ∘ Fin.cast (Nat.succ_add_eq_add_succ ..).symm := by
rw [append_left_snoc]; rfl
-theorem append_cons {α} (a : α) (as : Fin n → α) (bs : Fin m → α) :
+theorem append_cons {α : Sort*} (a : α) (as : Fin n → α) (bs : Fin m → α) :
Fin.append (cons a as) bs
= cons a (Fin.append as bs) ∘ (Fin.cast <| Nat.add_right_comm n 1 m) := by
funext i
@@ -661,7 +676,7 @@ theorem append_cons {α} (a : α) (as : Fin n → α) (bs : Fin m → α) :
· have : ¬i < n := Nat.not_le.mpr <| Nat.lt_succ.mp <| Nat.not_le.mp h
simp [addCases, this]
-theorem append_snoc {α} (as : Fin n → α) (bs : Fin m → α) (b : α) :
+theorem append_snoc {α : Sort*} (as : Fin n → α) (bs : Fin m → α) (b : α) :
Fin.append as (snoc bs b) = snoc (Fin.append as bs) b := by
funext i
rcases i with ⟨i, isLt⟩
@@ -675,7 +690,7 @@ theorem append_snoc {α} (as : Fin n → α) (bs : Fin m → α) (b : α) :
· have := Nat.sub_lt_left_of_lt_add (Nat.not_lt.mp lt_n) lt_add
contradiction
-theorem comp_init {α : Type*} {β : Type*} (g : α → β) (q : Fin n.succ → α) :
+theorem comp_init {α : Sort*} {β : Sort*} (g : α → β) (q : Fin n.succ → α) :
g ∘ init q = init (g ∘ q) := by
ext j
simp [init]
@@ -695,18 +710,18 @@ def snocCases {P : (∀ i : Fin n.succ, α i) → Sort*}
/-- Recurse on a tuple by splitting into `Fin.elim0` and `Fin.snoc`. -/
@[elab_as_elim]
-def snocInduction {α : Type*}
+def snocInduction {α : Sort*}
{P : ∀ {n : ℕ}, (Fin n → α) → 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
section InsertNth
-variable {α : Fin (n + 1) → Type u} {β : Type v}
+variable {α : Fin (n + 1) → Sort*} {β : Sort*}
/- Porting note: Lean told me `(fun x x_1 ↦ α x)` was an invalid motive, but disabling
automatic insertion and specifying that motive seems to work. -/
@@ -778,13 +793,13 @@ theorem insertNth_apply_succAbove (i : Fin (n + 1)) (x : α i) (p : ∀ j, α (i
generalize hk : castPred ((succAbove i) j) H₁ = k
rw [castPred_succAbove _ _ hlt] at hk; cases hk
intro; rfl
- · generalize_proofs H₁ H₂; revert H₂
+ · 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]
-theorem succAbove_cases_eq_insertNth : @succAboveCases.{u + 1} = @insertNth.{u} :=
+theorem succAbove_cases_eq_insertNth : @succAboveCases = @insertNth :=
rfl
@[simp] lemma removeNth_insertNth (p : Fin (n + 1)) (a : α p) (f : ∀ i, α (succAbove p i)) :
@@ -854,7 +869,7 @@ theorem insertNth_last (x : α (last n)) (p : ∀ j : Fin n, α ((last n).succAb
theorem insertNth_last' (x : β) (p : Fin n → β) :
@insertNth _ (fun _ ↦ β) (last n) x p = snoc p x := by simp [insertNth_last]
-lemma insertNth_rev {α : Type*} (i : Fin (n + 1)) (a : α) (f : Fin n → α) (j : Fin (n + 1)) :
+lemma insertNth_rev {α : Sort*} (i : Fin (n + 1)) (a : α) (f : Fin n → α) (j : Fin (n + 1)) :
insertNth (α := fun _ ↦ α) i a f (rev j) = insertNth (α := fun _ ↦ α) i.rev a (f ∘ rev) j := by
induction j using Fin.succAboveCases
· exact rev i
@@ -888,8 +903,9 @@ theorem insertNth_binop (op : ∀ j, α j → α j → α j) (i : Fin (n + 1)) (
op j (i.insertNth x p j) (i.insertNth y q j) :=
insertNth_eq_iff.2 <| by unfold removeNth; simp
-section
-variable [∀ i, Preorder (α i)]
+section Preorder
+
+variable {α : Fin (n + 1) → Type*} [∀ i, Preorder (α i)]
theorem insertNth_le_iff {i : Fin (n + 1)} {x : α i} {p : ∀ j, α (i.succAbove j)} {q : ∀ j, α j} :
i.insertNth x p ≤ q ↔ x ≤ q i ∧ p ≤ fun j ↦ q (i.succAbove j) := by
@@ -899,7 +915,7 @@ theorem le_insertNth_iff {i : Fin (n + 1)} {x : α i} {p : ∀ j, α (i.succAbov
q ≤ i.insertNth x p ↔ q i ≤ x ∧ (fun j ↦ q (i.succAbove j)) ≤ p := by
simp [Pi.le_def, forall_iff_succAbove i]
-end
+end Preorder
open Set
@@ -915,7 +931,7 @@ lemma insertNth_self_removeNth (p : Fin (n + 1)) (f : ∀ j, α j) :
/-- Separates an `n+1`-tuple, returning a selected index and then the rest of the tuple.
Functional form of `Equiv.piFinSuccAbove`. -/
@[deprecated removeNth (since := "2024-06-19")]
-def extractNth (i : Fin (n + 1)) (f : (∀ j, α j)) :
+def extractNth {α : Fin (n + 1) → Type*} (i : Fin (n + 1)) (f : (∀ j, α j)) :
α i × ∀ j, α (i.succAbove j) :=
(f i, removeNth i f)
@@ -936,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
@@ -954,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
@@ -979,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
@@ -1029,7 +1045,7 @@ end Find
section ContractNth
-variable {α : Type*}
+variable {α : Sort*}
/-- Sends `(g₀, ..., gₙ)` to `(g₀, ..., op gⱼ gⱼ₊₁, ..., gₙ)`. -/
def contractNth (j : Fin (n + 1)) (op : α → α → α) (g : Fin (n + 1) → α) (k : Fin n) : α :=
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 5d845ab373afb..7c012e3737704 100644
--- a/Mathlib/Data/Fin/Tuple/Finset.lean
+++ b/Mathlib/Data/Fin/Tuple/Finset.lean
@@ -3,34 +3,102 @@ Copyright (c) 2023 Bolton Bailey. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Bolton Bailey
-/
-import Mathlib.Data.Fin.Tuple.Basic
+import Mathlib.Data.Finset.Prod
import Mathlib.Data.Fintype.Pi
+import Mathlib.Logic.Equiv.Fin
/-!
# Fin-indexed tuples of finsets
-/
-open Fintype
+open Fin Fintype
namespace Fin
-variable {n : ℕ} {α : Fin (n + 1) → Type*}
+variable {n : ℕ} {α : Fin (n + 1) → Type*} {f : ∀ i, α i} {s : ∀ i, Finset (α i)} {p : Fin (n + 1)}
+
+open Fintype
+
+lemma mem_piFinset_iff_zero_tail :
+ f ∈ Fintype.piFinset s ↔ f 0 ∈ s 0 ∧ tail f ∈ piFinset (tail s) := by
+ simp only [Fintype.mem_piFinset, forall_fin_succ, tail]
+
+lemma mem_piFinset_iff_last_init :
+ f ∈ piFinset s ↔ f (last n) ∈ s (last n) ∧ init f ∈ piFinset (init s) := by
+ simp only [Fintype.mem_piFinset, forall_fin_succ', init, and_comm]
-lemma mem_piFinset_succ {x : ∀ i, α i} {s : ∀ i, Finset (α i)} :
- x ∈ piFinset s ↔ x 0 ∈ s 0 ∧ tail x ∈ piFinset (tail s) := by
- simp only [mem_piFinset, forall_iff_succ, tail]
+lemma mem_piFinset_iff_pivot_removeNth (p : Fin (n + 1)) :
+ f ∈ piFinset s ↔ f p ∈ s p ∧ removeNth p f ∈ piFinset (removeNth p s) := by
+ simp only [Fintype.mem_piFinset, forall_iff_succAbove p, removeNth]
-lemma mem_piFinset_succ' {x : ∀ i, α i} {s : ∀ i, Finset (α i)} :
- x ∈ piFinset s ↔ x (last n) ∈ s (last n) ∧ init x ∈ piFinset (init s) := by
- simp only [mem_piFinset, forall_iff_castSucc, init]
+@[deprecated (since := "2024-09-20")] alias mem_piFinset_succ := mem_piFinset_iff_zero_tail
+@[deprecated (since := "2024-09-20")] alias mem_piFinset_succ' := mem_piFinset_iff_last_init
-lemma cons_mem_piFinset_cons {x₀ : α 0} {x : ∀ i : Fin n, α i.succ}
- {s₀ : Finset (α 0)} {s : ∀ i : Fin n, Finset (α i.succ)} :
- cons x₀ x ∈ piFinset (cons s₀ s) ↔ x₀ ∈ s₀ ∧ x ∈ piFinset s := by
- simp_rw [mem_piFinset_succ, cons_zero, tail_cons]
+lemma cons_mem_piFinset_cons {x_zero : α 0} {x_tail : (i : Fin n) → α i.succ}
+ {s_zero : Finset (α 0)} {s_tail : (i : Fin n) → Finset (α i.succ)} :
+ cons x_zero x_tail ∈ piFinset (cons s_zero s_tail) ↔
+ x_zero ∈ s_zero ∧ x_tail ∈ piFinset s_tail := by
+ simp_rw [mem_piFinset_iff_zero_tail, cons_zero, tail_cons]
-lemma snoc_mem_piFinset_snoc {x : ∀ i : Fin n, α i.castSucc} {xₙ : α (.last n)}
- {s : ∀ i : Fin n, Finset (α i.castSucc)} {sₙ : Finset (α <| .last n)} :
- snoc x xₙ ∈ piFinset (snoc s sₙ) ↔ xₙ ∈ sₙ ∧ x ∈ piFinset s := by
- simp_rw [mem_piFinset_succ', init_snoc, snoc_last]
+lemma snoc_mem_piFinset_snoc {x_last : α (last n)} {x_init : (i : Fin n) → α i.castSucc}
+ {s_last : Finset (α (last n))} {s_init : (i : Fin n) → Finset (α i.castSucc)} :
+ snoc x_init x_last ∈ piFinset (snoc s_init s_last) ↔
+ x_last ∈ s_last ∧ x_init ∈ piFinset s_init := by
+ simp_rw [mem_piFinset_iff_last_init, init_snoc, snoc_last]
+
+lemma insertNth_mem_piFinset_insertNth {x_pivot : α p} {x_remove : ∀ i, α (succAbove p i)}
+ {s_pivot : Finset (α p)} {s_remove : ∀ i, Finset (α (succAbove p i))} :
+ insertNth p x_pivot x_remove ∈ piFinset (insertNth p s_pivot s_remove) ↔
+ x_pivot ∈ s_pivot ∧ x_remove ∈ piFinset s_remove := by
+ simp [mem_piFinset_iff_pivot_removeNth p]
end Fin
+
+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] :
+ {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] :
+ {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] :
+ {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] :
+ {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] :
+ {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] :
+ {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/NatAntidiagonal.lean b/Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean
index 4cef85d6ad0d3..7f311baa1744c 100644
--- a/Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean
+++ b/Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean
@@ -123,7 +123,7 @@ theorem antidiagonalTuple_one (n : ℕ) : antidiagonalTuple 1 n = [![n]] := by
Nat.sub_self, List.bind_append, List.bind_singleton, List.bind_map]
conv_rhs => rw [← List.nil_append [![n]]]
congr 1
- simp_rw [List.bind_eq_nil, List.mem_range, List.map_eq_nil]
+ simp_rw [List.bind_eq_nil_iff, List.mem_range, List.map_eq_nil_iff]
intro x hx
obtain ⟨m, rfl⟩ := Nat.exists_eq_add_of_lt hx
rw [add_assoc, add_tsub_cancel_left, antidiagonalTuple_zero_succ]
@@ -143,8 +143,8 @@ theorem antidiagonalTuple_pairwise_pi_lex :
simp_rw [antidiagonalTuple, List.pairwise_bind, List.pairwise_map, List.mem_map,
forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
simp only [mem_antidiagonal, Prod.forall, and_imp, forall_apply_eq_imp_iff₂]
- simp only [Fin.pi_lex_lt_cons_cons, eq_self_iff_true, true_and_iff, lt_self_iff_false,
- false_or_iff]
+ simp only [Fin.pi_lex_lt_cons_cons, eq_self_iff_true, true_and, lt_self_iff_false,
+ false_or]
refine ⟨fun _ _ _ => antidiagonalTuple_pairwise_pi_lex k _, ?_⟩
induction' n with n n_ih
· rw [antidiagonal_zero]
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 d53751d03f1f5..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
@@ -178,7 +179,7 @@ theorem comp_sort_eq_comp_iff_monotone : f ∘ σ = f ∘ sort f ↔ Monotone (f
/-- The sorted versions of a tuple `f` and of any permutation of `f` agree. -/
theorem comp_perm_comp_sort_eq_comp_sort : (f ∘ σ) ∘ sort (f ∘ σ) = f ∘ sort f := by
- rw [Function.comp.assoc, ← Equiv.Perm.coe_mul]
+ rw [Function.comp_assoc, ← Equiv.Perm.coe_mul]
exact unique_monotone (monotone_sort (f ∘ σ)) (monotone_sort f)
/-- If a permutation `f ∘ σ` of the tuple `f` is not the same as `f ∘ sort f`, then `f ∘ σ`
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 82688911d453d..f4a3ae5c5e0e2 100644
--- a/Mathlib/Data/FinEnum.lean
+++ b/Mathlib/Data/FinEnum.lean
@@ -76,7 +76,7 @@ noncomputable def ofInjective {α β} (f : α → β) [DecidableEq α] [FinEnum
ofList ((toList β).filterMap (partialInv f))
(by
intro x
- simp only [mem_toList, true_and_iff, List.mem_filterMap]
+ simp only [mem_toList, true_and, List.mem_filterMap]
use f x
simp only [h, Function.partialInv_left])
@@ -107,41 +107,19 @@ def Finset.enum [DecidableEq α] : List α → List (Finset α)
| [] => [∅]
| x :: xs => do
let r ← Finset.enum xs
- [r, {x} ∪ r]
+ [r, insert x r]
@[simp]
theorem Finset.mem_enum [DecidableEq α] (s : Finset α) (xs : List α) :
s ∈ Finset.enum xs ↔ ∀ x ∈ s, x ∈ xs := by
- induction' xs with xs_hd generalizing s <;> simp [*, Finset.enum]
- · simp [Finset.eq_empty_iff_forall_not_mem]
- · constructor
- · rintro ⟨a, h, h'⟩ x hx
- cases' h' with _ h' a b
- · right
- apply h
- subst a
- exact hx
- · simp only [h', mem_union, mem_singleton] at hx ⊢
- cases' hx with hx hx'
- · exact Or.inl hx
- · exact Or.inr (h _ hx')
- · intro h
- exists s \ ({xs_hd} : Finset α)
- simp only [and_imp, mem_sdiff, mem_singleton]
- simp only [or_iff_not_imp_left] at h
- exists h
- by_cases h : xs_hd ∈ s
- · have : {xs_hd} ⊆ s := by
- simp only [HasSubset.Subset, *, forall_eq, mem_singleton]
- simp only [union_sdiff_of_subset this, or_true_iff, Finset.union_sdiff_of_subset,
- eq_self_iff_true]
- · left
- symm
- simp only [sdiff_eq_self]
- intro a
- simp only [and_imp, mem_inter, mem_singleton]
- rintro h₀ rfl
- exact (h h₀).elim
+ induction xs generalizing s with
+ | nil => simp [enum, eq_empty_iff_forall_not_mem]
+ | cons x xs ih =>
+ simp only [enum, List.bind_eq_bind, List.mem_bind, List.mem_cons, List.mem_singleton,
+ List.not_mem_nil, or_false, ih]
+ refine ⟨by aesop, fun hs => ⟨s.erase x, ?_⟩⟩
+ simp only [or_iff_not_imp_left] at hs
+ simp (config := { contextual := true }) [eq_comm (a := s), or_iff_not_imp_left, hs]
instance Finset.finEnum [FinEnum α] : FinEnum (Finset α) :=
ofList (Finset.enum (toList α)) (by intro; simp)
@@ -160,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) :=
@@ -172,6 +150,8 @@ instance PSigma.finEnumPropProp {α : Prop} {β : α → Prop} [Decidable α] [
if h : ∃ a, β a then ofList [⟨h.fst, h.snd⟩] (by rintro ⟨⟩; simp)
else ofList [] fun a => (h ⟨a.fst, a.snd⟩).elim
+instance [DecidableEq α] (xs : List α) : FinEnum { x : α // x ∈ xs } := ofList xs.attach (by simp)
+
instance (priority := 100) [FinEnum α] : Fintype α where
elems := univ.map (equiv).symm.toEmbedding
complete := by intros; simp
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 ed5e6a411c850..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']
@@ -213,7 +211,7 @@ theorem keys_singleton (a : α) (b : β a) : (singleton a b).keys = {a} :=
@[simp]
theorem mem_singleton (x y : α) (b : β y) : x ∈ singleton y b ↔ x = y := by
- simp only [singleton]; erw [mem_cons, mem_nil_iff, or_false_iff]
+ simp only [singleton]; erw [mem_cons, mem_nil_iff, or_false]
section
@@ -341,7 +339,8 @@ end
/-- Fold a commutative function over the key-value pairs in the map -/
def foldl {δ : Type w} (f : δ → ∀ a, β a → δ)
(H : ∀ d a₁ b₁ a₂ b₂, f (f d a₁ b₁) a₂ b₂ = f (f d a₂ b₂) a₁ b₁) (d : δ) (m : Finmap β) : δ :=
- m.entries.foldl (fun d s => f d s.1 s.2) (fun _ _ _ => H _ _ _ _ _) d
+ letI : RightCommutative fun d (s : Sigma β) ↦ f d s.1 s.2 := ⟨fun _ _ _ ↦ H _ _ _ _ _⟩
+ m.entries.foldl (fun d s => f d s.1 s.2) d
/-- `any f s` returns `true` iff there exists a value `v` in `s` such that `f v = true`. -/
def any (f : ∀ x, β x → Bool) (s : Finmap β) : Bool :=
@@ -514,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 07d86ddb5847a..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
@@ -125,7 +126,7 @@ assert_not_exists CompleteLattice
assert_not_exists OrderedCommMonoid
-open Multiset Subtype Nat Function
+open Multiset Subtype Function
universe u
@@ -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]
@@ -773,9 +777,13 @@ theorem mk_cons {s : Multiset α} (h : (a ::ₘ s).Nodup) :
theorem cons_empty (a : α) : cons a ∅ (not_mem_empty _) = {a} := rfl
@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
-theorem nonempty_cons (h : a ∉ s) : (cons a s h).Nonempty :=
+theorem cons_nonempty (h : a ∉ s) : (cons a s h).Nonempty :=
⟨a, mem_cons.2 <| Or.inl rfl⟩
+@[deprecated (since := "2024-09-19")] alias nonempty_cons := cons_nonempty
+
+@[simp] theorem cons_ne_empty (h : a ∉ s) : cons a s h ≠ ∅ := (cons_nonempty _).ne_empty
+
@[simp]
theorem nonempty_mk {m : Multiset α} {hm} : (⟨m, hm⟩ : Finset α).Nonempty ↔ m ≠ 0 := by
induction m using Multiset.induction_on <;> simp
@@ -803,6 +811,41 @@ theorem ssubset_iff_exists_cons_subset : s ⊂ t ↔ ∃ (a : _) (h : a ∉ s),
obtain ⟨a, hs, ht⟩ := not_subset.1 h.2
exact ⟨a, ht, cons_subset.2 ⟨hs, h.subset⟩⟩
+theorem cons_swap (hb : b ∉ s) (ha : a ∉ s.cons b hb) :
+ (s.cons b hb).cons a ha = (s.cons a fun h ↦ ha (mem_cons.mpr (.inr h))).cons b fun h ↦
+ 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 -/
@@ -916,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 α) :=
@@ -951,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`. -/
@@ -982,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
@@ -1002,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]
@@ -1038,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
@@ -1098,7 +1137,7 @@ obtained by inserting an element in `t`. -/
@[elab_as_elim]
theorem Nonempty.cons_induction {α : Type*} {p : ∀ s : Finset α, s.Nonempty → Prop}
(singleton : ∀ a, p {a} (singleton_nonempty _))
- (cons : ∀ a s (h : a ∉ s) (hs), p s hs → p (Finset.cons a s h) (nonempty_cons h))
+ (cons : ∀ a s (h : a ∉ s) (hs), p s hs → p (Finset.cons a s h) (cons_nonempty h))
{s : Finset α} (hs : s.Nonempty) : p s hs := by
induction s using Finset.cons_induction with
| empty => exact (not_nonempty_empty hs).elim
@@ -1136,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 -/
@@ -1427,7 +1495,7 @@ theorem insert_inter_of_not_mem {s₁ s₂ : Finset α} {a : α} (h : a ∉ s₂
insert a s₁ ∩ s₂ = s₁ ∩ s₂ :=
ext fun x => by
have : ¬(x = a ∧ x ∈ s₂) := by rintro ⟨rfl, H⟩; exact h H
- simp only [mem_inter, mem_insert, or_and_right, this, false_or_iff]
+ simp only [mem_inter, mem_insert, or_and_right, this, false_or]
@[simp]
theorem inter_insert_of_not_mem {s₁ s₂ : Finset α} {a : α} (h : a ∉ s₁) :
@@ -1479,18 +1547,16 @@ instance : DistribLattice (Finset α) :=
{ le_sup_inf := fun a b c => by
simp (config := { contextual := true }) only
[sup_eq_union, inf_eq_inter, le_eq_subset, subset_iff, mem_inter, mem_union, and_imp,
- or_imp, true_or_iff, imp_true_iff, true_and_iff, or_true_iff] }
+ or_imp, true_or, imp_true_iff, true_and, or_true] }
@[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 :=
@@ -1637,7 +1703,7 @@ theorem erase_eq_self : s.erase a = s ↔ a ∉ s :=
theorem erase_insert_eq_erase (s : Finset α) (a : α) : (insert a s).erase a = s.erase a :=
ext fun x => by
simp (config := { contextual := true }) only [mem_erase, mem_insert, and_congr_right_iff,
- false_or_iff, iff_self_iff, imp_true_iff]
+ false_or, iff_self, imp_true_iff]
theorem erase_insert {a : α} {s : Finset α} (h : a ∉ s) : erase (insert a s) a = s := by
rw [erase_insert_eq_erase, erase_eq_of_not_mem h]
@@ -1654,7 +1720,7 @@ theorem erase_cons_of_ne {a b : α} {s : Finset α} (ha : a ∉ s) (hb : a ≠ b
@[simp] theorem insert_erase (h : a ∈ s) : insert a (erase s a) = s :=
ext fun x => by
- simp only [mem_insert, mem_erase, or_and_left, dec_em, true_and_iff]
+ simp only [mem_insert, mem_erase, or_and_left, dec_em, true_and]
apply or_iff_right_of_imp
rintro rfl
exact h
@@ -1772,11 +1838,11 @@ instance : GeneralizedBooleanAlgebra (Finset α) :=
simp only [Finset.ext_iff, mem_union, mem_sdiff, inf_eq_inter, sup_eq_union, mem_inter,
← and_or_left, em, and_true, implies_true]
inf_inf_sdiff := fun x y => by
- simp only [Finset.ext_iff, inter_sdiff_self, inter_empty, inter_assoc, false_iff_iff,
+ simp only [Finset.ext_iff, inter_sdiff_self, inter_empty, inter_assoc, false_iff,
inf_eq_inter, not_mem_empty, bot_eq_empty, not_false_iff, implies_true] }
theorem not_mem_sdiff_of_mem_right (h : a ∈ t) : a ∉ s \ t := by
- simp only [mem_sdiff, h, not_true, not_false_iff, and_false_iff]
+ simp only [mem_sdiff, h, not_true, not_false_iff, and_false]
theorem not_mem_sdiff_of_not_mem_left (h : a ∉ s) : a ∉ s \ t := by simp [h]
@@ -1796,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
@@ -1819,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
@@ -1848,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
@@ -1912,7 +1980,7 @@ theorem union_sdiff_self (s t : Finset α) : (s ∪ t) \ t = s \ t :=
-- TODO: Do we want to delete this lemma and `Finset.disjUnion_singleton`,
-- or instead add `Finset.union_singleton`/`Finset.singleton_union`?
-theorem sdiff_singleton_eq_erase (a : α) (s : Finset α) : s \ singleton a = erase s a := by
+theorem sdiff_singleton_eq_erase (a : α) (s : Finset α) : s \ {a} = erase s a := by
ext
rw [mem_erase, mem_sdiff, mem_singleton, and_comm]
@@ -1968,9 +2036,9 @@ theorem erase_union_of_mem (ha : a ∈ t) (s : Finset α) : s.erase a ∪ t = s
theorem union_erase_of_mem (ha : a ∈ s) (t : Finset α) : s ∪ t.erase a = s ∪ t := by
rw [← insert_erase (mem_union_left t ha), erase_union_distrib, ← insert_union, insert_erase ha]
-@[simp]
-theorem sdiff_singleton_eq_self (ha : a ∉ s) : s \ {a} = s :=
- sdiff_eq_self_iff_disjoint.2 <| by simp [ha]
+@[simp, deprecated erase_eq_of_not_mem (since := "2024-10-01")]
+theorem sdiff_singleton_eq_self (ha : a ∉ s) : s \ {a} = s := by
+ rw [← erase_eq, erase_eq_of_not_mem ha]
theorem Nontrivial.sdiff_singleton_nonempty {c : α} {s : Finset α} (hS : s.Nontrivial) :
(s \ {c}).Nonempty := by
@@ -2034,6 +2102,8 @@ theorem disjoint_sdiff_inter (s t : Finset α) : Disjoint (s \ t) (s ∩ t) :=
theorem sdiff_eq_self_iff_disjoint : s \ t = s ↔ Disjoint s t :=
sdiff_eq_self_iff_disjoint'
+@[deprecated (since := "2024-10-01")] alias sdiff_eq_self := sdiff_eq_self_iff_disjoint
+
theorem sdiff_eq_self_of_disjoint (h : Disjoint s t) : s \ t = s :=
sdiff_eq_self_iff_disjoint.2 h
@@ -2089,10 +2159,11 @@ theorem mem_attach (s : Finset α) : ∀ x, x ∈ s.attach :=
theorem attach_empty : attach (∅ : Finset α) = ∅ :=
rfl
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem attach_nonempty_iff {s : Finset α} : s.attach.Nonempty ↔ s.Nonempty := by
simp [Finset.Nonempty]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
protected alias ⟨_, Nonempty.attach⟩ := attach_nonempty_iff
@[simp]
@@ -2310,7 +2381,7 @@ theorem filter_singleton (a : α) : filter p {a} = if p a then {a} else ∅ := b
split_ifs with h <;> by_cases h' : x = a <;> simp [h, h']
theorem filter_cons_of_pos (a : α) (s : Finset α) (ha : a ∉ s) (hp : p a) :
- filter p (cons a s ha) = cons a (filter p s) (mem_filter.not.mpr <| mt And.left ha) :=
+ filter p (cons a s ha) = cons a (filter p s) ((mem_of_mem_filter _).mt ha) :=
eq_of_veq <| Multiset.filter_cons_of_pos s.val hp
theorem filter_cons_of_neg (a : α) (s : Finset α) (ha : a ∉ s) (hp : ¬p a) :
@@ -2339,6 +2410,8 @@ theorem disjoint_filter_filter_neg (s t : Finset α) (p : α → Prop)
Disjoint (s.filter p) (t.filter fun a => ¬p a) :=
disjoint_filter_filter' s t disjoint_compl_right
+@[deprecated (since := "2024-10-01")] alias filter_inter_filter_neg_eq := disjoint_filter_filter_neg
+
theorem filter_disj_union (s : Finset α) (t : Finset α) (h : Disjoint s t) :
filter p (disjUnion s t h) = (filter p s).disjUnion (filter p t) (disjoint_filter_filter h) :=
eq_of_veq <| Multiset.filter_add _ _ _
@@ -2352,15 +2425,10 @@ lemma _root_.Set.pairwiseDisjoint_filter [DecidableEq β] (f : α → β) (s : S
theorem filter_cons {a : α} (s : Finset α) (ha : a ∉ s) :
filter p (cons a s ha) =
- (if p a then {a} else ∅ : Finset α).disjUnion (filter p s)
- (by
- split_ifs
- · rw [disjoint_singleton_left]
- exact mem_filter.not.mpr <| mt And.left ha
- · exact disjoint_empty_left _) := by
+ if p a then cons a (filter p s) ((mem_of_mem_filter _).mt ha) else filter p s := by
split_ifs with h
- · rw [filter_cons_of_pos _ _ _ ha h, singleton_disjUnion]
- · rw [filter_cons_of_neg _ _ _ ha h, empty_disjUnion]
+ · rw [filter_cons_of_pos _ _ _ ha h]
+ · rw [filter_cons_of_neg _ _ _ ha h]
section
variable [DecidableEq α]
@@ -2393,7 +2461,7 @@ theorem filter_insert (a : α) (s : Finset α) :
theorem filter_erase (a : α) (s : Finset α) : filter p (erase s a) = erase (filter p s) a := by
ext x
- simp only [and_assoc, mem_filter, iff_self_iff, mem_erase]
+ simp only [and_assoc, mem_filter, iff_self, mem_erase]
theorem filter_or (s : Finset α) : (s.filter fun a => p a ∨ q a) = s.filter p ∪ s.filter q :=
ext fun _ => by simp [mem_filter, mem_union, and_or_left]
@@ -2413,9 +2481,6 @@ lemma filter_and_not (s : Finset α) (p q : α → Prop) [DecidablePred p] [Deci
theorem sdiff_eq_filter (s₁ s₂ : Finset α) : s₁ \ s₂ = filter (· ∉ s₂) s₁ :=
ext fun _ => by simp [mem_sdiff, mem_filter]
-theorem sdiff_eq_self (s₁ s₂ : Finset α) : s₁ \ s₂ = s₁ ↔ s₁ ∩ s₂ ⊆ ∅ := by
- simp [Subset.antisymm_iff, disjoint_iff_inter_eq_empty]
-
theorem subset_union_elim {s : Finset α} {t₁ t₂ : Set α} (h : ↑s ⊆ t₁ ∪ t₂) :
∃ s₁ s₂ : Finset α, s₁ ∪ s₂ = s ∧ ↑s₁ ⊆ t₁ ∧ ↑s₂ ⊆ t₂ \ t₁ := by
classical
@@ -2463,7 +2528,7 @@ theorem filter_eq [DecidableEq β] (s : Finset β) (b : β) :
rintro rfl
exact ⟨h, rfl⟩
· ext
- simp only [mem_filter, not_and, iff_false_iff, not_mem_empty, decide_eq_true_eq]
+ simp only [mem_filter, not_and, iff_false, not_mem_empty, decide_eq_true_eq]
rintro m rfl
exact h m
@@ -2484,10 +2549,6 @@ theorem filter_ne [DecidableEq β] (s : Finset β) (b : β) :
theorem filter_ne' [DecidableEq β] (s : Finset β) (b : β) : (s.filter fun a => a ≠ b) = s.erase b :=
_root_.trans (filter_congr fun _ _ => by simp_rw [@ne_comm _ b]) (filter_ne s b)
-theorem filter_inter_filter_neg_eq (s t : Finset α) :
- (s.filter p ∩ t.filter fun a => ¬p a) = ∅ := by
- simpa using (disjoint_filter_filter_neg s t p).eq_bot
-
theorem filter_union_filter_of_codisjoint (s : Finset α) (h : Codisjoint p q) :
s.filter p ∪ s.filter q = s :=
(filter_or _ _ _).symm.trans <| filter_true_of_mem fun x _ => h.top_le x trivial
@@ -2498,6 +2559,8 @@ theorem filter_union_filter_neg_eq [∀ x, Decidable (¬p x)] (s : Finset α) :
end
+variable {p q}
+
lemma filter_inj : s.filter p = t.filter p ↔ ∀ ⦃a⦄, p a → (a ∈ s ↔ a ∈ t) := by
simp [Finset.ext_iff]
@@ -2511,6 +2574,8 @@ end Filter
section Range
+open Nat
+
variable {n m l : ℕ}
/-- `range n` is the set of natural numbers less than `n`. -/
@@ -2543,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
@@ -2568,15 +2631,19 @@ theorem mem_range_le {n x : ℕ} (hx : x ∈ range n) : x ≤ n :=
theorem mem_range_sub_ne_zero {n x : ℕ} (hx : x ∈ range n) : n - x ≠ 0 :=
_root_.ne_of_gt <| Nat.sub_pos_of_lt <| mem_range.1 hx
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem nonempty_range_iff : (range n).Nonempty ↔ n ≠ 0 :=
⟨fun ⟨k, hk⟩ => (k.zero_le.trans_lt <| mem_range.1 hk).ne',
fun h => ⟨0, mem_range.2 <| Nat.pos_iff_ne_zero.2 h⟩⟩
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+protected alias ⟨_, Aesop.range_nonempty⟩ := nonempty_range_iff
+
@[simp]
theorem range_eq_empty_iff : range n = ∅ ↔ n = 0 := by
rw [← not_nonempty_iff_eq_empty, nonempty_range_iff, not_not]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
theorem nonempty_range_succ : (range <| n + 1).Nonempty :=
nonempty_range_iff.2 n.succ_ne_zero
@@ -2591,11 +2658,15 @@ lemma range_nontrivial {n : ℕ} (hn : 1 < n) : (Finset.range n).Nontrivial := b
rw [Finset.Nontrivial, Finset.coe_range]
exact ⟨0, Nat.zero_lt_one.trans hn, 1, hn, Nat.zero_ne_one⟩
+theorem exists_nat_subset_range (s : Finset ℕ) : ∃ n : ℕ, s ⊆ range n :=
+ s.induction_on (by simp)
+ fun a _ _ ⟨n, hn⟩ => ⟨max (a + 1) n, insert_subset (by simp) (hn.trans (by simp))⟩
+
end Range
-- useful rules for calculations with quantifiers
theorem exists_mem_empty_iff (p : α → Prop) : (∃ x, x ∈ (∅ : Finset α) ∧ p x) ↔ False := by
- simp only [not_mem_empty, false_and_iff, exists_false]
+ simp only [not_mem_empty, false_and, exists_false]
theorem exists_mem_insert [DecidableEq α] (a : α) (s : Finset α) (p : α → Prop) :
(∃ x, x ∈ insert a s ∧ p x) ↔ p a ∨ ∃ x, x ∈ s ∧ p x := by
@@ -2623,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 : ℕ) :
@@ -2712,10 +2783,13 @@ theorem toFinset_union (s t : Multiset α) : (s ∪ t).toFinset = s.toFinset ∪
theorem toFinset_eq_empty {m : Multiset α} : m.toFinset = ∅ ↔ m = 0 :=
Finset.val_inj.symm.trans Multiset.dedup_eq_zero
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem toFinset_nonempty : s.toFinset.Nonempty ↔ s ≠ 0 := by
simp only [toFinset_eq_empty, Ne, Finset.nonempty_iff_ne_empty]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+protected alias ⟨_, Aesop.toFinset_nonempty_of_ne⟩ := toFinset_nonempty
+
@[simp]
theorem toFinset_subset : s.toFinset ⊆ t.toFinset ↔ s ⊆ t := by
simp only [Finset.subset_iff, Multiset.subset_iff, Multiset.mem_toFinset]
@@ -2758,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 α :=
@@ -2799,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 _)]
@@ -2845,10 +2932,13 @@ theorem toFinset_inter (l l' : List α) : (l ∩ l').toFinset = l.toFinset ∩ l
theorem toFinset_eq_empty_iff (l : List α) : l.toFinset = ∅ ↔ l = nil := by
cases l <;> simp
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem toFinset_nonempty_iff (l : List α) : l.toFinset.Nonempty ↔ l ≠ [] := by
simp [Finset.nonempty_iff_ne_empty]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, Aesop.toFinset_nonempty_of_ne⟩ := toFinset_nonempty_iff
+
@[simp]
theorem toFinset_filter (s : List α) (p : α → Bool) :
(s.filter p).toFinset = s.toFinset.filter (p ·) := by
@@ -2897,6 +2987,11 @@ theorem toList_toFinset [DecidableEq α] (s : Finset α) : s.toList.toFinset = s
ext
simp
+theorem _root_.List.toFinset_toList [DecidableEq α] {s : List α} (hs : s.Nodup) :
+ s.toFinset.toList.Perm s := by
+ apply List.perm_of_nodup_nodup_toFinset_eq (nodup_toList _) hs
+ rw [toList_toFinset]
+
@[simp]
theorem toList_eq_singleton_iff {a : α} {s : Finset α} : s.toList = [a] ↔ s = {a} := by
rw [toList, Multiset.toList_eq_singleton_iff, val_eq_singleton_iff]
@@ -2990,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) :
@@ -3046,6 +3141,8 @@ You can add lemmas to the rule-set by tagging them with either:
* `aesop safe apply (rule_sets := [finsetNonempty])` if they are always a good idea to follow or
* `aesop unsafe apply (rule_sets := [finsetNonempty])` if they risk directing the search to a blind
alley.
+
+TODO: should some of the lemmas be `aesop safe simp` instead?
-/
def proveFinsetNonempty {u : Level} {α : Q(Type u)} (s : Q(Finset $α)) :
MetaM (Option Q(Finset.Nonempty $s)) := do
@@ -3071,4 +3168,4 @@ def proveFinsetNonempty {u : Level} {α : Q(Type u)} (s : Q(Finset $α)) :
end Mathlib.Meta
-set_option linter.style.longFile 3100
+set_option linter.style.longFile 3200
diff --git a/Mathlib/Data/Finset/Card.lean b/Mathlib/Data/Finset/Card.lean
index ee90c07098ad8..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,71 +245,83 @@ 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]
-nonrec lemma card_lt_card (h : s ⊂ t) : s.card < t.card := card_lt_card <| val_lt_iff.2 h
+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 < #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
suffices _ : a ∈ s ↔ ∃ (i : _) (hi : i ∈ range n), f i (mem_range.1 hi) = a by
- simpa only [mem_image, mem_attach, true_and_iff, Subtype.exists]
+ simpa only [mem_image, mem_attach, true_and, Subtype.exists]
constructor
· 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 => ?_⟩
@@ -683,17 +700,22 @@ lemma exists_of_one_lt_card_pi {ι : Type*} {α : ι → Type*} [∀ i, Decidabl
obtain rfl | hne := eq_or_ne (a2 i) ai
exacts [⟨a1, h1, hne⟩, ⟨a2, h2, hne⟩]
+theorem card_eq_succ_iff_cons :
+ #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]
@@ -702,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]
@@ -715,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 α)]
@@ -725,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 -/
@@ -738,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)
@@ -784,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]
@@ -810,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]
@@ -826,6 +848,4 @@ theorem lt_wf {α} : WellFounded (@LT.lt (Finset α) _) :=
card_lt_card hxy
Subrelation.wf H <| InvImage.wf _ <| (Nat.lt_wfRel).2
-@[deprecated (since := "2023-12-27")] alias card_le_of_subset := card_le_card
-
end Finset
diff --git a/Mathlib/Data/Finset/Density.lean b/Mathlib/Data/Finset/Density.lean
index 43125f7fcc4f3..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
@@ -110,23 +111,23 @@ lemma dens_image [Fintype β] [DecidableEq β] {f : α → β} (hf : Bijective f
(s.image f).dens = s.dens := by
simpa [map_eq_image, -dens_map_equiv] using dens_map_equiv (.ofBijective f hf)
-lemma card_mul_dens (s : Finset α) : Fintype.card α * s.dens = s.card := by
+@[simp] lemma card_mul_dens (s : Finset α) : Fintype.card α * s.dens = s.card := by
cases isEmpty_or_nonempty α
· simp [Subsingleton.elim s ∅]
rw [dens, mul_div_cancel₀]
exact mod_cast Fintype.card_ne_zero
-lemma dens_mul_card (s : Finset α) : s.dens * Fintype.card α = s.card := by
+@[simp] lemma dens_mul_card (s : Finset α) : s.dens * Fintype.card α = s.card := by
rw [mul_comm, card_mul_dens]
section Semifield
variable [Semifield 𝕜] [CharZero 𝕜]
-lemma natCast_card_mul_nnratCast_dens (s : Finset α) : (Fintype.card α * s.dens : 𝕜) = s.card :=
- mod_cast s.card_mul_dens
+@[simp] lemma natCast_card_mul_nnratCast_dens (s : Finset α) :
+ (Fintype.card α * s.dens : 𝕜) = s.card := mod_cast s.card_mul_dens
-lemma nnratCast_dens_mul_natCast_card (s : Finset α) : s.dens * Fintype.card α = s.card :=
- mod_cast s.dens_mul_card
+@[simp] lemma nnratCast_dens_mul_natCast_card (s : Finset α) :
+ (s.dens * Fintype.card α : 𝕜) = s.card := mod_cast s.dens_mul_card
@[norm_cast] lemma nnratCast_dens (s : Finset α) : (s.dens : 𝕜) = s.card / Fintype.card α := by
simp [dens]
diff --git a/Mathlib/Data/Finset/Fin.lean b/Mathlib/Data/Finset/Fin.lean
index fbe5e4dd8b999..03b2036cefe0c 100644
--- a/Mathlib/Data/Finset/Fin.lean
+++ b/Mathlib/Data/Finset/Fin.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Chris Hughes, Scott Morrison, Johan Commelin
+Authors: Chris Hughes, Kim Morrison, Johan Commelin
-/
import Mathlib.Data.Finset.Card
diff --git a/Mathlib/Data/Finset/Finsupp.lean b/Mathlib/Data/Finset/Finsupp.lean
index 08de380f2d4b9..43e04648e3ccf 100644
--- a/Mathlib/Data/Finset/Finsupp.lean
+++ b/Mathlib/Data/Finset/Finsupp.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yaël Dillies
-/
import Mathlib.Algebra.BigOperators.Finsupp
-import Mathlib.Data.Finset.Pointwise.Basic
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
import Mathlib.Data.Finsupp.Indicator
import Mathlib.Data.Fintype.BigOperators
@@ -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 2ae78966a4cd7..219d4336368e2 100644
--- a/Mathlib/Data/Finset/Functor.lean
+++ b/Mathlib/Data/Finset/Functor.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2021 Yaël Dillies. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Yaël Dillies, Scott Morrison
+Authors: Yaël Dillies, Kim Morrison
-/
import Mathlib.Data.Finset.Lattice
import Mathlib.Data.Finset.NAry
@@ -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
@@ -198,11 +198,16 @@ theorem map_comp_coe (h : α → β) :
Functor.map h ∘ Multiset.toFinset = Multiset.toFinset ∘ Functor.map h :=
funext fun _ => image_toFinset
+@[simp]
+theorem map_comp_coe_apply (h : α → β) (s : Multiset α) :
+ s.toFinset.image h = (h <$> s).toFinset :=
+ congrFun (map_comp_coe h) s
+
theorem map_traverse (g : α → G β) (h : β → γ) (s : Finset α) :
Functor.map h <$> traverse g s = traverse (Functor.map h ∘ g) s := by
unfold traverse
- simp only [map_comp_coe, functor_norm]
- rw [LawfulFunctor.comp_map, Multiset.map_traverse]
+ simp only [Functor.map_map, fmap_def, map_comp_coe_apply, Multiset.fmap_def, ←
+ Multiset.map_traverse]
end Traversable
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 4008aa95219f0..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
@@ -242,10 +242,11 @@ theorem map_cons (f : α ↪ β) (a : α) (s : Finset α) (ha : a ∉ s) :
@[simp]
theorem map_eq_empty : s.map f = ∅ ↔ s = ∅ := (map_injective f).eq_iff' (map_empty f)
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem map_nonempty : (s.map f).Nonempty ↔ s.Nonempty :=
mod_cast Set.image_nonempty (f := f) (s := s)
+@[aesop safe apply (rule_sets := [finsetNonempty])]
protected alias ⟨_, Nonempty.map⟩ := map_nonempty
@[simp]
@@ -344,25 +345,16 @@ theorem _root_.Function.Injective.mem_finset_image (hf : Injective f) :
obtain ⟨y, hy, heq⟩ := mem_image.1 h
exact hf heq ▸ hy
-theorem filter_mem_image_eq_image (f : α → β) (s : Finset α) (t : Finset β) (h : ∀ x ∈ s, f x ∈ t) :
- (t.filter fun y => y ∈ s.image f) = s.image f := by
- ext
- simp only [mem_filter, mem_image, decide_eq_true_eq, and_iff_right_iff_imp, forall_exists_index,
- and_imp]
- rintro x xel rfl
- exact h _ xel
-
-theorem fiber_nonempty_iff_mem_image (f : α → β) (s : Finset α) (y : β) :
- (s.filter fun x => f x = y).Nonempty ↔ y ∈ s.image f := by simp [Finset.Nonempty]
@[simp, norm_cast]
theorem coe_image : ↑(s.image f) = f '' ↑s :=
Set.ext <| by simp only [mem_coe, mem_image, Set.mem_image, implies_true]
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
lemma image_nonempty : (s.image f).Nonempty ↔ s.Nonempty :=
mod_cast Set.image_nonempty (f := f) (s := (s : Set α))
+@[aesop safe apply (rule_sets := [finsetNonempty])]
protected theorem Nonempty.image (h : s.Nonempty) (f : α → β) : (s.image f).Nonempty :=
image_nonempty.2 h
@@ -439,6 +431,14 @@ theorem filter_image {p : β → Prop} [DecidablePred p] :
⟨by rintro ⟨⟨x, h1, rfl⟩, h2⟩; exact ⟨x, ⟨h1, h2⟩, rfl⟩,
by rintro ⟨x, ⟨h1, h2⟩, rfl⟩; exact ⟨⟨x, h1, rfl⟩, h2⟩⟩
+@[deprecated filter_mem_eq_inter (since := "2024-09-15")]
+theorem filter_mem_image_eq_image (f : α → β) (s : Finset α) (t : Finset β) (h : ∀ x ∈ s, f x ∈ t) :
+ (t.filter fun y => y ∈ s.image f) = s.image f := by
+ rwa [filter_mem_eq_inter, inter_eq_right, image_subset_iff]
+
+theorem fiber_nonempty_iff_mem_image {y : β} : (s.filter (f · = y)).Nonempty ↔ y ∈ s.image f := by
+ simp [Finset.Nonempty]
+
theorem image_union [DecidableEq α] {f : α → β} (s₁ s₂ : Finset α) :
(s₁ ∪ s₂).image f = s₁.image f ∪ s₂.image f :=
mod_cast Set.image_union f s₁ s₂
@@ -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 α} :
@@ -697,9 +697,23 @@ theorem fin_mono {n} : Monotone (Finset.fin n) := fun s t h x => by simpa using
theorem fin_map {n} {s : Finset ℕ} : (s.fin n).map Fin.valEmbedding = s.filter (· < n) := by
simp [Finset.fin, Finset.map_map]
+/--
+If a finset `t` is a subset of the image of another finset `s` under `f`, then it is equal to the
+image of a subset of `s`.
+
+For the version where `s` is a set, see `subset_set_image_iff`.
+-/
+theorem subset_image_iff [DecidableEq β] {s : Finset α} {t : Finset β} {f : α → β} :
+ t ⊆ s.image f ↔ ∃ s' : Finset α, s' ⊆ s ∧ s'.image f = t := by
+ refine ⟨fun ht => ?_, fun ⟨s', hs', h⟩ => h ▸ image_subset_image hs'⟩
+ refine ⟨s.filter (f · ∈ t), filter_subset _ _, le_antisymm (by simp [image_subset_iff]) ?_⟩
+ intro x hx
+ specialize ht hx
+ aesop
+
/-- If a `Finset` is a subset of the image of a `Set` under `f`,
then it is equal to the `Finset.image` of a `Finset` subset of that `Set`. -/
-theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
+theorem subset_set_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
constructor; swap
· rintro ⟨t, ht, rfl⟩
@@ -757,9 +771,3 @@ theorem finsetCongr_toEmbedding (e : α ≃ β) :
rfl
end Equiv
-
-namespace Finset
-
-@[deprecated (since := "2023-12-27")] alias image_filter := filter_image
-
-end Finset
diff --git a/Mathlib/Data/Finset/Lattice.lean b/Mathlib/Data/Finset/Lattice.lean
index 452204c7d625f..9db20f9663e09 100644
--- a/Mathlib/Data/Finset/Lattice.lean
+++ b/Mathlib/Data/Finset/Lattice.lean
@@ -5,17 +5,22 @@ Authors: Mario Carneiro
-/
import Mathlib.Algebra.Order.Monoid.Unbundled.Pow
import Mathlib.Data.Finset.Fold
-import Mathlib.Data.Finset.Option
import Mathlib.Data.Finset.Pi
import Mathlib.Data.Finset.Prod
import Mathlib.Data.Multiset.Lattice
import Mathlib.Data.Set.Lattice
import Mathlib.Order.Hom.Lattice
-import Mathlib.Order.Minimal
import Mathlib.Order.Nat
/-!
# Lattice operations on finsets
+
+This file is concerned with folding binary lattice operations over finsets.
+
+For the special case of maximum and minimum of a finset, see Max.lean.
+
+See also SetLattice.lean, which is instead concerned with how big lattice or set operations behave
+when indexed by a finset.
-/
assert_not_exists OrderedCommMonoid
@@ -125,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)
@@ -204,9 +210,6 @@ theorem _root_.List.foldr_sup_eq_sup_toFinset [DecidableEq α] (l : List α) :
theorem subset_range_sup_succ (s : Finset ℕ) : s ⊆ range (s.sup id).succ := fun _ hn =>
mem_range.2 <| Nat.lt_succ_of_le <| @le_sup _ _ _ _ _ id _ hn
-theorem exists_nat_subset_range (s : Finset ℕ) : ∃ n : ℕ, s ⊆ range n :=
- ⟨_, s.subset_range_sup_succ⟩
-
theorem sup_induction {p : α → Prop} (hb : p ⊥) (hp : ∀ a₁, p a₁ → ∀ a₂, p a₂ → p (a₁ ⊔ a₂))
(hs : ∀ b ∈ s, p (f b)) : p (s.sup f) := by
induction s using Finset.cons_induction with
@@ -220,7 +223,7 @@ theorem sup_le_of_le_directed {α : Type*} [SemilatticeSup α] [OrderBot α] (s
(∀ x ∈ t, ∃ y ∈ s, x ≤ y) → ∃ x ∈ s, t.sup id ≤ x := by
classical
induction' t using Finset.induction_on with a r _ ih h
- · simpa only [forall_prop_of_true, and_true_iff, forall_prop_of_false, bot_le, not_false_iff,
+ · simpa only [forall_prop_of_true, and_true, forall_prop_of_false, bot_le, not_false_iff,
sup_empty, forall_true_iff, not_mem_empty]
· intro h
have incs : (r : Set α) ⊆ ↑(insert a r) := by
@@ -352,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)
@@ -627,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⟩
@@ -704,7 +708,7 @@ theorem coe_sup' : ((s.sup' H f : α) : WithBot α) = s.sup ((↑) ∘ f) := by
@[simp]
theorem sup'_cons {b : β} {hb : b ∉ s} :
- (cons b s hb).sup' (nonempty_cons hb) f = f b ⊔ s.sup' H f := by
+ (cons b s hb).sup' (cons_nonempty hb) f = f b ⊔ s.sup' H f := by
rw [← WithBot.coe_eq_coe]
simp [WithBot.coe_sup]
@@ -730,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
@@ -812,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 }
@@ -873,7 +881,7 @@ theorem coe_inf' : ((s.inf' H f : α) : WithTop α) = s.inf ((↑) ∘ f) :=
@[simp]
theorem inf'_cons {b : β} {hb : b ∉ s} :
- (cons b s hb).inf' (nonempty_cons hb) f = f b ⊓ s.inf' H f :=
+ (cons b s hb).inf' (cons_nonempty hb) f = f b ⊓ s.inf' H f :=
@sup'_cons αᵒᵈ _ _ _ H f _ _
@[simp]
@@ -898,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
@@ -964,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 }
@@ -1155,529 +1166,6 @@ theorem exists_mem_eq_inf [OrderTop α] (s : Finset ι) (h : s.Nonempty) (f : ι
end LinearOrder
-/-! ### max and min of finite sets -/
-
-
-section MaxMin
-
-variable [LinearOrder α]
-
-/-- Let `s` be a finset in a linear order. Then `s.max` is the maximum of `s` if `s` is not empty,
-and `⊥` otherwise. It belongs to `WithBot α`. If you want to get an element of `α`, see
-`s.max'`. -/
-protected def max (s : Finset α) : WithBot α :=
- sup s (↑)
-
-theorem max_eq_sup_coe {s : Finset α} : s.max = s.sup (↑) :=
- rfl
-
-theorem max_eq_sup_withBot (s : Finset α) : s.max = sup s (↑) :=
- rfl
-
-@[simp]
-theorem max_empty : (∅ : Finset α).max = ⊥ :=
- rfl
-
-@[simp]
-theorem max_insert {a : α} {s : Finset α} : (insert a s).max = max ↑a s.max :=
- fold_insert_idem
-
-@[simp]
-theorem max_singleton {a : α} : Finset.max {a} = (a : WithBot α) := by
- rw [← insert_emptyc_eq]
- exact max_insert
-
-theorem max_of_mem {s : Finset α} {a : α} (h : a ∈ s) : ∃ b : α, s.max = b := by
- obtain ⟨b, h, _⟩ := le_sup (α := WithBot α) h _ rfl
- exact ⟨b, h⟩
-
-theorem max_of_nonempty {s : Finset α} (h : s.Nonempty) : ∃ a : α, s.max = a :=
- let ⟨_, h⟩ := h
- max_of_mem h
-
-theorem max_eq_bot {s : Finset α} : s.max = ⊥ ↔ s = ∅ :=
- ⟨fun h ↦ s.eq_empty_or_nonempty.elim id fun H ↦ by
- obtain ⟨a, ha⟩ := max_of_nonempty H
- rw [h] at ha; cases ha; , -- the `;` is needed since the `cases` syntax allows `cases a, b`
- fun h ↦ h.symm ▸ max_empty⟩
-
-theorem mem_of_max {s : Finset α} : ∀ {a : α}, s.max = a → a ∈ s := by
- induction' s using Finset.induction_on with b s _ ih
- · intro _ H; cases H
- · intro a h
- by_cases p : b = a
- · induction p
- exact mem_insert_self b s
- · cases' max_choice (↑b) s.max with q q <;> rw [max_insert, q] at h
- · cases h
- cases p rfl
- · exact mem_insert_of_mem (ih h)
-
-theorem le_max {a : α} {s : Finset α} (as : a ∈ s) : ↑a ≤ s.max :=
- le_sup as
-
-theorem not_mem_of_max_lt_coe {a : α} {s : Finset α} (h : s.max < a) : a ∉ s :=
- mt le_max h.not_le
-
-theorem le_max_of_eq {s : Finset α} {a b : α} (h₁ : a ∈ s) (h₂ : s.max = b) : a ≤ b :=
- WithBot.coe_le_coe.mp <| (le_max h₁).trans h₂.le
-
-theorem not_mem_of_max_lt {s : Finset α} {a b : α} (h₁ : b < a) (h₂ : s.max = ↑b) : a ∉ s :=
- Finset.not_mem_of_max_lt_coe <| h₂.trans_lt <| WithBot.coe_lt_coe.mpr h₁
-
-@[gcongr]
-theorem max_mono {s t : Finset α} (st : s ⊆ t) : s.max ≤ t.max :=
- sup_mono st
-
-protected theorem max_le {M : WithBot α} {s : Finset α} (st : ∀ a ∈ s, (a : WithBot α) ≤ M) :
- s.max ≤ M :=
- Finset.sup_le st
-
-@[simp]
-protected lemma max_le_iff {m : WithBot α} {s : Finset α} : s.max ≤ m ↔ ∀ a ∈ s, a ≤ m :=
- Finset.sup_le_iff
-
-@[simp]
-protected lemma max_eq_top [OrderTop α] {s : Finset α} : s.max = ⊤ ↔ ⊤ ∈ s :=
- Finset.sup_eq_top_iff.trans <| by simp
-
-/-- Let `s` be a finset in a linear order. Then `s.min` is the minimum of `s` if `s` is not empty,
-and `⊤` otherwise. It belongs to `WithTop α`. If you want to get an element of `α`, see
-`s.min'`. -/
-protected def min (s : Finset α) : WithTop α :=
- inf s (↑)
-
-theorem min_eq_inf_withTop (s : Finset α) : s.min = inf s (↑) :=
- rfl
-
-@[simp]
-theorem min_empty : (∅ : Finset α).min = ⊤ :=
- rfl
-
-@[simp]
-theorem min_insert {a : α} {s : Finset α} : (insert a s).min = min (↑a) s.min :=
- fold_insert_idem
-
-@[simp]
-theorem min_singleton {a : α} : Finset.min {a} = (a : WithTop α) := by
- rw [← insert_emptyc_eq]
- exact min_insert
-
-theorem min_of_mem {s : Finset α} {a : α} (h : a ∈ s) : ∃ b : α, s.min = b := by
- obtain ⟨b, h, _⟩ := inf_le (α := WithTop α) h _ rfl
- exact ⟨b, h⟩
-
-theorem min_of_nonempty {s : Finset α} (h : s.Nonempty) : ∃ a : α, s.min = a :=
- let ⟨_, h⟩ := h
- min_of_mem h
-
-@[simp]
-theorem min_eq_top {s : Finset α} : s.min = ⊤ ↔ s = ∅ := by
- simp [Finset.min, eq_empty_iff_forall_not_mem]
-
-theorem mem_of_min {s : Finset α} : ∀ {a : α}, s.min = a → a ∈ s :=
- @mem_of_max αᵒᵈ _ s
-
-theorem min_le {a : α} {s : Finset α} (as : a ∈ s) : s.min ≤ a :=
- inf_le as
-
-theorem not_mem_of_coe_lt_min {a : α} {s : Finset α} (h : ↑a < s.min) : a ∉ s :=
- mt min_le h.not_le
-
-theorem min_le_of_eq {s : Finset α} {a b : α} (h₁ : b ∈ s) (h₂ : s.min = a) : a ≤ b :=
- WithTop.coe_le_coe.mp <| h₂.ge.trans (min_le h₁)
-
-theorem not_mem_of_lt_min {s : Finset α} {a b : α} (h₁ : a < b) (h₂ : s.min = ↑b) : a ∉ s :=
- Finset.not_mem_of_coe_lt_min <| (WithTop.coe_lt_coe.mpr h₁).trans_eq h₂.symm
-
-@[gcongr]
-theorem min_mono {s t : Finset α} (st : s ⊆ t) : t.min ≤ s.min :=
- inf_mono st
-
-protected theorem le_min {m : WithTop α} {s : Finset α} (st : ∀ a : α, a ∈ s → m ≤ a) : m ≤ s.min :=
- Finset.le_inf st
-
-@[simp]
-protected theorem le_min_iff {m : WithTop α} {s : Finset α} : m ≤ s.min ↔ ∀ a ∈ s, m ≤ a :=
- Finset.le_inf_iff
-
-@[simp]
-protected theorem min_eq_bot [OrderBot α] {s : Finset α} : s.min = ⊥ ↔ ⊥ ∈ s :=
- Finset.max_eq_top (α := αᵒᵈ)
-
-/-- Given a nonempty finset `s` in a linear order `α`, then `s.min' H` is its minimum, as an
-element of `α`, where `H` is a proof of nonemptiness. Without this assumption, use instead `s.min`,
-taking values in `WithTop α`. -/
-def min' (s : Finset α) (H : s.Nonempty) : α :=
- inf' s H id
-
-/-- Given a nonempty finset `s` in a linear order `α`, then `s.max' H` is its maximum, as an
-element of `α`, where `H` is a proof of nonemptiness. Without this assumption, use instead `s.max`,
-taking values in `WithBot α`. -/
-def max' (s : Finset α) (H : s.Nonempty) : α :=
- sup' s H id
-
-variable (s : Finset α) (H : s.Nonempty) {x : α}
-
-theorem min'_mem : s.min' H ∈ s :=
- mem_of_min <| by simp only [Finset.min, min', id_eq, coe_inf']; rfl
-
-theorem min'_le (x) (H2 : x ∈ s) : s.min' ⟨x, H2⟩ ≤ x :=
- min_le_of_eq H2 (WithTop.coe_untop _ _).symm
-
-theorem le_min' (x) (H2 : ∀ y ∈ s, x ≤ y) : x ≤ s.min' H :=
- H2 _ <| min'_mem _ _
-
-theorem isLeast_min' : IsLeast (↑s) (s.min' H) :=
- ⟨min'_mem _ _, min'_le _⟩
-
-@[simp]
-theorem le_min'_iff {x} : x ≤ s.min' H ↔ ∀ y ∈ s, x ≤ y :=
- le_isGLB_iff (isLeast_min' s H).isGLB
-
-/-- `{a}.min' _` is `a`. -/
-@[simp]
-theorem min'_singleton (a : α) : ({a} : Finset α).min' (singleton_nonempty _) = a := by simp [min']
-
-theorem max'_mem : s.max' H ∈ s :=
- mem_of_max <| by simp only [max', Finset.max, id_eq, coe_sup']; rfl
-
-theorem le_max' (x) (H2 : x ∈ s) : x ≤ s.max' ⟨x, H2⟩ :=
- le_max_of_eq H2 (WithBot.coe_unbot _ _).symm
-
-theorem max'_le (x) (H2 : ∀ y ∈ s, y ≤ x) : s.max' H ≤ x :=
- H2 _ <| max'_mem _ _
-
-theorem isGreatest_max' : IsGreatest (↑s) (s.max' H) :=
- ⟨max'_mem _ _, le_max' _⟩
-
-@[simp]
-theorem max'_le_iff {x} : s.max' H ≤ x ↔ ∀ y ∈ s, y ≤ x :=
- isLUB_le_iff (isGreatest_max' s H).isLUB
-
-@[simp]
-theorem max'_lt_iff {x} : s.max' H < x ↔ ∀ y ∈ s, y < x :=
- ⟨fun Hlt y hy => (s.le_max' y hy).trans_lt Hlt, fun H => H _ <| s.max'_mem _⟩
-
-@[simp]
-theorem lt_min'_iff : x < s.min' H ↔ ∀ y ∈ s, x < y :=
- @max'_lt_iff αᵒᵈ _ _ H _
-
-theorem max'_eq_sup' : s.max' H = s.sup' H id := rfl
-
-theorem min'_eq_inf' : s.min' H = s.inf' H id := rfl
-
-/-- `{a}.max' _` is `a`. -/
-@[simp]
-theorem max'_singleton (a : α) : ({a} : Finset α).max' (singleton_nonempty _) = a := by simp [max']
-
-theorem min'_lt_max' {i j} (H1 : i ∈ s) (H2 : j ∈ s) (H3 : i ≠ j) :
- s.min' ⟨i, H1⟩ < s.max' ⟨i, H1⟩ :=
- isGLB_lt_isLUB_of_ne (s.isLeast_min' _).isGLB (s.isGreatest_max' _).isLUB H1 H2 H3
-
-/-- If there's more than 1 element, the min' is less than the max'. An alternate version of
-`min'_lt_max'` which is sometimes more convenient.
--/
-theorem min'_lt_max'_of_card (h₂ : 1 < card s) :
- s.min' (Finset.card_pos.1 <| by omega) < s.max' (Finset.card_pos.1 <| by omega) := by
- rcases one_lt_card.1 h₂ with ⟨a, ha, b, hb, hab⟩
- exact s.min'_lt_max' ha hb hab
-
-theorem map_ofDual_min (s : Finset αᵒᵈ) : s.min.map ofDual = (s.image ofDual).max := by
- rw [max_eq_sup_withBot, sup_image]
- exact congr_fun Option.map_id _
-
-theorem map_ofDual_max (s : Finset αᵒᵈ) : s.max.map ofDual = (s.image ofDual).min := by
- rw [min_eq_inf_withTop, inf_image]
- exact congr_fun Option.map_id _
-
-theorem map_toDual_min (s : Finset α) : s.min.map toDual = (s.image toDual).max := by
- rw [max_eq_sup_withBot, sup_image]
- exact congr_fun Option.map_id _
-
-theorem map_toDual_max (s : Finset α) : s.max.map toDual = (s.image toDual).min := by
- rw [min_eq_inf_withTop, inf_image]
- exact congr_fun Option.map_id _
-
--- Porting note: new proofs without `convert` for the next four theorems.
-
-theorem ofDual_min' {s : Finset αᵒᵈ} (hs : s.Nonempty) :
- ofDual (min' s hs) = max' (s.image ofDual) (hs.image _) := by
- rw [← WithBot.coe_eq_coe]
- simp only [min'_eq_inf', id_eq, ofDual_inf', Function.comp_apply, coe_sup', max'_eq_sup',
- sup_image]
- rfl
-
-theorem ofDual_max' {s : Finset αᵒᵈ} (hs : s.Nonempty) :
- ofDual (max' s hs) = min' (s.image ofDual) (hs.image _) := by
- rw [← WithTop.coe_eq_coe]
- simp only [max'_eq_sup', id_eq, ofDual_sup', Function.comp_apply, coe_inf', min'_eq_inf',
- inf_image]
- rfl
-
-theorem toDual_min' {s : Finset α} (hs : s.Nonempty) :
- toDual (min' s hs) = max' (s.image toDual) (hs.image _) := by
- rw [← WithBot.coe_eq_coe]
- simp only [min'_eq_inf', id_eq, toDual_inf', Function.comp_apply, coe_sup', max'_eq_sup',
- sup_image]
- rfl
-
-theorem toDual_max' {s : Finset α} (hs : s.Nonempty) :
- toDual (max' s hs) = min' (s.image toDual) (hs.image _) := by
- rw [← WithTop.coe_eq_coe]
- simp only [max'_eq_sup', id_eq, toDual_sup', Function.comp_apply, coe_inf', min'_eq_inf',
- inf_image]
- rfl
-
-theorem max'_subset {s t : Finset α} (H : s.Nonempty) (hst : s ⊆ t) :
- s.max' H ≤ t.max' (H.mono hst) :=
- le_max' _ _ (hst (s.max'_mem H))
-
-theorem min'_subset {s t : Finset α} (H : s.Nonempty) (hst : s ⊆ t) :
- t.min' (H.mono hst) ≤ s.min' H :=
- min'_le _ _ (hst (s.min'_mem H))
-
-theorem max'_insert (a : α) (s : Finset α) (H : s.Nonempty) :
- (insert a s).max' (s.insert_nonempty a) = max (s.max' H) a :=
- (isGreatest_max' _ _).unique <| by
- rw [coe_insert, max_comm]
- exact (isGreatest_max' _ _).insert _
-
-theorem min'_insert (a : α) (s : Finset α) (H : s.Nonempty) :
- (insert a s).min' (s.insert_nonempty a) = min (s.min' H) a :=
- (isLeast_min' _ _).unique <| by
- rw [coe_insert, min_comm]
- exact (isLeast_min' _ _).insert _
-
-theorem lt_max'_of_mem_erase_max' [DecidableEq α] {a : α} (ha : a ∈ s.erase (s.max' H)) :
- a < s.max' H :=
- lt_of_le_of_ne (le_max' _ _ (mem_of_mem_erase ha)) <| ne_of_mem_of_not_mem ha <| not_mem_erase _ _
-
-theorem min'_lt_of_mem_erase_min' [DecidableEq α] {a : α} (ha : a ∈ s.erase (s.min' H)) :
- s.min' H < a :=
- @lt_max'_of_mem_erase_max' αᵒᵈ _ s H _ a ha
-
-/-- To rewrite from right to left, use `Monotone.map_finset_max'`. -/
-@[simp]
-theorem max'_image [LinearOrder β] {f : α → β} (hf : Monotone f) (s : Finset α)
- (h : (s.image f).Nonempty) : (s.image f).max' h = f (s.max' h.of_image) := by
- simp only [max', sup'_image]
- exact .symm <| comp_sup'_eq_sup'_comp _ _ fun _ _ ↦ hf.map_max
-
-/-- A version of `Finset.max'_image` with LHS and RHS reversed.
-Also, this version assumes that `s` is nonempty, not its image. -/
-lemma _root_.Monotone.map_finset_max' [LinearOrder β] {f : α → β} (hf : Monotone f) {s : Finset α}
- (h : s.Nonempty) : f (s.max' h) = (s.image f).max' (h.image f) :=
- .symm <| max'_image hf ..
-
-/-- To rewrite from right to left, use `Monotone.map_finset_min'`. -/
-@[simp]
-theorem min'_image [LinearOrder β] {f : α → β} (hf : Monotone f) (s : Finset α)
- (h : (s.image f).Nonempty) : (s.image f).min' h = f (s.min' h.of_image) := by
- simp only [min', inf'_image]
- exact .symm <| comp_inf'_eq_inf'_comp _ _ fun _ _ ↦ hf.map_min
-
-/-- A version of `Finset.min'_image` with LHS and RHS reversed.
-Also, this version assumes that `s` is nonempty, not its image. -/
-lemma _root_.Monotone.map_finset_min' [LinearOrder β] {f : α → β} (hf : Monotone f) {s : Finset α}
- (h : s.Nonempty) : f (s.min' h) = (s.image f).min' (h.image f) :=
- .symm <| min'_image hf ..
-
-theorem coe_max' {s : Finset α} (hs : s.Nonempty) : ↑(s.max' hs) = s.max :=
- coe_sup' hs id
-
-theorem coe_min' {s : Finset α} (hs : s.Nonempty) : ↑(s.min' hs) = s.min :=
- coe_inf' hs id
-
-theorem max_mem_image_coe {s : Finset α} (hs : s.Nonempty) :
- s.max ∈ (s.image (↑) : Finset (WithBot α)) :=
- mem_image.2 ⟨max' s hs, max'_mem _ _, coe_max' hs⟩
-
-theorem min_mem_image_coe {s : Finset α} (hs : s.Nonempty) :
- s.min ∈ (s.image (↑) : Finset (WithTop α)) :=
- mem_image.2 ⟨min' s hs, min'_mem _ _, coe_min' hs⟩
-
-theorem max_mem_insert_bot_image_coe (s : Finset α) :
- s.max ∈ (insert ⊥ (s.image (↑)) : Finset (WithBot α)) :=
- mem_insert.2 <| s.eq_empty_or_nonempty.imp max_eq_bot.2 max_mem_image_coe
-
-theorem min_mem_insert_top_image_coe (s : Finset α) :
- s.min ∈ (insert ⊤ (s.image (↑)) : Finset (WithTop α)) :=
- mem_insert.2 <| s.eq_empty_or_nonempty.imp min_eq_top.2 min_mem_image_coe
-
-theorem max'_erase_ne_self {s : Finset α} (s0 : (s.erase x).Nonempty) : (s.erase x).max' s0 ≠ x :=
- ne_of_mem_erase (max'_mem _ s0)
-
-theorem min'_erase_ne_self {s : Finset α} (s0 : (s.erase x).Nonempty) : (s.erase x).min' s0 ≠ x :=
- ne_of_mem_erase (min'_mem _ s0)
-
-theorem max_erase_ne_self {s : Finset α} : (s.erase x).max ≠ x := by
- by_cases s0 : (s.erase x).Nonempty
- · refine ne_of_eq_of_ne (coe_max' s0).symm ?_
- exact WithBot.coe_eq_coe.not.mpr (max'_erase_ne_self _)
- · rw [not_nonempty_iff_eq_empty.mp s0, max_empty]
- exact WithBot.bot_ne_coe
-
-theorem min_erase_ne_self {s : Finset α} : (s.erase x).min ≠ x := by
- -- Porting note: old proof `convert @max_erase_ne_self αᵒᵈ _ _ _`
- convert @max_erase_ne_self αᵒᵈ _ (toDual x) (s.map toDual.toEmbedding) using 1
- apply congr_arg -- Porting note: forces unfolding to see `Finset.min` is `Finset.max`
- congr!
- ext; simp only [mem_map_equiv]; exact Iff.rfl
-
-theorem exists_next_right {x : α} {s : Finset α} (h : ∃ y ∈ s, x < y) :
- ∃ y ∈ s, x < y ∧ ∀ z ∈ s, x < z → y ≤ z :=
- have Hne : (s.filter (x < ·)).Nonempty := h.imp fun y hy => mem_filter.2 (by simpa)
- have aux := mem_filter.1 (min'_mem _ Hne)
- ⟨min' _ Hne, aux.1, by simp, fun z hzs hz => min'_le _ _ <| mem_filter.2 ⟨hzs, by simpa⟩⟩
-
-theorem exists_next_left {x : α} {s : Finset α} (h : ∃ y ∈ s, y < x) :
- ∃ y ∈ s, y < x ∧ ∀ z ∈ s, z < x → z ≤ y :=
- @exists_next_right αᵒᵈ _ x s h
-
-/-- If finsets `s` and `t` are interleaved, then `Finset.card s ≤ Finset.card t + 1`. -/
-theorem card_le_of_interleaved {s t : Finset α}
- (h : ∀ᵉ (x ∈ s) (y ∈ s),
- x < y → (∀ z ∈ s, z ∉ Set.Ioo x y) → ∃ z ∈ t, x < z ∧ z < y) :
- s.card ≤ t.card + 1 := by
- replace h : ∀ᵉ (x ∈ s) (y ∈ s), x < y → ∃ z ∈ t, x < z ∧ z < y := by
- intro x hx y hy hxy
- rcases exists_next_right ⟨y, hy, hxy⟩ with ⟨a, has, hxa, ha⟩
- rcases h x hx a has hxa fun z hzs hz => hz.2.not_le <| ha _ hzs hz.1 with ⟨b, hbt, hxb, hba⟩
- exact ⟨b, hbt, hxb, hba.trans_le <| ha _ hy hxy⟩
- set f : α → WithTop α := fun x => (t.filter fun y => x < y).min
- have f_mono : StrictMonoOn f s := by
- intro x hx y hy hxy
- rcases h x hx y hy hxy with ⟨a, hat, hxa, hay⟩
- calc
- f x ≤ a := min_le (mem_filter.2 ⟨hat, by simpa⟩)
- _ < f y :=
- (Finset.lt_inf_iff <| WithTop.coe_lt_top a).2 fun b hb =>
- WithTop.coe_lt_coe.2 <| hay.trans (by simpa using (mem_filter.1 hb).2)
-
- calc
- s.card = (s.image f).card := (card_image_of_injOn f_mono.injOn).symm
- _ ≤ (insert ⊤ (t.image (↑)) : Finset (WithTop α)).card :=
- card_mono <| image_subset_iff.2 fun x _ =>
- insert_subset_insert _ (image_subset_image <| filter_subset _ _)
- (min_mem_insert_top_image_coe _)
- _ ≤ t.card + 1 := (card_insert_le _ _).trans (Nat.add_le_add_right card_image_le _)
-
-/-- If finsets `s` and `t` are interleaved, then `Finset.card s ≤ Finset.card (t \ s) + 1`. -/
-theorem card_le_diff_of_interleaved {s t : Finset α}
- (h :
- ∀ᵉ (x ∈ s) (y ∈ s),
- x < y → (∀ z ∈ s, z ∉ Set.Ioo x y) → ∃ z ∈ t, x < z ∧ z < y) :
- s.card ≤ (t \ s).card + 1 :=
- card_le_of_interleaved fun x hx y hy hxy hs =>
- let ⟨z, hzt, hxz, hzy⟩ := h x hx y hy hxy hs
- ⟨z, mem_sdiff.2 ⟨hzt, fun hzs => hs z hzs ⟨hxz, hzy⟩⟩, hxz, hzy⟩
-
-/-- Induction principle for `Finset`s in a linearly ordered type: a predicate is true on all
-`s : Finset α` provided that:
-
-* it is true on the empty `Finset`,
-* for every `s : Finset α` and an element `a` strictly greater than all elements of `s`, `p s`
- implies `p (insert a s)`. -/
-@[elab_as_elim]
-theorem induction_on_max [DecidableEq α] {p : Finset α → Prop} (s : Finset α) (h0 : p ∅)
- (step : ∀ a s, (∀ x ∈ s, x < a) → p s → p (insert a s)) : p s := by
- induction' s using Finset.strongInductionOn with s ihs
- rcases s.eq_empty_or_nonempty with (rfl | hne)
- · exact h0
- · have H : s.max' hne ∈ s := max'_mem s hne
- rw [← insert_erase H]
- exact step _ _ (fun x => s.lt_max'_of_mem_erase_max' hne) (ihs _ <| erase_ssubset H)
-
-/-- Induction principle for `Finset`s in a linearly ordered type: a predicate is true on all
-`s : Finset α` provided that:
-
-* it is true on the empty `Finset`,
-* for every `s : Finset α` and an element `a` strictly less than all elements of `s`, `p s`
- implies `p (insert a s)`. -/
-@[elab_as_elim]
-theorem induction_on_min [DecidableEq α] {p : Finset α → Prop} (s : Finset α) (h0 : p ∅)
- (step : ∀ a s, (∀ x ∈ s, a < x) → p s → p (insert a s)) : p s :=
- @induction_on_max αᵒᵈ _ _ _ s h0 step
-
-end MaxMin
-
-section MaxMinInductionValue
-
-variable [LinearOrder α] [LinearOrder β]
-
-/-- Induction principle for `Finset`s in any type from which a given function `f` maps to a linearly
-ordered type : a predicate is true on all `s : Finset α` provided that:
-
-* it is true on the empty `Finset`,
-* for every `s : Finset α` and an element `a` such that for elements of `s` denoted by `x` we have
- `f x ≤ f a`, `p s` implies `p (insert a s)`. -/
-@[elab_as_elim]
-theorem induction_on_max_value [DecidableEq ι] (f : ι → α) {p : Finset ι → Prop} (s : Finset ι)
- (h0 : p ∅) (step : ∀ a s, a ∉ s → (∀ x ∈ s, f x ≤ f a) → p s → p (insert a s)) : p s := by
- induction' s using Finset.strongInductionOn with s ihs
- rcases (s.image f).eq_empty_or_nonempty with (hne | hne)
- · simp only [image_eq_empty] at hne
- simp only [hne, h0]
- · have H : (s.image f).max' hne ∈ s.image f := max'_mem (s.image f) hne
- simp only [mem_image, exists_prop] at H
- rcases H with ⟨a, has, hfa⟩
- rw [← insert_erase has]
- refine step _ _ (not_mem_erase a s) (fun x hx => ?_) (ihs _ <| erase_ssubset has)
- rw [hfa]
- exact le_max' _ _ (mem_image_of_mem _ <| mem_of_mem_erase hx)
-
-/-- Induction principle for `Finset`s in any type from which a given function `f` maps to a linearly
-ordered type : a predicate is true on all `s : Finset α` provided that:
-
-* it is true on the empty `Finset`,
-* for every `s : Finset α` and an element `a` such that for elements of `s` denoted by `x` we have
- `f a ≤ f x`, `p s` implies `p (insert a s)`. -/
-@[elab_as_elim]
-theorem induction_on_min_value [DecidableEq ι] (f : ι → α) {p : Finset ι → Prop} (s : Finset ι)
- (h0 : p ∅) (step : ∀ a s, a ∉ s → (∀ x ∈ s, f a ≤ f x) → p s → p (insert a s)) : p s :=
- @induction_on_max_value αᵒᵈ ι _ _ _ _ s h0 step
-
-end MaxMinInductionValue
-
-section ExistsMaxMin
-
-variable [LinearOrder α]
-
-theorem exists_max_image (s : Finset β) (f : β → α) (h : s.Nonempty) :
- ∃ x ∈ s, ∀ x' ∈ s, f x' ≤ f x := by
- cases' max_of_nonempty (h.image f) with y hy
- rcases mem_image.mp (mem_of_max hy) with ⟨x, hx, rfl⟩
- exact ⟨x, hx, fun x' hx' => le_max_of_eq (mem_image_of_mem f hx') hy⟩
-
-theorem exists_min_image (s : Finset β) (f : β → α) (h : s.Nonempty) :
- ∃ x ∈ s, ∀ x' ∈ s, f x ≤ f x' :=
- @exists_max_image αᵒᵈ β _ s f h
-
-end ExistsMaxMin
-
-theorem isGLB_iff_isLeast [LinearOrder α] (i : α) (s : Finset α) (hs : s.Nonempty) :
- IsGLB (s : Set α) i ↔ IsLeast (↑s) i := by
- refine ⟨fun his => ?_, IsLeast.isGLB⟩
- suffices i = min' s hs by
- rw [this]
- exact isLeast_min' s hs
- rw [IsGLB, IsGreatest, mem_lowerBounds, mem_upperBounds] at his
- exact le_antisymm (his.1 (Finset.min' s hs) (Finset.min'_mem s hs)) (his.2 _ (Finset.min'_le s))
-
-theorem isLUB_iff_isGreatest [LinearOrder α] (i : α) (s : Finset α) (hs : s.Nonempty) :
- IsLUB (s : Set α) i ↔ IsGreatest (↑s) i :=
- @isGLB_iff_isLeast αᵒᵈ _ i s hs
-
-theorem isGLB_mem [LinearOrder α] {i : α} (s : Finset α) (his : IsGLB (s : Set α) i)
- (hs : s.Nonempty) : i ∈ s := by
- rw [← mem_coe]
- exact ((isGLB_iff_isLeast i s hs).mp his).1
-
-theorem isLUB_mem [LinearOrder α] {i : α} (s : Finset α) (his : IsLUB (s : Set α) i)
- (hs : s.Nonempty) : i ∈ s :=
- @isGLB_mem αᵒᵈ _ i s his hs
-
end Finset
namespace Multiset
@@ -1702,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
@@ -1715,241 +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
-
-section Lattice
-
-variable {ι' : Sort*} [CompleteLattice α]
-
-/-- Supremum of `s i`, `i : ι`, is equal to the supremum over `t : Finset ι` of suprema
-`⨆ i ∈ t, s i`. This version assumes `ι` is a `Type*`. See `iSup_eq_iSup_finset'` for a version
-that works for `ι : Sort*`. -/
-theorem iSup_eq_iSup_finset (s : ι → α) : ⨆ i, s i = ⨆ t : Finset ι, ⨆ i ∈ t, s i := by
- classical
- refine le_antisymm ?_ ?_
- · exact iSup_le fun b => le_iSup_of_le {b} <| le_iSup_of_le b <| le_iSup_of_le (by simp) <| le_rfl
- · exact iSup_le fun t => iSup_le fun b => iSup_le fun _ => le_iSup _ _
-
-/-- Supremum of `s i`, `i : ι`, is equal to the supremum over `t : Finset ι` of suprema
-`⨆ i ∈ t, s i`. This version works for `ι : Sort*`. See `iSup_eq_iSup_finset` for a version
-that assumes `ι : Type*` but has no `PLift`s. -/
-theorem iSup_eq_iSup_finset' (s : ι' → α) :
- ⨆ i, s i = ⨆ t : Finset (PLift ι'), ⨆ i ∈ t, s (PLift.down i) := by
- rw [← iSup_eq_iSup_finset, ← Equiv.plift.surjective.iSup_comp]; rfl
-
-/-- Infimum of `s i`, `i : ι`, is equal to the infimum over `t : Finset ι` of infima
-`⨅ i ∈ t, s i`. This version assumes `ι` is a `Type*`. See `iInf_eq_iInf_finset'` for a version
-that works for `ι : Sort*`. -/
-theorem iInf_eq_iInf_finset (s : ι → α) : ⨅ i, s i = ⨅ (t : Finset ι) (i ∈ t), s i :=
- @iSup_eq_iSup_finset αᵒᵈ _ _ _
-
-/-- Infimum of `s i`, `i : ι`, is equal to the infimum over `t : Finset ι` of infima
-`⨅ i ∈ t, s i`. This version works for `ι : Sort*`. See `iInf_eq_iInf_finset` for a version
-that assumes `ι : Type*` but has no `PLift`s. -/
-theorem iInf_eq_iInf_finset' (s : ι' → α) :
- ⨅ i, s i = ⨅ t : Finset (PLift ι'), ⨅ i ∈ t, s (PLift.down i) :=
- @iSup_eq_iSup_finset' αᵒᵈ _ _ _
-
-end Lattice
-
-namespace Set
-
-variable {ι' : Sort*}
-
-/-- Union of an indexed family of sets `s : ι → Set α` is equal to the union of the unions
-of finite subfamilies. This version assumes `ι : Type*`. See also `iUnion_eq_iUnion_finset'` for
-a version that works for `ι : Sort*`. -/
-theorem iUnion_eq_iUnion_finset (s : ι → Set α) : ⋃ i, s i = ⋃ t : Finset ι, ⋃ i ∈ t, s i :=
- iSup_eq_iSup_finset s
-
-/-- Union of an indexed family of sets `s : ι → Set α` is equal to the union of the unions
-of finite subfamilies. This version works for `ι : Sort*`. See also `iUnion_eq_iUnion_finset` for
-a version that assumes `ι : Type*` but avoids `PLift`s in the right hand side. -/
-theorem iUnion_eq_iUnion_finset' (s : ι' → Set α) :
- ⋃ i, s i = ⋃ t : Finset (PLift ι'), ⋃ i ∈ t, s (PLift.down i) :=
- iSup_eq_iSup_finset' s
-
-/-- Intersection of an indexed family of sets `s : ι → Set α` is equal to the intersection of the
-intersections of finite subfamilies. This version assumes `ι : Type*`. See also
-`iInter_eq_iInter_finset'` for a version that works for `ι : Sort*`. -/
-theorem iInter_eq_iInter_finset (s : ι → Set α) : ⋂ i, s i = ⋂ t : Finset ι, ⋂ i ∈ t, s i :=
- iInf_eq_iInf_finset s
-
-/-- Intersection of an indexed family of sets `s : ι → Set α` is equal to the intersection of the
-intersections of finite subfamilies. This version works for `ι : Sort*`. See also
-`iInter_eq_iInter_finset` for a version that assumes `ι : Type*` but avoids `PLift`s in the right
-hand side. -/
-theorem iInter_eq_iInter_finset' (s : ι' → Set α) :
- ⋂ i, s i = ⋂ t : Finset (PLift ι'), ⋂ i ∈ t, s (PLift.down i) :=
- iInf_eq_iInf_finset' s
-
-end Set
-
-namespace Finset
-
-section minimal
-
-variable [DecidableEq α] {P : Finset α → Prop} {s : Finset α}
-
-theorem maximal_iff_forall_insert (hP : ∀ ⦃s t⦄, P t → s ⊆ t → P s) :
- Maximal P s ↔ P s ∧ ∀ x ∉ s, ¬ P (insert x s) := by
- simp only [Maximal, and_congr_right_iff]
- exact fun _ ↦ ⟨fun h x hxs hx ↦ hxs <| h hx (subset_insert _ _) (mem_insert_self x s),
- fun h t ht hst x hxt ↦ by_contra fun hxs ↦ h x hxs (hP ht (insert_subset hxt hst))⟩
-
-theorem minimal_iff_forall_diff_singleton (hP : ∀ ⦃s t⦄, P t → t ⊆ s → P s) :
- Minimal P s ↔ P s ∧ ∀ x ∈ s, ¬ P (s.erase x) where
- mp h := ⟨h.prop, fun x hxs hx ↦ by simpa using h.le_of_le hx (erase_subset _ _) hxs⟩
- mpr h := ⟨h.1, fun t ht hts x hxs ↦ by_contra fun hxt ↦
- h.2 x hxs <| hP ht (subset_erase.2 ⟨hts, hxt⟩)⟩
-
-end minimal
-
-/-! ### Interaction with big lattice/set operations -/
-
-section Lattice
-
-theorem iSup_coe [SupSet β] (f : α → β) (s : Finset α) : ⨆ x ∈ (↑s : Set α), f x = ⨆ x ∈ s, f x :=
- rfl
-
-theorem iInf_coe [InfSet β] (f : α → β) (s : Finset α) : ⨅ x ∈ (↑s : Set α), f x = ⨅ x ∈ s, f x :=
- rfl
-
-variable [CompleteLattice β]
-
-theorem iSup_singleton (a : α) (s : α → β) : ⨆ x ∈ ({a} : Finset α), s x = s a := by simp
-
-theorem iInf_singleton (a : α) (s : α → β) : ⨅ x ∈ ({a} : Finset α), s x = s a := by simp
-
-theorem iSup_option_toFinset (o : Option α) (f : α → β) : ⨆ x ∈ o.toFinset, f x = ⨆ x ∈ o, f x := by
- simp
-
-theorem iInf_option_toFinset (o : Option α) (f : α → β) : ⨅ x ∈ o.toFinset, f x = ⨅ x ∈ o, f x :=
- @iSup_option_toFinset _ βᵒᵈ _ _ _
-
-variable [DecidableEq α]
-
-theorem iSup_union {f : α → β} {s t : Finset α} :
- ⨆ x ∈ s ∪ t, f x = (⨆ x ∈ s, f x) ⊔ ⨆ x ∈ t, f x := by simp [iSup_or, iSup_sup_eq]
-
-theorem iInf_union {f : α → β} {s t : Finset α} :
- ⨅ x ∈ s ∪ t, f x = (⨅ x ∈ s, f x) ⊓ ⨅ x ∈ t, f x :=
- @iSup_union α βᵒᵈ _ _ _ _ _
-
-theorem iSup_insert (a : α) (s : Finset α) (t : α → β) :
- ⨆ x ∈ insert a s, t x = t a ⊔ ⨆ x ∈ s, t x := by
- rw [insert_eq]
- simp only [iSup_union, Finset.iSup_singleton]
-
-theorem iInf_insert (a : α) (s : Finset α) (t : α → β) :
- ⨅ x ∈ insert a s, t x = t a ⊓ ⨅ x ∈ s, t x :=
- @iSup_insert α βᵒᵈ _ _ _ _ _
-
-theorem iSup_finset_image {f : γ → α} {g : α → β} {s : Finset γ} :
- ⨆ x ∈ s.image f, g x = ⨆ y ∈ s, g (f y) := by rw [← iSup_coe, coe_image, iSup_image, iSup_coe]
-
-theorem iInf_finset_image {f : γ → α} {g : α → β} {s : Finset γ} :
- ⨅ x ∈ s.image f, g x = ⨅ y ∈ s, g (f y) := by rw [← iInf_coe, coe_image, iInf_image, iInf_coe]
-
-theorem iSup_insert_update {x : α} {t : Finset α} (f : α → β) {s : β} (hx : x ∉ t) :
- ⨆ i ∈ insert x t, Function.update f x s i = s ⊔ ⨆ i ∈ t, f i := by
- simp only [Finset.iSup_insert, update_same]
- rcongr (i hi); apply update_noteq; rintro rfl; exact hx hi
-
-theorem iInf_insert_update {x : α} {t : Finset α} (f : α → β) {s : β} (hx : x ∉ t) :
- ⨅ i ∈ insert x t, update f x s i = s ⊓ ⨅ i ∈ t, f i :=
- @iSup_insert_update α βᵒᵈ _ _ _ _ f _ hx
-
-theorem iSup_biUnion (s : Finset γ) (t : γ → Finset α) (f : α → β) :
- ⨆ y ∈ s.biUnion t, f y = ⨆ (x ∈ s) (y ∈ t x), f y := by simp [@iSup_comm _ α, iSup_and]
-
-theorem iInf_biUnion (s : Finset γ) (t : γ → Finset α) (f : α → β) :
- ⨅ y ∈ s.biUnion t, f y = ⨅ (x ∈ s) (y ∈ t x), f y :=
- @iSup_biUnion _ βᵒᵈ _ _ _ _ _ _
-
-end Lattice
-
-theorem set_biUnion_coe (s : Finset α) (t : α → Set β) : ⋃ x ∈ (↑s : Set α), t x = ⋃ x ∈ s, t x :=
- rfl
-
-theorem set_biInter_coe (s : Finset α) (t : α → Set β) : ⋂ x ∈ (↑s : Set α), t x = ⋂ x ∈ s, t x :=
- rfl
-
-theorem set_biUnion_singleton (a : α) (s : α → Set β) : ⋃ x ∈ ({a} : Finset α), s x = s a :=
- iSup_singleton a s
-
-theorem set_biInter_singleton (a : α) (s : α → Set β) : ⋂ x ∈ ({a} : Finset α), s x = s a :=
- iInf_singleton a s
-
-@[simp]
-theorem set_biUnion_preimage_singleton (f : α → β) (s : Finset β) :
- ⋃ y ∈ s, f ⁻¹' {y} = f ⁻¹' s :=
- Set.biUnion_preimage_singleton f s
-
-theorem set_biUnion_option_toFinset (o : Option α) (f : α → Set β) :
- ⋃ x ∈ o.toFinset, f x = ⋃ x ∈ o, f x :=
- iSup_option_toFinset o f
-
-theorem set_biInter_option_toFinset (o : Option α) (f : α → Set β) :
- ⋂ x ∈ o.toFinset, f x = ⋂ x ∈ o, f x :=
- iInf_option_toFinset o f
-
-theorem subset_set_biUnion_of_mem {s : Finset α} {f : α → Set β} {x : α} (h : x ∈ s) :
- f x ⊆ ⋃ y ∈ s, f y :=
- show f x ≤ ⨆ y ∈ s, f y from le_iSup_of_le x <| by simp only [h, iSup_pos, le_refl]
-
-variable [DecidableEq α]
-
-theorem set_biUnion_union (s t : Finset α) (u : α → Set β) :
- ⋃ x ∈ s ∪ t, u x = (⋃ x ∈ s, u x) ∪ ⋃ x ∈ t, u x :=
- iSup_union
-
-theorem set_biInter_inter (s t : Finset α) (u : α → Set β) :
- ⋂ x ∈ s ∪ t, u x = (⋂ x ∈ s, u x) ∩ ⋂ x ∈ t, u x :=
- iInf_union
-
-theorem set_biUnion_insert (a : α) (s : Finset α) (t : α → Set β) :
- ⋃ x ∈ insert a s, t x = t a ∪ ⋃ x ∈ s, t x :=
- iSup_insert a s t
-
-theorem set_biInter_insert (a : α) (s : Finset α) (t : α → Set β) :
- ⋂ x ∈ insert a s, t x = t a ∩ ⋂ x ∈ s, t x :=
- iInf_insert a s t
-
-theorem set_biUnion_finset_image {f : γ → α} {g : α → Set β} {s : Finset γ} :
- ⋃ x ∈ s.image f, g x = ⋃ y ∈ s, g (f y) :=
- iSup_finset_image
-
-theorem set_biInter_finset_image {f : γ → α} {g : α → Set β} {s : Finset γ} :
- ⋂ x ∈ s.image f, g x = ⋂ y ∈ s, g (f y) :=
- iInf_finset_image
-
-theorem set_biUnion_insert_update {x : α} {t : Finset α} (f : α → Set β) {s : Set β} (hx : x ∉ t) :
- ⋃ i ∈ insert x t, @update _ _ _ f x s i = s ∪ ⋃ i ∈ t, f i :=
- iSup_insert_update f hx
-
-theorem set_biInter_insert_update {x : α} {t : Finset α} (f : α → Set β) {s : Set β} (hx : x ∉ t) :
- ⋂ i ∈ insert x t, @update _ _ _ f x s i = s ∩ ⋂ i ∈ t, f i :=
- iInf_insert_update f hx
-
-theorem set_biUnion_biUnion (s : Finset γ) (t : γ → Finset α) (f : α → Set β) :
- ⋃ y ∈ s.biUnion t, f y = ⋃ (x ∈ s) (y ∈ t x), f y :=
- iSup_biUnion s t f
-
-theorem set_biInter_biUnion (s : Finset γ) (t : γ → Finset α) (f : α → Set β) :
- ⋂ y ∈ s.biUnion t, f y = ⋂ (x ∈ s) (y ∈ t x), f y :=
- iInf_biUnion s t f
-
-end Finset
-
-set_option linter.style.longFile 2100
diff --git a/Mathlib/Data/Finset/Max.lean b/Mathlib/Data/Finset/Max.lean
new file mode 100644
index 0000000000000..a972df5dc3ddc
--- /dev/null
+++ b/Mathlib/Data/Finset/Max.lean
@@ -0,0 +1,543 @@
+/-
+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.Data.Finset.Lattice
+
+/-!
+# Maximum and minimum of finite sets
+-/
+
+assert_not_exists OrderedCommMonoid
+assert_not_exists MonoidWithZero
+
+open Function Multiset OrderDual
+
+variable {F α β γ ι κ : Type*}
+
+namespace Finset
+
+/-! ### max and min of finite sets -/
+
+section MaxMin
+
+variable [LinearOrder α]
+
+/-- Let `s` be a finset in a linear order. Then `s.max` is the maximum of `s` if `s` is not empty,
+and `⊥` otherwise. It belongs to `WithBot α`. If you want to get an element of `α`, see
+`s.max'`. -/
+protected def max (s : Finset α) : WithBot α :=
+ sup s (↑)
+
+theorem max_eq_sup_coe {s : Finset α} : s.max = s.sup (↑) :=
+ rfl
+
+theorem max_eq_sup_withBot (s : Finset α) : s.max = sup s (↑) :=
+ rfl
+
+@[simp]
+theorem max_empty : (∅ : Finset α).max = ⊥ :=
+ rfl
+
+@[simp]
+theorem max_insert {a : α} {s : Finset α} : (insert a s).max = max ↑a s.max :=
+ fold_insert_idem
+
+@[simp]
+theorem max_singleton {a : α} : Finset.max {a} = (a : WithBot α) := by
+ rw [← insert_emptyc_eq]
+ exact max_insert
+
+theorem max_of_mem {s : Finset α} {a : α} (h : a ∈ s) : ∃ b : α, s.max = b := by
+ obtain ⟨b, h, _⟩ := le_sup (α := WithBot α) h _ rfl
+ exact ⟨b, h⟩
+
+theorem max_of_nonempty {s : Finset α} (h : s.Nonempty) : ∃ a : α, s.max = a :=
+ let ⟨_, h⟩ := h
+ max_of_mem h
+
+theorem max_eq_bot {s : Finset α} : s.max = ⊥ ↔ s = ∅ :=
+ ⟨fun h ↦ s.eq_empty_or_nonempty.elim id fun H ↦ by
+ obtain ⟨a, ha⟩ := max_of_nonempty H
+ rw [h] at ha; cases ha; , -- the `;` is needed since the `cases` syntax allows `cases a, b`
+ fun h ↦ h.symm ▸ max_empty⟩
+
+theorem mem_of_max {s : Finset α} : ∀ {a : α}, s.max = a → a ∈ s := by
+ induction' s using Finset.induction_on with b s _ ih
+ · intro _ H; cases H
+ · intro a h
+ by_cases p : b = a
+ · induction p
+ exact mem_insert_self b s
+ · cases' max_choice (↑b) s.max with q q <;> rw [max_insert, q] at h
+ · cases h
+ cases p rfl
+ · exact mem_insert_of_mem (ih h)
+
+theorem le_max {a : α} {s : Finset α} (as : a ∈ s) : ↑a ≤ s.max :=
+ le_sup as
+
+theorem not_mem_of_max_lt_coe {a : α} {s : Finset α} (h : s.max < a) : a ∉ s :=
+ mt le_max h.not_le
+
+theorem le_max_of_eq {s : Finset α} {a b : α} (h₁ : a ∈ s) (h₂ : s.max = b) : a ≤ b :=
+ WithBot.coe_le_coe.mp <| (le_max h₁).trans h₂.le
+
+theorem not_mem_of_max_lt {s : Finset α} {a b : α} (h₁ : b < a) (h₂ : s.max = ↑b) : a ∉ s :=
+ Finset.not_mem_of_max_lt_coe <| h₂.trans_lt <| WithBot.coe_lt_coe.mpr h₁
+
+@[gcongr]
+theorem max_mono {s t : Finset α} (st : s ⊆ t) : s.max ≤ t.max :=
+ sup_mono st
+
+protected theorem max_le {M : WithBot α} {s : Finset α} (st : ∀ a ∈ s, (a : WithBot α) ≤ M) :
+ s.max ≤ M :=
+ Finset.sup_le st
+
+@[simp]
+protected lemma max_le_iff {m : WithBot α} {s : Finset α} : s.max ≤ m ↔ ∀ a ∈ s, a ≤ m :=
+ Finset.sup_le_iff
+
+@[simp]
+protected lemma max_eq_top [OrderTop α] {s : Finset α} : s.max = ⊤ ↔ ⊤ ∈ s :=
+ Finset.sup_eq_top_iff.trans <| by simp
+
+/-- Let `s` be a finset in a linear order. Then `s.min` is the minimum of `s` if `s` is not empty,
+and `⊤` otherwise. It belongs to `WithTop α`. If you want to get an element of `α`, see
+`s.min'`. -/
+protected def min (s : Finset α) : WithTop α :=
+ inf s (↑)
+
+theorem min_eq_inf_withTop (s : Finset α) : s.min = inf s (↑) :=
+ rfl
+
+@[simp]
+theorem min_empty : (∅ : Finset α).min = ⊤ :=
+ rfl
+
+@[simp]
+theorem min_insert {a : α} {s : Finset α} : (insert a s).min = min (↑a) s.min :=
+ fold_insert_idem
+
+@[simp]
+theorem min_singleton {a : α} : Finset.min {a} = (a : WithTop α) := by
+ rw [← insert_emptyc_eq]
+ exact min_insert
+
+theorem min_of_mem {s : Finset α} {a : α} (h : a ∈ s) : ∃ b : α, s.min = b := by
+ obtain ⟨b, h, _⟩ := inf_le (α := WithTop α) h _ rfl
+ exact ⟨b, h⟩
+
+theorem min_of_nonempty {s : Finset α} (h : s.Nonempty) : ∃ a : α, s.min = a :=
+ let ⟨_, h⟩ := h
+ min_of_mem h
+
+@[simp]
+theorem min_eq_top {s : Finset α} : s.min = ⊤ ↔ s = ∅ := by
+ simp [Finset.min, eq_empty_iff_forall_not_mem]
+
+theorem mem_of_min {s : Finset α} : ∀ {a : α}, s.min = a → a ∈ s :=
+ @mem_of_max αᵒᵈ _ s
+
+theorem min_le {a : α} {s : Finset α} (as : a ∈ s) : s.min ≤ a :=
+ inf_le as
+
+theorem not_mem_of_coe_lt_min {a : α} {s : Finset α} (h : ↑a < s.min) : a ∉ s :=
+ mt min_le h.not_le
+
+theorem min_le_of_eq {s : Finset α} {a b : α} (h₁ : b ∈ s) (h₂ : s.min = a) : a ≤ b :=
+ WithTop.coe_le_coe.mp <| h₂.ge.trans (min_le h₁)
+
+theorem not_mem_of_lt_min {s : Finset α} {a b : α} (h₁ : a < b) (h₂ : s.min = ↑b) : a ∉ s :=
+ Finset.not_mem_of_coe_lt_min <| (WithTop.coe_lt_coe.mpr h₁).trans_eq h₂.symm
+
+@[gcongr]
+theorem min_mono {s t : Finset α} (st : s ⊆ t) : t.min ≤ s.min :=
+ inf_mono st
+
+protected theorem le_min {m : WithTop α} {s : Finset α} (st : ∀ a : α, a ∈ s → m ≤ a) : m ≤ s.min :=
+ Finset.le_inf st
+
+@[simp]
+protected theorem le_min_iff {m : WithTop α} {s : Finset α} : m ≤ s.min ↔ ∀ a ∈ s, m ≤ a :=
+ Finset.le_inf_iff
+
+@[simp]
+protected theorem min_eq_bot [OrderBot α] {s : Finset α} : s.min = ⊥ ↔ ⊥ ∈ s :=
+ Finset.max_eq_top (α := αᵒᵈ)
+
+/-- Given a nonempty finset `s` in a linear order `α`, then `s.min' H` is its minimum, as an
+element of `α`, where `H` is a proof of nonemptiness. Without this assumption, use instead `s.min`,
+taking values in `WithTop α`. -/
+def min' (s : Finset α) (H : s.Nonempty) : α :=
+ inf' s H id
+
+/-- Given a nonempty finset `s` in a linear order `α`, then `s.max' H` is its maximum, as an
+element of `α`, where `H` is a proof of nonemptiness. Without this assumption, use instead `s.max`,
+taking values in `WithBot α`. -/
+def max' (s : Finset α) (H : s.Nonempty) : α :=
+ sup' s H id
+
+variable (s : Finset α) (H : s.Nonempty) {x : α}
+
+theorem min'_mem : s.min' H ∈ s :=
+ mem_of_min <| by simp only [Finset.min, min', id_eq, coe_inf']; rfl
+
+theorem min'_le (x) (H2 : x ∈ s) : s.min' ⟨x, H2⟩ ≤ x :=
+ min_le_of_eq H2 (WithTop.coe_untop _ _).symm
+
+theorem le_min' (x) (H2 : ∀ y ∈ s, x ≤ y) : x ≤ s.min' H :=
+ H2 _ <| min'_mem _ _
+
+theorem isLeast_min' : IsLeast (↑s) (s.min' H) :=
+ ⟨min'_mem _ _, min'_le _⟩
+
+@[simp]
+theorem le_min'_iff {x} : x ≤ s.min' H ↔ ∀ y ∈ s, x ≤ y :=
+ le_isGLB_iff (isLeast_min' s H).isGLB
+
+/-- `{a}.min' _` is `a`. -/
+@[simp]
+theorem min'_singleton (a : α) : ({a} : Finset α).min' (singleton_nonempty _) = a := by simp [min']
+
+theorem max'_mem : s.max' H ∈ s :=
+ mem_of_max <| by simp only [max', Finset.max, id_eq, coe_sup']; rfl
+
+theorem le_max' (x) (H2 : x ∈ s) : x ≤ s.max' ⟨x, H2⟩ :=
+ le_max_of_eq H2 (WithBot.coe_unbot _ _).symm
+
+theorem max'_le (x) (H2 : ∀ y ∈ s, y ≤ x) : s.max' H ≤ x :=
+ H2 _ <| max'_mem _ _
+
+theorem isGreatest_max' : IsGreatest (↑s) (s.max' H) :=
+ ⟨max'_mem _ _, le_max' _⟩
+
+@[simp]
+theorem max'_le_iff {x} : s.max' H ≤ x ↔ ∀ y ∈ s, y ≤ x :=
+ isLUB_le_iff (isGreatest_max' s H).isLUB
+
+@[simp]
+theorem max'_lt_iff {x} : s.max' H < x ↔ ∀ y ∈ s, y < x :=
+ ⟨fun Hlt y hy => (s.le_max' y hy).trans_lt Hlt, fun H => H _ <| s.max'_mem _⟩
+
+@[simp]
+theorem lt_min'_iff : x < s.min' H ↔ ∀ y ∈ s, x < y :=
+ @max'_lt_iff αᵒᵈ _ _ H _
+
+theorem max'_eq_sup' : s.max' H = s.sup' H id := rfl
+
+theorem min'_eq_inf' : s.min' H = s.inf' H id := rfl
+
+/-- `{a}.max' _` is `a`. -/
+@[simp]
+theorem max'_singleton (a : α) : ({a} : Finset α).max' (singleton_nonempty _) = a := by simp [max']
+
+theorem min'_lt_max' {i j} (H1 : i ∈ s) (H2 : j ∈ s) (H3 : i ≠ j) :
+ s.min' ⟨i, H1⟩ < s.max' ⟨i, H1⟩ :=
+ isGLB_lt_isLUB_of_ne (s.isLeast_min' _).isGLB (s.isGreatest_max' _).isLUB H1 H2 H3
+
+/-- If there's more than 1 element, the min' is less than the max'. An alternate version of
+`min'_lt_max'` which is sometimes more convenient.
+-/
+theorem min'_lt_max'_of_card (h₂ : 1 < card s) :
+ s.min' (Finset.card_pos.1 <| by omega) < s.max' (Finset.card_pos.1 <| by omega) := by
+ rcases one_lt_card.1 h₂ with ⟨a, ha, b, hb, hab⟩
+ exact s.min'_lt_max' ha hb hab
+
+theorem map_ofDual_min (s : Finset αᵒᵈ) : s.min.map ofDual = (s.image ofDual).max := by
+ rw [max_eq_sup_withBot, sup_image]
+ exact congr_fun Option.map_id _
+
+theorem map_ofDual_max (s : Finset αᵒᵈ) : s.max.map ofDual = (s.image ofDual).min := by
+ rw [min_eq_inf_withTop, inf_image]
+ exact congr_fun Option.map_id _
+
+theorem map_toDual_min (s : Finset α) : s.min.map toDual = (s.image toDual).max := by
+ rw [max_eq_sup_withBot, sup_image]
+ exact congr_fun Option.map_id _
+
+theorem map_toDual_max (s : Finset α) : s.max.map toDual = (s.image toDual).min := by
+ rw [min_eq_inf_withTop, inf_image]
+ exact congr_fun Option.map_id _
+
+-- Porting note: new proofs without `convert` for the next four theorems.
+
+theorem ofDual_min' {s : Finset αᵒᵈ} (hs : s.Nonempty) :
+ ofDual (min' s hs) = max' (s.image ofDual) (hs.image _) := by
+ rw [← WithBot.coe_eq_coe]
+ simp only [min'_eq_inf', id_eq, ofDual_inf', Function.comp_apply, coe_sup', max'_eq_sup',
+ sup_image]
+ rfl
+
+theorem ofDual_max' {s : Finset αᵒᵈ} (hs : s.Nonempty) :
+ ofDual (max' s hs) = min' (s.image ofDual) (hs.image _) := by
+ rw [← WithTop.coe_eq_coe]
+ simp only [max'_eq_sup', id_eq, ofDual_sup', Function.comp_apply, coe_inf', min'_eq_inf',
+ inf_image]
+ rfl
+
+theorem toDual_min' {s : Finset α} (hs : s.Nonempty) :
+ toDual (min' s hs) = max' (s.image toDual) (hs.image _) := by
+ rw [← WithBot.coe_eq_coe]
+ simp only [min'_eq_inf', id_eq, toDual_inf', Function.comp_apply, coe_sup', max'_eq_sup',
+ sup_image]
+ rfl
+
+theorem toDual_max' {s : Finset α} (hs : s.Nonempty) :
+ toDual (max' s hs) = min' (s.image toDual) (hs.image _) := by
+ rw [← WithTop.coe_eq_coe]
+ simp only [max'_eq_sup', id_eq, toDual_sup', Function.comp_apply, coe_inf', min'_eq_inf',
+ inf_image]
+ rfl
+
+theorem max'_subset {s t : Finset α} (H : s.Nonempty) (hst : s ⊆ t) :
+ s.max' H ≤ t.max' (H.mono hst) :=
+ le_max' _ _ (hst (s.max'_mem H))
+
+theorem min'_subset {s t : Finset α} (H : s.Nonempty) (hst : s ⊆ t) :
+ t.min' (H.mono hst) ≤ s.min' H :=
+ min'_le _ _ (hst (s.min'_mem H))
+
+theorem max'_insert (a : α) (s : Finset α) (H : s.Nonempty) :
+ (insert a s).max' (s.insert_nonempty a) = max (s.max' H) a :=
+ (isGreatest_max' _ _).unique <| by
+ rw [coe_insert, max_comm]
+ exact (isGreatest_max' _ _).insert _
+
+theorem min'_insert (a : α) (s : Finset α) (H : s.Nonempty) :
+ (insert a s).min' (s.insert_nonempty a) = min (s.min' H) a :=
+ (isLeast_min' _ _).unique <| by
+ rw [coe_insert, min_comm]
+ exact (isLeast_min' _ _).insert _
+
+theorem lt_max'_of_mem_erase_max' [DecidableEq α] {a : α} (ha : a ∈ s.erase (s.max' H)) :
+ a < s.max' H :=
+ lt_of_le_of_ne (le_max' _ _ (mem_of_mem_erase ha)) <| ne_of_mem_of_not_mem ha <| not_mem_erase _ _
+
+theorem min'_lt_of_mem_erase_min' [DecidableEq α] {a : α} (ha : a ∈ s.erase (s.min' H)) :
+ s.min' H < a :=
+ @lt_max'_of_mem_erase_max' αᵒᵈ _ s H _ a ha
+
+/-- To rewrite from right to left, use `Monotone.map_finset_max'`. -/
+@[simp]
+theorem max'_image [LinearOrder β] {f : α → β} (hf : Monotone f) (s : Finset α)
+ (h : (s.image f).Nonempty) : (s.image f).max' h = f (s.max' h.of_image) := by
+ simp only [max', sup'_image]
+ exact .symm <| comp_sup'_eq_sup'_comp _ _ fun _ _ ↦ hf.map_max
+
+/-- A version of `Finset.max'_image` with LHS and RHS reversed.
+Also, this version assumes that `s` is nonempty, not its image. -/
+lemma _root_.Monotone.map_finset_max' [LinearOrder β] {f : α → β} (hf : Monotone f) {s : Finset α}
+ (h : s.Nonempty) : f (s.max' h) = (s.image f).max' (h.image f) :=
+ .symm <| max'_image hf ..
+
+/-- To rewrite from right to left, use `Monotone.map_finset_min'`. -/
+@[simp]
+theorem min'_image [LinearOrder β] {f : α → β} (hf : Monotone f) (s : Finset α)
+ (h : (s.image f).Nonempty) : (s.image f).min' h = f (s.min' h.of_image) := by
+ simp only [min', inf'_image]
+ exact .symm <| comp_inf'_eq_inf'_comp _ _ fun _ _ ↦ hf.map_min
+
+/-- A version of `Finset.min'_image` with LHS and RHS reversed.
+Also, this version assumes that `s` is nonempty, not its image. -/
+lemma _root_.Monotone.map_finset_min' [LinearOrder β] {f : α → β} (hf : Monotone f) {s : Finset α}
+ (h : s.Nonempty) : f (s.min' h) = (s.image f).min' (h.image f) :=
+ .symm <| min'_image hf ..
+
+theorem coe_max' {s : Finset α} (hs : s.Nonempty) : ↑(s.max' hs) = s.max :=
+ coe_sup' hs id
+
+theorem coe_min' {s : Finset α} (hs : s.Nonempty) : ↑(s.min' hs) = s.min :=
+ coe_inf' hs id
+
+theorem max_mem_image_coe {s : Finset α} (hs : s.Nonempty) :
+ s.max ∈ (s.image (↑) : Finset (WithBot α)) :=
+ mem_image.2 ⟨max' s hs, max'_mem _ _, coe_max' hs⟩
+
+theorem min_mem_image_coe {s : Finset α} (hs : s.Nonempty) :
+ s.min ∈ (s.image (↑) : Finset (WithTop α)) :=
+ mem_image.2 ⟨min' s hs, min'_mem _ _, coe_min' hs⟩
+
+theorem max_mem_insert_bot_image_coe (s : Finset α) :
+ s.max ∈ (insert ⊥ (s.image (↑)) : Finset (WithBot α)) :=
+ mem_insert.2 <| s.eq_empty_or_nonempty.imp max_eq_bot.2 max_mem_image_coe
+
+theorem min_mem_insert_top_image_coe (s : Finset α) :
+ s.min ∈ (insert ⊤ (s.image (↑)) : Finset (WithTop α)) :=
+ mem_insert.2 <| s.eq_empty_or_nonempty.imp min_eq_top.2 min_mem_image_coe
+
+theorem max'_erase_ne_self {s : Finset α} (s0 : (s.erase x).Nonempty) : (s.erase x).max' s0 ≠ x :=
+ ne_of_mem_erase (max'_mem _ s0)
+
+theorem min'_erase_ne_self {s : Finset α} (s0 : (s.erase x).Nonempty) : (s.erase x).min' s0 ≠ x :=
+ ne_of_mem_erase (min'_mem _ s0)
+
+theorem max_erase_ne_self {s : Finset α} : (s.erase x).max ≠ x := by
+ by_cases s0 : (s.erase x).Nonempty
+ · refine ne_of_eq_of_ne (coe_max' s0).symm ?_
+ exact WithBot.coe_eq_coe.not.mpr (max'_erase_ne_self _)
+ · rw [not_nonempty_iff_eq_empty.mp s0, max_empty]
+ exact WithBot.bot_ne_coe
+
+theorem min_erase_ne_self {s : Finset α} : (s.erase x).min ≠ x := by
+ -- Porting note: old proof `convert @max_erase_ne_self αᵒᵈ _ _ _`
+ convert @max_erase_ne_self αᵒᵈ _ (toDual x) (s.map toDual.toEmbedding) using 1
+ apply congr_arg -- Porting note: forces unfolding to see `Finset.min` is `Finset.max`
+ congr!
+ ext; simp only [mem_map_equiv]; exact Iff.rfl
+
+theorem exists_next_right {x : α} {s : Finset α} (h : ∃ y ∈ s, x < y) :
+ ∃ y ∈ s, x < y ∧ ∀ z ∈ s, x < z → y ≤ z :=
+ have Hne : (s.filter (x < ·)).Nonempty := h.imp fun y hy => mem_filter.2 (by simpa)
+ have aux := mem_filter.1 (min'_mem _ Hne)
+ ⟨min' _ Hne, aux.1, by simp, fun z hzs hz => min'_le _ _ <| mem_filter.2 ⟨hzs, by simpa⟩⟩
+
+theorem exists_next_left {x : α} {s : Finset α} (h : ∃ y ∈ s, y < x) :
+ ∃ y ∈ s, y < x ∧ ∀ z ∈ s, z < x → z ≤ y :=
+ @exists_next_right αᵒᵈ _ x s h
+
+/-- If finsets `s` and `t` are interleaved, then `Finset.card s ≤ Finset.card t + 1`. -/
+theorem card_le_of_interleaved {s t : Finset α}
+ (h : ∀ᵉ (x ∈ s) (y ∈ s),
+ x < y → (∀ z ∈ s, z ∉ Set.Ioo x y) → ∃ z ∈ t, x < z ∧ z < y) :
+ s.card ≤ t.card + 1 := by
+ replace h : ∀ᵉ (x ∈ s) (y ∈ s), x < y → ∃ z ∈ t, x < z ∧ z < y := by
+ intro x hx y hy hxy
+ rcases exists_next_right ⟨y, hy, hxy⟩ with ⟨a, has, hxa, ha⟩
+ rcases h x hx a has hxa fun z hzs hz => hz.2.not_le <| ha _ hzs hz.1 with ⟨b, hbt, hxb, hba⟩
+ exact ⟨b, hbt, hxb, hba.trans_le <| ha _ hy hxy⟩
+ set f : α → WithTop α := fun x => (t.filter fun y => x < y).min
+ have f_mono : StrictMonoOn f s := by
+ intro x hx y hy hxy
+ rcases h x hx y hy hxy with ⟨a, hat, hxa, hay⟩
+ calc
+ f x ≤ a := min_le (mem_filter.2 ⟨hat, by simpa⟩)
+ _ < f y :=
+ (Finset.lt_inf_iff <| WithTop.coe_lt_top a).2 fun b hb =>
+ WithTop.coe_lt_coe.2 <| hay.trans (by simpa using (mem_filter.1 hb).2)
+
+ calc
+ s.card = (s.image f).card := (card_image_of_injOn f_mono.injOn).symm
+ _ ≤ (insert ⊤ (t.image (↑)) : Finset (WithTop α)).card :=
+ card_mono <| image_subset_iff.2 fun x _ =>
+ insert_subset_insert _ (image_subset_image <| filter_subset _ _)
+ (min_mem_insert_top_image_coe _)
+ _ ≤ t.card + 1 := (card_insert_le _ _).trans (Nat.add_le_add_right card_image_le _)
+
+/-- If finsets `s` and `t` are interleaved, then `Finset.card s ≤ Finset.card (t \ s) + 1`. -/
+theorem card_le_diff_of_interleaved {s t : Finset α}
+ (h :
+ ∀ᵉ (x ∈ s) (y ∈ s),
+ x < y → (∀ z ∈ s, z ∉ Set.Ioo x y) → ∃ z ∈ t, x < z ∧ z < y) :
+ s.card ≤ (t \ s).card + 1 :=
+ card_le_of_interleaved fun x hx y hy hxy hs =>
+ let ⟨z, hzt, hxz, hzy⟩ := h x hx y hy hxy hs
+ ⟨z, mem_sdiff.2 ⟨hzt, fun hzs => hs z hzs ⟨hxz, hzy⟩⟩, hxz, hzy⟩
+
+/-- Induction principle for `Finset`s in a linearly ordered type: a predicate is true on all
+`s : Finset α` provided that:
+
+* it is true on the empty `Finset`,
+* for every `s : Finset α` and an element `a` strictly greater than all elements of `s`, `p s`
+ implies `p (insert a s)`. -/
+@[elab_as_elim]
+theorem induction_on_max [DecidableEq α] {p : Finset α → Prop} (s : Finset α) (h0 : p ∅)
+ (step : ∀ a s, (∀ x ∈ s, x < a) → p s → p (insert a s)) : p s := by
+ induction' s using Finset.strongInductionOn with s ihs
+ rcases s.eq_empty_or_nonempty with (rfl | hne)
+ · exact h0
+ · have H : s.max' hne ∈ s := max'_mem s hne
+ rw [← insert_erase H]
+ exact step _ _ (fun x => s.lt_max'_of_mem_erase_max' hne) (ihs _ <| erase_ssubset H)
+
+/-- Induction principle for `Finset`s in a linearly ordered type: a predicate is true on all
+`s : Finset α` provided that:
+
+* it is true on the empty `Finset`,
+* for every `s : Finset α` and an element `a` strictly less than all elements of `s`, `p s`
+ implies `p (insert a s)`. -/
+@[elab_as_elim]
+theorem induction_on_min [DecidableEq α] {p : Finset α → Prop} (s : Finset α) (h0 : p ∅)
+ (step : ∀ a s, (∀ x ∈ s, a < x) → p s → p (insert a s)) : p s :=
+ @induction_on_max αᵒᵈ _ _ _ s h0 step
+
+end MaxMin
+
+section MaxMinInductionValue
+
+variable [LinearOrder α] [LinearOrder β]
+
+/-- Induction principle for `Finset`s in any type from which a given function `f` maps to a linearly
+ordered type : a predicate is true on all `s : Finset α` provided that:
+
+* it is true on the empty `Finset`,
+* for every `s : Finset α` and an element `a` such that for elements of `s` denoted by `x` we have
+ `f x ≤ f a`, `p s` implies `p (insert a s)`. -/
+@[elab_as_elim]
+theorem induction_on_max_value [DecidableEq ι] (f : ι → α) {p : Finset ι → Prop} (s : Finset ι)
+ (h0 : p ∅) (step : ∀ a s, a ∉ s → (∀ x ∈ s, f x ≤ f a) → p s → p (insert a s)) : p s := by
+ induction' s using Finset.strongInductionOn with s ihs
+ rcases (s.image f).eq_empty_or_nonempty with (hne | hne)
+ · simp only [image_eq_empty] at hne
+ simp only [hne, h0]
+ · have H : (s.image f).max' hne ∈ s.image f := max'_mem (s.image f) hne
+ simp only [mem_image, exists_prop] at H
+ rcases H with ⟨a, has, hfa⟩
+ rw [← insert_erase has]
+ refine step _ _ (not_mem_erase a s) (fun x hx => ?_) (ihs _ <| erase_ssubset has)
+ rw [hfa]
+ exact le_max' _ _ (mem_image_of_mem _ <| mem_of_mem_erase hx)
+
+/-- Induction principle for `Finset`s in any type from which a given function `f` maps to a linearly
+ordered type : a predicate is true on all `s : Finset α` provided that:
+
+* it is true on the empty `Finset`,
+* for every `s : Finset α` and an element `a` such that for elements of `s` denoted by `x` we have
+ `f a ≤ f x`, `p s` implies `p (insert a s)`. -/
+@[elab_as_elim]
+theorem induction_on_min_value [DecidableEq ι] (f : ι → α) {p : Finset ι → Prop} (s : Finset ι)
+ (h0 : p ∅) (step : ∀ a s, a ∉ s → (∀ x ∈ s, f a ≤ f x) → p s → p (insert a s)) : p s :=
+ @induction_on_max_value αᵒᵈ ι _ _ _ _ s h0 step
+
+end MaxMinInductionValue
+
+section ExistsMaxMin
+
+variable [LinearOrder α]
+
+theorem exists_max_image (s : Finset β) (f : β → α) (h : s.Nonempty) :
+ ∃ x ∈ s, ∀ x' ∈ s, f x' ≤ f x := by
+ cases' max_of_nonempty (h.image f) with y hy
+ rcases mem_image.mp (mem_of_max hy) with ⟨x, hx, rfl⟩
+ exact ⟨x, hx, fun x' hx' => le_max_of_eq (mem_image_of_mem f hx') hy⟩
+
+theorem exists_min_image (s : Finset β) (f : β → α) (h : s.Nonempty) :
+ ∃ x ∈ s, ∀ x' ∈ s, f x ≤ f x' :=
+ @exists_max_image αᵒᵈ β _ s f h
+
+end ExistsMaxMin
+
+theorem isGLB_iff_isLeast [LinearOrder α] (i : α) (s : Finset α) (hs : s.Nonempty) :
+ IsGLB (s : Set α) i ↔ IsLeast (↑s) i := by
+ refine ⟨fun his => ?_, IsLeast.isGLB⟩
+ suffices i = min' s hs by
+ rw [this]
+ exact isLeast_min' s hs
+ rw [IsGLB, IsGreatest, mem_lowerBounds, mem_upperBounds] at his
+ exact le_antisymm (his.1 (Finset.min' s hs) (Finset.min'_mem s hs)) (his.2 _ (Finset.min'_le s))
+
+theorem isLUB_iff_isGreatest [LinearOrder α] (i : α) (s : Finset α) (hs : s.Nonempty) :
+ IsLUB (s : Set α) i ↔ IsGreatest (↑s) i :=
+ @isGLB_iff_isLeast αᵒᵈ _ i s hs
+
+theorem isGLB_mem [LinearOrder α] {i : α} (s : Finset α) (his : IsGLB (s : Set α) i)
+ (hs : s.Nonempty) : i ∈ s := by
+ rw [← mem_coe]
+ exact ((isGLB_iff_isLeast i s hs).mp his).1
+
+theorem isLUB_mem [LinearOrder α] {i : α} (s : Finset α) (his : IsLUB (s : Set α) i)
+ (hs : s.Nonempty) : i ∈ s :=
+ @isGLB_mem αᵒᵈ _ i s his hs
+
+end Finset
diff --git a/Mathlib/Data/Finset/MulAntidiagonal.lean b/Mathlib/Data/Finset/MulAntidiagonal.lean
index d361b2e348cd7..534b98c618c6b 100644
--- a/Mathlib/Data/Finset/MulAntidiagonal.lean
+++ b/Mathlib/Data/Finset/MulAntidiagonal.lean
@@ -3,7 +3,7 @@ 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, Yaël Dillies
-/
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Algebra.Order.Monoid.Defs
import Mathlib.Data.Set.MulAntidiagonal
diff --git a/Mathlib/Data/Finset/NAry.lean b/Mathlib/Data/Finset/NAry.lean
index 74ad2d6a47ad7..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
@@ -94,11 +97,12 @@ theorem image₂_subset_iff_left : image₂ f s t ⊆ u ↔ ∀ a ∈ s, (t.imag
theorem image₂_subset_iff_right : image₂ f s t ⊆ u ↔ ∀ b ∈ t, (s.image fun a => f a b) ⊆ u := by
simp_rw [image₂_subset_iff, image_subset_iff, @forall₂_swap α]
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem image₂_nonempty_iff : (image₂ f s t).Nonempty ↔ s.Nonempty ∧ t.Nonempty := by
rw [← coe_nonempty, coe_image₂]
exact image2_nonempty_iff
+@[aesop safe apply (rule_sets := [finsetNonempty])]
theorem Nonempty.image₂ (hs : s.Nonempty) (ht : t.Nonempty) : (image₂ f s t).Nonempty :=
image₂_nonempty_iff.2 ⟨hs, ht⟩
@@ -192,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
@@ -207,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)
@@ -427,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
@@ -449,13 +453,13 @@ 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. -/
-theorem subset_image₂ {s : Set α} {t : Set β} (hu : ↑u ⊆ image2 f s t) :
+theorem subset_set_image₂ {s : Set α} {t : Set β} (hu : ↑u ⊆ image2 f s t) :
∃ (s' : Finset α) (t' : Finset β), ↑s' ⊆ s ∧ ↑t' ⊆ t ∧ u ⊆ image₂ f s' t' := by
- rw [← Set.image_prod, subset_image_iff] at hu
+ rw [← Set.image_prod, subset_set_image_iff] at hu
rcases hu with ⟨u, hu, rfl⟩
classical
use u.image Prod.fst, u.image Prod.snd
@@ -463,6 +467,8 @@ theorem subset_image₂ {s : Set α} {t : Set β} (hu : ↑u ⊆ image2 f s t) :
image_subset_iff]
exact ⟨fun _ h ↦ (hu h).1, fun _ h ↦ (hu h).2, fun x hx ↦ mem_image₂_of_mem hx hx⟩
+@[deprecated (since := "2024-09-22")] alias subset_image₂ := subset_set_image₂
+
end
section UnionInter
@@ -576,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/NatDivisors.lean b/Mathlib/Data/Finset/NatDivisors.lean
index 07fa594f4b6a3..cbc7aa896c2f5 100644
--- a/Mathlib/Data/Finset/NatDivisors.lean
+++ b/Mathlib/Data/Finset/NatDivisors.lean
@@ -3,8 +3,8 @@ Copyright (c) 2023 Damiano Testa. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Damiano Testa, Yury Kudryashov
-/
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
import Mathlib.NumberTheory.Divisors
-import Mathlib.Data.Finset.Pointwise.Basic
/-!
# `Nat.divisors` as a multiplicative homomorpism
diff --git a/Mathlib/Data/Finset/NoncommProd.lean b/Mathlib/Data/Finset/NoncommProd.lean
index 61a09de161041..7140198dd8237 100644
--- a/Mathlib/Data/Finset/NoncommProd.lean
+++ b/Mathlib/Data/Finset/NoncommProd.lean
@@ -39,11 +39,11 @@ namespace Multiset
on all elements `x ∈ s`. -/
def noncommFoldr (s : Multiset α)
(comm : { x | x ∈ s }.Pairwise fun x y => ∀ b, f x (f y b) = f y (f x b)) (b : β) : β :=
- s.attach.foldr (f ∘ Subtype.val)
- (fun ⟨_, hx⟩ ⟨_, hy⟩ =>
+ letI : LeftCommutative (α := { x // x ∈ s }) (f ∘ Subtype.val) :=
+ ⟨fun ⟨_, hx⟩ ⟨_, hy⟩ =>
haveI : IsRefl α fun x y => ∀ b, f x (f y b) = f y (f x b) := ⟨fun _ _ => rfl⟩
- comm.of_refl hx hy)
- b
+ comm.of_refl hx hy⟩
+ s.attach.foldr (f ∘ Subtype.val) b
@[simp]
theorem noncommFoldr_coe (l : List α) (comm) (b : β) :
@@ -61,8 +61,8 @@ theorem noncommFoldr_cons (s : Multiset α) (a : α) (h h') (b : β) :
induction s using Quotient.inductionOn
simp
-theorem noncommFoldr_eq_foldr (s : Multiset α) (h : LeftCommutative f) (b : β) :
- noncommFoldr f s (fun x _ y _ _ => h x y) b = foldr f h b s := by
+theorem noncommFoldr_eq_foldr (s : Multiset α) [h : LeftCommutative f] (b : β) :
+ noncommFoldr f s (fun x _ y _ _ => h.left_comm x y) b = foldr f b s := by
induction s using Quotient.inductionOn
simp
@@ -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/Pi.lean b/Mathlib/Data/Finset/Pi.lean
index 4415777515d4a..9751986c4519c 100644
--- a/Mathlib/Data/Finset/Pi.lean
+++ b/Mathlib/Data/Finset/Pi.lean
@@ -85,10 +85,17 @@ theorem Pi.cons_injective {a : α} {b : δ a} {s : Finset α} (hs : a ∉ s) :
theorem pi_empty {t : ∀ a : α, Finset (β a)} : pi (∅ : Finset α) t = singleton (Pi.empty β) :=
rfl
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
lemma pi_nonempty : (s.pi t).Nonempty ↔ ∀ a ∈ s, (t a).Nonempty := by
simp [Finset.Nonempty, Classical.skolem]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, pi_nonempty_of_forall_nonempty⟩ := pi_nonempty
+
+@[simp]
+lemma pi_eq_empty : s.pi t = ∅ ↔ ∃ a ∈ s, t a = ∅ := by
+ simp [← not_nonempty_iff_eq_empty]
+
@[simp]
theorem pi_insert [∀ a, DecidableEq (β a)] {s : Finset α} {t : ∀ a : α, Finset (β a)} {a : α}
(ha : a ∉ s) : pi (insert a s) t = (t a).biUnion fun b => (pi s t).image (Pi.cons s a b) := by
@@ -146,5 +153,30 @@ def piDiag (s : Finset α) (ι : Type*) [DecidableEq (ι → α)] : Finset (ι
@[simp] lemma card_piDiag (s : Finset α) (ι : Type*) [DecidableEq (ι → α)] [Nonempty ι] :
(s.piDiag ι).card = s.card := by rw [piDiag, card_image_of_injective _ const_injective]
+/-! ### Restriction -/
+
+variable {π : ι → Type*}
+
+/-- Restrict domain of a function `f` to a finite set `s`. -/
+@[simp]
+def restrict (s : Finset ι) (f : (i : ι) → π i) : (i : s) → π i := fun x ↦ f x
+
+theorem restrict_def (s : Finset ι) : s.restrict (π := π) = fun f x ↦ f x := rfl
+
+/-- If a function `f` is restricted to a finite set `t`, and `s ⊆ t`,
+this is the restriction to `s`. -/
+@[simp]
+def restrict₂ {s t : Finset ι} (hst : s ⊆ t) (f : (i : t) → π i) : (i : s) → π i :=
+ fun x ↦ f ⟨x.1, hst x.2⟩
+
+theorem restrict₂_def {s t : Finset ι} (hst : s ⊆ t) :
+ restrict₂ (π := π) hst = fun f x ↦ f ⟨x.1, hst x.2⟩ := rfl
+
+theorem restrict₂_comp_restrict {s t : Finset ι} (hst : s ⊆ t) :
+ (restrict₂ (π := π) hst) ∘ t.restrict = s.restrict := rfl
+
+theorem restrict₂_comp_restrict₂ {s t u : Finset ι} (hst : s ⊆ t) (htu : t ⊆ u) :
+ (restrict₂ (π := π) hst) ∘ (restrict₂ htu) = restrict₂ (hst.trans htu) := rfl
+
end Pi
end Finset
diff --git a/Mathlib/Data/Finset/PiInduction.lean b/Mathlib/Data/Finset/PiInduction.lean
index 4eb4a769d4e6a..14801945c227c 100644
--- a/Mathlib/Data/Finset/PiInduction.lean
+++ b/Mathlib/Data/Finset/PiInduction.lean
@@ -3,6 +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.Data.Finset.Max
import Mathlib.Data.Finset.Sigma
import Mathlib.Data.Fintype.Card
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/Pointwise/Card.lean b/Mathlib/Data/Finset/Pointwise/Card.lean
deleted file mode 100644
index 5516539f11c50..0000000000000
--- a/Mathlib/Data/Finset/Pointwise/Card.lean
+++ /dev/null
@@ -1,62 +0,0 @@
-/-
-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.Data.Finset.Pointwise.Basic
-import Mathlib.SetTheory.Cardinal.Finite
-
-/-!
-# Cardinalities of pointwise operations on sets.
--/
-
-namespace Set
-
-open Pointwise
-
-variable {α β : Type*}
-
-section MulAction
-variable [Group α] [MulAction α β]
-
-@[to_additive (attr := simp)]
-lemma card_smul_set (a : α) (s : Set β) : Nat.card ↥(a • s) = Nat.card s :=
- Nat.card_image_of_injective (MulAction.injective a) _
-
-end MulAction
-
-section IsCancelMul
-variable [Mul α] [IsCancelMul α] {s t : Set α}
-
-@[to_additive]
-lemma card_mul_le : Nat.card (s * t) ≤ Nat.card s * Nat.card t := by
- classical
- obtain h | h := (s * t).infinite_or_finite
- · simp [Set.Infinite.card_eq_zero h]
- obtain ⟨hs, ht⟩ | rfl | rfl := finite_mul.1 h
- · lift s to Finset α using hs
- lift t to Finset α using ht
- rw [← Finset.coe_mul]
- simpa [-Finset.coe_mul] using Finset.card_mul_le
- all_goals simp
-
-end IsCancelMul
-
-section InvolutiveInv
-variable [InvolutiveInv α] {s t : Set α}
-
-@[to_additive (attr := simp)]
-lemma card_inv (s : Set α) : Nat.card ↥(s⁻¹) = Nat.card s := by
- rw [← image_inv, Nat.card_image_of_injective inv_injective]
-
-end InvolutiveInv
-
-section Group
-variable [Group α] {s t : Set α}
-
-@[to_additive]
-lemma card_div_le : Nat.card (s / t) ≤ Nat.card s * Nat.card t := by
- rw [div_eq_mul_inv, ← card_inv t]; exact card_mul_le
-
-end Group
-end Set
diff --git a/Mathlib/Data/Finset/Powerset.lean b/Mathlib/Data/Finset/Powerset.lean
index ca7a34c9e0cbb..6e8275f105d31 100644
--- a/Mathlib/Data/Finset/Powerset.lean
+++ b/Mathlib/Data/Finset/Powerset.lean
@@ -234,10 +234,13 @@ theorem powersetCard_succ_insert [DecidableEq α] {x : α} {s : Finset α} (h :
have : x ∉ t := fun H => h (ht H)
simp [card_insert_of_not_mem this, Nat.succ_inj']
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
lemma powersetCard_nonempty : (powersetCard n s).Nonempty ↔ n ≤ s.card := by
aesop (add simp [Finset.Nonempty, exists_subset_card_eq, card_le_card])
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, powersetCard_nonempty_of_le⟩ := powersetCard_nonempty
+
@[simp]
theorem powersetCard_self (s : Finset α) : powersetCard s.card s = {s} := by
ext
diff --git a/Mathlib/Data/Finset/Preimage.lean b/Mathlib/Data/Finset/Preimage.lean
index 840e7e2c93e3e..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
@@ -80,6 +81,10 @@ theorem map_subset_iff_subset_preimage {f : α ↪ β} {s : Finset α} {t : Fins
s.map f ⊆ t ↔ s ⊆ t.preimage f f.injective.injOn := by
classical rw [map_eq_image, image_subset_iff_subset_preimage]
+lemma card_preimage (s : Finset β) (f : α → β) (hf) [DecidablePred (· ∈ Set.range f)] :
+ (s.preimage f hf).card = {x ∈ s | x ∈ Set.range f}.card :=
+ card_nbij f (by simp) (by simpa) (fun b hb ↦ by aesop)
+
theorem image_preimage [DecidableEq β] (f : α → β) (s : Finset β) [∀ x, Decidable (x ∈ Set.range f)]
(hf : Set.InjOn f (f ⁻¹' ↑s)) : image f (preimage s f hf) = s.filter fun x => x ∈ Set.range f :=
Finset.coe_inj.1 <| by
@@ -90,13 +95,17 @@ 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))
theorem subset_map_iff {f : α ↪ β} {s : Finset β} {t : Finset α} :
s ⊆ t.map f ↔ ∃ u ⊆ t, s = u.map f := by
classical
- simp_rw [← coe_subset, coe_map, subset_image_iff, map_eq_image, eq_comm]
+ simp_rw [map_eq_image, subset_image_iff, eq_comm]
theorem sigma_preimage_mk {β : α → Type*} [DecidableEq α] (s : Finset (Σa, β a)) (t : Finset α) :
(t.sigma fun a => s.preimage (Sigma.mk a) sigma_mk_injective.injOn) =
@@ -114,5 +123,13 @@ theorem sigma_image_fst_preimage_mk {β : α → Type*} [DecidableEq α] (s : Fi
s :=
s.sigma_preimage_mk_of_subset (Subset.refl _)
+@[simp] lemma preimage_inl (s : Finset (α ⊕ β)) :
+ s.preimage Sum.inl Sum.inl_injective.injOn = s.toLeft := by
+ ext x; simp
+
+@[simp] lemma preimage_inr (s : Finset (α ⊕ β)) :
+ s.preimage Sum.inr Sum.inr_injective.injOn = s.toRight := by
+ ext x; simp
+
end Preimage
end Finset
diff --git a/Mathlib/Data/Finset/Prod.lean b/Mathlib/Data/Finset/Prod.lean
index b0304921a947b..5af6d692ec6e5 100644
--- a/Mathlib/Data/Finset/Prod.lean
+++ b/Mathlib/Data/Finset/Prod.lean
@@ -168,6 +168,7 @@ theorem empty_product (t : Finset β) : (∅ : Finset α) ×ˢ t = ∅ :=
theorem product_empty (s : Finset α) : s ×ˢ (∅ : Finset β) = ∅ :=
eq_empty_of_forall_not_mem fun _ h => not_mem_empty _ (Finset.mem_product.1 h).2
+@[aesop safe apply (rule_sets := [finsetNonempty])]
theorem Nonempty.product (hs : s.Nonempty) (ht : t.Nonempty) : (s ×ˢ t).Nonempty :=
let ⟨x, hx⟩ := hs
let ⟨y, hy⟩ := ht
@@ -181,7 +182,7 @@ theorem Nonempty.snd (h : (s ×ˢ t).Nonempty) : t.Nonempty :=
let ⟨xy, hxy⟩ := h
⟨xy.2, (mem_product.1 hxy).2⟩
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem nonempty_product : (s ×ˢ t).Nonempty ↔ s.Nonempty ∧ t.Nonempty :=
⟨fun h => ⟨h.fst, h.snd⟩, fun h => h.1.product h.2⟩
diff --git a/Mathlib/Data/Finset/SMulAntidiagonal.lean b/Mathlib/Data/Finset/SMulAntidiagonal.lean
index 86b0c882b6255..53d0c959253ec 100644
--- a/Mathlib/Data/Finset/SMulAntidiagonal.lean
+++ b/Mathlib/Data/Finset/SMulAntidiagonal.lean
@@ -3,7 +3,7 @@ Copyright (c) 2024 Scott Carnahan. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Carnahan
-/
-import Mathlib.Data.Set.Pointwise.SMul
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Data.Set.SMulAntidiagonal
/-!
diff --git a/Mathlib/Data/Finset/Sigma.lean b/Mathlib/Data/Finset/Sigma.lean
index 5be327d9e74de..9be90160317cf 100644
--- a/Mathlib/Data/Finset/Sigma.lean
+++ b/Mathlib/Data/Finset/Sigma.lean
@@ -5,6 +5,7 @@ Authors: Mario Carneiro, Yaël Dillies, Bhavik Mehta
-/
import Mathlib.Data.Finset.Lattice
import Mathlib.Data.Set.Sigma
+import Mathlib.Order.CompleteLattice.Finset
/-!
# Finite sets in a sigma type
@@ -51,9 +52,12 @@ theorem coe_sigma (s : Finset ι) (t : ∀ i, Finset (α i)) :
(s.sigma t : Set (Σ i, α i)) = (s : Set ι).sigma fun i ↦ (t i : Set (α i)) :=
Set.ext fun _ => mem_sigma
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem sigma_nonempty : (s.sigma t).Nonempty ↔ ∃ i ∈ s, (t i).Nonempty := by simp [Finset.Nonempty]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, Aesop.sigma_nonempty_of_exists_nonempty⟩ := sigma_nonempty
+
@[simp]
theorem sigma_eq_empty : s.sigma t = ∅ ↔ ∀ i ∈ s, t i = ∅ := by
simp only [← not_nonempty_iff_eq_empty, sigma_nonempty, not_exists, not_and]
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 a8cf2ef2b5057..923e35810f214 100644
--- a/Mathlib/Data/Finset/Sort.lean
+++ b/Mathlib/Data/Finset/Sort.lean
@@ -6,7 +6,7 @@ Authors: Mario Carneiro
import Mathlib.Order.RelIso.Set
import Mathlib.Data.Multiset.Sort
import Mathlib.Data.List.NodupEquivFin
-import Mathlib.Data.Finset.Lattice
+import Mathlib.Data.Finset.Max
import Mathlib.Data.Fintype.Card
/-!
@@ -32,6 +32,10 @@ variable (r : α → α → Prop) [DecidableRel r] [IsTrans α r] [IsAntisymm α
def sort (s : Finset α) : List α :=
Multiset.sort r s.1
+@[simp]
+theorem sort_val (s : Finset α) : Multiset.sort r s.val = sort r s :=
+ rfl
+
@[simp]
theorem sort_sorted (s : Finset α) : List.Sorted r (sort r s) :=
Multiset.sort_sorted _ _
@@ -64,11 +68,27 @@ theorem sort_empty : sort r ∅ = [] :=
theorem sort_singleton (a : α) : sort r {a} = [a] :=
Multiset.sort_singleton r a
+theorem sort_cons {a : α} {s : Finset α} (h₁ : ∀ b ∈ s, r a b) (h₂ : a ∉ s) :
+ sort r (cons a s h₂) = a :: sort r s := by
+ rw [sort, cons_val, Multiset.sort_cons r a _ h₁, sort_val]
+
+theorem sort_insert [DecidableEq α] {a : α} {s : Finset α} (h₁ : ∀ b ∈ s, r a b) (h₂ : a ∉ s) :
+ sort r (insert a s) = a :: sort r s := by
+ rw [← cons_eq_insert _ _ h₂, sort_cons r h₁]
+
open scoped List in
theorem sort_perm_toList (s : Finset α) : sort r s ~ s.toList := by
rw [← Multiset.coe_eq_coe]
simp only [coe_toList, sort_eq]
+theorem _root_.List.toFinset_sort [DecidableEq α] {l : List α} (hl : l.Nodup) :
+ sort r l.toFinset = l ↔ l.Sorted r := by
+ refine ⟨?_, List.eq_of_perm_of_sorted ((sort_perm_toList r _).trans (List.toFinset_toList hl))
+ (sort_sorted r _)⟩
+ intro h
+ rw [← h]
+ exact sort_sorted r _
+
end sort
section SortLinearOrder
@@ -188,8 +208,8 @@ theorem orderEmbOfFin_singleton (a : α) (i : Fin 1) :
the increasing bijection `orderEmbOfFin s h`. -/
theorem orderEmbOfFin_unique {s : Finset α} {k : ℕ} (h : s.card = k) {f : Fin k → α}
(hfs : ∀ x, f x ∈ s) (hmono : StrictMono f) : f = s.orderEmbOfFin h := by
- apply Fin.strictMono_unique hmono (s.orderEmbOfFin h).strictMono
- rw [range_orderEmbOfFin, ← Set.image_univ, ← coe_univ, ← coe_image, coe_inj]
+ rw [← hmono.range_inj (s.orderEmbOfFin h).strictMono, range_orderEmbOfFin, ← Set.image_univ,
+ ← coe_univ, ← coe_image, coe_inj]
refine eq_of_subset_of_card_le (fun x hx => ?_) ?_
· rcases mem_image.1 hx with ⟨x, _, rfl⟩
exact hfs x
@@ -199,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/Sum.lean b/Mathlib/Data/Finset/Sum.lean
index f9863829696b5..678aaccf6ad61 100644
--- a/Mathlib/Data/Finset/Sum.lean
+++ b/Mathlib/Data/Finset/Sum.lean
@@ -1,7 +1,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
+Authors: Yaël Dillies, Bhavik Mehta
-/
import Mathlib.Data.Multiset.Sum
import Mathlib.Data.Finset.Card
@@ -15,6 +15,8 @@ the `Finset.sum` operation which computes the additive sum.
## Main declarations
* `Finset.disjSum`: `s.disjSum t` is the disjoint sum of `s` and `t`.
+* `Finset.toLeft`: Given a finset of elements `α ⊕ β`, extracts all the elements of the form `α`.
+* `Finset.toRight`: Given a finset of elements `α ⊕ β`, extracts all the elements of the form `β`.
-/
@@ -94,4 +96,109 @@ theorem disj_sum_strictMono_right (s : Finset α) :
StrictMono (s.disjSum : Finset β → Finset (α ⊕ β)) := fun _ _ =>
disjSum_ssubset_disjSum_of_subset_of_ssubset Subset.rfl
+@[simp] lemma disjSum_inj {α β : Type*} {s₁ s₂ : Finset α} {t₁ t₂ : Finset β} :
+ s₁.disjSum t₁ = s₂.disjSum t₂ ↔ s₁ = s₂ ∧ t₁ = t₂ := by
+ simp [Finset.ext_iff]
+
+lemma Injective2_disjSum {α β : Type*} : Function.Injective2 (@disjSum α β) :=
+ fun _ _ _ _ => by simp [Finset.ext_iff]
+
+/--
+Given a finset of elements `α ⊕ β`, extract all the elements of the form `α`. This
+forms a quasi-inverse to `disjSum`, in that it recovers its left input.
+
+See also `List.partitionMap`.
+-/
+def toLeft (s : Finset (α ⊕ β)) : Finset α :=
+ s.disjiUnion (Sum.elim singleton (fun _ => ∅)) <| by
+ simp [Set.PairwiseDisjoint, Set.Pairwise, Function.onFun, eq_comm]
+
+/--
+Given a finset of elements `α ⊕ β`, extract all the elements of the form `β`. This
+forms a quasi-inverse to `disjSum`, in that it recovers its right input.
+
+See also `List.partitionMap`.
+-/
+def toRight (s : Finset (α ⊕ β)) : Finset β :=
+ s.disjiUnion (Sum.elim (fun _ => ∅) singleton) <| by
+ simp [Set.PairwiseDisjoint, Set.Pairwise, Function.onFun, eq_comm]
+
+variable {u v : Finset (α ⊕ β)}
+
+@[simp] lemma mem_toLeft {x : α} : x ∈ u.toLeft ↔ inl x ∈ u := by
+ simp [toLeft]
+
+@[simp] lemma mem_toRight {x : β} : x ∈ u.toRight ↔ inr x ∈ u := by
+ simp [toRight]
+
+@[gcongr]
+lemma toLeft_subset_toLeft : u ⊆ v → u.toLeft ⊆ v.toLeft :=
+ fun h _ => by simpa only [mem_toLeft] using @h _
+
+@[gcongr]
+lemma toRight_subset_toRight : u ⊆ v → u.toRight ⊆ v.toRight :=
+ fun h _ => by simpa only [mem_toRight] using @h _
+
+lemma toLeft_monotone : Monotone (@toLeft α β) := fun _ _ => toLeft_subset_toLeft
+lemma toRight_monotone : Monotone (@toRight α β) := fun _ _ => toRight_subset_toRight
+
+lemma toLeft_disjSum_toRight : u.toLeft.disjSum u.toRight = u := by
+ ext (x | x) <;> simp
+
+lemma card_toLeft_add_card_toRight : u.toLeft.card + u.toRight.card = u.card := by
+ rw [← card_disjSum, toLeft_disjSum_toRight]
+
+lemma card_toLeft_le : u.toLeft.card ≤ u.card :=
+ (Nat.le_add_right _ _).trans_eq card_toLeft_add_card_toRight
+
+lemma card_toRight_le : u.toRight.card ≤ u.card :=
+ (Nat.le_add_left _ _).trans_eq card_toLeft_add_card_toRight
+
+@[simp] lemma toLeft_disjSum : (s.disjSum t).toLeft = s := by ext x; simp
+
+@[simp] lemma toRight_disjSum : (s.disjSum t).toRight = t := by ext x; simp
+
+lemma disjSum_eq_iff : s.disjSum t = u ↔ s = u.toLeft ∧ t = u.toRight :=
+ ⟨fun h => by simp [← h], fun h => by simp [h, toLeft_disjSum_toRight]⟩
+
+lemma eq_disjSum_iff : u = s.disjSum t ↔ u.toLeft = s ∧ u.toRight = t :=
+ ⟨fun h => by simp [h], fun h => by simp [← h, toLeft_disjSum_toRight]⟩
+
+@[simp] lemma toLeft_map_sumComm : (u.map (Equiv.sumComm _ _).toEmbedding).toLeft = u.toRight := by
+ ext x; simp
+
+@[simp] lemma toRight_map_sumComm : (u.map (Equiv.sumComm _ _).toEmbedding).toRight = u.toLeft := by
+ ext x; simp
+
+@[simp] lemma toLeft_cons_inl (ha) :
+ (cons (inl a) u ha).toLeft = cons a u.toLeft (by simpa) := by ext y; simp
+@[simp] lemma toLeft_cons_inr (hb) :
+ (cons (inr b) u hb).toLeft = u.toLeft := by ext y; simp
+@[simp] lemma toRight_cons_inl (ha) :
+ (cons (inl a) u ha).toRight = u.toRight := by ext y; simp
+@[simp] lemma toRight_cons_inr (hb) :
+ (cons (inr b) u hb).toRight = cons b u.toRight (by simpa) := by ext y; simp
+
+variable [DecidableEq α] [DecidableEq β]
+
+lemma toLeft_image_swap : (u.image Sum.swap).toLeft = u.toRight := by
+ ext x; simp
+
+lemma toRight_image_swap : (u.image Sum.swap).toRight = u.toLeft := by
+ ext x; simp
+
+@[simp] lemma toLeft_insert_inl : (insert (inl a) u).toLeft = insert a u.toLeft := by ext y; simp
+@[simp] lemma toLeft_insert_inr : (insert (inr b) u).toLeft = u.toLeft := by ext y; simp
+@[simp] lemma toRight_insert_inl : (insert (inl a) u).toRight = u.toRight := by ext y; simp
+@[simp] lemma toRight_insert_inr : (insert (inr b) u).toRight = insert b u.toRight := by ext y; simp
+
+lemma toLeft_inter : (u ∩ v).toLeft = u.toLeft ∩ v.toLeft := by ext x; simp
+lemma toRight_inter : (u ∩ v).toRight = u.toRight ∩ v.toRight := by ext x; simp
+
+lemma toLeft_union : (u ∪ v).toLeft = u.toLeft ∪ v.toLeft := by ext x; simp
+lemma toRight_union : (u ∪ v).toRight = u.toRight ∪ v.toRight := by ext x; simp
+
+lemma toLeft_sdiff : (u \ v).toLeft = u.toLeft \ v.toLeft := by ext x; simp
+lemma toRight_sdiff : (u \ v).toRight = u.toRight \ v.toRight := by ext x; simp
+
end Finset
diff --git a/Mathlib/Data/Finset/Sups.lean b/Mathlib/Data/Finset/Sups.lean
index 31bed739a4441..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}
@@ -99,10 +97,11 @@ theorem forall_sups_iff {p : α → Prop} : (∀ c ∈ s ⊻ t, p c) ↔ ∀ a
theorem sups_subset_iff : s ⊻ t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a ⊔ b ∈ u :=
image₂_subset_iff
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem sups_nonempty : (s ⊻ t).Nonempty ↔ s.Nonempty ∧ t.Nonempty :=
image₂_nonempty_iff
+@[aesop safe apply (rule_sets := [finsetNonempty])]
protected theorem Nonempty.sups : s.Nonempty → t.Nonempty → (s ⊻ t).Nonempty :=
Nonempty.image₂
@@ -145,7 +144,7 @@ theorem sups_inter_subset_right : s ⊻ (t₁ ∩ t₂) ⊆ s ⊻ t₁ ∩ s ⊻
theorem subset_sups {s t : Set α} :
↑u ⊆ s ⊻ t → ∃ s' t' : Finset α, ↑s' ⊆ s ∧ ↑t' ⊆ t ∧ u ⊆ s' ⊻ t' :=
- subset_image₂
+ subset_set_image₂
lemma image_sups (f : F) (s t : Finset α) : image f (s ⊻ t) = image f s ⊻ image f t :=
image_image₂_distrib <| map_sup f
@@ -161,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)
@@ -213,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}
@@ -245,10 +242,11 @@ theorem forall_infs_iff {p : α → Prop} : (∀ c ∈ s ⊼ t, p c) ↔ ∀ a
theorem infs_subset_iff : s ⊼ t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a ⊓ b ∈ u :=
image₂_subset_iff
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem infs_nonempty : (s ⊼ t).Nonempty ↔ s.Nonempty ∧ t.Nonempty :=
image₂_nonempty_iff
+@[aesop safe apply (rule_sets := [finsetNonempty])]
protected theorem Nonempty.infs : s.Nonempty → t.Nonempty → (s ⊼ t).Nonempty :=
Nonempty.image₂
@@ -291,7 +289,7 @@ theorem infs_inter_subset_right : s ⊼ (t₁ ∩ t₂) ⊆ s ⊼ t₁ ∩ s ⊼
theorem subset_infs {s t : Set α} :
↑u ⊆ s ⊼ t → ∃ s' t' : Finset α, ↑s' ⊆ s ∧ ↑t' ⊆ t ∧ u ⊆ s' ⊼ t' :=
- subset_image₂
+ subset_set_image₂
lemma image_infs (f : F) (s t : Finset α) : image f (s ⊼ t) = image f s ⊼ image f t :=
image_image₂_distrib <| map_inf f
@@ -307,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)
@@ -358,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
@@ -394,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
@@ -414,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₂}
@@ -480,6 +477,8 @@ theorem disjSups_comm : s ○ t = t ○ s := by
rw [sup_comm] at hs
exact ⟨b, hb, a, ha, hd, hs⟩
+instance : @Std.Commutative (Finset α) (· ○ ·) := ⟨disjSups_comm⟩
+
end DisjSups
open FinsetFamily
@@ -490,12 +489,14 @@ variable [DecidableEq α]
variable [DistribLattice α] [OrderBot α] [@DecidableRel α Disjoint] (s t u v : Finset α)
theorem disjSups_assoc : ∀ s t u : Finset α, s ○ t ○ u = s ○ (t ○ u) := by
- refine associative_of_commutative_of_le disjSups_comm ?_
+ refine (associative_of_commutative_of_le inferInstance ?_).assoc
simp only [le_eq_subset, disjSups_subset_iff, mem_disjSups]
rintro s t u _ ⟨a, ha, b, hb, hab, rfl⟩ c hc habc
rw [disjoint_sup_left] at habc
exact ⟨a, ha, _, ⟨b, hb, c, hc, habc.2, rfl⟩, hab.sup_right habc.1, (sup_assoc ..).symm⟩
+instance : @Std.Associative (Finset α) (· ○ ·) := ⟨disjSups_assoc⟩
+
theorem disjSups_left_comm : s ○ (t ○ u) = t ○ (s ○ u) := by
simp_rw [← disjSups_assoc, disjSups_comm s]
@@ -507,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₂ (· \ ·)
@@ -528,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}
@@ -551,9 +551,10 @@ lemma forall_mem_diffs {p : α → Prop} : (∀ c ∈ s \\ t, p c) ↔ ∀ a ∈
@[simp] lemma diffs_subset_iff : s \\ t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a \ b ∈ u := image₂_subset_iff
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
lemma diffs_nonempty : (s \\ t).Nonempty ↔ s.Nonempty ∧ t.Nonempty := image₂_nonempty_iff
+@[aesop safe apply (rule_sets := [finsetNonempty])]
protected lemma Nonempty.diffs : s.Nonempty → t.Nonempty → (s \\ t).Nonempty := Nonempty.image₂
lemma Nonempty.of_diffs_left : (s \\ t).Nonempty → s.Nonempty := Nonempty.of_image₂_left
@@ -575,7 +576,7 @@ lemma diffs_inter_subset_right : s \\ (t₁ ∩ t₂) ⊆ s \\ t₁ ∩ s \\ t
lemma subset_diffs {s t : Set α} :
↑u ⊆ Set.image2 (· \ ·) s t → ∃ s' t' : Finset α, ↑s' ⊆ s ∧ ↑t' ⊆ t ∧ u ⊆ s' \\ t' :=
- subset_image₂
+ subset_set_image₂
variable (s t u)
@@ -591,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⟩
@@ -601,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]
@@ -612,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
@@ -625,10 +626,11 @@ lemma exists_compls_iff {p : α → Prop} : (∃ a ∈ sᶜˢ, p a) ↔ ∃ a
lemma compls_subset_iff : sᶜˢ ⊆ t ↔ s ⊆ tᶜˢ := by rw [← compls_subset_compls, compls_compls]
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
lemma compls_nonempty : sᶜˢ.Nonempty ↔ s.Nonempty := map_nonempty
protected alias ⟨Nonempty.of_compls, Nonempty.compls⟩ := compls_nonempty
+attribute [aesop safe apply (rule_sets := [finsetNonempty])] Nonempty.compls
@[simp] lemma compls_empty : (∅ : Finset α)ᶜˢ = ∅ := map_empty _
@[simp] lemma compls_eq_empty : sᶜˢ = ∅ ↔ s = ∅ := map_eq_empty
diff --git a/Mathlib/Data/Finset/Sym.lean b/Mathlib/Data/Finset/Sym.lean
index 951449e44c9db..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
@@ -109,11 +107,12 @@ theorem sym2_empty : (∅ : Finset α).sym2 = ∅ := rfl
theorem sym2_eq_empty : s.sym2 = ∅ ↔ s = ∅ := by
rw [← val_eq_zero, sym2_val, Multiset.sym2_eq_zero_iff, val_eq_zero]
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem sym2_nonempty : s.sym2.Nonempty ↔ s.Nonempty := by
rw [← not_iff_not]
simp_rw [not_nonempty_iff_eq_empty, sym2_eq_empty]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
protected alias ⟨_, Nonempty.sym2⟩ := sym2_nonempty
@[simp]
diff --git a/Mathlib/Data/Finset/Union.lean b/Mathlib/Data/Finset/Union.lean
index b54499d3e58d9..fd0fac60d95ee 100644
--- a/Mathlib/Data/Finset/Union.lean
+++ b/Mathlib/Data/Finset/Union.lean
@@ -52,7 +52,7 @@ lemma disjiUnion_val (s : Finset α) (t : α → Finset β) (h) :
@[simp, norm_cast]
lemma coe_disjiUnion {h} : (s.disjiUnion t h : Set β) = ⋃ x ∈ (s : Set α), t x := by
- simp [Set.ext_iff, mem_disjiUnion, Set.mem_iUnion, iff_self_iff, mem_coe, imp_true_iff]
+ simp [Set.ext_iff, mem_disjiUnion, Set.mem_iUnion, mem_coe, imp_true_iff]
@[simp] lemma disjiUnion_cons (a : α) (s : Finset α) (ha : a ∉ s) (f : α → Finset β) (H) :
disjiUnion (cons a s ha) f H =
@@ -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
@@ -119,7 +119,7 @@ protected def biUnion (s : Finset α) (t : α → Finset β) : Finset β :=
@[simp, norm_cast]
lemma coe_biUnion : (s.biUnion t : Set β) = ⋃ x ∈ (s : Set α), t x := by
- simp [Set.ext_iff, mem_biUnion, Set.mem_iUnion, iff_self_iff, mem_coe, imp_true_iff]
+ simp [Set.ext_iff, mem_biUnion, Set.mem_iUnion, mem_coe, imp_true_iff]
@[simp]
lemma biUnion_insert [DecidableEq α] {a : α} : (insert a s).biUnion t = t a ∪ s.biUnion t :=
diff --git a/Mathlib/Data/Finset/Update.lean b/Mathlib/Data/Finset/Update.lean
index a0a7aa87054bf..d4dfb055c18ea 100644
--- a/Mathlib/Data/Finset/Update.lean
+++ b/Mathlib/Data/Finset/Update.lean
@@ -56,8 +56,7 @@ theorem updateFinset_updateFinset {s t : Finset ι} (hst : Disjoint s t)
set e := Equiv.Finset.union s t hst
congr with i
by_cases his : i ∈ s <;> by_cases hit : i ∈ t <;>
- simp only [updateFinset, his, hit, dif_pos, dif_neg, Finset.mem_union, true_or_iff,
- false_or_iff, not_false_iff]
+ simp only [updateFinset, his, hit, dif_pos, dif_neg, Finset.mem_union, false_or, not_false_iff]
· exfalso; exact Finset.disjoint_left.mp hst his hit
· exact piCongrLeft_sum_inl (fun b : ↥(s ∪ t) => π b) e y z ⟨i, his⟩ |>.symm
· exact piCongrLeft_sum_inr (fun b : ↥(s ∪ t) => π b) e y z ⟨i, hit⟩ |>.symm
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 17123acc6aff6..97af1005ed711 100644
--- a/Mathlib/Data/Finsupp/Basic.lean
+++ b/Mathlib/Data/Finsupp/Basic.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johannes Hölzl, Scott Morrison
+Authors: Johannes Hölzl, Kim Morrison
-/
import Mathlib.Algebra.BigOperators.Finsupp
import Mathlib.Algebra.Group.Action.Basic
@@ -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)
@@ -622,7 +622,7 @@ theorem sum_comapDomain [Zero M] [AddCommMonoid N] (f : α → β) (l : β →
theorem eq_zero_of_comapDomain_eq_zero [AddCommMonoid M] (f : α → β) (l : β →₀ M)
(hf : Set.BijOn f (f ⁻¹' ↑l.support) ↑l.support) : comapDomain f l hf.injOn = 0 → l = 0 := by
rw [← support_eq_empty, ← support_eq_empty, comapDomain]
- simp only [Finset.ext_iff, Finset.not_mem_empty, iff_false_iff, mem_preimage]
+ simp only [Finset.ext_iff, Finset.not_mem_empty, iff_false, mem_preimage]
intro h a ha
cases' hf.2.2 ha with b hb
exact h b (hb.2.symm ▸ ha)
@@ -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 4e65162454d8b..31b93c4c9ac8f 100644
--- a/Mathlib/Data/Finsupp/Defs.lean
+++ b/Mathlib/Data/Finsupp/Defs.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johannes Hölzl, Scott Morrison
+Authors: Johannes Hölzl, Kim Morrison
-/
import Mathlib.Algebra.Group.Indicator
import Mathlib.Algebra.Group.Submonoid.Basic
@@ -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` -/
@@ -756,7 +762,7 @@ def embDomain (f : α ↪ β) (v : α →₀ M) : β →₀ M where
mem_support_toFun a₂ := by
dsimp
split_ifs with h
- · simp only [h, true_iff_iff, Ne]
+ · simp only [h, true_iff, Ne]
rw [← not_mem_support_iff, not_not]
classical apply Finset.choose_mem
· simp only [h, Ne, ne_self_iff_false, not_true_eq_false]
@@ -1048,6 +1054,60 @@ theorem induction_linear {p : (α →₀ M) → Prop} (f : α →₀ M) (h0 : p
(hadd : ∀ f g : α →₀ M, p f → p g → p (f + g)) (hsingle : ∀ a b, p (single a b)) : p f :=
induction₂ f h0 fun _a _b _f _ _ w => hadd _ _ w (hsingle _ _)
+section LinearOrder
+
+variable [LinearOrder α] {p : (α →₀ M) → Prop}
+
+/-- A finitely supported function can be built by adding up `single a b` for increasing `a`.
+
+The theorem `induction_on_max₂` swaps the argument order in the sum. -/
+theorem induction_on_max (f : α →₀ M) (h0 : p 0)
+ (ha : ∀ (a b) (f : α →₀ M), (∀ c ∈ f.support, c < a) → b ≠ 0 → p f → p (single a b + f)) :
+ p f := by
+ suffices ∀ (s) (f : α →₀ M), f.support = s → p f from this _ _ rfl
+ refine fun s => s.induction_on_max (fun f h => ?_) (fun a s hm hf f hs => ?_)
+ · rwa [support_eq_empty.1 h]
+ · have hs' : (erase a f).support = s := by
+ rw [support_erase, hs, erase_insert (fun ha => (hm a ha).false)]
+ rw [← single_add_erase a f]
+ refine ha _ _ _ (fun c hc => hm _ <| hs'.symm ▸ hc) ?_ (hf _ hs')
+ rw [← mem_support_iff, hs]
+ exact mem_insert_self a s
+
+/-- A finitely supported function can be built by adding up `single a b` for decreasing `a`.
+
+The theorem `induction_on_min₂` swaps the argument order in the sum. -/
+theorem induction_on_min (f : α →₀ M) (h0 : p 0)
+ (ha : ∀ (a b) (f : α →₀ M), (∀ c ∈ f.support, a < c) → b ≠ 0 → p f → p (single a b + f)) :
+ p f :=
+ induction_on_max (α := αᵒᵈ) f h0 ha
+
+/-- A finitely supported function can be built by adding up `single a b` for increasing `a`.
+
+The theorem `induction_on_max` swaps the argument order in the sum. -/
+theorem induction_on_max₂ (f : α →₀ M) (h0 : p 0)
+ (ha : ∀ (a b) (f : α →₀ M), (∀ c ∈ f.support, c < a) → b ≠ 0 → p f → p (f + single a b)) :
+ p f := by
+ suffices ∀ (s) (f : α →₀ M), f.support = s → p f from this _ _ rfl
+ refine fun s => s.induction_on_max (fun f h => ?_) (fun a s hm hf f hs => ?_)
+ · rwa [support_eq_empty.1 h]
+ · have hs' : (erase a f).support = s := by
+ rw [support_erase, hs, erase_insert (fun ha => (hm a ha).false)]
+ rw [← erase_add_single a f]
+ refine ha _ _ _ (fun c hc => hm _ <| hs'.symm ▸ hc) ?_ (hf _ hs')
+ rw [← mem_support_iff, hs]
+ exact mem_insert_self a s
+
+/-- A finitely supported function can be built by adding up `single a b` for decreasing `a`.
+
+The theorem `induction_on_min` swaps the argument order in the sum. -/
+theorem induction_on_min₂ (f : α →₀ M) (h0 : p 0)
+ (ha : ∀ (a b) (f : α →₀ M), (∀ c ∈ f.support, a < c) → b ≠ 0 → p f → p (f + single a b)) :
+ p f :=
+ induction_on_max₂ (α := αᵒᵈ) f h0 ha
+
+end LinearOrder
+
@[simp]
theorem add_closure_setOf_eq_single :
AddSubmonoid.closure { f : α →₀ M | ∃ a b, f = single a b } = ⊤ :=
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/Pointwise.lean b/Mathlib/Data/Finsupp/Pointwise.lean
index 609f2a8f9b146..059bf76ad5eed 100644
--- a/Mathlib/Data/Finsupp/Pointwise.lean
+++ b/Mathlib/Data/Finsupp/Pointwise.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Module.Defs
import Mathlib.Algebra.Ring.Pi
diff --git a/Mathlib/Data/Finsupp/Weight.lean b/Mathlib/Data/Finsupp/Weight.lean
index fc57c22790c2d..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
@@ -157,7 +153,7 @@ theorem weight_eq_zero_iff_eq_zero
ext s
simp only [Finsupp.coe_zero, Pi.zero_apply]
by_contra hs
- apply NonTorsionWeight.ne_zero w _
+ apply NonTorsionWeight.ne_zero w s
rw [← nonpos_iff_eq_zero, ← h]
exact le_weight_of_ne_zero' w hs
· intro h
diff --git a/Mathlib/Data/Fintype/Basic.lean b/Mathlib/Data/Fintype/Basic.lean
index 64062b2403702..997a6dd16aeb4 100644
--- a/Mathlib/Data/Fintype/Basic.lean
+++ b/Mathlib/Data/Fintype/Basic.lean
@@ -93,7 +93,7 @@ theorem Nonempty.eq_univ [Subsingleton α] : s.Nonempty → s = univ := by
theorem univ_nonempty_iff : (univ : Finset α).Nonempty ↔ Nonempty α := by
rw [← coe_nonempty, coe_univ, Set.nonempty_iff_univ_nonempty]
-@[aesop unsafe apply (rule_sets := [finsetNonempty])]
+@[simp, aesop unsafe apply (rule_sets := [finsetNonempty])]
theorem univ_nonempty [Nonempty α] : (univ : Finset α).Nonempty :=
univ_nonempty_iff.2 ‹_›
@@ -270,7 +270,7 @@ theorem compl_erase : (s.erase a)ᶜ = insert a sᶜ := by
@[simp]
theorem compl_insert : (insert a s)ᶜ = sᶜ.erase a := by
ext
- simp only [not_or, mem_insert, iff_self_iff, mem_compl, mem_erase]
+ simp only [not_or, mem_insert, mem_compl, mem_erase]
theorem insert_compl_insert (ha : a ∉ s) : insert a (insert a s)ᶜ = sᶜ := by
simp_rw [compl_insert, insert_erase (mem_compl.2 ha)]
@@ -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) :=
@@ -492,7 +492,7 @@ This function computes by checking all terms `a : α` to find the `f a = b`, so
-/
def invOfMemRange : Set.range f → α := fun b =>
Finset.choose (fun a => f a = b) Finset.univ
- ((existsUnique_congr (by simp)).mp (hf.exists_unique_of_mem_range b.property))
+ ((existsUnique_congr (by simp)).mp (hf.existsUnique_of_mem_range b.property))
theorem left_inv_of_invOfMemRange (b : Set.range f) : f (hf.invOfMemRange b) = b :=
(Finset.choose_spec (fun a => f a = b) _ _).right
@@ -621,10 +621,13 @@ def decidableMemOfFintype [DecidableEq α] (s : Set α) [Fintype s] (a) : Decida
theorem coe_toFinset (s : Set α) [Fintype s] : (↑s.toFinset : Set α) = s :=
Set.ext fun _ => mem_toFinset
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem toFinset_nonempty {s : Set α} [Fintype s] : s.toFinset.Nonempty ↔ s.Nonempty := by
rw [← Finset.coe_nonempty, coe_toFinset]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, Aesop.toFinset_nonempty_of_nonempty⟩ := toFinset_nonempty
+
@[simp]
theorem toFinset_inj {s t : Set α} [Fintype s] [Fintype t] : s.toFinset = t.toFinset ↔ s = t :=
⟨fun h => by rw [← s.coe_toFinset, h, t.coe_toFinset], fun h => by simp [h]⟩
diff --git a/Mathlib/Data/Fintype/BigOperators.lean b/Mathlib/Data/Fintype/BigOperators.lean
index c1ae6185decf8..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
@@ -224,26 +222,31 @@ theorem Fintype.prod_sum_type (f : α₁ ⊕ α₂ → M) :
∏ x, f x = (∏ a₁, f (Sum.inl a₁)) * ∏ a₂, f (Sum.inr a₂) :=
prod_disj_sum _ _ _
-@[to_additive (attr := simp) Fintype.sum_prod_type]
-theorem Fintype.prod_prod_type [CommMonoid γ] {f : α₁ × α₂ → γ} :
+/-- The product over a product type equals the product of the fiberwise products. For rewriting
+in the reverse direction, use `Fintype.prod_prod_type'`. -/
+@[to_additive Fintype.sum_prod_type "The sum over a product type equals the sum of fiberwise sums.
+For rewriting in the reverse direction, use `Fintype.sum_prod_type'`."]
+theorem Fintype.prod_prod_type [CommMonoid γ] (f : α₁ × α₂ → γ) :
∏ x, f x = ∏ x, ∏ y, f (x, y) :=
- Finset.prod_product
+ Finset.prod_product ..
-/-- An uncurried version of `Finset.prod_prod_type`. -/
-@[to_additive Fintype.sum_prod_type' "An uncurried version of `Finset.sum_prod_type`"]
-theorem Fintype.prod_prod_type' [CommMonoid γ] {f : α₁ → α₂ → γ} :
+/-- The product over a product type equals the product of the fiberwise products. For rewriting
+in the reverse direction, use `Fintype.prod_prod_type`. -/
+@[to_additive Fintype.sum_prod_type' "The sum over a product type equals the sum of fiberwise sums.
+For rewriting in the reverse direction, use `Fintype.sum_prod_type`."]
+theorem Fintype.prod_prod_type' [CommMonoid γ] (f : α₁ → α₂ → γ) :
∏ x : α₁ × α₂, f x.1 x.2 = ∏ x, ∏ y, f x y :=
- Finset.prod_product'
+ Finset.prod_product' ..
@[to_additive Fintype.sum_prod_type_right]
-theorem Fintype.prod_prod_type_right [CommMonoid γ] {f : α₁ × α₂ → γ} :
+theorem Fintype.prod_prod_type_right [CommMonoid γ] (f : α₁ × α₂ → γ) :
∏ x, f x = ∏ y, ∏ x, f (x, y) :=
- Finset.prod_product_right
+ Finset.prod_product_right ..
/-- An uncurried version of `Finset.prod_prod_type_right`. -/
@[to_additive Fintype.sum_prod_type_right' "An uncurried version of `Finset.sum_prod_type_right`"]
-theorem Fintype.prod_prod_type_right' [CommMonoid γ] {f : α₁ → α₂ → γ} :
+theorem Fintype.prod_prod_type_right' [CommMonoid γ] (f : α₁ → α₂ → γ) :
∏ x : α₁ × α₂, f x.1 x.2 = ∏ y, ∏ x, f x y :=
- Finset.prod_product_right'
+ Finset.prod_product_right' ..
end
diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean
index c2ac99212e5f5..e5e21cc3387b4 100644
--- a/Mathlib/Data/Fintype/Card.lean
+++ b/Mathlib/Data/Fintype/Card.lean
@@ -48,8 +48,6 @@ assert_not_exists MulAction
open Function
-open Nat
-
universe u v
variable {α β γ : Type*}
@@ -114,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
@@ -225,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 _)] :
@@ -288,28 +283,30 @@ 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. -/
theorem fin_injective : Function.Injective Fin := fun m n h =>
(Fintype.card_fin m).symm.trans <| (Fintype.card_congr <| Equiv.cast h).trans (Fintype.card_fin n)
+theorem Fin.val_eq_val_of_heq {k l : ℕ} {i : Fin k} {j : Fin l} (h : HEq i j) :
+ (i : ℕ) = (j : ℕ) :=
+ (Fin.heq_ext_iff (fin_injective (type_eq_of_heq h))).1 h
+
/-- A reversed version of `Fin.cast_eq_cast` that is easier to rewrite with. -/
theorem Fin.cast_eq_cast' {n m : ℕ} (h : Fin n = Fin m) :
_root_.cast h = Fin.cast (fin_injective h) := by
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
@@ -399,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
@@ -406,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
@@ -529,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,
@@ -542,7 +554,7 @@ theorem one_lt_card_iff : 1 < card α ↔ ∃ a b : α, a ≠ b :=
one_lt_card_iff_nontrivial.trans nontrivial_iff
nonrec theorem two_lt_card_iff : 2 < card α ↔ ∃ a b c : α, a ≠ b ∧ a ≠ c ∧ b ≠ c := by
- simp_rw [← Finset.card_univ, two_lt_card_iff, mem_univ, true_and_iff]
+ simp_rw [← Finset.card_univ, two_lt_card_iff, mem_univ, true_and]
theorem card_of_bijective {f : α → β} (hf : Bijective f) : card α = card β :=
card_congr (Equiv.ofBijective f hf)
@@ -648,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 :=
@@ -728,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⟩
@@ -760,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
@@ -810,12 +822,10 @@ 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_iff, mem_univ, hxy]
+ Finset.subset_iff, mem_filter, true_and, mem_univ, hxy]
exact
⟨fun z hzx => _root_.trans hzx hxy,
not_forall_of_exists_not ⟨x, Classical.not_imp.2 ⟨hxy, irrefl x⟩⟩⟩
@@ -884,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]
@@ -897,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⟩⟩
@@ -975,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 α] :
@@ -997,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'
@@ -1017,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 1c108db32e13b..63559a8ab0c85 100644
--- a/Mathlib/Data/Fintype/Fin.lean
+++ b/Mathlib/Data/Fintype/Fin.lean
@@ -37,8 +37,7 @@ theorem Iio_last_eq_map : Iio (Fin.last n) = Finset.univ.map Fin.castSuccEmb :=
@[simp]
theorem Ioi_succ (i : Fin n) : Ioi i.succ = (Ioi i).map (Fin.succEmb _) := by
ext i
- simp only [mem_filter, mem_Ioi, mem_map, mem_univ, true_and_iff, Function.Embedding.coeFn_mk,
- exists_true_left]
+ simp only [mem_filter, mem_Ioi, mem_map, mem_univ, Function.Embedding.coeFn_mk, exists_true_left]
constructor
· refine cases ?_ ?_ i
· rintro ⟨⟨⟩⟩
@@ -53,21 +52,19 @@ theorem Iio_castSucc (i : Fin n) : Iio (castSucc i) = (Iio i).map Fin.castSuccEm
rw [Finset.map_map, Fin.map_valEmbedding_Iio]
exact (Fin.map_valEmbedding_Iio i).symm
-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
- rw [Fin.univ_succ, filter_cons, card_disjUnion, filter_map, card_map]
- split_ifs <;> simp
-
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 :=
- (card_filter_univ_succ' p).trans (by split_ifs <;> simp [add_comm 1])
+ #{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] :
+ #{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/Lattice.lean b/Mathlib/Data/Fintype/Lattice.lean
index 27835fd7979ce..64865d35bb0c7 100644
--- a/Mathlib/Data/Fintype/Lattice.lean
+++ b/Mathlib/Data/Fintype/Lattice.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
import Mathlib.Data.Fintype.Card
-import Mathlib.Data.Finset.Lattice
+import Mathlib.Data.Finset.Max
/-!
# Lemmas relating fintypes and order/lattice structure.
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 93fb8dff25530..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. -/
@@ -156,15 +157,37 @@ end Fintype
/-! ### Properties for PartialOrders -/
-lemma Finite.exists_ge_minimal {α} [Finite α] [PartialOrder α] {a : α} {p : α → Prop} (h : p a) :
- ∃ b, b ≤ a ∧ Minimal p b := by
+section PartialOrder
+
+variable {α : Type*} [PartialOrder α] {a : α} {p : α → Prop}
+
+lemma Finite.exists_minimal_le [Finite α] (h : p a) : ∃ b, b ≤ a ∧ Minimal p b := by
obtain ⟨b, ⟨hba, hb⟩, hbmin⟩ :=
Set.Finite.exists_minimal_wrt id {x | x ≤ a ∧ p x} (Set.toFinite _) ⟨a, rfl.le, h⟩
exact ⟨b, hba, hb, fun x hx hxb ↦ (hbmin x ⟨hxb.trans hba, hx⟩ hxb).le⟩
-lemma Finite.exists_le_maximal {α} [Finite α] [PartialOrder α] {a : α} {p : α → Prop} (h : p a) :
- ∃ b, a ≤ b ∧ Maximal p b :=
- Finite.exists_ge_minimal (α := αᵒᵈ) h
+@[deprecated (since := "2024-09-23")] alias Finite.exists_ge_minimal := Finite.exists_minimal_le
+
+lemma Finite.exists_le_maximal [Finite α] (h : p a) : ∃ b, a ≤ b ∧ Maximal p b :=
+ Finite.exists_minimal_le (α := αᵒᵈ) h
+
+lemma Finset.exists_minimal_le (s : Finset α) (h : a ∈ s) : ∃ b, b ≤ a ∧ Minimal (· ∈ s) b := by
+ obtain ⟨⟨b, _⟩, lb, minb⟩ := @Finite.exists_minimal_le s _ ⟨a, h⟩ (·.1 ∈ s) _ h
+ use b, lb; rwa [minimal_subtype, inf_idem] at minb
+
+lemma Finset.exists_le_maximal (s : Finset α) (h : a ∈ s) : ∃ b, a ≤ b ∧ Maximal (· ∈ s) b :=
+ s.exists_minimal_le (α := αᵒᵈ) h
+
+lemma Set.Finite.exists_minimal_le {s : Set α} (hs : s.Finite) (h : a ∈ s) :
+ ∃ b, b ≤ a ∧ Minimal (· ∈ s) b := by
+ obtain ⟨b, lb, minb⟩ := hs.toFinset.exists_minimal_le (hs.mem_toFinset.mpr h)
+ use b, lb; simpa using minb
+
+lemma Set.Finite.exists_le_maximal {s : Set α} (hs : s.Finite) (h : a ∈ s) :
+ ∃ b, a ≤ b ∧ Maximal (· ∈ s) b :=
+ hs.exists_minimal_le (α := αᵒᵈ) h
+
+end PartialOrder
/-! ### Concrete instances -/
diff --git a/Mathlib/Data/Fintype/Perm.lean b/Mathlib/Data/Fintype/Perm.lean
index bdf570b09044a..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`
@@ -46,7 +47,7 @@ theorem mem_permsOfList_of_mem {l : List α} {f : Perm α} (h : ∀ x, f x ≠ x
| nil =>
-- Porting note: applied `not_mem_nil` because it is no longer true definitionally.
simp only [not_mem_nil] at h
- exact List.mem_singleton.2 (Equiv.ext fun x => Decidable.by_contradiction <| h x)
+ exact List.mem_singleton.2 (Equiv.ext fun x => Decidable.byContradiction <| h x)
| cons a l IH =>
by_cases hfa : f a = a
· refine mem_append_left _ (IH fun x hx => mem_of_ne_of_mem ?_ (h x hx))
@@ -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 a216886258a7e..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
@@ -49,12 +49,16 @@ theorem piFinset_subset (t₁ t₂ : ∀ a, Finset (δ a)) (h : ∀ a, t₁ a
piFinset t₁ ⊆ piFinset t₂ := fun _ hg => mem_piFinset.2 fun a => h a <| mem_piFinset.1 hg a
@[simp]
-theorem piFinset_empty [Nonempty α] : piFinset (fun _ => ∅ : ∀ i, Finset (δ i)) = ∅ :=
- eq_empty_of_forall_not_mem fun _ => by simp
+theorem piFinset_eq_empty : piFinset s = ∅ ↔ ∃ i, s i = ∅ := by simp [piFinset]
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
-lemma piFinset_nonempty : (piFinset s).Nonempty ↔ ∀ a, (s a).Nonempty := by
- simp [Finset.Nonempty, Classical.skolem]
+@[simp]
+theorem piFinset_empty [Nonempty α] : piFinset (fun _ => ∅ : ∀ i, Finset (δ i)) = ∅ := by simp
+
+@[simp]
+lemma piFinset_nonempty : (piFinset s).Nonempty ↔ ∀ a, (s a).Nonempty := by simp [piFinset]
+
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, Aesop.piFinset_nonempty_of_forall_nonempty⟩ := piFinset_nonempty
lemma _root_.Finset.Nonempty.piFinset_const {ι : Type*} [Fintype ι] [DecidableEq ι] {s : Finset β}
(hs : s.Nonempty) : (piFinset fun _ : ι ↦ s).Nonempty := piFinset_nonempty.2 fun _ ↦ hs
@@ -65,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 =>
@@ -79,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 _
@@ -100,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 ↦ ?_⟩
@@ -120,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
@@ -168,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/Prod.lean b/Mathlib/Data/Fintype/Prod.lean
index 0d91984495e7f..2a5dfcdbbbf59 100644
--- a/Mathlib/Data/Fintype/Prod.lean
+++ b/Mathlib/Data/Fintype/Prod.lean
@@ -14,8 +14,6 @@ import Mathlib.Data.Finset.Prod
open Function
-open Nat
-
universe u v
variable {α β γ : Type*}
diff --git a/Mathlib/Data/Fintype/Quotient.lean b/Mathlib/Data/Fintype/Quotient.lean
index 83851ba7b8a46..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 => ?_
@@ -63,10 +63,10 @@ def Quotient.finChoice {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → T
(⟦fun (i : ι) (_ : i ∈ a) => Quotient.out (f i)⟧ : Quotient (by infer_instance))
apply eq_of_heq
trans (g a)
- · exact eq_rec_heq (φ := fun l : Multiset ι => @Quotient (∀ i ∈ l, α i) (by infer_instance))
+ · 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 045f7ee4c7aa8..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,
+ 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₀,
+ 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]
@@ -125,7 +129,7 @@ theorem count_modEq_card_eq_ceil (v : ℕ) :
rw [← div_add_mod v r, cast_add, cast_mul, add_comm]
tactic => simp_rw [← sub_sub, sub_div (_ - _), mul_div_cancel_left₀ _ hr'.ne', ceil_sub_nat]
rw [sub_sub_sub_cancel_right, cast_zero, zero_sub]
- rw [sub_eq_self, ceil_eq_zero_iff, Set.mem_Ioc, div_le_iff₀ hr', lt_div_iff hr', neg_one_mul,
+ rw [sub_eq_self, ceil_eq_zero_iff, Set.mem_Ioc, div_le_iff₀ hr', lt_div_iff₀ hr', neg_one_mul,
zero_mul, neg_lt_neg_iff, cast_lt]
exact ⟨mod_lt _ hr, by simp⟩
@@ -139,10 +143,10 @@ theorem count_modEq_card (v : ℕ) :
mul_div_cancel_left₀ _ hr'.ne', add_comm, Int.ceil_add_nat, add_comm]
rw [add_right_inj]
split_ifs with h
- · rw [← cast_sub h.le, Int.ceil_eq_iff, div_le_iff₀ hr', lt_div_iff hr', cast_one, Int.cast_one,
+ · rw [← cast_sub h.le, Int.ceil_eq_iff, div_le_iff₀ hr', lt_div_iff₀ hr', cast_one, Int.cast_one,
sub_self, zero_mul, cast_pos, tsub_pos_iff_lt, one_mul, cast_le, tsub_le_iff_right]
exact ⟨h, ((mod_lt _ hr).trans_le (by simp)).le⟩
- · rw [cast_zero, ceil_eq_zero_iff, Set.mem_Ioc, div_le_iff₀ hr', lt_div_iff hr', zero_mul,
+ · rw [cast_zero, ceil_eq_zero_iff, Set.mem_Ioc, div_le_iff₀ hr', lt_div_iff₀ hr', zero_mul,
tsub_nonpos, ← neg_eq_neg_one_mul, neg_lt_sub_iff_lt_add, ← cast_add, cast_lt, cast_le]
exact ⟨(mod_lt _ hr).trans_le (by simp), not_lt.mp h⟩
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/Defs.lean b/Mathlib/Data/Int/Defs.lean
index b5619f8bcea08..6bf06c9ff023a 100644
--- a/Mathlib/Data/Int/Defs.lean
+++ b/Mathlib/Data/Int/Defs.lean
@@ -30,7 +30,6 @@ namespace Int
variable {a b c d m n : ℤ}
section Order
-variable {a b c : ℤ}
protected lemma le_rfl : a ≤ a := a.le_refl
protected lemma lt_or_lt_of_ne : a ≠ b → a < b ∨ b < a := Int.lt_or_gt_of_ne
@@ -43,6 +42,7 @@ protected lemma le_antisymm_iff : a = b ↔ a ≤ b ∧ b ≤ a :=
⟨fun h ↦ ⟨Int.le_of_eq h, Int.ge_of_eq h⟩, fun h ↦ Int.le_antisymm h.1 h.2⟩
protected lemma le_iff_eq_or_lt : a ≤ b ↔ a = b ∨ a < b := by
rw [Int.le_antisymm_iff, Int.lt_iff_le_not_le, ← and_or_left]; simp [em]
+
protected lemma le_iff_lt_or_eq : a ≤ b ↔ a < b ∨ a = b := by rw [Int.le_iff_eq_or_lt, or_comm]
end Order
diff --git a/Mathlib/Data/Int/DivMod.lean b/Mathlib/Data/Int/DivMod.lean
new file mode 100644
index 0000000000000..53fa12a4f2eb5
--- /dev/null
+++ b/Mathlib/Data/Int/DivMod.lean
@@ -0,0 +1,24 @@
+/-
+Copyright (c) 2024 Lean FRO. All rights reserved.
+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
+
+-/
+
+namespace Int
+
+/-! ### `emod` -/
+
+theorem emod_eq_sub_self_emod {a b : Int} : a % b = (a - b) % b :=
+ (emod_sub_cancel a b).symm
+
+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 038b354fda39a..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 ℤ
@@ -322,7 +324,7 @@ theorem gcd_least_linear {a b : ℤ} (ha : a ≠ 0) :
IsLeast { n : ℕ | 0 < n ∧ ∃ x y : ℤ, ↑n = a * x + b * y } (a.gcd b) := by
simp_rw [← gcd_dvd_iff]
constructor
- · simpa [and_true_iff, dvd_refl, Set.mem_setOf_eq] using gcd_pos_of_ne_zero_left b ha
+ · simpa [and_true, dvd_refl, Set.mem_setOf_eq] using gcd_pos_of_ne_zero_left b ha
· simp only [lowerBounds, and_imp, Set.mem_setOf_eq]
exact fun n hn_pos hn => Nat.le_of_dvd hn_pos hn
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 9300c6b89865c..7808804746ccb 100644
--- a/Mathlib/Data/Int/Lemmas.lean
+++ b/Mathlib/Data/Int/Lemmas.lean
@@ -6,6 +6,7 @@ Authors: Jeremy Avigad
import Mathlib.Data.Int.Bitwise
import Mathlib.Data.Int.Order.Lemmas
import Mathlib.Data.Set.Function
+import Mathlib.Data.Set.Monotone
import Mathlib.Order.Interval.Set.Basic
/-!
@@ -29,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
@@ -107,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/ModEq.lean b/Mathlib/Data/Int/ModEq.lean
index bdd7e1559edbd..d171639d57b4d 100644
--- a/Mathlib/Data/Int/ModEq.lean
+++ b/Mathlib/Data/Int/ModEq.lean
@@ -4,8 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes
-/
import Mathlib.Data.Nat.ModEq
-import Mathlib.Tactic.Abel
-import Mathlib.Tactic.GCongr.Core
/-!
@@ -92,8 +90,7 @@ theorem mod_modEq (a n) : a % n ≡ a [ZMOD n] :=
@[simp]
theorem neg_modEq_neg : -a ≡ -b [ZMOD n] ↔ a ≡ b [ZMOD n] := by
--- Porting note: Restore old proof once #3309 is through
- simp [-sub_neg_eq_add, neg_sub_neg, modEq_iff_dvd, dvd_sub_comm]
+ simp only [modEq_iff_dvd, (by omega : -b - -a = -(b - a)), Int.dvd_neg]
@[simp]
theorem modEq_neg : a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n] := by simp [modEq_iff_dvd]
@@ -105,9 +102,9 @@ protected theorem of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m]
protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] := by
obtain hc | rfl | hc := lt_trichotomy c 0
- · rw [← neg_modEq_neg, ← modEq_neg, ← neg_mul, ← neg_mul, ← neg_mul]
+ · rw [← neg_modEq_neg, ← modEq_neg, ← Int.neg_mul, ← Int.neg_mul, ← Int.neg_mul]
simp only [ModEq, mul_emod_mul_of_pos _ _ (neg_pos.2 hc), h.eq]
- · simp only [zero_mul, ModEq.rfl]
+ · simp only [Int.zero_mul, ModEq.rfl]
· simp only [ModEq, mul_emod_mul_of_pos _ _ hc, h.eq]
protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n * c] := by
@@ -115,7 +112,7 @@ protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n *
@[gcongr]
protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
- modEq_iff_dvd.2 <| by convert dvd_add h₁.dvd h₂.dvd using 1; abel
+ modEq_iff_dvd.2 <| by convert Int.dvd_add h₁.dvd h₂.dvd using 1; omega
@[gcongr] protected theorem add_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c + a ≡ c + b [ZMOD n] :=
ModEq.rfl.add h
@@ -125,10 +122,10 @@ protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a +
protected theorem add_left_cancel (h₁ : a ≡ b [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
c ≡ d [ZMOD n] :=
- have : d - c = b + d - (a + c) - (b - a) := by abel
+ have : d - c = b + d - (a + c) - (b - a) := by omega
modEq_iff_dvd.2 <| by
rw [this]
- exact dvd_sub h₂.dvd h₁.dvd
+ exact Int.dvd_sub h₂.dvd h₁.dvd
protected theorem add_left_cancel' (c : ℤ) (h : c + a ≡ c + b [ZMOD n]) : a ≡ b [ZMOD n] :=
ModEq.rfl.add_left_cancel h
@@ -183,7 +180,7 @@ theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
rw [modEq_iff_dvd] at h ⊢
-- Porting note: removed `show` due to leanprover-community/mathlib4#3305
refine Int.dvd_of_dvd_mul_right_of_gcd_one (?_ : m / d ∣ c / d * (b - a)) ?_
- · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) gcd_dvd_right, sub_mul]
+ · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) gcd_dvd_right, Int.sub_mul]
exact Int.ediv_dvd_ediv gcd_dvd_left h
· rw [gcd_div gcd_dvd_left gcd_dvd_right, natAbs_ofNat,
Nat.div_self (gcd_pos_of_ne_zero_left c hm.ne')]
@@ -233,7 +230,7 @@ theorem modEq_add_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a + n *
_ ≡ b [ZMOD n] := by rw [add_zero]
theorem modEq_sub_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a - n * c ≡ b [ZMOD n] := by
- convert Int.modEq_add_fac (-c) ha using 1; rw [mul_neg, sub_eq_add_neg]
+ convert Int.modEq_add_fac (-c) ha using 1; rw [Int.mul_neg, sub_eq_add_neg]
theorem modEq_add_fac_self {a t n : ℤ} : a + n * t ≡ a [ZMOD n] :=
modEq_add_fac _ ModEq.rfl
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 e7bc9e148fc42..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
@@ -34,15 +31,4 @@ theorem natAbs_le_iff_mul_self_le {a b : ℤ} : a.natAbs ≤ b.natAbs ↔ a * a
rw [← abs_le_iff_mul_self_le, abs_eq_natAbs, abs_eq_natAbs]
exact Int.ofNat_le.symm
-/-! ### units -/
-
-
-theorem eq_zero_of_abs_lt_dvd {m x : ℤ} (h1 : m ∣ x) (h2 : |x| < m) : x = 0 := by
- obtain rfl | hm := eq_or_ne m 0
- · exact Int.zero_dvd.1 h1
- rcases h1 with ⟨d, rfl⟩
- apply mul_eq_zero_of_right
- rw [← abs_lt_one_iff, ← mul_lt_iff_lt_one_right (abs_pos.mpr hm), ← abs_mul]
- exact lt_of_lt_of_le h2 (le_abs_self m)
-
end Int
diff --git a/Mathlib/Data/Int/WithZero.lean b/Mathlib/Data/Int/WithZero.lean
new file mode 100644
index 0000000000000..782b0c9336573
--- /dev/null
+++ b/Mathlib/Data/Int/WithZero.lean
@@ -0,0 +1,91 @@
+/-
+Copyright (c) 2024 María Inés de Frutos-Fernández, Filippo A. E. Nuccio. All rights reserved.
+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.Defs
+
+/-!
+# WithZero
+
+In this file we provide some basic API lemmas for the `WithZero` construction and we define
+the morphism `WithZeroMultInt.toNNReal`.
+
+## Main Definitions
+
+* `WithZeroMultInt.toNNReal` : The `MonoidWithZeroHom` from `ℤₘ₀ → ℝ≥0` sending `0 ↦ 0` and
+ `x ↦ e^(Multiplicative.toAdd (WithZero.unzero hx)` when `x ≠ 0`, for a nonzero `e : ℝ≥0`.
+
+## Main Results
+
+* `WithZeroMultInt.toNNReal_strictMono` : The map `withZeroMultIntToNNReal` is strictly
+ monotone whenever `1 < e`.
+
+## Tags
+
+WithZero, multiplicative, nnreal
+-/
+
+noncomputable section
+
+open scoped NNReal
+
+open Multiplicative WithZero
+
+namespace WithZeroMulInt
+
+/-- Given a nonzero `e : ℝ≥0`, this is the map `ℤₘ₀ → ℝ≥0` sending `0 ↦ 0` and
+ `x ↦ e^(Multiplicative.toAdd (WithZero.unzero hx)` when `x ≠ 0` as a `MonoidWithZeroHom`. -/
+def toNNReal {e : NNReal} (he : e ≠ 0) : ℤₘ₀ →*₀ ℝ≥0 where
+ toFun := fun x ↦ if hx : x = 0 then 0 else e ^ Multiplicative.toAdd (WithZero.unzero hx)
+ map_zero' := rfl
+ map_one' := by
+ simp only [dif_neg one_ne_zero]
+ erw [toAdd_one, zpow_zero]
+ map_mul' x y := by
+ simp only
+ by_cases hxy : x * y = 0
+ · cases' zero_eq_mul.mp (Eq.symm hxy) with hx hy
+ --either x = 0 or y = 0
+ · rw [dif_pos hxy, dif_pos hx, MulZeroClass.zero_mul]
+ · rw [dif_pos hxy, dif_pos hy, MulZeroClass.mul_zero]
+ · cases' mul_ne_zero_iff.mp hxy with hx hy
+ -- x Equiv≠ 0 and y ≠ 0
+ rw [dif_neg hxy, dif_neg hx, dif_neg hy, ← zpow_add' (Or.inl he), ← toAdd_mul]
+ congr
+ rw [← WithZero.coe_inj, WithZero.coe_mul, coe_unzero hx, coe_unzero hy, coe_unzero hxy]
+
+theorem toNNReal_pos_apply {e : NNReal} (he : e ≠ 0) {x : ℤₘ₀} (hx : x = 0) :
+ toNNReal he x = 0 := by
+ simp only [toNNReal, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk]
+ split_ifs; rfl
+
+theorem toNNReal_neg_apply {e : NNReal} (he : e ≠ 0) {x : ℤₘ₀} (hx : x ≠ 0) :
+ toNNReal he x = e ^ Multiplicative.toAdd (WithZero.unzero hx) := by
+ simp only [toNNReal, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk]
+ split_ifs
+ · tauto
+ · rfl
+
+/-- `toNNReal` sends nonzero elements to nonzero elements. -/
+theorem toNNReal_ne_zero {e : NNReal} {m : ℤₘ₀} (he : e ≠ 0) (hm : m ≠ 0) : toNNReal he m ≠ 0 := by
+ simp only [ne_eq, map_eq_zero, hm, not_false_eq_true]
+
+/-- `toNNReal` sends nonzero elements to positive elements. -/
+theorem toNNReal_pos {e : NNReal} {m : ℤₘ₀} (he : e ≠ 0) (hm : m ≠ 0) : 0 < toNNReal he m :=
+ lt_of_le_of_ne zero_le' (toNNReal_ne_zero he hm).symm
+
+/-- The map `toNNReal` is strictly monotone whenever `1 < e`. -/
+theorem toNNReal_strictMono {e : NNReal} (he : 1 < e) :
+ StrictMono (toNNReal (ne_zero_of_lt he)) := by
+ intro x y hxy
+ simp only [toNNReal, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk]
+ split_ifs with hx hy hy
+ · simp only [hy, not_lt_zero'] at hxy
+ · exact zpow_pos he.bot_lt _
+ · simp only [hy, not_lt_zero'] at hxy
+ · rw [zpow_lt_zpow_iff_right₀ he, Multiplicative.toAdd_lt, ← coe_lt_coe, coe_unzero hx,
+ WithZero.coe_unzero hy]
+ exact hxy
+
+end WithZeroMulInt
diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean
index 736e7afea4837..efee2daa93ea1 100644
--- a/Mathlib/Data/List/Basic.lean
+++ b/Mathlib/Data/List/Basic.lean
@@ -3,10 +3,12 @@ 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.Control.Basic
import Mathlib.Data.Nat.Defs
import Mathlib.Data.Option.Basic
import Mathlib.Data.List.Defs
import Mathlib.Data.List.Monad
+import Mathlib.Logic.OpClass
import Mathlib.Logic.Unique
import Mathlib.Order.Basic
import Mathlib.Tactic.Common
@@ -34,8 +36,6 @@ variable {ι : Type*} {α : Type u} {β : Type v} {γ : Type w} {l₁ l₂ : Lis
@[deprecated (since := "2024-07-27")]
theorem le_eq_not_gt [LT α] : ∀ l₁ l₂ : List α, (l₁ ≤ l₂) = ¬l₂ < l₁ := fun _ _ => rfl
-@[deprecated (since := "2024-06-07")] alias toArray_data := Array.data_toArray
-
-- Porting note: Delete this attribute
-- attribute [inline] List.head!
@@ -58,9 +58,6 @@ instance : Std.Associative (α := List α) Append.append where
theorem singleton_injective : Injective fun a : α => [a] := fun _ _ h => (cons_eq_cons.1 h).1
-theorem singleton_inj {a b : α} : [a] = [b] ↔ a = b :=
- singleton_injective.eq_iff
-
theorem set_of_mem_cons (l : List α) (a : α) : { x | x ∈ a :: l } = insert a { x | x ∈ l } :=
Set.ext fun _ => mem_cons
@@ -198,10 +195,6 @@ theorem map_subset_iff {l₁ l₂ : List α} (f : α → β) (h : Injective f) :
theorem append_eq_has_append {L₁ L₂ : List α} : List.append L₁ L₂ = L₁ ++ L₂ :=
rfl
-@[deprecated (since := "2024-03-24")] alias append_eq_cons_iff := append_eq_cons
-
-@[deprecated (since := "2024-03-24")] alias cons_eq_append_iff := cons_eq_append
-
@[deprecated (since := "2024-01-18")] alias append_left_cancel := append_cancel_left
@[deprecated (since := "2024-01-18")] alias append_right_cancel := append_cancel_right
@@ -228,10 +221,10 @@ theorem replicate_subset_singleton (n) (a : α) : replicate n a ⊆ [a] := fun _
mem_singleton.2 (eq_of_mem_replicate h)
theorem subset_singleton_iff {a : α} {L : List α} : L ⊆ [a] ↔ ∃ n, L = replicate n a := by
- simp only [eq_replicate, subset_def, mem_singleton, exists_eq_left']
+ simp only [eq_replicate_iff, subset_def, mem_singleton, exists_eq_left']
theorem replicate_right_injective {n : ℕ} (hn : n ≠ 0) : Injective (@replicate α n) :=
- fun _ _ h => (eq_replicate.1 h).2 _ <| mem_replicate.2 ⟨hn, rfl⟩
+ fun _ _ h => (eq_replicate_iff.1 h).2 _ <| mem_replicate.2 ⟨hn, rfl⟩
theorem replicate_right_inj {a b : α} {n : ℕ} (hn : n ≠ 0) :
replicate n a = replicate n b ↔ a = b :=
@@ -268,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
@@ -294,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
@@ -319,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
@@ -359,21 +346,10 @@ lemma getLast_filter {p : α → Bool} :
/-! ### getLast? -/
--- This is a duplicate of `getLast?_eq_none_iff`.
--- We should remove one of them.
-theorem getLast?_eq_none : ∀ {l : List α}, getLast? l = none ↔ l = []
- | [] => by simp
- | [a] => by simp
- | a :: b :: l => by simp [@getLast?_eq_none (b :: l)]
+@[deprecated (since := "2024-09-06")] alias getLast?_eq_none := getLast?_eq_none_iff
@[deprecated (since := "2024-06-20")] alias getLast?_isNone := getLast?_eq_none
-@[simp]
-theorem getLast?_isSome : ∀ {l : List α}, l.getLast?.isSome ↔ l ≠ []
- | [] => by simp
- | [a] => by simp
- | a :: b :: l => by simp [@getLast?_isSome (b :: l)]
-
theorem mem_getLast?_eq_getLast : ∀ {l : List α} {x : α}, x ∈ l.getLast? → ∃ h, x = getLast l h
| [], x, hx => False.elim <| by simp at hx
| [a], x, hx =>
@@ -394,10 +370,6 @@ theorem mem_getLast?_cons {x y : α} : ∀ {l : List α}, x ∈ l.getLast? → x
| [], _ => by contradiction
| _ :: _, h => h
-theorem mem_of_mem_getLast? {l : List α} {a : α} (ha : a ∈ l.getLast?) : a ∈ l :=
- let ⟨_, h₂⟩ := mem_getLast?_eq_getLast ha
- h₂.symm ▸ getLast_mem _
-
theorem dropLast_append_getLast? : ∀ {l : List α}, ∀ a ∈ l.getLast?, dropLast l ++ [a] = l
| [], a, ha => (Option.not_mem_none a ha).elim
| [a], _, rfl => rfl
@@ -407,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₁)]
@@ -461,9 +433,6 @@ theorem eq_cons_of_mem_head? {x : α} : ∀ {l : List α}, x ∈ l.head? → l =
simp only [head?, Option.mem_def, Option.some_inj] at h
exact h ▸ rfl
-theorem mem_of_mem_head? {x : α} {l : List α} (h : x ∈ l.head?) : x ∈ l :=
- (eq_cons_of_mem_head? h).symm ▸ mem_cons_self _ _
-
@[simp] theorem head!_cons [Inhabited α] (a : α) (l : List α) : head! (a :: l) = a := rfl
@[simp]
@@ -497,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)
@@ -510,6 +479,15 @@ theorem get_eq_get? (l : List α) (i : Fin l.length) :
l.get i = (l.get? i).get (by simp [getElem?_eq_getElem]) := by
simp
+theorem exists_mem_iff_getElem {l : List α} {p : α → Prop} :
+ (∃ x ∈ l, p x) ↔ ∃ (i : ℕ) (_ : i < l.length), p l[i] := by
+ simp only [mem_iff_getElem]
+ exact ⟨fun ⟨_x, ⟨i, hi, hix⟩, hxp⟩ ↦ ⟨i, hi, hix ▸ hxp⟩, fun ⟨i, hi, hp⟩ ↦ ⟨_, ⟨i, hi, rfl⟩, hp⟩⟩
+
+theorem forall_mem_iff_getElem {l : List α} {p : α → Prop} :
+ (∀ x ∈ l, p x) ↔ ∀ (i : ℕ) (_ : i < l.length), p l[i] := by
+ simp [mem_iff_getElem, @forall_swap α]
+
theorem getElem_cons {l : List α} {a : α} {n : ℕ} (h : n < (a :: l).length) :
(a :: l)[n] = if hn : n = 0 then a else l[n - 1]'(by rw [length_cons] at h; omega) := by
cases n <;> simp
@@ -525,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
@@ -718,7 +693,7 @@ theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a
rw [cond_eq_if]
split_ifs with h <;> simp at h
· exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h.symm
- · simp only [Ne.symm h, false_or_iff]
+ · simp only [Ne.symm h, false_or]
rw [← ih]
exact succ_inj'
@@ -734,7 +709,7 @@ theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := b
· rw [if_neg h]; exact succ_le_succ ih
theorem indexOf_lt_length {a} {l : List α} : indexOf a l < length l ↔ a ∈ l :=
- ⟨fun h => Decidable.by_contradiction fun al => Nat.ne_of_lt h <| indexOf_eq_length.2 al,
+ ⟨fun h => Decidable.byContradiction fun al => Nat.ne_of_lt h <| indexOf_eq_length.2 al,
fun al => (lt_of_le_of_ne indexOf_le_length) fun h => indexOf_eq_length.1 h al⟩
theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l₂) = indexOf a l₁ := by
@@ -829,14 +804,6 @@ theorem getElem?_indexOf [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) :
theorem indexOf_get? [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) :
get? l (indexOf a l) = some a := by simp [h]
-@[deprecated (since := "2023-01-05")]
-theorem get_reverse_aux₁ :
- ∀ (l r : List α) (i h1 h2), get (reverseAux l r) ⟨i + length l, h1⟩ = get r ⟨i, h2⟩
- | [], r, i => fun h1 _ => rfl
- | a :: l, r, i => by
- rw [show i + length (a :: l) = i + 1 + length l from Nat.add_right_comm i (length l) 1]
- exact fun h1 h2 => get_reverse_aux₁ l (a :: r) (i + 1) h1 (succ_lt_succ h2)
-
theorem indexOf_inj [DecidableEq α] {l : List α} {x y : α} (hx : x ∈ l) (hy : y ∈ l) :
indexOf x l = indexOf y l ↔ x = y :=
⟨fun h => by
@@ -846,30 +813,13 @@ theorem indexOf_inj [DecidableEq α] {l : List α} {x y : α} (hx : x ∈ l) (hy
simp only [h]
simp only [indexOf_get] at x_eq_y; exact x_eq_y, fun h => by subst h; rfl⟩
-@[deprecated (since := "2024-08-15")]
-theorem getElem_reverse_aux₂ :
- ∀ (l r : List α) (i : Nat) (h1) (h2),
- (reverseAux l r)[length l - 1 - i]'h1 = l[i]'h2
- | [], r, i, h1, h2 => absurd h2 (Nat.not_lt_zero _)
- | a :: l, r, 0, h1, _ => by
- have aux := get_reverse_aux₁ l (a :: r) 0
- rw [Nat.zero_add] at aux
- exact aux _ (zero_lt_succ _)
- | a :: l, r, i + 1, h1, h2 => by
- have aux := getElem_reverse_aux₂ l (a :: r) i
- have heq : length (a :: l) - 1 - (i + 1) = length l - 1 - i := by rw [length]; omega
- rw [← heq] at aux
- apply aux
-
-@[deprecated (since := "2024-06-12")]
-theorem get_reverse_aux₂ (l r : List α) (i : Nat) (h1) (h2) :
- get (reverseAux l r) ⟨length l - 1 - i, h1⟩ = get l ⟨i, h2⟩ := by
- simp only [get_eq_getElem, h2, getElem_reverse_aux₂]
-
@[deprecated getElem_reverse (since := "2024-06-12")]
theorem get_reverse (l : List α) (i : Nat) (h1 h2) :
- get (reverse l) ⟨length l - 1 - i, h1⟩ = get l ⟨i, h2⟩ :=
- get_reverse_aux₂ _ _ _ _ _
+ get (reverse l) ⟨length l - 1 - i, h1⟩ = get l ⟨i, h2⟩ := by
+ rw [get_eq_getElem, get_eq_getElem, getElem_reverse]
+ congr
+ dsimp
+ omega
theorem get_reverse' (l : List α) (n) (hn') :
l.reverse.get n = l.get ⟨l.length - 1 - n, hn'⟩ := by
@@ -885,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)
-theorem modifyNthTail_modifyNthTail_le {f g : List α → List α} (m n : ℕ) (l : List α)
+@[deprecated (since := "2024-10-21")]
+alias modifyNthTail_modifyNthTail := modifyTailIdx_modifyTailIdx
+
+theorem modifyTailIdx_modifyTailIdx_le {f g : List α → List α} (m n : ℕ) (l : List α)
(h : n ≤ m) :
- (l.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]
+
+@[deprecated (since := "2024-10-21")]
+alias modifyNthTail_modifyNthTail_le := modifyTailIdx_modifyTailIdx_le
-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
+theorem modifyTailIdx_modifyTailIdx_same {f g : List α → List α} (n : ℕ) (l : List α) :
+ (l.modifyTailIdx f n).modifyTailIdx g n = l.modifyTailIdx (g ∘ f) n := by
+ rw [modifyTailIdx_modifyTailIdx_le n n l (le_refl n), Nat.sub_self]; rfl
-@[deprecated (since := "2024-05-04")] alias removeNth_eq_nthTail := eraseIdx_eq_modifyNthTail
+@[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 modifyNth_eq_set (f : α → α) :
- ∀ (n) (l : List α), modifyNth f n l = ((fun a => set l n (f a)) <$> l[n]?).getD l
+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 : α)
@@ -928,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 :=
@@ -950,9 +915,6 @@ theorem infix_bind_of_mem {a : α} {as : List α} (h : a ∈ as) (f : α → Lis
theorem map_eq_map {α β} (f : α → β) (l : List α) : f <$> l = map f l :=
rfl
-@[simp]
-theorem map_tail (f : α → β) (l) : map f (tail l) = tail (map f l) := by cases l <;> rfl
-
/-- A single `List.map` of a composition of functions is equal to
composing a `List.map` with another `List.map`, fully applied.
This is the reverse direction of `List.map_map`.
@@ -1040,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
@@ -1149,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]
@@ -1188,7 +1148,7 @@ lemma append_cons_inj_of_not_mem {x₁ x₂ z₁ z₂ : List α} {a₁ a₂ : α
(notin_x : a₂ ∉ x₁) (notin_z : a₂ ∉ z₁) :
x₁ ++ a₁ :: z₁ = x₂ ++ a₂ :: z₂ ↔ x₁ = x₂ ∧ a₁ = a₂ ∧ z₁ = z₂ := by
constructor
- · simp only [append_eq_append_iff, cons_eq_append, cons_eq_cons]
+ · simp only [append_eq_append_iff, cons_eq_append_iff, cons_eq_cons]
rintro (⟨c, rfl, ⟨rfl, rfl, rfl⟩ | ⟨d, rfl, rfl⟩⟩ |
⟨c, rfl, ⟨rfl, rfl, rfl⟩ | ⟨d, rfl, rfl⟩⟩) <;> simp_all
· rintro ⟨rfl, rfl, rfl⟩
@@ -1199,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 _ _
@@ -1257,7 +1217,7 @@ theorem getElem_succ_scanl {i : ℕ} (h : i + 1 < (scanl f b l).length) :
· simp only [length] at h
exact absurd h (by omega)
· simp_rw [scanl_cons]
- rw [getElem_append_right']
+ rw [getElem_append_right]
· simp only [length, Nat.zero_add 1, succ_add_sub_one, hi]; rfl
· simp only [length_singleton]; omega
@@ -1288,25 +1248,27 @@ section FoldlEqFoldr
-- foldl and foldr coincide when f is commutative and associative
variable {f : α → α → α}
-theorem foldl1_eq_foldr1 (hassoc : Associative 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 hassoc _ _ l]; rw [hassoc]
+ simp only [cons_append, foldl_cons, foldr_cons, foldl1_eq_foldr1 _ _ l]
+ rw [hassoc.assoc]
-theorem foldl_eq_of_comm_of_assoc (hcomm : Commutative f) (hassoc : Associative f) :
+theorem foldl_eq_of_comm_of_assoc [hcomm : Std.Commutative f] [hassoc : Std.Associative f] :
∀ a b l, foldl f a (b :: l) = f b (foldl f a l)
- | a, b, nil => hcomm a b
+ | a, b, nil => hcomm.comm a b
| a, b, c :: l => by
simp only [foldl_cons]
- rw [← foldl_eq_of_comm_of_assoc hcomm hassoc .., right_comm _ hcomm hassoc]; rfl
+ have : RightCommutative f := inferInstance
+ rw [← foldl_eq_of_comm_of_assoc .., this.right_comm]; rfl
-theorem foldl_eq_foldr (hcomm : Commutative f) (hassoc : Associative f) :
+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 hcomm hassoc]
- rw [foldl_eq_foldr hcomm hassoc a l]
+ simp only [foldr_cons, foldl_eq_of_comm_of_assoc]
+ rw [foldl_eq_foldr a l]
end FoldlEqFoldr
@@ -1318,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'
@@ -1333,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'
@@ -1348,16 +1310,9 @@ local notation a " ⋆ " b => op a b
/-- Notation for `foldl op a l`. -/
local notation l " <*> " a => foldl op a l
-theorem foldl_assoc : ∀ {l : List α} {a₁ a₂}, (l <*> a₁ ⋆ a₂) = a₁ ⋆ l <*> a₂
- | [], a₁, a₂ => rfl
- | a :: l, a₁, a₂ =>
- calc
- ((a :: l) <*> a₁ ⋆ a₂) = l <*> a₁ ⋆ a₂ ⋆ a := by simp only [foldl_cons, ha.assoc]
- _ = a₁ ⋆ (a :: l) <*> a₂ := by rw [foldl_assoc, foldl_cons]
-
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]
@@ -1407,7 +1362,7 @@ theorem intersperse_cons_cons (a b c : α) (tl : List α) :
section SplitAtOn
-variable (p : α → Bool) (xs ys : List α) (ls : List (List α)) (f : List α → List α)
+variable (p : α → Bool) (xs : List α) (ls : List (List α))
attribute [simp] splitAt_eq
@@ -1537,18 +1492,19 @@ theorem modifyLast.go_append_one (f : α → α) (a : α) (tl : List α) (r : Ar
rw [modifyLast.go, modifyLast.go]
case x_3 | x_3 => exact append_ne_nil_of_right_ne_nil tl (cons_ne_nil a [])
rw [modifyLast.go_append_one _ _ tl _, modifyLast.go_append_one _ _ tl (Array.push #[] hd)]
- simp only [Array.toListAppend_eq, Array.push_data, Array.data_toArray, nil_append, append_assoc]
+ simp only [Array.toListAppend_eq, Array.push_toList, Array.toList_toArray, nil_append,
+ append_assoc]
theorem modifyLast_append_one (f : α → α) (a : α) (l : List α) :
modifyLast f (l ++ [a]) = l ++ [f a] := by
cases l with
| nil =>
- simp only [nil_append, modifyLast, modifyLast.go, Array.toListAppend_eq, Array.data_toArray]
+ simp only [nil_append, modifyLast, modifyLast.go, Array.toListAppend_eq, Array.toList_toArray]
| cons _ tl =>
simp only [cons_append, modifyLast]
rw [modifyLast.go]
case x_3 => exact append_ne_nil_of_right_ne_nil tl (cons_ne_nil a [])
- rw [modifyLast.go_append_one, Array.toListAppend_eq, Array.push_data, Array.data_toArray,
+ rw [modifyLast.go_append_one, Array.toListAppend_eq, Array.push_toList, Array.toList_toArray,
nil_append, cons_append, nil_append, cons_inj_right]
exact modifyLast_append_one _ _ tl
@@ -1583,8 +1539,6 @@ theorem sizeOf_lt_sizeOf_of_mem [SizeOf α] {x : α} {l : List α} (hx : x ∈ l
section find?
-variable {p : α → Bool} {l : List α} {a : α}
-
@[deprecated (since := "2024-05-05")] alias find?_mem := mem_of_find?_eq_some
end find?
@@ -1599,11 +1553,13 @@ variable (f : α → Option α)
theorem lookmap.go_append (l : List α) (acc : Array α) :
lookmap.go f l acc = acc.toListAppend (lookmap f l) := by
cases l with
- | nil => rfl
+ | nil => simp [go, lookmap]
| cons hd tl =>
rw [lookmap, go, go]
cases f hd with
- | none => simp only [go_append tl _, Array.toListAppend_eq, append_assoc, Array.push_data]; rfl
+ | none =>
+ simp only [go_append tl _, Array.toListAppend_eq, append_assoc, Array.push_toList]
+ rfl
| some a => rfl
@[simp]
@@ -1613,13 +1569,13 @@ theorem lookmap_nil : [].lookmap f = [] :=
@[simp]
theorem lookmap_cons_none {a : α} (l : List α) (h : f a = none) :
(a :: l).lookmap f = a :: l.lookmap f := by
- simp only [lookmap, lookmap.go, Array.toListAppend_eq, Array.data_toArray, nil_append]
+ simp only [lookmap, lookmap.go, Array.toListAppend_eq, Array.toList_toArray, nil_append]
rw [lookmap.go_append, h]; rfl
@[simp]
theorem lookmap_cons_some {a b : α} (l : List α) (h : f a = some b) :
(a :: l).lookmap f = b :: l := by
- simp only [lookmap, lookmap.go, Array.toListAppend_eq, Array.data_toArray, nil_append]
+ simp only [lookmap, lookmap.go, Array.toListAppend_eq, Array.toList_toArray, nil_append]
rw [h]
theorem lookmap_some : ∀ l : List α, l.lookmap some = l
@@ -1766,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]
@@ -1774,13 +1730,13 @@ 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]
lemma filter_comm (q) (l : List α) : filter p (filter q l) = filter q (filter p l) := by
- simp [and_comm]
+ simp [Bool.and_comm]
@[simp]
theorem filter_true (l : List α) :
@@ -1902,7 +1858,7 @@ theorem erase_getElem [DecidableEq ι] {l : List ι} {i : ℕ} (hi : i < l.lengt
| succ i =>
have hi' : i < l.length := by simpa using hi
if ha : a = l[i] then
- simpa [ha] using .trans (perm_cons_erase (l.getElem_mem i _)) (.cons _ (IH hi'))
+ simpa [ha] using .trans (perm_cons_erase (getElem_mem _)) (.cons _ (IH hi'))
else
simpa [ha] using IH hi'
@@ -1937,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
@@ -1989,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
@@ -2017,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
@@ -2046,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
@@ -2102,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
@@ -2136,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
@@ -2174,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
@@ -2197,7 +2147,7 @@ variable {p q : α → Prop} {l : List α}
@[simp]
theorem forall_cons (p : α → Prop) (x : α) : ∀ l : List α, Forall p (x :: l) ↔ p x ∧ Forall p l
- | [] => (and_true_iff _).symm
+ | [] => (and_iff_left_of_imp fun _ ↦ trivial).symm
| _ :: _ => Iff.rfl
theorem forall_iff_forall_mem : ∀ {l : List α}, Forall p l ↔ ∀ x ∈ l, p x
@@ -2222,16 +2172,8 @@ end Forall
/-! ### Miscellaneous lemmas -/
-@[simp]
-theorem getElem_attach (L : List α) (i : Nat) (h : i < L.attach.length) :
- L.attach[i].1 = L[i]'(length_attach L ▸ h) :=
- calc
- L.attach[i].1 = (L.attach.map Subtype.val)[i]'(by simpa using h) := by
- rw [getElem_map]
- _ = L[i]'_ := by congr 2; simp
-
theorem get_attach (L : List α) (i) :
- (L.attach.get i).1 = L.get ⟨i, length_attach L ▸ i.2⟩ := by simp
+ (L.attach.get i).1 = L.get ⟨i, length_attach (L := L) ▸ i.2⟩ := by simp
@[simp 1100]
theorem mem_map_swap (x : α) (y : β) (xs : List (α × β)) :
@@ -2298,6 +2240,15 @@ theorem disjoint_map {f : α → β} {s t : List α} (hf : Function.Injective f)
rw [← pmap_eq_map _ _ _ (fun _ _ ↦ trivial), ← pmap_eq_map _ _ _ (fun _ _ ↦ trivial)]
exact disjoint_pmap _ _ (fun _ _ _ _ h' ↦ hf h') h
+alias Disjoint.map := disjoint_map
+
+theorem Disjoint.of_map {f : α → β} {s t : List α} (h : Disjoint (s.map f) (t.map f)) :
+ Disjoint s t := fun _a has hat ↦
+ h (mem_map_of_mem f has) (mem_map_of_mem f hat)
+
+theorem Disjoint.map_iff {f : α → β} {s t : List α} (hf : Function.Injective f) :
+ Disjoint (s.map f) (t.map f) ↔ Disjoint s t :=
+ ⟨fun h ↦ h.of_map, fun h ↦ h.map hf⟩
theorem Perm.disjoint_left {l₁ l₂ l : List α} (p : List.Perm l₁ l₂) :
Disjoint l₁ l ↔ Disjoint l₂ l := by
@@ -2318,8 +2269,7 @@ theorem disjoint_reverse_right {l₁ l₂ : List α} : Disjoint l₁ l₂.revers
end Disjoint
section lookup
-
-variable {α β : Type*} [BEq α] [LawfulBEq α]
+variable [BEq α] [LawfulBEq α]
lemma lookup_graph (f : α → β) {a : α} {as : List α} (h : a ∈ as) :
lookup a (as.map fun x => (x, f x)) = some (f a) := by
@@ -2333,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 b73a2aa957cd3..8b844a1f6243c 100644
--- a/Mathlib/Data/List/Chain.lean
+++ b/Mathlib/Data/List/Chain.lean
@@ -42,15 +42,15 @@ 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_iff]
+ simp only [chain_cons, Chain.nil, and_true]
theorem chain_split {a b : α} {l₁ l₂ : List α} :
Chain R a (l₁ ++ b :: l₂) ↔ Chain R a (l₁ ++ [b]) ∧ Chain R b l₂ := by
induction' l₁ with x l₁ IH generalizing a <;>
- simp only [*, nil_append, cons_append, Chain.nil, chain_cons, and_true_iff, and_assoc]
+ simp only [*, nil_append, cons_append, Chain.nil, chain_cons, and_true, and_assoc]
@[simp]
theorem chain_append_cons_cons {a b c : α} {l₁ l₂ : List α} :
@@ -95,11 +95,11 @@ 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
- simp only [mem_cons, forall_eq_or_imp, h, true_and_iff]
+ simp only [mem_cons, forall_eq_or_imp, h, true_and]
exact fun c hc => _root_.trans h (rel_of_pairwise_cons hb.pairwise hc))
theorem chain_iff_pairwise [IsTrans α R] {a : α} {l : List α} : Chain R a l ↔ Pairwise R (a :: l) :=
@@ -138,6 +138,19 @@ theorem chain_iff_get {R} : ∀ {a : α} {l : List α}, Chain R a l ↔
intro i w
exact h (i+1) (by simp only [length_cons]; omega)
+theorem chain_replicate_of_rel (n : ℕ) {a : α} (h : r a a) : Chain r a (replicate n a) :=
+ match n with
+ | 0 => Chain.nil
+ | n + 1 => Chain.cons h (chain_replicate_of_rel n h)
+
+theorem chain_eq_iff_eq_replicate {a : α} {l : List α} :
+ Chain (· = ·) a l ↔ l = replicate l.length a :=
+ match l with
+ | [] => by simp
+ | b :: l => by
+ rw [chain_cons]
+ simp (config := {contextual := true}) [eq_comm, replicate_succ, chain_eq_iff_eq_replicate]
+
theorem Chain'.imp {S : α → α → Prop} (H : ∀ a b, R a b → S a b) {l : List α} (p : Chain' R l) :
Chain' S l := by cases l <;> [trivial; exact Chain.imp H p]
@@ -165,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₂)
@@ -232,8 +245,7 @@ theorem chain'_append :
| [], l => by simp
| [a], l => by simp [chain'_cons', and_comm]
| a :: b :: l₁, l₂ => by
- rw [cons_append, cons_append, chain'_cons, chain'_cons, ← cons_append, chain'_append,
- and_assoc]
+ rw [cons_append, cons_append, chain'_cons, chain'_cons, ← cons_append, chain'_append, and_assoc]
simp
theorem Chain'.append (h₁ : Chain' R l₁) (h₂ : Chain' R l₂)
@@ -266,7 +278,7 @@ theorem Chain'.take (h : Chain' R l) (n : ℕ) : Chain' R (take n l) :=
h.prefix (take_prefix _ _)
theorem chain'_pair {x y} : Chain' R [x, y] ↔ R x y := by
- simp only [chain'_singleton, chain'_cons, and_true_iff]
+ simp only [chain'_singleton, chain'_cons, and_true]
theorem Chain'.imp_head {x y} (h : ∀ {z}, R x z → R y z) {l} (hl : Chain' R (x :: l)) :
Chain' R (y :: l) :=
@@ -307,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`.
@@ -419,6 +451,17 @@ lemma Chain'.iterate_eq_of_apply_eq {α : Type*} {f : α → α} {l : List α}
apply hl
omega
+theorem chain'_replicate_of_rel (n : ℕ) {a : α} (h : r a a) : Chain' r (replicate n a) :=
+ match n with
+ | 0 => chain'_nil
+ | n + 1 => chain_replicate_of_rel n h
+
+theorem chain'_eq_iff_eq_replicate {l : List α} :
+ Chain' (· = ·) l ↔ ∀ a ∈ l.head?, l = replicate l.length a :=
+ match l with
+ | [] => by simp
+ | a :: l => by simp [Chain', chain_eq_iff_eq_replicate, replicate_succ]
+
end List
diff --git a/Mathlib/Data/List/Count.lean b/Mathlib/Data/List/Count.lean
index 45f4be1166e42..13c127b563b2a 100644
--- a/Mathlib/Data/List/Count.lean
+++ b/Mathlib/Data/List/Count.lean
@@ -3,14 +3,14 @@ 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.Nat.Defs
+import Mathlib.Logic.Function.Basic
+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
@@ -19,7 +19,7 @@ assert_not_exists Ring
open Nat
-variable {α : Type*} {l : List α}
+variable {α : Type*}
namespace List
@@ -34,14 +34,6 @@ theorem count_map_of_injective {β} [DecidableEq α] [DecidableEq β] (l : List
unfold Function.comp
simp only [hf.beq_eq]
-variable [DecidableEq α]
-
-@[deprecated (since := "2023-08-23")]
-theorem count_cons' (a b : α) (l : List α) :
- count a (b :: l) = count a l + if a = b then 1 else 0 := by
- simp only [count, beq_iff_eq, countP_cons, Nat.add_right_inj]
- simp only [eq_comm]
-
end Count
end List
diff --git a/Mathlib/Data/List/Cycle.lean b/Mathlib/Data/List/Cycle.lean
index d68df32b94451..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
@@ -334,7 +333,7 @@ theorem prev_next (l : List α) (h : Nodup l) (x : α) (hx : x ∈ l) :
obtain ⟨⟨n, hn⟩, rfl⟩ := get_of_mem hx
simp only [next_get, prev_get, h, Nat.mod_add_mod]
cases' l with hd tl
- · simp at hx
+ · simp at hn
· have : (n + 1 + length tl) % (length tl + 1) = n := by
rw [length_cons] at hn
rw [add_assoc, add_comm 1, Nat.add_mod_right, Nat.mod_eq_of_lt hn]
@@ -345,7 +344,7 @@ theorem next_prev (l : List α) (h : Nodup l) (x : α) (hx : x ∈ l) :
obtain ⟨⟨n, hn⟩, rfl⟩ := get_of_mem hx
simp only [next_get, prev_get, h, Nat.mod_add_mod]
cases' l with hd tl
- · simp at hx
+ · simp at hn
· have : (n + length tl + 1) % (length tl + 1) = n := by
rw [length_cons] at hn
rw [add_assoc, Nat.add_mod_right, Nat.mod_eq_of_lt hn]
@@ -528,7 +527,7 @@ theorem Subsingleton.congr {s : Cycle α} (h : Subsingleton s) :
∀ ⦃x⦄ (_hx : x ∈ s) ⦃y⦄ (_hy : y ∈ s), x = y := by
induction' s using Quot.inductionOn with l
simp only [length_subsingleton_iff, length_coe, mk_eq_coe, le_iff_lt_or_eq, Nat.lt_add_one_iff,
- length_eq_zero, length_eq_one, Nat.not_lt_zero, false_or_iff] at h
+ length_eq_zero, length_eq_one, Nat.not_lt_zero, false_or] at h
rcases h with (rfl | ⟨z, rfl⟩) <;> simp
/-- A `s : Cycle α` that is made up of at least two unique elements. -/
@@ -543,7 +542,7 @@ theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
· simp
· simp
· simp only [mem_cons, exists_prop, mem_coe_iff, List.length, Ne, Nat.succ_le_succ_iff,
- Nat.zero_le, iff_true_iff]
+ Nat.zero_le, iff_true]
refine ⟨hd, hd', ?_, by simp⟩
simp only [not_or, mem_cons, nodup_cons] at hl
exact hl.left.left
@@ -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
@@ -880,7 +878,7 @@ theorem chain_iff_pairwise [IsTrans α r] : Chain r s ↔ ∀ a ∈ s, ∀ b ∈
intro hs b hb c hc
rw [Cycle.chain_coe_cons, List.chain_iff_pairwise] at hs
simp only [pairwise_append, pairwise_cons, mem_append, mem_singleton, List.not_mem_nil,
- IsEmpty.forall_iff, imp_true_iff, Pairwise.nil, forall_eq, true_and_iff] at hs
+ IsEmpty.forall_iff, imp_true_iff, Pairwise.nil, forall_eq, true_and] at hs
simp only [mem_coe_iff, mem_cons] at hb hc
rcases hb with (rfl | hb) <;> rcases hc with (rfl | hc)
· exact hs.1 c (Or.inr rfl)
diff --git a/Mathlib/Data/List/Dedup.lean b/Mathlib/Data/List/Dedup.lean
index bb2bf2901cd89..2c282a581e0bd 100644
--- a/Mathlib/Data/List/Dedup.lean
+++ b/Mathlib/Data/List/Dedup.lean
@@ -82,7 +82,7 @@ theorem dedup_eq_cons (l : List α) (a : α) (l' : List α) :
l.dedup = a :: l' ↔ a ∈ l ∧ a ∉ l' ∧ l.dedup.tail = l' := by
refine ⟨fun h => ?_, fun h => ?_⟩
· refine ⟨mem_dedup.1 (h.symm ▸ mem_cons_self _ _), fun ha => ?_, by rw [h, tail_cons]⟩
- have := count_pos_iff_mem.2 ha
+ have := count_pos_iff.2 ha
have : count a l.dedup ≤ 1 := nodup_iff_count_le_one.1 (nodup_dedup l) a
rw [h, count_cons_self] at this
omega
@@ -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 80750fd2c8b30..fed56f7a1c26f 100644
--- a/Mathlib/Data/List/Defs.lean
+++ b/Mathlib/Data/List/Defs.lean
@@ -10,6 +10,7 @@ import Mathlib.Util.CompileInductive
import Batteries.Tactic.Lint.Basic
import Batteries.Data.List.Lemmas
import Batteries.Data.RBMap.Basic
+import Batteries.Logic
/-!
## Definitions on lists
@@ -487,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/EditDistance/Bounds.lean b/Mathlib/Data/List/EditDistance/Bounds.lean
index 5ad1aafb05254..7a20e9e681c9a 100644
--- a/Mathlib/Data/List/EditDistance/Bounds.lean
+++ b/Mathlib/Data/List/EditDistance/Bounds.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Kim Liesinger. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kim Liesinger
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Order.Monoid.Canonical.Defs
import Mathlib.Data.List.Infix
diff --git a/Mathlib/Data/List/EditDistance/Defs.lean b/Mathlib/Data/List/EditDistance/Defs.lean
index ed13538ca6e25..a52cf793066d8 100644
--- a/Mathlib/Data/List/EditDistance/Defs.lean
+++ b/Mathlib/Data/List/EditDistance/Defs.lean
@@ -1,9 +1,10 @@
/-
-Copyright (c) 2023 Kim Liesinger. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kim Liesinger
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Defs
+import Batteries.Data.List.Basic
/-!
# Levenshtein distances
diff --git a/Mathlib/Data/List/EditDistance/Estimator.lean b/Mathlib/Data/List/EditDistance/Estimator.lean
index 056d119f6af71..e000b2bc0d02b 100644
--- a/Mathlib/Data/List/EditDistance/Estimator.lean
+++ b/Mathlib/Data/List/EditDistance/Estimator.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Kim Liesinger. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kim Liesinger
+Authors: Kim Morrison
-/
import Mathlib.Data.List.EditDistance.Bounds
import Mathlib.Order.Estimator
diff --git a/Mathlib/Data/List/Enum.lean b/Mathlib/Data/List/Enum.lean
index edc801c308976..a574ea756a233 100644
--- a/Mathlib/Data/List/Enum.lean
+++ b/Mathlib/Data/List/Enum.lean
@@ -3,24 +3,23 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Yakov Pechersky, Eric Wieser
-/
-import Batteries.Tactic.Alias
-import Mathlib.Tactic.TypeStar
-import Mathlib.Data.Nat.Notation
+import Mathlib.Data.List.Basic
/-!
# Properties of `List.enum`
## Deprecation note
-Everything in this file has been replaced by theorems in Lean4,
+
+Many lemmas in this file have been replaced by theorems in Lean4,
in terms of `xs[i]?` and `xs[i]` rather than `get` and `get?`.
-The results here are unused in Mathlib, and deprecated.
+The deprecated results here are unused in Mathlib.
Any downstream users who can not easily adapt may remove the deprecations as needed.
-/
namespace List
-variable {α β : Type*}
+variable {α : Type*}
@[deprecated getElem?_enumFrom (since := "2024-08-15")]
theorem get?_enumFrom (n) (l : List α) (m) :
@@ -64,4 +63,20 @@ set_option linter.deprecated false in
theorem mem_enum_iff_get? {x : ℕ × α} {l : List α} : x ∈ enum l ↔ l.get? x.1 = x.2 :=
mk_mem_enum_iff_get?
+theorem forall_mem_enumFrom {l : List α} {n : ℕ} {p : ℕ × α → Prop} :
+ (∀ x ∈ l.enumFrom n, p x) ↔ ∀ (i : ℕ) (_ : i < length l), p (n + i, l[i]) := by
+ simp only [forall_mem_iff_getElem, getElem_enumFrom, enumFrom_length]
+
+theorem forall_mem_enum {l : List α} {p : ℕ × α → Prop} :
+ (∀ x ∈ l.enum, p x) ↔ ∀ (i : ℕ) (_ : i < length l), p (i, l[i]) :=
+ forall_mem_enumFrom.trans <| by simp
+
+theorem exists_mem_enumFrom {l : List α} {n : ℕ} {p : ℕ × α → Prop} :
+ (∃ x ∈ l.enumFrom n, p x) ↔ ∃ (i : ℕ) (_ : i < length l), p (n + i, l[i]) := by
+ simp only [exists_mem_iff_getElem, getElem_enumFrom, enumFrom_length]
+
+theorem exists_mem_enum {l : List α} {p : ℕ × α → Prop} :
+ (∃ x ∈ l.enum, p x) ↔ ∃ (i : ℕ) (_ : i < length l), p (i, l[i]) :=
+ exists_mem_enumFrom.trans <| by simp
+
end List
diff --git a/Mathlib/Data/List/FinRange.lean b/Mathlib/Data/List/FinRange.lean
index bb4b35d88e9a0..62d8122999597 100644
--- a/Mathlib/Data/List/FinRange.lean
+++ b/Mathlib/Data/List/FinRange.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Kenny Lau, Scott Morrison, Alex Keizer
+Authors: Mario Carneiro, Kenny Lau, Kim Morrison, Alex Keizer
-/
import Mathlib.Data.List.OfFn
import Mathlib.Data.List.Range
@@ -42,7 +42,7 @@ theorem finRange_succ (n : ℕ) :
theorem ofFn_eq_pmap {n} {f : Fin n → α} :
ofFn f = pmap (fun i hi => f ⟨i, hi⟩) (range n) fun _ => mem_range.1 := by
rw [pmap_eq_map_attach]
- exact ext_getElem (by simp) fun i hi1 hi2 => by simp [getElem_ofFn f i hi1]
+ exact ext_getElem (by simp) fun i hi1 hi2 => by simp [List.getElem_ofFn f i hi1]
theorem ofFn_id (n) : ofFn id = finRange n :=
ofFn_eq_pmap
@@ -72,7 +72,7 @@ open List
theorem Equiv.Perm.map_finRange_perm {n : ℕ} (σ : Equiv.Perm (Fin n)) :
map σ (finRange n) ~ finRange n := by
rw [perm_ext_iff_of_nodup ((nodup_finRange n).map σ.injective) <| nodup_finRange n]
- simpa [mem_map, mem_finRange, true_and_iff, iff_true_iff] using σ.surjective
+ simpa [mem_map, mem_finRange] using σ.surjective
/-- The list obtained from a permutation of a tuple `f` is permutation equivalent to
the list obtained from `f`. -/
diff --git a/Mathlib/Data/List/Forall2.lean b/Mathlib/Data/List/Forall2.lean
index f2e78d52a7c08..79f5bf6c1cb0a 100644
--- a/Mathlib/Data/List/Forall2.lean
+++ b/Mathlib/Data/List/Forall2.lean
@@ -87,8 +87,7 @@ theorem forall₂_cons_right_iff {b l u} :
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_iff]
+ 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, and_assoc,
@and_comm _ (p a), @and_left_comm _ (p a), exists_and_left]
@@ -244,7 +243,7 @@ theorem rel_filter {p : α → Bool} {q : β → Bool}
dsimp [LiftFun] at hpq
by_cases h : p a
· have : q b := by rwa [← hpq h₁]
- simp only [filter_cons_of_pos h, filter_cons_of_pos this, forall₂_cons, h₁, true_and_iff,
+ simp only [filter_cons_of_pos h, filter_cons_of_pos this, forall₂_cons, h₁, true_and,
rel_filter hpq h₂]
· have : ¬q b := by rwa [← hpq h₁]
simp only [filter_cons_of_neg h, filter_cons_of_neg this, rel_filter hpq h₂]
diff --git a/Mathlib/Data/List/GetD.lean b/Mathlib/Data/List/GetD.lean
index bc144f95b4785..33af5b90cdb00 100644
--- a/Mathlib/Data/List/GetD.lean
+++ b/Mathlib/Data/List/GetD.lean
@@ -72,16 +72,13 @@ alias getD_replicate_default_eq := getElem?_getD_replicate_default_eq
theorem getD_append (l l' : List α) (d : α) (n : ℕ) (h : n < l.length) :
(l ++ l').getD n d = l.getD n d := by
rw [getD_eq_getElem _ _ (Nat.lt_of_lt_of_le h (length_append _ _ ▸ Nat.le_add_right _ _)),
- getElem_append _ h, getD_eq_getElem]
+ getElem_append_left h, getD_eq_getElem]
theorem getD_append_right (l l' : List α) (d : α) (n : ℕ) (h : l.length ≤ n) :
(l ++ l').getD n d = l'.getD (n - l.length) d := by
cases Nat.lt_or_ge n (l ++ l').length with
| inl h' =>
- rw [getD_eq_getElem (l ++ l') d h', getElem_append_right, getD_eq_getElem]
- · rw [length_append] at h'
- exact Nat.sub_lt_left_of_lt_add h h'
- · exact Nat.not_lt_of_le h
+ rw [getD_eq_getElem (l ++ l') d h', getElem_append_right h, getD_eq_getElem]
| inr h' =>
rw [getD_eq_default _ _ h', getD_eq_default]
rwa [Nat.le_sub_iff_add_le' h, ← length_append]
@@ -132,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/Indexes.lean b/Mathlib/Data/List/Indexes.lean
index b2351ad435a24..7e53018e89d4b 100644
--- a/Mathlib/Data/List/Indexes.lean
+++ b/Mathlib/Data/List/Indexes.lean
@@ -55,9 +55,9 @@ theorem mapIdxGo_append : ∀ (f : ℕ → α → β) (l₁ l₂ : List α) (arr
cases l₂
· rfl
· rw [List.length_append] at h; contradiction
- rw [l₁_nil, l₂_nil]; simp only [mapIdx.go, Array.toList_eq, Array.toArray_data]
+ rw [l₁_nil, l₂_nil]; simp only [mapIdx.go, List.toArray_toList]
· cases' l₁ with head tail <;> simp only [mapIdx.go]
- · simp only [nil_append, Array.toList_eq, Array.toArray_data]
+ · simp only [nil_append, List.toArray_toList]
· simp only [List.append_eq]
rw [ih]
· simp only [cons_append, length_cons, length_append, Nat.succ.injEq] at h
@@ -67,7 +67,7 @@ theorem mapIdxGo_length : ∀ (f : ℕ → α → β) (l : List α) (arr : Array
length (mapIdx.go f l arr) = length l + arr.size := by
intro f l
induction' l with head tail ih
- · intro; simp only [mapIdx.go, Array.toList_eq, length_nil, Nat.zero_add]
+ · intro; simp only [mapIdx.go, length_nil, Nat.zero_add]
· intro; simp only [mapIdx.go]; rw [ih]; simp only [Array.size_push, length_cons]
simp only [Nat.add_succ, Fin.add_zero, Nat.add_comm]
@@ -77,7 +77,7 @@ theorem mapIdx_append_one : ∀ (f : ℕ → α → β) (l : List α) (e : α),
unfold mapIdx
rw [mapIdxGo_append f l [e]]
simp only [mapIdx.go, Array.size_toArray, mapIdxGo_length, length_nil, Nat.add_zero,
- Array.toList_eq, Array.push_data, Array.data_toArray]
+ Array.push_toList, Array.toList_toArray]
@[local simp]
theorem map_enumFrom_eq_zipWith : ∀ (l : List α) (n : ℕ) (f : ℕ → α → β),
@@ -119,15 +119,16 @@ theorem getElem?_mapIdx_go (f : ℕ → α → β) : ∀ (l : List α) (arr : Ar
(mapIdx.go f l arr)[i]? =
if h : i < arr.size then some arr[i] else Option.map (f i) l[i - arr.size]?
| [], arr, i => by
- simp [mapIdx.go, getElem?_eq, Array.getElem_eq_data_getElem]
+ simp only [mapIdx.go, Array.toListImpl_eq, getElem?_eq, Array.length_toList,
+ Array.getElem_eq_getElem_toList, length_nil, Nat.not_lt_zero, ↓reduceDIte, Option.map_none']
| a :: l, arr, i => by
rw [mapIdx.go, getElem?_mapIdx_go]
simp only [Array.size_push]
split <;> split
· simp only [Option.some.injEq]
- rw [Array.getElem_eq_data_getElem]
- simp only [Array.push_data]
- rw [getElem_append_left, Array.getElem_eq_data_getElem]
+ rw [Array.getElem_eq_getElem_toList]
+ simp only [Array.push_toList]
+ rw [getElem_append_left, Array.getElem_eq_getElem_toList]
· have : i = arr.size := by omega
simp_all
· omega
@@ -158,7 +159,7 @@ theorem mapIdx_append (K L : List α) (f : ℕ → α → β) :
@[simp]
theorem mapIdx_eq_nil {f : ℕ → α → β} {l : List α} : List.mapIdx f l = [] ↔ l = [] := by
- rw [List.mapIdx_eq_enum_map, List.map_eq_nil, List.enum_eq_nil]
+ rw [List.mapIdx_eq_enum_map, List.map_eq_nil_iff, List.enum_eq_nil]
theorem get_mapIdx (l : List α) (f : ℕ → α → β) (i : ℕ) (h : i < l.length)
(h' : i < (l.mapIdx f).length := h.trans_le (l.length_mapIdx f).ge) :
@@ -356,12 +357,12 @@ theorem mapIdxMGo_eq_mapIdxMAuxSpec
congr
conv => { lhs; intro x; rw [ih _ _ h]; }
funext x
- simp only [Array.toList_eq, Array.push_data, append_assoc, singleton_append, Array.size_push,
+ simp only [Array.push_toList, append_assoc, singleton_append, Array.size_push,
map_eq_pure_bind]
theorem mapIdxM_eq_mmap_enum [LawfulMonad m] {β} (f : ℕ → α → m β) (as : List α) :
as.mapIdxM f = List.traverse (uncurry f) (enum as) := by
- simp only [mapIdxM, mapIdxMGo_eq_mapIdxMAuxSpec, Array.toList_eq, Array.data_toArray,
+ simp only [mapIdxM, mapIdxMGo_eq_mapIdxMAuxSpec, Array.toList_toArray,
nil_append, mapIdxMAuxSpec, Array.size_toArray, length_nil, id_map', enum]
end MapIdxM
diff --git a/Mathlib/Data/List/Infix.lean b/Mathlib/Data/List/Infix.lean
index 4218035da5095..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 -/
@@ -63,18 +63,14 @@ lemma dropSlice_subset (n m : ℕ) (l : List α) : l.dropSlice n m ⊆ l :=
lemma mem_of_mem_dropSlice {n m : ℕ} {l : List α} {a : α} (h : a ∈ l.dropSlice n m) : a ∈ l :=
dropSlice_subset n m l h
-attribute [gcongr] drop_sublist_drop_left
-
theorem tail_subset (l : List α) : tail l ⊆ l :=
(tail_sublist l).subset
theorem mem_of_mem_dropLast (h : a ∈ l.dropLast) : a ∈ l :=
dropLast_subset l h
-theorem mem_of_mem_tail (h : a ∈ l.tail) : a ∈ l :=
- tail_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
@@ -83,6 +79,14 @@ theorem concat_get_prefix {x y : List α} (h : x <+: y) (hl : x.length < y.lengt
convert List.take_append_drop (x.length + 1) y using 2
rw [← List.take_concat_get, List.concat_eq_append]; rfl
+instance decidableInfix [DecidableEq α] : ∀ l₁ l₂ : List α, Decidable (l₁ <:+: l₂)
+ | [], l₂ => isTrue ⟨[], l₂, rfl⟩
+ | a :: l₁, [] => isFalse fun ⟨s, t, te⟩ => by simp at te
+ | l₁, b :: l₂ =>
+ letI := l₁.decidableInfix l₂
+ @decidable_of_decidable_of_iff (l₁ <+: b :: l₂ ∨ l₁ <:+: l₂) _ _
+ infix_cons_iff.symm
+
@[deprecated cons_prefix_cons (since := "2024-08-14")]
theorem cons_prefix_iff : a :: l₁ <+: b :: l₂ ↔ a = b ∧ l₁ <+: l₂ := by
simp
@@ -154,7 +158,17 @@ theorem inits_cons (a : α) (l : List α) : inits (a :: l) = [] :: l.inits.map f
theorem tails_cons (a : α) (l : List α) : tails (a :: l) = (a :: l) :: l.tails := by simp
-@[simp]
+#adaptation_note
+/--
+This can be removed after nightly-2024-09-07.
+-/
+attribute [-simp] map_tail
+
+#adaptation_note
+/--
+`nolint simpNF` should be removed after nightly-2024-09-07.
+-/
+@[simp, nolint simpNF]
theorem inits_append : ∀ s t : List α, inits (s ++ t) = s.inits ++ t.inits.tail.map fun l => s ++ l
| [], [] => by simp
| [], a :: t => by simp
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 99646ea33a4c5..48923ca75aef6 100644
--- a/Mathlib/Data/List/InsertNth.lean
+++ b/Mathlib/Data/List/InsertNth.lean
@@ -1,185 +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₁)
-
-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),
- ← or_assoc, @or_comm (a = a'), 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 fdfa018a9e884..9c89237d400af 100644
--- a/Mathlib/Data/List/Intervals.lean
+++ b/Mathlib/Data/List/Intervals.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Data.List.Lattice
import Mathlib.Data.Bool.Basic
@@ -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) :
@@ -135,7 +133,7 @@ theorem filter_lt_of_top_le {n m l : ℕ} (hml : m ≤ l) :
simp only [(lt_of_lt_of_le (mem.1 hk).2 hml), decide_True]
theorem filter_lt_of_le_bot {n m l : ℕ} (hln : l ≤ n) : ((Ico n m).filter fun x => x < l) = [] :=
- filter_eq_nil.2 fun k hk => by
+ filter_eq_nil_iff.2 fun k hk => by
simp only [decide_eq_true_eq, not_lt]
apply le_trans hln
exact (mem.1 hk).1
@@ -161,7 +159,7 @@ theorem filter_le_of_le_bot {n m l : ℕ} (hln : l ≤ n) :
exact le_trans hln (mem.1 hk).1
theorem filter_le_of_top_le {n m l : ℕ} (hml : m ≤ l) : ((Ico n m).filter fun x => l ≤ x) = [] :=
- filter_eq_nil.2 fun k hk => by
+ filter_eq_nil_iff.2 fun k hk => by
rw [decide_eq_true_eq]
exact not_le_of_gt (lt_of_lt_of_le (mem.1 hk).2 hml)
diff --git a/Mathlib/Data/List/Lattice.lean b/Mathlib/Data/List/Lattice.lean
index 181f14ce99536..67914f83dc501 100644
--- a/Mathlib/Data/List/Lattice.lean
+++ b/Mathlib/Data/List/Lattice.lean
@@ -2,7 +2,7 @@
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro,
-Scott Morrison
+Kim Morrison
-/
import Mathlib.Data.List.Basic
@@ -29,7 +29,7 @@ open Nat
namespace List
-variable {α : Type*} {l l₁ l₂ : List α} {p : α → Prop} {a : α}
+variable {α : Type*} {l₁ l₂ : List α} {p : α → Prop} {a : α}
/-! ### `Disjoint` -/
@@ -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
@@ -178,13 +178,13 @@ theorem cons_bagInter_of_neg (l₁ : List α) (h : a ∉ l₂) :
@[simp]
theorem mem_bagInter {a : α} : ∀ {l₁ l₂ : List α}, a ∈ l₁.bagInter l₂ ↔ a ∈ l₁ ∧ a ∈ l₂
- | [], l₂ => by simp only [nil_bagInter, not_mem_nil, false_and_iff]
+ | [], l₂ => by simp only [nil_bagInter, not_mem_nil, false_and]
| b :: l₁, l₂ => by
by_cases h : b ∈ l₂
· rw [cons_bagInter_of_pos _ h, mem_cons, mem_cons, mem_bagInter]
by_cases ba : a = b
- · simp only [ba, h, eq_self_iff_true, true_or_iff, true_and_iff]
- · simp only [mem_erase_of_ne ba, ba, false_or_iff]
+ · simp only [ba, h, eq_self_iff_true, true_or, true_and]
+ · simp only [mem_erase_of_ne ba, ba, false_or]
· rw [cons_bagInter_of_neg _ h, mem_bagInter, mem_cons, or_and_right]
symm
apply or_iff_right_of_imp
@@ -203,7 +203,7 @@ theorem count_bagInter {a : α} :
by_cases ba : b = a
· simp only [beq_iff_eq]
rw [if_pos ba, Nat.sub_add_cancel]
- rwa [succ_le_iff, count_pos_iff_mem, ← ba]
+ rwa [succ_le_iff, count_pos_iff, ← ba]
· simp only [beq_iff_eq]
rw [if_neg ba, Nat.sub_zero, Nat.add_zero, Nat.add_zero]
· rw [cons_bagInter_of_neg _ hb, count_bagInter]
diff --git a/Mathlib/Data/List/Lemmas.lean b/Mathlib/Data/List/Lemmas.lean
index 72e4ddac0a2a7..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
@@ -30,22 +30,10 @@ theorem tail_reverse_eq_reverse_dropLast (l : List α) :
· rw [getElem?_eq_none, getElem?_eq_none]
all_goals (simp; omega)
-theorem getLast_tail (l : List α) (hl : l.tail ≠ []) :
- l.tail.getLast hl = l.getLast (by intro h; rw [h] at hl; simp at hl) := by
- simp only [← drop_one, ne_eq, drop_eq_nil_iff_le,
- not_le, getLast_eq_getElem, length_drop] at hl |-
- rw [← getElem_drop']
- · simp [show 1 + (l.length - 1 - 1) = l.length - 1 by omega]
- omega
-
-lemma getElem_tail {i} (L : List α) (hi : i < L.tail.length) :
- L.tail[i] = L[i + 1]'(by simp at *; omega) := by
- induction L <;> simp at hi |-
-
@[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]
@@ -56,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_iff, 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⟩
@@ -109,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]
@@ -119,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 c20935506c371..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
@@ -433,25 +433,31 @@ theorem minimum_of_length_pos_le_getElem {i : ℕ} (w : i < l.length) (h := (Nat
l.minimum_of_length_pos h ≤ l[i] :=
getElem_le_maximum_of_length_pos (α := αᵒᵈ) w
-lemma getD_maximum?_eq_unbot'_maximum (l : List α) (d : α) :
- l.maximum?.getD d = l.maximum.unbot' d := by
+lemma getD_max?_eq_unbot'_maximum (l : List α) (d : α) :
+ l.max?.getD d = l.maximum.unbot' d := by
cases hy : l.maximum with
| bot => simp [List.maximum_eq_bot.mp hy]
| coe y =>
rw [List.maximum_eq_coe_iff] at hy
simp only [WithBot.unbot'_coe]
- cases hz : l.maximum? with
- | none => simp [List.maximum?_eq_none_iff.mp hz] at hy
+ cases hz : l.max? with
+ | none => simp [List.max?_eq_none_iff.mp hz] at hy
| some z =>
have : Antisymm (α := α) (· ≤ ·) := ⟨_root_.le_antisymm⟩
- rw [List.maximum?_eq_some_iff] at hz
+ rw [List.max?_eq_some_iff] at hz
· rw [Option.getD_some]
exact _root_.le_antisymm (hy.right _ hz.left) (hz.right _ hy.left)
all_goals simp [le_total]
-lemma getD_minimum?_eq_untop'_minimum (l : List α) (d : α) :
- l.minimum?.getD d = l.minimum.untop' d :=
- getD_maximum?_eq_unbot'_maximum (α := αᵒᵈ) _ _
+@[deprecated (since := "2024-09-29")]
+alias getD_maximum?_eq_unbot'_maximum := getD_max?_eq_unbot'_maximum
+
+lemma getD_min?_eq_untop'_minimum (l : List α) (d : α) :
+ l.min?.getD d = l.minimum.untop' d :=
+ getD_max?_eq_unbot'_maximum (α := αᵒᵈ) _ _
+
+@[deprecated (since := "2024-09-29")]
+alias getD_minimum?_eq_untop'_minimum := getD_min?_eq_untop'_minimum
end LinearOrder
diff --git a/Mathlib/Data/List/Monad.lean b/Mathlib/Data/List/Monad.lean
index a89b5f05d5272..04d1477cbd14d 100644
--- a/Mathlib/Data/List/Monad.lean
+++ b/Mathlib/Data/List/Monad.lean
@@ -9,11 +9,11 @@ import Mathlib.Init
# Monad instances for `List`
-/
-universe u v w
+universe u
namespace List
-variable {α : Type u} {β : Type v} {γ : Type w}
+variable {α : Type u}
instance instMonad : Monad List.{u} where
pure := @List.pure
diff --git a/Mathlib/Data/List/NatAntidiagonal.lean b/Mathlib/Data/List/NatAntidiagonal.lean
index fbbf06a9c47bb..b7ccdccf19f70 100644
--- a/Mathlib/Data/List/NatAntidiagonal.lean
+++ b/Mathlib/Data/List/NatAntidiagonal.lean
@@ -59,8 +59,8 @@ theorem nodup_antidiagonal (n : ℕ) : Nodup (antidiagonal n) :=
@[simp]
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, true_and_iff, Nat.add_succ_sub_one,
- Nat.add_zero, id, eq_self_iff_true, Nat.sub_zero, map_map, Prod.map_mk]
+ 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_apply]
apply congr rfl (congr rfl _)
ext; simp
diff --git a/Mathlib/Data/List/Nodup.lean b/Mathlib/Data/List/Nodup.lean
index c4ede7b589049..7fc680190d8c0 100644
--- a/Mathlib/Data/List/Nodup.lean
+++ b/Mathlib/Data/List/Nodup.lean
@@ -16,9 +16,9 @@ predicate.
universe u v
-open Nat Function
+open Function
-variable {α : Type u} {β : Type v} {l l₁ l₂ : List α} {r : α → α → Prop} {a b : α}
+variable {α : Type u} {β : Type v} {l l₁ l₂ : List α} {r : α → α → Prop} {a : α}
namespace List
@@ -140,14 +140,14 @@ theorem nodup_iff_count_le_one [DecidableEq α] {l : List α} : Nodup l ↔ ∀
theorem nodup_iff_count_eq_one [DecidableEq α] : Nodup l ↔ ∀ a ∈ l, count a l = 1 :=
nodup_iff_count_le_one.trans <| forall_congr' fun _ =>
- ⟨fun H h => H.antisymm (count_pos_iff_mem.mpr h),
+ ⟨fun H h => H.antisymm (count_pos_iff.mpr h),
fun H => if h : _ then (H h).le else (count_eq_zero.mpr h).trans_le (Nat.zero_le 1)⟩
@[simp]
theorem count_eq_one_of_mem [DecidableEq α] {a : α} {l : List α} (d : Nodup l) (h : a ∈ l) :
count a l = 1 :=
- _root_.le_antisymm (nodup_iff_count_le_one.1 d a) (Nat.succ_le_of_lt (count_pos_iff_mem.2 h))
+ _root_.le_antisymm (nodup_iff_count_le_one.1 d a) (Nat.succ_le_of_lt (count_pos_iff.2 h))
theorem count_eq_of_nodup [DecidableEq α] {a : α} {l : List α} (d : Nodup l) :
count a l = if a ∈ l then 1 else 0 := by
@@ -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 :=
@@ -244,8 +241,8 @@ theorem Nodup.erase_getElem [DecidableEq α] {l : List α} (hl : l.Nodup)
· simp [IH hl.2]
· rw [beq_iff_eq]
simp only [getElem_cons_succ]
- simp only [length_cons, succ_eq_add_one, Nat.add_lt_add_iff_right] at h
- exact mt (· ▸ l.getElem_mem i h) hl.1
+ simp only [length_cons, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right] at h
+ exact mt (· ▸ getElem_mem h) hl.1
theorem Nodup.erase_get [DecidableEq α] {l : List α} (hl : l.Nodup) (i : Fin l.length) :
l.erase (l.get i) = l.eraseIdx ↑i := by
@@ -262,8 +259,8 @@ theorem nodup_join {L : List (List α)} :
theorem nodup_bind {l₁ : List α} {f : α → List β} :
Nodup (l₁.bind f) ↔
(∀ x ∈ l₁, Nodup (f x)) ∧ Pairwise (fun a b : α => Disjoint (f a) (f b)) l₁ := by
- simp only [List.bind, nodup_join, pairwise_map, and_comm, and_left_comm, mem_map, exists_imp,
- and_imp]
+ simp only [List.bind, nodup_join, pairwise_map, and_comm, and_left_comm, mem_map,
+ exists_imp, and_imp]
rw [show (∀ (l : List β) (x : α), f x = l → x ∈ l₁ → Nodup l) ↔ ∀ x : α, x ∈ l₁ → Nodup (f x)
from forall_swap.trans <| forall_congr' fun _ => forall_eq']
@@ -304,13 +301,12 @@ theorem Nodup.union [DecidableEq α] (l₁ : List α) (h : Nodup l₂) : (l₁
theorem Nodup.inter [DecidableEq α] (l₂ : List α) : Nodup l₁ → Nodup (l₁ ∩ l₂) :=
Nodup.filter _
-theorem Nodup.diff_eq_filter [DecidableEq α] :
+theorem Nodup.diff_eq_filter [BEq α] [LawfulBEq α] :
∀ {l₁ l₂ : List α} (_ : l₁.Nodup), l₁.diff l₂ = l₁.filter (· ∉ l₂)
| l₁, [], _ => by simp
| l₁, a :: l₂, hl₁ => by
rw [diff_cons, (hl₁.erase _).diff_eq_filter, hl₁.erase_eq_filter, filter_filter]
- simp only [decide_not, Bool.not_eq_true', decide_eq_false_iff_not, bne_iff_ne, ne_eq, and_comm,
- Bool.decide_and, mem_cons, not_or]
+ simp only [decide_not, bne, Bool.and_comm, mem_cons, not_or, decide_mem_cons, Bool.not_or]
theorem Nodup.mem_diff_iff [DecidableEq α] (hl₁ : l₁.Nodup) : a ∈ l₁.diff l₂ ↔ a ∈ l₁ ∧ a ∉ l₂ := by
rw [hl₁.diff_eq_filter, mem_filter, decide_eq_true_iff]
diff --git a/Mathlib/Data/List/NodupEquivFin.lean b/Mathlib/Data/List/NodupEquivFin.lean
index 5266ae7b60164..0dcf11280caae 100644
--- a/Mathlib/Data/List/NodupEquivFin.lean
+++ b/Mathlib/Data/List/NodupEquivFin.lean
@@ -126,7 +126,7 @@ theorem sublist_of_orderEmbedding_get?_eq {l l' : List α} (f : ℕ ↪o ℕ)
exact ix.succ_pos
rw [← List.take_append_drop (f 0 + 1) l', ← List.singleton_append]
apply List.Sublist.append _ (IH _ this)
- rw [List.singleton_sublist, ← h, l'.getElem_take _ (Nat.lt_succ_self _)]
+ rw [List.singleton_sublist, ← h, l'.getElem_take' _ (Nat.lt_succ_self _)]
apply List.get_mem
/-- A `l : List α` is `Sublist l l'` for `l' : List α` iff
diff --git a/Mathlib/Data/List/OfFn.lean b/Mathlib/Data/List/OfFn.lean
index cdfcb9554f599..27001ba3ea4b0 100644
--- a/Mathlib/Data/List/OfFn.lean
+++ b/Mathlib/Data/List/OfFn.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 Batteries.Data.List.Pairwise
+import Batteries.Data.List.OfFn
import Mathlib.Data.Fin.Tuple.Basic
/-!
@@ -16,7 +16,6 @@ of length `n`.
The main statements pertain to lists generated using `List.ofFn`
-- `List.length_ofFn`, which tells us the length of such a list
- `List.get?_ofFn`, which tells us the nth element of such a list
- `List.equivSigmaTuple`, which is an `Equiv` between lists and the functions that generate them
via `List.ofFn`.
@@ -32,44 +31,9 @@ open Nat
namespace List
-@[simp]
-theorem length_ofFn_go {n} (f : Fin n → α) (i j h) : length (ofFn.go f i j h) = i := by
- induction i generalizing j <;> simp_all [ofFn.go]
-
-/-- The length of a list converted from a function is the size of the domain. -/
-@[simp]
-theorem length_ofFn {n} (f : Fin n → α) : length (ofFn f) = n := by
- simp [ofFn, length_ofFn_go]
-
-theorem getElem_ofFn_go {n} (f : Fin n → α) (i j h) (k) (hk : k < (ofFn.go f i j h).length) :
- (ofFn.go f i j h)[k] = f ⟨j + k, by simp at hk; omega⟩ := by
- let i+1 := i
- cases k <;> simp [ofFn.go, getElem_ofFn_go (i := i)]
- congr 2; omega
-
-theorem get_ofFn_go {n} (f : Fin n → α) (i j h) (k) (hk) :
- get (ofFn.go f i j h) ⟨k, hk⟩ = f ⟨j + k, by simp at hk; omega⟩ := by
- simp [getElem_ofFn_go]
-
-@[simp]
-theorem getElem_ofFn {n} (f : Fin n → α) (i : Nat) (h : i < (ofFn f).length) :
- (ofFn f)[i] = f ⟨i, by simp_all⟩ := by
- simp [ofFn, getElem_ofFn_go]
-
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
simp; congr
-/-- The `n`th element of a list -/
-@[simp]
-theorem getElem?_ofFn {n} (f : Fin n → α) (i) : (ofFn f)[i]? = ofFnNthVal f i :=
- if h : i < (ofFn f).length
- then by
- rw [getElem?_eq_getElem h, getElem_ofFn]
- · simp only [length_ofFn] at h; simp [ofFnNthVal, h]
- else by
- rw [ofFnNthVal, dif_neg] <;>
- simpa using h
-
/-- The `n`th element of a list -/
theorem get?_ofFn {n} (f : Fin n → α) (i) : get? (ofFn f) i = ofFnNthVal f i := by
simp
@@ -213,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]
@@ -235,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 565fc6ade6048..0000000000000
--- a/Mathlib/Data/List/Perm.lean
+++ /dev/null
@@ -1,649 +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 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, 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.fold_op_eq {l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : (l₁ <*> a) = l₂ <*> a :=
- h.foldl_eq (right_comm _ IC.comm IA.assoc) _
-
-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_iff, 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 e5812cb86b262..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.
@@ -43,7 +42,7 @@ end CommMonoidWithZero
section CancelCommMonoidWithZero
-variable {M : Type*} [CancelCommMonoidWithZero M] [Unique (Units M)]
+variable {M : Type*} [CancelCommMonoidWithZero M] [Subsingleton Mˣ]
theorem mem_list_primes_of_dvd_prod {p : M} (hp : Prime p) {L : List M} (hL : ∀ q ∈ L, Prime q)
(hpL : p ∣ L.prod) : p ∈ L := by
@@ -54,10 +53,10 @@ theorem perm_of_prod_eq_prod :
∀ {l₁ l₂ : List M}, l₁.prod = l₂.prod → (∀ p ∈ l₁, Prime p) → (∀ p ∈ l₂, Prime p) → Perm l₁ l₂
| [], [], _, _, _ => Perm.nil
| [], a :: l, h₁, _, h₃ =>
- have ha : a ∣ 1 := @prod_nil M _ ▸ h₁.symm ▸ (@prod_cons _ _ l a).symm ▸ dvd_mul_right _ _
+ have ha : a ∣ 1 := prod_nil (M := M) ▸ h₁.symm ▸ (prod_cons (l := l)).symm ▸ dvd_mul_right _ _
absurd ha (Prime.not_dvd_one (h₃ a (mem_cons_self _ _)))
| a :: l, [], h₁, h₂, _ =>
- have ha : a ∣ 1 := @prod_nil M _ ▸ h₁ ▸ (@prod_cons _ _ l a).symm ▸ dvd_mul_right _ _
+ have ha : a ∣ 1 := prod_nil (M := M) ▸ h₁ ▸ (prod_cons (l := l)).symm ▸ dvd_mul_right _ _
absurd ha (Prime.not_dvd_one (h₂ a (mem_cons_self _ _)))
| a :: l₁, b :: l₂, h, hl₁, hl₂ => by
classical
diff --git a/Mathlib/Data/List/Range.lean b/Mathlib/Data/List/Range.lean
index 66dd6c10fdb9b..9f779d7aa545b 100644
--- a/Mathlib/Data/List/Range.lean
+++ b/Mathlib/Data/List/Range.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Kenny Lau, Scott Morrison
+Authors: Mario Carneiro, Kenny Lau, Kim Morrison
-/
import Mathlib.Data.List.Chain
import Mathlib.Data.List.Nodup
@@ -34,8 +34,7 @@ theorem chain'_range_succ (r : ℕ → ℕ → Prop) (n : ℕ) :
induction' n with n hn
· simp
· rw [range_succ]
- simp only [append_assoc, singleton_append, chain'_append_cons_cons, chain'_singleton,
- and_true_iff]
+ simp only [append_assoc, singleton_append, chain'_append_cons_cons, chain'_singleton, and_true]
rw [hn, forall_lt_succ]
theorem chain_range_succ (r : ℕ → ℕ → Prop) (n a : ℕ) :
@@ -43,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/ReduceOption.lean b/Mathlib/Data/List/ReduceOption.lean
index f86d28a812369..8994967357edb 100644
--- a/Mathlib/Data/List/ReduceOption.lean
+++ b/Mathlib/Data/List/ReduceOption.lean
@@ -34,8 +34,7 @@ theorem reduceOption_map {l : List (Option α)} {f : α → β} :
induction' l with hd tl hl
· simp only [reduceOption_nil, map_nil]
· cases hd <;>
- simpa [true_and_iff, Option.map_some', map, eq_self_iff_true,
- reduceOption_cons_of_some] using hl
+ simpa [Option.map_some', map, eq_self_iff_true, reduceOption_cons_of_some] using hl
theorem reduceOption_append (l l' : List (Option α)) :
(l ++ l').reduceOption = l.reduceOption ++ l'.reduceOption :=
diff --git a/Mathlib/Data/List/Rotate.lean b/Mathlib/Data/List/Rotate.lean
index 5cbd6337a5630..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 :
@@ -116,7 +116,7 @@ theorem length_rotate (l : List α) (n : ℕ) : (l.rotate n).length = l.length :
@[simp]
theorem rotate_replicate (a : α) (n : ℕ) (k : ℕ) : (replicate n a).rotate k = replicate n a :=
- eq_replicate.2 ⟨by rw [length_rotate, length_replicate], fun b hb =>
+ eq_replicate_iff.2 ⟨by rw [length_rotate, length_replicate], fun b hb =>
eq_of_mem_replicate <| mem_rotate.1 hb⟩
theorem rotate_eq_drop_append_take {l : List α} {n : ℕ} :
@@ -473,7 +473,7 @@ theorem IsRotated.dropLast_tail {α}
| [] => by simp
| [_] => by simp
| a :: b :: L => by
- simp at hL' |-
+ simp only [head_cons, ne_eq, reduceCtorEq, not_false_eq_true, getLast_cons] at hL'
simp [hL', IsRotated.cons_getLast_dropLast]
/-- List of all cyclic permutations of `l`.
@@ -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/Sections.lean b/Mathlib/Data/List/Sections.lean
index 5fc1305b9cafa..c604e4d75e47c 100644
--- a/Mathlib/Data/List/Sections.lean
+++ b/Mathlib/Data/List/Sections.lean
@@ -25,7 +25,7 @@ theorem mem_sections {L : List (List α)} {f} : f ∈ sections L ↔ Forall₂ (
exact Forall₂.nil
simp only [sections, bind_eq_bind, mem_bind, mem_map] at h
rcases h with ⟨_, _, _, _, rfl⟩
- simp only [*, forall₂_cons, true_and_iff]
+ simp only [*, forall₂_cons, true_and]
· induction' h with a l f L al fL fs
· simp only [sections, mem_singleton]
simp only [sections, bind_eq_bind, mem_bind, mem_map]
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 6936029a0217b..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
@@ -123,8 +116,8 @@ theorem eq_of_perm_of_sorted [IsAntisymm α r] {l₁ l₂ : List α} (hp : l₁
congr
have : ∀ x ∈ u₂, x = a := fun x m =>
antisymm ((pairwise_append.1 hs₂).2.2 _ m a (mem_cons_self _ _)) (h₁ _ (by simp [m]))
- rw [(@eq_replicate _ a (length u₂ + 1) (a :: u₂)).2,
- (@eq_replicate _ a (length u₂ + 1) (u₂ ++ [a])).2] <;>
+ rw [(@eq_replicate_iff _ a (length u₂ + 1) (a :: u₂)).2,
+ (@eq_replicate_iff _ a (length u₂ + 1) (u₂ ++ [a])).2] <;>
constructor <;>
simp [iff_true_intro this, or_comm]
@@ -149,10 +142,18 @@ theorem Sorted.rel_of_mem_take_of_mem_drop {l : List α} (h : List.Sorted r l) {
(hx : x ∈ List.take k l) (hy : y ∈ List.drop k l) : r x y := by
obtain ⟨iy, hiy, rfl⟩ := getElem_of_mem hy
obtain ⟨ix, hix, rfl⟩ := getElem_of_mem hx
- rw [getElem_take', getElem_drop]
+ rw [getElem_take, getElem_drop]
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
@@ -198,18 +199,27 @@ def orderedInsert (a : α) : List α → List α
| [] => [a]
| b :: l => if a ≼ b then a :: b :: l else b :: orderedInsert a l
+theorem orderedInsert_of_le {a b : α} (l : List α) (h : a ≼ b) :
+ orderedInsert r a (b :: l) = a :: b :: l :=
+ dif_pos h
+
/-- `insertionSort l` returns `l` sorted using the insertion sort algorithm. -/
@[simp]
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]
@@ -281,6 +291,17 @@ theorem mem_insertionSort {l : List α} {x : α} : x ∈ l.insertionSort r ↔ x
theorem length_insertionSort (l : List α) : (insertionSort r l).length = l.length :=
(perm_insertionSort r _).length_eq
+theorem insertionSort_cons {a : α} {l : List α} (h : ∀ b ∈ l, r a b) :
+ insertionSort r (a :: l) = a :: insertionSort r l := by
+ rw [insertionSort]
+ cases hi : insertionSort r l with
+ | nil => rfl
+ | cons b m =>
+ rw [orderedInsert_of_le]
+ apply h b <| (mem_insertionSort r).1 _
+ rw [hi]
+ exact mem_cons_self b m
+
theorem map_insertionSort (f : α → β) (l : List α) (hl : ∀ a ∈ l, ∀ b ∈ l, a ≼ b ↔ f a ≼ f b) :
(l.insertionSort r).map f = (l.map f).insertionSort s := by
induction l with
@@ -298,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]
@@ -345,6 +366,40 @@ theorem sublist_orderedInsert (x : α) (xs : List α) : xs <+ xs.orderedInsert r
refine Sublist.trans ?_ (.append_left (.cons _ (.refl _)) _)
rw [takeWhile_append_dropWhile]
+theorem cons_sublist_orderedInsert {l c : List α} {a : α} (hl : c <+ l) (ha : ∀ a' ∈ c, a ≼ a') :
+ a :: c <+ orderedInsert r a l := by
+ induction l with
+ | nil => simp_all only [sublist_nil, orderedInsert, Sublist.refl]
+ | cons _ _ ih =>
+ unfold orderedInsert
+ split_ifs with hr
+ · exact .cons₂ _ hl
+ · cases hl with
+ | cons _ h => exact .cons _ <| ih h
+ | cons₂ => exact absurd (ha _ <| mem_cons_self ..) hr
+
+theorem Sublist.orderedInsert_sublist [IsTrans α r] {as bs} (x) (hs : as <+ bs) (hb : bs.Sorted r) :
+ orderedInsert r x as <+ orderedInsert r x bs := by
+ cases as with
+ | nil => simp
+ | cons a as =>
+ cases bs with
+ | nil => contradiction
+ | cons b bs =>
+ unfold orderedInsert
+ cases hs <;> split_ifs with hr
+ · exact .cons₂ _ <| .cons _ ‹a :: as <+ bs›
+ · have ih := orderedInsert_sublist x ‹a :: as <+ bs› hb.of_cons
+ simp only [hr, orderedInsert, ite_true] at ih
+ exact .trans ih <| .cons _ (.refl _)
+ · have hba := pairwise_cons.mp hb |>.left _ (mem_of_cons_sublist ‹a :: as <+ bs›)
+ exact absurd (trans_of _ ‹r x b› hba) hr
+ · have ih := orderedInsert_sublist x ‹a :: as <+ bs› hb.of_cons
+ rw [orderedInsert, if_neg hr] at ih
+ exact .cons _ ih
+ · simp_all only [sorted_cons, cons_sublist_cons]
+ · exact .cons₂ _ <| orderedInsert_sublist x ‹as <+ bs› hb.of_cons
+
section TotalAndTransitive
variable [IsTotal α r] [IsTrans α r]
@@ -374,214 +429,118 @@ theorem sorted_insertionSort : ∀ l, Sorted r (insertionSort r l)
end TotalAndTransitive
-end Correctness
-
-end InsertionSort
-
-/-! ### Merge sort -/
+/--
+If `c` is a sorted sublist of `l`, then `c` is still a sublist of `insertionSort r l`.
+-/
+theorem sublist_insertionSort {l c : List α} (hr : c.Pairwise r) (hc : c <+ l) :
+ c <+ insertionSort r l := by
+ induction l generalizing c with
+ | nil => simp_all only [sublist_nil, insertionSort, Sublist.refl]
+ | cons _ _ ih =>
+ cases hc with
+ | cons _ h => exact ih hr h |>.trans (sublist_orderedInsert ..)
+ | cons₂ _ h =>
+ obtain ⟨hr, hp⟩ := pairwise_cons.mp hr
+ exact cons_sublist_orderedInsert (ih hp h) hr
+/--
+Another statement of stability of insertion sort.
+If a pair `[a, b]` is a sublist of `l` and `r a b`,
+then `[a, b]` is still a sublist of `insertionSort r l`.
+-/
+theorem pair_sublist_insertionSort {a b : α} {l : List α} (hab : r a b) (h : [a, b] <+ l) :
+ [a, b] <+ insertionSort r l :=
+ sublist_insertionSort (pairwise_pair.mpr hab) h
-section MergeSort
+variable [IsAntisymm α r] [IsTotal α r] [IsTrans α r]
--- 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.
+/--
+A version of `insertionSort_stable` which only assumes `c <+~ l` (instead of `c <+ l`), but
+additionally requires `IsAntisymm α r`, `IsTotal α r` and `IsTrans α r`.
+-/
+theorem sublist_insertionSort' {l c : List α} (hs : c.Sorted r) (hc : c <+~ l) :
+ c <+ insertionSort r l := by
+ classical
+ obtain ⟨d, hc, hd⟩ := hc
+ induction l generalizing c d with
+ | nil => simp_all only [sublist_nil, insertionSort, nil_perm]
+ | cons a _ ih =>
+ cases hd with
+ | cons _ h => exact ih hs _ hc h |>.trans (sublist_orderedInsert ..)
+ | cons₂ _ h =>
+ specialize ih (hs.erase _) _ (erase_cons_head a ‹List _› ▸ hc.erase a) h
+ have hm := hc.mem_iff.mp <| mem_cons_self ..
+ have he := orderedInsert_erase _ _ hm hs
+ exact he ▸ Sublist.orderedInsert_sublist _ ih (sorted_insertionSort ..)
- 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₁)
+/--
+Another statement of stability of insertion sort.
+If a pair `[a, b]` is a sublist of a permutation of `l` and `a ≼ b`,
+then `[a, b]` is still a sublist of `insertionSort r l`.
+-/
+theorem pair_sublist_insertionSort' {a b : α} {l : List α} (hab : a ≼ b) (h : [a, b] <+~ l) :
+ [a, b] <+ insertionSort r l :=
+ sublist_insertionSort' (pairwise_pair.mpr hab) h
-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]
+end Correctness
-@[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]
+end InsertionSort
-@[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 (r · ·) (mergeSort' ls.1) (mergeSort' ls.2)
- 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 (r · ·) (mergeSort' r l₁) (mergeSort' r l₂) := by
- simp only [mergeSort', h]
+/-! ### Merge sort
-section Correctness
+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.
+-/
-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
+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_mergeSort' {l : List α} {x : α} : x ∈ l.mergeSort' r ↔ x ∈ l :=
- (perm_mergeSort' r l).mem_iff
+section MergeSort
-@[simp]
-theorem length_mergeSort' (l : List α) : (mergeSort' r l).length = l.length :=
- (perm_mergeSort' r _).length_eq
+section Correctness
section TotalAndTransitive
variable {r} [IsTotal α r] [IsTrans α r]
-theorem Sorted.merge : ∀ {l l' : List α}, Sorted r l → Sorted r l' → Sorted r (merge (r · ·) l l')
- | [], [], _, _ => 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 (r · ·) l (b :: l'), 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 (r · ·) (a :: l) l', 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_merge (f : α → β) (r : α → α → Bool) (s : β → β → Bool) (l l' : List α)
- (hl : ∀ a ∈ l, ∀ b ∈ l', r a b = s (f a) (f b)) :
- (l.merge r l').map f = (l.map f).merge s (l'.map f) := by
- match l, l' with
- | [], x' => simp
- | x, [] => simp
- | x :: xs, x' :: xs' =>
- simp_rw [List.forall_mem_cons, forall_and] at hl
- simp_rw [List.map, List.cons_merge_cons]
- rw [← hl.1.1]
- split
- · rw [List.map, map_merge _ r s, List.map]
- simp_rw [List.forall_mem_cons, forall_and]
- exact ⟨hl.2.1, hl.2.2⟩
- · rw [List.map, map_merge _ r s, List.map]
- simp_rw [List.forall_mem_cons]
- exact ⟨hl.1.2, hl.2.2⟩
-
-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 _ (r · ·) (s · ·), 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 8eac342a35b41..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
@@ -44,7 +44,7 @@ theorem sublists'Aux_eq_array_foldl (a : α) : ∀ (r₁ r₂ : List (List α)),
sublists'Aux a r₁ r₂ = ((r₁.toArray).foldl (init := r₂.toArray)
(fun r l => r.push (a :: l))).toList := by
intro r₁ r₂
- rw [sublists'Aux, Array.foldl_eq_foldl_data]
+ rw [sublists'Aux, Array.foldl_eq_foldl_toList]
have := List.foldl_hom Array.toList (fun r l => r.push (a :: l))
(fun r l => r ++ [a :: l]) r₁ r₂.toArray (by simp)
simpa using this
@@ -53,8 +53,7 @@ theorem sublists'_eq_sublists'Aux (l : List α) :
sublists' l = l.foldr (fun a r => sublists'Aux a r r) [[]] := by
simp only [sublists', sublists'Aux_eq_array_foldl]
rw [← List.foldr_hom Array.toList]
- · rfl
- · intros _ _; congr <;> simp
+ · intros _ _; congr
theorem sublists'Aux_eq_map (a : α) (r₁ : List (List α)) : ∀ (r₂ : List (List α)),
sublists'Aux a r₁ r₂ = r₂ ++ map (cons a) r₁ :=
@@ -107,7 +106,7 @@ theorem sublistsAux_eq_array_foldl :
(r.toArray.foldl (init := #[])
fun r l => (r.push l).push (a :: l)).toList := by
funext a r
- simp only [sublistsAux, Array.foldl_eq_foldl_data, Array.mkEmpty]
+ simp only [sublistsAux, Array.foldl_eq_foldl_toList, Array.mkEmpty]
have := foldl_hom Array.toList (fun r l => (r.push l).push (a :: l))
(fun (r : List (List α)) l => r ++ [l, a :: l]) r #[]
(by simp)
@@ -126,10 +125,9 @@ theorem sublistsAux_eq_bind :
ext α l : 2
trans l.foldr sublistsAux [[]]
· rw [sublistsAux_eq_bind, sublists]
- · simp only [sublistsFast, sublistsAux_eq_array_foldl, Array.foldr_eq_foldr_data]
+ · simp only [sublistsFast, sublistsAux_eq_array_foldl, Array.foldr_eq_foldr_toList]
rw [← foldr_hom Array.toList]
- · rfl
- · intros _ _; congr <;> simp
+ · intros _ _; congr
theorem sublists_append (l₁ l₂ : List α) :
sublists (l₁ ++ l₂) = (sublists l₂) >>= (fun x => (sublists l₁).map (· ++ x)) := by
@@ -207,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,
@@ -329,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
@@ -380,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/Sym.lean b/Mathlib/Data/List/Sym.lean
index 80954c1ad9dc7..1d6228b9258e3 100644
--- a/Mathlib/Data/List/Sym.lean
+++ b/Mathlib/Data/List/Sym.lean
@@ -237,7 +237,7 @@ theorem sym_one_eq : xs.sym 1 = xs.map (· ::ₛ .nil) := by
theorem sym2_eq_sym_two : xs.sym2.map (Sym2.equivSym α) = xs.sym 2 := by
induction xs with
- | nil => simp only [List.sym, map_eq_nil, sym2_eq_nil_iff]
+ | nil => simp only [List.sym, map_eq_nil_iff, sym2_eq_nil_iff]
| cons x xs ih =>
rw [List.sym, ← ih, sym_one_eq, map_map, List.sym2, map_append, map_map]
rfl
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 b53a34837076a..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]
@@ -92,7 +92,7 @@ theorem zipWith3_same_right (f : α → β → β → γ) :
| _ :: _, [] => rfl
| _ :: as, _ :: bs => congr_arg (cons _) <| zipWith3_same_right f as bs
-instance (f : α → α → β) [IsSymmOp α β f] : IsSymmOp (List α) (List β) (zipWith f) :=
+instance (f : α → α → β) [IsSymmOp f] : IsSymmOp (zipWith f) :=
⟨zipWith_comm_of_comm f IsSymmOp.symm_op⟩
@[simp]
diff --git a/Mathlib/Data/MLList/BestFirst.lean b/Mathlib/Data/MLList/BestFirst.lean
index 04d8b676c5644..1eceab8e6500c 100644
--- a/Mathlib/Data/MLList/BestFirst.lean
+++ b/Mathlib/Data/MLList/BestFirst.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Batteries.Data.MLList.Basic
import Mathlib.Data.Prod.Lex
diff --git a/Mathlib/Data/MLList/Dedup.lean b/Mathlib/Data/MLList/Dedup.lean
index 870c13fb4f7ab..736453f47d9f1 100644
--- a/Mathlib/Data/MLList/Dedup.lean
+++ b/Mathlib/Data/MLList/Dedup.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Batteries.Data.MLList.Basic
@@ -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/MLList/DepthFirst.lean b/Mathlib/Data/MLList/DepthFirst.lean
index 4454d1b3d8207..cc407b0ef5c2d 100644
--- a/Mathlib/Data/MLList/DepthFirst.lean
+++ b/Mathlib/Data/MLList/DepthFirst.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Batteries.Data.MLList.Basic
import Mathlib.Control.Combinators
diff --git a/Mathlib/Data/MLList/IO.lean b/Mathlib/Data/MLList/IO.lean
index 3887b991697a4..caec83d6d5838 100644
--- a/Mathlib/Data/MLList/IO.lean
+++ b/Mathlib/Data/MLList/IO.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Batteries.Data.MLList.Basic
diff --git a/Mathlib/Data/MLList/Split.lean b/Mathlib/Data/MLList/Split.lean
index 4a29154f9b6d2..2705ad27826e6 100644
--- a/Mathlib/Data/MLList/Split.lean
+++ b/Mathlib/Data/MLList/Split.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Batteries.Data.MLList.Basic
import Mathlib.Data.ULift
diff --git a/Mathlib/Data/Matrix/Basic.lean b/Mathlib/Data/Matrix/Basic.lean
index dfb96ff464262..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
@@ -492,6 +518,11 @@ theorem diagonal_conjTranspose [AddMonoid α] [StarAddMonoid α] (v : n → α)
rw [conjTranspose, diagonal_transpose, diagonal_map (star_zero _)]
rfl
+theorem diagonal_unique [Unique m] [DecidableEq m] [Zero α] (d : m → α) :
+ diagonal d = of fun _ _ => d default := by
+ ext i j
+ rw [Subsingleton.elim i default, Subsingleton.elim j default, diagonal_apply_eq _ _, of_apply]
+
section One
variable [Zero α] [One α]
@@ -1164,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} :
@@ -1204,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
/-!
@@ -1258,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
@@ -1286,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
@@ -1310,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
@@ -1340,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
@@ -1354,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 α) :=
@@ -2093,7 +2230,6 @@ variants which this lemma would not apply to:
* `Matrix.conjTranspose_intCast_smul`
* `Matrix.conjTranspose_inv_natCast_smul`
* `Matrix.conjTranspose_inv_intCast_smul`
-* `Matrix.conjTranspose_rat_smul`
* `Matrix.conjTranspose_ratCast_smul`
-/
@[simp]
@@ -2107,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
@@ -2161,7 +2296,6 @@ theorem conjTranspose_ratCast_smul [DivisionRing R] [AddCommGroup α] [StarAddMo
(c : ℚ) (M : Matrix m n α) : ((c : R) • M)ᴴ = (c : R) • Mᴴ :=
Matrix.ext <| by simp
-@[simp]
theorem conjTranspose_rat_smul [AddCommGroup α] [StarAddMonoid α] [Module ℚ α] (c : ℚ)
(M : Matrix m n α) : (c • M)ᴴ = c • Mᴴ :=
Matrix.ext <| by simp
@@ -2446,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
@@ -2469,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 1204f7bb9f157..23333213c522e 100644
--- a/Mathlib/Data/Matrix/Basis.lean
+++ b/Mathlib/Data/Matrix/Basis.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Jalex Stark. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Jalex Stark, Scott Morrison, Eric Wieser, Oliver Nash, Wen Yang
+Authors: Jalex Stark, Kim Morrison, Eric Wieser, Oliver Nash, Wen Yang
-/
import Mathlib.Data.Matrix.Basic
import Mathlib.LinearAlgebra.Matrix.Trace
@@ -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 6961195e3a83e..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)
@@ -258,17 +258,8 @@ lemma fromColumns_mul_fromRows_eq_one_comm
[Fintype n₁] [Fintype n₂] [Fintype n] [DecidableEq n] [DecidableEq n₁] [DecidableEq n₂]
(e : n ≃ n₁ ⊕ n₂)
(A₁ : Matrix n n₁ R) (A₂ : Matrix n n₂ R) (B₁ : Matrix n₁ n R) (B₂ : Matrix n₂ n R) :
- fromColumns A₁ A₂ * fromRows B₁ B₂ = 1 ↔ fromRows B₁ B₂ * fromColumns A₁ A₂ = 1 := by
- calc fromColumns A₁ A₂ * fromRows B₁ B₂ = 1
- _ ↔ submatrix (fromColumns A₁ A₂) id e * submatrix (fromRows B₁ B₂) e id = 1 := by
- simp
- _ ↔ submatrix (fromRows B₁ B₂) e id * submatrix (fromColumns A₁ A₂) id e = 1 :=
- mul_eq_one_comm
- _ ↔ reindex e.symm e.symm (fromRows B₁ B₂ * fromColumns A₁ A₂) = reindex e.symm e.symm 1 := by
- simp only [reindex_apply, Equiv.symm_symm, submatrix_one_equiv,
- submatrix_mul (he₂ := Function.bijective_id)]
- _ ↔ fromRows B₁ B₂ * fromColumns A₁ A₂ = 1 :=
- (reindex _ _).injective.eq_iff
+ fromColumns A₁ A₂ * fromRows B₁ B₂ = 1 ↔ fromRows B₁ B₂ * fromColumns A₁ A₂ = 1 :=
+ mul_eq_one_comm_of_equiv e
/-- The lemma `fromColumns_mul_fromRows_eq_one_comm` specialized to the case where the index sets n₁
and n₂, are the result of subtyping by a predicate and its complement. -/
diff --git a/Mathlib/Data/Matrix/Composition.lean b/Mathlib/Data/Matrix/Composition.lean
index de52659e526d6..1970544baa99b 100644
--- a/Mathlib/Data/Matrix/Composition.lean
+++ b/Mathlib/Data/Matrix/Composition.lean
@@ -55,9 +55,7 @@ variable [Semiring R] [Fintype I] [Fintype J] [DecidableEq I] [DecidableEq J]
@[simps!]
def compRingEquiv : Matrix I I (Matrix J J R) ≃+* Matrix (I × J) (I × J) R where
__ := Matrix.compAddEquiv I I J J R
- map_mul' _ _ := by
- ext _ _
- exact (Matrix.sum_apply _ _ _ _).trans <| Eq.symm Fintype.sum_prod_type
+ map_mul' _ _ := by ext; exact (Matrix.sum_apply ..).trans <| .symm <| Fintype.sum_prod_type ..
end Semiring
diff --git a/Mathlib/Data/Matrix/DMatrix.lean b/Mathlib/Data/Matrix/DMatrix.lean
index 64fcb5711e21b..cf00fbd771964 100644
--- a/Mathlib/Data/Matrix/DMatrix.lean
+++ b/Mathlib/Data/Matrix/DMatrix.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Hom.Defs
@@ -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/Invertible.lean b/Mathlib/Data/Matrix/Invertible.lean
index 5b38bcb33b6e3..d5581bd17d0de 100644
--- a/Mathlib/Data/Matrix/Invertible.lean
+++ b/Mathlib/Data/Matrix/Invertible.lean
@@ -1,9 +1,10 @@
/-
Copyright (c) 2023 Eric Wieser. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Eric Wieser
+Authors: Eric Wieser, Ahmad Alkhalawi
-/
import Mathlib.Data.Matrix.Basic
+import Mathlib.Tactic.Abel
/-! # Extra lemmas about invertible matrices
@@ -47,10 +48,14 @@ protected theorem invOf_mul_cancel_right (A : Matrix m n α) (B : Matrix n n α)
protected theorem mul_invOf_cancel_right (A : Matrix m n α) (B : Matrix n n α) [Invertible B] :
A * B * ⅟ B = A := by rw [Matrix.mul_assoc, mul_invOf_self, Matrix.mul_one]
-@[deprecated (since := "2024-09-07")] alias invOf_mul_self_assoc := invOf_mul_cancel_left
-@[deprecated (since := "2024-09-07")] alias mul_invOf_self_assoc := mul_invOf_cancel_left
-@[deprecated (since := "2024-09-07")] alias mul_invOf_mul_self_cancel := invOf_mul_cancel_right
-@[deprecated (since := "2024-09-07")] alias mul_mul_invOf_self_cancel := mul_invOf_cancel_right
+@[deprecated (since := "2024-09-07")]
+protected alias invOf_mul_self_assoc := Matrix.invOf_mul_cancel_left
+@[deprecated (since := "2024-09-07")]
+protected alias mul_invOf_self_assoc := Matrix.mul_invOf_cancel_left
+@[deprecated (since := "2024-09-07")]
+protected alias mul_invOf_mul_self_cancel := Matrix.invOf_mul_cancel_right
+@[deprecated (since := "2024-09-07")]
+protected alias mul_mul_invOf_self_cancel := Matrix.mul_invOf_cancel_right
section ConjTranspose
variable [StarRing α] (A : Matrix n n α)
@@ -106,4 +111,68 @@ def transposeInvertibleEquivInvertible : Invertible Aᵀ ≃ Invertible A where
end CommSemiring
+section Ring
+
+section Woodbury
+
+variable [Fintype m] [DecidableEq m] [Ring α]
+ (A : Matrix n n α) (U : Matrix n m α) (C : Matrix m m α) (V : Matrix m n α)
+ [Invertible A] [Invertible C] [Invertible (⅟C + V * ⅟A * U)]
+
+-- No spaces around multiplication signs for better clarity
+lemma add_mul_mul_invOf_mul_eq_one :
+ (A + U*C*V)*(⅟A - ⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A) = 1 := by
+ calc
+ (A + U*C*V)*(⅟A - ⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A)
+ _ = A*⅟A - A*⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A + U*C*V*⅟A - U*C*V*⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A := by
+ simp_rw [add_sub_assoc, add_mul, mul_sub, Matrix.mul_assoc]
+ _ = (1 + U*C*V*⅟A) - (U*⅟(⅟C + V*⅟A*U)*V*⅟A + U*C*V*⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A) := by
+ rw [mul_invOf_self, Matrix.one_mul]
+ abel
+ _ = 1 + U*C*V*⅟A - (U + U*C*V*⅟A*U)*⅟(⅟C + V*⅟A*U)*V*⅟A := by
+ rw [sub_right_inj, Matrix.add_mul, Matrix.add_mul, Matrix.add_mul]
+ _ = 1 + U*C*V*⅟A - U*C*(⅟C + V*⅟A*U)*⅟(⅟C + V*⅟A*U)*V*⅟A := by
+ congr
+ simp only [Matrix.mul_add, Matrix.mul_invOf_cancel_right, ← Matrix.mul_assoc]
+ _ = 1 := by
+ rw [Matrix.mul_invOf_cancel_right]
+ abel
+
+/-- Like `add_mul_mul_invOf_mul_eq_one`, but with multiplication reversed. -/
+lemma add_mul_mul_invOf_mul_eq_one' :
+ (⅟A - ⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A)*(A + U*C*V) = 1 := by
+ calc
+ (⅟A - ⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A)*(A + U*C*V)
+ _ = ⅟A*A - ⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A*A + ⅟A*U*C*V - ⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A*U*C*V := by
+ simp_rw [add_sub_assoc, _root_.mul_add, _root_.sub_mul, Matrix.mul_assoc]
+ _ = (1 + ⅟A*U*C*V) - (⅟A*U*⅟(⅟C + V*⅟A*U)*V + ⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A*U*C*V) := by
+ rw [invOf_mul_self, Matrix.invOf_mul_cancel_right]
+ abel
+ _ = 1 + ⅟A*U*C*V - ⅟A*U*⅟(⅟C + V*⅟A*U)*(V + V*⅟A*U*C*V) := by
+ rw [sub_right_inj, Matrix.mul_add]
+ simp_rw [Matrix.mul_assoc]
+ _ = 1 + ⅟A*U*C*V - ⅟A*U*⅟(⅟C + V*⅟A*U)*(⅟C + V*⅟A*U)*C*V := by
+ congr 1
+ simp only [Matrix.mul_add, Matrix.add_mul, ← Matrix.mul_assoc,
+ Matrix.invOf_mul_cancel_right]
+ _ = 1 := by
+ rw [Matrix.invOf_mul_cancel_right]
+ abel
+
+/-- If matrices `A`, `C`, and `C⁻¹ + V * A⁻¹ * U` are invertible, then so is `A + U * C * V`-/
+def invertibleAddMulMul : Invertible (A + U*C*V) where
+ invOf := ⅟A - ⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A
+ invOf_mul_self := add_mul_mul_invOf_mul_eq_one' _ _ _ _
+ mul_invOf_self := add_mul_mul_invOf_mul_eq_one _ _ _ _
+
+/-- The **Woodbury Identity** (`⅟` version). -/
+theorem invOf_add_mul_mul [Invertible (A + U*C*V)] :
+ ⅟(A + U*C*V) = ⅟A - ⅟A*U*⅟(⅟C + V*⅟A*U)*V*⅟A := by
+ letI := invertibleAddMulMul A U C V
+ convert (rfl : ⅟(A + U*C*V) = _)
+
+end Woodbury
+
+end Ring
+
end Matrix
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/Rank.lean b/Mathlib/Data/Matrix/Rank.lean
index 8ae0a21d0de4a..13db0d03e2bc9 100644
--- a/Mathlib/Data/Matrix/Rank.lean
+++ b/Mathlib/Data/Matrix/Rank.lean
@@ -26,7 +26,7 @@ open Matrix
namespace Matrix
-open FiniteDimensional
+open Module
variable {l m n o R : Type*} [Fintype n] [Fintype o]
@@ -168,7 +168,7 @@ variable [Field R]
/-- The rank of a diagnonal matrix is the count of non-zero elements on its main diagonal -/
theorem rank_diagonal [Fintype m] [DecidableEq m] [DecidableEq R] (w : m → R) :
(diagonal w).rank = Fintype.card {i // (w i) ≠ 0} := by
- rw [Matrix.rank, ← Matrix.toLin'_apply', FiniteDimensional.finrank, ← LinearMap.rank,
+ rw [Matrix.rank, ← Matrix.toLin'_apply', Module.finrank, ← LinearMap.rank,
LinearMap.rank_diagonal, Cardinal.toNat_natCast]
end Field
@@ -265,4 +265,23 @@ theorem rank_eq_finrank_span_row [Field R] [Finite m] (A : Matrix m n R) :
cases nonempty_fintype m
rw [← rank_transpose, rank_eq_finrank_span_cols, transpose_transpose]
+theorem _root_.LinearIndependent.rank_matrix [Field R] [Fintype m]
+ {M : Matrix m n R} (h : LinearIndependent R M) : M.rank = Fintype.card m := by
+ rw [M.rank_eq_finrank_span_row, linearIndependent_iff_card_eq_finrank_span.mp h, Set.finrank]
+
+lemma rank_add_rank_le_card_of_mul_eq_zero [Field R] [Finite l] [Fintype m]
+ {A : Matrix l m R} {B : Matrix m n R} (hAB : A * B = 0) :
+ A.rank + B.rank ≤ Fintype.card m := by
+ classical
+ let el : Basis l R (l → R) := Pi.basisFun R l
+ let em : Basis m R (m → R) := Pi.basisFun R m
+ let en : Basis n R (n → R) := Pi.basisFun R n
+ rw [Matrix.rank_eq_finrank_range_toLin A el em,
+ Matrix.rank_eq_finrank_range_toLin B em en,
+ ← Module.finrank_fintype_fun_eq_card R,
+ ← LinearMap.finrank_range_add_finrank_ker (Matrix.toLin em el A),
+ add_le_add_iff_left]
+ apply Submodule.finrank_mono
+ rw [LinearMap.range_le_ker_iff, ← Matrix.toLin_mul, hAB, map_zero]
+
end Matrix
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/Matrix/RowCol.lean b/Mathlib/Data/Matrix/RowCol.lean
index 2529d88fd19ee..6ce7feb0bcaa5 100644
--- a/Mathlib/Data/Matrix/RowCol.lean
+++ b/Mathlib/Data/Matrix/RowCol.lean
@@ -136,6 +136,16 @@ theorem row_mulVec [Fintype n] [NonUnitalNonAssocSemiring α] (M : Matrix m n α
ext
rfl
+theorem row_mulVec_eq_const [Fintype m] [NonUnitalNonAssocSemiring α] (v w : m → α) :
+ Matrix.row ι v *ᵥ w = Function.const _ (v ⬝ᵥ w) := rfl
+
+theorem mulVec_col_eq_const [Fintype m] [NonUnitalNonAssocSemiring α] (v w : m → α) :
+ v ᵥ* Matrix.col ι w = Function.const _ (v ⬝ᵥ w) := rfl
+
+theorem row_mul_col [Fintype m] [Mul α] [AddCommMonoid α] (v w : m → α) :
+ row ι v * col ι w = of fun _ _ => v ⬝ᵥ w :=
+ rfl
+
@[simp]
theorem row_mul_col_apply [Fintype m] [Mul α] [AddCommMonoid α] (v w : m → α) (i j) :
(row ι v * col ι w) i j = v ⬝ᵥ w :=
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 94e09d5bf9e63..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)
@@ -306,7 +310,7 @@ theorem coe_singleton (a : α) : ([a] : Multiset α) = {a} :=
@[simp]
theorem mem_singleton {a b : α} : b ∈ ({a} : Multiset α) ↔ b = a := by
- simp only [← cons_zero, mem_cons, iff_self_iff, or_false_iff, not_mem_zero]
+ simp only [← cons_zero, mem_cons, iff_self, or_false, not_mem_zero]
theorem mem_singleton_self (a : α) : a ∈ ({a} : Multiset α) := by
rw [← cons_zero]
@@ -528,10 +532,18 @@ theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
perm_middle.subperm_left.2
((subperm_cons _).2 <| ((sublist_or_mem_of_sublist s).resolve_right m₁).subperm)
+theorem cons_le_of_not_mem (hs : a ∉ s) : a ::ₘ s ≤ t ↔ a ∈ t ∧ s ≤ t := by
+ apply Iff.intro (fun h ↦ ⟨subset_of_le h (mem_cons_self a s), le_trans (le_cons_self s a) h⟩)
+ rintro ⟨h₁, h₂⟩; rcases exists_cons_of_mem h₁ with ⟨_, rfl⟩
+ exact cons_le_cons _ ((le_cons_of_not_mem hs).mp h₂)
+
@[simp]
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 =>
@@ -581,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)
@@ -601,6 +613,10 @@ theorem le_add_right (s t : Multiset α) : s ≤ s + t := by simpa using add_le_
theorem le_add_left (s t : Multiset α) : s ≤ t + s := by simpa using add_le_add_right (zero_le t) s
+lemma subset_add_left {s t : Multiset α} : s ⊆ s + t := subset_of_le <| le_add_right s t
+
+lemma subset_add_right {s t : Multiset α} : s ⊆ t + s := subset_of_le <| le_add_left s t
+
theorem le_iff_exists_add {s t : Multiset α} : s ≤ t ↔ ∃ u, t = s + u :=
⟨fun h =>
leInductionOn h fun s =>
@@ -855,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 _ _),
@@ -961,6 +981,9 @@ theorem mem_of_mem_erase {a b : α} {s : Multiset α} : a ∈ s.erase b → a
theorem erase_comm (s : Multiset α) (a b : α) : (s.erase a).erase b = (s.erase b).erase a :=
Quot.inductionOn s fun l => congr_arg _ <| l.erase_comm a b
+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
@@ -1140,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]
@@ -1154,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⟩
@@ -1189,92 +1212,104 @@ theorem map_surjective_of_surjective {f : α → β} (hf : Function.Surjective f
/-! ### `Multiset.fold` -/
+section foldl
+
/-- `foldl f H b s` is the lift of the list operation `foldl f b l`,
which folds `f` over the multiset. It is well defined when `f` is right-commutative,
that is, `f (f b a₁) a₂ = f (f b a₂) a₁`. -/
-def foldl (f : β → α → β) (H : RightCommutative f) (b : β) (s : Multiset α) : β :=
- Quot.liftOn s (fun l => List.foldl f b l) fun _l₁ _l₂ p => p.foldl_eq H b
+def foldl (f : β → α → β) [RightCommutative f] (b : β) (s : Multiset α) : β :=
+ Quot.liftOn s (fun l => List.foldl f b l) fun _l₁ _l₂ p => p.foldl_eq b
+
+variable (f : β → α → β) [RightCommutative f]
@[simp]
-theorem foldl_zero (f : β → α → β) (H b) : foldl f H b 0 = b :=
+theorem foldl_zero (b) : foldl f b 0 = b :=
rfl
@[simp]
-theorem foldl_cons (f : β → α → β) (H b a s) : foldl f H b (a ::ₘ s) = foldl f H (f b a) s :=
+theorem foldl_cons (b a s) : foldl f b (a ::ₘ s) = foldl f (f b a) s :=
Quot.inductionOn s fun _l => rfl
@[simp]
-theorem foldl_add (f : β → α → β) (H b s t) : foldl f H b (s + t) = foldl f H (foldl f H b s) t :=
+theorem foldl_add (b s t) : foldl f b (s + t) = foldl f (foldl f b s) t :=
Quotient.inductionOn₂ s t fun _l₁ _l₂ => foldl_append _ _ _ _
+end foldl
+
+section foldr
+
/-- `foldr f H b s` is the lift of the list operation `foldr f b l`,
which folds `f` over the multiset. It is well defined when `f` is left-commutative,
that is, `f a₁ (f a₂ b) = f a₂ (f a₁ b)`. -/
-def foldr (f : α → β → β) (H : LeftCommutative f) (b : β) (s : Multiset α) : β :=
- Quot.liftOn s (fun l => List.foldr f b l) fun _l₁ _l₂ p => p.foldr_eq H b
+def foldr (f : α → β → β) [LeftCommutative f] (b : β) (s : Multiset α) : β :=
+ Quot.liftOn s (fun l => List.foldr f b l) fun _l₁ _l₂ p => p.foldr_eq b
+
+variable (f : α → β → β) [LeftCommutative f]
@[simp]
-theorem foldr_zero (f : α → β → β) (H b) : foldr f H b 0 = b :=
+theorem foldr_zero (b) : foldr f b 0 = b :=
rfl
@[simp]
-theorem foldr_cons (f : α → β → β) (H b a s) : foldr f H b (a ::ₘ s) = f a (foldr f H b s) :=
+theorem foldr_cons (b a s) : foldr f b (a ::ₘ s) = f a (foldr f b s) :=
Quot.inductionOn s fun _l => rfl
@[simp]
-theorem foldr_singleton (f : α → β → β) (H b a) : foldr f H b ({a} : Multiset α) = f a b :=
+theorem foldr_singleton (b a) : foldr f b ({a} : Multiset α) = f a b :=
rfl
@[simp]
-theorem foldr_add (f : α → β → β) (H b s t) : foldr f H b (s + t) = foldr f H (foldr f H b t) s :=
+theorem foldr_add (b s t) : foldr f b (s + t) = foldr f (foldr f b t) s :=
Quotient.inductionOn₂ s t fun _l₁ _l₂ => foldr_append _ _ _ _
+end foldr
+
@[simp]
-theorem coe_foldr (f : α → β → β) (H : LeftCommutative f) (b : β) (l : List α) :
- foldr f H b l = l.foldr f b :=
+theorem coe_foldr (f : α → β → β) [LeftCommutative f] (b : β) (l : List α) :
+ foldr f b l = l.foldr f b :=
rfl
@[simp]
-theorem coe_foldl (f : β → α → β) (H : RightCommutative f) (b : β) (l : List α) :
- foldl f H b l = l.foldl f b :=
+theorem coe_foldl (f : β → α → β) [RightCommutative f] (b : β) (l : List α) :
+ foldl f b l = l.foldl f b :=
rfl
-theorem coe_foldr_swap (f : α → β → β) (H : LeftCommutative f) (b : β) (l : List α) :
- foldr f H b l = l.foldl (fun x y => f y x) b :=
- (congr_arg (foldr f H b) (coe_reverse l)).symm.trans <| foldr_reverse _ _ _
+theorem coe_foldr_swap (f : α → β → β) [LeftCommutative f] (b : β) (l : List α) :
+ foldr f b l = l.foldl (fun x y => f y x) b :=
+ (congr_arg (foldr f b) (coe_reverse l)).symm.trans <| foldr_reverse _ _ _
-theorem foldr_swap (f : α → β → β) (H : LeftCommutative f) (b : β) (s : Multiset α) :
- foldr f H b s = foldl (fun x y => f y x) (fun _x _y _z => (H _ _ _).symm) b s :=
- Quot.inductionOn s fun _l => coe_foldr_swap _ _ _ _
+theorem foldr_swap (f : α → β → β) [LeftCommutative f] (b : β) (s : Multiset α) :
+ foldr f b s = foldl (fun x y => f y x) b s :=
+ Quot.inductionOn s fun _l => coe_foldr_swap _ _ _
-theorem foldl_swap (f : β → α → β) (H : RightCommutative f) (b : β) (s : Multiset α) :
- foldl f H b s = foldr (fun x y => f y x) (fun _x _y _z => (H _ _ _).symm) b s :=
- (foldr_swap _ _ _ _).symm
+theorem foldl_swap (f : β → α → β) [RightCommutative f] (b : β) (s : Multiset α) :
+ foldl f b s = foldr (fun x y => f y x) b s :=
+ (foldr_swap _ _ _).symm
-theorem foldr_induction' (f : α → β → β) (H : LeftCommutative f) (x : β) (q : α → Prop)
+theorem foldr_induction' (f : α → β → β) [LeftCommutative f] (x : β) (q : α → Prop)
(p : β → Prop) (s : Multiset α) (hpqf : ∀ a b, q a → p b → p (f a b)) (px : p x)
- (q_s : ∀ a ∈ s, q a) : p (foldr f H x s) := by
+ (q_s : ∀ a ∈ s, q a) : p (foldr f x s) := by
induction s using Multiset.induction with
| empty => simpa
| cons a s ihs =>
simp only [forall_mem_cons, foldr_cons] at q_s ⊢
exact hpqf _ _ q_s.1 (ihs q_s.2)
-theorem foldr_induction (f : α → α → α) (H : LeftCommutative f) (x : α) (p : α → Prop)
+theorem foldr_induction (f : α → α → α) [LeftCommutative f] (x : α) (p : α → Prop)
(s : Multiset α) (p_f : ∀ a b, p a → p b → p (f a b)) (px : p x) (p_s : ∀ a ∈ s, p a) :
- p (foldr f H x s) :=
- foldr_induction' f H x p p s p_f px p_s
+ p (foldr f x s) :=
+ foldr_induction' f x p p s p_f px p_s
-theorem foldl_induction' (f : β → α → β) (H : RightCommutative f) (x : β) (q : α → Prop)
+theorem foldl_induction' (f : β → α → β) [RightCommutative f] (x : β) (q : α → Prop)
(p : β → Prop) (s : Multiset α) (hpqf : ∀ a b, q a → p b → p (f b a)) (px : p x)
- (q_s : ∀ a ∈ s, q a) : p (foldl f H x s) := by
+ (q_s : ∀ a ∈ s, q a) : p (foldl f x s) := by
rw [foldl_swap]
- exact foldr_induction' (fun x y => f y x) (fun x y z => (H _ _ _).symm) x q p s hpqf px q_s
+ exact foldr_induction' (fun x y => f y x) x q p s hpqf px q_s
-theorem foldl_induction (f : α → α → α) (H : RightCommutative f) (x : α) (p : α → Prop)
+theorem foldl_induction (f : α → α → α) [RightCommutative f] (x : α) (p : α → Prop)
(s : Multiset α) (p_f : ∀ a b, p a → p b → p (f b a)) (px : p x) (p_s : ∀ a ∈ s, p a) :
- p (foldl f H x s) :=
- foldl_induction' f H x p p s p_f px p_s
+ p (foldl f x s) :=
+ foldl_induction' f x p p s p_f px p_s
/-! ### Map for partial functions -/
@@ -1327,8 +1362,7 @@ theorem pmap_eq_map (p : α → Prop) (f : α → β) (s : Multiset α) :
theorem pmap_congr {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a, q a → β} (s : Multiset α) :
∀ {H₁ H₂}, (∀ a ∈ s, ∀ (h₁ h₂), f a h₁ = g a h₂) → pmap f s H₁ = pmap g s H₂ :=
- @(Quot.inductionOn s (fun l _H₁ _H₂ h => congr_arg _ <| List.pmap_congr l h))
-
+ @(Quot.inductionOn s (fun l _H₁ _H₂ h => congr_arg _ <| List.pmap_congr_left l h))
theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (s) :
∀ H, map g (pmap f s H) = pmap (fun a h => g (f a h)) s H :=
@@ -1373,7 +1407,7 @@ theorem attach_cons (a : α) (m : Multiset α) :
Quotient.inductionOn m fun l =>
congr_arg _ <|
congr_arg (List.cons _) <| by
- rw [List.map_pmap]; exact List.pmap_congr _ fun _ _ _ _ => Subtype.eq rfl
+ rw [List.map_pmap]; exact List.pmap_congr_left _ fun _ _ _ _ => Subtype.eq rfl
section DecidablePiExists
@@ -1381,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
@@ -1392,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`. -/
@@ -1464,9 +1498,9 @@ instance : ExistsAddOfLE (Multiset α) where
theorem cons_sub_of_le (a : α) {s t : Multiset α} (h : t ≤ s) : a ::ₘ s - t = a ::ₘ (s - t) := by
rw [← singleton_add, ← singleton_add, add_tsub_assoc_of_le h]
-theorem sub_eq_fold_erase (s t : Multiset α) : s - t = foldl erase erase_comm s t :=
+theorem sub_eq_fold_erase (s t : Multiset α) : s - t = foldl erase s t :=
Quotient.inductionOn₂ s t fun l₁ l₂ => by
- show ofList (l₁.diff l₂) = foldl erase erase_comm l₁ l₂
+ show ofList (l₁.diff l₂) = foldl erase l₁ l₂
rw [diff_eq_foldl l₁ l₂]
symm
exact foldl_hom _ _ _ _ _ fun x y => rfl
@@ -1499,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
@@ -1604,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 _
@@ -1688,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
@@ -1704,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
@@ -1718,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 :=
@@ -1916,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
@@ -1984,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)
@@ -1999,11 +2039,11 @@ theorem countP_eq_countP_filter_add (s) (p q : α → Prop) [DecidablePred p] [D
@[simp]
theorem countP_True {s : Multiset α} : countP (fun _ => True) s = card s :=
- Quot.inductionOn s fun _l => List.countP_true
+ Quot.inductionOn s fun _l => congrFun List.countP_true _
@[simp]
theorem countP_False {s : Multiset α} : countP (fun _ => False) s = 0 :=
- Quot.inductionOn s fun _l => List.countP_false
+ Quot.inductionOn s fun _l => congrFun List.countP_false _
theorem countP_map (f : α → β) (s : Multiset α) (p : β → Prop) [DecidablePred p] :
countP p (map f s) = card (s.filter fun a => p (f a)) := by
@@ -2032,7 +2072,7 @@ lemma filter_attach (s : Multiset α) (p : α → Prop) [DecidablePred p] :
variable {p}
theorem countP_pos {s} : 0 < countP p s ↔ ∃ a ∈ s, p a :=
- Quot.inductionOn s fun _l => by simpa using List.countP_pos (p ·)
+ Quot.inductionOn s fun _l => by simp
theorem countP_eq_zero {s} : countP p s = 0 ↔ ∀ a ∈ s, ¬p a :=
Quot.inductionOn s fun _l => by simp [List.countP_eq_zero]
@@ -2043,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
@@ -2086,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 _
@@ -2332,6 +2374,24 @@ theorem map_count_True_eq_filter_card (s : Multiset α) (p : α → Prop) [Decid
simp only [count_eq_card_filter_eq, filter_map, card_map, Function.id_comp,
eq_true_eq_id, Function.comp_apply]
+@[simp] theorem sub_singleton [DecidableEq α] (a : α) (s : Multiset α) : s - {a} = s.erase a := by
+ ext
+ simp only [count_sub, count_singleton]
+ split <;> simp_all
+
+theorem mem_sub [DecidableEq α] {a : α} {s t : Multiset α} :
+ a ∈ s - t ↔ t.count a < s.count a := by
+ rw [← count_pos, count_sub, Nat.sub_pos_iff_lt]
+
+theorem inter_add_sub_of_add_eq_add [DecidableEq α] {M N P Q : Multiset α} (h : M + N = P + Q) :
+ (N ∩ Q) + (P - M) = N := by
+ ext x
+ rw [Multiset.count_add, Multiset.count_inter, Multiset.count_sub]
+ have h0 : M.count x + N.count x = P.count x + Q.count x := by
+ rw [Multiset.ext] at h
+ simp_all only [Multiset.mem_add, Multiset.count_add]
+ omega
+
/-! ### Lift a relation to `Multiset`s -/
@@ -2478,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 : ℕ} :
@@ -2518,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]
@@ -2732,9 +2792,6 @@ theorem coe_subsingletonEquiv [Subsingleton α] :
(subsingletonEquiv α : List α → Multiset α) = ofList :=
rfl
-@[deprecated (since := "2023-12-27")] alias card_le_of_le := card_le_card
-@[deprecated (since := "2023-12-27")] alias card_lt_of_lt := card_lt_card
-
end Multiset
set_option linter.style.longFile 2900
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 eef7f8002adbf..369c39be15028 100644
--- a/Mathlib/Data/Multiset/Fintype.lean
+++ b/Mathlib/Data/Multiset/Fintype.lean
@@ -188,8 +188,7 @@ theorem Multiset.map_univ_coeEmbedding (m : Multiset α) :
ext ⟨x, i⟩
simp only [Fin.exists_iff, Finset.mem_map, Finset.mem_univ, Multiset.coeEmbedding_apply,
Prod.mk.inj_iff, exists_true_left, Multiset.exists_coe, Multiset.coe_mk, Fin.val_mk,
- exists_prop, exists_eq_right_right, exists_eq_right, Multiset.mem_toEnumFinset, iff_self_iff,
- true_and_iff]
+ exists_prop, exists_eq_right_right, exists_eq_right, Multiset.mem_toEnumFinset, true_and]
@[simp]
theorem Multiset.map_univ_coe (m : Multiset α) :
@@ -218,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/Fold.lean b/Mathlib/Data/Multiset/Fold.lean
index 6cced7eebd0e1..5ec3691c966d1 100644
--- a/Mathlib/Data/Multiset/Fold.lean
+++ b/Mathlib/Data/Multiset/Fold.lean
@@ -26,10 +26,10 @@ local notation a " * " b => op a b
/-- `fold op b s` folds a commutative associative operation `op` over
the multiset `s`. -/
def fold : α → Multiset α → α :=
- foldr op (left_comm _ hc.comm ha.assoc)
+ foldr op
theorem fold_eq_foldr (b : α) (s : Multiset α) :
- fold op b s = foldr op (left_comm _ hc.comm ha.assoc) b s :=
+ fold op b s = foldr op b s :=
rfl
@[simp]
@@ -37,10 +37,10 @@ theorem coe_fold_r (b : α) (l : List α) : fold op b l = l.foldr op b :=
rfl
theorem coe_fold_l (b : α) (l : List α) : fold op b l = l.foldl op b :=
- (coe_foldr_swap op _ b l).trans <| by simp [hc.comm]
+ (coe_foldr_swap op b l).trans <| by simp [hc.comm]
theorem fold_eq_foldl (b : α) (s : Multiset α) :
- fold op b s = foldl op (right_comm _ hc.comm ha.assoc) b s :=
+ fold op b s = foldl op b s :=
Quot.inductionOn s fun _ => coe_fold_l _ _ _
@[simp]
@@ -49,7 +49,7 @@ theorem fold_zero (b : α) : (0 : Multiset α).fold op b = b :=
@[simp]
theorem fold_cons_left : ∀ (b a : α) (s : Multiset α), (a ::ₘ s).fold op b = a * s.fold op b :=
- foldr_cons _ _
+ foldr_cons _
theorem fold_cons_right (b a : α) (s : Multiset α) : (a ::ₘ s).fold op b = s.fold op b * a := by
simp [hc.comm]
@@ -74,7 +74,7 @@ theorem fold_bind {ι : Type*} (s : Multiset ι) (t : ι → Multiset α) (b :
· rw [cons_bind, map_cons, map_cons, fold_cons_left, fold_cons_left, fold_add, ih]
theorem fold_singleton (b a : α) : ({a} : Multiset α).fold op b = a * b :=
- foldr_singleton _ _ _ _
+ foldr_singleton _ _ _
theorem fold_distrib {f g : β → α} (u₁ u₂ : α) (s : Multiset β) :
(s.map fun x => f x * g x).fold op (u₁ * u₂) = (s.map f).fold op u₁ * (s.map g).fold op u₂ :=
diff --git a/Mathlib/Data/Multiset/Functor.lean b/Mathlib/Data/Multiset/Functor.lean
index 9c8f9ecbfb459..81575f5f445c4 100644
--- a/Mathlib/Data/Multiset/Functor.lean
+++ b/Mathlib/Data/Multiset/Functor.lean
@@ -99,7 +99,6 @@ theorem comp_traverse {G H : Type _ → Type _} [Applicative G] [Applicative H]
intro
simp only [traverse, quot_mk_to_coe, lift_coe, Coe.coe, Function.comp_apply, Functor.map_map,
functor_norm]
- simp only [Function.comp_def, lift_coe]
theorem map_traverse {G : Type* → Type _} [Applicative G] [CommApplicative G] {α β γ : Type _}
(g : α → G β) (h : β → γ) (x : Multiset α) :
@@ -107,7 +106,8 @@ theorem map_traverse {G : Type* → Type _} [Applicative G] [CommApplicative G]
refine Quotient.inductionOn x ?_
intro
simp only [traverse, quot_mk_to_coe, lift_coe, Function.comp_apply, Functor.map_map, map_comp_coe]
- rw [LawfulFunctor.comp_map, Traversable.map_traverse']
+ rw [Traversable.map_traverse']
+ simp only [fmap_def, Function.comp_apply, Functor.map_map, List.map_eq_map]
rfl
theorem traverse_map {G : Type* → Type _} [Applicative G] [CommApplicative G] {α β γ : Type _}
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 545d09d151580..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,42 +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 (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 c3165b2271890..be8f76fd33712 100644
--- a/Mathlib/Data/NNReal/Basic.lean
+++ b/Mathlib/Data/NNReal/Basic.lean
@@ -3,265 +3,39 @@ 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.BigOperators.Expect
import Mathlib.Algebra.Order.BigOperators.Ring.Finset
import Mathlib.Algebra.Order.Field.Canonical.Basic
-import Mathlib.Algebra.Order.Nonneg.Field
import Mathlib.Algebra.Order.Nonneg.Floor
import Mathlib.Data.Real.Pointwise
+import Mathlib.Data.NNReal.Defs
import Mathlib.Order.ConditionallyCompleteLattice.Group
-import Mathlib.Tactic.Bound.Attribute
-import Mathlib.Tactic.GCongr.Core
-import Mathlib.Algebra.Ring.Regular
/-!
-# 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
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
+open scoped BigOperators
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
@@ -278,250 +52,35 @@ theorem coe_multiset_sum (s : Multiset ℝ≥0) : ((s.sum : ℝ≥0) : ℝ) = (s
theorem coe_multiset_prod (s : Multiset ℝ≥0) : ((s.prod : ℝ≥0) : ℝ) = (s.map (↑)).prod :=
map_multiset_prod toRealHom s
+variable {ι : Type*} {s : Finset ι} {f : ι → ℝ}
+
@[simp, norm_cast]
-theorem coe_sum {α} {s : Finset α} {f : α → ℝ≥0} : ↑(∑ a ∈ s, f a) = ∑ a ∈ s, (f a : ℝ) :=
+theorem coe_sum (s : Finset ι) (f : ι → ℝ≥0) : ∑ i ∈ s, f i = ∑ i ∈ s, (f i : ℝ) :=
map_sum toRealHom _ _
-theorem _root_.Real.toNNReal_sum_of_nonneg {α} {s : Finset α} {f : α → ℝ}
- (hf : ∀ a, a ∈ s → 0 ≤ f a) :
+@[simp, norm_cast]
+lemma coe_expect (s : Finset ι) (f : ι → ℝ≥0) : 𝔼 i ∈ s, f i = 𝔼 i ∈ s, (f i : ℝ) :=
+ map_expect toRealHom ..
+
+theorem _root_.Real.toNNReal_sum_of_nonneg (hf : ∀ i ∈ s, 0 ≤ f i) :
Real.toNNReal (∑ a ∈ s, f a) = ∑ a ∈ s, Real.toNNReal (f a) := by
rw [← coe_inj, NNReal.coe_sum, Real.coe_toNNReal _ (Finset.sum_nonneg hf)]
exact Finset.sum_congr rfl fun x hxs => by rw [Real.coe_toNNReal _ (hf x hxs)]
@[simp, norm_cast]
-theorem coe_prod {α} {s : Finset α} {f : α → ℝ≥0} : ↑(∏ a ∈ s, f a) = ∏ a ∈ s, (f a : ℝ) :=
+theorem coe_prod (s : Finset ι) (f : ι → ℝ≥0) : ↑(∏ a ∈ s, f a) = ∏ a ∈ s, (f a : ℝ) :=
map_prod toRealHom _ _
-theorem _root_.Real.toNNReal_prod_of_nonneg {α} {s : Finset α} {f : α → ℝ}
- (hf : ∀ a, a ∈ s → 0 ≤ f a) :
+theorem _root_.Real.toNNReal_prod_of_nonneg (hf : ∀ a, a ∈ s → 0 ≤ f a) :
Real.toNNReal (∏ a ∈ s, f a) = ∏ a ∈ s, Real.toNNReal (f a) := by
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)
@@ -533,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
/-!
@@ -785,167 +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₀ <| pos_iff_ne_zero.2 hr
-
-nonrec theorem le_div_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a ≤ b / r ↔ r * a ≤ b :=
- le_div_iff₀' <| pos_iff_ne_zero.2 hr
-
-theorem div_lt_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a / r < b ↔ a < b * r :=
- lt_iff_lt_of_le_iff_le (le_div_iff₀ (pos_iff_ne_zero.2 hr))
-
-theorem div_lt_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a / r < b ↔ a < r * b :=
- lt_iff_lt_of_le_iff_le (le_div_iff₀' (pos_iff_ne_zero.2 hr))
-
-theorem lt_div_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a < b / r ↔ a * r < b :=
- lt_iff_lt_of_le_iff_le (div_le_iff₀ (pos_iff_ne_zero.2 hr))
-
-theorem lt_div_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a < b / r ↔ r * a < b :=
- lt_iff_lt_of_le_iff_le (div_le_iff₀' (pos_iff_ne_zero.2 hr))
-
-theorem mul_lt_of_lt_div {a b r : ℝ≥0} (h : a < b / r) : a * r < b :=
- (lt_div_iff 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, one_mul]
- exact ne_of_gt (lt_of_le_of_lt (zero_le _) h)
-
-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, 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.ciInf_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 _) _
@@ -996,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 8e257d61ead92..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
@@ -35,17 +35,17 @@ elements of `s` in increasing order. -/
def bitIndices (n : ℕ) : List ℕ :=
@binaryRec (fun _ ↦ List ℕ) [] (fun b _ s ↦ b.casesOn (s.map (· + 1)) (0 :: s.map (· + 1))) n
-@[simp] theorem bitIndices_zero : bitIndices 0 = [] := by rfl
+@[simp] theorem bitIndices_zero : bitIndices 0 = [] := by simp [bitIndices]
-@[simp] theorem bitIndices_one : bitIndices 1 = [0] := by rfl
+@[simp] theorem bitIndices_one : bitIndices 1 = [0] := by simp [bitIndices]
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 3fff69bc6dc3f..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
@@ -25,7 +26,7 @@ and `Nat.digits`.
-- Once we're in the `Nat` namespace, `xor` will inconveniently resolve to `Nat.xor`.
/-- `bxor` denotes the `xor` function i.e. the exclusive-or function on type `Bool`. -/
-local notation "bxor" => _root_.xor
+local notation "bxor" => xor
namespace Nat
universe u
@@ -48,7 +49,7 @@ def bodd (n : ℕ) : Bool := (boddDiv2 n).1
@[simp] lemma bodd_zero : bodd 0 = false := rfl
-lemma bodd_one : bodd 1 = true := rfl
+@[simp] lemma bodd_one : bodd 1 = true := rfl
lemma bodd_two : bodd 2 = false := rfl
@@ -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]
@@ -88,18 +89,18 @@ lemma mod_two_of_bodd (n : ℕ) : n % 2 = cond (bodd n) 1 0 := by
@[simp] lemma div2_zero : div2 0 = 0 := rfl
-lemma div2_one : div2 1 = 0 := rfl
+@[simp] lemma div2_one : div2 1 = 0 := rfl
lemma div2_two : div2 2 = 1 := rfl
@[simp]
-lemma div2_succ (n : ℕ) : div2 (succ n) = cond (bodd n) (succ (div2 n)) (div2 n) := by
+lemma div2_succ (n : ℕ) : div2 (n + 1) = cond (bodd n) (succ (div2 n)) (div2 n) := by
simp only [bodd, boddDiv2, div2]
rcases boddDiv2 n with ⟨_|_, _⟩ <;> simp
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,12 +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
-
/-! bitwise ops -/
lemma bodd_bit (b n) : bodd (bit b n) = b := by
@@ -213,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]
@@ -222,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
@@ -242,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` -/
@@ -289,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 <| (eq_rec_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
@@ -328,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_iff, 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]
@@ -391,6 +278,7 @@ theorem bit1_bits (n : ℕ) : (2 * n + 1).bits = true :: n.bits :=
@[simp]
theorem one_bits : Nat.bits 1 = [true] := by
convert bit1_bits 0
+ simp
-- TODO Find somewhere this can live.
-- example : bits 3423 = [true, true, true, true, true, false, true, false, true, false, true, true]
diff --git a/Mathlib/Data/Nat/Bitwise.lean b/Mathlib/Data/Nat/Bitwise.lean
index 2a2306e5f1f71..70965de4413df 100644
--- a/Mathlib/Data/Nat/Bitwise.lean
+++ b/Mathlib/Data/Nat/Bitwise.lean
@@ -3,9 +3,11 @@ 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
@@ -35,7 +37,6 @@ should be connected.
bitwise, and, or, xor
-/
-
open Function
namespace Nat
@@ -68,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) :
@@ -85,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) :=
@@ -143,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`
@@ -272,9 +263,6 @@ theorem lor_comm (n m : ℕ) : n ||| m = m ||| n :=
theorem land_comm (n m : ℕ) : n &&& m = m &&& n :=
bitwise_comm Bool.and_comm n m
-protected lemma xor_comm (n m : ℕ) : n ^^^ m = m ^^^ n :=
- bitwise_comm (Bool.bne_eq_xor ▸ Bool.xor_comm) n m
-
lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
refine eq_of_testBit_eq fun j => ?_
obtain rfl | hij := Decidable.eq_or_ne i j <;> cases' h : n.testBit i
@@ -286,13 +274,6 @@ lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
lemma two_pow_and (n i : ℕ) : 2 ^ i &&& n = 2 ^ i * (n.testBit i).toNat := by
rw [mul_comm, land_comm, and_two_pow]
-@[simp]
-theorem zero_xor (n : ℕ) : 0 ^^^ n = n := by simp [HXor.hXor, Xor.xor, xor]
-
-@[simp]
-theorem xor_zero (n : ℕ) : n ^^^ 0 = n := by simp [HXor.hXor, Xor.xor, xor]
-
-
/-- Proving associativity of bitwise operations in general essentially boils down to a huge case
distinction, so it is shorter to use this tactic instead of proving it in the general case. -/
macro "bitwise_assoc_tac" : tactic => set_option hygiene false in `(tactic| (
@@ -305,22 +286,16 @@ macro "bitwise_assoc_tac" : tactic => set_option hygiene false in `(tactic| (
-- This is necessary because these are simp lemmas in mathlib
<;> simp [hn, Bool.or_assoc, Bool.and_assoc, Bool.bne_eq_xor]))
-protected lemma xor_assoc (n m k : ℕ) : (n ^^^ m) ^^^ k = n ^^^ (m ^^^ k) := by bitwise_assoc_tac
-
theorem land_assoc (n m k : ℕ) : (n &&& m) &&& k = n &&& (m &&& k) := by bitwise_assoc_tac
theorem lor_assoc (n m k : ℕ) : (n ||| m) ||| k = n ||| (m ||| k) := by bitwise_assoc_tac
-@[simp]
-theorem xor_self (n : ℕ) : n ^^^ n = 0 :=
- zero_of_testBit_eq_false fun i => by simp
-
-- These lemmas match `mul_inv_cancel_right` and `mul_inv_cancel_left`.
theorem xor_cancel_right (n m : ℕ) : (m ^^^ n) ^^^ n = m := by
- rw [Nat.xor_assoc, xor_self, xor_zero]
+ rw [Nat.xor_assoc, Nat.xor_self, xor_zero]
theorem xor_cancel_left (n m : ℕ) : n ^^^ (n ^^^ m) = m := by
- rw [← Nat.xor_assoc, xor_self, zero_xor]
+ rw [← Nat.xor_assoc, Nat.xor_self, zero_xor]
theorem xor_right_injective {n : ℕ} : Function.Injective (HXor.hXor n : ℕ → ℕ) := fun m m' h => by
rw [← xor_cancel_left n m, ← xor_cancel_left n m', h]
@@ -339,45 +314,59 @@ theorem xor_left_inj {n m m' : ℕ} : m ^^^ n = m' ^^^ n ↔ m = m' :=
@[simp]
theorem xor_eq_zero {n m : ℕ} : n ^^^ m = 0 ↔ n = m := by
- rw [← xor_self n, xor_right_inj, eq_comm]
+ rw [← Nat.xor_self n, xor_right_inj, eq_comm]
theorem xor_ne_zero {n m : ℕ} : n ^^^ m ≠ 0 ↔ n ≠ m :=
xor_eq_zero.not
-theorem xor_trichotomy {a b c : ℕ} (h : a ≠ b ^^^ c) :
- b ^^^ c < a ∨ a ^^^ c < b ∨ a ^^^ b < c := by
- set v := a ^^^ (b ^^^ c) with hv
+theorem xor_trichotomy {a b c : ℕ} (h : a ^^^ b ^^^ c ≠ 0) :
+ b ^^^ c < a ∨ c ^^^ a < b ∨ a ^^^ b < c := by
+ set v := a ^^^ b ^^^ c with hv
-- The xor of any two of `a`, `b`, `c` is the xor of `v` and the third.
have hab : a ^^^ b = c ^^^ v := by
- rw [hv]
- conv_rhs =>
- rw [Nat.xor_comm]
- simp [Nat.xor_assoc]
- have hac : a ^^^ c = b ^^^ v := by
- rw [hv]
- conv_rhs =>
- right
- rw [← Nat.xor_comm]
- rw [← Nat.xor_assoc, ← Nat.xor_assoc, xor_self, zero_xor, Nat.xor_comm]
- have hbc : b ^^^ c = a ^^^ v := by simp [hv, ← Nat.xor_assoc]
+ rw [Nat.xor_comm c, xor_cancel_right]
+ have hbc : b ^^^ c = a ^^^ v := by
+ rw [← Nat.xor_assoc, xor_cancel_left]
+ have hca : c ^^^ a = b ^^^ v := by
+ rw [hv, Nat.xor_assoc, Nat.xor_comm a, ← Nat.xor_assoc, xor_cancel_left]
-- If `i` is the position of the most significant bit of `v`, then at least one of `a`, `b`, `c`
-- has a one bit at position `i`.
- obtain ⟨i, ⟨hi, hi'⟩⟩ := exists_most_significant_bit (xor_ne_zero.2 h)
- have : testBit a i = true ∨ testBit b i = true ∨ testBit c i = true := by
+ obtain ⟨i, ⟨hi, hi'⟩⟩ := exists_most_significant_bit h
+ have : testBit a i ∨ testBit b i ∨ testBit c i := by
contrapose! hi
- simp only [Bool.eq_false_eq_not_eq_true, Ne, testBit_xor, Bool.bne_eq_xor] at hi ⊢
- rw [hi.1, hi.2.1, hi.2.2, Bool.xor_false, Bool.xor_false]
+ simp_rw [Bool.eq_false_eq_not_eq_true] at hi ⊢
+ rw [testBit_xor, testBit_xor, hi.1, hi.2.1, hi.2.2]
+ rfl
-- If, say, `a` has a one bit at position `i`, then `a xor v` has a zero bit at position `i`, but
-- the same bits as `a` in positions greater than `j`, so `a xor v < a`.
- rcases this with (h | h | h)
+ obtain h | h | h := this
on_goal 1 => left; rw [hbc]
- on_goal 2 => right; left; rw [hac]
+ on_goal 2 => right; left; rw [hca]
on_goal 3 => right; right; rw [hab]
all_goals
- exact lt_of_testBit i (by simp [h, hi]) h fun j hj => by simp [hi' _ hj]
+ refine lt_of_testBit i ?_ h fun j hj => ?_
+ · rw [testBit_xor, h, hi]
+ rfl
+ · simp only [testBit_xor, hi' _ hj, Bool.bne_false]
+
+theorem lt_xor_cases {a b c : ℕ} (h : a < b ^^^ c) : a ^^^ c < b ∨ a ^^^ b < c := by
+ 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]
-theorem lt_xor_cases {a b c : ℕ} (h : a < b ^^^ c) : a ^^^ c < b ∨ a ^^^ b < c :=
- (or_iff_right fun h' => (h.asymm h').elim).1 <| xor_trichotomy h.ne
+@[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/NeZero.lean b/Mathlib/Data/Nat/Cast/NeZero.lean
index d49f78b3b3095..c3f00eb8b8820 100644
--- a/Mathlib/Data/Nat/Cast/NeZero.lean
+++ b/Mathlib/Data/Nat/Cast/NeZero.lean
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Gabriel Ebner
-/
import Mathlib.Data.Nat.Cast.Defs
-import Mathlib.Algebra.NeZero
/-!
# Lemmas about nonzero elements of an `AddMonoidWithOne`
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 af9347cfba776..d50601dc0a59d 100644
--- a/Mathlib/Data/Nat/Choose/Basic.lean
+++ b/Mathlib/Data/Nat/Choose/Basic.lean
@@ -60,9 +60,24 @@ theorem choose_succ_succ (n k : ℕ) : choose (succ n) (succ k) = choose n k + c
theorem choose_succ_succ' (n k : ℕ) : choose (n + 1) (k + 1) = choose n k + choose n (k + 1) :=
rfl
+theorem choose_succ_left (n k : ℕ) (hk : 0 < k) :
+ choose (n + 1) k = choose n (k - 1) + choose n k := by
+ obtain ⟨l, rfl⟩ : ∃ l, k = l + 1 := Nat.exists_eq_add_of_le' hk
+ rfl
+
+theorem choose_succ_right (n k : ℕ) (hn : 0 < n) :
+ choose n (k + 1) = choose (n - 1) k + choose (n - 1) (k + 1) := by
+ obtain ⟨l, rfl⟩ : ∃ l, n = l + 1 := Nat.exists_eq_add_of_le' hn
+ rfl
+
+theorem choose_eq_choose_pred_add {n k : ℕ} (hn : 0 < n) (hk : 0 < k) :
+ choose n k = choose (n - 1) (k - 1) + choose (n - 1) k := by
+ obtain ⟨l, rfl⟩ : ∃ l, k = l + 1 := Nat.exists_eq_add_of_le' hk
+ rw [choose_succ_right _ _ hn, Nat.add_one_sub_one]
+
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
@@ -94,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⟩
@@ -362,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 71966a049eb3a..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)
@@ -78,7 +81,7 @@ theorem factorization_choose_of_lt_three_mul (hp' : p ≠ 2) (hk : p ≤ k) (hk'
n < 3 * p := hn
_ ≤ p * p := mul_le_mul_right' this p
_ = p ^ 2 := (sq p).symm
- _ ≤ p ^ i := pow_le_pow_right hp.one_lt.le hi
+ _ ≤ p ^ i := pow_right_mono₀ hp.one_lt.le hi
rwa [mod_eq_of_lt (lt_of_le_of_lt hkn hn), mod_eq_of_lt (lt_of_le_of_lt tsub_le_self hn),
add_tsub_cancel_of_le hkn]
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 d9bafecbbe840..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
@@ -74,6 +73,17 @@ theorem add_pow [CommSemiring R] (x y : R) (n : ℕ) :
(x + y) ^ n = ∑ m ∈ range (n + 1), x ^ m * y ^ (n - m) * n.choose m :=
(Commute.all x y).add_pow n
+/-- A special case of the **binomial theorem** -/
+theorem sub_pow [CommRing R] (x y : R) (n : ℕ) :
+ (x - y) ^ n = ∑ m ∈ range (n + 1), (-1) ^ (m + n) * x ^ m * y ^ (n - m) * n.choose m := by
+ rw [sub_eq_add_neg, add_pow]
+ congr! 1 with m hm
+ have : (-1 : R) ^ (n - m) = (-1) ^ (n + m) := by
+ rw [mem_range] at hm
+ simp [show n + m = n - m + 2 * m by omega, pow_add]
+ rw [neg_pow, this]
+ ring
+
namespace Nat
/-- The sum of entries in a row of Pascal's triangle -/
@@ -113,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`. -/
@@ -158,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]
@@ -171,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 c3e60e57f4397..4d8294ce6bceb 100644
--- a/Mathlib/Data/Nat/Count.lean
+++ b/Mathlib/Data/Nat/Count.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2021 Vladimir Goryachev. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Yaël Dillies, Vladimir Goryachev, Kyle Miller, Scott Morrison, Eric Rodriguez
+Authors: Yaël Dillies, Vladimir Goryachev, Kyle Miller, Kim Morrison, Eric Rodriguez
-/
import Mathlib.SetTheory.Cardinal.Basic
@@ -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 dd38886b716c7..2d0223819be8a 100644
--- a/Mathlib/Data/Nat/Defs.lean
+++ b/Mathlib/Data/Nat/Defs.lean
@@ -5,7 +5,7 @@ Authors: Floris van Doorn, Leonardo de Moura, Jeremy Avigad, Mario Carneiro
-/
import Mathlib.Logic.Function.Basic
import Mathlib.Logic.Nontrivial.Defs
-import Mathlib.Tactic.GCongr.Core
+import Mathlib.Tactic.GCongr.CoreAttrs
import Mathlib.Tactic.PushNeg
import Mathlib.Util.AssertExists
@@ -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
@@ -137,10 +137,20 @@ lemma one_lt_iff_ne_zero_and_ne_one : ∀ {n : ℕ}, 1 < n ↔ n ≠ 0 ∧ n ≠
lemma le_one_iff_eq_zero_or_eq_one : ∀ {n : ℕ}, n ≤ 1 ↔ n = 0 ∨ n = 1 := by simp [le_succ_iff]
-@[simp] lemma lt_one_iff : n < 1 ↔ n = 0 := Nat.lt_succ_iff.trans <| by rw [le_zero_eq]
-
lemma one_le_of_lt (h : a < b) : 1 ≤ b := Nat.lt_of_le_of_lt (Nat.zero_le _) h
+protected lemma min_left_comm (a b c : ℕ) : min a (min b c) = min b (min a c) := by
+ rw [← Nat.min_assoc, ← Nat.min_assoc, b.min_comm]
+
+protected lemma max_left_comm (a b c : ℕ) : max a (max b c) = max b (max a c) := by
+ rw [← Nat.max_assoc, ← Nat.max_assoc, b.max_comm]
+
+protected lemma min_right_comm (a b c : ℕ) : min (min a b) c = min (min a c) b := by
+ rw [Nat.min_assoc, Nat.min_assoc, b.min_comm]
+
+protected lemma max_right_comm (a b c : ℕ) : max (max a b) c = max (max a c) b := by
+ rw [Nat.max_assoc, Nat.max_assoc, b.max_comm]
+
@[simp] lemma min_eq_zero_iff : min m n = 0 ↔ m = 0 ∨ n = 0 := by omega
@[simp] lemma max_eq_zero_iff : max m n = 0 ↔ m = 0 ∧ n = 0 := by omega
@@ -208,8 +218,7 @@ attribute [simp] le_add_left le_add_right Nat.lt_add_left_iff_pos Nat.lt_add_rig
-- Sometimes a bare `Nat.add` or similar appears as a consequence of unfolding during pattern
-- matching. These lemmas package them back up as typeclass mediated operations.
--- TODO: This is a duplicate of `Nat.add_eq`
-@[simp] lemma add_def : Nat.add m n = m + n := rfl
+@[deprecated (since := "2024-04-05")] alias add_def := add_eq
-- We want to use these two lemmas earlier than the lemmas simp can prove them with
@[simp, nolint simpNF] protected lemma add_eq_left : a + b = a ↔ b = 0 := by omega
@@ -298,11 +307,11 @@ lemma two_mul_ne_two_mul_add_one : 2 * n ≠ 2 * m + 1 :=
-- TODO: Replace `Nat.mul_right_cancel_iff` with `Nat.mul_left_inj`
protected lemma mul_left_inj (ha : a ≠ 0) : b * a = c * a ↔ b = c :=
- Nat.mul_right_cancel_iff (Nat.pos_iff_ne_zero.2 ha) _ _
+ Nat.mul_right_cancel_iff (Nat.pos_iff_ne_zero.2 ha)
-- TODO: Replace `Nat.mul_left_cancel_iff` with `Nat.mul_right_inj`
protected lemma mul_right_inj (ha : a ≠ 0) : a * b = a * c ↔ b = c :=
- Nat.mul_left_cancel_iff (Nat.pos_iff_ne_zero.2 ha) _ _
+ Nat.mul_left_cancel_iff (Nat.pos_iff_ne_zero.2 ha)
protected lemma mul_ne_mul_left (ha : a ≠ 0) : b * a ≠ c * a ↔ b ≠ c :=
not_congr (Nat.mul_left_inj ha)
@@ -586,9 +595,6 @@ protected lemma pow_le_pow_iff_left {n : ℕ} (hn : n ≠ 0) : a ^ n ≤ b ^ n
protected lemma pow_lt_pow_iff_left (hn : n ≠ 0) : a ^ n < b ^ n ↔ a < b := by
simp only [← Nat.not_le, Nat.pow_le_pow_iff_left hn]
-@[deprecated (since := "2023-12-23")] alias pow_lt_pow_of_lt_left := Nat.pow_lt_pow_left
-@[deprecated (since := "2023-12-23")] alias pow_le_iff_le_left := Nat.pow_le_pow_iff_left
-
lemma pow_left_injective (hn : n ≠ 0) : Injective (fun a : ℕ ↦ a ^ n) := by
simp [Injective, le_antisymm_iff, Nat.pow_le_pow_iff_left hn]
@@ -734,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']
@@ -822,7 +828,7 @@ This is an alias of `Nat.leRec`, specialized to `Prop`. -/
@[elab_as_elim]
lemma le_induction {m : ℕ} {P : ∀ n, m ≤ n → Prop} (base : P m m.le_refl)
(succ : ∀ n hmn, P n hmn → P (n + 1) (le_succ_of_le hmn)) : ∀ n hmn, P n hmn :=
- @Nat.leRec (motive := P) base succ
+ @Nat.leRec (motive := P) _ base succ
/-- Induction principle deriving the next case from the two previous ones. -/
def twoStepInduction {P : ℕ → Sort*} (zero : P 0) (one : P 1)
@@ -864,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]
@@ -875,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 =>
@@ -908,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*`.
@@ -928,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
@@ -1006,9 +1012,6 @@ lemma div_ne_zero_iff_of_dvd (hba : b ∣ a) : a / b ≠ 0 ↔ a ≠ 0 ∧ b ≠
@[simp] lemma mul_mod_mod (a b c : ℕ) : (a * (b % c)) % c = a * b % c := by
rw [mul_mod, mod_mod, ← mul_mod]
-@[simp] lemma mod_mul_mod (a b c : ℕ) : (a % c * b) % c = a * b % c := by
- rw [mul_mod, mod_mod, ← mul_mod]
-
lemma pow_mod (a b n : ℕ) : a ^ b % n = (a % n) ^ b % n := by
induction b with
| zero => rfl
@@ -1297,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 cd2a1c41ebd01..2af99d2651db3 100644
--- a/Mathlib/Data/Nat/Digits.lean
+++ b/Mathlib/Data/Nat/Digits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Shing Tak Lam, Mario Carneiro
+Authors: Kim Morrison, Shing Tak Lam, Mario Carneiro
-/
import Mathlib.Algebra.BigOperators.Intervals
import Mathlib.Algebra.BigOperators.Ring.List
@@ -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
@@ -570,7 +569,7 @@ theorem sub_one_mul_sum_log_div_pow_eq_sub_sum_digits {p : ℕ} (n : ℕ) :
theorem digits_two_eq_bits (n : ℕ) : digits 2 n = n.bits.map fun b => cond b 1 0 := by
induction' n using Nat.binaryRecFromOne with b n h ih
· simp
- · rfl
+ · simp
rw [bits_append_bit _ _ fun hn => absurd hn h]
cases b
· rw [digits_def' one_lt_two]
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/Basic.lean b/Mathlib/Data/Nat/Factorial/Basic.lean
index cacc9997b8c7e..79539c43a7625 100644
--- a/Mathlib/Data/Nat/Factorial/Basic.lean
+++ b/Mathlib/Data/Nat/Factorial/Basic.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Chris Hughes, Floris van Doorn, Yaël Dillies
-/
import Mathlib.Data.Nat.Defs
-import Mathlib.Tactic.GCongr.Core
+import Mathlib.Tactic.GCongr.CoreAttrs
import Mathlib.Tactic.Common
import Mathlib.Tactic.Monotonicity.Attr
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 6e116bcf98273..f39676359793d 100644
--- a/Mathlib/Data/Nat/Factorization/Basic.lean
+++ b/Mathlib/Data/Nat/Factorization/Basic.lean
@@ -13,7 +13,7 @@ import Mathlib.Tactic.IntervalCases
# Basic lemmas on prime factorizations
-/
-open Nat Finset List Finsupp
+open Finset List Finsupp
namespace Nat
variable {a b m n p : ℕ}
@@ -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
@@ -309,7 +308,7 @@ theorem dvd_iff_prime_pow_dvd_dvd (n d : ℕ) :
rcases eq_or_ne n 0 with (rfl | hn)
· simp
rcases eq_or_ne d 0 with (rfl | hd)
- · simp only [zero_dvd_iff, hn, false_iff_iff, not_forall]
+ · simp only [zero_dvd_iff, hn, false_iff, not_forall]
exact ⟨2, n, prime_two, dvd_zero _, mt (le_of_dvd hn.bot_lt) (lt_two_pow n).not_le⟩
refine ⟨fun h p k _ hpkd => dvd_trans hpkd h, ?_⟩
rw [← factorization_prime_le_iff_dvd hd hn]
@@ -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 fbabc1edc00fd..a274e6adeb506 100644
--- a/Mathlib/Data/Nat/Factorization/Defs.lean
+++ b/Mathlib/Data/Nat/Factorization/Defs.lean
@@ -86,7 +86,7 @@ alias factorization_eq_factors_multiset := factorization_eq_primeFactorsList_mul
theorem Prime.factorization_pos_of_dvd {n p : ℕ} (hp : p.Prime) (hn : n ≠ 0) (h : p ∣ n) :
0 < n.factorization p := by
- rwa [← primeFactorsList_count_eq, count_pos_iff_mem, mem_primeFactorsList_iff_dvd hn hp]
+ rwa [← primeFactorsList_count_eq, count_pos_iff, mem_primeFactorsList_iff_dvd hn hp]
theorem multiplicity_eq_factorization {n p : ℕ} (pp : p.Prime) (hn : n ≠ 0) :
multiplicity p n = n.factorization p := by
@@ -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
@@ -172,7 +172,7 @@ theorem factorization_prod {α : Type*} {S : Finset α} {g : α → ℕ} (hS :
· simp
· intro x T hxS hTS hxT IH
have hT : T.prod g ≠ 0 := prod_ne_zero_iff.mpr fun x hx => hS x (hTS hx)
- simp [prod_insert hxT, sum_insert hxT, ← IH, factorization_mul (hS x hxS) hT]
+ simp [prod_insert hxT, sum_insert hxT, IH, factorization_mul (hS x hxS) hT]
/-- For any `p`, the power of `p` in `n^k` is `k` times the power in `n` -/
@[simp]
diff --git a/Mathlib/Data/Nat/Factorization/PrimePow.lean b/Mathlib/Data/Nat/Factorization/PrimePow.lean
index 5f35804b888b8..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
@@ -137,6 +138,6 @@ theorem Nat.mul_divisors_filter_prime_pow {a b : ℕ} (hab : a.Coprime b) :
· simp only [Nat.coprime_zero_right] at hab
simp [hab, Finset.filter_singleton, not_isPrimePow_one]
ext n
- simp only [ha, hb, Finset.mem_union, Finset.mem_filter, Nat.mul_eq_zero, and_true_iff, Ne,
+ simp only [ha, hb, Finset.mem_union, Finset.mem_filter, Nat.mul_eq_zero, and_true, Ne,
and_congr_left_iff, not_false_iff, Nat.mem_divisors, or_self_iff]
apply hab.isPrimePow_dvd_mul
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 dadaa5b902c92..cd3c50fdd53c6 100644
--- a/Mathlib/Data/Nat/Lattice.lean
+++ b/Mathlib/Data/Nat/Lattice.lean
@@ -45,9 +45,9 @@ theorem _root_.Set.Infinite.Nat.sSup_eq_zero {s : Set ℕ} (h : s.Infinite) : sS
theorem sInf_eq_zero {s : Set ℕ} : sInf s = 0 ↔ 0 ∈ s ∨ s = ∅ := by
cases eq_empty_or_nonempty s with
| inl h => subst h
- simp only [or_true_iff, eq_self_iff_true, iff_true_iff, iInf, InfSet.sInf,
+ simp only [or_true, eq_self_iff_true, iInf, InfSet.sInf,
mem_empty_iff_false, exists_false, dif_neg, not_false_iff]
- | inr h => simp only [h.ne_empty, or_false_iff, Nat.sInf_def, h, Nat.find_eq_zero]
+ | inr h => simp only [h.ne_empty, or_false, Nat.sInf_def, h, Nat.find_eq_zero]
@[simp]
theorem sInf_empty : sInf ∅ = 0 := by
@@ -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 eb2ae3bc58f52..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 -/
@@ -124,8 +132,8 @@ theorem lt_pow_succ_log_self {b : ℕ} (hb : 1 < b) (x : ℕ) : x < b ^ (log b x
theorem log_eq_iff {b m n : ℕ} (h : m ≠ 0 ∨ 1 < b ∧ n ≠ 0) :
log b n = m ↔ b ^ m ≤ n ∧ n < b ^ (m + 1) := by
rcases em (1 < b ∧ n ≠ 0) with (⟨hb, hn⟩ | hbn)
- · rw [le_antisymm_iff, ← Nat.lt_succ_iff, ← pow_le_iff_le_log, ← lt_pow_iff_log_lt, and_comm] <;>
- assumption
+ · rw [le_antisymm_iff, ← Nat.lt_succ_iff, ← pow_le_iff_le_log, ← lt_pow_iff_log_lt,
+ and_comm] <;> assumption
have hm : m ≠ 0 := h.resolve_right hbn
rw [not_and_or, not_lt, Ne, not_not] at hbn
rcases hbn with (hb | rfl)
diff --git a/Mathlib/Data/Nat/ModEq.lean b/Mathlib/Data/Nat/ModEq.lean
index 5877782fc1102..29ff2fed4da9d 100644
--- a/Mathlib/Data/Nat/ModEq.lean
+++ b/Mathlib/Data/Nat/ModEq.lean
@@ -3,10 +3,8 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
-import Mathlib.Algebra.Ring.Regular
+import Mathlib.Algebra.Order.Group.Unbundled.Int
import Mathlib.Data.Int.GCD
-import Mathlib.Data.Int.Order.Lemmas
-import Mathlib.Tactic.NormNum.Basic
/-!
# Congruences modulo a natural number
@@ -24,6 +22,7 @@ and proves basic properties about it such as the Chinese Remainder Theorem
ModEq, congruence, mod, MOD, modulo
-/
+assert_not_exists OrderedAddCommMonoid
assert_not_exists Function.support
namespace Nat
@@ -37,8 +36,8 @@ notation:50 a " ≡ " b " [MOD " n "]" => ModEq n a b
variable {m n a b c d : ℕ}
--- Porting note: This instance should be derivable automatically
-instance : Decidable (ModEq n a b) := decEq (a % n) (b % n)
+-- Since `ModEq` is semi-reducible, we need to provide the decidable instance manually
+instance : Decidable (ModEq n a b) := inferInstanceAs <| Decidable (a % n = b % n)
namespace ModEq
@@ -91,7 +90,7 @@ theorem mod_modEq (a n) : a % n ≡ a [MOD n] :=
namespace ModEq
lemma of_dvd (d : m ∣ n) (h : a ≡ b [MOD n]) : a ≡ b [MOD m] :=
- modEq_of_dvd <| d.natCast.trans h.dvd
+ modEq_of_dvd <| Int.ofNat_dvd.mpr d |>.trans h.dvd
protected theorem mul_left' (c : ℕ) (h : a ≡ b [MOD n]) : c * a ≡ c * b [MOD c * n] := by
unfold ModEq at *; rw [mul_mod_mul_left, mul_mod_mul_left, h]
@@ -122,7 +121,7 @@ protected theorem pow (m : ℕ) (h : a ≡ b [MOD n]) : a ^ m ≡ b ^ m [MOD n]
@[gcongr]
protected theorem add (h₁ : a ≡ b [MOD n]) (h₂ : c ≡ d [MOD n]) : a + c ≡ b + d [MOD n] := by
rw [modEq_iff_dvd, Int.ofNat_add, Int.ofNat_add, add_sub_add_comm]
- exact dvd_add h₁.dvd h₂.dvd
+ exact Int.dvd_add h₁.dvd h₂.dvd
@[gcongr]
protected theorem add_left (c : ℕ) (h : a ≡ b [MOD n]) : c + a ≡ c + b [MOD n] :=
@@ -136,7 +135,7 @@ protected theorem add_left_cancel (h₁ : a ≡ b [MOD n]) (h₂ : a + c ≡ b +
c ≡ d [MOD n] := by
simp only [modEq_iff_dvd, Int.ofNat_add] at *
rw [add_sub_add_comm] at h₂
- convert _root_.dvd_sub h₂ h₁ using 1
+ convert Int.dvd_sub h₂ h₁ using 1
rw [add_sub_cancel_left]
protected theorem add_left_cancel' (c : ℕ) (h : c + a ≡ c + b [MOD n]) : a ≡ b [MOD n] :=
@@ -155,7 +154,8 @@ protected theorem add_right_cancel' (c : ℕ) (h : a + c ≡ b + c [MOD n]) : a
For cancelling left multiplication in the modulus, see `Nat.ModEq.of_mul_left`. -/
protected theorem mul_left_cancel' {a b c m : ℕ} (hc : c ≠ 0) :
c * a ≡ c * b [MOD c * m] → a ≡ b [MOD m] := by
- simp [modEq_iff_dvd, ← mul_sub, mul_dvd_mul_iff_left (by simp [hc] : (c : ℤ) ≠ 0)]
+ simp only [modEq_iff_dvd, Int.natCast_mul, ← Int.mul_sub]
+ exact fun h => (Int.dvd_of_mul_dvd_mul_left (Int.ofNat_ne_zero.mpr hc) h)
protected theorem mul_left_cancel_iff' {a b c m : ℕ} (hc : c ≠ 0) :
c * a ≡ c * b [MOD c * m] ↔ a ≡ b [MOD m] :=
@@ -166,7 +166,8 @@ protected theorem mul_left_cancel_iff' {a b c m : ℕ} (hc : c ≠ 0) :
For cancelling right multiplication in the modulus, see `Nat.ModEq.of_mul_right`. -/
protected theorem mul_right_cancel' {a b c m : ℕ} (hc : c ≠ 0) :
a * c ≡ b * c [MOD m * c] → a ≡ b [MOD m] := by
- simp [modEq_iff_dvd, ← sub_mul, mul_dvd_mul_iff_right (by simp [hc] : (c : ℤ) ≠ 0)]
+ simp only [modEq_iff_dvd, Int.natCast_mul, ← Int.sub_mul]
+ exact fun h => (Int.dvd_of_mul_dvd_mul_right (Int.ofNat_ne_zero.mpr hc) h)
protected theorem mul_right_cancel_iff' {a b c m : ℕ} (hc : c ≠ 0) :
a * c ≡ b * c [MOD m * c] ↔ a ≡ b [MOD m] :=
@@ -204,10 +205,10 @@ namespace ModEq
theorem le_of_lt_add (h1 : a ≡ b [MOD m]) (h2 : a < b + m) : a ≤ b :=
(le_total a b).elim id fun h3 =>
Nat.le_of_sub_eq_zero
- (eq_zero_of_dvd_of_lt ((modEq_iff_dvd' h3).mp h1.symm) ((tsub_lt_iff_left h3).mpr h2))
+ (eq_zero_of_dvd_of_lt ((modEq_iff_dvd' h3).mp h1.symm) (by omega))
theorem add_le_of_lt (h1 : a ≡ b [MOD m]) (h2 : a < b) : a + m ≤ b :=
- le_of_lt_add (add_modEq_right.trans h1) (add_lt_add_right h2 m)
+ le_of_lt_add (add_modEq_right.trans h1) (by omega)
theorem dvd_iff (h : a ≡ b [MOD m]) (hdm : d ∣ m) : d ∣ a ↔ d ∣ b := by
simp only [← modEq_zero_iff_dvd]
@@ -227,9 +228,7 @@ lemma eq_of_abs_lt (h : a ≡ b [MOD m]) (h2 : |(b : ℤ) - a| < m) : a = b := b
exact Int.eq_zero_of_abs_lt_dvd h.dvd h2
lemma eq_of_lt_of_lt (h : a ≡ b [MOD m]) (ha : a < m) (hb : b < m) : a = b :=
- h.eq_of_abs_lt <| abs_sub_lt_iff.2
- ⟨(sub_le_self _ <| Int.natCast_nonneg _).trans_lt <| Int.ofNat_lt.2 hb,
- (sub_le_self _ <| Int.natCast_nonneg _).trans_lt <| Int.ofNat_lt.2 ha⟩
+ h.eq_of_abs_lt <| Int.abs_sub_lt_of_lt_lt ha hb
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c` -/
lemma cancel_left_div_gcd (hm : 0 < m) (h : c * a ≡ c * b [MOD m]) : a ≡ b [MOD m / gcd m c] := by
@@ -241,7 +240,7 @@ lemma cancel_left_div_gcd (hm : 0 < m) (h : c * a ≡ c * b [MOD m]) : a ≡ b
· show (m / d : ℤ) ∣ c / d * (b - a)
rw [mul_comm, ← Int.mul_ediv_assoc (b - a) (Int.natCast_dvd_natCast.mpr hcd), mul_comm]
apply Int.ediv_dvd_ediv (Int.natCast_dvd_natCast.mpr hmd)
- rw [mul_sub]
+ rw [Int.mul_sub]
exact modEq_iff_dvd.mp h
· show Int.gcd (m / d) (c / d) = 1
simp only [← Int.natCast_div, Int.gcd_natCast_natCast (m / d) (c / d), gcd_div hmd hcd,
@@ -299,18 +298,18 @@ def chineseRemainder' (h : a ≡ b [MOD gcd n m]) : { k // k ≡ a [MOD n] ∧ k
have hcoedvd : ∀ t, (gcd n m : ℤ) ∣ t * (b - a) := fun t => h.dvd.mul_left _
have := gcd_eq_gcd_ab n m
constructor <;> rw [Int.emod_def, ← sub_add] <;>
- refine dvd_add ?_ (dvd_mul_of_dvd_left ?_ _) <;>
+ refine Int.dvd_add ?_ (dvd_mul_of_dvd_left ?_ _) <;>
try norm_cast
· rw [← sub_eq_iff_eq_add'] at this
- rw [← this, sub_mul, ← add_sub_assoc, add_comm, add_sub_assoc, ← mul_sub,
+ rw [← this, Int.sub_mul, ← add_sub_assoc, add_comm, add_sub_assoc, ← Int.mul_sub,
Int.add_ediv_of_dvd_left, Int.mul_ediv_cancel_left _ hnonzero,
- Int.mul_ediv_assoc _ h.dvd, ← sub_sub, sub_self, zero_sub, dvd_neg, mul_assoc]
+ Int.mul_ediv_assoc _ h.dvd, ← sub_sub, sub_self, zero_sub, Int.dvd_neg, mul_assoc]
· exact dvd_mul_right _ _
norm_cast
exact dvd_mul_right _ _
· exact dvd_lcm_left n m
· rw [← sub_eq_iff_eq_add] at this
- rw [← this, sub_mul, sub_add, ← mul_sub, Int.sub_ediv_of_dvd,
+ rw [← this, Int.sub_mul, sub_add, ← Int.mul_sub, Int.sub_ediv_of_dvd,
Int.mul_ediv_cancel_left _ hnonzero, Int.mul_ediv_assoc _ h.dvd, ← sub_add, sub_self,
zero_add, mul_assoc]
· exact dvd_mul_right _ _
@@ -407,7 +406,7 @@ protected theorem add_div_of_dvd_right {a b c : ℕ} (hca : c ∣ a) : (a + b) /
add_div_eq_of_add_mod_lt
(by
rw [Nat.mod_eq_zero_of_dvd hca, zero_add]
- exact Nat.mod_lt _ (pos_iff_ne_zero.mpr h))
+ exact Nat.mod_lt _ (zero_lt_of_ne_zero h))
protected theorem add_div_of_dvd_left {a b c : ℕ} (hca : c ∣ b) : (a + b) / c = a / c + b / c := by
rwa [add_comm, Nat.add_div_of_dvd_right, add_comm]
@@ -430,27 +429,24 @@ theorem odd_mul_odd {n m : ℕ} : n % 2 = 1 → m % 2 = 1 → n * m % 2 = 1 := b
theorem odd_mul_odd_div_two {m n : ℕ} (hm1 : m % 2 = 1) (hn1 : n % 2 = 1) :
m * n / 2 = m * (n / 2) + m / 2 :=
- have hm0 : 0 < m := Nat.pos_of_ne_zero fun h => by simp_all
have hn0 : 0 < n := Nat.pos_of_ne_zero fun h => by simp_all
mul_right_injective₀ two_ne_zero <| by
dsimp
rw [mul_add, two_mul_odd_div_two hm1, mul_left_comm, two_mul_odd_div_two hn1,
- two_mul_odd_div_two (Nat.odd_mul_odd hm1 hn1), mul_tsub, mul_one, ←
- add_tsub_assoc_of_le (succ_le_of_lt hm0),
- tsub_add_cancel_of_le (le_mul_of_one_le_right (Nat.zero_le _) hn0)]
+ two_mul_odd_div_two (Nat.odd_mul_odd hm1 hn1), Nat.mul_sub, mul_one, ←
+ Nat.add_sub_assoc (by omega), Nat.sub_add_cancel (Nat.le_mul_of_pos_right m hn0)]
theorem odd_of_mod_four_eq_one {n : ℕ} : n % 4 = 1 → n % 2 = 1 := by
- simpa [ModEq, show 2 * 2 = 4 by norm_num] using @ModEq.of_mul_left 2 n 1 2
+ simpa [ModEq] using @ModEq.of_mul_left 2 n 1 2
theorem odd_of_mod_four_eq_three {n : ℕ} : n % 4 = 3 → n % 2 = 1 := by
- simpa [ModEq, show 2 * 2 = 4 by norm_num, show 3 % 4 = 3 by norm_num] using
- @ModEq.of_mul_left 2 n 3 2
+ simpa [ModEq] using @ModEq.of_mul_left 2 n 3 2
/-- A natural number is odd iff it has residue `1` or `3` mod `4`-/
theorem odd_mod_four_iff {n : ℕ} : n % 2 = 1 ↔ n % 4 = 1 ∨ n % 4 = 3 :=
have help : ∀ m : ℕ, m < 4 → m % 2 = 1 → m = 1 ∨ m = 3 := by decide
⟨fun hn =>
- help (n % 4) (mod_lt n (by norm_num)) <| (mod_mod_of_dvd n (by decide : 2 ∣ 4)).trans hn,
+ help (n % 4) (mod_lt n (by omega)) <| (mod_mod_of_dvd n (by decide : 2 ∣ 4)).trans hn,
fun h => Or.elim h odd_of_mod_four_eq_one odd_of_mod_four_eq_three⟩
lemma mod_eq_of_modEq {a b n} (h : a ≡ b [MOD n]) (hb : b < n) : a % n = b :=
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 e31e9bcb4390d..fb3e78daa3035 100644
--- a/Mathlib/Data/Nat/Nth.lean
+++ b/Mathlib/Data/Nat/Nth.lean
@@ -1,13 +1,14 @@
/-
Copyright (c) 2021 Vladimir Goryachev. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Yaël Dillies, Vladimir Goryachev, Kyle Miller, Scott Morrison, Eric Rodriguez
+Authors: Yaël Dillies, Vladimir Goryachev, Kyle Miller, Kim Morrison, Eric Rodriguez
-/
import Mathlib.Data.List.GetD
import Mathlib.Data.Nat.Count
import Mathlib.Data.Nat.SuccPred
import Mathlib.Order.Interval.Set.Monotone
import Mathlib.Order.OrderIsoNat
+import Mathlib.Order.WellFounded
/-!
# The `n`th Number Satisfying a Predicate
@@ -57,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
@@ -98,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
/-!
@@ -157,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⟩
@@ -173,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
@@ -209,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⟩
@@ -229,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⟩
@@ -237,13 +238,13 @@ theorem nth_eq_zero {n} :
exacts [nth_zero_of_zero h₀, nth_of_card_le hf hle]
theorem nth_eq_zero_mono (h₀ : ¬p 0) {a b : ℕ} (hab : a ≤ b) (ha : nth p a = 0) : nth p b = 0 := by
- simp only [nth_eq_zero, h₀, false_and_iff, false_or_iff] at ha ⊢
+ simp only [nth_eq_zero, h₀, false_and, false_or] at ha ⊢
exact ha.imp fun hf hle => hle.trans hab
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
@@ -261,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⟩
@@ -269,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
@@ -279,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 _
@@ -295,19 +296,23 @@ 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
theorem count_nth_of_infinite (hp : (setOf p).Infinite) (n : ℕ) : count p (nth p n) = n :=
count_nth fun hf => absurd hf hp
-theorem count_nth_succ {n : ℕ} (hn : ∀ hf : (setOf p).Finite, n < hf.toFinset.card) :
+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) :
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
@@ -318,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 1111f4009e1b7..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' (true_and_iff _) fun _ _ => zero_add _
- add_zero x := Part.ext' (and_true_iff _) 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 :=
@@ -98,7 +98,7 @@ instance : AddCommMonoidWithOne PartENat :=
one := 1
natCast := some
natCast_zero := rfl
- natCast_succ := fun _ => Part.ext' (true_and_iff _).symm fun _ _ => rfl }
+ natCast_succ := fun _ => Part.ext' (iff_of_eq (true_and _)).symm fun _ _ => rfl }
theorem some_eq_natCast (n : ℕ) : some n = n :=
rfl
@@ -157,7 +157,7 @@ protected theorem casesOn {P : PartENat → Prop} : ∀ a : PartENat, P ⊤ →
-- not a simp lemma as we will provide a `LinearOrderedAddCommMonoidWithTop` instance later
theorem top_add (x : PartENat) : ⊤ + x = ⊤ :=
- Part.ext' (false_and_iff _) fun h => h.left.elim
+ Part.ext' (iff_of_eq (false_and _)) fun h => h.left.elim
-- not a simp lemma as we will provide a `LinearOrderedAddCommMonoidWithTop` instance later
theorem add_top (x : PartENat) : x + ⊤ = ⊤ := by rw [add_comm, top_add]
@@ -379,7 +379,7 @@ theorem eq_top_iff_forall_le (x : PartENat) : x = ⊤ ↔ ∀ n : ℕ, (n : Part
theorem pos_iff_one_le {x : PartENat} : 0 < x ↔ 1 ≤ x :=
PartENat.casesOn x
- (by simp only [iff_true_iff, le_top, natCast_lt_top, ← @Nat.cast_zero PartENat])
+ (by simp only [le_top, natCast_lt_top, ← @Nat.cast_zero PartENat])
fun n => by
rw [← Nat.cast_zero, ← Nat.cast_one, PartENat.coe_lt_coe, PartENat.coe_le_coe]
rfl
@@ -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/Periodic.lean b/Mathlib/Data/Nat/Periodic.lean
index 5836ce4f952c9..1e2e335bec976 100644
--- a/Mathlib/Data/Nat/Periodic.lean
+++ b/Mathlib/Data/Nat/Periodic.lean
@@ -24,7 +24,7 @@ theorem periodic_gcd (a : ℕ) : Periodic (gcd a) a := by
simp only [forall_const, gcd_add_self_right, eq_self_iff_true, Periodic]
theorem periodic_coprime (a : ℕ) : Periodic (Coprime a) a := by
- simp only [coprime_add_self_right, forall_const, iff_self_iff, eq_iff_iff, Periodic]
+ simp only [coprime_add_self_right, forall_const, eq_iff_iff, Periodic]
theorem periodic_mod (a : ℕ) : Periodic (fun n => n % a) a := by
simp only [forall_const, eq_self_iff_true, add_mod_right, Periodic]
diff --git a/Mathlib/Data/Nat/Prime/Basic.lean b/Mathlib/Data/Nat/Prime/Basic.lean
index e75aca751b05e..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
@@ -156,19 +153,7 @@ theorem Prime.eq_one_of_pow {x n : ℕ} (h : (x ^ n).Prime) : n = 1 :=
theorem Prime.pow_eq_iff {p a k : ℕ} (hp : p.Prime) : a ^ k = p ↔ a = p ∧ k = 1 := by
refine ⟨fun h => ?_, fun h => by rw [h.1, h.2, pow_one]⟩
rw [← h] at hp
- rw [← h, hp.eq_one_of_pow, eq_self_iff_true, and_true_iff, 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]
+ rw [← h, hp.eq_one_of_pow, eq_self_iff_true, _root_.and_true, pow_one]
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
@@ -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 _
@@ -247,7 +224,7 @@ theorem ne_one_iff_exists_prime_dvd : ∀ {n}, n ≠ 1 ↔ ∃ p : ℕ, p.Prime
| n + 2 => by
let a := n + 2
let ha : a ≠ 1 := Nat.succ_succ_ne_one n
- simp only [true_iff_iff, Ne, not_false_iff, ha]
+ simp only [true_iff, Ne, not_false_iff, ha]
exact ⟨a.minFac, Nat.minFac_prime ha, a.minFac_dvd⟩
theorem eq_one_iff_not_exists_prime_dvd {n : ℕ} : n = 1 ↔ ∀ p : ℕ, p.Prime → ¬p ∣ n := by
@@ -268,64 +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)⟩
-
-theorem exists_pow_lt_factorial (c : ℕ) : ∃ n0 > 1, ∀ n ≥ n0, c ^ n < (n - 1)! := by
- refine ⟨2 * (c ^ 2 + 1), ?_, ?_⟩
- · omega
- intro n hn
- obtain ⟨d, rfl⟩ := Nat.exists_eq_add_of_le hn
- obtain (rfl | c0) := c.eq_zero_or_pos
- · simp [Nat.factorial_pos]
- refine (Nat.le_mul_of_pos_right _ (Nat.pow_pos (n := d) c0)).trans_lt ?_
- convert_to (c ^ 2) ^ (c ^ 2 + d + 1) < (c ^ 2 + (c ^ 2 + d + 1))!
- · rw [← pow_mul, ← pow_add]
- congr 1
- omega
- · congr
- omega
- refine lt_of_lt_of_le ?_ Nat.factorial_mul_pow_le_factorial
- rw [← one_mul (_ ^ _ : ℕ)]
- exact Nat.mul_lt_mul_of_le_of_lt (Nat.one_le_of_lt (Nat.factorial_pos _))
- (Nat.pow_lt_pow_left (Nat.lt_succ_self _) (Nat.succ_ne_zero _)) (Nat.factorial_pos _)
-
-theorem exists_mul_pow_lt_factorial (a : ℕ) (c : ℕ) : ∃ n0, ∀ n ≥ n0, a * c ^ n < (n - 1)! := by
- obtain ⟨n0, hn, h⟩ := Nat.exists_pow_lt_factorial (a * c)
- refine ⟨n0, fun n hn => lt_of_le_of_lt ?_ (h n hn)⟩
- rw [mul_pow]
- refine Nat.mul_le_mul_right _ (Nat.le_self_pow ?_ _)
- omega
-
-theorem exists_prime_mul_pow_lt_factorial (n a c : ℕ) : ∃ p > n, p.Prime ∧ a * c ^ p < (p - 1)! :=
- have ⟨n0, h⟩ := Nat.exists_mul_pow_lt_factorial a c
- have ⟨p, hp, prime_p⟩ := (max (n + 1) n0).exists_infinite_primes
- ⟨p, (le_max_left _ _).trans hp, prime_p, h _ <| le_of_max_le_right hp⟩
-
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 8cff72a3c2aa9..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 [iff_self_iff, 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 :=
@@ -337,7 +316,7 @@ theorem minFac_le_div {n : ℕ} (pos : 0 < n) (np : ¬Prime n) : minFac n ≤ n
| ⟨0, h0⟩ => absurd pos <| by rw [h0, mul_zero]; decide
| ⟨1, h1⟩ => by
rw [mul_one] at h1
- rw [prime_def_minFac, not_and_or, ← h1, eq_self_iff_true, _root_.not_true, or_false_iff,
+ rw [prime_def_minFac, not_and_or, ← h1, eq_self_iff_true, _root_.not_true, _root_.or_false,
not_le] at np
rw [le_antisymm (le_of_lt_succ np) (succ_le_of_lt pos), minFac_one, Nat.div_one]
| ⟨x + 2, hx⟩ => by
@@ -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 8e5ebe1de87d1..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_iff]
- 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 5602a10425923..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
@@ -229,7 +231,7 @@ theorem prime_iff_card_units (p : ℕ) [Fintype (ZMod p)ˣ] :
p.Prime ↔ Fintype.card (ZMod p)ˣ = p - 1 := by
cases' eq_zero_or_neZero p with hp hp
· subst hp
- simp only [ZMod, not_prime_zero, false_iff_iff, zero_tsub]
+ simp only [ZMod, not_prime_zero, false_iff, zero_tsub]
-- the subst created a non-defeq but subsingleton instance diamond; resolve it
suffices Fintype.card ℤˣ ≠ 0 by convert this
simp
@@ -245,7 +247,7 @@ theorem totient_eq_one_iff : ∀ {n : ℕ}, n.totient = 1 ↔ n = 1 ∨ n = 2
| 2 => by simp
| n + 3 => by
have : 3 ≤ n + 3 := le_add_self
- simp only [succ_succ_ne_one, false_or_iff]
+ simp only [succ_succ_ne_one, false_or]
exact ⟨fun h => not_even_one.elim <| h ▸ totient_even this, by rintro ⟨⟩⟩
theorem dvd_two_of_totient_le_one {a : ℕ} (han : 0 < a) (ha : a.totient ≤ 1) : a ∣ 2 := by
diff --git a/Mathlib/Data/Num/Basic.lean b/Mathlib/Data/Num/Basic.lean
index 1353fdd100589..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
@@ -169,33 +171,27 @@ section
variable {α : Type*} [One α] [Add α]
-section deprecated
-set_option linter.deprecated false
-
/-- `castPosNum` casts a `PosNum` into any type which has `1` and `+`. -/
-@[deprecated (since := "2022-11-18"), coe]
+@[coe]
def castPosNum : PosNum → α
| 1 => 1
| PosNum.bit0 a => castPosNum a + castPosNum a
| PosNum.bit1 a => castPosNum a + castPosNum a + 1
/-- `castNum` casts a `Num` into any type which has `0`, `1` and `+`. -/
-@[deprecated (since := "2022-11-18"), coe]
+@[coe]
def castNum [Zero α] : Num → α
| 0 => 0
| Num.pos p => castPosNum p
-- see Note [coercion into rings]
-@[deprecated (since := "2023-03-31")] instance (priority := 900) posNumCoe : CoeHTCT PosNum α :=
+instance (priority := 900) posNumCoe : CoeHTCT PosNum α :=
⟨castPosNum⟩
-- see Note [coercion into rings]
-@[deprecated (since := "2023-03-31")]
instance (priority := 900) numNatCoe [Zero α] : CoeHTCT Num α :=
⟨castNum⟩
-end deprecated
-
instance : Repr PosNum :=
⟨fun n _ => repr (n : ℕ)⟩
@@ -593,19 +589,17 @@ def gcd (a b : ZNum) : Num :=
end ZNum
section
-
-set_option linter.deprecated false
variable {α : Type*} [Zero α] [One α] [Add α] [Neg α]
/-- `castZNum` casts a `ZNum` into any type which has `0`, `1`, `+` and `neg` -/
-@[deprecated (since := "2022-11-18"), coe]
+@[coe]
def castZNum : ZNum → α
| 0 => 0
| ZNum.pos p => p
| ZNum.neg p => -p
-- see Note [coercion into rings]
-@[deprecated (since := "2023-03-31")] instance (priority := 900) znumCoe : CoeHTCT ZNum α :=
+instance (priority := 900) znumCoe : CoeHTCT ZNum α :=
⟨castZNum⟩
instance : Repr ZNum :=
diff --git a/Mathlib/Data/Num/Lemmas.lean b/Mathlib/Data/Num/Lemmas.lean
index ac946c8f455bc..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
@@ -867,7 +866,7 @@ theorem castNum_testBit (m n) : testBit m n = Nat.testBit m n := by
· rfl
· rw [PosNum.cast_bit1, ← two_mul, ← congr_fun Nat.bit_true, Nat.testBit_bit_zero]
· rw [PosNum.cast_bit0, ← two_mul, ← congr_fun Nat.bit_false, Nat.testBit_bit_zero]
- · simp
+ · simp [Nat.testBit_add_one]
· rw [PosNum.cast_bit1, ← two_mul, ← congr_fun Nat.bit_true, Nat.testBit_bit_succ, IH]
· rw [PosNum.cast_bit0, ← two_mul, ← congr_fun Nat.bit_false, Nat.testBit_bit_succ, IH]
@@ -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 9fedb11939f4b..c9f9e120603ca 100644
--- a/Mathlib/Data/Opposite.lean
+++ b/Mathlib/Data/Opposite.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Reid Barton, Simon Hudon, Kenny Lau
+Authors: Kim Morrison, Reid Barton, Simon Hudon, Kenny Lau
-/
import Mathlib.Logic.Equiv.Defs
@@ -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 138ba4471da95..ba871ac9136ba 100644
--- a/Mathlib/Data/Option/Basic.lean
+++ b/Mathlib/Data/Option/Basic.lean
@@ -137,36 +137,19 @@ variable {p : α → Prop} (f : ∀ a : α, p a → β) (x : Option α)
theorem pbind_eq_bind (f : α → Option β) (x : Option α) : (x.pbind fun a _ ↦ f a) = x.bind f := by
cases x <;> simp only [pbind, none_bind', some_bind']
-theorem map_bind {α β γ} (f : β → γ) (x : Option α) (g : α → Option β) :
- Option.map f (x >>= g) = x >>= fun a ↦ Option.map f (g a) := by
- simp only [← map_eq_map, ← bind_pure_comp, LawfulMonad.bind_assoc]
-
theorem map_bind' (f : β → γ) (x : Option α) (g : α → Option β) :
Option.map f (x.bind g) = x.bind fun a ↦ Option.map f (g a) := by cases x <;> simp
-theorem map_pbind (f : β → γ) (x : Option α) (g : ∀ a, a ∈ x → Option β) :
- Option.map f (x.pbind g) = x.pbind fun a H ↦ Option.map f (g a H) := by
- cases x <;> simp only [pbind, map_none']
-
theorem pbind_map (f : α → β) (x : Option α) (g : ∀ b : β, b ∈ x.map f → Option γ) :
pbind (Option.map f x) g = x.pbind fun a h ↦ g (f a) (mem_map_of_mem _ h) := by cases x <;> rfl
-@[simp]
-theorem pmap_none (f : ∀ a : α, p a → β) {H} : pmap f (@none α) H = none :=
- rfl
-
-@[simp]
-theorem pmap_some (f : ∀ a : α, p a → β) {x : α} (h : p x) :
- pmap f (some x) = fun _ ↦ some (f x h) :=
- rfl
-
theorem mem_pmem {a : α} (h : ∀ a ∈ x, p a) (ha : a ∈ x) : f a (h a ha) ∈ pmap f x h := by
rw [mem_def] at ha ⊢
subst 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) :
@@ -181,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) :
@@ -208,24 +191,6 @@ theorem pbind_eq_some {f : ∀ a : α, a ∈ x → Option β} {y : β} :
simp only [mem_def, Option.some_inj] at H
simpa [H] using hz
--- Porting note: Can't simp tag this anymore because `pmap` simplifies
--- @[simp]
-theorem pmap_eq_none_iff {h} : pmap f x h = none ↔ x = none := by cases x <;> simp
-
--- Porting note: Can't simp tag this anymore because `pmap` simplifies
--- @[simp]
-theorem pmap_eq_some_iff {hf} {y : β} :
- pmap f x hf = some y ↔ ∃ (a : α) (H : x = some a), f a (hf a H) = y := by
- rcases x with (_|x)
- · simp only [not_mem_none, exists_false, pmap, not_false_iff, exists_prop_of_false, reduceCtorEq]
- · constructor
- · intro h
- simp only [pmap, Option.some_inj] at h
- exact ⟨x, rfl, h⟩
- · rintro ⟨a, H, rfl⟩
- simp only [mem_def, Option.some_inj] at H
- simp only [H, pmap]
-
-- Porting note: Can't simp tag this anymore because `join` and `pmap` simplify
-- @[simp]
theorem join_pmap_eq_pmap_join {f : ∀ a, p a → β} {x : Option (Option α)} (H) :
@@ -268,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 e140c43e996c9..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] :
@@ -75,10 +75,6 @@ abbrev iget [Inhabited α] : Option α → α
theorem iget_some [Inhabited α] {a : α} : (some a).iget = a :=
rfl
-@[simp]
-theorem mem_toList {a : α} {o : Option α} : a ∈ toList o ↔ a ∈ o := by
- cases o <;> simp [toList, eq_comm]
-
instance liftOrGet_isCommutative (f : α → α → α) [Std.Commutative f] :
Std.Commutative (liftOrGet f) :=
⟨fun a b ↦ by cases a <;> cases b <;> simp [liftOrGet, Std.Commutative.comm]⟩
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/Ordering/Basic.lean b/Mathlib/Data/Ordering/Basic.lean
index 47a83a56ad26f..45c2f5778c1d4 100644
--- a/Mathlib/Data/Ordering/Basic.lean
+++ b/Mathlib/Data/Ordering/Basic.lean
@@ -3,9 +3,10 @@ Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
+import Batteries.Tactic.Alias
+import Mathlib.Tactic.Lemma
+import Mathlib.Tactic.TypeStar
-
-import Mathlib.Init
/-!
# Helper definitions and instances for `Ordering`
-/
@@ -16,18 +17,26 @@ deriving instance Repr for Ordering
namespace Ordering
-/-- Combine two `Ordering`s lexicographically. -/
-@[inline]
-def orElse : Ordering → Ordering → Ordering
- | lt, _ => lt
- | eq, o => o
- | gt, _ => gt
-
-/-- The relation corresponding to each `Ordering` constructor (e.g. `.lt.toProp a b` is `a < b`). -/
-def toRel {α : Type u} [LT α] : Ordering → α → α → Prop
- | .lt => (· < ·)
- | .eq => Eq
- | .gt => (· > ·)
+variable {α : Type*}
+
+@[deprecated (since := "2024-09-13")] alias orElse := «then»
+
+/-- `Compares o a b` means that `a` and `b` have the ordering relation `o` between them, assuming
+that the relation `a < b` is defined. -/
+-- Porting note: we have removed `@[simp]` here in favour of separate simp lemmas,
+-- otherwise this definition will unfold to a match.
+def Compares [LT α] : Ordering → α → α → Prop
+ | lt, a, b => a < b
+ | eq, a, b => a = b
+ | gt, a, b => a > b
+
+@[deprecated (since := "2024-09-13")] alias toRel := Compares
+
+@[simp] lemma compares_lt [LT α] (a b : α) : Compares lt a b = (a < b) := rfl
+
+@[simp] lemma compares_eq [LT α] (a b : α) : Compares eq a b = (a = b) := rfl
+
+@[simp] lemma compares_gt [LT α] (a b : α) : Compares gt a b = (a > b) := rfl
end Ordering
diff --git a/Mathlib/Data/Ordmap/Ordnode.lean b/Mathlib/Data/Ordmap/Ordnode.lean
index 0739a52acab99..31245ed62ad9a 100644
--- a/Mathlib/Data/Ordmap/Ordnode.lean
+++ b/Mathlib/Data/Ordmap/Ordnode.lean
@@ -313,11 +313,11 @@ def All (P : α → Prop) : Ordnode α → Prop
| node _ l x r => All P l ∧ P x ∧ All P r
instance All.decidable {P : α → Prop} : (t : Ordnode α) → [DecidablePred P] → Decidable (All P t)
- | nil => decidableTrue
- | node _ l _ r =>
+ | nil => isTrue trivial
+ | node _ l m r =>
have : Decidable (All P l) := All.decidable l
have : Decidable (All P r) := All.decidable r
- And.decidable
+ inferInstanceAs <| Decidable (All P l ∧ P m ∧ All P r)
/-- O(n). Does any element of the map satisfy property `P`?
@@ -328,11 +328,11 @@ def Any (P : α → Prop) : Ordnode α → Prop
| node _ l x r => Any P l ∨ P x ∨ Any P r
instance Any.decidable {P : α → Prop} : (t : Ordnode α ) → [DecidablePred P] → Decidable (Any P t)
- | nil => decidableFalse
- | node _ l _ r =>
+ | nil => isFalse id
+ | node _ l m r =>
have : Decidable (Any P l) := Any.decidable l
have : Decidable (Any P r) := Any.decidable r
- Or.decidable
+ inferInstanceAs <| Decidable (Any P l ∨ P m ∨ Any P r)
/-- O(n). Exact membership in the set. This is useful primarily for stating
correctness properties; use `∈` for a version that actually uses the BST property
@@ -604,7 +604,8 @@ instance [Std.ToFormat α] : Std.ToFormat (Ordnode α) where
def Equiv (t₁ t₂ : Ordnode α) : Prop :=
t₁.size = t₂.size ∧ t₁.toList = t₂.toList
-instance [DecidableEq α] : DecidableRel (@Equiv α) := fun _ _ => And.decidable
+instance [DecidableEq α] : DecidableRel (@Equiv α) := fun x y =>
+ inferInstanceAs (Decidable (x.size = y.size ∧ x.toList = y.toList))
/-- O(2^n). Constructs the powerset of a given set, that is, the set of all subsets.
diff --git a/Mathlib/Data/Ordmap/Ordset.lean b/Mathlib/Data/Ordmap/Ordset.lean
index d0706d174ec05..290b42a70f8e6 100644
--- a/Mathlib/Data/Ordmap/Ordset.lean
+++ b/Mathlib/Data/Ordmap/Ordset.lean
@@ -151,7 +151,7 @@ and nothing on the other. -/
def BalancedSz (l r : ℕ) : Prop :=
l + r ≤ 1 ∨ l ≤ delta * r ∧ r ≤ delta * l
-instance BalancedSz.dec : DecidableRel BalancedSz := fun _ _ => Or.decidable
+instance BalancedSz.dec : DecidableRel BalancedSz := fun _ _ => inferInstanceAs (Decidable (_ ∨ _))
/-- The `Balanced t` asserts that the tree `t` satisfies the balance invariants
(at every level). -/
@@ -378,7 +378,7 @@ theorem Sized.rotateR_size {l x r} (hl : Sized l) :
rw [← size_dual, dual_rotateR, hl.dual.rotateL_size, size_dual, size_dual, add_comm (size l)]
theorem Sized.balance' {l x r} (hl : @Sized α l) (hr : Sized r) : Sized (balance' l x r) := by
- unfold balance'; split_ifs
+ unfold Ordnode.balance'; split_ifs
· exact hl.node' hr
· exact hl.rotateL hr
· exact hl.rotateR hr
@@ -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 ?_
@@ -1258,7 +1258,7 @@ theorem Valid'.glue_aux {l r o₁ o₂} (hl : Valid' o₁ l o₂) (hr : Valid' o
suffices H : _ by
refine ⟨Valid'.balanceL (hl.of_lt ?_ ?_) v H, ?_⟩
· refine @findMin'_all (P := fun a : α => Bounded nil o₁ (a : WithBot α))
- rl rx (sep.2.1.1.imp ?_) hr.1.1.to_nil
+ _ rl rx (sep.2.1.1.imp ?_) hr.1.1.to_nil
exact fun y h => hl.1.1.to_nil.mono_right (le_of_lt h)
· exact
@findMin'_all _ (fun a => All (· < a) (.node ls ll lx lr)) rl rx
@@ -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 b80eb899c2f5e..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
@@ -390,7 +391,7 @@ instance [DecidableEq α] [DecidableEq β] : SemilatticeInf (α ≃. β) :=
· contrapose! h2
rw [h2]
rw [← h1, hf, h2] at hg
- simp only [mem_def, true_iff_iff, eq_self_iff_true] at hg
+ simp only [mem_def, true_iff, eq_self_iff_true] at hg
rw [hg]
· contrapose! h1
rw [h1] at hf h2
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 f3eb8596e529a..58879cd06c136 100644
--- a/Mathlib/Data/PFunctor/Univariate/M.lean
+++ b/Mathlib/Data/PFunctor/Univariate/M.lean
@@ -91,8 +91,8 @@ theorem truncate_eq_of_agree {n : ℕ} (x : CofixA F n) (y : CofixA F (succ n))
· rfl
· -- cases' h with _ _ _ _ _ h₀ h₁
cases h
- simp only [truncate, Function.comp_def, true_and_iff, eq_self_iff_true, heq_iff_eq]
- -- Porting note: used to be `ext y`
+ simp only [truncate, Function.comp_def, eq_self_iff_true, heq_iff_eq]
+ -- 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]
@@ -479,8 +479,8 @@ theorem ext_aux [Inhabited (M F)] [DecidableEq F.A] {n : ℕ} (x y z : M F) (hx
induction y using PFunctor.M.casesOn'
simp only [iselect_nil] at hrec
subst hrec
- simp only [approx_mk, true_and_iff, eq_self_iff_true, heq_iff_eq, zero_eq, CofixA.intro.injEq,
- heq_eq_eq, eq_iff_true_of_subsingleton, and_self]
+ simp only [approx_mk, eq_self_iff_true, heq_iff_eq, zero_eq, CofixA.intro.injEq,
+ heq_eq_eq, eq_iff_true_of_subsingleton, and_self]
· cases hx
cases hy
induction x using PFunctor.M.casesOn'
@@ -488,7 +488,7 @@ theorem ext_aux [Inhabited (M F)] [DecidableEq F.A] {n : ℕ} (x y z : M F) (hx
subst z
iterate 3 (have := mk_inj ‹_›; cases this)
rename_i n_ih a f₃ f₂ hAgree₂ _ _ h₂ _ _ f₁ h₁ hAgree₁ clr
- simp only [approx_mk, true_and_iff, eq_self_iff_true, heq_iff_eq]
+ simp only [approx_mk, eq_self_iff_true, heq_iff_eq]
have := mk_inj h₁
cases this; clear h₁
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/Defs.lean b/Mathlib/Data/PNat/Defs.lean
index 3004d33fc9df7..6eb644184ac56 100644
--- a/Mathlib/Data/PNat/Defs.lean
+++ b/Mathlib/Data/PNat/Defs.lean
@@ -3,7 +3,6 @@ Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Neil Strickland
-/
-import Mathlib.Algebra.NeZero
import Mathlib.Data.Nat.Defs
import Mathlib.Order.Basic
import Mathlib.Order.TypeTags
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 097dd92225da5..c4337051e8a85 100644
--- a/Mathlib/Data/PSigma/Order.lean
+++ b/Mathlib/Data/PSigma/Order.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Minchao Wu
+Authors: Kim Morrison, Minchao Wu
-/
import Mathlib.Data.Sigma.Lex
import Mathlib.Order.BoundedOrder
@@ -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 f30532075537d..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.
@@ -186,12 +181,12 @@ theorem snd_eq_iff : ∀ {p : α × β} {x : β}, p.2 = x ↔ p = (p.1, x)
variable {r : α → α → Prop} {s : β → β → Prop} {x y : α × β}
-lemma lex_iff : Prod.Lex r s x y ↔ r x.1 y.1 ∨ x.1 = y.1 ∧ s x.2 y.2 := lex_def _ _
+lemma lex_iff : Prod.Lex r s x y ↔ r x.1 y.1 ∨ x.1 = y.1 ∧ s x.2 y.2 := lex_def
instance Lex.decidable [DecidableEq α]
(r : α → α → Prop) (s : β → β → Prop) [DecidableRel r] [DecidableRel s] :
DecidableRel (Prod.Lex r s) :=
- fun _ _ ↦ decidable_of_decidable_of_iff (lex_def r s).symm
+ fun _ _ ↦ decidable_of_decidable_of_iff lex_def.symm
@[refl]
theorem Lex.refl_left (r : α → α → Prop) (s : β → β → Prop) [IsRefl α r] : ∀ x, Prod.Lex r s x x
diff --git a/Mathlib/Data/Prod/Lex.lean b/Mathlib/Data/Prod/Lex.lean
index f55eac2c324de..b0271fecee021 100644
--- a/Mathlib/Data/Prod/Lex.lean
+++ b/Mathlib/Data/Prod/Lex.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Minchao Wu
+Authors: Kim Morrison, Minchao Wu
-/
import Mathlib.Order.BoundedOrder
@@ -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 (· < ·) (· ≤ ·)
@@ -48,11 +44,11 @@ instance instLT (α β : Type*) [LT α] [LT β] : LT (α ×ₗ β) where lt := P
theorem le_iff [LT α] [LE β] (a b : α × β) :
toLex a ≤ toLex b ↔ a.1 < b.1 ∨ a.1 = b.1 ∧ a.2 ≤ b.2 :=
- Prod.lex_def (· < ·) (· ≤ ·)
+ Prod.lex_def
theorem lt_iff [LT α] [LT β] (a b : α × β) :
toLex a < toLex b ↔ a.1 < b.1 ∨ a.1 = b.1 ∧ a.2 < b.2 :=
- Prod.lex_def (· < ·) (· < ·)
+ Prod.lex_def
example (x : α) (y : β) : toLex (x, y) = toLex (x, y) := rfl
@@ -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 643f4426c88c1..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
@@ -19,15 +18,13 @@ import Mathlib.Data.Rat.Lemmas
We define the canonical injection from ℚ into an arbitrary division ring and prove various
casting lemmas showing the well-behavedness of this injection.
-## Notations
-
-- `/.` is infix notation for `Rat.divInt`.
-
## Tags
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 f684d39ce96de..2423ed18b9d60 100644
--- a/Mathlib/Data/Rat/Lemmas.lean
+++ b/Mathlib/Data/Rat/Lemmas.lean
@@ -53,7 +53,7 @@ theorem num_mk (n d : ℤ) : (n /. d).num = d.sign * n / n.gcd d := by
have (m : ℕ) : Int.natAbs (m + 1) = m + 1 := by
rw [← Nat.cast_one, ← Nat.cast_add, Int.natAbs_cast]
rcases d with ((_ | _) | _) <;>
- rw [← Int.div_eq_ediv_of_dvd] <;>
+ rw [← Int.tdiv_eq_ediv_of_dvd] <;>
simp [divInt, mkRat, Rat.normalize, Nat.succPNat, Int.sign, Int.gcd,
Int.zero_ediv, Int.ofNat_dvd_left, Nat.gcd_dvd_left, this]
@@ -195,7 +195,7 @@ theorem div_int_inj {a b c d : ℤ} (hb0 : 0 < b) (hd0 : 0 < d) (h1 : Nat.Coprim
theorem intCast_div_self (n : ℤ) : ((n / n : ℤ) : ℚ) = n / n := by
by_cases hn : n = 0
· subst hn
- simp only [Int.cast_zero, Int.zero_div, zero_div, Int.ediv_zero]
+ simp only [Int.cast_zero, Int.zero_tdiv, zero_div, Int.ediv_zero]
· have : (n : ℚ) ≠ 0 := by rwa [← coe_int_inj] at hn
simp only [Int.ediv_self hn, Int.cast_one, Ne, not_false_iff, div_self this]
@@ -247,9 +247,9 @@ theorem inv_intCast_num (a : ℤ) : (a : ℚ)⁻¹.num = Int.sign a := by
rcases lt_trichotomy a 0 with lt | rfl | gt
· obtain ⟨a, rfl⟩ : ∃ b, -b = a := ⟨-a, a.neg_neg⟩
simp at lt
- simp [Rat.inv_neg, inv_intCast_num_of_pos lt, (Int.sign_eq_one_iff_pos _).mpr lt]
- · rfl
- · simp [inv_intCast_num_of_pos gt, (Int.sign_eq_one_iff_pos _).mpr gt]
+ simp [Rat.inv_neg, inv_intCast_num_of_pos lt, Int.sign_eq_one_iff_pos.mpr lt]
+ · simp
+ · simp [inv_intCast_num_of_pos gt, Int.sign_eq_one_iff_pos.mpr gt]
@[simp]
theorem inv_natCast_num (a : ℕ) : (a : ℚ)⁻¹.num = Int.sign a :=
@@ -268,7 +268,7 @@ theorem inv_intCast_den (a : ℤ) : (a : ℚ)⁻¹.den = if a = 0 then 1 else a.
rw [if_neg (by omega)]
simp only [Int.cast_neg, Rat.inv_neg, neg_den, inv_intCast_den_of_pos lt, Int.natAbs_neg]
exact Int.eq_natAbs_of_zero_le (by omega)
- · rfl
+ · simp
· rw [if_neg (by omega)]
simp only [inv_intCast_den_of_pos gt]
exact Int.eq_natAbs_of_zero_le (by omega)
@@ -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 320d601909bab..2e6e3bb63eb7a 100644
--- a/Mathlib/Data/Real/Archimedean.lean
+++ b/Mathlib/Data/Real/Archimedean.lean
@@ -3,9 +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, Floris van Doorn
-/
-import Mathlib.Algebra.Bounds
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
/-!
@@ -17,6 +18,7 @@ open scoped Classical
open Pointwise CauSeq
namespace Real
+variable {ι : Sort*} {f : ι → ℝ} {s : Set ℝ} {a : ℝ}
instance instArchimedean : Archimedean ℝ :=
archimedean_iff_rat_le.2 fun x =>
@@ -49,9 +51,9 @@ theorem exists_floor (x : ℝ) : ∃ ub : ℤ, (ub : ℝ) ≤ x ∧ ∀ z : ℤ,
(let ⟨n, hn⟩ := exists_int_lt x
⟨n, le_of_lt hn⟩)
-theorem exists_isLUB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddAbove S) : ∃ x, IsLUB S x := by
+theorem exists_isLUB (hne : s.Nonempty) (hbdd : BddAbove s) : ∃ x, IsLUB s x := by
rcases hne, hbdd with ⟨⟨L, hL⟩, ⟨U, hU⟩⟩
- have : ∀ d : ℕ, BddAbove { m : ℤ | ∃ y ∈ S, (m : ℝ) ≤ y * d } := by
+ have : ∀ d : ℕ, BddAbove { m : ℤ | ∃ y ∈ s, (m : ℝ) ≤ y * d } := by
cases' exists_int_gt U with k hk
refine fun d => ⟨k * d, fun z h => ?_⟩
rcases h with ⟨y, yS, hy⟩
@@ -60,14 +62,14 @@ theorem exists_isLUB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddAbove S) : ∃
exact mul_le_mul_of_nonneg_right ((hU yS).trans hk.le) d.cast_nonneg
choose f hf using fun d : ℕ =>
Int.exists_greatest_of_bdd (this d) ⟨⌊L * d⌋, L, hL, Int.floor_le _⟩
- have hf₁ : ∀ n > 0, ∃ y ∈ S, ((f n / n : ℚ) : ℝ) ≤ y := fun n n0 =>
+ have hf₁ : ∀ n > 0, ∃ y ∈ s, ((f n / n : ℚ) : ℝ) ≤ y := fun n n0 =>
let ⟨y, yS, hy⟩ := (hf n).1
⟨y, yS, by simpa using (div_le_iff₀ (Nat.cast_pos.2 n0 : (_ : ℝ) < _)).2 hy⟩
- have hf₂ : ∀ n > 0, ∀ y ∈ S, (y - ((n : ℕ) : ℝ)⁻¹) < (f n / n : ℚ) := by
+ have hf₂ : ∀ n > 0, ∀ y ∈ s, (y - ((n : ℕ) : ℝ)⁻¹) < (f n / n : ℚ) := by
intro n n0 y yS
have := (Int.sub_one_lt_floor _).trans_le (Int.cast_le.2 <| (hf n).2 _ ⟨y, yS, Int.floor_le _⟩)
simp only [Rat.cast_div, Rat.cast_intCast, Rat.cast_natCast, gt_iff_lt]
- rwa [lt_div_iff (Nat.cast_pos.2 n0 : (_ : ℝ) < _), sub_mul, inv_mul_cancel₀]
+ rwa [lt_div_iff₀ (Nat.cast_pos.2 n0 : (_ : ℝ) < _), sub_mul, inv_mul_cancel₀]
exact ne_of_gt (Nat.cast_pos.2 n0)
have hg : IsCauSeq abs (fun n => f n / n : ℕ → ℚ) := by
intro ε ε0
@@ -81,7 +83,7 @@ theorem exists_isLUB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddAbove S) : ∃
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 => ?_⟩⟩
@@ -92,7 +94,7 @@ theorem exists_isLUB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddAbove S) : ∃
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 =>
@@ -100,56 +102,52 @@ theorem exists_isLUB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddAbove S) : ∃
le_trans hx (h xS)⟩
/-- A nonempty, bounded below set of real numbers has a greatest lower bound. -/
-theorem exists_isGLB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddBelow S) : ∃ x, IsGLB S x := by
- have hne' : (-S).Nonempty := Set.nonempty_neg.mpr hne
- have hbdd' : BddAbove (-S) := bddAbove_neg.mpr hbdd
+theorem exists_isGLB (hne : s.Nonempty) (hbdd : BddBelow s) : ∃ x, IsGLB s x := by
+ have hne' : (-s).Nonempty := Set.nonempty_neg.mpr hne
+ have hbdd' : BddAbove (-s) := bddAbove_neg.mpr hbdd
use -Classical.choose (Real.exists_isLUB hne' hbdd')
rw [← isLUB_neg]
exact Classical.choose_spec (Real.exists_isLUB hne' hbdd')
noncomputable instance : SupSet ℝ :=
- ⟨fun S => if h : S.Nonempty ∧ BddAbove S then Classical.choose (exists_isLUB h.1 h.2) else 0⟩
+ ⟨fun s => if h : s.Nonempty ∧ BddAbove s then Classical.choose (exists_isLUB h.1 h.2) else 0⟩
-theorem sSup_def (S : Set ℝ) :
- sSup S = if h : S.Nonempty ∧ BddAbove S then Classical.choose (exists_isLUB h.1 h.2) else 0 :=
+theorem sSup_def (s : Set ℝ) :
+ sSup s = if h : s.Nonempty ∧ BddAbove s then Classical.choose (exists_isLUB h.1 h.2) else 0 :=
rfl
-protected theorem isLUB_sSup (S : Set ℝ) (h₁ : S.Nonempty) (h₂ : BddAbove S) :
- IsLUB S (sSup S) := by
+protected theorem isLUB_sSup (h₁ : s.Nonempty) (h₂ : BddAbove s) : IsLUB s (sSup s) := by
simp only [sSup_def, dif_pos (And.intro h₁ h₂)]
apply Classical.choose_spec
noncomputable instance : InfSet ℝ :=
- ⟨fun S => -sSup (-S)⟩
+ ⟨fun s => -sSup (-s)⟩
-theorem sInf_def (S : Set ℝ) : sInf S = -sSup (-S) :=
- rfl
+theorem sInf_def (s : Set ℝ) : sInf s = -sSup (-s) := rfl
-protected theorem is_glb_sInf (S : Set ℝ) (h₁ : S.Nonempty) (h₂ : BddBelow S) :
- IsGLB S (sInf S) := by
+protected theorem isGLB_sInf (h₁ : s.Nonempty) (h₂ : BddBelow s) : IsGLB s (sInf s) := by
rw [sInf_def, ← isLUB_neg', neg_neg]
- exact Real.isLUB_sSup _ h₁.neg h₂.neg
-
-noncomputable instance : ConditionallyCompleteLinearOrder ℝ :=
- { Real.linearOrder, Real.lattice with
- sSup := SupSet.sSup
- sInf := InfSet.sInf
- le_csSup := fun s a hs ha => (Real.isLUB_sSup s ⟨a, ha⟩ hs).1 ha
- csSup_le := fun s a hs ha => (Real.isLUB_sSup s hs ⟨a, ha⟩).2 ha
- csInf_le := fun s a hs ha => (Real.is_glb_sInf s ⟨a, ha⟩ hs).1 ha
- le_csInf := fun s a hs ha => (Real.is_glb_sInf s hs ⟨a, ha⟩).2 ha
- csSup_of_not_bddAbove := fun s hs ↦ by simp [hs, sSup_def]
- csInf_of_not_bddBelow := fun s hs ↦ by simp [hs, sInf_def, sSup_def] }
-
-theorem lt_sInf_add_pos {s : Set ℝ} (h : s.Nonempty) {ε : ℝ} (hε : 0 < ε) :
- ∃ a ∈ s, a < sInf s + ε :=
+ exact Real.isLUB_sSup h₁.neg h₂.neg
+
+@[deprecated (since := "2024-10-02")] alias is_glb_sInf := isGLB_sInf
+
+noncomputable instance : ConditionallyCompleteLinearOrder ℝ where
+ __ := Real.linearOrder
+ __ := Real.lattice
+ le_csSup s a hs ha := (Real.isLUB_sSup ⟨a, ha⟩ hs).1 ha
+ csSup_le s a hs ha := (Real.isLUB_sSup hs ⟨a, ha⟩).2 ha
+ csInf_le s a hs ha := (Real.isGLB_sInf ⟨a, ha⟩ hs).1 ha
+ le_csInf s a hs ha := (Real.isGLB_sInf hs ⟨a, ha⟩).2 ha
+ csSup_of_not_bddAbove s hs := by simp [hs, sSup_def]
+ csInf_of_not_bddBelow s hs := by simp [hs, sInf_def, sSup_def]
+
+theorem lt_sInf_add_pos (h : s.Nonempty) {ε : ℝ} (hε : 0 < ε) : ∃ a ∈ s, a < sInf s + ε :=
exists_lt_of_csInf_lt h <| lt_add_of_pos_right _ hε
-theorem add_neg_lt_sSup {s : Set ℝ} (h : s.Nonempty) {ε : ℝ} (hε : ε < 0) :
- ∃ a ∈ s, sSup s + ε < a :=
+theorem add_neg_lt_sSup (h : s.Nonempty) {ε : ℝ} (hε : ε < 0) : ∃ a ∈ s, sSup s + ε < a :=
exists_lt_of_lt_csSup h <| add_lt_iff_neg_left.2 hε
-theorem sInf_le_iff {s : Set ℝ} (h : BddBelow s) (h' : s.Nonempty) {a : ℝ} :
+theorem sInf_le_iff (h : BddBelow s) (h' : s.Nonempty) :
sInf s ≤ a ↔ ∀ ε, 0 < ε → ∃ x ∈ s, x < a + ε := by
rw [le_iff_forall_pos_lt_add]
constructor <;> intro H ε ε_pos
@@ -157,7 +155,7 @@ theorem sInf_le_iff {s : Set ℝ} (h : BddBelow s) (h' : s.Nonempty) {a : ℝ} :
· rcases H ε ε_pos with ⟨x, x_in, hx⟩
exact csInf_lt_of_lt h x_in hx
-theorem le_sSup_iff {s : Set ℝ} (h : BddAbove s) (h' : s.Nonempty) {a : ℝ} :
+theorem le_sSup_iff (h : BddAbove s) (h' : s.Nonempty) :
a ≤ sSup s ↔ ∀ ε, ε < 0 → ∃ x ∈ s, a + ε < x := by
rw [le_iff_forall_pos_lt_add]
refine ⟨fun H ε ε_neg => ?_, fun H ε ε_pos => ?_⟩
@@ -169,102 +167,128 @@ theorem le_sSup_iff {s : Set ℝ} (h : BddAbove s) (h' : s.Nonempty) {a : ℝ} :
theorem sSup_empty : sSup (∅ : Set ℝ) = 0 :=
dif_neg <| by simp
-@[simp] lemma iSup_of_isEmpty {α : Sort*} [IsEmpty α] (f : α → ℝ) : ⨆ i, f i = 0 := by
+@[simp] lemma iSup_of_isEmpty [IsEmpty ι] (f : ι → ℝ) : ⨆ i, f i = 0 := by
dsimp [iSup]
convert Real.sSup_empty
rw [Set.range_eq_empty_iff]
infer_instance
@[simp]
-theorem ciSup_const_zero {α : Sort*} : ⨆ _ : α, (0 : ℝ) = 0 := by
- cases isEmpty_or_nonempty α
+theorem iSup_const_zero : ⨆ _ : ι, (0 : ℝ) = 0 := by
+ cases isEmpty_or_nonempty ι
· exact Real.iSup_of_isEmpty _
· exact ciSup_const
-theorem sSup_of_not_bddAbove {s : Set ℝ} (hs : ¬BddAbove s) : sSup s = 0 :=
- dif_neg fun h => hs h.2
-
-theorem iSup_of_not_bddAbove {α : Sort*} {f : α → ℝ} (hf : ¬BddAbove (Set.range f)) :
- ⨆ i, f i = 0 :=
- sSup_of_not_bddAbove hf
+lemma sSup_of_not_bddAbove (hs : ¬BddAbove s) : sSup s = 0 := dif_neg fun h => hs h.2
+lemma iSup_of_not_bddAbove (hf : ¬BddAbove (Set.range f)) : ⨆ i, f i = 0 := sSup_of_not_bddAbove hf
theorem sSup_univ : sSup (@Set.univ ℝ) = 0 := Real.sSup_of_not_bddAbove not_bddAbove_univ
@[simp]
theorem sInf_empty : sInf (∅ : Set ℝ) = 0 := by simp [sInf_def, sSup_empty]
-@[simp] nonrec lemma iInf_of_isEmpty {α : Sort*} [IsEmpty α] (f : α → ℝ) : ⨅ i, f i = 0 := by
+@[simp] nonrec lemma iInf_of_isEmpty [IsEmpty ι] (f : ι → ℝ) : ⨅ i, f i = 0 := by
rw [iInf_of_isEmpty, sInf_empty]
@[simp]
-theorem ciInf_const_zero {α : Sort*} : ⨅ _ : α, (0 : ℝ) = 0 := by
- cases isEmpty_or_nonempty α
+theorem iInf_const_zero : ⨅ _ : ι, (0 : ℝ) = 0 := by
+ cases isEmpty_or_nonempty ι
· exact Real.iInf_of_isEmpty _
· exact ciInf_const
-theorem sInf_of_not_bddBelow {s : Set ℝ} (hs : ¬BddBelow s) : sInf s = 0 :=
+theorem sInf_of_not_bddBelow (hs : ¬BddBelow s) : sInf s = 0 :=
neg_eq_zero.2 <| sSup_of_not_bddAbove <| mt bddAbove_neg.1 hs
-theorem iInf_of_not_bddBelow {α : Sort*} {f : α → ℝ} (hf : ¬BddBelow (Set.range f)) :
- ⨅ i, f i = 0 :=
+theorem iInf_of_not_bddBelow (hf : ¬BddBelow (Set.range f)) : ⨅ i, f i = 0 :=
sInf_of_not_bddBelow hf
-/--
-As `0` is the default value for `Real.sSup` of the empty set or sets which are not bounded above, it
-suffices to show that `S` is bounded below by `0` to show that `0 ≤ sSup S`.
--/
-theorem sSup_nonneg (S : Set ℝ) (hS : ∀ x ∈ S, (0 : ℝ) ≤ x) : 0 ≤ sSup S := by
- rcases S.eq_empty_or_nonempty with (rfl | ⟨y, hy⟩)
- · exact sSup_empty.ge
- · apply dite _ (fun h => le_csSup_of_le h hy <| hS y hy) fun h => (sSup_of_not_bddAbove h).ge
+/-- As `sSup s = 0` when `s` is an empty set of reals, it suffices to show that all elements of `s`
+are at most some nonnegative number `a` to show that `sSup s ≤ a`.
-/--
-As `0` is the default value for `Real.sSup` of the empty set or sets which are not bounded above, it
-suffices to show that `f i` is nonnegative to show that `0 ≤ ⨆ i, f i`.
--/
-protected theorem iSup_nonneg {ι : Sort*} {f : ι → ℝ} (hf : ∀ i, 0 ≤ f i) : 0 ≤ ⨆ i, f i :=
- sSup_nonneg _ <| Set.forall_mem_range.2 hf
+See also `csSup_le`. -/
+protected lemma sSup_le (hs : ∀ x ∈ s, x ≤ a) (ha : 0 ≤ a) : sSup s ≤ a := by
+ obtain rfl | hs' := s.eq_empty_or_nonempty
+ exacts [sSup_empty.trans_le ha, csSup_le hs' hs]
-/--
-As `0` is the default value for `Real.sSup` of the empty set or sets which are not bounded above, it
-suffices to show that all elements of `S` are bounded by a nonnegative number to show that `sSup S`
-is bounded by this number.
--/
-protected theorem sSup_le {S : Set ℝ} {a : ℝ} (hS : ∀ x ∈ S, x ≤ a) (ha : 0 ≤ a) : sSup S ≤ a := by
- rcases S.eq_empty_or_nonempty with (rfl | hS₂)
- exacts [sSup_empty.trans_le ha, csSup_le hS₂ hS]
+/-- As `⨆ i, f i = 0` when the domain of the real-valued function `f` is empty, it suffices to show
+that all values of `f` are at most some nonnegative number `a` to show that `⨆ i, f i ≤ a`.
-protected theorem iSup_le {ι : Sort*} {f : ι → ℝ} {a : ℝ} (hS : ∀ i, f i ≤ a) (ha : 0 ≤ a) :
- ⨆ i, f i ≤ a :=
- Real.sSup_le (Set.forall_mem_range.2 hS) ha
+See also `ciSup_le`. -/
+protected lemma iSup_le (hf : ∀ i, f i ≤ a) (ha : 0 ≤ a) : ⨆ i, f i ≤ a :=
+ Real.sSup_le (Set.forall_mem_range.2 hf) ha
-/-- As `0` is the default value for `Real.sSup` of the empty set, it suffices to show that `S` is
-bounded above by `0` to show that `sSup S ≤ 0`.
--/
-theorem sSup_nonpos (S : Set ℝ) (hS : ∀ x ∈ S, x ≤ (0 : ℝ)) : sSup S ≤ 0 :=
- Real.sSup_le hS le_rfl
+/-- As `sInf s = 0` when `s` is an empty set of reals, it suffices to show that all elements of `s`
+are at least some nonpositive number `a` to show that `a ≤ sInf s`.
-/-- As `0` is the default value for `Real.sInf` of the empty set, it suffices to show that `S` is
-bounded below by `0` to show that `0 ≤ sInf S`.
--/
-theorem sInf_nonneg (S : Set ℝ) (hS : ∀ x ∈ S, (0 : ℝ) ≤ x) : 0 ≤ sInf S := by
- rcases S.eq_empty_or_nonempty with (rfl | hS₂)
- exacts [sInf_empty.ge, le_csInf hS₂ hS]
+See also `le_csInf`. -/
+protected lemma le_sInf (hs : ∀ x ∈ s, a ≤ x) (ha : a ≤ 0) : a ≤ sInf s := by
+ obtain rfl | hs' := s.eq_empty_or_nonempty
+ exacts [ha.trans_eq sInf_empty.symm, le_csInf hs' hs]
-/-- As `0` is the default value for `Real.sInf` of the empty set, it suffices to show that `f i` is
-bounded below by `0` to show that `0 ≤ iInf f`.
--/
-theorem iInf_nonneg {ι} {f : ι → ℝ} (hf : ∀ i, 0 ≤ f i) : 0 ≤ iInf f :=
- sInf_nonneg _ <| Set.forall_mem_range.2 hf
+/-- As `⨅ i, f i = 0` when the domain of the real-valued function `f` is empty, it suffices to show
+that all values of `f` are at least some nonpositive number `a` to show that `a ≤ ⨅ i, f i`.
-/--
-As `0` is the default value for `Real.sInf` of the empty set or sets which are not bounded below, it
-suffices to show that `S` is bounded above by `0` to show that `sInf S ≤ 0`.
--/
-theorem sInf_nonpos (S : Set ℝ) (hS : ∀ x ∈ S, x ≤ (0 : ℝ)) : sInf S ≤ 0 := by
- rcases S.eq_empty_or_nonempty with (rfl | ⟨y, hy⟩)
+See also `le_ciInf`. -/
+protected lemma le_iInf (hf : ∀ i, a ≤ f i) (ha : a ≤ 0) : a ≤ ⨅ i, f i :=
+ Real.le_sInf (Set.forall_mem_range.2 hf) ha
+
+/-- As `sSup s = 0` when `s` is an empty set of reals, it suffices to show that all elements of `s`
+are nonpositive to show that `sSup s ≤ 0`. -/
+lemma sSup_nonpos (hs : ∀ x ∈ s, x ≤ 0) : sSup s ≤ 0 := Real.sSup_le hs le_rfl
+
+/-- As `⨆ i, f i = 0` when the domain of the real-valued function `f` is empty,
+it suffices to show that all values of `f` are nonpositive to show that `⨆ i, f i ≤ 0`. -/
+lemma iSup_nonpos (hf : ∀ i, f i ≤ 0) : ⨆ i, f i ≤ 0 := Real.iSup_le hf le_rfl
+
+/-- As `sInf s = 0` when `s` is an empty set of reals, it suffices to show that all elements of `s`
+are nonnegative to show that `0 ≤ sInf s`. -/
+lemma sInf_nonneg (hs : ∀ x ∈ s, 0 ≤ x) : 0 ≤ sInf s := Real.le_sInf hs le_rfl
+
+/-- As `⨅ i, f i = 0` when the domain of the real-valued function `f` is empty,
+it suffices to show that all values of `f` are nonnegative to show that `0 ≤ ⨅ i, f i`. -/
+lemma iInf_nonneg (hf : ∀ i, 0 ≤ f i) : 0 ≤ iInf f := Real.le_iInf hf le_rfl
+
+/-- As `sSup s = 0` when `s` is a set of reals that's unbounded above, it suffices to show that `s`
+contains a nonnegative element to show that `0 ≤ sSup s`. -/
+lemma sSup_nonneg' (hs : ∃ x ∈ s, 0 ≤ x) : 0 ≤ sSup s := by
+ obtain ⟨x, hxs, hx⟩ := hs
+ exact dite _ (fun h ↦ le_csSup_of_le h hxs hx) fun h ↦ (sSup_of_not_bddAbove h).ge
+
+/-- As `⨆ i, f i = 0` when the real-valued function `f` is unbounded above,
+it suffices to show that `f` takes a nonnegative value to show that `0 ≤ ⨆ i, f i`. -/
+lemma iSup_nonneg' (hf : ∃ i, 0 ≤ f i) : 0 ≤ ⨆ i, f i := sSup_nonneg' <| Set.exists_range_iff.2 hf
+
+/-- As `sInf s = 0` when `s` is a set of reals that's unbounded below, it suffices to show that `s`
+contains a nonpositive element to show that `sInf s ≤ 0`. -/
+lemma sInf_nonpos' (hs : ∃ x ∈ s, x ≤ 0) : sInf s ≤ 0 := by
+ obtain ⟨x, hxs, hx⟩ := hs
+ exact dite _ (fun h ↦ csInf_le_of_le h hxs hx) fun h ↦ (sInf_of_not_bddBelow h).le
+
+/-- As `⨅ i, f i = 0` when the real-valued function `f` is unbounded below,
+it suffices to show that `f` takes a nonpositive value to show that `0 ≤ ⨅ i, f i`. -/
+lemma iInf_nonpos' (hf : ∃ i, f i ≤ 0) : ⨅ i, f i ≤ 0 := sInf_nonpos' <| Set.exists_range_iff.2 hf
+
+/-- As `sSup s = 0` when `s` is a set of reals that's either empty or unbounded above,
+it suffices to show that all elements of `s` are nonnegative to show that `0 ≤ sSup s`. -/
+lemma sSup_nonneg (hs : ∀ x ∈ s, 0 ≤ x) : 0 ≤ sSup s := by
+ obtain rfl | ⟨x, hx⟩ := s.eq_empty_or_nonempty
+ · exact sSup_empty.ge
+ · exact sSup_nonneg' ⟨x, hx, hs _ hx⟩
+
+/-- As `⨆ i, f i = 0` when the domain of the real-valued function `f` is empty or unbounded above,
+it suffices to show that all values of `f` are nonnegative to show that `0 ≤ ⨆ i, f i`. -/
+lemma iSup_nonneg (hf : ∀ i, 0 ≤ f i) : 0 ≤ ⨆ i, f i := sSup_nonneg <| Set.forall_mem_range.2 hf
+
+/-- As `sInf s = 0` when `s` is a set of reals that's either empty or unbounded below,
+it suffices to show that all elements of `s` are nonpositive to show that `sInf s ≤ 0`. -/
+lemma sInf_nonpos (hs : ∀ x ∈ s, x ≤ 0) : sInf s ≤ 0 := by
+ obtain rfl | ⟨x, hx⟩ := s.eq_empty_or_nonempty
· exact sInf_empty.le
- · apply dite _ (fun h => csInf_le_of_le h hy <| hS y hy) fun h => (sInf_of_not_bddBelow h).le
+ · exact sInf_nonpos' ⟨x, hx, hs _ hx⟩
+
+/-- As `⨅ i, f i = 0` when the domain of the real-valued function `f` is empty or unbounded below,
+it suffices to show that all values of `f` are nonpositive to show that `0 ≤ ⨅ i, f i`. -/
+lemma iInf_nonpos (hf : ∀ i, f i ≤ 0) : ⨅ i, f i ≤ 0 := sInf_nonpos <| Set.forall_mem_range.2 hf
theorem sInf_le_sSup (s : Set ℝ) (h₁ : BddBelow s) (h₂ : BddAbove s) : sInf s ≤ sSup s := by
rcases s.eq_empty_or_nonempty with (rfl | hne)
@@ -272,12 +296,12 @@ theorem sInf_le_sSup (s : Set ℝ) (h₁ : BddBelow s) (h₂ : BddAbove s) : sIn
· exact csInf_le_csSup h₁ h₂ hne
theorem cauSeq_converges (f : CauSeq ℝ abs) : ∃ x, f ≈ const abs x := by
- let S := { x : ℝ | const abs x < f }
- have lb : ∃ x, x ∈ S := exists_lt f
- have ub' : ∀ x, f < const abs x → ∀ y ∈ S, y ≤ x := fun x h y yS =>
+ let s := {x : ℝ | const abs x < f}
+ have lb : ∃ x, x ∈ s := exists_lt f
+ have ub' : ∀ x, f < const abs x → ∀ y ∈ s, y ≤ x := fun x h y yS =>
le_of_lt <| const_lt.1 <| CauSeq.lt_trans yS h
- have ub : ∃ x, ∀ y ∈ S, y ≤ x := (exists_gt f).imp ub'
- refine ⟨sSup S, ((lt_total _ _).resolve_left fun h => ?_).resolve_right fun h => ?_⟩
+ have ub : ∃ x, ∀ y ∈ s, y ≤ x := (exists_gt f).imp ub'
+ refine ⟨sSup s, ((lt_total _ _).resolve_left fun h => ?_).resolve_right fun h => ?_⟩
· rcases h with ⟨ε, ε0, i, ih⟩
refine (csSup_le lb (ub' _ ?_)).not_lt (sub_lt_self _ (half_pos ε0))
refine ⟨_, half_pos ε0, i, fun j ij => ?_⟩
@@ -336,8 +360,7 @@ theorem iInter_Iic_rat : ⋂ r : ℚ, Iic (r : ℝ) = ∅ := by
exact iInter_Iic_eq_empty_iff.mpr not_bddBelow_coe
/-- Exponentiation is eventually larger than linear growth. -/
-lemma exists_natCast_add_one_lt_pow_of_one_lt {a : ℝ} (ha : 1 < a) :
- ∃ m : ℕ, (m + 1 : ℝ) < a ^ m := by
+lemma exists_natCast_add_one_lt_pow_of_one_lt (ha : 1 < a) : ∃ m : ℕ, (m + 1 : ℝ) < a ^ m := by
obtain ⟨k, posk, hk⟩ : ∃ k : ℕ, 0 < k ∧ 1 / k + 1 < a := by
contrapose! ha
refine le_of_forall_lt_rat_imp_le ?_
diff --git a/Mathlib/Data/Real/Basic.lean b/Mathlib/Data/Real/Basic.lean
index 8de982a5ba82f..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
@@ -600,3 +601,10 @@ def IsNonarchimedean {A : Type*} [Add A] (f : A → ℝ) : Prop :=
`f (r ^ n) = (f r) ^ n`. -/
def IsPowMul {R : Type*} [Pow R ℕ] (f : R → ℝ) :=
∀ (a : R) {n : ℕ}, 1 ≤ n → f (a ^ n) = f a ^ n
+
+/-- A ring homomorphism `f : α →+* β` is bounded with respect to the functions `nα : α → ℝ` and
+ `nβ : β → ℝ` if there exists a positive constant `C` such that for all `x` in `α`,
+ `nβ (f x) ≤ C * nα x`. -/
+def RingHom.IsBoundedWrt {α : Type*} [Ring α] {β : Type*} [Ring β] (nα : α → ℝ) (nβ : β → ℝ)
+ (f : α →+* β) : Prop :=
+ ∃ C : ℝ, 0 < C ∧ ∀ x : α, nβ (f x) ≤ C * nα x
diff --git a/Mathlib/Data/Real/ConjExponents.lean b/Mathlib/Data/Real/ConjExponents.lean
index 5323170031fd4..581ac0eb8bed3 100644
--- a/Mathlib/Data/Real/ConjExponents.lean
+++ b/Mathlib/Data/Real/ConjExponents.lean
@@ -18,6 +18,8 @@ analysis, especially when dealing with `L^p` spaces.
* `Real.conjExponent`: Conjugate exponent of a real number.
* `NNReal.IsConjExponent`: Predicate for two nonnegative real numbers to be conjugate.
* `NNReal.conjExponent`: Conjugate exponent of a nonnegative real number.
+* `ENNReal.IsConjExponent`: Predicate for two extended nonnegative real numbers to be conjugate.
+* `ENNReal.conjExponent`: Conjugate exponent of an extended nonnegative real number.
## TODO
@@ -27,7 +29,7 @@ analysis, especially when dealing with `L^p` spaces.
noncomputable section
-open scoped ENNReal
+open scoped ENNReal NNReal
namespace Real
@@ -106,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
@@ -116,6 +118,8 @@ lemma one_sub_inv_inv (ha₀ : 0 < a) (ha₁ : a < 1) : (1 - a)⁻¹.IsConjExpon
end IsConjExponent
+lemma isConjExponent_comm : p.IsConjExponent q ↔ q.IsConjExponent p := ⟨.symm, .symm⟩
+
lemma isConjExponent_iff_eq_conjExponent (hp : 1 < p) : p.IsConjExponent q ↔ q = p / (p - 1) :=
⟨IsConjExponent.conj_eq, fun h ↦ ⟨hp, by field_simp [h]⟩⟩
@@ -195,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)⁻¹ :=
@@ -206,6 +210,8 @@ lemma one_sub_inv_inv (ha₀ : a ≠ 0) (ha₁ : a < 1) : (1 - a)⁻¹.IsConjExp
end IsConjExponent
+lemma isConjExponent_comm : p.IsConjExponent q ↔ q.IsConjExponent p := ⟨.symm, .symm⟩
+
lemma isConjExponent_iff_eq_conjExponent (h : 1 < p) : p.IsConjExponent q ↔ q = p / (p - 1) := by
rw [← isConjExponent_coe, Real.isConjExponent_iff_eq_conjExponent (mod_cast h), ← coe_inj,
NNReal.coe_div, NNReal.coe_sub h.le, coe_one]
@@ -220,3 +226,120 @@ protected lemma Real.IsConjExponent.toNNReal {p q : ℝ} (hpq : p.IsConjExponent
one_lt := by simpa using hpq.one_lt
inv_add_inv_conj := by rw [← toNNReal_inv, ← toNNReal_inv, ← toNNReal_add hpq.inv_nonneg
hpq.symm.inv_nonneg, hpq.inv_add_inv_conj, toNNReal_one]
+
+namespace ENNReal
+
+/-- Two extended nonnegative real exponents `p, q` are conjugate and satisfy the equality
+`1/p + 1/q = 1`. This condition shows up in many theorems in analysis, notably related to `L^p`
+norms. Note that we permit one of the exponents to be `∞` and the other `1`. -/
+@[mk_iff]
+structure IsConjExponent (p q : ℝ≥0∞) : Prop where
+ inv_add_inv_conj : p⁻¹ + q⁻¹ = 1
+
+/-- The conjugate exponent of `p` is `q = 1 + (p - 1)⁻¹`, so that `1/p + 1/q = 1`. -/
+noncomputable def conjExponent (p : ℝ≥0∞) : ℝ≥0∞ := 1 + (p - 1)⁻¹
+
+lemma coe_conjExponent {p : ℝ≥0} (hp : 1 < p) : p.conjExponent = conjExponent p := by
+ rw [NNReal.conjExponent, conjExponent]
+ norm_cast
+ rw [← coe_inv (tsub_pos_of_lt hp).ne']
+ norm_cast
+ field_simp [(tsub_pos_of_lt hp).ne']
+ rw [tsub_add_cancel_of_le hp.le]
+
+variable {a b p q : ℝ≥0∞} (h : p.IsConjExponent q)
+
+@[simp, norm_cast] lemma isConjExponent_coe {p q : ℝ≥0} :
+ IsConjExponent p q ↔ p.IsConjExponent q := by
+ simp only [isConjExponent_iff, NNReal.isConjExponent_iff]
+ refine ⟨fun h ↦ ⟨?_, ?_⟩, ?_⟩
+ · simpa using (ENNReal.lt_add_right (fun hp ↦ by simp [hp] at h) <| by simp).trans_eq h
+ · rw [← coe_inv, ← coe_inv] at h
+ · norm_cast at h
+ all_goals rintro rfl; simp at h
+ · rintro ⟨hp, h⟩
+ rw [← coe_inv (zero_lt_one.trans hp).ne', ← coe_inv, ← coe_add, h, coe_one]
+ rintro rfl
+ simp [hp.ne'] at h
+
+alias ⟨_, _root_.NNReal.IsConjExponent.coe_ennreal⟩ := isConjExponent_coe
+
+namespace IsConjExponent
+
+protected lemma conjExponent (hp : 1 ≤ p) : p.IsConjExponent (conjExponent p) := by
+ have : p ≠ 0 := (zero_lt_one.trans_le hp).ne'
+ rw [isConjExponent_iff, conjExponent, add_comm]
+ 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 [tsub_eq_zero_of_le]
+ obtain rfl | hp := eq_or_ne p ∞
+ · simp
+ calc
+ 1 + (p - 1)⁻¹ = (p - 1 + 1) / (p - 1) := by
+ rw [ENNReal.add_div, ENNReal.div_self ((tsub_pos_of_lt hp₁).ne') (sub_ne_top hp), one_div]
+ _ = (1 - p⁻¹)⁻¹ := by
+ rw [tsub_add_cancel_of_le, ← inv_eq_iff_eq_inv, div_eq_mul_inv, ENNReal.mul_inv, inv_inv,
+ ENNReal.mul_sub, ENNReal.inv_mul_cancel, mul_one] <;> simp [*]
+
+section
+include h
+
+@[symm]
+protected lemma symm : q.IsConjExponent p where
+ inv_add_inv_conj := by simpa [add_comm] using h.inv_add_inv_conj
+
+lemma one_le : 1 ≤ p := ENNReal.inv_le_one.1 <| by
+ rw [← add_zero p⁻¹, ← h.inv_add_inv_conj]; gcongr; positivity
+
+lemma pos : 0 < p := zero_lt_one.trans_le h.one_le
+lemma ne_zero : p ≠ 0 := h.pos.ne'
+
+lemma one_sub_inv : 1 - p⁻¹ = q⁻¹ :=
+ ENNReal.sub_eq_of_eq_add_rev' one_ne_top h.inv_add_inv_conj.symm
+
+lemma conjExponent_eq : conjExponent p = q := by
+ have hp : 1 ≤ p := h.one_le
+ have : p⁻¹ ≠ ∞ := by simpa using h.ne_zero
+ simpa [ENNReal.add_right_inj, *] using
+ (IsConjExponent.conjExponent hp).inv_add_inv_conj.trans h.inv_add_inv_conj.symm
+
+lemma conj_eq : q = 1 + (p - 1)⁻¹ := h.conjExponent_eq.symm
+
+lemma mul_eq_add : p * q = p + q := by
+ obtain rfl | hp := eq_or_ne p ∞
+ · simp [h.symm.ne_zero]
+ obtain rfl | hq := eq_or_ne q ∞
+ · simp [h.ne_zero]
+ rw [← mul_one (_ * _), ← h.inv_add_inv_conj, mul_add, mul_right_comm,
+ ENNReal.mul_inv_cancel h.ne_zero hp, one_mul, mul_assoc,
+ ENNReal.mul_inv_cancel h.symm.ne_zero hq, mul_one, add_comm]
+
+lemma div_conj_eq_sub_one : p / q = p - 1 := by
+ obtain rfl | hq := eq_or_ne q ∞
+ · 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]
+
+end
+
+protected lemma inv_inv (hab : a + b = 1) : a⁻¹.IsConjExponent b⁻¹ where
+ inv_add_inv_conj := by simpa only [inv_inv] using hab
+
+lemma inv_one_sub_inv (ha : a ≤ 1) : a⁻¹.IsConjExponent (1 - a)⁻¹ :=
+ .inv_inv <| add_tsub_cancel_of_le ha
+
+lemma one_sub_inv_inv (ha : a ≤ 1) : (1 - a)⁻¹.IsConjExponent a⁻¹ := (inv_one_sub_inv ha).symm
+
+lemma top_one : IsConjExponent ∞ 1 := ⟨by simp⟩
+lemma one_top : IsConjExponent 1 ∞ := ⟨by simp⟩
+
+end IsConjExponent
+
+lemma isConjExponent_comm : p.IsConjExponent q ↔ q.IsConjExponent p := ⟨.symm, .symm⟩
+
+lemma isConjExponent_iff_eq_conjExponent (hp : 1 ≤ p) : p.IsConjExponent q ↔ q = 1 + (p - 1)⁻¹ :=
+ ⟨fun h ↦ h.conj_eq, by rintro rfl; exact .conjExponent hp⟩
+
+end ENNReal
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 63905e911911d..2518fadf3188a 100644
--- a/Mathlib/Data/Real/GoldenRatio.lean
+++ b/Mathlib/Data/Real/GoldenRatio.lean
@@ -95,7 +95,7 @@ theorem gold_ne_zero : φ ≠ 0 :=
theorem one_lt_gold : 1 < φ := by
refine lt_of_mul_lt_mul_left ?_ (le_of_lt gold_pos)
- simp [← sq, gold_pos, zero_lt_one, - div_pow] -- Porting note: Added `- div_pow`
+ simp [← sq, gold_pos, zero_lt_one]
theorem gold_lt_two : φ < 2 := by calc
(1 + sqrt 5) / 2 < (1 + 3) / 2 := by gcongr; rw [sqrt_lt'] <;> norm_num
@@ -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
@@ -120,8 +120,7 @@ theorem neg_one_lt_goldConj : -1 < ψ := by
theorem gold_irrational : Irrational φ := by
have := Nat.Prime.irrational_sqrt (show Nat.Prime 5 by norm_num)
have := this.rat_add 1
- have := this.rat_mul (show (0.5 : ℚ) ≠ 0 by norm_num)
- convert this
+ convert this.rat_mul (show (0.5 : ℚ) ≠ 0 by norm_num)
norm_num
field_simp
@@ -129,8 +128,7 @@ theorem gold_irrational : Irrational φ := by
theorem goldConj_irrational : Irrational ψ := by
have := Nat.Prime.irrational_sqrt (show Nat.Prime 5 by norm_num)
have := this.rat_sub 1
- have := this.rat_mul (show (0.5 : ℚ) ≠ 0 by norm_num)
- convert this
+ convert this.rat_mul (show (0.5 : ℚ) ≠ 0 by norm_num)
norm_num
field_simp
@@ -170,12 +168,12 @@ theorem fib_isSol_fibRec : fibRec.IsSolution (fun x => x.fib : ℕ → α) := by
/-- The geometric sequence `fun n ↦ φ^n` is a solution of `fibRec`. -/
theorem geom_gold_isSol_fibRec : fibRec.IsSolution (φ ^ ·) := by
rw [fibRec.geom_sol_iff_root_charPoly, fibRec_charPoly_eq]
- simp [sub_eq_zero, - div_pow] -- Porting note: Added `- div_pow`
+ simp [sub_eq_zero]
/-- The geometric sequence `fun n ↦ ψ^n` is a solution of `fibRec`. -/
theorem geom_goldConj_isSol_fibRec : fibRec.IsSolution (ψ ^ ·) := by
rw [fibRec.geom_sol_iff_root_charPoly, fibRec_charPoly_eq]
- simp [sub_eq_zero, - div_pow] -- Porting note: Added `- div_pow`
+ simp [sub_eq_zero]
end Fibrec
@@ -203,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/Real/Pi/Bounds.lean b/Mathlib/Data/Real/Pi/Bounds.lean
index 20ca11d6273d2..131af1b4136f2 100644
--- a/Mathlib/Data/Real/Pi/Bounds.lean
+++ b/Mathlib/Data/Real/Pi/Bounds.lean
@@ -11,41 +11,36 @@ import Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds
This file contains lemmas which establish bounds on `Real.pi`.
Notably, these include `pi_gt_sqrtTwoAddSeries` and `pi_lt_sqrtTwoAddSeries`,
which bound `π` using series;
-numerical bounds on `π` such as `pi_gt_314`and `pi_lt_315` (more precise versions are given, too).
+numerical bounds on `π` such as `pi_gt_d2` and `pi_lt_d2` (more precise versions are given, too).
See also `Mathlib/Data/Real/Pi/Leibniz.lean` and `Mathlib/Data/Real/Pi/Wallis.lean` for infinite
formulas for `π`.
-/
--- Porting note: needed to add a lot of type ascriptions for lean to interpret numbers as reals.
-
open scoped Real
namespace Real
-theorem pi_gt_sqrtTwoAddSeries (n : ℕ) :
- (2 : ℝ) ^ (n + 1) * √(2 - sqrtTwoAddSeries 0 n) < π := by
- have : √(2 - sqrtTwoAddSeries 0 n) / (2 : ℝ) * (2 : ℝ) ^ (n + 2) < π := by
- rw [← lt_div_iff, ← sin_pi_over_two_pow_succ]
+theorem pi_gt_sqrtTwoAddSeries (n : ℕ) : 2 ^ (n + 1) * √(2 - sqrtTwoAddSeries 0 n) < π := by
+ have : √(2 - sqrtTwoAddSeries 0 n) / 2 * 2 ^ (n + 2) < π := by
+ rw [← lt_div_iff₀, ← sin_pi_over_two_pow_succ]
focus
apply sin_lt
apply div_pos pi_pos
all_goals apply pow_pos; norm_num
- apply lt_of_le_of_lt (le_of_eq _) this
+ refine lt_of_le_of_lt (le_of_eq ?_) this
rw [pow_succ' _ (n + 1), ← mul_assoc, div_mul_cancel₀, mul_comm]; norm_num
theorem pi_lt_sqrtTwoAddSeries (n : ℕ) :
- π < (2 : ℝ) ^ (n + 1) * √(2 - sqrtTwoAddSeries 0 n) + 1 / (4 : ℝ) ^ n := by
- have : π <
- (√(2 - sqrtTwoAddSeries 0 n) / (2 : ℝ) + (1 : ℝ) / ((2 : ℝ) ^ n) ^ 3 / 4) *
- (2 : ℝ) ^ (n + 2) := by
- rw [← div_lt_iff (by norm_num), ← sin_pi_over_two_pow_succ]
+ π < 2 ^ (n + 1) * √(2 - sqrtTwoAddSeries 0 n) + 1 / 4 ^ n := by
+ have : π < (√(2 - sqrtTwoAddSeries 0 n) / 2 + 1 / (2 ^ n) ^ 3 / 4) * (2 : ℝ) ^ (n + 2) := by
+ rw [← div_lt_iff₀ (by norm_num), ← sin_pi_over_two_pow_succ]
refine lt_of_lt_of_le (lt_add_of_sub_right_lt (sin_gt_sub_cube ?_ ?_)) ?_
· apply div_pos pi_pos; apply pow_pos; norm_num
· rw [div_le_iff₀']
· refine le_trans pi_le_four ?_
simp only [show (4 : ℝ) = (2 : ℝ) ^ 2 by norm_num, mul_one]
- apply pow_le_pow_right (by norm_num)
+ apply pow_right_mono₀ (by norm_num)
apply le_add_of_nonneg_left; apply Nat.zero_le
· apply pow_pos; norm_num
apply add_le_add_left; rw [div_le_div_right (by norm_num)]
@@ -57,10 +52,8 @@ theorem pi_lt_sqrtTwoAddSeries (n : ℕ) :
· rw [← le_div_iff₀ (by norm_num)]
refine le_trans ((div_le_div_right ?_).mpr pi_le_four) ?_
· apply pow_pos; norm_num
- · simp only [pow_succ', ← div_div, one_div]
- -- Porting note: removed `convert le_rfl`
- norm_num
- apply lt_of_lt_of_le this (le_of_eq _); rw [add_mul]; congr 1
+ · ring_nf; rfl
+ refine lt_of_lt_of_le this (le_of_eq ?_); rw [add_mul]; congr 1
· ring
simp only [show (4 : ℝ) = 2 ^ 2 by norm_num, ← pow_mul, div_div, ← pow_add]
rw [one_div, one_div, inv_mul_eq_iff_eq_mul₀, eq_comm, mul_inv_eq_iff_eq_mul₀, ← pow_add]
@@ -74,7 +67,7 @@ theorem pi_lower_bound_start (n : ℕ) {a}
(h : sqrtTwoAddSeries ((0 : ℕ) / (1 : ℕ)) n ≤ (2 : ℝ) - (a / (2 : ℝ) ^ (n + 1)) ^ 2) :
a < π := by
refine lt_of_le_of_lt ?_ (pi_gt_sqrtTwoAddSeries n); rw [mul_comm]
- refine (div_le_iff₀ (pow_pos (by norm_num) _ : (0 : ℝ) < _)).mp (le_sqrt_of_sq_le ?_)
+ refine (div_le_iff₀ (pow_pos (by norm_num) _)).mp (le_sqrt_of_sq_le ?_)
rwa [le_sub_comm, show (0 : ℝ) = (0 : ℕ) / (1 : ℕ) by rw [Nat.cast_zero, zero_div]]
theorem sqrtTwoAddSeries_step_up (c d : ℕ) {a b n : ℕ} {z : ℝ} (hz : sqrtTwoAddSeries (c / d) n ≤ z)
@@ -87,35 +80,6 @@ theorem sqrtTwoAddSeries_step_up (c d : ℕ) {a b n : ℕ} {z : ℝ} (hz : sqrtT
add_div_eq_mul_add_div _ _ (ne_of_gt hb'), div_le_div_iff hb' (pow_pos hd' _)]
exact mod_cast h
-section Tactic
-
-open Lean Elab Tactic
-
-/-- `numDen stx` takes a syntax expression `stx` and
-* if it is of the form `a / b`, then it returns `some (a, b)`;
-* otherwise it returns `none`.
--/
-private def numDen : Syntax → Option (Syntax.Term × Syntax.Term)
- | `($a / $b) => some (a, b)
- | _ => none
-
-/-- Create a proof of `a < π` for a fixed rational number `a`, given a witness, which is a
-sequence of rational numbers `√2 < r 1 < r 2 < ... < r n < 2` satisfying the property that
-`√(2 + r i) ≤ r(i+1)`, where `r 0 = 0` and `√(2 - r n) ≥ a/2^(n+1)`. -/
-elab "pi_lower_bound " "[" l:term,* "]" : tactic => do
- let rat_sep := l.elemsAndSeps
- let sep := rat_sep.getD 1 .missing
- let ratStx := rat_sep.filter (· != sep)
- let n := ← (toExpr ratStx.size).toSyntax
- let els := (ratStx.map numDen).reduceOption
- evalTactic (← `(tactic| apply pi_lower_bound_start $n))
- let _ := ← els.mapM fun (x, y) => do
- evalTactic (← `(tactic| apply sqrtTwoAddSeries_step_up $x $y))
- evalTactic (← `(tactic| simp [sqrtTwoAddSeries]))
- allGoals (evalTactic (← `(tactic| norm_num1)))
-
-end Tactic
-
/-- From a lower bound on `sqrtTwoAddSeries 0 n = 2 cos (π / 2 ^ (n+1))` of the form
`2 - ((a - 1 / 4 ^ n) / 2 ^ (n + 1)) ^ 2 ≤ sqrtTwoAddSeries 0 n`, one can deduce the upper bound
`π < a` thanks to basic trigonometric formulas as expressed in `pi_lt_sqrtTwoAddSeries`. -/
@@ -141,52 +105,133 @@ theorem sqrtTwoAddSeries_step_down (a b : ℕ) {c d n : ℕ} {z : ℝ}
section Tactic
-open Lean Elab Tactic
+open Lean Elab Tactic Qq
+
+/-- Create a proof of `a < π` for a fixed rational number `a`, given a witness, which is a
+sequence of rational numbers `√2 < r 1 < r 2 < ... < r n < 2` satisfying the property that
+`√(2 + r i) ≤ r(i+1)`, where `r 0 = 0` and `√(2 - r n) ≥ a/2^(n+1)`. -/
+elab "pi_lower_bound " "[" l:term,* "]" : tactic => do
+ have els := l.getElems
+ let n := quote els.size
+ evalTactic (← `(tactic| apply pi_lower_bound_start $n))
+ for l in els do
+ let {num, den, ..} ← unsafe Meta.evalExpr ℚ q(ℚ) (← Term.elabTermAndSynthesize l (some q(ℚ)))
+ evalTactic (← `(tactic| apply sqrtTwoAddSeries_step_up $(quote num.toNat) $(quote den)))
+ evalTactic (← `(tactic| simp [sqrtTwoAddSeries]))
+ allGoals <| evalTactic (← `(tactic| norm_num1))
/-- Create a proof of `π < a` for a fixed rational number `a`, given a witness, which is a
sequence of rational numbers `√2 < r 1 < r 2 < ... < r n < 2` satisfying the property that
-`√(2 + r i) ≥ r(i+1)`, where `r 0 = 0` and `√(2 - r n) ≥ (a - 1/4^n) / 2^(n+1)`. -/
+`√(2 + r i) ≥ r(i+1)`, where `r 0 = 0` and `√(2 - r n) ≤ (a - 1/4^n) / 2^(n+1)`. -/
elab "pi_upper_bound " "[" l:term,* "]" : tactic => do
- let rat_sep := l.elemsAndSeps
- let sep := rat_sep.getD 1 .missing
- let ratStx := rat_sep.filter (· != sep)
- let n := ← (toExpr ratStx.size).toSyntax
- let els := (ratStx.map numDen).reduceOption
+ have els := l.getElems
+ let n := quote els.size
evalTactic (← `(tactic| apply pi_upper_bound_start $n))
- let _ := ← els.mapM fun (x, y) => do
- evalTactic (← `(tactic| apply sqrtTwoAddSeries_step_down $x $y))
+ for l in els do
+ let {num, den, ..} ← unsafe Meta.evalExpr ℚ q(ℚ) (← Term.elabTermAndSynthesize l (some q(ℚ)))
+ evalTactic (← `(tactic| apply sqrtTwoAddSeries_step_down $(quote num.toNat) $(quote den)))
evalTactic (← `(tactic| simp [sqrtTwoAddSeries]))
- allGoals (evalTactic (← `(tactic| norm_num1)))
+ allGoals <| evalTactic (← `(tactic| norm_num1))
end Tactic
-theorem pi_gt_three : 3 < π := by
- pi_lower_bound [23/16]
-
-theorem pi_gt_314 : 3.14 < π := by
- pi_lower_bound [99 / 70, 874 / 473, 1940 / 989, 1447 / 727]
-
-theorem pi_lt_315 : π < 3.15 := by
- pi_upper_bound [140 / 99, 279 / 151, 51 / 26, 412 / 207]
-
-theorem pi_gt_31415 : 3.1415 < π := by
- pi_lower_bound
- [11482 / 8119, 5401 / 2923, 2348 / 1197, 11367 / 5711, 25705 / 12868, 23235 / 11621]
-
-theorem pi_lt_31416 : π < 3.1416 := by
- pi_upper_bound
- [4756 / 3363, 101211 / 54775, 505534 / 257719, 83289 / 41846, 411278 / 205887,
- 438142 / 219137, 451504 / 225769, 265603 / 132804, 849938 / 424971]
-
-theorem pi_gt_3141592 : 3.141592 < π := by
- pi_lower_bound
- [11482 / 8119, 7792 / 4217, 54055 / 27557, 949247 / 476920, 3310126 / 1657059,
- 2635492 / 1318143, 1580265 / 790192, 1221775 / 610899, 3612247 / 1806132, 849943 / 424972]
+/-!
+The below witnesses were generated using the following Mathematica script:
+```mathematica
+bound[a_, Iters -> n_, Rounding -> extra_, Precision -> prec_] := Module[{r0, r, r2, diff, sign},
+ On[Assert];
+ sign = If[a >= \[Pi], Print["upper"]; 1, Print["lower"]; -1];
+ r0 = 2 - ((a - (sign + 1)/2/4^n)/2^(n + 1))^2;
+ r = Log[2 - NestList[#^2 - 2 &, N[r0, prec], n - 1]];
+ diff = (r[[-1]] - Log[2 - Sqrt[2]])/(Length[r] + 1);
+ If[sign diff <= 0, Return["insufficient iterations"]];
+ r2 = Log[Rationalize[Exp[#], extra (Exp[#] - Exp[# - sign diff])] &
+ /@ (r - diff Range[1, Length[r]])];
+ Assert[sign (2 - Exp@r2[[1]] - r0) >= 0];
+ Assert[And @@ Table[
+ sign (Sqrt@(4 - Exp@r2[[i + 1]]) - (2 - Exp@r2[[i]])) >= 0, {i, 1, Length[r2] - 1}]];
+ Assert[sign (Exp@r2[[-1]] - (2 - Sqrt[2])) >= 0];
+ With[{s1 = ToString@InputForm[2 - #], s2 = ToString@InputForm[#]},
+ If[StringLength[s1] <= StringLength[s2] + 2, s1, "2-" <> s2]] & /@ Exp@Reverse@r2
+];
+```
+-/
-theorem pi_lt_3141593 : π < 3.141593 := by
- pi_upper_bound
- [27720 / 19601, 56935 / 30813, 49359 / 25163, 258754 / 130003, 113599 / 56868,
- 1101994 / 551163, 8671537 / 4336095, 3877807 / 1938940, 52483813 / 26242030,
- 56946167 / 28473117, 23798415 / 11899211]
+theorem pi_gt_three : 3 < π := by
+ -- bound[3, Iters -> 1, Rounding -> 2, Precision -> 3]
+ pi_lower_bound [23 / 16]
+
+theorem pi_lt_four : π < 4 := by
+ -- bound[4, Iters -> 1, Rounding -> 1, Precision -> 1]
+ pi_upper_bound [4 / 3]
+
+theorem pi_gt_d2 : 3.14 < π := by
+ -- bound[314*^-2, Iters -> 4, Rounding -> 1.5, Precision -> 8]
+ pi_lower_bound [338 / 239, 704 / 381, 1940 / 989, 1447 / 727]
+@[deprecated (since := "2024-09-19")] alias pi_gt_314 := pi_gt_d2
+
+theorem pi_lt_d2 : π < 3.15 := by
+ -- bound[315*^-2, Iters -> 4, Rounding -> 1.4, Precision -> 7]
+ pi_upper_bound [41 / 29, 109 / 59, 865 / 441, 412 / 207]
+@[deprecated (since := "2024-09-19")] alias pi_lt_315 := pi_lt_d2
+
+theorem pi_gt_d4 : 3.1415 < π := by
+ -- bound[31415*^-4, Iters -> 6, Rounding -> 1.1, Precision -> 10]
+ pi_lower_bound [
+ 1970 / 1393, 3010 / 1629, 11689 / 5959, 10127 / 5088, 33997 / 17019, 23235 / 11621]
+@[deprecated (since := "2024-09-19")] alias pi_gt_31415 := pi_gt_d4
+
+theorem pi_lt_d4 : π < 3.1416 := by
+ -- bound[31416*^-4, Iters -> 9, Rounding -> .9, Precision -> 16]
+ pi_upper_bound [
+ 4756/3363, 14965/8099, 21183/10799, 49188/24713, 2-53/22000, 2-71/117869, 2-47/312092,
+ 2-17/451533, 2-4/424971]
+@[deprecated (since := "2024-09-19")] alias pi_lt_31416 := pi_lt_d4
+
+theorem pi_gt_d6 : 3.141592 < π := by
+ -- bound[3141592*^-6, Iters -> 10, Rounding -> .8, Precision -> 16]
+ pi_lower_bound [
+ 11482/8119, 7792/4217, 54055/27557, 2-623/64690, 2-337/139887, 2-208/345307, 2-167/1108925,
+ 2-64/1699893, 2-31/3293535, 2-48/20398657]
+@[deprecated (since := "2024-09-19")] alias pi_gt_3141592 := pi_gt_d6
+
+theorem pi_lt_d6 : π < 3.141593 := by
+ -- bound[3141593*^-6, Iters -> 11, Rounding -> .5, Precision -> 17]
+ pi_upper_bound [
+ 35839/25342, 49143/26596, 145729/74292, 294095/147759, 2-137/56868, 2-471/781921, 2-153/1015961,
+ 2-157/4170049, 2-28/2974805, 2-9/3824747, 2-7/11899211]
+@[deprecated (since := "2024-09-19")] alias pi_lt_3141593 := pi_lt_d6
+
+theorem pi_gt_d20 : 3.14159265358979323846 < π := by
+ -- bound[314159265358979323846*^-20, Iters -> 34, Rounding -> .6, Precision -> 46]
+ pi_lower_bound [
+ 671574048197/474874563549, 58134718954/31462283181, 3090459598621/1575502640777,
+ 2-7143849599/741790664068, 8431536490061/4220852446654, 2-2725579171/4524814682468,
+ 2-2494895647/16566776788806, 2-608997841/16175484287402, 2-942567063/100141194694075,
+ 2-341084060/144951150987041, 2-213717653/363295959742218, 2-71906926/488934711121807,
+ 2-29337101/797916288104986, 2-45326311/4931175952730065, 2-7506877/3266776448781479,
+ 2-5854787/10191338039232571, 2-4538642/31601378399861717, 2-276149/7691013341581098,
+ 2-350197/39013283396653714, 2-442757/197299283738495963, 2-632505/1127415566199968707,
+ 2-1157/8249230030392285, 2-205461/5859619883403334178, 2-33721/3846807755987625852,
+ 2-11654/5317837263222296743, 2-8162/14897610345776687857, 2-731/5337002285107943372,
+ 2-1320/38549072592845336201, 2-707/82588467645883795866, 2-53/24764858756615791675,
+ 2-237/442963888703240952920, 2-128/956951523274512100791, 2-32/956951523274512100783,
+ 2-27/3229711391051478340136]
+
+theorem pi_lt_d20 : π < 3.14159265358979323847 := by
+ -- bound[314159265358979323847*^-20, Iters -> 34, Rounding -> .5, Precision -> 46]
+ pi_upper_bound [
+ 215157040700/152139002499, 936715022285/506946517009, 1760670193473/897581880893,
+ 2-6049918861/628200981455, 2-8543385003/3546315642356, 2-2687504973/4461606579043,
+ 2-1443277808/9583752057175, 2-546886849/14525765179168, 2-650597193/69121426717657,
+ 2-199969519/84981432264454, 2-226282901/384655467333100, 2-60729699/412934601558121,
+ 2-25101251/682708800188252, 2-7156464/778571703825145, 2-7524725/3274543383827551,
+ 2-4663362/8117442793616861, 2-1913009/13319781840326041, 2-115805/3225279830894912,
+ 2-708749/78957345705688293, 2-131255/58489233342660393, 2-101921/181670219085488669,
+ 2-44784/319302953916238627, 2-82141/2342610212364552264, 2-4609/525783249231842696,
+ 2-4567/2083967975041722089, 2-2273/4148770928197796067, 2-563/4110440884426500846,
+ 2-784/22895812812720260289, 2-1717/200571992854289218531, 2-368/171952226838388893139,
+ 2-149/278487845640434185590, 2-207/1547570041545500037992, 2-20/598094702046570062987,
+ 2-7/837332582865198088180]
end Real
diff --git a/Mathlib/Data/Real/Pi/Irrational.lean b/Mathlib/Data/Real/Pi/Irrational.lean
new file mode 100644
index 0000000000000..e3884b774698d
--- /dev/null
+++ b/Mathlib/Data/Real/Pi/Irrational.lean
@@ -0,0 +1,306 @@
+/-
+Copyright (c) 2022 Bhavik Mehta. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Bhavik Mehta
+-/
+import Mathlib.Analysis.SpecialFunctions.Integrals
+import Mathlib.Data.Real.Irrational
+import Mathlib.Topology.Algebra.Order.Floor
+
+/-!
+# `Real.pi` is irrational
+
+The main result of this file is `irrational_pi`.
+
+The proof is adapted from https://en.wikipedia.org/wiki/Proof_that_%CF%80_is_irrational#Cartwright's_proof.
+
+The proof idea is as follows.
+* Define a sequence of integrals `I n θ = ∫ x in (-1)..1, (1 - x ^ 2) ^ n * cos (x * θ)`.
+* Give a recursion formula for `I (n + 2) θ * θ ^ 2` in terms of `I n θ` and `I (n + 1) θ`.
+ Note we do not find it helpful to define `J` as in the above proof, and instead work directly
+ with `I`.
+* Define polynomials with integer coefficients `sinPoly n` and `cosPoly n` such that
+ `I n θ * θ ^ (2 * n + 1) = n ! * (sinPoly n θ * sin θ + cosPoly n θ * cos θ)`.
+ Note that in the informal proof, these polynomials are not defined explicitly, but we find it
+ useful to define them by recursion.
+* Show that both these polynomials have degree bounded by `n`.
+* Show that `0 < I n (π / 2) ≤ 2` for all `n`.
+* Now we can finish: if `π / 2` is rational, write it as `a / b` with `a, b > 0`. Then
+ `b ^ (2 * n + 1) * sinPoly n (a / b)` is a positive integer by the degree bound. But it is equal
+ to `a ^ (2 * n + 1) / n ! * I n (π / 2) ≤ 2 * a * (2 * n + 1) / n !`, which converges to 0 as
+ `n → ∞`.
+
+-/
+
+noncomputable section
+
+open intervalIntegral MeasureTheory.MeasureSpace Set Polynomial Real
+open scoped Nat
+
+/-- The sequence of integrals used for Cartwright's proof of irrationality of `π`. -/
+private def I (n : ℕ) (θ : ℝ) : ℝ := ∫ x in (-1)..1, (1 - x ^ 2) ^ n * cos (x * θ)
+
+variable {n : ℕ} {θ : ℝ}
+
+private lemma I_zero : I 0 θ * θ = 2 * sin θ := by
+ rw [mul_comm, I]
+ simp [mul_integral_comp_mul_right, two_mul]
+
+/--
+Auxiliary for the proof that `π` is irrational.
+While it is most natural to give the recursive formula for `I (n + 2) θ`, as well as give the second
+base case of `I 1 θ`, it is in fact more convenient to give the recursive formula for `I (n + 1) θ`
+in terms of `I n θ` and `I (n - 1) θ` (note the natural subtraction!).
+Despite the usually inconvenient subtraction, this in fact allows deducing both of the above facts
+with significantly fewer analysis computations.
+In addition, note the `0 ^ n` on the right hand side - this is intentional, and again allows
+combining the proof of the "usual" recursion formula and the base case `I 1 θ`.
+-/
+private lemma recursion' (n : ℕ) :
+ I (n + 1) θ * θ ^ 2 = - (2 * 2 * ((n + 1) * (0 ^ n * cos θ))) +
+ 2 * (n + 1) * (2 * n + 1) * I n θ - 4 * (n + 1) * n * I (n - 1) θ := by
+ rw [I]
+ let f (x : ℝ) : ℝ := 1 - x ^ 2
+ let u₁ (x : ℝ) : ℝ := f x ^ (n + 1)
+ let u₁' (x : ℝ) : ℝ := - (2 * (n + 1) * x * f x ^ n)
+ let v₁ (x : ℝ) : ℝ := sin (x * θ)
+ let v₁' (x : ℝ) : ℝ := cos (x * θ) * θ
+ let u₂ (x : ℝ) : ℝ := x * (f x) ^ n
+ let u₂' (x : ℝ) : ℝ := (f x) ^ n - 2 * n * x ^ 2 * (f x) ^ (n - 1)
+ let v₂ (x : ℝ) : ℝ := cos (x * θ)
+ let v₂' (x : ℝ) : ℝ := -sin (x * θ) * θ
+ have hfd : Continuous f := by fun_prop
+ have hu₁d : Continuous u₁' := by fun_prop
+ have hv₁d : Continuous v₁' := by fun_prop
+ have hu₂d : Continuous u₂' := by fun_prop
+ have hv₂d : Continuous v₂' := by fun_prop
+ have hu₁_eval_one : u₁ 1 = 0 := by simp only [u₁, f]; simp
+ have hu₁_eval_neg_one : u₁ (-1) = 0 := by simp only [u₁, f]; simp
+ have t : u₂ 1 * v₂ 1 - u₂ (-1) * v₂ (-1) = 2 * (0 ^ n * cos θ) := by simp [u₂, v₂, f, ← two_mul]
+ have hf (x) : HasDerivAt f (- 2 * x) x := by
+ convert (hasDerivAt_pow 2 x).const_sub 1 using 1
+ simp
+ have hu₁ (x) : HasDerivAt u₁ (u₁' x) x := by
+ convert (hf x).pow _ using 1
+ simp only [Nat.add_succ_sub_one, u₁', Nat.cast_add_one]
+ ring
+ have hv₁ (x) : HasDerivAt v₁ (v₁' x) x := (hasDerivAt_mul_const θ).sin
+ have hu₂ (x) : HasDerivAt u₂ (u₂' x) x := by
+ convert (hasDerivAt_id' x).mul ((hf x).pow _) using 1
+ simp only [u₂']
+ ring
+ have hv₂ (x) : HasDerivAt v₂ (v₂' x) x := (hasDerivAt_mul_const θ).cos
+ convert_to (∫ (x : ℝ) in (-1)..1, u₁ x * v₁' x) * θ = _ using 1
+ · simp_rw [u₁, v₁', ← intervalIntegral.integral_mul_const, sq θ, mul_assoc]
+ rw [integral_mul_deriv_eq_deriv_mul (fun x _ => hu₁ x) (fun x _ => hv₁ x)
+ (hu₁d.intervalIntegrable _ _) (hv₁d.intervalIntegrable _ _), hu₁_eval_one, hu₁_eval_neg_one,
+ zero_mul, zero_mul, sub_zero, zero_sub, ← integral_neg, ← integral_mul_const]
+ convert_to ((-2 : ℝ) * (n + 1)) * ∫ (x : ℝ) in (-1)..1, (u₂ x * v₂' x) = _ using 1
+ · rw [← integral_const_mul]
+ congr 1 with x
+ dsimp [u₁', v₁, u₂, v₂']
+ ring
+ rw [integral_mul_deriv_eq_deriv_mul (fun x _ => hu₂ x) (fun x _ => hv₂ x)
+ (hu₂d.intervalIntegrable _ _) (hv₂d.intervalIntegrable _ _),
+ mul_sub, t, neg_mul, neg_mul, neg_mul, sub_neg_eq_add]
+ have (x) : u₂' x = (2 * n + 1) * f x ^ n - 2 * n * f x ^ (n - 1) := by
+ cases n with
+ | zero => simp [u₂']
+ | succ n => ring!
+ simp_rw [this, sub_mul, mul_assoc _ _ (v₂ _)]
+ have : Continuous v₂ := by fun_prop
+ rw [mul_mul_mul_comm, integral_sub, mul_sub, add_sub_assoc]
+ · congr 1
+ simp_rw [integral_const_mul]
+ ring!
+ all_goals exact Continuous.intervalIntegrable (by fun_prop) _ _
+
+/--
+Auxiliary for the proof that `π` is irrational.
+The recursive formula for `I (n + 2) θ * θ ^ 2` in terms of `I n θ` and `I (n + 1) θ`.
+-/
+private lemma recursion (n : ℕ) :
+ I (n + 2) θ * θ ^ 2 =
+ 2 * (n + 2) * (2 * n + 3) * I (n + 1) θ - 4 * (n + 2) * (n + 1) * I n θ := by
+ rw [recursion' (n + 1)]
+ simp
+ ring!
+
+/--
+Auxiliary for the proof that `π` is irrational.
+The second base case for the induction on `n`, giving an explicit formula for `I 1 θ`.
+-/
+private lemma I_one : I 1 θ * θ ^ 3 = 4 * sin θ - 4 * θ * cos θ := by
+ rw [_root_.pow_succ, ← mul_assoc, recursion' 0, sub_mul, add_mul, mul_assoc _ (I 0 θ), I_zero]
+ ring
+
+/--
+Auxiliary for the proof that `π` is irrational.
+The first of the two integer-coefficient polynomials that describe the behaviour of the
+sequence of integrals `I`.
+While not given in the informal proof, these are easy to deduce from the recursion formulae.
+-/
+private def sinPoly : ℕ → ℤ[X]
+ | 0 => C 2
+ | 1 => C 4
+ | (n+2) => ((2 : ℤ) * (2 * n + 3)) • sinPoly (n + 1) + monomial 2 (-4) * sinPoly n
+
+/--
+Auxiliary for the proof that `π` is irrational.
+The second of the two integer-coefficient polynomials that describe the behaviour of the
+sequence of integrals `I`.
+While not given in the informal proof, these are easy to deduce from the recursion formulae.
+-/
+private def cosPoly : ℕ → ℤ[X]
+ | 0 => 0
+ | 1 => monomial 1 (-4)
+ | (n+2) => ((2 : ℤ) * (2 * n + 3)) • cosPoly (n + 1) + monomial 2 (-4) * cosPoly n
+
+/--
+Auxiliary for the proof that `π` is irrational.
+Prove a degree bound for `sinPoly n` by induction. Note this is where we find the value in an
+explicit description of `sinPoly`.
+-/
+private lemma sinPoly_natDegree_le : ∀ n : ℕ, (sinPoly n).natDegree ≤ n
+ | 0 => by simp [sinPoly]
+ | 1 => by simp only [natDegree_C, mul_one, zero_le', sinPoly]
+ | n + 2 => by
+ rw [sinPoly]
+ refine natDegree_add_le_of_degree_le ((natDegree_smul_le _ _).trans ?_) ?_
+ · exact (sinPoly_natDegree_le (n + 1)).trans (by simp)
+ refine natDegree_mul_le.trans ?_
+ simpa [add_comm 2] using sinPoly_natDegree_le n
+
+/--
+Auxiliary for the proof that `π` is irrational.
+Prove a degree bound for `cosPoly n` by induction. Note this is where we find the value in an
+explicit description of `cosPoly`.
+-/
+private lemma cosPoly_natDegree_le : ∀ n : ℕ, (cosPoly n).natDegree ≤ n
+ | 0 => by simp [cosPoly]
+ | 1 => (natDegree_monomial_le _).trans (by simp)
+ | n + 2 => by
+ rw [cosPoly]
+ refine natDegree_add_le_of_degree_le ((natDegree_smul_le _ _).trans ?_) ?_
+ · exact (cosPoly_natDegree_le (n + 1)).trans (by simp)
+ exact natDegree_mul_le.trans (by simp [add_comm 2, cosPoly_natDegree_le n])
+
+/--
+Auxiliary for the proof that `π` is irrational.
+The key lemma: the sequence of integrals `I` can be written as a linear combination of `sin` and
+`cos`, with coefficients given by the polynomials `sinPoly` and `cosPoly`.
+-/
+private lemma sinPoly_add_cosPoly_eval (θ : ℝ) :
+ ∀ n : ℕ,
+ I n θ * θ ^ (2 * n + 1) = n ! * ((sinPoly n).eval₂ (Int.castRingHom _) θ * sin θ +
+ (cosPoly n).eval₂ (Int.castRingHom _) θ * cos θ)
+ | 0 => by simp [sinPoly, cosPoly, I_zero]
+ | 1 => by simp [I_one, sinPoly, cosPoly, sub_eq_add_neg]
+ | n + 2 => by
+ calc I (n + 2) θ * θ ^ (2 * (n + 2) + 1) = I (n + 2) θ * θ ^ 2 * θ ^ (2 * n + 3) := by ring
+ _ = 2 * (n + 2) * (2 * n + 3) * (I (n + 1) θ * θ ^ (2 * (n + 1) + 1)) -
+ 4 * (n + 2) * (n + 1) * θ ^ 2 * (I n θ * θ ^ (2 * n + 1)) := by rw [recursion]; ring
+ _ = _ := by simp [sinPoly_add_cosPoly_eval, sinPoly, cosPoly, Nat.factorial_succ]; ring
+
+/--
+Auxiliary for the proof that `π` is irrational.
+For a polynomial `p` with natural degree `≤ k` and integer coefficients, evaluating `p` at a
+rational `a / b` gives a rational of the form `z / b ^ k`.
+TODO: should this be moved elsewhere? It uses none of the pi-specific definitions.
+-/
+private lemma is_integer {p : ℤ[X]} (a b : ℤ) {k : ℕ} (hp : p.natDegree ≤ k) :
+ ∃ z : ℤ, p.eval₂ (Int.castRingHom ℝ) (a / b) * b ^ k = z := by
+ rcases eq_or_ne b 0 with rfl | hb
+ · rcases k.eq_zero_or_pos with rfl | hk
+ · exact ⟨p.coeff 0, by simp⟩
+ exact ⟨0, by simp [hk.ne']⟩
+ refine ⟨∑ i in p.support, p.coeff i * a ^ i * b ^ (k - i), ?_⟩
+ conv => lhs; rw [← sum_monomial_eq p]
+ rw [eval₂_sum, sum, Finset.sum_mul, Int.cast_sum]
+ simp only [eval₂_monomial, eq_intCast, div_pow, Int.cast_mul, Int.cast_pow]
+ refine Finset.sum_congr rfl (fun i hi => ?_)
+ have ik := (le_natDegree_of_mem_supp i hi).trans hp
+ rw [mul_assoc, div_mul_comm, ← Int.cast_pow, ← Int.cast_pow, ← Int.cast_pow,
+ ← pow_sub_mul_pow b ik, ← Int.cast_div_charZero, Int.mul_ediv_cancel _ (pow_ne_zero _ hb),
+ ← mul_assoc, mul_right_comm, ← Int.cast_pow]
+ exact dvd_mul_left _ _
+
+open Filter
+
+/--
+Auxiliary for the proof that `π` is irrational.
+The integrand in the definition of `I` is nonnegative and takes a positive value at least one point,
+so the integral is positive.
+-/
+private lemma I_pos : 0 < I n (π / 2) := by
+ refine integral_pos (by norm_num) (Continuous.continuousOn (by continuity)) ?_ ⟨0, by simp⟩
+ refine fun x hx => mul_nonneg (pow_nonneg ?_ _) ?_
+ · rw [sub_nonneg, sq_le_one_iff_abs_le_one, abs_le]
+ exact ⟨hx.1.le, hx.2⟩
+ refine cos_nonneg_of_neg_pi_div_two_le_of_le ?_ ?_ <;>
+ nlinarith [hx.1, hx.2, pi_pos]
+
+/--
+Auxiliary for the proof that `π` is irrational.
+The integrand in the definition of `I` is bounded by 1 and the interval has length 2, so the
+integral is bounded above by `2`.
+-/
+private lemma I_le (n : ℕ) : I n (π / 2) ≤ 2 := by
+ rw [← norm_of_nonneg I_pos.le]
+ refine (norm_integral_le_of_norm_le_const ?_).trans (show (1 : ℝ) * _ ≤ _ by norm_num)
+ intros x hx
+ simp only [uIoc_of_le, neg_le_self_iff, zero_le_one, mem_Ioc] at hx
+ rw [norm_eq_abs, abs_mul, abs_pow]
+ refine mul_le_one₀ (pow_le_one₀ (abs_nonneg _) ?_) (abs_nonneg _) (abs_cos_le_one _)
+ rw [abs_le]
+ constructor <;> nlinarith
+
+/--
+Auxiliary for the proof that `π` is irrational.
+For any real `a`, we have that `a ^ (2n+1) / n!` tends to `0` as `n → ∞`. This is just a
+reformulation of tendsto_pow_div_factorial_atTop, which asserts the same for `a ^ n / n!`
+-/
+private lemma tendsto_pow_div_factorial_at_top_aux (a : ℝ) :
+ Tendsto (fun n => (a : ℝ) ^ (2 * n + 1) / n !) atTop (nhds 0) := by
+ rw [← mul_zero a]
+ refine ((FloorSemiring.tendsto_pow_div_factorial_atTop (a ^ 2)).const_mul a).congr (fun x => ?_)
+ rw [← pow_mul, mul_div_assoc', _root_.pow_succ']
+
+/-- If `x` is rational, it can be written as `a / b` with `a : ℤ` and `b : ℕ` satisfying `b > 0`. -/
+private lemma not_irrational_exists_rep {x : ℝ} :
+ ¬Irrational x → ∃ (a : ℤ) (b : ℕ), 0 < b ∧ x = a / b := by
+ rw [Irrational, not_not, mem_range]
+ rintro ⟨q, rfl⟩
+ exact ⟨q.num, q.den, q.pos, by exact_mod_cast (Rat.num_div_den _).symm⟩
+
+@[simp] theorem irrational_pi : Irrational π := by
+ apply Irrational.of_div_nat 2
+ rw [Nat.cast_two]
+ by_contra h'
+ obtain ⟨a, b, hb, h⟩ := not_irrational_exists_rep h'
+ have ha : (0 : ℝ) < a := by
+ have : 0 < (a : ℝ) / b := h ▸ pi_div_two_pos
+ rwa [lt_div_iff₀ (by positivity), zero_mul] at this
+ have k (n : ℕ) : 0 < (a : ℝ) ^ (2 * n + 1) / n ! := by positivity
+ have j : ∀ᶠ n : ℕ in atTop, (a : ℝ) ^ (2 * n + 1) / n ! * I n (π / 2) < 1 := by
+ have := eventually_lt_of_tendsto_lt (show (0 : ℝ) < 1 / 2 by norm_num)
+ (tendsto_pow_div_factorial_at_top_aux a)
+ filter_upwards [this] with n hn
+ rw [lt_div_iff₀ (zero_lt_two : (0 : ℝ) < 2)] at hn
+ exact hn.trans_le' (mul_le_mul_of_nonneg_left (I_le _) (by positivity))
+ obtain ⟨n, hn⟩ := j.exists
+ have hn' : 0 < a ^ (2 * n + 1) / n ! * I n (π / 2) := mul_pos (k _) I_pos
+ obtain ⟨z, hz⟩ : ∃ z : ℤ, (sinPoly n).eval₂ (Int.castRingHom ℝ) (a / b) * b ^ (2 * n + 1) = z :=
+ is_integer a b ((sinPoly_natDegree_le _).trans (by linarith))
+ have e := sinPoly_add_cosPoly_eval (π / 2) n
+ rw [cos_pi_div_two, sin_pi_div_two, mul_zero, mul_one, add_zero] at e
+ have : a ^ (2 * n + 1) / n ! * I n (π / 2) =
+ eval₂ (Int.castRingHom ℝ) (π / 2) (sinPoly n) * b ^ (2 * n + 1) := by
+ nth_rw 2 [h] at e
+ field_simp at e ⊢
+ linear_combination e
+ have : (0 : ℝ) < z ∧ (z : ℝ) < 1 := by simp [← hz, ← h, ← this, hn', hn]
+ norm_cast at this
+ omega
+
+end
diff --git a/Mathlib/Data/Real/Pointwise.lean b/Mathlib/Data/Real/Pointwise.lean
index bb83de2135f9c..8672dab314d36 100644
--- a/Mathlib/Data/Real/Pointwise.lean
+++ b/Mathlib/Data/Real/Pointwise.lean
@@ -6,6 +6,7 @@ Authors: Yaël Dillies, Eric Wieser
import Mathlib.Algebra.Order.Module.OrderedSMul
import Mathlib.Algebra.Order.Module.Pointwise
import Mathlib.Data.Real.Archimedean
+import Mathlib.Data.Set.Pointwise.SMul
/-!
# Pointwise operations on sets of reals
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 2f8667ca00005..0cb816198ffd8 100644
--- a/Mathlib/Data/Seq/Computation.lean
+++ b/Mathlib/Data/Seq/Computation.lean
@@ -503,8 +503,8 @@ theorem length_thinkN (s : Computation α) [_h : Terminates s] (n) :
theorem eq_thinkN {s : Computation α} {a n} (h : Results s a n) : s = thinkN (pure a) n := by
revert s
- induction n with | zero => _ | succ n IH => _
- all_goals intro s; apply recOn s (fun a' => _) fun s => _ <;> intro a h
+ induction n with | zero => _ | succ n IH => _ <;>
+ (intro s; apply recOn s (fun a' => _) fun s => _) <;> intro a h
· rw [← eq_of_pure_mem h.mem]
rfl
· cases' of_results_think h with n h
@@ -695,7 +695,7 @@ theorem length_bind (s : Computation α) (f : α → Computation β) [_T1 : Term
theorem of_results_bind {s : Computation α} {f : α → Computation β} {b k} :
Results (bind s f) b k → ∃ a m n, Results s a m ∧ Results (f a) b n ∧ k = n + m := by
induction k generalizing s with | zero => _ | succ n IH => _
- all_goals apply recOn s (fun a => _) fun s' => _ <;> intro e h
+ <;> apply recOn s (fun a => _) fun s' => _ <;> intro e h
· simp only [ret_bind] at h
exact ⟨e, _, _, results_pure _, h, rfl⟩
· have := congr_arg head (eq_thinkN h)
@@ -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 8a167a30145c9..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
@@ -717,12 +716,9 @@ theorem head_terminates_of_head_tail_terminates (s : WSeq α) [T : Terminates (h
Terminates (head s) :=
(head_terminates_iff _).2 <| by
rcases (head_terminates_iff _).1 T with ⟨⟨a, h⟩⟩
- simp? [tail] at h says simp only [tail, destruct_flatten] at h
+ simp? [tail] at h says simp only [tail, destruct_flatten, bind_map_left] at h
rcases exists_of_mem_bind h with ⟨s', h1, _⟩
- unfold Functor.map at h1
- exact
- let ⟨t, h3, _⟩ := Computation.exists_of_mem_map h1
- Computation.terminates_of_mem h3
+ exact terminates_of_mem h1
theorem destruct_some_of_destruct_tail_some {s : WSeq α} {a} (h : some a ∈ destruct (tail s)) :
∃ a', some a' ∈ destruct s := by
@@ -878,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 dba783a5ea356..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
@@ -622,11 +618,11 @@ theorem union_self (a : Set α) : a ∪ a = a :=
@[simp]
theorem union_empty (a : Set α) : a ∪ ∅ = a :=
- ext fun _ => or_false_iff _
+ ext fun _ => iff_of_eq (or_false _)
@[simp]
theorem empty_union (a : Set α) : ∅ ∪ a = a :=
- ext fun _ => false_or_iff _
+ ext fun _ => iff_of_eq (false_or _)
theorem union_comm (a b : Set α) : a ∪ b = b ∪ a :=
ext fun _ => or_comm
@@ -740,11 +736,11 @@ theorem inter_self (a : Set α) : a ∩ a = a :=
@[simp]
theorem inter_empty (a : Set α) : a ∩ ∅ = ∅ :=
- ext fun _ => and_false_iff _
+ ext fun _ => iff_of_eq (and_false _)
@[simp]
theorem empty_inter (a : Set α) : ∅ ∩ a = ∅ :=
- ext fun _ => false_and_iff _
+ ext fun _ => iff_of_eq (false_and _)
theorem inter_comm (a b : Set α) : a ∩ b = b ∩ a :=
ext fun _ => and_comm
@@ -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
@@ -1134,21 +1146,17 @@ theorem sep_eq_self_iff_mem_true : { x ∈ s | p x } = s ↔ ∀ x ∈ s, p x :=
@[simp]
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_iff, not_and]
+ 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}
@@ -1187,7 +1195,7 @@ theorem Nonempty.subset_singleton_iff (h : s.Nonempty) : s ⊆ {a} ↔ s = {a} :
subset_singleton_iff_eq.trans <| or_iff_right h.ne_empty
theorem ssubset_singleton_iff {s : Set α} {x : α} : s ⊂ {x} ↔ s = ∅ := by
- rw [ssubset_iff_subset_ne, subset_singleton_iff_eq, or_and_right, and_not_self_iff, or_false_iff,
+ rw [ssubset_iff_subset_ne, subset_singleton_iff_eq, or_and_right, and_not_self_iff, or_false,
and_iff_left_iff_imp]
exact fun h => h ▸ (singleton_ne_empty _).symm
@@ -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
@@ -1581,7 +1598,7 @@ theorem insert_diff_self_of_not_mem {a : α} {s : Set α} (h : a ∉ s) : insert
theorem insert_diff_eq_singleton {a : α} {s : Set α} (h : a ∉ s) : insert a s \ s = {a} := by
ext
rw [Set.mem_diff, Set.mem_insert_iff, Set.mem_singleton_iff, or_and_right, and_not_self_iff,
- or_false_iff, and_iff_left_iff_imp]
+ or_false, and_iff_left_iff_imp]
rintro rfl
exact h
@@ -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
@@ -1958,7 +1936,7 @@ open Set
namespace Function
-variable {ι : Sort*} {α : Type*} {β : Type*} {f : α → β}
+variable {α : Type*} {β : Type*}
theorem Injective.nonempty_apply_iff {f : Set α → Set β} (hf : Injective f) (h2 : f ∅ = ∅)
{s : Set α} : (f s).Nonempty ↔ s.Nonempty := by
@@ -2141,7 +2119,7 @@ end Monotone
/-! ### Disjoint sets -/
-variable {α β : Type*} {s t u : Set α} {f : α → β}
+variable {α : Type*} {s t u : Set α}
namespace Disjoint
diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean
index 5a5ef3d7719d6..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]
@@ -616,6 +615,15 @@ theorem ncard_exchange' {a b : α} (ha : a ∉ s) (hb : b ∈ s) :
rw [← ncard_exchange ha hb, ← singleton_union, ← singleton_union, union_diff_distrib,
@diff_singleton_eq_self _ b {a} fun h ↦ ha (by rwa [← mem_singleton_iff.mp h])]
+lemma odd_card_insert_iff {a : α} (hs : s.Finite := by toFinite_tac) (ha : a ∉ s) :
+ Odd (insert a s).ncard ↔ Even s.ncard := by
+ rw [ncard_insert_of_not_mem ha hs, Nat.odd_add]
+ simp only [Nat.odd_add, ← Nat.not_even_iff_odd, Nat.not_even_one, iff_false, Decidable.not_not]
+
+lemma even_card_insert_iff {a : α} (hs : s.Finite := by toFinite_tac) (ha : a ∉ s) :
+ Even (insert a s).ncard ↔ Odd s.ncard := by
+ rw [ncard_insert_of_not_mem ha hs, Nat.even_add_one, Nat.not_even_iff_odd]
+
end InsertErase
variable {f : α → β}
@@ -992,6 +1000,12 @@ theorem one_lt_ncard_iff (hs : s.Finite := by toFinite_tac) :
rw [one_lt_ncard hs]
simp only [exists_prop, exists_and_left]
+lemma one_lt_ncard_of_nonempty_of_even (hs : Set.Finite s) (hn : Set.Nonempty s := by toFinite_tac)
+ (he : Even (s.ncard)) : 1 < s.ncard := by
+ rw [← Set.ncard_pos hs] at hn
+ have : s.ncard ≠ 1 := fun h ↦ by simp [h] at he
+ omega
+
theorem two_lt_ncard_iff (hs : s.Finite := by toFinite_tac) :
2 < s.ncard ↔ ∃ a b c, a ∈ s ∧ b ∈ s ∧ c ∈ s ∧ a ≠ b ∧ a ≠ c ∧ b ≠ c := by
simp_rw [ncard_eq_toFinset_card _ hs, Finset.two_lt_card_iff, Finite.mem_toFinset]
@@ -1035,7 +1049,4 @@ theorem ncard_eq_three : s.ncard = 3 ↔ ∃ x y z, x ≠ y ∧ x ≠ z ∧ y
simp [h]
end ncard
-
-@[deprecated (since := "2023-12-27")] alias ncard_le_of_subset := ncard_le_ncard
-
end Set
diff --git a/Mathlib/Data/Set/Countable.lean b/Mathlib/Data/Set/Countable.lean
index 074e6b876960c..4add89c35bb25 100644
--- a/Mathlib/Data/Set/Countable.lean
+++ b/Mathlib/Data/Set/Countable.lean
@@ -226,7 +226,7 @@ theorem Countable.of_diff {s t : Set α} (h : (s \ t).Countable) (ht : t.Countab
@[simp]
theorem countable_insert {s : Set α} {a : α} : (insert a s).Countable ↔ s.Countable := by
- simp only [insert_eq, countable_union, countable_singleton, true_and_iff]
+ simp only [insert_eq, countable_union, countable_singleton, true_and]
protected theorem Countable.insert {s : Set α} (a : α) (h : s.Countable) : (insert a s).Countable :=
countable_insert.2 h
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 3807e40b76e3c..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.Finset.Basic
-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]
@@ -897,7 +895,7 @@ theorem exists_subset_image_finite_and {f : α → β} {s : Set α} {p : Set β
(∃ t ⊆ f '' s, t.Finite ∧ p t) ↔ ∃ t ⊆ s, t.Finite ∧ p (f '' t) := by
classical
simp_rw [@and_comm (_ ⊆ _), and_assoc, exists_finite_iff_finset, @and_comm (p _),
- Finset.subset_image_iff]
+ Finset.subset_set_image_iff]
aesop
section Pi
@@ -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
@@ -1528,6 +1523,7 @@ protected theorem bddBelow [SemilatticeInf α] [Nonempty α] (s : Finset α) : B
end Finset
+section LinearOrder
variable [LinearOrder α] {s : Set α}
/-- If a linear order does not contain any triple of elements `x < y < z`, then this type
@@ -1568,4 +1564,19 @@ theorem DirectedOn.exists_mem_subset_of_finset_subset_biUnion {α ι : Type*} {f
haveI := hn.coe_sort
simpa using (directed_comp.2 hc.directed_val).exists_mem_subset_of_finset_subset_biUnion hs
+end LinearOrder
+
+namespace List
+variable (α) [Finite α] (n : ℕ)
+
+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
+
+lemma finite_length_le : {l : List α | l.length ≤ n}.Finite := by
+ simpa [Nat.lt_succ_iff] using finite_length_lt α (n + 1)
+
+end List
+
set_option linter.style.longFile 1700
diff --git a/Mathlib/Data/Set/Function.lean b/Mathlib/Data/Set/Function.lean
index 56e1886f2c539..230e18833cc9c 100644
--- a/Mathlib/Data/Set/Function.lean
+++ b/Mathlib/Data/Set/Function.lean
@@ -44,11 +44,13 @@ section restrict
takes an argument `↥s` instead of `Subtype s`. -/
def restrict (s : Set α) (f : ∀ a : α, π a) : ∀ a : s, π a := fun x => f x
+theorem restrict_def (s : Set α) : s.restrict (π := π) = fun f x ↦ f x := rfl
+
theorem restrict_eq (f : α → β) (s : Set α) : s.restrict f = f ∘ Subtype.val :=
rfl
@[simp]
-theorem restrict_apply (f : α → β) (s : Set α) (x : s) : s.restrict f x = f x :=
+theorem restrict_apply (f : (a : α) → π a) (s : Set α) (x : s) : s.restrict f x = f x :=
rfl
theorem restrict_eq_iff {f : ∀ a, π a} {s : Set α} {g : ∀ a : s, π a} :
@@ -110,6 +112,20 @@ theorem restrict_extend_compl_range (f : α → β) (g : α → γ) (g' : β →
classical
exact restrict_dite_compl _ _
+/-- If a function `f` is restricted to a set `t`, and `s ⊆ t`, this is the restriction to `s`. -/
+@[simp]
+def restrict₂ {s t : Set α} (hst : s ⊆ t) (f : ∀ a : t, π a) : ∀ a : s, π a :=
+ fun x => f ⟨x.1, hst x.2⟩
+
+theorem restrict₂_def {s t : Set α} (hst : s ⊆ t) :
+ restrict₂ (π := π) hst = fun f x ↦ f ⟨x.1, hst x.2⟩ := rfl
+
+theorem restrict₂_comp_restrict {s t : Set α} (hst : s ⊆ t) :
+ (restrict₂ (π := π) hst) ∘ t.restrict = s.restrict := rfl
+
+theorem restrict₂_comp_restrict₂ {s t u : Set α} (hst : s ⊆ t) (htu : t ⊆ u) :
+ (restrict₂ (π := π) hst) ∘ (restrict₂ htu) = restrict₂ (hst.trans htu) := rfl
+
theorem range_extend_subset (f : α → β) (g : α → γ) (g' : β → γ) :
range (extend f g g') ⊆ range g ∪ g' '' (range f)ᶜ := by
classical
@@ -150,8 +166,7 @@ end restrict
/-! ### Equality on a set -/
section equality
-variable {s s₁ s₂ : Set α} {t t₁ t₂ : Set β} {p : Set γ} {f f₁ f₂ f₃ : α → β} {g g₁ g₂ : β → γ}
- {f' f₁' f₂' : β → α} {g' : γ → β} {a : α} {b : β}
+variable {s s₁ s₂ : Set α} {f₁ f₂ f₃ : α → β} {g : β → γ} {a : α}
@[simp]
theorem eqOn_empty (f₁ f₂ : α → β) : EqOn f₁ f₂ ∅ := fun _ => False.elim
@@ -217,78 +232,7 @@ alias ⟨EqOn.comp_eq, _⟩ := eqOn_range
end equality
-/-! ### Congruence lemmas for monotonicity and antitonicity -/
-section Order
-
-variable {s : Set α} {f₁ f₂ : α → β} [Preorder α] [Preorder β]
-
-theorem _root_.MonotoneOn.congr (h₁ : MonotoneOn f₁ s) (h : s.EqOn f₁ f₂) : MonotoneOn f₂ s := by
- intro a ha b hb hab
- rw [← h ha, ← h hb]
- exact h₁ ha hb hab
-
-theorem _root_.AntitoneOn.congr (h₁ : AntitoneOn f₁ s) (h : s.EqOn f₁ f₂) : AntitoneOn f₂ s :=
- h₁.dual_right.congr h
-
-theorem _root_.StrictMonoOn.congr (h₁ : StrictMonoOn f₁ s) (h : s.EqOn f₁ f₂) :
- StrictMonoOn f₂ s := by
- intro a ha b hb hab
- rw [← h ha, ← h hb]
- exact h₁ ha hb hab
-
-theorem _root_.StrictAntiOn.congr (h₁ : StrictAntiOn f₁ s) (h : s.EqOn f₁ f₂) : StrictAntiOn f₂ s :=
- h₁.dual_right.congr h
-
-theorem EqOn.congr_monotoneOn (h : s.EqOn f₁ f₂) : MonotoneOn f₁ s ↔ MonotoneOn f₂ s :=
- ⟨fun h₁ => h₁.congr h, fun h₂ => h₂.congr h.symm⟩
-
-theorem EqOn.congr_antitoneOn (h : s.EqOn f₁ f₂) : AntitoneOn f₁ s ↔ AntitoneOn f₂ s :=
- ⟨fun h₁ => h₁.congr h, fun h₂ => h₂.congr h.symm⟩
-
-theorem EqOn.congr_strictMonoOn (h : s.EqOn f₁ f₂) : StrictMonoOn f₁ s ↔ StrictMonoOn f₂ s :=
- ⟨fun h₁ => h₁.congr h, fun h₂ => h₂.congr h.symm⟩
-
-theorem EqOn.congr_strictAntiOn (h : s.EqOn f₁ f₂) : StrictAntiOn f₁ s ↔ StrictAntiOn f₂ s :=
- ⟨fun h₁ => h₁.congr h, fun h₂ => h₂.congr h.symm⟩
-
-end Order
-
-/-! ### Monotonicity lemmas -/
-section Mono
-
-variable {s s₁ s₂ : Set α} {f f₁ f₂ : α → β} [Preorder α] [Preorder β]
-
-theorem _root_.MonotoneOn.mono (h : MonotoneOn f s) (h' : s₂ ⊆ s) : MonotoneOn f s₂ :=
- fun _ hx _ hy => h (h' hx) (h' hy)
-
-theorem _root_.AntitoneOn.mono (h : AntitoneOn f s) (h' : s₂ ⊆ s) : AntitoneOn f s₂ :=
- fun _ hx _ hy => h (h' hx) (h' hy)
-
-theorem _root_.StrictMonoOn.mono (h : StrictMonoOn f s) (h' : s₂ ⊆ s) : StrictMonoOn f s₂ :=
- fun _ hx _ hy => h (h' hx) (h' hy)
-
-theorem _root_.StrictAntiOn.mono (h : StrictAntiOn f s) (h' : s₂ ⊆ s) : StrictAntiOn f s₂ :=
- fun _ hx _ hy => h (h' hx) (h' hy)
-
-protected theorem _root_.MonotoneOn.monotone (h : MonotoneOn f s) :
- Monotone (f ∘ Subtype.val : s → β) :=
- fun x y hle => h x.coe_prop y.coe_prop hle
-
-protected theorem _root_.AntitoneOn.monotone (h : AntitoneOn f s) :
- Antitone (f ∘ Subtype.val : s → β) :=
- fun x y hle => h x.coe_prop y.coe_prop hle
-
-protected theorem _root_.StrictMonoOn.strictMono (h : StrictMonoOn f s) :
- StrictMono (f ∘ Subtype.val : s → β) :=
- fun x y hlt => h x.coe_prop y.coe_prop hlt
-
-protected theorem _root_.StrictAntiOn.strictAnti (h : StrictAntiOn f s) :
- StrictAnti (f ∘ Subtype.val : s → β) :=
- fun x y hlt => h x.coe_prop y.coe_prop hlt
-
-end Mono
-
-variable {s s₁ s₂ : Set α} {t t₁ t₂ : Set β} {p : Set γ} {f f₁ f₂ f₃ : α → β} {g g₁ g₂ : β → γ}
+variable {s s₁ s₂ : Set α} {t t₁ t₂ : Set β} {p : Set γ} {f f₁ f₂ : α → β} {g g₁ g₂ : β → γ}
{f' f₁' f₂' : β → α} {g' : γ → β} {a : α} {b : β}
section MapsTo
@@ -328,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 :=
@@ -337,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 :=
@@ -417,6 +361,9 @@ theorem mapsTo_union : MapsTo f (s₁ ∪ s₂) t ↔ MapsTo f s₁ t ∧ MapsTo
theorem MapsTo.inter (h₁ : MapsTo f s t₁) (h₂ : MapsTo f s t₂) : MapsTo f s (t₁ ∩ t₂) := fun _ hx =>
⟨h₁ hx, h₂ hx⟩
+lemma MapsTo.insert (h : MapsTo f s t) (x : α) : MapsTo f (insert x s) (insert (f x) t) := by
+ simpa [← singleton_union] using h.mono_right subset_union_right
+
theorem MapsTo.inter_inter (h₁ : MapsTo f s₁ t₁) (h₂ : MapsTo f s₂ t₂) :
MapsTo f (s₁ ∩ s₂) (t₁ ∩ t₂) := fun _ hx => ⟨h₁ hx.1, h₂ hx.2⟩
@@ -437,11 +384,6 @@ theorem mapsTo_image_iff {f : α → β} {g : γ → α} {s : Set γ} {t : Set
MapsTo f (g '' s) t ↔ MapsTo (f ∘ g) s t :=
⟨fun h c hc => h ⟨c, hc, rfl⟩, fun h _ ⟨_, hc⟩ => hc.2 ▸ h hc.1⟩
-@[deprecated (since := "2023-12-25")]
-lemma maps_image_to (f : α → β) (g : γ → α) (s : Set γ) (t : Set β) :
- MapsTo f (g '' s) t ↔ MapsTo (f ∘ g) s t :=
- mapsTo_image_iff
-
lemma MapsTo.comp_left (g : β → γ) (hf : MapsTo f s t) : MapsTo (g ∘ f) s (g '' t) :=
fun x hx ↦ ⟨f x, hf hx, rfl⟩
@@ -452,10 +394,6 @@ lemma MapsTo.comp_right {s : Set β} {t : Set γ} (hg : MapsTo g s t) (f : α
lemma mapsTo_univ_iff : MapsTo f univ t ↔ ∀ x, f x ∈ t :=
⟨fun h _ => h (mem_univ _), fun h x _ => h x⟩
-@[deprecated (since := "2023-12-25")]
-theorem maps_univ_to (f : α → β) (s : Set β) : MapsTo f univ s ↔ ∀ a, f a ∈ s :=
- mapsTo_univ_iff
-
@[simp]
lemma mapsTo_range_iff {g : ι → α} : MapsTo f (range g) t ↔ ∀ i, f (g i) ∈ t :=
forall_mem_range
@@ -502,8 +440,6 @@ theorem preimage_restrictPreimage {u : Set t} :
rw [← preimage_preimage (g := f) (f := Subtype.val), ← image_val_preimage_restrictPreimage,
preimage_image_eq _ Subtype.val_injective]
-variable {U : ι → Set β}
-
lemma restrictPreimage_injective (hf : Injective f) : Injective (t.restrictPreimage f) :=
fun _ _ e => Subtype.coe_injective <| hf <| Subtype.mk.inj e
@@ -608,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⟩⟩
@@ -689,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 :=
@@ -709,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 ↦ ?_⟩
@@ -930,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
@@ -986,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 -/
@@ -1312,23 +1301,6 @@ lemma bijOn_comm {g : β → α} (h : InvOn f g t s) : BijOn f s t ↔ BijOn g t
end Set
-/-! ### Monotone -/
-namespace Monotone
-
-variable [Preorder α] [Preorder β] {f : α → β}
-
-protected theorem restrict (h : Monotone f) (s : Set α) : Monotone (s.restrict f) := fun _ _ hxy =>
- h hxy
-
-protected theorem codRestrict (h : Monotone f) {s : Set β} (hs : ∀ x, f x ∈ s) :
- Monotone (s.codRestrict f hs) :=
- h
-
-protected theorem rangeFactorization (h : Monotone f) : Monotone (Set.rangeFactorization f) :=
- h
-
-end Monotone
-
/-! ### Piecewise defined function -/
namespace Set
@@ -1351,10 +1323,6 @@ theorem piecewise_insert_self {j : α} [∀ i, Decidable (i ∈ insert j s)] :
variable [∀ j, Decidable (j ∈ s)]
--- TODO: move!
-instance Compl.decidableMem (j : α) : Decidable (j ∈ sᶜ) :=
- instDecidableNot
-
theorem piecewise_insert [DecidableEq α] (j : α) [∀ i, Decidable (i ∈ insert j s)] :
(insert j s).piecewise f g = Function.update (s.piecewise f g) j (f j) := by
simp (config := { unfoldPartialApp := true }) only [piecewise, mem_insert_iff]
@@ -1395,11 +1363,14 @@ theorem le_piecewise {δ : α → Type*} [∀ i, Preorder (δ i)] {s : Set α} [
g ≤ s.piecewise f₁ f₂ :=
@piecewise_le α (fun i => (δ i)ᵒᵈ) _ s _ _ _ _ h₁ h₂
-theorem piecewise_le_piecewise {δ : α → Type*} [∀ i, Preorder (δ i)] {s : Set α}
+@[gcongr]
+theorem piecewise_mono {δ : α → Type*} [∀ i, Preorder (δ i)] {s : Set α}
[∀ j, Decidable (j ∈ s)] {f₁ f₂ g₁ g₂ : ∀ i, δ i} (h₁ : ∀ i ∈ s, f₁ i ≤ g₁ i)
(h₂ : ∀ i ∉ s, f₂ i ≤ g₂ i) : s.piecewise f₁ f₂ ≤ s.piecewise g₁ g₂ := by
apply piecewise_le <;> intros <;> simp [*]
+@[deprecated (since := "2024-10-06")] alias piecewise_le_piecewise := piecewise_mono
+
@[simp]
theorem piecewise_insert_of_ne {i j : α} (h : i ≠ j) [∀ i, Decidable (i ∈ insert j s)] :
(insert j s).piecewise f g i = s.piecewise f g i := by simp [piecewise, h]
@@ -1494,46 +1465,6 @@ theorem univ_pi_piecewise_univ {ι : Type*} {α : ι → Type*} (s : Set ι) (t
end Set
-section strictMono
-
-theorem StrictMonoOn.injOn [LinearOrder α] [Preorder β] {f : α → β} {s : Set α}
- (H : StrictMonoOn f s) : s.InjOn f := fun x hx y hy hxy =>
- show Ordering.eq.Compares x y from (H.compares hx hy).1 hxy
-
-theorem StrictAntiOn.injOn [LinearOrder α] [Preorder β] {f : α → β} {s : Set α}
- (H : StrictAntiOn f s) : s.InjOn f :=
- @StrictMonoOn.injOn α βᵒᵈ _ _ f s H
-
-theorem StrictMonoOn.comp [Preorder α] [Preorder β] [Preorder γ] {g : β → γ} {f : α → β} {s : Set α}
- {t : Set β} (hg : StrictMonoOn g t) (hf : StrictMonoOn f s) (hs : Set.MapsTo f s t) :
- StrictMonoOn (g ∘ f) s := fun _x hx _y hy hxy => hg (hs hx) (hs hy) <| hf hx hy hxy
-
-theorem StrictMonoOn.comp_strictAntiOn [Preorder α] [Preorder β] [Preorder γ] {g : β → γ}
- {f : α → β} {s : Set α} {t : Set β} (hg : StrictMonoOn g t) (hf : StrictAntiOn f s)
- (hs : Set.MapsTo f s t) : StrictAntiOn (g ∘ f) s := fun _x hx _y hy hxy =>
- hg (hs hy) (hs hx) <| hf hx hy hxy
-
-theorem StrictAntiOn.comp [Preorder α] [Preorder β] [Preorder γ] {g : β → γ} {f : α → β} {s : Set α}
- {t : Set β} (hg : StrictAntiOn g t) (hf : StrictAntiOn f s) (hs : Set.MapsTo f s t) :
- StrictMonoOn (g ∘ f) s := fun _x hx _y hy hxy => hg (hs hy) (hs hx) <| hf hx hy hxy
-
-theorem StrictAntiOn.comp_strictMonoOn [Preorder α] [Preorder β] [Preorder γ] {g : β → γ}
- {f : α → β} {s : Set α} {t : Set β} (hg : StrictAntiOn g t) (hf : StrictMonoOn f s)
- (hs : Set.MapsTo f s t) : StrictAntiOn (g ∘ f) s := fun _x hx _y hy hxy =>
- hg (hs hx) (hs hy) <| hf hx hy hxy
-
-@[simp]
-theorem strictMono_restrict [Preorder α] [Preorder β] {f : α → β} {s : Set α} :
- StrictMono (s.restrict f) ↔ StrictMonoOn f s := by simp [Set.restrict, StrictMono, StrictMonoOn]
-
-alias ⟨_root_.StrictMono.of_restrict, _root_.StrictMonoOn.restrict⟩ := strictMono_restrict
-
-theorem StrictMono.codRestrict [Preorder α] [Preorder β] {f : α → β} (hf : StrictMono f)
- {s : Set β} (hs : ∀ x, f x ∈ s) : StrictMono (Set.codRestrict f s hs) :=
- hf
-
-end strictMono
-
namespace Function
open Set
@@ -1621,21 +1552,9 @@ theorem update_comp_eq_of_not_mem_range {α : Sort*} {β : Type*} {γ : Sort*} [
theorem insert_injOn (s : Set α) : sᶜ.InjOn fun a => insert a s := fun _a ha _ _ =>
(insert_inj ha).1
-theorem monotoneOn_of_rightInvOn_of_mapsTo {α β : Type*} [PartialOrder α] [LinearOrder β]
- {φ : β → α} {ψ : α → β} {t : Set β} {s : Set α} (hφ : MonotoneOn φ t)
- (φψs : Set.RightInvOn ψ φ s) (ψts : Set.MapsTo ψ s t) : MonotoneOn ψ s := by
- rintro x xs y ys l
- rcases le_total (ψ x) (ψ y) with (ψxy|ψyx)
- · exact ψxy
- · have := hφ (ψts ys) (ψts xs) ψyx
- rw [φψs.eq ys, φψs.eq xs] at this
- induction le_antisymm l this
- exact le_refl _
-
-theorem antitoneOn_of_rightInvOn_of_mapsTo [PartialOrder α] [LinearOrder β]
- {φ : β → α} {ψ : α → β} {t : Set β} {s : Set α} (hφ : AntitoneOn φ t)
- (φψs : Set.RightInvOn ψ φ s) (ψts : Set.MapsTo ψ s t) : AntitoneOn ψ s :=
- (monotoneOn_of_rightInvOn_of_mapsTo hφ.dual_left φψs ψts).dual_right
+lemma apply_eq_of_range_eq_singleton {f : α → β} {b : β} (h : range f = {b}) (a : α) :
+ f a = b := by
+ simpa only [h, mem_singleton_iff] using mem_range_self (f := f) a
end Function
@@ -1718,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 _⟩
@@ -1742,4 +1661,4 @@ lemma bijOn_swap (ha : a ∈ s) (hb : b ∈ s) : BijOn (swap a b) s s :=
end Equiv
-set_option linter.style.longFile 1900
+set_option linter.style.longFile 1800
diff --git a/Mathlib/Data/Set/Image.lean b/Mathlib/Data/Set/Image.lean
index 09b79da91cf44..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
@@ -987,24 +993,24 @@ end Range
section Subsingleton
-variable {s : Set α}
+variable {s : Set α} {f : α → β}
/-- The image of a subsingleton is a subsingleton. -/
theorem Subsingleton.image (hs : s.Subsingleton) (f : α → β) : (f '' s).Subsingleton :=
fun _ ⟨_, hx, Hx⟩ _ ⟨_, hy, Hy⟩ => Hx ▸ Hy ▸ congr_arg f (hs hx hy)
/-- The preimage of a subsingleton under an injective map is a subsingleton. -/
-theorem Subsingleton.preimage {s : Set β} (hs : s.Subsingleton) {f : α → β}
+theorem Subsingleton.preimage {s : Set β} (hs : s.Subsingleton)
(hf : Function.Injective f) : (f ⁻¹' s).Subsingleton := fun _ ha _ hb => hf <| hs ha hb
/-- If the image of a set under an injective map is a subsingleton, the set is a subsingleton. -/
-theorem subsingleton_of_image {f : α → β} (hf : Function.Injective f) (s : Set α)
+theorem subsingleton_of_image (hf : Function.Injective f) (s : Set α)
(hs : (f '' s).Subsingleton) : s.Subsingleton :=
(hs.preimage hf).anti <| subset_preimage_image _ _
/-- If the preimage of a set under a surjective map is a subsingleton,
the set is a subsingleton. -/
-theorem subsingleton_of_preimage {f : α → β} (hf : Function.Surjective f) (s : Set β)
+theorem subsingleton_of_preimage (hf : Function.Surjective f) (s : Set β)
(hs : (f ⁻¹' s).Subsingleton) : s.Subsingleton := fun fx hx fy hy => by
rcases hf fx, hf fy with ⟨⟨x, rfl⟩, ⟨y, rfl⟩⟩
exact congr_arg f (hs hx hy)
@@ -1013,29 +1019,39 @@ theorem subsingleton_range {α : Sort*} [Subsingleton α] (f : α → β) : (ran
forall_mem_range.2 fun x => forall_mem_range.2 fun y => congr_arg f (Subsingleton.elim x y)
/-- The preimage of a nontrivial set under a surjective map is nontrivial. -/
-theorem Nontrivial.preimage {s : Set β} (hs : s.Nontrivial) {f : α → β}
+theorem Nontrivial.preimage {s : Set β} (hs : s.Nontrivial)
(hf : Function.Surjective f) : (f ⁻¹' s).Nontrivial := by
rcases hs with ⟨fx, hx, fy, hy, hxy⟩
rcases hf fx, hf fy with ⟨⟨x, rfl⟩, ⟨y, rfl⟩⟩
exact ⟨x, hx, y, hy, mt (congr_arg f) hxy⟩
/-- The image of a nontrivial set under an injective map is nontrivial. -/
-theorem Nontrivial.image (hs : s.Nontrivial) {f : α → β} (hf : Function.Injective f) :
+theorem Nontrivial.image (hs : s.Nontrivial) (hf : Function.Injective f) :
(f '' s).Nontrivial :=
let ⟨x, hx, y, hy, hxy⟩ := hs
⟨f x, mem_image_of_mem f hx, f y, mem_image_of_mem f hy, hf.ne hxy⟩
+theorem Nontrivial.image_of_injOn (hs : s.Nontrivial) (hf : s.InjOn f) :
+ (f '' s).Nontrivial := by
+ obtain ⟨x, hx, y, hy, hxy⟩ := hs
+ exact ⟨f x, mem_image_of_mem _ hx, f y, mem_image_of_mem _ hy, (hxy <| hf hx hy ·)⟩
+
/-- If the image of a set is nontrivial, the set is nontrivial. -/
theorem nontrivial_of_image (f : α → β) (s : Set α) (hs : (f '' s).Nontrivial) : s.Nontrivial :=
let ⟨_, ⟨x, hx, rfl⟩, _, ⟨y, hy, rfl⟩, hxy⟩ := hs
⟨x, hx, y, hy, mt (congr_arg f) hxy⟩
@[simp]
-theorem image_nontrivial {f : α → β} (hf : f.Injective) : (f '' s).Nontrivial ↔ s.Nontrivial :=
+theorem image_nontrivial (hf : f.Injective) : (f '' s).Nontrivial ↔ s.Nontrivial :=
⟨nontrivial_of_image f s, fun h ↦ h.image hf⟩
+@[simp]
+theorem InjOn.image_nontrivial_iff (hf : s.InjOn f) :
+ (f '' s).Nontrivial ↔ s.Nontrivial :=
+ ⟨nontrivial_of_image f s, fun h ↦ h.image_of_injOn hf⟩
+
/-- If the preimage of a set under an injective map is nontrivial, the set is nontrivial. -/
-theorem nontrivial_of_preimage {f : α → β} (hf : Function.Injective f) (s : Set β)
+theorem nontrivial_of_preimage (hf : Function.Injective f) (s : Set β)
(hs : (f ⁻¹' s).Nontrivial) : s.Nontrivial :=
(hs.image hf).mono <| image_preimage_subset _ _
@@ -1080,6 +1096,9 @@ theorem Injective.image_injective (hf : Injective f) : Injective (image f) := by
intro s t h
rw [← preimage_image_eq s hf, ← preimage_image_eq t hf, h]
+lemma Injective.image_strictMono (inj : Function.Injective f) : StrictMono (image f) :=
+ monotone_image.strictMono_of_injective inj.image_injective
+
theorem Surjective.preimage_subset_preimage_iff {s t : Set β} (hf : Surjective f) :
f ⁻¹' s ⊆ f ⁻¹' t ↔ s ⊆ t := by
apply Set.preimage_subset_preimage_iff
@@ -1090,13 +1109,17 @@ theorem Surjective.range_comp {ι' : Sort*} {f : ι → ι'} (hf : Surjective f)
range (g ∘ f) = range g :=
ext fun y => (@Surjective.exists _ _ _ hf fun x => g x = y).symm
-theorem Injective.mem_range_iff_exists_unique (hf : Injective f) {b : β} :
+theorem Injective.mem_range_iff_existsUnique (hf : Injective f) {b : β} :
b ∈ range f ↔ ∃! a, f a = b :=
⟨fun ⟨a, h⟩ => ⟨a, h, fun _ ha => hf (ha.trans h.symm)⟩, ExistsUnique.exists⟩
-theorem Injective.exists_unique_of_mem_range (hf : Injective f) {b : β} (hb : b ∈ range f) :
- ∃! a, f a = b :=
- hf.mem_range_iff_exists_unique.mp hb
+alias ⟨Injective.existsUnique_of_mem_range, _⟩ := Injective.mem_range_iff_existsUnique
+
+@[deprecated (since := "2024-09-25")]
+alias Injective.mem_range_iff_exists_unique := Injective.mem_range_iff_existsUnique
+
+@[deprecated (since := "2024-09-25")]
+alias Injective.exists_unique_of_mem_range := Injective.existsUnique_of_mem_range
theorem Injective.compl_image_eq (hf : Injective f) (s : Set α) :
(f '' s)ᶜ = f '' sᶜ ∪ (range f)ᶜ := by
diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean
index fbff041791382..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`
@@ -1243,6 +1264,14 @@ theorem image_sInter_subset (S : Set (Set α)) (f : α → β) : f '' ⋂₀ S
rw [sInter_eq_biInter]
apply image_iInter₂_subset
+theorem image2_sInter_right_subset (t : Set α) (S : Set (Set β)) (f : α → β → γ) :
+ image2 f t (⋂₀ S) ⊆ ⋂ s ∈ S, image2 f t s := by
+ aesop
+
+theorem image2_sInter_left_subset (S : Set (Set α)) (t : Set β) (f : α → β → γ) :
+ image2 f (⋂₀ S) t ⊆ ⋂ s ∈ S, image2 f s t := by
+ aesop
+
/-! ### `restrictPreimage` -/
@@ -1575,6 +1604,14 @@ theorem image2_iUnion_right (s : Set α) (t : ι → Set β) :
image2 f s (⋃ i, t i) = ⋃ i, image2 f s (t i) := by
simp only [← image_prod, prod_iUnion, image_iUnion]
+theorem image2_sUnion_left (S : Set (Set α)) (t : Set β) :
+ image2 f (⋃₀ S) t = ⋃ s ∈ S, image2 f s t := by
+ aesop
+
+theorem image2_sUnion_right (s : Set α) (T : Set (Set β)) :
+ image2 f s (⋃₀ T) = ⋃ t ∈ T, image2 f s t := by
+ aesop
+
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
theorem image2_iUnion₂_left (s : ∀ i, κ i → Set α) (t : Set β) :
@@ -1610,6 +1647,16 @@ theorem image2_iInter₂_subset_right (s : Set α) (t : ∀ i, κ i → Set β)
simp_rw [image2_subset_iff, mem_iInter]
exact fun x hx y hy i j => mem_image2_of_mem hx (hy _ _)
+theorem image2_sInter_subset_left (S : Set (Set α)) (t : Set β) :
+ image2 f (⋂₀ S) t ⊆ ⋂ s ∈ S, image2 f s t := by
+ rw [sInter_eq_biInter]
+ exact image2_iInter₂_subset_left ..
+
+theorem image2_sInter_subset_right (s : Set α) (T : Set (Set β)) :
+ image2 f s (⋂₀ T) ⊆ ⋂ t ∈ T, image2 f s t := by
+ rw [sInter_eq_biInter]
+ exact image2_iInter₂_subset_right ..
+
theorem prod_eq_biUnion_left : s ×ˢ t = ⋃ a ∈ s, (fun b => (a, b)) '' t := by
rw [iUnion_image_left, image2_mk_eq_prod]
@@ -1741,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/MemPartition.lean b/Mathlib/Data/Set/MemPartition.lean
index 25b578031b0f6..5a13d62ad7baf 100644
--- a/Mathlib/Data/Set/MemPartition.lean
+++ b/Mathlib/Data/Set/MemPartition.lean
@@ -118,7 +118,6 @@ lemma memPartitionSet_succ (f : ℕ → Set α) (n : ℕ) (a : α) [Decidable (a
memPartitionSet f (n + 1) a
= if a ∈ f n then memPartitionSet f n a ∩ f n else memPartitionSet f n a \ f n := by
simp [memPartitionSet]
- congr
lemma memPartitionSet_mem (f : ℕ → Set α) (n : ℕ) (a : α) :
memPartitionSet f n a ∈ memPartition f n := by
diff --git a/Mathlib/Data/Set/Monotone.lean b/Mathlib/Data/Set/Monotone.lean
new file mode 100644
index 0000000000000..5bd60bb9fb1c5
--- /dev/null
+++ b/Mathlib/Data/Set/Monotone.lean
@@ -0,0 +1,193 @@
+/-
+Copyright (c) 2014 Jeremy Avigad. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Jeremy Avigad, Andrew Zipperer, Haitao Zhang, Minchao Wu, Yury Kudryashov
+-/
+import Mathlib.Data.Set.Function
+
+/-!
+# Monotone functions over sets
+-/
+
+variable {α β γ : Type*}
+
+open Equiv Equiv.Perm Function
+
+namespace Set
+
+
+/-! ### Congruence lemmas for monotonicity and antitonicity -/
+section Order
+
+variable {s : Set α} {f₁ f₂ : α → β} [Preorder α] [Preorder β]
+
+theorem _root_.MonotoneOn.congr (h₁ : MonotoneOn f₁ s) (h : s.EqOn f₁ f₂) : MonotoneOn f₂ s := by
+ intro a ha b hb hab
+ rw [← h ha, ← h hb]
+ exact h₁ ha hb hab
+
+theorem _root_.AntitoneOn.congr (h₁ : AntitoneOn f₁ s) (h : s.EqOn f₁ f₂) : AntitoneOn f₂ s :=
+ h₁.dual_right.congr h
+
+theorem _root_.StrictMonoOn.congr (h₁ : StrictMonoOn f₁ s) (h : s.EqOn f₁ f₂) :
+ StrictMonoOn f₂ s := by
+ intro a ha b hb hab
+ rw [← h ha, ← h hb]
+ exact h₁ ha hb hab
+
+theorem _root_.StrictAntiOn.congr (h₁ : StrictAntiOn f₁ s) (h : s.EqOn f₁ f₂) : StrictAntiOn f₂ s :=
+ h₁.dual_right.congr h
+
+theorem EqOn.congr_monotoneOn (h : s.EqOn f₁ f₂) : MonotoneOn f₁ s ↔ MonotoneOn f₂ s :=
+ ⟨fun h₁ => h₁.congr h, fun h₂ => h₂.congr h.symm⟩
+
+theorem EqOn.congr_antitoneOn (h : s.EqOn f₁ f₂) : AntitoneOn f₁ s ↔ AntitoneOn f₂ s :=
+ ⟨fun h₁ => h₁.congr h, fun h₂ => h₂.congr h.symm⟩
+
+theorem EqOn.congr_strictMonoOn (h : s.EqOn f₁ f₂) : StrictMonoOn f₁ s ↔ StrictMonoOn f₂ s :=
+ ⟨fun h₁ => h₁.congr h, fun h₂ => h₂.congr h.symm⟩
+
+theorem EqOn.congr_strictAntiOn (h : s.EqOn f₁ f₂) : StrictAntiOn f₁ s ↔ StrictAntiOn f₂ s :=
+ ⟨fun h₁ => h₁.congr h, fun h₂ => h₂.congr h.symm⟩
+
+end Order
+
+/-! ### Monotonicity lemmas -/
+section Mono
+
+variable {s s₂ : Set α} {f : α → β} [Preorder α] [Preorder β]
+
+theorem _root_.MonotoneOn.mono (h : MonotoneOn f s) (h' : s₂ ⊆ s) : MonotoneOn f s₂ :=
+ fun _ hx _ hy => h (h' hx) (h' hy)
+
+theorem _root_.AntitoneOn.mono (h : AntitoneOn f s) (h' : s₂ ⊆ s) : AntitoneOn f s₂ :=
+ fun _ hx _ hy => h (h' hx) (h' hy)
+
+theorem _root_.StrictMonoOn.mono (h : StrictMonoOn f s) (h' : s₂ ⊆ s) : StrictMonoOn f s₂ :=
+ fun _ hx _ hy => h (h' hx) (h' hy)
+
+theorem _root_.StrictAntiOn.mono (h : StrictAntiOn f s) (h' : s₂ ⊆ s) : StrictAntiOn f s₂ :=
+ fun _ hx _ hy => h (h' hx) (h' hy)
+
+protected theorem _root_.MonotoneOn.monotone (h : MonotoneOn f s) :
+ Monotone (f ∘ Subtype.val : s → β) :=
+ fun x y hle => h x.coe_prop y.coe_prop hle
+
+protected theorem _root_.AntitoneOn.monotone (h : AntitoneOn f s) :
+ Antitone (f ∘ Subtype.val : s → β) :=
+ fun x y hle => h x.coe_prop y.coe_prop hle
+
+protected theorem _root_.StrictMonoOn.strictMono (h : StrictMonoOn f s) :
+ StrictMono (f ∘ Subtype.val : s → β) :=
+ fun x y hlt => h x.coe_prop y.coe_prop hlt
+
+protected theorem _root_.StrictAntiOn.strictAnti (h : StrictAntiOn f s) :
+ StrictAnti (f ∘ Subtype.val : s → β) :=
+ fun x y hlt => h x.coe_prop y.coe_prop hlt
+
+lemma MonotoneOn_insert_iff {a : α} :
+ MonotoneOn f (insert a s) ↔
+ (∀ b ∈ s, b ≤ a → f b ≤ f a) ∧ (∀ b ∈ s, a ≤ b → f a ≤ f b) ∧ MonotoneOn f s := by
+ simp [MonotoneOn, forall_and]
+
+lemma AntitoneOn_insert_iff {a : α} :
+ AntitoneOn f (insert a s) ↔
+ (∀ b ∈ s, b ≤ a → f a ≤ f b) ∧ (∀ b ∈ s, a ≤ b → f b ≤ f a) ∧ AntitoneOn f s :=
+ @MonotoneOn_insert_iff α βᵒᵈ _ _ _ _ _
+
+end Mono
+
+end Set
+
+
+
+open Function
+
+/-! ### Monotone -/
+namespace Monotone
+
+variable [Preorder α] [Preorder β] {f : α → β}
+
+protected theorem restrict (h : Monotone f) (s : Set α) : Monotone (s.restrict f) := fun _ _ hxy =>
+ h hxy
+
+protected theorem codRestrict (h : Monotone f) {s : Set β} (hs : ∀ x, f x ∈ s) :
+ Monotone (s.codRestrict f hs) :=
+ h
+
+protected theorem rangeFactorization (h : Monotone f) : Monotone (Set.rangeFactorization f) :=
+ h
+
+end Monotone
+
+section strictMono
+
+theorem StrictMonoOn.injOn [LinearOrder α] [Preorder β] {f : α → β} {s : Set α}
+ (H : StrictMonoOn f s) : s.InjOn f := fun x hx y hy hxy =>
+ show Ordering.eq.Compares x y from (H.compares hx hy).1 hxy
+
+theorem StrictAntiOn.injOn [LinearOrder α] [Preorder β] {f : α → β} {s : Set α}
+ (H : StrictAntiOn f s) : s.InjOn f :=
+ @StrictMonoOn.injOn α βᵒᵈ _ _ f s H
+
+theorem StrictMonoOn.comp [Preorder α] [Preorder β] [Preorder γ] {g : β → γ} {f : α → β} {s : Set α}
+ {t : Set β} (hg : StrictMonoOn g t) (hf : StrictMonoOn f s) (hs : Set.MapsTo f s t) :
+ StrictMonoOn (g ∘ f) s := fun _x hx _y hy hxy => hg (hs hx) (hs hy) <| hf hx hy hxy
+
+theorem StrictMonoOn.comp_strictAntiOn [Preorder α] [Preorder β] [Preorder γ] {g : β → γ}
+ {f : α → β} {s : Set α} {t : Set β} (hg : StrictMonoOn g t) (hf : StrictAntiOn f s)
+ (hs : Set.MapsTo f s t) : StrictAntiOn (g ∘ f) s := fun _x hx _y hy hxy =>
+ hg (hs hy) (hs hx) <| hf hx hy hxy
+
+theorem StrictAntiOn.comp [Preorder α] [Preorder β] [Preorder γ] {g : β → γ} {f : α → β} {s : Set α}
+ {t : Set β} (hg : StrictAntiOn g t) (hf : StrictAntiOn f s) (hs : Set.MapsTo f s t) :
+ StrictMonoOn (g ∘ f) s := fun _x hx _y hy hxy => hg (hs hy) (hs hx) <| hf hx hy hxy
+
+theorem StrictAntiOn.comp_strictMonoOn [Preorder α] [Preorder β] [Preorder γ] {g : β → γ}
+ {f : α → β} {s : Set α} {t : Set β} (hg : StrictAntiOn g t) (hf : StrictMonoOn f s)
+ (hs : Set.MapsTo f s t) : StrictAntiOn (g ∘ f) s := fun _x hx _y hy hxy =>
+ hg (hs hx) (hs hy) <| hf hx hy hxy
+
+@[simp]
+theorem strictMono_restrict [Preorder α] [Preorder β] {f : α → β} {s : Set α} :
+ StrictMono (s.restrict f) ↔ StrictMonoOn f s := by simp [Set.restrict, StrictMono, StrictMonoOn]
+
+alias ⟨_root_.StrictMono.of_restrict, _root_.StrictMonoOn.restrict⟩ := strictMono_restrict
+
+theorem StrictMono.codRestrict [Preorder α] [Preorder β] {f : α → β} (hf : StrictMono f)
+ {s : Set β} (hs : ∀ x, f x ∈ s) : StrictMono (Set.codRestrict f s hs) :=
+ hf
+
+lemma strictMonoOn_insert_iff [Preorder α] [Preorder β] {f : α → β} {s : Set α} {a : α} :
+ StrictMonoOn f (insert a s) ↔
+ (∀ b ∈ s, b < a → f b < f a) ∧ (∀ b ∈ s, a < b → f a < f b) ∧ StrictMonoOn f s := by
+ simp [StrictMonoOn, forall_and]
+
+lemma strictAntiOn_insert_iff [Preorder α] [Preorder β] {f : α → β} {s : Set α} {a : α} :
+ StrictAntiOn f (insert a s) ↔
+ (∀ b ∈ s, b < a → f a < f b) ∧ (∀ b ∈ s, a < b → f b < f a) ∧ StrictAntiOn f s :=
+ @strictMonoOn_insert_iff α βᵒᵈ _ _ _ _ _
+
+end strictMono
+
+namespace Function
+
+open Set
+
+theorem monotoneOn_of_rightInvOn_of_mapsTo {α β : Type*} [PartialOrder α] [LinearOrder β]
+ {φ : β → α} {ψ : α → β} {t : Set β} {s : Set α} (hφ : MonotoneOn φ t)
+ (φψs : Set.RightInvOn ψ φ s) (ψts : Set.MapsTo ψ s t) : MonotoneOn ψ s := by
+ rintro x xs y ys l
+ rcases le_total (ψ x) (ψ y) with (ψxy|ψyx)
+ · exact ψxy
+ · have := hφ (ψts ys) (ψts xs) ψyx
+ rw [φψs.eq ys, φψs.eq xs] at this
+ induction le_antisymm l this
+ exact le_refl _
+
+theorem antitoneOn_of_rightInvOn_of_mapsTo [PartialOrder α] [LinearOrder β]
+ {φ : β → α} {ψ : α → β} {t : Set β} {s : Set α} (hφ : AntitoneOn φ t)
+ (φψs : Set.RightInvOn ψ φ s) (ψts : Set.MapsTo ψ s t) : AntitoneOn ψ s :=
+ (monotoneOn_of_rightInvOn_of_mapsTo hφ.dual_left φψs ψts).dual_right
+
+end Function
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/Operations.lean b/Mathlib/Data/Set/Operations.lean
index 620c7afe1b44c..bed6dc9156d8b 100644
--- a/Mathlib/Data/Set/Operations.lean
+++ b/Mathlib/Data/Set/Operations.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Jeremy Avigad, Johannes Hölzl, Reid Barton, Scott Morrison, Patrick Massot, Kyle Miller,
+Authors: Jeremy Avigad, Johannes Hölzl, Reid Barton, Kim Morrison, Patrick Massot, Kyle Miller,
Minchao Wu, Yury Kudryashov, Floris van Doorn
-/
import Mathlib.Data.SProd
diff --git a/Mathlib/Data/Set/Pairwise/Basic.lean b/Mathlib/Data/Set/Pairwise/Basic.lean
index 64e482ceb8858..ec5b714ca6538 100644
--- a/Mathlib/Data/Set/Pairwise/Basic.lean
+++ b/Mathlib/Data/Set/Pairwise/Basic.lean
@@ -30,16 +30,16 @@ 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
-theorem pairwise_disjoint_on_bool [SemilatticeInf α] [OrderBot α] {a b : α} :
+theorem pairwise_disjoint_on_bool [PartialOrder α] [OrderBot α] {a b : α} :
Pairwise (Disjoint on fun c => cond c a b) ↔ Disjoint a b :=
pairwise_on_bool Disjoint.symm
@@ -47,14 +47,24 @@ theorem Symmetric.pairwise_on [LinearOrder ι] (hr : Symmetric r) (f : ι → α
Pairwise (r on f) ↔ ∀ ⦃m n⦄, m < n → r (f m) (f n) :=
⟨fun h _m _n hmn => h hmn.ne, fun h _m _n hmn => hmn.lt_or_lt.elim (@h _ _) fun h' => hr (h h')⟩
-theorem pairwise_disjoint_on [SemilatticeInf α] [OrderBot α] [LinearOrder ι] (f : ι → α) :
+theorem pairwise_disjoint_on [PartialOrder α] [OrderBot α] [LinearOrder ι] (f : ι → α) :
Pairwise (Disjoint on f) ↔ ∀ ⦃m n⦄, m < n → Disjoint (f m) (f n) :=
Symmetric.pairwise_on Disjoint.symm f
-theorem pairwise_disjoint_mono [SemilatticeInf α] [OrderBot α] (hs : Pairwise (Disjoint on f))
+theorem pairwise_disjoint_mono [PartialOrder α] [OrderBot α] (hs : Pairwise (Disjoint on f))
(h : g ≤ f) : Pairwise (Disjoint on g) :=
hs.mono fun i j hij => Disjoint.mono (h i) (h j) hij
+theorem Pairwise.disjoint_extend_bot [PartialOrder γ] [OrderBot γ]
+ {e : α → β} {f : α → γ} (hf : Pairwise (Disjoint on f)) (he : FactorsThrough f e) :
+ Pairwise (Disjoint on extend e f ⊥) := by
+ intro b₁ b₂ hne
+ rcases em (∃ a₁, e a₁ = b₁) with ⟨a₁, rfl⟩ | hb₁
+ · rcases em (∃ a₂, e a₂ = b₂) with ⟨a₂, rfl⟩ | hb₂
+ · simpa only [onFun, he.extend_apply] using hf (ne_of_apply_ne e hne)
+ · simpa only [onFun, extend_apply' _ _ _ hb₂] using disjoint_bot_right
+ · simpa only [onFun, extend_apply' _ _ _ hb₁] using disjoint_bot_left
+
namespace Set
theorem Pairwise.mono (h : t ⊆ s) (hs : s.Pairwise r) : t.Pairwise r :=
@@ -129,8 +139,7 @@ theorem pairwise_union_of_symmetric (hr : Symmetric r) :
theorem pairwise_insert :
(insert a s).Pairwise r ↔ s.Pairwise r ∧ ∀ b ∈ s, a ≠ b → r a b ∧ r b a := by
- simp only [insert_eq, pairwise_union, pairwise_singleton, true_and_iff, mem_singleton_iff,
- forall_eq]
+ simp only [insert_eq, pairwise_union, pairwise_singleton, true_and, mem_singleton_iff, forall_eq]
theorem pairwise_insert_of_not_mem (ha : a ∉ s) :
(insert a s).Pairwise r ↔ s.Pairwise r ∧ ∀ b ∈ s, r a b ∧ r b a :=
@@ -287,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 ι) :
@@ -302,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/BigOperators.lean b/Mathlib/Data/Set/Pointwise/BigOperators.lean
index 2cc66bb66f328..7772e8e35548f 100644
--- a/Mathlib/Data/Set/Pointwise/BigOperators.lean
+++ b/Mathlib/Data/Set/Pointwise/BigOperators.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Eric Wieser
-/
import Mathlib.Algebra.BigOperators.Group.Finset
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
/-!
# Results about pointwise operations on sets and big operators.
diff --git a/Mathlib/Data/Set/Pointwise/BoundedMul.lean b/Mathlib/Data/Set/Pointwise/BoundedMul.lean
index 0472b092e5f72..2d630b685665e 100644
--- a/Mathlib/Data/Set/Pointwise/BoundedMul.lean
+++ b/Mathlib/Data/Set/Pointwise/BoundedMul.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 KudryashovJ
-/
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Algebra.Order.Monoid.Defs
/-!
diff --git a/Mathlib/Data/Set/Pointwise/Finite.lean b/Mathlib/Data/Set/Pointwise/Finite.lean
index 02e69997156ee..370ad1550f6b6 100644
--- a/Mathlib/Data/Set/Pointwise/Finite.lean
+++ b/Mathlib/Data/Set/Pointwise/Finite.lean
@@ -3,8 +3,9 @@ Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Floris van Doorn
-/
+import Mathlib.Algebra.Group.Action.Basic
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Data.Set.Finite
-import Mathlib.Data.Set.Pointwise.SMul
/-! # Finiteness lemmas for pointwise operations on sets -/
@@ -25,16 +26,6 @@ theorem finite_one : (1 : Set α).Finite :=
end One
-section InvolutiveInv
-
-variable [InvolutiveInv α] {s : Set α}
-
-@[to_additive]
-theorem Finite.inv (hs : s.Finite) : s⁻¹.Finite :=
- hs.preimage inv_injective.injOn
-
-end InvolutiveInv
-
section Mul
variable [Mul α] {s t : Set α}
@@ -108,20 +99,52 @@ section Cancel
variable [Mul α] [IsLeftCancelMul α] [IsRightCancelMul α] {s t : Set α}
@[to_additive]
-theorem infinite_mul : (s * t).Infinite ↔ s.Infinite ∧ t.Nonempty ∨ t.Infinite ∧ s.Nonempty :=
- infinite_image2 (fun _ _ => (mul_left_injective _).injOn) fun _ _ =>
- (mul_right_injective _).injOn
+lemma finite_mul : (s * t).Finite ↔ s.Finite ∧ t.Finite ∨ s = ∅ ∨ t = ∅ :=
+ finite_image2 (fun _ _ ↦ (mul_left_injective _).injOn) fun _ _ ↦ (mul_right_injective _).injOn
@[to_additive]
-lemma finite_mul : (s * t).Finite ↔ s.Finite ∧ t.Finite ∨ s = ∅ ∨ t = ∅ :=
- finite_image2 (fun _ _ ↦ (mul_left_injective _).injOn)
- fun _ _ ↦ (mul_right_injective _).injOn
+lemma infinite_mul : (s * t).Infinite ↔ s.Infinite ∧ t.Nonempty ∨ t.Infinite ∧ s.Nonempty :=
+ infinite_image2 (fun _ _ => (mul_left_injective _).injOn) fun _ _ => (mul_right_injective _).injOn
end Cancel
+section InvolutiveInv
+variable [InvolutiveInv α] {s : Set α}
+
+@[to_additive (attr := simp)] lemma finite_inv : s⁻¹.Finite ↔ s.Finite := by
+ rw [← image_inv, finite_image_iff inv_injective.injOn]
+
+@[to_additive (attr := simp)] lemma infinite_inv : s⁻¹.Infinite ↔ s.Infinite := finite_inv.not
+
+@[to_additive] alias ⟨Finite.of_inv, Finite.inv⟩ := finite_inv
+
+end InvolutiveInv
+
+section Div
+variable [Div α] {s t : Set α}
+
+@[to_additive] lemma Finite.div : s.Finite → t.Finite → (s / t).Finite := .image2 _
+
+/-- Division preserves finiteness. -/
+@[to_additive "Subtraction preserves finiteness."]
+def fintypeDiv [DecidableEq α] (s t : Set α) [Fintype s] [Fintype t] : Fintype (s / t) :=
+ Set.fintypeImage2 _ _ _
+
+end Div
+
section Group
-variable [Group α] [MulAction α β] {a : α} {s : Set β}
+variable [Group α] {s t : Set α}
+
+@[to_additive]
+lemma finite_div : (s / t).Finite ↔ s.Finite ∧ t.Finite ∨ s = ∅ ∨ t = ∅ :=
+ finite_image2 (fun _ _ ↦ div_left_injective.injOn) fun _ _ ↦ div_right_injective.injOn
+
+@[to_additive]
+lemma infinite_div : (s / t).Infinite ↔ s.Infinite ∧ t.Nonempty ∨ t.Infinite ∧ s.Nonempty :=
+ infinite_image2 (fun _ _ ↦ div_left_injective.injOn) fun _ _ ↦ div_right_injective.injOn
+
+variable [MulAction α β] {a : α} {s : Set β}
@[to_additive (attr := simp)]
theorem finite_smul_set : (a • s).Finite ↔ s.Finite :=
@@ -131,11 +154,8 @@ theorem finite_smul_set : (a • s).Finite ↔ s.Finite :=
theorem infinite_smul_set : (a • s).Infinite ↔ s.Infinite :=
infinite_image_iff (MulAction.injective _).injOn
-alias ⟨Finite.of_smul_set, _⟩ := finite_smul_set
-
-alias ⟨_, Infinite.smul_set⟩ := infinite_smul_set
-
-attribute [to_additive] Finite.of_smul_set Infinite.smul_set
+@[to_additive] alias ⟨Finite.of_smul_set, _⟩ := finite_smul_set
+@[to_additive] alias ⟨_, Infinite.smul_set⟩ := infinite_smul_set
end Group
diff --git a/Mathlib/Data/Set/Pointwise/Interval.lean b/Mathlib/Data/Set/Pointwise/Interval.lean
index 291fcb810c4c8..535b6e9100c34 100644
--- a/Mathlib/Data/Set/Pointwise/Interval.lean
+++ b/Mathlib/Data/Set/Pointwise/Interval.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, Patrick Massot
-/
-import Mathlib.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Algebra.Order.Field.Basic
import Mathlib.Algebra.Order.Group.MinMax
import Mathlib.Algebra.Order.Interval.Set.Monoid
@@ -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]
@@ -509,12 +508,12 @@ variable [LinearOrderedField α] {a : α}
@[simp]
theorem preimage_mul_const_Iio (a : α) {c : α} (h : 0 < c) :
(fun x => x * c) ⁻¹' Iio a = Iio (a / c) :=
- ext fun _x => (lt_div_iff h).symm
+ ext fun _x => (lt_div_iff₀ h).symm
@[simp]
theorem preimage_mul_const_Ioi (a : α) {c : α} (h : 0 < c) :
(fun x => x * c) ⁻¹' Ioi a = Ioi (a / c) :=
- ext fun _x => (div_lt_iff h).symm
+ ext fun _x => (div_lt_iff₀ h).symm
@[simp]
theorem preimage_mul_const_Iic (a : α) {c : α} (h : 0 < c) :
@@ -582,11 +581,11 @@ theorem preimage_mul_const_Icc_of_neg (a b : α) {c : α} (h : c < 0) :
@[simp]
theorem preimage_const_mul_Iio (a : α) {c : α} (h : 0 < c) : (c * ·) ⁻¹' Iio a = Iio (a / c) :=
- ext fun _x => (lt_div_iff' h).symm
+ ext fun _x => (lt_div_iff₀' h).symm
@[simp]
theorem preimage_const_mul_Ioi (a : α) {c : α} (h : 0 < c) : (c * ·) ⁻¹' Ioi a = Ioi (a / c) :=
- ext fun _x => (div_lt_iff' h).symm
+ ext fun _x => (div_lt_iff₀' h).symm
@[simp]
theorem preimage_const_mul_Iic (a : α) {c : α} (h : 0 < c) : (c * ·) ⁻¹' Iic a = Iic (a / c) :=
@@ -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 309b0b70bb701..120059da9dfca 100644
--- a/Mathlib/Data/Set/Pointwise/ListOfFn.lean
+++ b/Mathlib/Data/Set/Pointwise/ListOfFn.lean
@@ -4,7 +4,7 @@ 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.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Data.List.OfFn
/-!
@@ -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 71e47a9d5b35c..68200c4096290 100644
--- a/Mathlib/Data/Set/Pointwise/SMul.lean
+++ b/Mathlib/Data/Set/Pointwise/SMul.lean
@@ -4,28 +4,18 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Floris van Doorn
-/
import Mathlib.Algebra.Group.Pi.Basic
-import Mathlib.Algebra.Group.Pointwise.Set
+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
/-!
-# Pointwise operations of sets
+# Pointwise action on sets
-This file defines pointwise algebraic operations on sets.
-
-## Main declarations
-
-For sets `s` and `t` and scalar `a`:
-* `s • t`: Scalar multiplication, set of all `x • y` where `x ∈ s` and `y ∈ t`.
-* `s +ᵥ t`: Scalar addition, set of all `x +ᵥ y` where `x ∈ s` and `y ∈ t`.
-* `s -ᵥ t`: Scalar subtraction, set of all `x -ᵥ y` where `x ∈ s` and `y ∈ t`.
-* `a • s`: Scaling, set of all `a • x` where `x ∈ s`.
-* `a +ᵥ s`: Translation, set of all `a +ᵥ x` where `x ∈ s`.
-
-For `α` a semigroup/monoid, `Set α` is a semigroup/monoid.
-
-Appropriate definitions and results are also transported to the additive theory via `to_additive`.
+This file proves that several kinds of actions of a type `α` on another type `β` transfer to actions
+of `α`/`Set α` on `Set β`.
## Implementation notes
@@ -49,255 +39,6 @@ open Pointwise
section SMul
-/-- The dilation of set `x • s` is defined as `{x • y | y ∈ s}` in locale `Pointwise`. -/
-@[to_additive
- "The translation of set `x +ᵥ s` is defined as `{x +ᵥ y | y ∈ s}` in
- locale `Pointwise`."]
-protected def smulSet [SMul α β] : SMul α (Set β) :=
- ⟨fun a ↦ image (a • ·)⟩
-
-/-- The pointwise scalar multiplication of sets `s • t` is defined as `{x • y | x ∈ s, y ∈ t}` in
-locale `Pointwise`. -/
-@[to_additive
- "The pointwise scalar addition of sets `s +ᵥ t` is defined as
- `{x +ᵥ y | x ∈ s, y ∈ t}` in locale `Pointwise`."]
-protected def smul [SMul α β] : SMul (Set α) (Set β) :=
- ⟨image2 (· • ·)⟩
-
-scoped[Pointwise] attribute [instance] Set.smulSet Set.smul
-
-scoped[Pointwise] attribute [instance] Set.vaddSet Set.vadd
-
-section SMul
-
-variable {ι : Sort*} {κ : ι → Sort*} [SMul α β] {s s₁ s₂ : Set α} {t t₁ t₂ u : Set β} {a : α}
- {b : β}
-
-@[to_additive (attr := simp)]
-theorem image2_smul : image2 SMul.smul s t = s • t :=
- rfl
-
-@[to_additive vadd_image_prod]
-theorem image_smul_prod : (fun x : α × β ↦ x.fst • x.snd) '' s ×ˢ t = s • t :=
- image_prod _
-
-@[to_additive]
-theorem mem_smul : b ∈ s • t ↔ ∃ x ∈ s, ∃ y ∈ t, x • y = b :=
- Iff.rfl
-
-@[to_additive]
-theorem smul_mem_smul : a ∈ s → b ∈ t → a • b ∈ s • t :=
- mem_image2_of_mem
-
-@[to_additive (attr := simp)]
-theorem empty_smul : (∅ : Set α) • t = ∅ :=
- image2_empty_left
-
-@[to_additive (attr := simp)]
-theorem smul_empty : s • (∅ : Set β) = ∅ :=
- image2_empty_right
-
-@[to_additive (attr := simp)]
-theorem smul_eq_empty : s • t = ∅ ↔ s = ∅ ∨ t = ∅ :=
- image2_eq_empty_iff
-
-@[to_additive (attr := simp)]
-theorem smul_nonempty : (s • t).Nonempty ↔ s.Nonempty ∧ t.Nonempty :=
- image2_nonempty_iff
-
-@[to_additive]
-theorem Nonempty.smul : s.Nonempty → t.Nonempty → (s • t).Nonempty :=
- Nonempty.image2
-
-@[to_additive]
-theorem Nonempty.of_smul_left : (s • t).Nonempty → s.Nonempty :=
- Nonempty.of_image2_left
-
-@[to_additive]
-theorem Nonempty.of_smul_right : (s • t).Nonempty → t.Nonempty :=
- Nonempty.of_image2_right
-
-@[to_additive (attr := simp low+1)]
-theorem smul_singleton : s • ({b} : Set β) = (· • b) '' s :=
- image2_singleton_right
-
-@[to_additive (attr := simp low+1)]
-theorem singleton_smul : ({a} : Set α) • t = a • t :=
- image2_singleton_left
-
-@[to_additive (attr := simp high)]
-theorem singleton_smul_singleton : ({a} : Set α) • ({b} : Set β) = {a • b} :=
- image2_singleton
-
-@[to_additive (attr := mono)]
-theorem smul_subset_smul : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ • t₁ ⊆ s₂ • t₂ :=
- image2_subset
-
-@[to_additive]
-theorem smul_subset_smul_left : t₁ ⊆ t₂ → s • t₁ ⊆ s • t₂ :=
- image2_subset_left
-
-@[to_additive]
-theorem smul_subset_smul_right : s₁ ⊆ s₂ → s₁ • t ⊆ s₂ • t :=
- image2_subset_right
-
-@[to_additive]
-theorem smul_subset_iff : s • t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a • b ∈ u :=
- image2_subset_iff
-
-
-@[to_additive]
-theorem union_smul : (s₁ ∪ s₂) • t = s₁ • t ∪ s₂ • t :=
- image2_union_left
-
-@[to_additive]
-theorem smul_union : s • (t₁ ∪ t₂) = s • t₁ ∪ s • t₂ :=
- image2_union_right
-
-@[to_additive]
-theorem inter_smul_subset : (s₁ ∩ s₂) • t ⊆ s₁ • t ∩ s₂ • t :=
- image2_inter_subset_left
-
-@[to_additive]
-theorem smul_inter_subset : s • (t₁ ∩ t₂) ⊆ s • t₁ ∩ s • t₂ :=
- image2_inter_subset_right
-
-@[to_additive]
-theorem inter_smul_union_subset_union : (s₁ ∩ s₂) • (t₁ ∪ t₂) ⊆ s₁ • t₁ ∪ s₂ • t₂ :=
- image2_inter_union_subset_union
-
-@[to_additive]
-theorem union_smul_inter_subset_union : (s₁ ∪ s₂) • (t₁ ∩ t₂) ⊆ s₁ • t₁ ∪ s₂ • t₂ :=
- image2_union_inter_subset_union
-
-@[to_additive]
-theorem iUnion_smul_left_image : ⋃ a ∈ s, a • t = s • t :=
- iUnion_image_left _
-
-@[to_additive]
-theorem iUnion_smul_right_image : ⋃ a ∈ t, (· • a) '' s = s • t :=
- iUnion_image_right _
-
-@[to_additive]
-theorem iUnion_smul (s : ι → Set α) (t : Set β) : (⋃ i, s i) • t = ⋃ i, s i • t :=
- image2_iUnion_left _ _ _
-
-@[to_additive]
-theorem smul_iUnion (s : Set α) (t : ι → Set β) : (s • ⋃ i, t i) = ⋃ i, s • t i :=
- image2_iUnion_right _ _ _
-
-@[to_additive]
-theorem iUnion₂_smul (s : ∀ i, κ i → Set α) (t : Set β) :
- (⋃ (i) (j), s i j) • t = ⋃ (i) (j), s i j • t :=
- image2_iUnion₂_left _ _ _
-
-@[to_additive]
-theorem smul_iUnion₂ (s : Set α) (t : ∀ i, κ i → Set β) :
- (s • ⋃ (i) (j), t i j) = ⋃ (i) (j), s • t i j :=
- image2_iUnion₂_right _ _ _
-
-@[to_additive]
-theorem iInter_smul_subset (s : ι → Set α) (t : Set β) : (⋂ i, s i) • t ⊆ ⋂ i, s i • t :=
- image2_iInter_subset_left _ _ _
-
-@[to_additive]
-theorem smul_iInter_subset (s : Set α) (t : ι → Set β) : (s • ⋂ i, t i) ⊆ ⋂ i, s • t i :=
- image2_iInter_subset_right _ _ _
-
-@[to_additive]
-theorem iInter₂_smul_subset (s : ∀ i, κ i → Set α) (t : Set β) :
- (⋂ (i) (j), s i j) • t ⊆ ⋂ (i) (j), s i j • t :=
- image2_iInter₂_subset_left _ _ _
-
-@[to_additive]
-theorem smul_iInter₂_subset (s : Set α) (t : ∀ i, κ i → Set β) :
- (s • ⋂ (i) (j), t i j) ⊆ ⋂ (i) (j), s • t i j :=
- image2_iInter₂_subset_right _ _ _
-
-@[to_additive]
-theorem smul_set_subset_smul {s : Set α} : a ∈ s → a • t ⊆ s • t :=
- image_subset_image2_right
-
-@[to_additive (attr := simp)]
-theorem iUnion_smul_set (s : Set α) (t : Set β) : ⋃ a ∈ s, a • t = s • t :=
- iUnion_image_left _
-
-end SMul
-
-section SMulSet
-
-variable {ι : Sort*} {κ : ι → Sort*} [SMul α β] {s t t₁ t₂ : Set β} {a : α} {b : β} {x y : β}
-
-@[to_additive]
-theorem image_smul : (fun x ↦ a • x) '' t = a • t :=
- rfl
-
-scoped[Pointwise] attribute [simp] Set.image_smul Set.image_vadd
-
-@[to_additive]
-theorem mem_smul_set : x ∈ a • t ↔ ∃ y, y ∈ t ∧ a • y = x :=
- Iff.rfl
-
-@[to_additive]
-theorem smul_mem_smul_set : b ∈ s → a • b ∈ a • s :=
- mem_image_of_mem _
-
-@[to_additive (attr := simp)]
-theorem smul_set_empty : a • (∅ : Set β) = ∅ :=
- image_empty _
-
-@[to_additive (attr := simp)]
-theorem smul_set_eq_empty : a • s = ∅ ↔ s = ∅ :=
- image_eq_empty
-
-@[to_additive (attr := simp)]
-theorem smul_set_nonempty : (a • s).Nonempty ↔ s.Nonempty :=
- image_nonempty
-
-@[to_additive (attr := simp)]
-theorem smul_set_singleton : a • ({b} : Set β) = {a • b} :=
- image_singleton
-
-@[to_additive]
-theorem smul_set_mono : s ⊆ t → a • s ⊆ a • t :=
- image_subset _
-
-@[to_additive]
-theorem smul_set_subset_iff : a • s ⊆ t ↔ ∀ ⦃b⦄, b ∈ s → a • b ∈ t :=
- image_subset_iff
-
-@[to_additive]
-theorem smul_set_union : a • (t₁ ∪ t₂) = a • t₁ ∪ a • t₂ :=
- image_union _ _ _
-
-@[to_additive]
-theorem smul_set_inter_subset : a • (t₁ ∩ t₂) ⊆ a • t₁ ∩ a • t₂ :=
- image_inter_subset _ _ _
-
-@[to_additive]
-theorem smul_set_iUnion (a : α) (s : ι → Set β) : (a • ⋃ i, s i) = ⋃ i, a • s i :=
- image_iUnion
-
-@[to_additive]
-theorem smul_set_iUnion₂ (a : α) (s : ∀ i, κ i → Set β) :
- (a • ⋃ (i) (j), s i j) = ⋃ (i) (j), a • s i j :=
- image_iUnion₂ _ _
-
-@[to_additive]
-theorem smul_set_iInter_subset (a : α) (t : ι → Set β) : (a • ⋂ i, t i) ⊆ ⋂ i, a • t i :=
- image_iInter_subset _ _
-
-@[to_additive]
-theorem smul_set_iInter₂_subset (a : α) (t : ∀ i, κ i → Set β) :
- (a • ⋂ (i) (j), t i j) ⊆ ⋂ (i) (j), a • t i j :=
- image_iInter₂_subset _ _
-
-@[to_additive]
-theorem Nonempty.smul_set : s.Nonempty → (a • s).Nonempty :=
- Nonempty.image _
-
-end SMulSet
-
section Mul
variable [Mul α] {s t u : Set α} {a : α}
@@ -327,19 +68,6 @@ end Mul
variable {s s₁ s₂ : Set α} {t t₁ t₂ : Set β} {a : α} {b : β}
-@[to_additive]
-theorem range_smul_range {ι κ : Type*} [SMul α β] (b : ι → α) (c : κ → β) :
- range b • range c = range fun p : ι × κ ↦ b p.1 • c p.2 :=
- image2_range ..
-
-@[to_additive]
-theorem smul_set_range [SMul α β] {ι : Sort*} (a : α) (f : ι → β) :
- a • range f = range fun i ↦ a • f i :=
- (range_comp _ _).symm
-
-@[to_additive] lemma range_smul [SMul α β] {ι : Sort*} (a : α) (f : ι → β) :
- range (fun i ↦ a • f i) = a • range f := (smul_set_range ..).symm
-
@[to_additive] lemma range_mul [Mul α] {ι : Sort*} (a : α) (f : ι → α) :
range (fun i ↦ a * f i) = a • range f := range_smul a f
@@ -458,141 +186,8 @@ instance [Zero α] [Mul α] [NoZeroDivisors α] : NoZeroDivisors (Set α) :=
end SMul
-section VSub
-
-variable {ι : Sort*} {κ : ι → Sort*} [VSub α β] {s s₁ s₂ t t₁ t₂ : Set β} {u : Set α} {a : α}
- {b c : β}
-
-instance vsub : VSub (Set α) (Set β) :=
- ⟨image2 (· -ᵥ ·)⟩
-
-@[simp]
-theorem image2_vsub : (image2 VSub.vsub s t : Set α) = s -ᵥ t :=
- rfl
-
-theorem image_vsub_prod : (fun x : β × β ↦ x.fst -ᵥ x.snd) '' s ×ˢ t = s -ᵥ t :=
- image_prod _
-
-theorem mem_vsub : a ∈ s -ᵥ t ↔ ∃ x ∈ s, ∃ y ∈ t, x -ᵥ y = a :=
- Iff.rfl
-
-theorem vsub_mem_vsub (hb : b ∈ s) (hc : c ∈ t) : b -ᵥ c ∈ s -ᵥ t :=
- mem_image2_of_mem hb hc
-
-@[simp]
-theorem empty_vsub (t : Set β) : ∅ -ᵥ t = ∅ :=
- image2_empty_left
-
-@[simp]
-theorem vsub_empty (s : Set β) : s -ᵥ ∅ = ∅ :=
- image2_empty_right
-
-@[simp]
-theorem vsub_eq_empty : s -ᵥ t = ∅ ↔ s = ∅ ∨ t = ∅ :=
- image2_eq_empty_iff
-
-@[simp]
-theorem vsub_nonempty : (s -ᵥ t : Set α).Nonempty ↔ s.Nonempty ∧ t.Nonempty :=
- image2_nonempty_iff
-
-theorem Nonempty.vsub : s.Nonempty → t.Nonempty → (s -ᵥ t : Set α).Nonempty :=
- Nonempty.image2
-
-theorem Nonempty.of_vsub_left : (s -ᵥ t : Set α).Nonempty → s.Nonempty :=
- Nonempty.of_image2_left
-
-theorem Nonempty.of_vsub_right : (s -ᵥ t : Set α).Nonempty → t.Nonempty :=
- Nonempty.of_image2_right
-
-@[simp low+1]
-theorem vsub_singleton (s : Set β) (b : β) : s -ᵥ {b} = (· -ᵥ b) '' s :=
- image2_singleton_right
-
-@[simp low+1]
-theorem singleton_vsub (t : Set β) (b : β) : {b} -ᵥ t = (b -ᵥ ·) '' t :=
- image2_singleton_left
-
-@[simp high]
-theorem singleton_vsub_singleton : ({b} : Set β) -ᵥ {c} = {b -ᵥ c} :=
- image2_singleton
-
-@[mono]
-theorem vsub_subset_vsub : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ -ᵥ t₁ ⊆ s₂ -ᵥ t₂ :=
- image2_subset
-
-theorem vsub_subset_vsub_left : t₁ ⊆ t₂ → s -ᵥ t₁ ⊆ s -ᵥ t₂ :=
- image2_subset_left
-
-theorem vsub_subset_vsub_right : s₁ ⊆ s₂ → s₁ -ᵥ t ⊆ s₂ -ᵥ t :=
- image2_subset_right
-
-theorem vsub_subset_iff : s -ᵥ t ⊆ u ↔ ∀ x ∈ s, ∀ y ∈ t, x -ᵥ y ∈ u :=
- image2_subset_iff
-
-theorem vsub_self_mono (h : s ⊆ t) : s -ᵥ s ⊆ t -ᵥ t :=
- vsub_subset_vsub h h
-
-theorem union_vsub : s₁ ∪ s₂ -ᵥ t = s₁ -ᵥ t ∪ (s₂ -ᵥ t) :=
- image2_union_left
-
-theorem vsub_union : s -ᵥ (t₁ ∪ t₂) = s -ᵥ t₁ ∪ (s -ᵥ t₂) :=
- image2_union_right
-
-theorem inter_vsub_subset : s₁ ∩ s₂ -ᵥ t ⊆ (s₁ -ᵥ t) ∩ (s₂ -ᵥ t) :=
- image2_inter_subset_left
-
-theorem vsub_inter_subset : s -ᵥ t₁ ∩ t₂ ⊆ (s -ᵥ t₁) ∩ (s -ᵥ t₂) :=
- image2_inter_subset_right
-
-theorem inter_vsub_union_subset_union : s₁ ∩ s₂ -ᵥ (t₁ ∪ t₂) ⊆ s₁ -ᵥ t₁ ∪ (s₂ -ᵥ t₂) :=
- image2_inter_union_subset_union
-
-theorem union_vsub_inter_subset_union : s₁ ∪ s₂ -ᵥ t₁ ∩ t₂ ⊆ s₁ -ᵥ t₁ ∪ (s₂ -ᵥ t₂) :=
- image2_union_inter_subset_union
-
-theorem iUnion_vsub_left_image : ⋃ a ∈ s, (a -ᵥ ·) '' t = s -ᵥ t :=
- iUnion_image_left _
-
-theorem iUnion_vsub_right_image : ⋃ a ∈ t, (· -ᵥ a) '' s = s -ᵥ t :=
- iUnion_image_right _
-
-theorem iUnion_vsub (s : ι → Set β) (t : Set β) : (⋃ i, s i) -ᵥ t = ⋃ i, s i -ᵥ t :=
- image2_iUnion_left _ _ _
-
-theorem vsub_iUnion (s : Set β) (t : ι → Set β) : (s -ᵥ ⋃ i, t i) = ⋃ i, s -ᵥ t i :=
- image2_iUnion_right _ _ _
-
-theorem iUnion₂_vsub (s : ∀ i, κ i → Set β) (t : Set β) :
- (⋃ (i) (j), s i j) -ᵥ t = ⋃ (i) (j), s i j -ᵥ t :=
- image2_iUnion₂_left _ _ _
-
-theorem vsub_iUnion₂ (s : Set β) (t : ∀ i, κ i → Set β) :
- (s -ᵥ ⋃ (i) (j), t i j) = ⋃ (i) (j), s -ᵥ t i j :=
- image2_iUnion₂_right _ _ _
-
-theorem iInter_vsub_subset (s : ι → Set β) (t : Set β) : (⋂ i, s i) -ᵥ t ⊆ ⋂ i, s i -ᵥ t :=
- image2_iInter_subset_left _ _ _
-
-theorem vsub_iInter_subset (s : Set β) (t : ι → Set β) : (s -ᵥ ⋂ i, t i) ⊆ ⋂ i, s -ᵥ t i :=
- image2_iInter_subset_right _ _ _
-
-theorem iInter₂_vsub_subset (s : ∀ i, κ i → Set β) (t : Set β) :
- (⋂ (i) (j), s i j) -ᵥ t ⊆ ⋂ (i) (j), s i j -ᵥ t :=
- image2_iInter₂_subset_left _ _ _
-
-theorem vsub_iInter₂_subset (s : Set β) (t : ∀ i, κ i → Set β) :
- (s -ᵥ ⋂ (i) (j), t i j) ⊆ ⋂ (i) (j), s -ᵥ t i j :=
- image2_iInter₂_subset_right _ _ _
-
-end VSub
-
open Pointwise
-@[to_additive]
-theorem image_smul_comm [SMul α β] [SMul α γ] (f : β → γ) (a : α) (s : Set β) :
- (∀ b, f (a • b) = a • f b) → f '' (a • s) = a • f '' s :=
- image_comm
-
@[to_additive]
theorem image_smul_distrib [MulOneClass α] [MulOneClass β] [FunLike F α β] [MonoidHomClass F α β]
(f : F) (a : α) (s : Set α) :
@@ -737,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
@@ -808,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 07ef12d57509b..5464761ef4475 100644
--- a/Mathlib/Data/Set/Prod.lean
+++ b/Mathlib/Data/Set/Prod.lean
@@ -9,13 +9,15 @@ import Mathlib.Data.SProd
/-!
# Sets in product and pi types
-This file defines the product of sets in `α × β` and in `Π i, α i` along with the diagonal of a
-type.
+This file proves basic properties of product of sets in `α × β` and in `Π i, α i`, and of the
+diagonal of a type.
## Main declarations
+This file contains basic results on the following notions, which are defined in `Set.Operations`.
+
* `Set.prod`: Binary product of sets. For `s : Set α`, `t : Set β`, we have
- `s.prod t : Set (α × β)`.
+ `s.prod t : Set (α × β)`. Denoted by `s ×ˢ t`.
* `Set.diagonal`: Diagonal of a type. `Set.diagonal α = {(x, x) | x : α}`.
* `Set.offDiag`: Off-diagonal. `s ×ˢ s` without the diagonal.
* `Set.pi`: Arbitrary product of sets.
@@ -38,7 +40,7 @@ theorem Subsingleton.prod (hs : s.Subsingleton) (ht : t.Subsingleton) :
Prod.ext (hs hx.1 hy.1) (ht hx.2 hy.2)
noncomputable instance decidableMemProd [DecidablePred (· ∈ s)] [DecidablePred (· ∈ t)] :
- DecidablePred (· ∈ s ×ˢ t) := fun _ => And.decidable
+ DecidablePred (· ∈ s ×ˢ t) := fun x => inferInstanceAs (Decidable (x.1 ∈ s ∧ x.2 ∈ t))
@[gcongr]
theorem prod_mono (hs : s₁ ⊆ s₂) (ht : t₁ ⊆ t₂) : s₁ ×ˢ t₁ ⊆ s₂ ×ˢ t₂ :=
@@ -72,17 +74,17 @@ theorem exists_prod_set {p : α × β → Prop} : (∃ x ∈ s ×ˢ t, p x) ↔
@[simp]
theorem prod_empty : s ×ˢ (∅ : Set β) = ∅ := by
ext
- exact and_false_iff _
+ exact iff_of_eq (and_false _)
@[simp]
theorem empty_prod : (∅ : Set α) ×ˢ t = ∅ := by
ext
- exact false_and_iff _
+ exact iff_of_eq (false_and _)
@[simp, mfld_simps]
theorem univ_prod_univ : @univ α ×ˢ @univ β = univ := by
ext
- exact true_and_iff _
+ exact iff_of_eq (true_and _)
theorem univ_prod {t : Set β} : (univ : Set α) ×ˢ t = Prod.snd ⁻¹' t := by simp [prod_eq]
@@ -299,6 +301,9 @@ theorem fst_image_prod (s : Set β) {t : Set α} (ht : t.Nonempty) : Prod.fst ''
let ⟨x, hx⟩ := ht
⟨(y, x), ⟨hy, hx⟩, rfl⟩
+lemma mapsTo_fst_prod {s : Set α} {t : Set β} : MapsTo Prod.fst (s ×ˢ t) s :=
+ fun _ hx ↦ (mem_prod.1 hx).1
+
theorem prod_subset_preimage_snd (s : Set α) (t : Set β) : s ×ˢ t ⊆ Prod.snd ⁻¹' t :=
inter_subset_right
@@ -310,6 +315,9 @@ theorem snd_image_prod {s : Set α} (hs : s.Nonempty) (t : Set β) : Prod.snd ''
let ⟨x, x_in⟩ := hs
⟨(x, y), ⟨x_in, y_in⟩, rfl⟩
+lemma mapsTo_snd_prod {s : Set α} {t : Set β} : MapsTo Prod.snd (s ×ˢ t) t :=
+ fun _ hx ↦ (mem_prod.1 hx).2
+
theorem prod_diff_prod : s ×ˢ t \ s₁ ×ˢ t₁ = s ×ˢ (t \ t₁) ∪ (s \ s₁) ×ˢ t := by
ext x
by_cases h₁ : x.1 ∈ s₁ <;> by_cases h₂ : x.2 ∈ t₁ <;> simp [*]
@@ -326,7 +334,7 @@ theorem prod_subset_prod_iff : s ×ˢ t ⊆ s₁ ×ˢ t₁ ↔ s ⊆ s₁ ∧ t
· have := image_subset (Prod.snd : α × β → β) H
rwa [snd_image_prod st.1, snd_image_prod (h.mono H).fst] at this
· intro H
- simp only [st.1.ne_empty, st.2.ne_empty, or_false_iff] at H
+ simp only [st.1.ne_empty, st.2.ne_empty, or_false] at H
exact prod_mono H.1 H.2
theorem prod_eq_prod_iff_of_nonempty (h : (s ×ˢ t).Nonempty) :
@@ -335,7 +343,7 @@ theorem prod_eq_prod_iff_of_nonempty (h : (s ×ˢ t).Nonempty) :
· intro heq
have h₁ : (s₁ ×ˢ t₁ : Set _).Nonempty := by rwa [← heq]
rw [prod_nonempty_iff] at h h₁
- rw [← fst_image_prod s h.2, ← fst_image_prod s₁ h₁.2, heq, eq_self_iff_true, true_and_iff, ←
+ rw [← fst_image_prod s h.2, ← fst_image_prod s₁ h₁.2, heq, eq_self_iff_true, true_and, ←
snd_image_prod h.1 t, ← snd_image_prod h₁.1 t₁, heq]
· rintro ⟨rfl, rfl⟩
rfl
@@ -344,18 +352,17 @@ theorem prod_eq_prod_iff :
s ×ˢ t = s₁ ×ˢ t₁ ↔ s = s₁ ∧ t = t₁ ∨ (s = ∅ ∨ t = ∅) ∧ (s₁ = ∅ ∨ t₁ = ∅) := by
symm
rcases eq_empty_or_nonempty (s ×ˢ t) with h | h
- · simp_rw [h, @eq_comm _ ∅, prod_eq_empty_iff, prod_eq_empty_iff.mp h, true_and_iff,
+ · simp_rw [h, @eq_comm _ ∅, prod_eq_empty_iff, prod_eq_empty_iff.mp h, true_and,
or_iff_right_iff_imp]
rintro ⟨rfl, rfl⟩
exact prod_eq_empty_iff.mp h
rw [prod_eq_prod_iff_of_nonempty h]
rw [nonempty_iff_ne_empty, Ne, prod_eq_empty_iff] at h
- simp_rw [h, false_and_iff, or_false_iff]
+ simp_rw [h, false_and, or_false]
@[simp]
theorem prod_eq_iff_eq (ht : t.Nonempty) : s ×ˢ t = s₁ ×ˢ t ↔ s = s₁ := by
- simp_rw [prod_eq_prod_iff, ht.ne_empty, and_true_iff, or_iff_left_iff_imp,
- or_false_iff]
+ simp_rw [prod_eq_prod_iff, ht.ne_empty, and_true, or_iff_left_iff_imp, or_false]
rintro ⟨rfl, rfl⟩
rfl
@@ -525,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 _
@@ -631,7 +638,7 @@ theorem pi_congr (h : s₁ = s₂) (h' : ∀ i ∈ s₁, t₁ i = t₂ i) : s₁
theorem pi_eq_empty (hs : i ∈ s) (ht : t i = ∅) : s.pi t = ∅ := by
ext f
- simp only [mem_empty_iff_false, not_forall, iff_false_iff, mem_pi, Classical.not_imp]
+ simp only [mem_empty_iff_false, not_forall, iff_false, mem_pi, Classical.not_imp]
exact ⟨i, hs, by simp [ht]⟩
theorem univ_pi_eq_empty (ht : t i = ∅) : pi univ t = ∅ :=
@@ -679,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
@@ -802,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
@@ -815,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
@@ -831,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 65db6ecc8dee6..e275628926e7c 100644
--- a/Mathlib/Data/Set/Semiring.lean
+++ b/Mathlib/Data/Set/Semiring.lean
@@ -3,7 +3,7 @@ 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.Algebra.Group.Pointwise.Set
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.Algebra.Order.Kleene
import Mathlib.Algebra.Order.Ring.Canonical
@@ -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/Sigma.lean b/Mathlib/Data/Set/Sigma.lean
index b10a51f01db79..7201429b16acc 100644
--- a/Mathlib/Data/Set/Sigma.lean
+++ b/Mathlib/Data/Set/Sigma.lean
@@ -68,15 +68,17 @@ theorem exists_sigma_iff {p : (Σi, α i) → Prop} :
(∃ x ∈ s.sigma t, p x) ↔ ∃ i ∈ s, ∃ a ∈ t i, p ⟨i, a⟩ :=
⟨fun ⟨⟨i, a⟩, ha, h⟩ ↦ ⟨i, ha.1, a, ha.2, h⟩, fun ⟨i, hi, a, ha, h⟩ ↦ ⟨⟨i, a⟩, ⟨hi, ha⟩, h⟩⟩
-@[simp] theorem sigma_empty : s.sigma (fun i ↦ (∅ : Set (α i))) = ∅ := ext fun _ ↦ and_false_iff _
+@[simp] theorem sigma_empty : s.sigma (fun i ↦ (∅ : Set (α i))) = ∅ :=
+ ext fun _ ↦ iff_of_eq (and_false _)
-@[simp] theorem empty_sigma : (∅ : Set ι).sigma t = ∅ := ext fun _ ↦ false_and_iff _
+@[simp] theorem empty_sigma : (∅ : Set ι).sigma t = ∅ := ext fun _ ↦ iff_of_eq (false_and _)
-theorem univ_sigma_univ : (@univ ι).sigma (fun _ ↦ @univ (α i)) = univ := ext fun _ ↦ true_and_iff _
+theorem univ_sigma_univ : (@univ ι).sigma (fun _ ↦ @univ (α i)) = univ :=
+ ext fun _ ↦ iff_of_eq (true_and _)
@[simp]
theorem sigma_univ : s.sigma (fun _ ↦ univ : ∀ i, Set (α i)) = Sigma.fst ⁻¹' s :=
- ext fun _ ↦ and_true_iff _
+ ext fun _ ↦ iff_of_eq (and_true _)
@[simp] theorem univ_sigma_preimage_mk (s : Set (Σ i, α i)) :
(univ : Set ι).sigma (fun i ↦ Sigma.mk i ⁻¹' s) = s :=
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/Subsingleton.lean b/Mathlib/Data/Set/Subsingleton.lean
index b31273026245f..fa736da6540c2 100644
--- a/Mathlib/Data/Set/Subsingleton.lean
+++ b/Mathlib/Data/Set/Subsingleton.lean
@@ -215,7 +215,7 @@ theorem Nontrivial.ne_singleton {x} (hs : s.Nontrivial) : s ≠ {x} := fun H =>
exact not_nontrivial_singleton hs
theorem Nontrivial.not_subset_singleton {x} (hs : s.Nontrivial) : ¬s ⊆ {x} :=
- (not_congr subset_singleton_iff_eq).2 (not_or_of_not hs.ne_empty hs.ne_singleton)
+ (not_congr subset_singleton_iff_eq).2 (not_or_intro hs.ne_empty hs.ne_singleton)
theorem nontrivial_univ [Nontrivial α] : (univ : Set α).Nontrivial :=
let ⟨x, y, hxy⟩ := exists_pair_ne α
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 fa52573699827..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.
@@ -121,9 +121,9 @@ uses the `SetLike.instMembership` instance. -/
def delabSubtypeSetLike : Delab := whenPPOption getPPNotation do
let #[_, .lam n _ body _] := (← getExpr).getAppArgs | failure
guard <| body.isAppOf ``Membership.mem
- let #[_, _, inst, .bvar 0, _] := body.getAppArgs | failure
+ let #[_, _, inst, _, .bvar 0] := body.getAppArgs | failure
guard <| inst.isAppOfArity ``instMembership 3
- let S ← withAppArg <| withBindingBody n <| withNaryArg 4 delab
+ let S ← withAppArg <| withBindingBody n <| withNaryArg 3 delab
`(↥$S)
end Delab
@@ -191,17 +191,15 @@ instance (priority := 100) instPartialOrder : PartialOrder A :=
theorem le_def {S T : A} : S ≤ T ↔ ∀ ⦃x : B⦄, x ∈ S → x ∈ T :=
Iff.rfl
-@[simp, norm_cast]
-theorem coe_subset_coe {S T : A} : (S : Set B) ⊆ T ↔ S ≤ T :=
- Iff.rfl
+@[simp, norm_cast] lemma coe_subset_coe {S T : A} : (S : Set B) ⊆ T ↔ S ≤ T := .rfl
+@[simp, norm_cast] lemma coe_ssubset_coe {S T : A} : (S : Set B) ⊂ T ↔ S < T := .rfl
+
+@[gcongr] protected alias ⟨_, GCongr.coe_subset_coe⟩ := coe_subset_coe
+@[gcongr] protected alias ⟨_, GCongr.coe_ssubset_coe⟩ := coe_ssubset_coe
@[mono]
theorem coe_mono : Monotone (SetLike.coe : A → Set B) := fun _ _ => coe_subset_coe.mpr
-@[simp, norm_cast]
-theorem coe_ssubset_coe {S T : A} : (S : Set B) ⊂ T ↔ S < T :=
- Iff.rfl
-
@[mono]
theorem coe_strictMono : StrictMono (SetLike.coe : A → Set B) := fun _ _ => coe_ssubset_coe.mpr
diff --git a/Mathlib/Data/Setoid/Basic.lean b/Mathlib/Data/Setoid/Basic.lean
index ca1d0ac665068..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⟩
@@ -420,7 +473,7 @@ def sigmaQuotientEquivOfLe {r s : Setoid α} (hle : r ≤ s) :
(Σ q : Quotient s, Quotient (r.comap (Subtype.val : Quotient.mk s ⁻¹' {q} → α))) ≃
Quotient r :=
.trans (.symm <| .sigmaCongrRight fun _ ↦ .subtypeQuotientEquivQuotientSubtype
- (s₁ := r) (s₂ := r.comap Subtype.val) _ (fun _ ↦ Iff.rfl) fun _ _ ↦ Iff.rfl)
+ (s₁ := r) (s₂ := r.comap Subtype.val) _ _ (fun _ ↦ Iff.rfl) fun _ _ ↦ Iff.rfl)
(.sigmaFiberEquiv fun a ↦ a.lift (Quotient.mk s) fun _ _ h ↦ Quotient.sound <| hle h)
end Setoid
@@ -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 99c98349ad745..d77a4e02a1f33 100644
--- a/Mathlib/Data/String/Basic.lean
+++ b/Mathlib/Data/String/Basic.lean
@@ -3,9 +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
-/
+import Batteries.Data.String.Lemmas
import Mathlib.Data.List.Lex
import Mathlib.Data.Char
-import Mathlib.Tactic.AdaptationNote
import Mathlib.Algebra.Order.Group.Nat
/-!
@@ -16,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
@@ -75,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,
@@ -138,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/Subtype.lean b/Mathlib/Data/Subtype.lean
index 48aaa0d08f165..0583ba40e98cc 100644
--- a/Mathlib/Data/Subtype.lean
+++ b/Mathlib/Data/Subtype.lean
@@ -207,7 +207,7 @@ end Subtype
namespace Subtype
/-! Some facts about sets, which require that `α` is a type. -/
-variable {α β γ : Type*} {p : α → Prop}
+variable {α : Type*}
@[simp]
theorem coe_prop {S : Set α} (a : { a // a ∈ S }) : ↑a ∈ S :=
diff --git a/Mathlib/Data/Sum/Basic.lean b/Mathlib/Data/Sum/Basic.lean
index 9da00e98e9adb..d65e9ce7874fe 100644
--- a/Mathlib/Data/Sum/Basic.lean
+++ b/Mathlib/Data/Sum/Basic.lean
@@ -35,7 +35,7 @@ theorem sum_rec_congr (P : α ⊕ β → Sort*) (f : ∀ i, P (inl i)) (g : ∀
section get
-variable {x y : α ⊕ β}
+variable {x : α ⊕ β}
theorem eq_left_iff_getLeft_eq {a : α} : x = inl a ↔ ∃ h, x.getLeft h = a := by
cases x <;> simp
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 e94c465684a68..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
@@ -299,8 +299,7 @@ instance : SetLike (Sym2 α) α where
induction' z with x y
induction' z' with x' y'
have hx := h x; have hy := h y; have hx' := h x'; have hy' := h y'
- simp only [mem_iff', eq_self_iff_true, or_true_iff, iff_true_iff,
- true_or_iff, true_iff_iff] at hx hy hx' hy'
+ simp only [mem_iff', eq_self_iff_true] at hx hy hx' hy'
aesop
@[simp]
@@ -457,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 :=
@@ -648,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]
@@ -661,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 81ec5ceb94570..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 α :=
@@ -119,7 +119,7 @@ def take (i : ℕ) : Vector α n → Vector α (min i n)
/-- Remove the element at position `i` from a vector of length `n`. -/
def eraseIdx (i : Fin n) : Vector α n → Vector α (n - 1)
- | ⟨l, p⟩ => ⟨List.eraseIdx l i.1, by rw [l.length_eraseIdx] <;> rw [p]; exact i.2⟩
+ | ⟨l, p⟩ => ⟨List.eraseIdx l i.1, by rw [l.length_eraseIdx_of_lt] <;> rw [p]; exact i.2⟩
@[deprecated (since := "2024-05-04")] alias removeNth := eraseIdx
diff --git a/Mathlib/Data/Vector/Zip.lean b/Mathlib/Data/Vector/Zip.lean
index eee02c2029439..f8c69ad4814b4 100644
--- a/Mathlib/Data/Vector/Zip.lean
+++ b/Mathlib/Data/Vector/Zip.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Data.Vector.Basic
diff --git a/Mathlib/Data/Vector3.lean b/Mathlib/Data/Vector3.lean
index 4e0562d15422e..d1c8061307db8 100644
--- a/Mathlib/Data/Vector3.lean
+++ b/Mathlib/Data/Vector3.lean
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
import Mathlib.Data.Fin.Fin2
-import Mathlib.Init.Logic
import Mathlib.Util.Notation3
import Mathlib.Tactic.TypeStar
@@ -147,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`. -/
@@ -206,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
@@ -236,7 +235,7 @@ theorem vectorAllP_singleton (p : α → Prop) (x : α) : VectorAllP p (cons x [
@[simp]
theorem vectorAllP_cons (p : α → Prop) (x : α) (v : Vector3 α n) :
VectorAllP p (x :: v) ↔ p x ∧ VectorAllP p v :=
- Vector3.recOn v (and_true_iff _).symm fun _ _ _ => Iff.rfl
+ Vector3.recOn v (iff_of_eq (and_true _)).symm fun _ _ _ => Iff.rfl
theorem vectorAllP_iff_forall (p : α → Prop) (v : Vector3 α n) :
VectorAllP p v ↔ ∀ i, p (v i) := by
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 a1afa41447cfb..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
@@ -435,7 +435,7 @@ theorem castHom_bijective [Fintype R] (h : Fintype.card R = n) :
intro hn
rw [hn] at h
exact (Fintype.card_eq_zero_iff.mp h).elim' 0⟩
- rw [Fintype.bijective_iff_injective_and_card, ZMod.card, h, eq_self_iff_true, and_true_iff]
+ rw [Fintype.bijective_iff_injective_and_card, ZMod.card, h, eq_self_iff_true, and_true]
apply ZMod.castHom_injective
/-- The unique ring isomorphism between `ZMod n` and a ring `R`
@@ -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 =>
@@ -826,6 +825,17 @@ theorem eq_iff_modEq_nat (n : ℕ) {a b : ℕ} : (a : ZMod n) = b ↔ a ≡ b [M
· rw [Fin.ext_iff, Nat.ModEq, ← val_natCast, ← val_natCast]
exact Iff.rfl
+theorem eq_zero_iff_even {n : ℕ} : (n : ZMod 2) = 0 ↔ Even n :=
+ (CharP.cast_eq_zero_iff (ZMod 2) 2 n).trans even_iff_two_dvd.symm
+
+theorem eq_one_iff_odd {n : ℕ} : (n : ZMod 2) = 1 ↔ Odd n := by
+ rw [← @Nat.cast_one (ZMod 2), ZMod.eq_iff_modEq_nat, Nat.odd_iff, Nat.ModEq]
+
+theorem ne_zero_iff_odd {n : ℕ} : (n : ZMod 2) ≠ 0 ↔ Odd n := by
+ constructor <;>
+ · contrapose
+ simp [eq_zero_iff_even]
+
theorem coe_mul_inv_eq_one {n : ℕ} (x : ℕ) (h : Nat.Coprime x n) :
((x : ZMod n) * (x : ZMod n)⁻¹) = 1 := by
rw [Nat.Coprime, Nat.gcd_comm, Nat.gcd_rec] at h
@@ -1005,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)⟩
@@ -1014,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
@@ -1128,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
@@ -1207,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
@@ -1320,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
@@ -1421,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
@@ -1442,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 324dec3252219..97124f237c44e 100644
--- a/Mathlib/Data/ZMod/Defs.lean
+++ b/Mathlib/Data/ZMod/Defs.lean
@@ -5,6 +5,7 @@ Authors: Eric Rodriguez
-/
import Mathlib.Algebra.Group.Fin.Basic
import Mathlib.Algebra.NeZero
+import Mathlib.Algebra.Ring.Int
import Mathlib.Data.Nat.ModEq
import Mathlib.Data.Fintype.Card
@@ -15,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`.
-/
@@ -44,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 _
@@ -53,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 _
@@ -103,7 +104,7 @@ namespace ZMod
instance instUnique : Unique (ZMod 1) := Fin.uniqueFinOne
instance fintype : ∀ (n : ℕ) [NeZero n], Fintype (ZMod n)
- | 0, h => (h.ne rfl).elim
+ | 0, h => (h.ne _ rfl).elim
| n + 1, _ => Fin.fintype (n + 1)
instance infinite : Infinite (ZMod 0) :=
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/Parity.lean b/Mathlib/Data/ZMod/Parity.lean
deleted file mode 100644
index b6686f1e23ec5..0000000000000
--- a/Mathlib/Data/ZMod/Parity.lean
+++ /dev/null
@@ -1,33 +0,0 @@
-/-
-Copyright (c) 2020 Kyle Miller. All rights reserved.
-Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kyle Miller
--/
-import Mathlib.Algebra.Order.Ring.Abs
-import Mathlib.Data.ZMod.Basic
-
-/-!
-# Relating parity to natural numbers mod 2
-
-This module provides lemmas relating `ZMod 2` to `Even` and `Odd`.
-
-## Tags
-
-parity, zmod, even, odd
--/
-
-
-namespace ZMod
-
-theorem eq_zero_iff_even {n : ℕ} : (n : ZMod 2) = 0 ↔ Even n :=
- (CharP.cast_eq_zero_iff (ZMod 2) 2 n).trans even_iff_two_dvd.symm
-
-theorem eq_one_iff_odd {n : ℕ} : (n : ZMod 2) = 1 ↔ Odd n := by
- rw [← @Nat.cast_one (ZMod 2), ZMod.eq_iff_modEq_nat, Nat.odd_iff, Nat.ModEq]
-
-theorem ne_zero_iff_odd {n : ℕ} : (n : ZMod 2) ≠ 0 ↔ Odd n := by
- constructor <;>
- · contrapose
- simp [eq_zero_iff_even]
-
-end ZMod
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/Data/ZMod/Units.lean b/Mathlib/Data/ZMod/Units.lean
index 319a7d55013c4..3d4def6281661 100644
--- a/Mathlib/Data/ZMod/Units.lean
+++ b/Mathlib/Data/ZMod/Units.lean
@@ -42,7 +42,7 @@ theorem unitsMap_surjective [hm : NeZero m] (h : n ∣ m) :
have ⟨k, hk⟩ := this x.val.val (val_coe_unit_coprime x)
refine ⟨unitOfCoprime _ hk, Units.ext ?_⟩
have : NeZero n := ⟨fun hn ↦ hm.out (eq_zero_of_zero_dvd (hn ▸ h))⟩
- simp [unitsMap_def]
+ simp [unitsMap_def, - castHom_apply]
intro x hx
let ps := m.primeFactors.filter (fun p ↦ ¬p ∣ x)
use ps.prod id
diff --git a/Mathlib/Init/Algebra/Classes.lean b/Mathlib/Deprecated/AlgebraClasses.lean
similarity index 50%
rename from Mathlib/Init/Algebra/Classes.lean
rename to Mathlib/Deprecated/AlgebraClasses.lean
index e5149ae4efa16..cc26f497422b2 100644
--- a/Mathlib/Init/Algebra/Classes.lean
+++ b/Mathlib/Deprecated/AlgebraClasses.lean
@@ -3,154 +3,36 @@ 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 Mathlib.Init.Logic
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.
-
-(Yaël): The only things of interest in this file now are the unbundled algebra classes
+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
-These classes are part of an incomplete refactor described
+These classes were part of an incomplete refactor described
[here on the github Wiki](https://github.com/leanprover/lean/wiki/Refactoring-structures#encoding-the-algebraic-hierarchy-1).
However a subset of them are widely used in mathlib3,
and it has been tricky to clean this up as this file was in core Lean 3.
-
-By themselves, these classes are not good replacements for the `Monoid` / `Group` etc structures
-provided by mathlib, as they are not discoverable by `simp` unlike the current lemmas due to there
-being little to index on. The Wiki page linked above describes an algebraic normalizer, but it was
-never implemented in Lean 3.
-
-## Porting note:
-This file is ancient, and it would be good to replace it with a clean version
-that provides what mathlib4 actually needs.
-
-I've omitted all the `@[algebra]` attributes, as they are not used elsewhere.
-
-The section `StrictWeakOrder` has been omitted, but I've left the mathport output in place.
-Please delete if cleaning up.
-
-I've commented out some classes which we think are completely unused in mathlib.
-
-I've added many of the declarations to `nolints.json`.
-If you clean up this file, please add documentation to classes that we are keeping.
-
-Mario made the following analysis of uses in mathlib3:
-* `is_symm_op`: unused except for some instances
-* `is_commutative`: used a fair amount via some theorems about folds
- (also assuming `is_associative`)
-* `is_associative`: ditto, also used in `noncomm_fold`
-* `is_left_id`, `is_right_id`: unused except in the mathlib class `is_unital` and in `mono`
- (which looks like it could use `is_unital`)
-* `is_left_null`, `is_right_null`: unused
-* `is_left_cancel`, `is_right_cancel`: unused except for instances
-* `is_idempotent`: this one is actually used to prove things not directly about `is_idempotent`
-* `is_left_distrib`, `is_right_distrib`, `is_left_inv`, `is_right_inv`, `is_cond_left_inv`,
- `is_cond_right_inv`: unused
-* `is_distinct`: unused (although we reinvented this one as `nontrivial`)
-* `is_irrefl`, `is_refl`, `is_symm`, `is_trans`: significant usage
-* `is_asymm`, `is_antisymm`, `is_total`, `is_strict_order`: a lot of uses but all in order theory
- and it's unclear how much could not be transferred to another typeclass
-* `is_preorder`: unused except for instances
- (except `antisymmetrization`, maybe it could be transferred)
-* `is_total_preorder`, `is_partial_order`: unused except for instances
-* `is_linear_order`: unused except for instances
-* `is_equiv`: unused except for instances (most uses can use `equivalence` instead)
-* `is_per`: unused
-* `is_incomp_trans`: unused
-* `is_strict_weak_order`: significant usage (most of it on `rbmap`, could be transferred)
-* `is_trichotomous`: some usage
-* `is_strict_total_order`: looks like the only usage is in `rbmap` again
-/
set_option linter.deprecated false
universe u v
--- Porting note: removed `outParam`
-class IsSymmOp (α : Sort u) (β : Sort v) (op : α → α → β) : Prop where
- symm_op : ∀ a b, op a b = op b a
-
-/-- A commutative binary operation. -/
-@[deprecated Std.Commutative (since := "2024-02-02")]
-abbrev IsCommutative (α : Sort u) (op : α → α → α) := Std.Commutative op
-
-instance (priority := 100) isSymmOp_of_isCommutative (α : Sort u) (op : α → α → α)
- [Std.Commutative op] : IsSymmOp α α op where symm_op := Std.Commutative.comm
-
-/-- An associative binary operation. -/
-@[deprecated Std.Associative (since := "2024-02-02")]
-abbrev IsAssociative (α : Sort u) (op : α → α → α) := Std.Associative op
-
-/-- A binary operation with a left identity. -/
-@[deprecated Std.LawfulLeftIdentity (since := "2024-02-02")]
-abbrev IsLeftId (α : Sort u) (op : α → α → α) (o : outParam α) := Std.LawfulLeftIdentity op o
-
-/-- A binary operation with a right identity. -/
-@[deprecated Std.LawfulRightIdentity (since := "2024-02-02")]
-abbrev IsRightId (α : Sort u) (op : α → α → α) (o : outParam α) := Std.LawfulRightIdentity op o
-
--- class IsLeftNull (α : Sort u) (op : α → α → α) (o : outParam α) : Prop where
--- left_null : ∀ a, op o a = o
-
--- class IsRightNull (α : Sort u) (op : α → α → α) (o : outParam α) : Prop where
--- right_null : ∀ a, op a o = o
+variable {α : Sort u}
+@[deprecated (since := "2024-09-11")]
class IsLeftCancel (α : Sort u) (op : α → α → α) : Prop where
left_cancel : ∀ a b c, op a b = op a c → b = c
+@[deprecated (since := "2024-09-11")]
class IsRightCancel (α : Sort u) (op : α → α → α) : Prop where
right_cancel : ∀ a b c, op a b = op c b → a = c
-@[deprecated Std.IdempotentOp (since := "2024-02-02")]
-abbrev IsIdempotent (α : Sort u) (op : α → α → α) := Std.IdempotentOp op
-
--- class IsLeftDistrib (α : Sort u) (op₁ : α → α → α) (op₂ : outParam <| α → α → α) : Prop where
--- left_distrib : ∀ a b c, op₁ a (op₂ b c) = op₂ (op₁ a b) (op₁ a c)
-
--- class IsRightDistrib (α : Sort u) (op₁ : α → α → α) (op₂ : outParam <| α → α → α) : Prop where
--- right_distrib : ∀ a b c, op₁ (op₂ a b) c = op₂ (op₁ a c) (op₁ b c)
-
--- class IsLeftInv (α : Sort u) (op : α → α → α) (inv : outParam <| α → α) (o : outParam α) :
--- Prop where
--- left_inv : ∀ a, op (inv a) a = o
-
--- class IsRightInv (α : Sort u) (op : α → α → α) (inv : outParam <| α → α) (o : outParam α) :
--- Prop where
--- right_inv : ∀ a, op a (inv a) = o
-
--- class IsCondLeftInv (α : Sort u) (op : α → α → α) (inv : outParam <| α → α) (o : outParam α)
--- (p : outParam <| α → Prop) : Prop where
--- left_inv : ∀ a, p a → op (inv a) a = o
-
--- class IsCondRightInv (α : Sort u) (op : α → α → α) (inv : outParam <| α → α) (o : outParam α)
--- (p : outParam <| α → Prop) : Prop where
--- right_inv : ∀ a, p a → op a (inv a) = o
-
--- class IsDistinct (α : Sort u) (a : α) (b : α) : Prop where
--- distinct : a ≠ b
-
-/-
--- The following type class doesn't seem very useful, a regular simp lemma should work for this.
-class is_inv (α : Sort u) (β : Sort v) (f : α → β) (g : out β → α) : Prop :=
-(inv : ∀ a, g (f a) = a)
-
--- The following one can also be handled using a regular simp lemma
-class is_idempotent (α : Sort u) (f : α → α) : Prop :=
-(idempotent : ∀ a, f (f a) = f a)
--/
-
-/-- The opposite of a symmetric relation is symmetric. -/
-instance (priority := 100) isSymmOp_of_isSymm (α : Sort u) (r : α → α → Prop) [IsSymm α r] :
- IsSymmOp α Prop r where symm_op a b := propext <| Iff.intro (IsSymm.symm a b) (IsSymm.symm b a)
-
/-- `IsTotalPreorder X r` means that the binary relation `r` on `X` is total and a preorder. -/
@[deprecated (since := "2024-07-30")]
class IsTotalPreorder (α : Sort u) (r : α → α → Prop) extends IsTrans α r, IsTotal α r : Prop
@@ -161,10 +43,6 @@ instance (priority := 100) isTotalPreorder_isPreorder (α : Sort u) (r : α →
trans := s.trans
refl a := Or.elim (@IsTotal.total _ r _ a a) id id
--- /-- `IsPer X r` means that the binary relation `r` on `X` is a partial equivalence relation, that
--- is, `IsSymm X r` and `IsTrans X r`. -/
--- class IsPer (α : Sort u) (r : α → α → Prop) extends IsSymm α r, IsTrans α r : Prop
-
/-- `IsIncompTrans X lt` means that for `lt` a binary relation on `X`, the incomparable relation
`fun a b => ¬ lt a b ∧ ¬ lt b a` is transitive. -/
@[deprecated (since := "2024-07-30")]
@@ -177,7 +55,7 @@ instance (priority := 100) (α : Sort u) (lt : α → α → Prop) [IsStrictWeak
section
-variable {α : Sort u} {r : α → α → Prop}
+variable {r : α → α → Prop}
local infixl:50 " ≺ " => r
@@ -203,7 +81,7 @@ namespace StrictWeakOrder
section
-variable {α : Sort u} {r : α → α → Prop}
+variable {r : α → α → Prop}
local infixl:50 " ≺ " => r
@@ -241,7 +119,7 @@ instance isEquiv : IsEquiv α (@Equiv _ r) where
end
/-- The equivalence relation induced by `lt` -/
-notation:50 a " ≈[" lt "]" b:50 => @Equiv _ lt a b--Equiv (r := lt) a b
+notation:50 a " ≈[" lt "]" b:50 => @Equiv _ lt a b
end StrictWeakOrder
@@ -276,7 +154,6 @@ instance : IsTotalPreorder α (· ≤ ·) where
trans := @le_trans _ _
total := le_total
--- TODO(Leo): decide whether we should keep this instance or not
set_option linter.deprecated false in
@[deprecated (since := "2024-07-30")]
instance isStrictWeakOrder_of_linearOrder : IsStrictWeakOrder α (· < ·) :=
@@ -290,7 +167,7 @@ theorem lt_of_lt_of_incomp {α : Sort u} {lt : α → α → Prop} [IsStrictWeak
[DecidableRel lt] : ∀ {a b c}, lt a b → ¬lt b c ∧ ¬lt c b → lt a c :=
@fun a b c hab ⟨nbc, ncb⟩ =>
have nca : ¬lt c a := fun hca => absurd (trans_of lt hca hab) ncb
- Decidable.by_contradiction fun nac : ¬lt a c =>
+ Decidable.byContradiction fun nac : ¬lt a c =>
have : ¬lt a b ∧ ¬lt b a := incomp_trans_of lt ⟨nac, nca⟩ ⟨ncb, nbc⟩
absurd hab this.1
@@ -299,7 +176,7 @@ theorem lt_of_incomp_of_lt {α : Sort u} {lt : α → α → Prop} [IsStrictWeak
[DecidableRel lt] : ∀ {a b c}, ¬lt a b ∧ ¬lt b a → lt b c → lt a c :=
@fun a b c ⟨nab, nba⟩ hbc =>
have nca : ¬lt c a := fun hca => absurd (trans_of lt hbc hca) nba
- Decidable.by_contradiction fun nac : ¬lt a c =>
+ Decidable.byContradiction fun nac : ¬lt a c =>
have : ¬lt b c ∧ ¬lt c b := incomp_trans_of lt ⟨nba, nab⟩ ⟨nac, nca⟩
absurd hbc this.1
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/Deprecated/HashMap.lean b/Mathlib/Deprecated/HashMap.lean
index a25770f9840a0..b5c815bd6e5a0 100644
--- a/Mathlib/Deprecated/HashMap.lean
+++ b/Mathlib/Deprecated/HashMap.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
diff --git a/Mathlib/Init/Logic.lean b/Mathlib/Deprecated/Logic.lean
similarity index 51%
rename from Mathlib/Init/Logic.lean
rename to Mathlib/Deprecated/Logic.lean
index 40c2fd17cf866..0117b26449c81 100644
--- a/Mathlib/Init/Logic.lean
+++ b/Mathlib/Deprecated/Logic.lean
@@ -3,237 +3,167 @@ Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Jeremy Avigad, Floris van Doorn
-/
-import Mathlib.Tactic.Lemma
-import Mathlib.Tactic.Relation.Trans
-import Mathlib.Tactic.ProjectionNotation
import Batteries.Tactic.Alias
-import Batteries.Tactic.Lint.Misc
+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
+
universe u v
variable {α : Sort u}
-/- Eq -/
+section Binary
-theorem not_of_eq_false {p : Prop} (h : p = False) : ¬p := fun hp ↦ h ▸ hp
+variable {α : Type u} {β : Type v} (f : α → α → α) (inv : α → α) (one : α)
-theorem cast_proof_irrel {β : Sort u} (h₁ h₂ : α = β) (a : α) : cast h₁ a = cast h₂ a := rfl
+/-- Local notation for `f`, high priority to avoid ambiguity with `HMul.hMul`. -/
+local infix:70 (priority := high) " * " => f
-attribute [symm] Eq.symm
+/-- Local notation for `inv`, high priority to avoid ambiguity with `Inv.inv`. -/
+local postfix:100 (priority := high) "⁻¹" => inv
-/- Ne -/
+variable (g : α → α → α)
-attribute [symm] Ne.symm
+/-- Local notation for `g`, high priority to avoid ambiguity with `HAdd.hAdd`. -/
+local infix:65 (priority := high) " + " => g
-/- HEq -/
+@[deprecated Std.Commutative (since := "2024-09-13")]
+def Commutative := ∀ a b, a * b = b * a
+@[deprecated Std.Associative (since := "2024-09-13")]
+def Associative := ∀ a b c, (a * b) * c = a * (b * c)
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
+def LeftIdentity := ∀ a, one * a = a
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
+def RightIdentity := ∀ a, a * one = a
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
+def RightInverse := ∀ a, a * a⁻¹ = one
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
+def LeftCancelative := ∀ a b c, a * b = a * c → b = c
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
+def RightCancelative := ∀ a b c, a * b = c * b → a = c
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
+def LeftDistributive := ∀ a b c, a * (b + c) = a * b + a * c
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
+def RightDistributive := ∀ a b c, (a + b) * c = a * c + b * c
-alias eq_rec_heq := eqRec_heq
+end Binary
--- FIXME This is still rejected after #857
--- attribute [refl] HEq.refl
-attribute [symm] HEq.symm
-attribute [trans] HEq.trans
-attribute [trans] heq_of_eq_of_heq
+@[deprecated (since := "2024-09-03")] alias not_of_eq_false := of_eq_false
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
+theorem cast_proof_irrel {β : Sort u} (h₁ h₂ : α = β) (a : α) : cast h₁ a = cast h₂ a := rfl
+@[deprecated (since := "2024-09-03")] alias eq_rec_heq := eqRec_heq
+@[deprecated (since := "2024-09-03")] alias heq_prop := proof_irrel_heq
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem heq_of_eq_rec_left {φ : α → Sort v} {a a' : α} {p₁ : φ a} {p₂ : φ a'} :
(e : a = a') → (h₂ : Eq.rec (motive := fun a _ ↦ φ a) p₁ e = p₂) → HEq p₁ p₂
| rfl, rfl => HEq.rfl
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem heq_of_eq_rec_right {φ : α → Sort v} {a a' : α} {p₁ : φ a} {p₂ : φ a'} :
(e : a' = a) → (h₂ : p₁ = Eq.rec (motive := fun a _ ↦ φ a) p₂ e) → HEq p₁ p₂
| rfl, rfl => HEq.rfl
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem of_heq_true {a : Prop} (h : HEq a True) : a := of_eq_true (eq_of_heq h)
+@[deprecated (since := "2024-09-03")]
theorem eq_rec_compose {α β φ : Sort u} :
∀ (p₁ : β = φ) (p₂ : α = β) (a : α),
(Eq.recOn p₁ (Eq.recOn p₂ a : β) : φ) = Eq.recOn (Eq.trans p₂ p₁) a
| rfl, rfl, _ => rfl
-theorem heq_prop {P Q : Prop} (p : P) (q : Q) : HEq p q :=
- Subsingleton.helim (propext <| iff_of_true p q) _ _
-
-/- and -/
-
-variable {a b c d : Prop}
+-- unused in Mathlib
+@[deprecated (since := "2024-09-11")] alias ⟨not_of_not_not_not, _⟩ := not_not_not
-/- xor -/
+variable {a : Prop} (p : Prop)
-def Xor' (a b : Prop) := (a ∧ ¬ b) ∨ (b ∧ ¬ a)
-
-/- iff -/
-
-attribute [refl] Iff.refl
-attribute [trans] Iff.trans
-attribute [symm] Iff.symm
-
-alias ⟨not_of_not_not_not, _⟩ := not_not_not
-
-variable (p)
-
--- FIXME: remove _iff and add _eq for the lean 4 core versions
+@[deprecated and_true (since := "2024-09-12")]
theorem and_true_iff : p ∧ True ↔ p := iff_of_eq (and_true _)
+@[deprecated true_and (since := "2024-09-12")]
theorem true_and_iff : True ∧ p ↔ p := iff_of_eq (true_and _)
+@[deprecated and_false (since := "2024-09-12")]
theorem and_false_iff : p ∧ False ↔ False := iff_of_eq (and_false _)
+@[deprecated false_and (since := "2024-09-12")]
theorem false_and_iff : False ∧ p ↔ False := iff_of_eq (false_and _)
-
-theorem true_or_iff : True ∨ p ↔ True := iff_of_eq (true_or _)
+@[deprecated or_true (since := "2024-09-12")]
theorem or_true_iff : p ∨ True ↔ True := iff_of_eq (or_true _)
-theorem false_or_iff : False ∨ p ↔ p := iff_of_eq (false_or _)
+@[deprecated true_or (since := "2024-09-12")]
+theorem true_or_iff : True ∨ p ↔ True := iff_of_eq (true_or _)
+@[deprecated or_false (since := "2024-09-12")]
theorem or_false_iff : p ∨ False ↔ p := iff_of_eq (or_false _)
-
-theorem not_or_of_not : ¬a → ¬b → ¬(a ∨ b) := fun h1 h2 ↦ not_or.2 ⟨h1, h2⟩
-
+@[deprecated false_or (since := "2024-09-12")]
+theorem false_or_iff : False ∨ p ↔ p := iff_of_eq (false_or _)
+@[deprecated iff_true (since := "2024-09-12")]
theorem iff_true_iff : (a ↔ True) ↔ a := iff_of_eq (iff_true _)
+@[deprecated true_iff (since := "2024-09-12")]
theorem true_iff_iff : (True ↔ a) ↔ a := iff_of_eq (true_iff _)
-
+@[deprecated iff_false (since := "2024-09-12")]
theorem iff_false_iff : (a ↔ False) ↔ ¬a := iff_of_eq (iff_false _)
-
+@[deprecated false_iff (since := "2024-09-12")]
theorem false_iff_iff : (False ↔ a) ↔ ¬a := iff_of_eq (false_iff _)
-
+@[deprecated iff_self (since := "2024-09-12")]
theorem iff_self_iff (a : Prop) : (a ↔ a) ↔ True := iff_of_eq (iff_self _)
-
-/- exists unique -/
-
-def ExistsUnique (p : α → Prop) := ∃ x, p x ∧ ∀ y, p y → y = x
-
-namespace Mathlib.Notation
-open Lean
-
-/--
-Checks to see that `xs` has only one binder.
--/
-def isExplicitBinderSingular (xs : TSyntax ``explicitBinders) : Bool :=
- match xs with
- | `(explicitBinders| $_:binderIdent $[: $_]?) => true
- | `(explicitBinders| ($_:binderIdent : $_)) => true
- | _ => false
-
-open TSyntax.Compat in
-/--
-`∃! x : α, p x` means that there exists a unique `x` in `α` such that `p x`.
-This is notation for `ExistsUnique (fun (x : α) ↦ p x)`.
-
-This notation does not allow multiple binders like `∃! (x : α) (y : β), p x y`
-as a shorthand for `∃! (x : α), ∃! (y : β), p x y` since it is liable to be misunderstood.
-Often, the intended meaning is instead `∃! q : α × β, p q.1 q.2`.
--/
-macro "∃!" xs:explicitBinders ", " b:term : term => do
- if !isExplicitBinderSingular xs then
- Macro.throwErrorAt xs "\
- The `ExistsUnique` notation should not be used with more than one binder.\n\
- \n\
- The reason for this is that `∃! (x : α), ∃! (y : β), p x y` has a completely different \
- meaning from `∃! q : α × β, p q.1 q.2`. \
- To prevent confusion, this notation requires that you be explicit \
- and use one with the correct interpretation."
- expandExplicitBinders ``ExistsUnique xs b
-
-/--
-Pretty-printing for `ExistsUnique`, following the same pattern as pretty printing for `Exists`.
-However, it does *not* merge binders.
--/
-@[app_unexpander ExistsUnique] def unexpandExistsUnique : Lean.PrettyPrinter.Unexpander
- | `($(_) fun $x:ident ↦ $b) => `(∃! $x:ident, $b)
- | `($(_) fun ($x:ident : $t) ↦ $b) => `(∃! $x:ident : $t, $b)
- | _ => throw ()
-
-/--
-`∃! x ∈ s, p x` means `∃! x, x ∈ s ∧ p x`, which is to say that there exists a unique `x ∈ s`
-such that `p x`.
-Similarly, notations such as `∃! x ≤ n, p n` are supported,
-using any relation defined using the `binder_predicate` command.
--/
-syntax "∃! " binderIdent binderPred ", " term : term
-
-macro_rules
- | `(∃! $x:ident $p:binderPred, $b) => `(∃! $x:ident, satisfies_binder_pred% $x $p ∧ $b)
- | `(∃! _ $p:binderPred, $b) => `(∃! x, satisfies_binder_pred% x $p ∧ $b)
-
-end Mathlib.Notation
-
--- @[intro] -- TODO
-theorem ExistsUnique.intro {p : α → Prop} (w : α)
- (h₁ : p w) (h₂ : ∀ y, p y → y = w) : ∃! x, p x := ⟨w, h₁, h₂⟩
-
-theorem ExistsUnique.elim {α : Sort u} {p : α → Prop} {b : Prop}
- (h₂ : ∃! x, p x) (h₁ : ∀ x, p x → (∀ y, p y → y = x) → b) : b :=
- Exists.elim h₂ (fun w hw ↦ h₁ w (And.left hw) (And.right hw))
-
-theorem exists_unique_of_exists_of_unique {α : Sort u} {p : α → Prop}
- (hex : ∃ x, p x) (hunique : ∀ y₁ y₂, p y₁ → p y₂ → y₁ = y₂) : ∃! x, p x :=
- Exists.elim hex (fun x px ↦ ExistsUnique.intro x px (fun y (h : p y) ↦ hunique y x h px))
-
-theorem ExistsUnique.exists {p : α → Prop} : (∃! x, p x) → ∃ x, p x | ⟨x, h, _⟩ => ⟨x, h⟩
-
-theorem ExistsUnique.unique {α : Sort u} {p : α → Prop}
- (h : ∃! x, p x) {y₁ y₂ : α} (py₁ : p y₁) (py₂ : p y₂) : y₁ = y₂ :=
- let ⟨_, _, hy⟩ := h; (hy _ py₁).trans (hy _ py₂).symm
-
-/- exists, forall, exists unique congruences -/
-
--- TODO
--- attribute [congr] forall_congr'
--- attribute [congr] exists_congr'
-
--- @[congr]
-theorem existsUnique_congr {p q : α → Prop} (h : ∀ a, p a ↔ q a) : (∃! a, p a) ↔ ∃! a, q a :=
- exists_congr fun _ ↦ and_congr (h _) <| forall_congr' fun _ ↦ imp_congr_left (h _)
+@[deprecated (since := "2024-09-12")] alias not_or_of_not := not_or_intro
/- decidable -/
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem decide_True' (h : Decidable True) : decide True = true := by simp
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem decide_False' (h : Decidable False) : decide False = false := by simp
namespace Decidable
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
def recOn_true [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u}
(h₃ : p) (h₄ : h₁ h₃) : Decidable.recOn h h₂ h₁ :=
cast (by match h with | .isTrue _ => rfl) h₄
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
def recOn_false [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u} (h₃ : ¬p) (h₄ : h₂ h₃) :
Decidable.recOn h h₂ h₁ :=
cast (by match h with | .isFalse _ => rfl) h₄
-alias by_cases := byCases
-alias by_contradiction := byContradiction
+@[deprecated (since := "2024-09-03")] alias by_cases := byCases
+@[deprecated (since := "2024-09-03")] alias by_contradiction := byContradiction
@[deprecated (since := "2024-07-27")] alias not_not_iff := not_not
end Decidable
-alias Or.decidable := instDecidableOr
-alias And.decidable := instDecidableAnd
-alias Not.decidable := instDecidableNot
-alias Iff.decidable := instDecidableIff
-alias decidableTrue := instDecidableTrue
-alias decidableFalse := instDecidableFalse
-
-instance {q : Prop} [Decidable p] [Decidable q] : Decidable (Xor' p q) :=
- inferInstanceAs (Decidable (Or ..))
+@[deprecated (since := "2024-09-03")] alias Or.decidable := instDecidableOr
+@[deprecated (since := "2024-09-03")] alias And.decidable := instDecidableAnd
+@[deprecated (since := "2024-09-03")] alias Not.decidable := instDecidableNot
+@[deprecated (since := "2024-09-03")] alias Iff.decidable := instDecidableIff
+@[deprecated (since := "2024-09-03")] alias decidableTrue := instDecidableTrue
+@[deprecated (since := "2024-09-03")] alias decidableFalse := instDecidableFalse
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
def IsDecEq {α : Sort u} (p : α → α → Bool) : Prop := ∀ ⦃x y : α⦄, p x y = true → x = y
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
def IsDecRefl {α : Sort u} (p : α → α → Bool) : Prop := ∀ x, p x x = true
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
def decidableEq_of_bool_pred {α : Sort u} {p : α → α → Bool} (h₁ : IsDecEq p)
(h₂ : IsDecRefl p) : DecidableEq α
| x, y =>
if hp : p x y = true then isTrue (h₁ hp)
else isFalse (fun hxy : x = y ↦ absurd (h₂ y) (by rwa [hxy] at hp))
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem decidableEq_inl_refl {α : Sort u} [h : DecidableEq α] (a : α) :
h a a = isTrue (Eq.refl a) :=
match h a a with
| isTrue _ => rfl
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem decidableEq_inr_neg {α : Sort u} [h : DecidableEq α] {a b : α}
(n : a ≠ b) : h a b = isFalse n :=
match h a b with
@@ -241,6 +171,7 @@ theorem decidableEq_inr_neg {α : Sort u} [h : DecidableEq α] {a b : α}
/- subsingleton -/
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem rec_subsingleton {p : Prop} [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u}
[h₃ : ∀ h : p, Subsingleton (h₁ h)] [h₄ : ∀ h : ¬p, Subsingleton (h₂ h)] :
Subsingleton (Decidable.recOn h h₂ h₁) :=
@@ -248,24 +179,27 @@ theorem rec_subsingleton {p : Prop} [h : Decidable p] {h₁ : p → Sort u} {h
| isTrue h => h₃ h
| isFalse h => h₄ h
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem imp_of_if_pos {c t e : Prop} [Decidable c] (h : ite c t e) (hc : c) : t :=
(if_pos hc ▸ h :)
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem imp_of_if_neg {c t e : Prop} [Decidable c] (h : ite c t e) (hnc : ¬c) : e :=
(if_neg hnc ▸ h :)
-theorem if_ctx_congr {α : Sort u} {b c : Prop} [dec_b : Decidable b] [dec_c : Decidable c]
- {x y u v : α} (h_c : b ↔ c) (h_t : c → x = u) (h_e : ¬c → y = v) : ite b x y = ite c u v :=
+@[deprecated (since := "2024-09-11")]
+theorem dif_ctx_congr {α : Sort u} {b c : Prop} [dec_b : Decidable b] [dec_c : Decidable c]
+ {x : b → α} {u : c → α} {y : ¬b → α} {v : ¬c → α}
+ (h_c : b ↔ c) (h_t : ∀ h : c, x (Iff.mpr h_c h) = u h)
+ (h_e : ∀ h : ¬c, y (Iff.mpr (not_congr h_c) h) = v h) :
+ @dite α b dec_b x y = @dite α c dec_c u v :=
match dec_b, dec_c with
- | isFalse _, isFalse h₂ => h_e h₂
- | isTrue _, isTrue h₂ => h_t h₂
- | isFalse h₁, isTrue h₂ => absurd h₂ (Iff.mp (not_congr h_c) h₁)
- | isTrue h₁, isFalse h₂ => absurd h₁ (Iff.mpr (not_congr h_c) h₂)
-
-theorem if_congr {α : Sort u} {b c : Prop} [Decidable b] [Decidable c]
- {x y u v : α} (h_c : b ↔ c) (h_t : x = u) (h_e : y = v) : ite b x y = ite c u v :=
- if_ctx_congr h_c (fun _ ↦ h_t) (fun _ ↦ h_e)
+ | isFalse _, isFalse h₂ => h_e h₂
+ | isTrue _, isTrue h₂ => h_t h₂
+ | isFalse h₁, isTrue h₂ => absurd h₂ (Iff.mp (not_congr h_c) h₁)
+ | isTrue h₁, isFalse h₂ => absurd h₁ (Iff.mpr (not_congr h_c) h₂)
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem if_ctx_congr_prop {b c x y u v : Prop} [dec_b : Decidable b] [dec_c : Decidable c]
(h_c : b ↔ c) (h_t : c → (x ↔ u)) (h_e : ¬c → (y ↔ v)) : ite b x y ↔ ite c u v :=
match dec_b, dec_c with
@@ -275,10 +209,12 @@ theorem if_ctx_congr_prop {b c x y u v : Prop} [dec_b : Decidable b] [dec_c : De
| isTrue h₁, isFalse h₂ => absurd h₁ (Iff.mpr (not_congr h_c) h₂)
-- @[congr]
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem if_congr_prop {b c x y u v : Prop} [Decidable b] [Decidable c] (h_c : b ↔ c) (h_t : x ↔ u)
(h_e : y ↔ v) : ite b x y ↔ ite c u v :=
if_ctx_congr_prop h_c (fun _ ↦ h_t) (fun _ ↦ h_e)
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem if_ctx_simp_congr_prop {b c x y u v : Prop} [Decidable b] (h_c : b ↔ c) (h_t : c → (x ↔ u))
-- FIXME: after https://github.com/leanprover/lean4/issues/1867 is fixed,
-- this should be changed back to:
@@ -286,6 +222,7 @@ theorem if_ctx_simp_congr_prop {b c x y u v : Prop} [Decidable b] (h_c : b ↔ c
(h_e : ¬c → (y ↔ v)) : ite b x y ↔ @ite _ c (decidable_of_decidable_of_iff h_c) u v :=
if_ctx_congr_prop (dec_c := decidable_of_decidable_of_iff h_c) h_c h_t h_e
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem if_simp_congr_prop {b c x y u v : Prop} [Decidable b] (h_c : b ↔ c) (h_t : x ↔ u)
-- FIXME: after https://github.com/leanprover/lean4/issues/1867 is fixed,
-- this should be changed back to:
@@ -293,18 +230,7 @@ theorem if_simp_congr_prop {b c x y u v : Prop} [Decidable b] (h_c : b ↔ c) (h
(h_e : y ↔ v) : ite b x y ↔ (@ite _ c (decidable_of_decidable_of_iff h_c) u v) :=
if_ctx_simp_congr_prop h_c (fun _ ↦ h_t) (fun _ ↦ h_e)
--- @[congr]
-theorem dif_ctx_congr {α : Sort u} {b c : Prop} [dec_b : Decidable b] [dec_c : Decidable c]
- {x : b → α} {u : c → α} {y : ¬b → α} {v : ¬c → α}
- (h_c : b ↔ c) (h_t : ∀ h : c, x (Iff.mpr h_c h) = u h)
- (h_e : ∀ h : ¬c, y (Iff.mpr (not_congr h_c) h) = v h) :
- @dite α b dec_b x y = @dite α c dec_c u v :=
- match dec_b, dec_c with
- | isFalse _, isFalse h₂ => h_e h₂
- | isTrue _, isTrue h₂ => h_t h₂
- | isFalse h₁, isTrue h₂ => absurd h₂ (Iff.mp (not_congr h_c) h₁)
- | isTrue h₁, isFalse h₂ => absurd h₁ (Iff.mpr (not_congr h_c) h₂)
-
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem dif_ctx_simp_congr {α : Sort u} {b c : Prop} [Decidable b]
{x : b → α} {u : c → α} {y : ¬b → α} {v : ¬c → α}
(h_c : b ↔ c) (h_t : ∀ h : c, x (Iff.mpr h_c h) = u h)
@@ -315,111 +241,31 @@ theorem dif_ctx_simp_congr {α : Sort u} {b c : Prop} [Decidable b]
dite b x y = @dite _ c (decidable_of_decidable_of_iff h_c) u v :=
dif_ctx_congr (dec_c := decidable_of_decidable_of_iff h_c) h_c h_t h_e
+@[deprecated (since := "2024-09-03")]
def AsTrue (c : Prop) [Decidable c] : Prop := if c then True else False
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
def AsFalse (c : Prop) [Decidable c] : Prop := if c then False else True
+@[deprecated (since := "2024-09-03")]
theorem AsTrue.get {c : Prop} [h₁ : Decidable c] (_ : AsTrue c) : c :=
match h₁ with
| isTrue h_c => h_c
/- Equalities for rewriting let-expressions -/
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem let_value_eq {α : Sort u} {β : Sort v} {a₁ a₂ : α} (b : α → β)
(h : a₁ = a₂) : (let x : α := a₁; b x) = (let x : α := a₂; b x) := congrArg b h
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem let_value_heq {α : Sort v} {β : α → Sort u} {a₁ a₂ : α} (b : ∀ x : α, β x)
(h : a₁ = a₂) : HEq (let x : α := a₁; b x) (let x : α := a₂; b x) := by cases h; rfl
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem let_body_eq {α : Sort v} {β : α → Sort u} (a : α) {b₁ b₂ : ∀ x : α, β x}
(h : ∀ x, b₁ x = b₂ x) : (let x : α := a; b₁ x) = (let x : α := a; b₂ x) := by exact h _ ▸ rfl
+@[deprecated (since := "2024-09-03")] -- unused in Mathlib
theorem let_eq {α : Sort v} {β : Sort u} {a₁ a₂ : α} {b₁ b₂ : α → β}
(h₁ : a₁ = a₂) (h₂ : ∀ x, b₁ x = b₂ x) :
(let x : α := a₁; b₁ x) = (let x : α := a₂; b₂ x) := by simp [h₁, h₂]
-
-section Relation
-
-variable {α : Sort u} {β : Sort v} (r : β → β → Prop)
-
-/-- Local notation for an arbitrary binary relation `r`. -/
-local infix:50 " ≺ " => r
-
-/-- A reflexive relation relates every element to itself. -/
-def Reflexive := ∀ x, x ≺ x
-
-/-- A relation is symmetric if `x ≺ y` implies `y ≺ x`. -/
-def Symmetric := ∀ ⦃x y⦄, x ≺ y → y ≺ x
-
-/-- A relation is transitive if `x ≺ y` and `y ≺ z` together imply `x ≺ z`. -/
-def Transitive := ∀ ⦃x y z⦄, x ≺ y → y ≺ z → x ≺ z
-
-lemma Equivalence.reflexive {r : β → β → Prop} (h : Equivalence r) : Reflexive r := h.refl
-
-lemma Equivalence.symmetric {r : β → β → Prop} (h : Equivalence r) : Symmetric r := fun _ _ ↦ h.symm
-
-lemma Equivalence.transitive {r : β → β → Prop} (h : Equivalence r) : Transitive r :=
- fun _ _ _ ↦ h.trans
-
-/-- A relation is total if for all `x` and `y`, either `x ≺ y` or `y ≺ x`. -/
-def Total := ∀ x y, x ≺ y ∨ y ≺ x
-
-/-- Irreflexive means "not reflexive". -/
-def Irreflexive := ∀ x, ¬ x ≺ x
-
-/-- A relation is antisymmetric if `x ≺ y` and `y ≺ x` together imply that `x = y`. -/
-def AntiSymmetric := ∀ ⦃x y⦄, x ≺ y → y ≺ x → x = y
-
-/-- An empty relation does not relate any elements. -/
-@[nolint unusedArguments]
-def EmptyRelation := fun _ _ : α ↦ False
-
-theorem InvImage.trans (f : α → β) (h : Transitive r) : Transitive (InvImage r f) :=
- fun (a₁ a₂ a₃ : α) (h₁ : InvImage r f a₁ a₂) (h₂ : InvImage r f a₂ a₃) ↦ h h₁ h₂
-
-theorem InvImage.irreflexive (f : α → β) (h : Irreflexive r) : Irreflexive (InvImage r f) :=
- fun (a : α) (h₁ : InvImage r f a a) ↦ h (f a) h₁
-
-end Relation
-
-section Binary
-
-variable {α : Type u} {β : Type v} (f : α → α → α) (inv : α → α) (one : α)
-
-/-- Local notation for `f`, high priority to avoid ambiguity with `HMul.hMul`. -/
-local infix:70 (priority := high) " * " => f
-
-/-- Local notation for `inv`, high priority to avoid ambiguity with `Inv.inv`. -/
-local postfix:100 (priority := high) "⁻¹" => inv
-
-variable (g : α → α → α)
-
-/-- Local notation for `g`, high priority to avoid ambiguity with `HAdd.hAdd`. -/
-local infix:65 (priority := high) " + " => g
-
-def Commutative := ∀ a b, a * b = b * a
-def Associative := ∀ a b c, (a * b) * c = a * (b * c)
-def LeftIdentity := ∀ a, one * a = a
-def RightIdentity := ∀ a, a * one = a
-def RightInverse := ∀ a, a * a⁻¹ = one
-def LeftCancelative := ∀ a b c, a * b = a * c → b = c
-def RightCancelative := ∀ a b c, a * b = c * b → a = c
-def LeftDistributive := ∀ a b c, a * (b + c) = a * b + a * c
-def RightDistributive := ∀ a b c, (a + b) * c = a * c + b * c
-def RightCommutative (h : β → α → β) := ∀ b a₁ a₂, h (h b a₁) a₂ = h (h b a₂) a₁
-def LeftCommutative (h : α → β → β) := ∀ a₁ a₂ b, h a₁ (h a₂ b) = h a₂ (h a₁ b)
-
-theorem left_comm : Commutative f → Associative f → LeftCommutative f :=
- fun hcomm hassoc a b c ↦
- calc a*(b*c)
- _ = (a*b)*c := Eq.symm (hassoc a b c)
- _ = (b*a)*c := hcomm a b ▸ rfl
- _ = b*(a*c) := hassoc b a c
-
-theorem right_comm : Commutative f → Associative f → RightCommutative f :=
- fun hcomm hassoc a b c ↦
- calc (a*b)*c
- _ = a*(b*c) := hassoc a b c
- _ = a*(c*b) := hcomm b c ▸ rfl
- _ = (a*c)*b := Eq.symm (hassoc a c b)
-
-end Binary
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 cf7b641cb3195..5c168b0eb1a99 100644
--- a/Mathlib/Deprecated/Subgroup.lean
+++ b/Mathlib/Deprecated/Subgroup.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johannes Hölzl, Mitchell Rowett, Scott Morrison, Johan Commelin, Mario Carneiro,
+Authors: Johannes Hölzl, Mitchell Rowett, Kim Morrison, Johan Commelin, Mario Carneiro,
Michael Howes
-/
import Mathlib.Algebra.Group.Subgroup.Basic
@@ -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
@@ -453,10 +453,11 @@ theorem closure_subgroup {s : Set G} (hs : IsSubgroup s) : closure s = s :=
@[to_additive]
theorem exists_list_of_mem_closure {s : Set G} {a : G} (h : a ∈ closure s) :
∃ l : List G, (∀ x ∈ l, x ∈ s ∨ x⁻¹ ∈ s) ∧ l.prod = a :=
- InClosure.recOn h (fun {x} hxs => ⟨[x], List.forall_mem_singleton.2 <| Or.inl hxs, one_mul _⟩)
+ 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 7c267c4d4f513..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,
@@ -97,7 +95,8 @@ theorem exists_list_of_mem_closure {a : R} (h : a ∈ closure s) :
∃ L : List (List R), (∀ l ∈ L, ∀ x ∈ l, x ∈ s ∨ x = (-1 : R)) ∧ (L.map List.prod).sum = a :=
AddGroup.InClosure.recOn h
fun {x} hx ↦ match x, Monoid.exists_list_of_mem_closure hx with
- | _, ⟨L, h1, rfl⟩ => ⟨[L], List.forall_mem_singleton.2 fun r hr ↦ Or.inl (h1 r hr), zero_add _⟩
+ | _, ⟨L, h1, rfl⟩ =>
+ ⟨[L], List.forall_mem_singleton.2 fun r hr ↦ Or.inl (h1 r hr), List.sum_singleton⟩
⟨[], List.forall_mem_nil _, rfl⟩
fun {b} _ ih ↦ match b, ih with
| _, ⟨L1, h1, rfl⟩ =>
diff --git a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean
index a47e9d3145ffb..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 :=
@@ -852,8 +852,8 @@ theorem semiconj_of_group_action_of_forall_translationNumber_eq {G : Type*} [Gro
have hF₁ : ∀ g, ⇑(F₁ g) = f₁ g := fun _ => rfl
have hF₂ : ∀ g, ⇑(F₂ g) = f₂ g := fun _ => rfl
-- Now we apply `csSup_div_semiconj` and go back to `f₁` and `f₂`.
- refine ⟨⟨⟨_, fun x y hxy => ?_⟩, fun x => ?_⟩, csSup_div_semiconj F₂ F₁ fun x => ?_⟩ <;>
- simp only [hF₁, hF₂, ← map_inv, coe_mk]
+ refine ⟨⟨⟨fun x ↦ ⨆ g', (F₂ g')⁻¹ (F₁ g' x), fun x y hxy => ?_⟩, fun x => ?_⟩,
+ csSup_div_semiconj F₂ F₁ fun x => ?_⟩ <;> simp only [hF₁, hF₂, ← map_inv, coe_mk]
· exact ciSup_mono (this y) fun g => mono _ (mono _ hxy)
· simp only [map_add_one]
exact (Monotone.map_ciSup_of_continuousAt (continuousAt_id.add continuousAt_const)
diff --git a/Mathlib/Dynamics/Ergodic/Action/OfMinimal.lean b/Mathlib/Dynamics/Ergodic/Action/OfMinimal.lean
new file mode 100644
index 0000000000000..266a45e4f70f7
--- /dev/null
+++ b/Mathlib/Dynamics/Ergodic/Action/OfMinimal.lean
@@ -0,0 +1,241 @@
+/-
+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.Dynamics.Ergodic.Action.Regular
+import Mathlib.MeasureTheory.Measure.ContinuousPreimage
+import Mathlib.MeasureTheory.Measure.Haar.Unique
+
+/-!
+# Ergodicity from minimality
+
+In this file we prove that the left shift `(a * ·)` on a compact topological group `G`
+is ergodic with respect to the Haar measure if and only if its minimal,
+i.e., the powers `a ^ n` are dense in `G`.
+
+The proof of the more difficult "if minimal, then ergodic" implication
+is based on the ergodicity of the left action of a group on itself
+and the following fact that we prove in `ergodic_smul_of_denseRange_pow` below:
+
+If a monoid `M` continuously acts on an R₁ topological space `X`,
+`g` is an element of `M such that its natural powers are dense in `M`,
+and `μ` is a finite inner regular measure on `X` which is ergodic with respect to the action of `M`,
+then the scalar multiplication by `g` is an ergodic map.
+
+We also prove that a continuous monoid homomorphism `f : G →* G` is ergodic,
+if it is surjective and the preimages of `1` under iterations of `f` are dense in the group.
+This theorem applies, e.g., to the map `z ↦ n • z` on the additive circle or a torus.
+-/
+
+open MeasureTheory Filter Set Function
+open scoped Pointwise Topology
+
+section SMul
+
+variable {M : Type*} [TopologicalSpace M]
+ {X : Type*} [TopologicalSpace X] [R1Space X] [MeasurableSpace X] [BorelSpace X]
+ [SMul M X] [ContinuousSMul M X]
+ {μ : Measure X} [IsFiniteMeasure μ] [μ.InnerRegular] [ErgodicSMul M X μ] {s : Set X}
+
+/-- Let `M` act continuously on an R₁ topological space `X`.
+Let `μ` be a finite inner regular measure on `X` which is ergodic with respect to this action.
+If a null measurable set `s` is a.e. equal
+to its preimages under the action of a dense set of elements of `M`,
+then it is either null or conull. -/
+@[to_additive "Let `M` act continuously on an R₁ topological space `X`.
+Let `μ` be a finite inner regular measure on `X` which is ergodic with respect to this action.
+If a null measurable set `s` is a.e. equal
+to its preimages under the action of a dense set of elements of `M`,
+then it is either null or conull."]
+theorem aeconst_of_dense_setOf_preimage_smul_ae (hsm : NullMeasurableSet s μ)
+ (hd : Dense {g : M | (g • ·) ⁻¹' s =ᵐ[μ] s}) : EventuallyConst s (ae μ) := by
+ borelize M
+ refine aeconst_of_forall_preimage_smul_ae_eq M hsm ?_
+ rwa [dense_iff_closure_eq, IsClosed.closure_eq, eq_univ_iff_forall] at hd
+ let f : C(M × X, X) := ⟨(· • ·).uncurry, continuous_smul⟩
+ exact isClosed_setOf_preimage_ae_eq f.curry.continuous (measurePreserving_smul · μ) _ hsm
+ (measure_ne_top _ _)
+
+@[to_additive]
+theorem aeconst_of_dense_setOf_preimage_smul_eq (hsm : NullMeasurableSet s μ)
+ (hd : Dense {g : M | (g • ·) ⁻¹' s = s}) : EventuallyConst s (ae μ) :=
+ aeconst_of_dense_setOf_preimage_smul_ae hsm <| hd.mono fun _ h ↦ mem_setOf.2 <| .of_eq h
+
+/-- If a monoid `M` continuously acts on an R₁ topological space `X`,
+`g` is an element of `M such that its natural powers are dense in `M`,
+and `μ` is a finite inner regular measure on `X` which is ergodic with respect to the action of `M`,
+then the scalar multiplication by `g` is an ergodic map. -/
+@[to_additive "If an additive monoid `M` continuously acts on an R₁ topological space `X`,
+`g` is an element of `M such that its natural multiples are dense in `M`,
+and `μ` is a finite inner regular measure on `X` which is ergodic with respect to the action of `M`,
+then the vector addition of `g` is an ergodic map."]
+theorem ergodic_smul_of_denseRange_pow {M : Type*} [Monoid M] [TopologicalSpace M]
+ [MulAction M X] [ContinuousSMul M X] {g : M} (hg : DenseRange (g ^ · : ℕ → M))
+ (μ : Measure X) [IsFiniteMeasure μ] [μ.InnerRegular] [ErgodicSMul M X μ] :
+ Ergodic (g • ·) μ := by
+ borelize M
+ refine ⟨measurePreserving_smul _ _, ⟨fun s hsm hs ↦ ?_⟩⟩
+ refine aeconst_of_dense_setOf_preimage_smul_eq hsm.nullMeasurableSet (hg.mono ?_)
+ refine range_subset_iff.2 fun n ↦ ?_
+ rw [mem_setOf, ← smul_iterate, preimage_iterate_eq, iterate_fixed hs]
+
+end SMul
+
+section IsScalarTower
+
+variable {M X : Type*} [Monoid M] [SMul M X]
+ [TopologicalSpace X] [R1Space X] [MeasurableSpace X] [BorelSpace X]
+ (μ : Measure X) [IsFiniteMeasure μ] [μ.InnerRegular]
+
+/-- If `N` acts continuously and ergodically on `X` and `M` acts minimally on `N`,
+then the corresponding action of `M` on `X` is ergodic. -/
+@[to_additive
+ "If `N` acts additively continuously and ergodically on `X` and `M` acts minimally on `N`,
+then the corresponding action of `M` on `X` is ergodic."]
+theorem ErgodicSMul.trans_isMinimal (N : Type*) [MulAction M N]
+ [Monoid N] [TopologicalSpace N] [MulAction.IsMinimal M N]
+ [MulAction N X] [IsScalarTower M N X] [ContinuousSMul N X] [ErgodicSMul N X μ] :
+ ErgodicSMul M X μ where
+ measure_preimage_smul c s hsm := by
+ simpa only [smul_one_smul] using SMulInvariantMeasure.measure_preimage_smul (c • 1 : N) hsm
+ aeconst_of_forall_preimage_smul_ae_eq {s} hsm hs := by
+ refine aeconst_of_dense_setOf_preimage_smul_ae (M := N) hsm.nullMeasurableSet ?_
+ refine (MulAction.dense_orbit M 1).mono ?_
+ rintro _ ⟨g, rfl⟩
+ simpa using hs g
+
+end IsScalarTower
+
+section MulActionGroup
+
+variable {G : Type*} [Group G] [TopologicalSpace G] [ContinuousInv G]
+ {X : Type*} [TopologicalSpace X] [R1Space X] [MeasurableSpace X] [BorelSpace X]
+ [MulAction G X] [ContinuousSMul G X]
+ {μ : Measure X} [IsFiniteMeasure μ] [μ.InnerRegular] [ErgodicSMul G X μ] {s : Set X}
+
+@[to_additive]
+theorem aeconst_of_dense_aestabilizer_smul (hsm : NullMeasurableSet s μ)
+ (hd : Dense (MulAction.aestabilizer G μ s : Set G)) : EventuallyConst s (ae μ) :=
+ aeconst_of_dense_setOf_preimage_smul_ae hsm <| (hd.preimage (isOpenMap_inv _)).mono fun g hg ↦ by
+ simpa only [preimage_smul] using hg
+
+/-- If a monoid `M` continuously acts on an R₁ topological space `X`,
+`g` is an element of `M such that its integer powers are dense in `M`,
+and `μ` is a finite inner regular measure on `X` which is ergodic with respect to the action of `M`,
+then the scalar multiplication by `g` is an ergodic map. -/
+@[to_additive "If an additive monoid `M` continuously acts on an R₁ topological space `X`,
+`g` is an element of `M such that its integer multiples are dense in `M`,
+and `μ` is a finite inner regular measure on `X` which is ergodic with respect to the action of `M`,
+then the vector addition of `g` is an ergodic map."]
+theorem ergodic_smul_of_denseRange_zpow {g : G} (hg : DenseRange (g ^ · : ℤ → G))
+ (μ : Measure X) [IsFiniteMeasure μ] [μ.InnerRegular] [ErgodicSMul G X μ] :
+ Ergodic (g • ·) μ := by
+ borelize G
+ refine ⟨measurePreserving_smul _ _, ⟨fun s hsm hs ↦ ?_⟩⟩
+ refine aeconst_of_dense_aestabilizer_smul hsm.nullMeasurableSet (hg.mono ?_)
+ rw [← Subgroup.coe_zpowers, SetLike.coe_subset_coe, ← Subgroup.zpowers_inv, Subgroup.zpowers_le,
+ MulAction.mem_aestabilizer, ← preimage_smul, hs]
+
+ end MulActionGroup
+
+section TopologicalGroup
+
+variable {G : Type*} [Group G] [TopologicalSpace G] [TopologicalGroup G] [MeasurableSpace G]
+
+/-- If the left multiplication by `g` is ergodic
+with respect to a measure which is positive on nonempty open sets,
+then the integer powers of `g` are dense in `G`. -/
+@[to_additive "If the left addition of `g` is ergodic
+with respect to a measure which is positive on nonempty open sets,
+then the integer multiples of `g` are dense in `G`."]
+theorem DenseRange.zpow_of_ergodic_mul_left [OpensMeasurableSpace G]
+ {μ : Measure G} [μ.IsOpenPosMeasure] {g : G} (hg : Ergodic (g * ·) μ) :
+ DenseRange (g ^ · : ℤ → G) := by
+ intro a
+ by_contra h
+ obtain ⟨V, hV₁, hVo, hV⟩ :
+ ∃ V : Set G, 1 ∈ V ∧ IsOpen V ∧ ∀ x ∈ V, ∀ y ∈ V, ∀ m : ℤ, g ^ m ≠ a * x / y := by
+ rw [← mem_compl_iff, ← interior_compl, mem_interior_iff_mem_nhds] at h
+ have : Tendsto (fun (x, y) ↦ a * x / y) (𝓝 1) (𝓝 a) :=
+ Continuous.tendsto' (by fun_prop) _ _ (by simp)
+ rw [nhds_prod_eq] at this
+ simpa [(nhds_basis_opens (1 : G)).prod_self.mem_iff, prod_subset_iff, and_assoc] using this h
+ set s := ⋃ m : ℤ, g ^ m • V
+ have hso : IsOpen s := isOpen_iUnion fun m ↦ hVo.smul _
+ have hsne : s.Nonempty := ⟨1, mem_iUnion.2 ⟨0, by simpa⟩⟩
+ have hd : Disjoint s (a • V) := by
+ simp_rw [s, disjoint_iUnion_left, disjoint_left]
+ rintro m _ ⟨x, hx, rfl⟩ ⟨y, hy, hxy⟩
+ apply hV y hy x hx m
+ simp_all
+ have hgs : (g * ·) ⁻¹' s = s := by
+ simp only [s, preimage_iUnion, ← smul_eq_mul, preimage_smul]
+ refine iUnion_congr_of_surjective _ (add_left_surjective (-1)) fun m ↦ ?_
+ simp [zpow_add, mul_smul]
+ cases hg.measure_self_or_compl_eq_zero hso.measurableSet hgs with
+ | inl h => exact hso.measure_ne_zero _ hsne h
+ | inr h =>
+ refine (hVo.smul a).measure_ne_zero μ (.image _ ⟨1, hV₁⟩) (measure_mono_null ?_ h)
+ rwa [disjoint_right] at hd
+
+variable [SecondCountableTopology G] [BorelSpace G] {g : G}
+
+@[to_additive]
+theorem ergodic_mul_left_of_denseRange_pow (hg : DenseRange (g ^ · : ℕ → G))
+ (μ : Measure G) [IsFiniteMeasure μ] [μ.InnerRegular] [μ.IsMulLeftInvariant] :
+ Ergodic (g * ·) μ :=
+ ergodic_smul_of_denseRange_pow hg μ
+
+@[to_additive]
+theorem ergodic_mul_left_of_denseRange_zpow (hg : DenseRange (g ^ · : ℤ → G))
+ (μ : Measure G) [IsFiniteMeasure μ] [μ.InnerRegular] [μ.IsMulLeftInvariant] :
+ Ergodic (g * ·) μ :=
+ ergodic_smul_of_denseRange_zpow hg μ
+
+@[to_additive]
+theorem ergodic_mul_left_iff_denseRange_zpow (μ : Measure G) [IsFiniteMeasure μ]
+ [μ.InnerRegular] [μ.IsMulLeftInvariant] [NeZero μ] :
+ Ergodic (g * ·) μ ↔ DenseRange (g ^ · : ℤ → G) :=
+ ⟨.zpow_of_ergodic_mul_left, (ergodic_mul_left_of_denseRange_zpow · μ)⟩
+
+end TopologicalGroup
+
+namespace MonoidHom
+
+variable {G : Type*} [Group G] [TopologicalSpace G]
+ [TopologicalGroup G] [SecondCountableTopology G] [MeasurableSpace G] [BorelSpace G]
+
+/-- Let `f : G →* G` be a group endomorphism of a topological group with second countable topology.
+If the preimages of `1` under the iterations of `f` are dense,
+then it is preergodic with respect to any finite inner regular left invariant measure. -/
+@[to_additive "Let `f : G →+ G` be an additive group endomorphism
+of a topological additive group with second countable topology.
+If the preimages of `0` under the iterations of `f` are dense,
+then it is preergodic with respect to any finite inner regular left invariant measure."]
+theorem preErgodic_of_dense_iUnion_preimage_one
+ {μ : Measure G} [IsFiniteMeasure μ] [μ.InnerRegular] [μ.IsMulLeftInvariant]
+ (f : G →* G) (hf : Dense (⋃ n, f^[n] ⁻¹' 1)) : PreErgodic f μ := by
+ refine ⟨fun s hsm hs ↦ aeconst_of_dense_setOf_preimage_smul_eq (M := G) hsm.nullMeasurableSet ?_⟩
+ refine hf.mono <| iUnion_subset fun n x hx ↦ ?_
+ have hsn : f^[n] ⁻¹' s = s := by
+ rw [preimage_iterate_eq, iterate_fixed hs]
+ rw [mem_preimage, Set.mem_one] at hx
+ rw [mem_setOf, ← hsn]
+ ext y
+ simp [hx]
+
+/-- Let `f : G →* G` be a continuous surjective group endomorphism
+of a compact topological group with second countable topology.
+If the preimages of `1` under the iterations of `f` are dense,
+then `f` is ergodic with respect to any finite inner regular left invariant measure. -/
+@[to_additive "Let `f : G →+ G` be a continuous surjective additive group endomorphism
+of a compact topological additive group with second countable topology.
+If the preimages of `0` under the iterations of `f` are dense,
+then `f` is ergodic with respect to any finite inner regular left invariant measure."]
+theorem ergodic_of_dense_iUnion_preimage_one [CompactSpace G] {μ : Measure G} [μ.IsHaarMeasure]
+ (f : G →* G) (hf : Dense (⋃ n, f^[n] ⁻¹' 1)) (hcont : Continuous f) (hsurj : Surjective f) :
+ Ergodic f μ :=
+ ⟨f.measurePreserving hcont hsurj rfl, f.preErgodic_of_dense_iUnion_preimage_one hf⟩
+
+end MonoidHom
diff --git a/Mathlib/Dynamics/Ergodic/Conservative.lean b/Mathlib/Dynamics/Ergodic/Conservative.lean
index 7e924b8864da3..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
@@ -67,6 +67,17 @@ protected theorem id (μ : Measure α) : Conservative id μ :=
exists_mem_iterate_mem' := fun _ _ h0 => by
simpa [exists_ne] using nonempty_of_measure_ne_zero h0 }
+theorem of_absolutelyContinuous {ν : Measure α} (h : Conservative f μ) (hν : ν ≪ μ)
+ (h' : QuasiMeasurePreserving f ν ν) : Conservative f ν :=
+ ⟨h', fun _ hsm h0 ↦ h.exists_mem_iterate_mem' hsm (mt (@hν _) h0)⟩
+
+/-- Restriction of a conservative system to an invariant set is a conservative system,
+formulated in terms of the restriction of the measure. -/
+theorem measureRestrict (h : Conservative f μ) (hs : MapsTo f s s) :
+ Conservative f (μ.restrict s) :=
+ .of_absolutelyContinuous h (absolutelyContinuous_of_le restrict_le_self) <|
+ h.toQuasiMeasurePreserving.restrict hs
+
/-- If `f` is a conservative self-map and `s` is a null measurable set of nonzero measure,
then there exists a point `x ∈ s` that returns to `s` under a non-zero iteration of `f`. -/
theorem exists_mem_iterate_mem (hf : Conservative f μ)
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/Ergodic/MeasurePreserving.lean b/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean
index f3cf7b84dd1bf..aeb910c97b9ae 100644
--- a/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean
+++ b/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean
@@ -102,13 +102,13 @@ protected theorem comp_left_iff {g : α → β} {e : β ≃ᵐ γ} (h : MeasureP
MeasurePreserving (e ∘ g) μa μc ↔ MeasurePreserving g μa μb := by
refine ⟨fun hg => ?_, fun hg => h.comp hg⟩
convert (MeasurePreserving.symm e h).comp hg
- simp [← Function.comp.assoc e.symm e g]
+ simp [← Function.comp_assoc e.symm e g]
protected theorem comp_right_iff {g : α → β} {e : γ ≃ᵐ α} (h : MeasurePreserving e μc μa) :
MeasurePreserving (g ∘ e) μc μb ↔ MeasurePreserving g μa μb := by
refine ⟨fun hg => ?_, fun hg => hg.comp h⟩
convert hg.comp (MeasurePreserving.symm e h)
- simp [Function.comp.assoc g e e.symm]
+ simp [Function.comp_assoc g e e.symm]
protected theorem sigmaFinite {f : α → β} (hf : MeasurePreserving f μa μb) [SigmaFinite μb] :
SigmaFinite μa :=
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 3f47192c4cc47..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]⟩⟩
@@ -338,7 +339,7 @@ theorem not_isPeriodicPt_of_pos_of_lt_minimalPeriod :
theorem IsPeriodicPt.minimalPeriod_dvd (hx : IsPeriodicPt f n x) : minimalPeriod f x ∣ n :=
(eq_or_lt_of_le <| n.zero_le).elim (fun hn0 => hn0 ▸ dvd_zero _) fun hn0 =>
-- Porting note: `Nat.dvd_iff_mod_eq_zero` gained explicit arguments
- (Nat.dvd_iff_mod_eq_zero _ _).2 <|
+ Nat.dvd_iff_mod_eq_zero.2 <|
(hx.mod <| isPeriodicPt_minimalPeriod f x).eq_zero_of_lt_minimalPeriod <|
Nat.mod_lt _ <| hx.minimalPeriod_pos hn0
@@ -433,7 +434,7 @@ theorem periodicOrbit_length : (periodicOrbit f x).length = minimalPeriod f x :=
@[simp]
theorem periodicOrbit_eq_nil_iff_not_periodic_pt :
periodicOrbit f x = Cycle.nil ↔ x ∉ periodicPts f := by
- simp only [periodicOrbit.eq_1, Cycle.coe_eq_nil, List.map_eq_nil, List.range_eq_nil]
+ simp only [periodicOrbit.eq_1, Cycle.coe_eq_nil, List.map_eq_nil_iff, List.range_eq_nil]
exact minimalPeriod_eq_zero_iff_nmem_periodicPts
theorem periodicOrbit_eq_nil_of_not_periodic_pt (h : x ∉ periodicPts f) :
diff --git a/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean b/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean
index 0333f199aa230..b5c4368d3eecd 100644
--- a/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean
+++ b/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean
@@ -19,7 +19,7 @@ A notable choice is that we define the topological entropy of a subset `F` of th
Usually, one defines the entropy of an invariant subset `F` as the entropy of the restriction of the
transformation to `F`. We avoid the latter definition as it would involve frequent manipulation of
subtypes. Our version directly gives a meaning to the topological entropy of a subsystem, and a
-single theorem (`subset_restriction_entropy` in `TopologicalEntropy.Morphism`) will give the
+single theorem (`subset_restriction_entropy` in `TopologicalEntropy.Semiconj`) will give the
equivalence between both versions.
Another choice is to give a meaning to the entropy of `∅` (it must be `-∞` to stay coherent) and to
@@ -28,11 +28,11 @@ reals `[-∞, +∞]`. The consequence is that we use `ℕ∞`, `ℝ≥0∞` and
## Main definitions
- `IsDynCoverOf`: property that dynamical balls centered on a subset `s` cover a subset `F`.
-- `coverMincard`: minimal cardinal of a dynamical cover. Takes values in `ℕ∞`.
-- `coverEntropyInfEnt`/`coverEntropyEnt`: exponential growth of `coverMincard`. The former is
-defined with a `liminf`, the later with a `limsup`. Take values in `EReal`.
-- `coverEntropyInf`/`coverEntropy`: supremum of `coverEntropyInfEnt`/`coverEntropyEnt` over
-all entourages (or limit as the entourages go to the diagonal). These are Bowen-Dinaburg's
+- `coverMincard`: minimal cardinality of a dynamical cover. Takes values in `ℕ∞`.
+- `coverEntropyInfEntourage`/`coverEntropyEntourage`: exponential growth of `coverMincard`.
+The former is defined with a `liminf`, the later with a `limsup`. Take values in `EReal`.
+- `coverEntropyInf`/`coverEntropy`: supremum of `coverEntropyInfEntourage`/`coverEntropyEntourage`
+over all entourages (or limit as the entourages go to the diagonal). These are Bowen-Dinaburg's
versions of the topological entropy with covers. Take values in `EReal`.
## Implementation notes
@@ -46,8 +46,8 @@ using only `coverEntropy`.
## Main results
- `IsDynCoverOf.iterate_le_pow`: given a dynamical cover at time `n`, creates dynamical covers
at all iterates `n * m` with controlled cardinality.
-- `IsDynCoverOf.coverEntropyEnt_le_log_card_div`: upper bound on `coverEntropyEnt` given any
-dynamical cover.
+- `IsDynCoverOf.coverEntropyEntourage_le_log_card_div`: upper bound on `coverEntropyEntourage`
+given any dynamical cover.
- `coverEntropyInf_eq_coverEntropy`: equality between the notions of topological entropy defined
with a `liminf` and a `limsup`.
@@ -56,11 +56,11 @@ cover, entropy
## TODO
The most painful part of many manipulations involving topological entropy is going from
-`coverMincard` to `coverEntropyInfEnt`/`coverEntropyEnt`. It involves a logarithm, a division, a
-`liminf`/`limsup`, and multiple coercions. The best thing to do would be to write a file on
-"exponential growth" to make a clean pathway from estimates on `coverMincard` to estimates on
-`coverEntropyInf`/`coverEntropy`. It would also be useful in other similar contexts, including the
-definition of entropy using nets.
+`coverMincard` to `coverEntropyInfEntourage`/`coverEntropyEntourage`. It involves a logarithm,
+a division, a `liminf`/`limsup`, and multiple coercions. The best thing to do would be to write
+a file on "exponential growth" to make a clean pathway from estimates on `coverMincard`
+to estimates on `coverEntropyInf`/`coverEntropy`. It would also be useful
+in other similar contexts, including the definition of entropy using nets.
Get versions of the topological entropy on (pseudo-e)metric spaces.
-/
@@ -133,8 +133,8 @@ lemma IsDynCoverOf.nonempty_inter {T : X → X} {F : Set X} {U : Set (X × X)} {
/-- From a dynamical cover `s` with entourage `U` and time `m`, we construct covers with entourage
`U ○ U` and any multiple `m * n` of `m` with controlled cardinality. This lemma is the first step
in a submultiplicative-like property of `coverMincard`, with consequences such as explicit bounds
-for the topological entropy (`coverEntropyInfEnt_le_card_div`) and an equality between two notions
-of topological entropy (`coverEntropyInf_eq_coverEntropySup_of_inv`).-/
+for the topological entropy (`coverEntropyInfEntourage_le_card_div`) and an equality between
+two notions of topological entropy (`coverEntropyInf_eq_coverEntropySup_of_inv`).-/
lemma IsDynCoverOf.iterate_le_pow {T : X → X} {F : Set X} (F_inv : MapsTo T F F) {U : Set (X × X)}
(U_symm : SymmetricRel U) {m : ℕ} (n : ℕ) {s : Finset X} (h : IsDynCoverOf T F U m s) :
∃ t : Finset X, IsDynCoverOf T F (U ○ U) (m * n) t ∧ t.card ≤ s.card ^ n := by
@@ -234,8 +234,8 @@ lemma exists_isDynCoverOf_of_isCompact_invariant [UniformSpace X] {T : X → X}
noncomputable def coverMincard (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) : ℕ∞ :=
⨅ (s : Finset X) (_ : IsDynCoverOf T F U n s), (s.card : ℕ∞)
-lemma coverMincard_le_card {T : X → X} {F : Set X} {U : Set (X × X)} {n : ℕ} {s : Finset X}
- (h : IsDynCoverOf T F U n s) :
+lemma IsDynCoverOf.coverMincard_le_card {T : X → X} {F : Set X} {U : Set (X × X)} {n : ℕ}
+ {s : Finset X} (h : IsDynCoverOf T F U n s) :
coverMincard T F U n ≤ s.card := iInf₂_le s h
lemma coverMincard_monotone_time (T : X → X) (F : Set X) (U : Set (X × X)) :
@@ -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
@@ -290,7 +290,7 @@ lemma coverMincard_zero (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X
rcases h with ⟨x, _⟩
have := isDynCoverOf_zero T F U (singleton_nonempty x)
rw [← Finset.coe_singleton] at this
- apply le_of_le_of_eq (coverMincard_le_card this)
+ apply this.coverMincard_le_card.trans_eq
rw [Finset.card_singleton, Nat.cast_one]
lemma coverMincard_univ (T : X → X) {F : Set X} (h : F.Nonempty) (n : ℕ) :
@@ -299,7 +299,7 @@ lemma coverMincard_univ (T : X → X) {F : Set X} (h : F.Nonempty) (n : ℕ) :
rcases h with ⟨x, _⟩
have := isDynCoverOf_univ T F n (singleton_nonempty x)
rw [← Finset.coe_singleton] at this
- apply le_of_le_of_eq (coverMincard_le_card this)
+ apply this.coverMincard_le_card.trans_eq
rw [Finset.card_singleton, Nat.cast_one]
lemma coverMincard_mul_le_pow {T : X → X} {F : Set X} (F_inv : MapsTo T F F) {U : Set (X × X)}
@@ -310,16 +310,16 @@ lemma coverMincard_mul_le_pow {T : X → X} {F : Set X} (F_inv : MapsTo T F F) {
rcases n.eq_zero_or_pos with rfl | n_pos
· rw [mul_zero, coverMincard_zero T F_nonempty (U ○ U), pow_zero]
rcases eq_top_or_lt_top (coverMincard T F U m) with h | h
- · exact h ▸ le_of_le_of_eq (le_top (α := ℕ∞)) (ENat.top_pow n_pos).symm
+ · exact h ▸ (le_top (α := ℕ∞)).trans_eq (ENat.top_pow n_pos).symm
· rcases (coverMincard_finite_iff T F U m).1 h with ⟨s, s_cover, s_coverMincard⟩
rcases s_cover.iterate_le_pow F_inv U_symm n with ⟨t, t_cover, t_le_sn⟩
rw [← s_coverMincard]
- exact (coverMincard_le_card t_cover).trans (WithTop.coe_le_coe.2 t_le_sn)
+ exact t_cover.coverMincard_le_card.trans (WithTop.coe_le_coe.2 t_le_sn)
lemma coverMincard_le_pow {T : X → X} {F : Set X} (F_inv : MapsTo T F F) {U : Set (X × X)}
(U_symm : SymmetricRel U) {m : ℕ} (m_pos : 0 < m) (n : ℕ) :
coverMincard T F (U ○ U) n ≤ coverMincard T F U m ^ (n / m + 1) :=
- (coverMincard_monotone_time T F (U ○ U) (le_of_lt (Nat.lt_mul_div_succ n m_pos))).trans
+ (coverMincard_monotone_time T F (U ○ U) (Nat.lt_mul_div_succ n m_pos).le).trans
(coverMincard_mul_le_pow F_inv U_symm m (n / m + 1))
lemma coverMincard_finite_of_isCompact_uniformContinuous [UniformSpace X] {T : X → X}
@@ -327,13 +327,13 @@ lemma coverMincard_finite_of_isCompact_uniformContinuous [UniformSpace X] {T : X
(n : ℕ) :
coverMincard T F U n < ⊤ := by
rcases exists_isDynCoverOf_of_isCompact_uniformContinuous F_comp h U_uni n with ⟨s, s_cover⟩
- exact (coverMincard_le_card s_cover).trans_lt (WithTop.coe_lt_top s.card)
+ exact s_cover.coverMincard_le_card.trans_lt (WithTop.coe_lt_top s.card)
lemma coverMincard_finite_of_isCompact_invariant [UniformSpace X] {T : X → X} {F : Set X}
(F_comp : IsCompact F) (F_inv : MapsTo T F F) {U : Set (X × X)} (U_uni : U ∈ 𝓤 X) (n : ℕ) :
coverMincard T F U n < ⊤ := by
rcases exists_isDynCoverOf_of_isCompact_invariant F_comp F_inv U_uni n with ⟨s, s_cover⟩
- exact (coverMincard_le_card s_cover).trans_lt (WithTop.coe_lt_top s.card)
+ exact s_cover.coverMincard_le_card.trans_lt (WithTop.coe_lt_top s.card)
/-- All dynamical balls of a minimal dynamical cover of `F` intersect `F`. This lemma is the key
to relate Bowen-Dinaburg's definition of topological entropy with covers and their definition
@@ -356,7 +356,7 @@ lemma nonempty_inter_of_coverMincard {T : X → X} {F : Set X} {U : Set (X × X)
rw [← ball_empt]
rw [z_x] at hz
exact mem_inter y_F hz
- apply not_lt_of_le (coverMincard_le_card smaller_cover)
+ apply smaller_cover.coverMincard_le_card.not_lt
rw [← h']
exact_mod_cast Finset.card_erase_lt_of_mem x_s
@@ -391,83 +391,82 @@ lemma log_coverMincard_le_add {T : X → X} {F : Set X} (F_inv : MapsTo T F F)
have h_nm : (0 : EReal) ≤ (n / m : ℕ) := Nat.cast_nonneg' (n / m)
have h_log := log_coverMincard_nonneg T F_nemp U m
have n_div_n := EReal.div_self (natCast_ne_bot n) (natCast_ne_top n)
- (ne_of_gt (Nat.cast_pos'.2 n_pos))
+ (Nat.cast_pos'.2 n_pos).ne.symm
apply le_trans <| div_le_div_right_of_nonneg (Nat.cast_pos'.2 n_pos).le
(log_monotone (ENat.toENNReal_le.2 (coverMincard_le_pow F_inv U_symm m_pos n)))
rw [ENat.toENNReal_pow, log_pow, Nat.cast_add, Nat.cast_one, right_distrib_of_nonneg h_nm
zero_le_one, one_mul, div_right_distrib_of_nonneg (Left.mul_nonneg h_nm h_log) h_log, mul_comm,
← EReal.mul_div, div_eq_mul_inv _ (m : EReal)]
apply add_le_add_right (mul_le_mul_of_nonneg_left _ h_log)
- apply le_of_le_of_eq <| div_le_div_right_of_nonneg (Nat.cast_pos'.2 n_pos).le (natCast_div_le n m)
+ apply (div_le_div_right_of_nonneg (Nat.cast_pos'.2 n_pos).le (natCast_div_le n m)).trans_eq
rw [EReal.div_div, mul_comm, ← EReal.div_div, n_div_n, one_div (m : EReal)]
/-! ### Cover entropy of entourages -/
open Filter
-/-- The entropy of an entourage `U` (`Ent` stands for "entourage"), defined as the exponential rate
- of growth of the size of the smallest `(U, n)`-refined cover of `F`. Takes values in the space of
- extended real numbers `[-∞, +∞]`. This first version uses a `limsup`, and is chosen as the
- default definition.-/
-noncomputable def coverEntropyEnt (T : X → X) (F : Set X) (U : Set (X × X)) :=
+/-- The entropy of an entourage `U`, defined as the exponential rate of growth of the size
+ of the smallest `(U, n)`-refined cover of `F`. Takes values in the space of extended real numbers
+ `[-∞, +∞]`. This first version uses a `limsup`, and is chosen as the default definition.-/
+noncomputable def coverEntropyEntourage (T : X → X) (F : Set X) (U : Set (X × X)) :=
atTop.limsup fun n : ℕ ↦ log (coverMincard T F U n) / n
-/-- The entropy of an entourage `U` (`Ent` stands for "entourage"), defined as the exponential rate
- of growth of the size of the smallest `(U, n)`-refined cover of `F`. Takes values in the space of
- extended real numbers `[-∞, +∞]`. This second version uses a `liminf`, and is chosen as an
- alternative definition.-/
-noncomputable def coverEntropyInfEnt (T : X → X) (F : Set X) (U : Set (X × X)) :=
+/-- The entropy of an entourage `U`, defined as the exponential rate of growth of the size
+ of the smallest `(U, n)`-refined cover of `F`. Takes values in the space of extended real numbers
+ `[-∞, +∞]`. This second version uses a `liminf`, and is chosen as an alternative definition.-/
+noncomputable def coverEntropyInfEntourage (T : X → X) (F : Set X) (U : Set (X × X)) :=
atTop.liminf fun n : ℕ ↦ log (coverMincard T F U n) / n
-lemma coverEntropyInfEnt_antitone (T : X → X) (F : Set X) :
- Antitone (fun U : Set (X × X) ↦ coverEntropyInfEnt T F U) :=
+lemma coverEntropyInfEntourage_antitone (T : X → X) (F : Set X) :
+ Antitone (fun U : Set (X × X) ↦ coverEntropyInfEntourage T F U) :=
fun _ _ U_V ↦ (liminf_le_liminf) <| Eventually.of_forall
fun n ↦ monotone_div_right_of_nonneg (Nat.cast_nonneg' n)
<| log_monotone (ENat.toENNReal_mono (coverMincard_antitone T F n U_V))
-lemma coverEntropyEnt_antitone (T : X → X) (F : Set X) :
- Antitone (fun U : Set (X × X) ↦ coverEntropyEnt T F U) :=
+lemma coverEntropyEntourage_antitone (T : X → X) (F : Set X) :
+ Antitone (fun U : Set (X × X) ↦ coverEntropyEntourage T F U) :=
fun _ _ U_V ↦ (limsup_le_limsup) <| Eventually.of_forall
fun n ↦ monotone_div_right_of_nonneg (Nat.cast_nonneg' n)
<| log_monotone (ENat.toENNReal_mono (coverMincard_antitone T F n U_V))
-lemma coverEntropyInfEnt_le_coverEntropyEnt (T : X → X) (F : Set X) (U : Set (X × X)) :
- coverEntropyInfEnt T F U ≤ coverEntropyEnt T F U := liminf_le_limsup
+lemma coverEntropyInfEntourage_le_coverEntropyEntourage (T : X → X) (F : Set X) (U : Set (X × X)) :
+ coverEntropyInfEntourage T F U ≤ coverEntropyEntourage T F U := liminf_le_limsup
@[simp]
-lemma coverEntropyEnt_empty {T : X → X} {U : Set (X × X)} :
- coverEntropyEnt T ∅ U = ⊥ := by
+lemma coverEntropyEntourage_empty {T : X → X} {U : Set (X × X)} :
+ coverEntropyEntourage T ∅ U = ⊥ := by
suffices h : ∀ᶠ n : ℕ in atTop, log (coverMincard T ∅ U n) / n = ⊥ by
- rw [coverEntropyEnt]
+ rw [coverEntropyEntourage]
exact limsup_congr h ▸ limsup_const ⊥
· simp only [coverMincard_empty, ENat.toENNReal_zero, log_zero, eventually_atTop]
exact ⟨1, fun n n_pos ↦ bot_div_of_pos_ne_top (Nat.cast_pos'.2 n_pos) (natCast_ne_top n)⟩
@[simp]
-lemma coverEntropyInfEnt_empty {T : X → X} {U : Set (X × X)} :
- coverEntropyInfEnt T ∅ U = ⊥ :=
- eq_bot_mono (coverEntropyInfEnt_le_coverEntropyEnt T ∅ U) coverEntropyEnt_empty
+lemma coverEntropyInfEntourage_empty {T : X → X} {U : Set (X × X)} :
+ coverEntropyInfEntourage T ∅ U = ⊥ :=
+ eq_bot_mono (coverEntropyInfEntourage_le_coverEntropyEntourage T ∅ U) coverEntropyEntourage_empty
-lemma coverEntropyInfEnt_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) :
- 0 ≤ coverEntropyInfEnt T F U :=
+lemma coverEntropyInfEntourage_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) :
+ 0 ≤ coverEntropyInfEntourage T F U :=
(le_iInf fun n ↦ div_nonneg (log_coverMincard_nonneg T h U n) (Nat.cast_nonneg' n)).trans
iInf_le_liminf
-lemma coverEntropyEnt_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) :
- 0 ≤ coverEntropyEnt T F U :=
- (coverEntropyInfEnt_nonneg T h U).trans (coverEntropyInfEnt_le_coverEntropyEnt T F U)
+lemma coverEntropyEntourage_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) :
+ 0 ≤ coverEntropyEntourage T F U :=
+ (coverEntropyInfEntourage_nonneg T h U).trans
+ (coverEntropyInfEntourage_le_coverEntropyEntourage T F U)
-lemma coverEntropyEnt_univ (T : X → X) {F : Set X} (h : F.Nonempty) :
- coverEntropyEnt T F univ = 0 := by
- simp [coverEntropyEnt, coverMincard_univ T h]
+lemma coverEntropyEntourage_univ (T : X → X) {F : Set X} (h : F.Nonempty) :
+ coverEntropyEntourage T F univ = 0 := by
+ simp [coverEntropyEntourage, coverMincard_univ T h]
-lemma coverEntropyInfEnt_univ (T : X → X) {F : Set X} (h : F.Nonempty) :
- coverEntropyInfEnt T F univ = 0 := by
- simp [coverEntropyInfEnt, coverMincard_univ T h]
+lemma coverEntropyInfEntourage_univ (T : X → X) {F : Set X} (h : F.Nonempty) :
+ coverEntropyInfEntourage T F univ = 0 := by
+ simp [coverEntropyInfEntourage, coverMincard_univ T h]
-lemma coverEntropyEnt_le_log_coverMincard_div {T : X → X} {F : Set X} (F_inv : MapsTo T F F)
+lemma coverEntropyEntourage_le_log_coverMincard_div {T : X → X} {F : Set X} (F_inv : MapsTo T F F)
{U : Set (X × X)} (U_symm : SymmetricRel U) {n : ℕ} (n_pos : 0 < n) :
- coverEntropyEnt T F (U ○ U) ≤ log (coverMincard T F U n) / n := by
+ coverEntropyEntourage T F (U ○ U) ≤ log (coverMincard T F U n) / n := by
-- Deal with the edge cases: `F = ∅` or `F` has no finite cover.
rcases eq_or_ne (log (coverMincard T F U n)) ⊥ with logm_bot | logm_nneg
· rw [log_eq_bot_iff, ← ENat.toENNReal_zero, ENat.toENNReal_coe_eq_iff,
@@ -487,46 +486,48 @@ lemma coverEntropyEnt_le_log_coverMincard_div {T : X → X} {F : Set X} (F_inv :
have := @limsup_add_le_add_limsup ℕ atTop u v
rw [h, add_zero] at this
specialize this (Or.inr EReal.zero_ne_top) (Or.inr EReal.zero_ne_bot)
- exact le_of_le_of_eq this (limsup_const (log (coverMincard T F U n) / n))
+ exact this.trans_eq (limsup_const (log (coverMincard T F U n) / n))
exact Tendsto.limsup_eq (EReal.tendsto_const_div_atTop_nhds_zero_nat logm_nneg logm_fin)
-lemma IsDynCoverOf.coverEntropyEnt_le_log_card_div {T : X → X} {F : Set X} (F_inv : MapsTo T F F)
- {U : Set (X × X)} (U_symm : SymmetricRel U) {n : ℕ} (n_pos : 0 < n) {s : Finset X}
- (h : IsDynCoverOf T F U n s) :
- coverEntropyEnt T F (U ○ U) ≤ log s.card / n := by
- apply (coverEntropyEnt_le_log_coverMincard_div F_inv U_symm n_pos).trans
+lemma IsDynCoverOf.coverEntropyEntourage_le_log_card_div {T : X → X} {F : Set X}
+ (F_inv : MapsTo T F F) {U : Set (X × X)} (U_symm : SymmetricRel U) {n : ℕ} (n_pos : 0 < n)
+ {s : Finset X} (h : IsDynCoverOf T F U n s) :
+ coverEntropyEntourage T F (U ○ U) ≤ log s.card / n := by
+ apply (coverEntropyEntourage_le_log_coverMincard_div F_inv U_symm n_pos).trans
apply monotone_div_right_of_nonneg (Nat.cast_nonneg' n) (log_monotone _)
exact_mod_cast coverMincard_le_card h
-lemma coverEntropyEnt_le_coverEntropyInfEnt {T : X → X} {F : Set X} (F_inv : MapsTo T F F)
- {U : Set (X × X)} (U_symm : SymmetricRel U) :
- coverEntropyEnt T F (U ○ U) ≤ coverEntropyInfEnt T F U :=
+lemma coverEntropyEntourage_le_coverEntropyInfEntourage {T : X → X} {F : Set X}
+ (F_inv : MapsTo T F F) {U : Set (X × X)} (U_symm : SymmetricRel U) :
+ coverEntropyEntourage T F (U ○ U) ≤ coverEntropyInfEntourage T F U :=
(le_liminf_of_le) (eventually_atTop.2
- ⟨1, fun m m_pos ↦ coverEntropyEnt_le_log_coverMincard_div F_inv U_symm m_pos⟩)
+ ⟨1, fun m m_pos ↦ coverEntropyEntourage_le_log_coverMincard_div F_inv U_symm m_pos⟩)
-lemma coverEntropyEnt_finite_of_isCompact_invariant [UniformSpace X] {T : X → X} {F : Set X}
+lemma coverEntropyEntourage_finite_of_isCompact_invariant [UniformSpace X] {T : X → X} {F : Set X}
(F_comp : IsCompact F) (F_inv : MapsTo T F F) {U : Set (X × X)} (U_uni : U ∈ 𝓤 X) :
- coverEntropyEnt T F U < ⊤ := by
+ coverEntropyEntourage T F U < ⊤ := by
rcases comp_symm_mem_uniformity_sets U_uni with ⟨V, V_uni, V_symm, V_U⟩
rcases exists_isDynCoverOf_of_isCompact_invariant F_comp F_inv V_uni 1 with ⟨s, s_cover⟩
- apply (coverEntropyEnt_antitone T F V_U).trans_lt
- apply (s_cover.coverEntropyEnt_le_log_card_div F_inv V_symm zero_lt_one).trans_lt
+ apply (coverEntropyEntourage_antitone T F V_U).trans_lt
+ apply (s_cover.coverEntropyEntourage_le_log_card_div F_inv V_symm zero_lt_one).trans_lt
rw [Nat.cast_one, div_one, log_lt_top_iff, ← ENat.toENNReal_top]
exact_mod_cast Ne.lt_top (ENat.coe_ne_top (Finset.card s))
/-! ### Cover entropy -/
-/-- The entropy of `T` restricted to `F`, obtained by taking the supremum over entourages.
- Note that this supremum is approached by taking small entourages. This first version uses a
- `limsup`, and is chosen as the default definition for topological entropy.-/
+/-- The entropy of `T` restricted to `F`, obtained by taking the supremum
+ of `coverEntropyEntourage` over entourages. Note that this supremum is approached by taking small
+ entourages. This first version uses a `limsup`, and is chosen as the default definition
+ for topological entropy.-/
noncomputable def coverEntropy [UniformSpace X] (T : X → X) (F : Set X) :=
- ⨆ U ∈ 𝓤 X, coverEntropyEnt T F U
+ ⨆ U ∈ 𝓤 X, coverEntropyEntourage T F U
-/-- The entropy of `T` restricted to `F`, obtained by taking the supremum over entourages.
- Note that this supremum is approached by taking small entourages. This second version uses a
- `liminf`, and is chosen as an alternative definition for topological entropy.-/
+/-- The entropy of `T` restricted to `F`, obtained by taking the supremum
+ of `coverEntropyInfEntourage` over entourages. Note that this supremum is approached by taking
+ small entourages. This second version uses a `liminf`, and is chosen as an alternative
+ definition for topological entropy.-/
noncomputable def coverEntropyInf [UniformSpace X] (T : X → X) (F : Set X) :=
- ⨆ U ∈ 𝓤 X, coverEntropyInfEnt T F U
+ ⨆ U ∈ 𝓤 X, coverEntropyInfEntourage T F U
lemma coverEntropyInf_antitone (T : X → X) (F : Set X) :
Antitone fun (u : UniformSpace X) ↦ @coverEntropyInf X u T F :=
@@ -538,49 +539,51 @@ lemma coverEntropy_antitone (T : X → X) (F : Set X) :
variable [UniformSpace X]
-lemma coverEntropyEnt_le_coverEntropy (T : X → X) (F : Set X) {U : Set (X × X)} (h : U ∈ 𝓤 X) :
- coverEntropyEnt T F U ≤ coverEntropy T F :=
- le_iSup₂ (f := fun (U : Set (X × X)) (_ : U ∈ 𝓤 X) ↦ coverEntropyEnt T F U) U h
+lemma coverEntropyEntourage_le_coverEntropy (T : X → X) (F : Set X) {U : Set (X × X)}
+ (h : U ∈ 𝓤 X) :
+ coverEntropyEntourage T F U ≤ coverEntropy T F :=
+ le_iSup₂ (f := fun (U : Set (X × X)) (_ : U ∈ 𝓤 X) ↦ coverEntropyEntourage T F U) U h
-lemma coverEntropyInfEnt_le_coverEntropyInf (T : X → X) (F : Set X) {U : Set (X × X)}
+lemma coverEntropyInfEntourage_le_coverEntropyInf (T : X → X) (F : Set X) {U : Set (X × X)}
(h : U ∈ 𝓤 X) :
- coverEntropyInfEnt T F U ≤ coverEntropyInf T F :=
- le_iSup₂ (f := fun (U : Set (X × X)) (_ : U ∈ 𝓤 X) ↦ coverEntropyInfEnt T F U) U h
+ coverEntropyInfEntourage T F U ≤ coverEntropyInf T F :=
+ le_iSup₂ (f := fun (U : Set (X × X)) (_ : U ∈ 𝓤 X) ↦ coverEntropyInfEntourage T F U) U h
lemma coverEntropy_eq_iSup_basis {ι : Sort*} {p : ι → Prop} {s : ι → Set (X × X)}
(h : (𝓤 X).HasBasis p s) (T : X → X) (F : Set X) :
- coverEntropy T F = ⨆ (i : ι) (_ : p i), coverEntropyEnt T F (s i) := by
+ coverEntropy T F = ⨆ (i : ι) (_ : p i), coverEntropyEntourage T F (s i) := by
refine (iSup₂_le fun U U_uni ↦ ?_).antisymm
(iSup₂_mono' fun i h_i ↦ ⟨s i, HasBasis.mem_of_mem h h_i, le_refl _⟩)
rcases (HasBasis.mem_iff h).1 U_uni with ⟨i, h_i, si_U⟩
- exact (coverEntropyEnt_antitone T F si_U).trans
- (le_iSup₂ (f := fun (i : ι) (_ : p i) ↦ coverEntropyEnt T F (s i)) i h_i)
+ exact (coverEntropyEntourage_antitone T F si_U).trans
+ (le_iSup₂ (f := fun (i : ι) (_ : p i) ↦ coverEntropyEntourage T F (s i)) i h_i)
lemma coverEntropyInf_eq_iSup_basis {ι : Sort*} {p : ι → Prop} {s : ι → Set (X × X)}
(h : (𝓤 X).HasBasis p s) (T : X → X) (F : Set X) :
- coverEntropyInf T F = ⨆ (i : ι) (_ : p i), coverEntropyInfEnt T F (s i) := by
+ coverEntropyInf T F = ⨆ (i : ι) (_ : p i), coverEntropyInfEntourage T F (s i) := by
refine (iSup₂_le fun U U_uni ↦ ?_).antisymm
(iSup₂_mono' fun i h_i ↦ ⟨s i, HasBasis.mem_of_mem h h_i, le_refl _⟩)
rcases (HasBasis.mem_iff h).1 U_uni with ⟨i, h_i, si_U⟩
- exact (coverEntropyInfEnt_antitone T F si_U).trans
- (le_iSup₂ (f := fun (i : ι) (_ : p i) ↦ coverEntropyInfEnt T F (s i)) i h_i)
+ exact (coverEntropyInfEntourage_antitone T F si_U).trans
+ (le_iSup₂ (f := fun (i : ι) (_ : p i) ↦ coverEntropyInfEntourage T F (s i)) i h_i)
lemma coverEntropyInf_le_coverEntropy (T : X → X) (F : Set X) :
coverEntropyInf T F ≤ coverEntropy T F :=
- iSup₂_mono fun (U : Set (X × X)) (_ : U ∈ 𝓤 X) ↦ coverEntropyInfEnt_le_coverEntropyEnt T F U
+ iSup₂_mono fun (U : Set (X × X)) (_ : U ∈ 𝓤 X) ↦
+ coverEntropyInfEntourage_le_coverEntropyEntourage T F U
@[simp]
lemma coverEntropy_empty {T : X → X} : coverEntropy T ∅ = ⊥ := by
- simp only [coverEntropy, coverEntropyEnt_empty, iSup_bot]
+ simp only [coverEntropy, coverEntropyEntourage_empty, iSup_bot]
@[simp]
lemma coverEntropyInf_empty {T : X → X} : coverEntropyInf T ∅ = ⊥ := by
- simp only [coverEntropyInf, coverEntropyInfEnt_empty, iSup_bot]
+ simp only [coverEntropyInf, coverEntropyInfEntourage_empty, iSup_bot]
lemma coverEntropyInf_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) :
0 ≤ coverEntropyInf T F :=
- le_of_eq_of_le (coverEntropyInfEnt_univ T h).symm
- (coverEntropyInfEnt_le_coverEntropyInf T F univ_mem)
+ (coverEntropyInfEntourage_le_coverEntropyInf T F univ_mem).trans_eq'
+ (coverEntropyInfEntourage_univ T h).symm
lemma coverEntropy_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) :
0 ≤ coverEntropy T F :=
@@ -590,7 +593,7 @@ lemma coverEntropyInf_eq_coverEntropy (T : X → X) {F : Set X} (h : MapsTo T F
coverEntropyInf T F = coverEntropy T F := by
refine le_antisymm (coverEntropyInf_le_coverEntropy T F) (iSup₂_le fun U U_uni ↦ ?_)
rcases comp_symm_mem_uniformity_sets U_uni with ⟨V, V_uni, V_symm, V_U⟩
- exact (coverEntropyEnt_antitone T F V_U).trans
- (le_iSup₂_of_le V V_uni (coverEntropyEnt_le_coverEntropyInfEnt h V_symm))
+ exact (coverEntropyEntourage_antitone T F V_U).trans
+ (le_iSup₂_of_le V V_uni (coverEntropyEntourage_le_coverEntropyInfEntourage h V_symm))
end Dynamics
diff --git a/Mathlib/Dynamics/TopologicalEntropy/DynamicalEntourage.lean b/Mathlib/Dynamics/TopologicalEntropy/DynamicalEntourage.lean
index ad6c52b6be339..08b6c75d0d4c0 100644
--- a/Mathlib/Dynamics/TopologicalEntropy/DynamicalEntourage.lean
+++ b/Mathlib/Dynamics/TopologicalEntropy/DynamicalEntourage.lean
@@ -88,7 +88,7 @@ lemma _root_.isOpen.dynEntourage [TopologicalSpace X] {T : X → X} (T_cont : Co
IsOpen (dynEntourage T U n) := by
rw [dynEntourage_eq_inter_Ico T U n]
refine isOpen_iInter_of_finite fun k ↦ ?_
- exact continuous_def.1 ((T_cont.prod_map T_cont).iterate k) U U_open
+ exact U_open.preimage ((T_cont.prodMap T_cont).iterate k)
lemma dynEntourage_monotone (T : X → X) (n : ℕ) :
Monotone (fun U : Set (X × X) ↦ dynEntourage T U n) :=
diff --git a/Mathlib/Dynamics/TopologicalEntropy/NetEntropy.lean b/Mathlib/Dynamics/TopologicalEntropy/NetEntropy.lean
new file mode 100644
index 0000000000000..7720c694f1ce9
--- /dev/null
+++ b/Mathlib/Dynamics/TopologicalEntropy/NetEntropy.lean
@@ -0,0 +1,408 @@
+/-
+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 via nets
+We implement Bowen-Dinaburg's definitions of the topological entropy, via nets.
+
+The major design decisions are the same as in `Mathlib.Dynamics.TopologicalEntropy.CoverEntropy`,
+and are explained in detail there: use of uniform spaces, definition of the topological entropy of
+a subset, and values taken in `EReal`.
+
+Given a map `T : X → X` and a subset `F ⊆ X`, the topological entropy is loosely defined using
+nets as the exponential growth (in `n`) of the number of distinguishable orbits of length `n`
+starting from `F`. More precisely, given an entourage `U`, two orbits of length `n` can be
+distinguished if there exists some index `k < n` such that `T^[k] x` and `T^[k] y` are far enough
+(i.e. `(T^[k] x, T^[k] y)` is not in `U`). The maximal number of distinguishable orbits of
+length `n` is `netMaxcard T F U n`, and its exponential growth `netEntropyEntourage T F U`. This
+quantity increases when `U` decreases, and a definition of the topological entropy is
+`⨆ U ∈ 𝓤 X, netEntropyInfEntourage T F U`.
+
+The definition of topological entropy using nets coincides with the definition using covers.
+Instead of defining a new notion of topological entropy, we prove that
+`coverEntropy` coincides with `⨆ U ∈ 𝓤 X, netEntropyEntourage T F U`.
+
+## Main definitions
+- `IsDynNetIn`: property that dynamical balls centered on a subset `s` of `F` are disjoint.
+- `netMaxcard`: maximal cardinality of a dynamical net. Takes values in `ℕ∞`.
+- `netEntropyInfEntourage`/`netEntropyEntourage`: exponential growth of `netMaxcard`. The former is
+defined with a `liminf`, the latter with a `limsup`. Take values in `EReal`.
+
+## Implementation notes
+As when using covers, there are two competing definitions `netEntropyInfEntourage` and
+`netEntropyEntourage` in this file: one uses a `liminf`, the other a `limsup`. When using covers,
+we chose the `limsup` definition as the default.
+
+## Main results
+- `coverEntropy_eq_iSup_netEntropyEntourage`: equality between the notions of topological entropy
+defined with covers and with nets. Has a variant for `coverEntropyInf`.
+
+## Tags
+net, entropy
+
+## TODO
+Get versions of the topological entropy on (pseudo-e)metric spaces.
+-/
+
+namespace Dynamics
+
+open Set Uniformity UniformSpace
+
+variable {X : Type*}
+
+/-! ### Dynamical nets -/
+
+/-- Given a subset `F`, an entourage `U` and an integer `n`, a subset `s` of `F` is a
+`(U, n)`-dynamical net of `F` if no two orbits of length `n` of points in `s` shadow each other.-/
+def IsDynNetIn (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) (s : Set X) : Prop :=
+ s ⊆ F ∧ s.PairwiseDisjoint (fun x : X ↦ ball x (dynEntourage T U n))
+
+lemma IsDynNetIn.of_le {T : X → X} {F : Set X} {U : Set (X × X)} {m n : ℕ} (m_n : m ≤ n) {s : Set X}
+ (h : IsDynNetIn T F U m s) :
+ IsDynNetIn T F U n s :=
+ ⟨h.1, PairwiseDisjoint.mono h.2 (fun x ↦ ball_mono (dynEntourage_antitone T U m_n) x)⟩
+
+lemma IsDynNetIn.of_entourage_subset {T : X → X} {F : Set X} {U V : Set (X × X)} (U_V : U ⊆ V)
+ {n : ℕ} {s : Set X} (h : IsDynNetIn T F V n s) :
+ IsDynNetIn T F U n s :=
+ ⟨h.1, PairwiseDisjoint.mono h.2 (fun x ↦ ball_mono (dynEntourage_monotone T n U_V) x)⟩
+
+lemma isDynNetIn_empty {T : X → X} {F : Set X} {U : Set (X × X)} {n : ℕ} :
+ IsDynNetIn T F U n ∅ :=
+ ⟨empty_subset F, pairwise_empty _⟩
+
+lemma isDynNetIn_singleton (T : X → X) {F : Set X} (U : Set (X × X)) (n : ℕ) {x : X} (h : x ∈ F) :
+ IsDynNetIn T F U n {x} :=
+ ⟨singleton_subset_iff.2 h, pairwise_singleton x _⟩
+
+/-- Given an entourage `U` and a time `n`, a dynamical net has a smaller cardinality than
+ a dynamical cover. This lemma is the first of two key results to compare two versions of
+ topological entropy: with cover and with nets, the second being `coverMincard_le_netMaxcard`.-/
+lemma IsDynNetIn.card_le_card_of_isDynCoverOf {T : X → X} {F : Set X} {U : Set (X × X)}
+ (U_symm : SymmetricRel U) {n : ℕ} {s t : Finset X} (hs : IsDynNetIn T F U n s)
+ (ht : IsDynCoverOf T F U n t) :
+ s.card ≤ t.card := by
+ have (x : X) (x_s : x ∈ s) : ∃ z ∈ t, x ∈ ball z (dynEntourage T U n) := by
+ specialize ht (hs.1 x_s)
+ simp only [Finset.coe_sort_coe, mem_iUnion, Subtype.exists, exists_prop] at ht
+ exact ht
+ choose! F s_t using this
+ simp only [mem_ball_symmetry (U_symm.dynEntourage T n)] at s_t
+ apply Finset.card_le_card_of_injOn F (fun x x_s ↦ (s_t x x_s).1)
+ exact fun x x_s y y_s Fx_Fy ↦
+ PairwiseDisjoint.elim_set hs.2 x_s y_s (F x) (s_t x x_s).2 (Fx_Fy ▸ (s_t y y_s).2)
+
+/-! ### Maximal cardinality of dynamical nets -/
+
+/-- The largest cardinality of a `(U, n)`-dynamical net of `F`. Takes values in `ℕ∞`, and is
+infinite if and only if `F` admits nets of arbitrarily large size.-/
+noncomputable def netMaxcard (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) : ℕ∞ :=
+ ⨆ (s : Finset X) (_ : IsDynNetIn T F U n s), (s.card : ℕ∞)
+
+lemma IsDynNetIn.card_le_netMaxcard {T : X → X} {F : Set X} {U : Set (X × X)} {n : ℕ} {s : Finset X}
+ (h : IsDynNetIn T F U n s) :
+ s.card ≤ netMaxcard T F U n :=
+ le_iSup₂ (α := ℕ∞) s h
+
+lemma netMaxcard_monotone_time (T : X → X) (F : Set X) (U : Set (X × X)) :
+ Monotone (fun n : ℕ ↦ netMaxcard T F U n) :=
+ fun _ _ m_n ↦ biSup_mono (fun _ h ↦ h.of_le m_n)
+
+lemma netMaxcard_antitone (T : X → X) (F : Set X) (n : ℕ) :
+ Antitone (fun U : Set (X × X) ↦ netMaxcard T F U n) :=
+ fun _ _ U_V ↦ biSup_mono (fun _ h ↦ h.of_entourage_subset U_V)
+
+lemma netMaxcard_finite_iff (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) :
+ netMaxcard T F U n < ⊤ ↔
+ ∃ s : Finset X, IsDynNetIn T F U n s ∧ (s.card : ℕ∞) = netMaxcard T F U n := by
+ apply Iff.intro <;> intro h
+ · rcases WithTop.ne_top_iff_exists.1 h.ne with ⟨k, k_max⟩
+ rw [← k_max]
+ simp only [ENat.some_eq_coe, Nat.cast_inj]
+ -- The criterion we want to use is `Nat.sSup_mem`. We rewrite `netMaxcard` with an `sSup`,
+ -- then check its `BddAbove` and `Nonempty` hypotheses.
+ have : netMaxcard T F U n
+ = sSup (WithTop.some '' (Finset.card '' {s : Finset X | IsDynNetIn T F U n s})) := by
+ rw [netMaxcard, ← image_comp, sSup_image]
+ simp only [mem_setOf_eq, ENat.some_eq_coe, Function.comp_apply]
+ rw [this] at k_max
+ have h_bdda : BddAbove (Finset.card '' {s : Finset X | IsDynNetIn T F U n s}) := by
+ refine ⟨k, mem_upperBounds.2 ?_⟩
+ simp only [mem_image, mem_setOf_eq, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
+ intro s h
+ rw [← WithTop.coe_le_coe, k_max]
+ apply le_sSup
+ simp only [ENat.some_eq_coe, mem_image, mem_setOf_eq, Nat.cast_inj, exists_eq_right]
+ exact Filter.frequently_principal.mp fun a ↦ a h rfl
+ have h_nemp : (Finset.card '' {s : Finset X | IsDynNetIn T F U n s}).Nonempty := by
+ refine ⟨0, ?_⟩
+ simp only [mem_image, mem_setOf_eq, Finset.card_eq_zero, exists_eq_right, Finset.coe_empty]
+ exact isDynNetIn_empty
+ rw [← WithTop.coe_sSup' h_bdda, ENat.some_eq_coe, Nat.cast_inj] at k_max
+ have key := Nat.sSup_mem h_nemp h_bdda
+ rw [← k_max, mem_image] at key
+ simp only [mem_setOf_eq] at key
+ exact key
+ · rcases h with ⟨s, _, s_netMaxcard⟩
+ rw [← s_netMaxcard]
+ exact WithTop.coe_lt_top s.card
+
+@[simp]
+lemma netMaxcard_empty {T : X → X} {U : Set (X × X)} {n : ℕ} : netMaxcard T ∅ U n = 0 := by
+ rw [netMaxcard, ← bot_eq_zero, iSup₂_eq_bot]
+ intro s s_net
+ replace s_net := subset_empty_iff.1 s_net.1
+ norm_cast at s_net
+ rw [s_net, Finset.card_empty, CharP.cast_eq_zero, bot_eq_zero']
+
+lemma netMaxcard_eq_zero_iff (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) :
+ netMaxcard T F U n = 0 ↔ F = ∅ := by
+ refine Iff.intro (fun h ↦ ?_) (fun h ↦ by rw [h, netMaxcard_empty])
+ rw [eq_empty_iff_forall_not_mem]
+ intro x x_F
+ have key := isDynNetIn_singleton T U n x_F
+ rw [← Finset.coe_singleton] at key
+ replace key := key.card_le_netMaxcard
+ rw [Finset.card_singleton, Nat.cast_one, h] at key
+ exact key.not_lt zero_lt_one
+
+lemma one_le_netMaxcard_iff (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) :
+ 1 ≤ netMaxcard T F U n ↔ F.Nonempty := by
+ rw [ENat.one_le_iff_ne_zero, nonempty_iff_ne_empty]
+ exact not_iff_not.2 (netMaxcard_eq_zero_iff T F U n)
+
+lemma netMaxcard_zero (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) :
+ netMaxcard T F U 0 = 1 := by
+ apply (iSup₂_le _).antisymm ((one_le_netMaxcard_iff T F U 0).2 h)
+ intro s ⟨_, s_net⟩
+ simp only [ball, dynEntourage_zero, preimage_univ] at s_net
+ norm_cast
+ refine Finset.card_le_one.2 (fun x x_s y y_s ↦ ?_)
+ exact PairwiseDisjoint.elim_set s_net x_s y_s x (mem_univ x) (mem_univ x)
+
+lemma netMaxcard_univ (T : X → X) {F : Set X} (h : F.Nonempty) (n : ℕ) :
+ netMaxcard T F univ n = 1 := by
+ apply (iSup₂_le _).antisymm ((one_le_netMaxcard_iff T F univ n).2 h)
+ intro s ⟨_, s_net⟩
+ simp only [ball, dynEntourage_univ, preimage_univ] at s_net
+ norm_cast
+ refine Finset.card_le_one.2 (fun x x_s y y_s ↦ ?_)
+ exact PairwiseDisjoint.elim_set s_net x_s y_s x (mem_univ x) (mem_univ x)
+
+lemma netMaxcard_infinite_iff (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) :
+ netMaxcard T F U n = ⊤ ↔ ∀ k : ℕ, ∃ s : Finset X, IsDynNetIn T F U n s ∧ k ≤ s.card := by
+ apply Iff.intro <;> intro h
+ · intro k
+ rw [netMaxcard, iSup_subtype', iSup_eq_top] at h
+ specialize h k (ENat.coe_lt_top k)
+ simp only [Nat.cast_lt, Subtype.exists, exists_prop] at h
+ rcases h with ⟨s, s_net, s_k⟩
+ exact ⟨s, ⟨s_net, s_k.le⟩⟩
+ · refine WithTop.forall_gt_iff_eq_top.1 fun k ↦ ?_
+ specialize h (k + 1)
+ rcases h with ⟨s, s_net, s_card⟩
+ apply s_net.card_le_netMaxcard.trans_lt'
+ rw [ENat.some_eq_coe, Nat.cast_lt]
+ exact (lt_add_one k).trans_le s_card
+
+lemma netMaxcard_le_coverMincard (T : X → X) (F : Set X) {U : Set (X × X)} (U_symm : SymmetricRel U)
+ (n : ℕ) :
+ netMaxcard T F U n ≤ coverMincard T F U n := by
+ rcases eq_top_or_lt_top (coverMincard T F U n) with h | h
+ · exact h ▸ le_top
+ · rcases ((coverMincard_finite_iff T F U n).1 h) with ⟨t, t_cover, t_mincard⟩
+ rw [← t_mincard]
+ exact iSup₂_le (fun s s_net ↦ Nat.cast_le.2 (s_net.card_le_card_of_isDynCoverOf U_symm t_cover))
+
+/-- Given an entourage `U` and a time `n`, a minimal dynamical cover by `U ○ U` has a smaller
+ cardinality than a maximal dynamical net by `U`. This lemma is the second of two key results to
+ compare two versions topological entropy: with cover and with nets.-/
+lemma coverMincard_le_netMaxcard (T : X → X) (F : Set X) {U : Set (X × X)} (U_rfl : idRel ⊆ U)
+ (U_symm : SymmetricRel U) (n : ℕ) :
+ coverMincard T F (U ○ U) n ≤ netMaxcard T F U n := by
+ classical
+ -- WLOG, there exists a maximal dynamical net `s`.
+ rcases (eq_top_or_lt_top (netMaxcard T F U n)) with h | h
+ · exact h ▸ le_top
+ rcases ((netMaxcard_finite_iff T F U n).1 h) with ⟨s, s_net, s_netMaxcard⟩
+ rw [← s_netMaxcard]
+ apply IsDynCoverOf.coverMincard_le_card
+ -- We have to check that `s` is a cover for `dynEntourage T F (U ○ U) n`.
+ -- If `s` is not a cover, then we can add to `s` a point `x` which is not covered
+ -- and get a new net. This contradicts the maximality of `s`.
+ by_contra h
+ rcases not_subset.1 h with ⟨x, x_F, x_uncov⟩
+ simp only [Finset.mem_coe, mem_iUnion, exists_prop, not_exists, not_and] at x_uncov
+ have larger_net : IsDynNetIn T F U n (insert x s) :=
+ And.intro (insert_subset x_F s_net.1) (pairwiseDisjoint_insert.2 (And.intro s_net.2
+ (fun y y_s _ ↦ (disjoint_left.2 (fun z z_x z_y ↦ x_uncov y y_s
+ (mem_ball_dynEntourage_comp T n U_symm x y (nonempty_of_mem ⟨z_x, z_y⟩)))))))
+ rw [← Finset.coe_insert x s] at larger_net
+ apply larger_net.card_le_netMaxcard.not_lt
+ rw [← s_netMaxcard, Nat.cast_lt]
+ refine (lt_add_one s.card).trans_eq (Finset.card_insert_of_not_mem fun x_s ↦ ?_).symm
+ apply x_uncov x x_s (ball_mono (dynEntourage_monotone T n (subset_comp_self U_rfl)) x
+ (ball_mono (idRel_subset_dynEntourage T U_rfl n) x _))
+ simp only [ball, mem_preimage, mem_idRel]
+
+open ENNReal EReal
+
+lemma log_netMaxcard_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) (n : ℕ) :
+ 0 ≤ log (netMaxcard T F U n) := by
+ apply zero_le_log_iff.2
+ rw [← ENat.toENNReal_one, ENat.toENNReal_le]
+ exact (one_le_netMaxcard_iff T F U n).2 h
+
+/-! ### Net entropy of entourages -/
+
+open Filter
+
+/-- The entropy of an entourage `U`, defined as the exponential rate of growth of the size of the
+largest `(U, n)`-dynamical net of `F`. Takes values in the space of extended real numbers
+`[-∞,+∞]`. This version uses a `limsup`, and is chosen as the default definition.-/
+noncomputable def netEntropyEntourage (T : X → X) (F : Set X) (U : Set (X × X)) :=
+ atTop.limsup fun n : ℕ ↦ log (netMaxcard T F U n) / n
+
+/-- The entropy of an entourage `U`, defined as the exponential rate of growth of the size of the
+largest `(U, n)`-dynamical net of `F`. Takes values in the space of extended real numbers
+`[-∞,+∞]`. This version uses a `liminf`, and is an alternative definition.-/
+noncomputable def netEntropyInfEntourage (T : X → X) (F : Set X) (U : Set (X × X)) :=
+ atTop.liminf fun n : ℕ ↦ log (netMaxcard T F U n) / n
+
+lemma netEntropyInfEntourage_antitone (T : X → X) (F : Set X) :
+ Antitone (fun U : Set (X × X) ↦ netEntropyInfEntourage T F U) :=
+ fun _ _ U_V ↦ (liminf_le_liminf) (Eventually.of_forall
+ fun n ↦ monotone_div_right_of_nonneg (Nat.cast_nonneg' n)
+ (log_monotone (ENat.toENNReal_mono (netMaxcard_antitone T F n U_V))))
+
+lemma netEntropyEntourage_antitone (T : X → X) (F : Set X) :
+ Antitone (fun U : Set (X × X) ↦ netEntropyEntourage T F U) :=
+ fun _ _ U_V ↦ (limsup_le_limsup) (Eventually.of_forall
+ fun n ↦ (monotone_div_right_of_nonneg (Nat.cast_nonneg' n)
+ (log_monotone (ENat.toENNReal_mono (netMaxcard_antitone T F n U_V)))))
+
+lemma netEntropyInfEntourage_le_netEntropyEntourage (T : X → X) (F : Set X) (U : Set (X × X)) :
+ netEntropyInfEntourage T F U ≤ netEntropyEntourage T F U := liminf_le_limsup
+
+@[simp]
+lemma netEntropyEntourage_empty {T : X → X} {U : Set (X × X)} : netEntropyEntourage T ∅ U = ⊥ := by
+ suffices h : ∀ᶠ n : ℕ in atTop, log (netMaxcard T ∅ U n) / n = ⊥ by
+ rw [netEntropyEntourage, limsup_congr h]
+ exact limsup_const ⊥
+ simp only [netMaxcard_empty, ENat.toENNReal_zero, log_zero, eventually_atTop]
+ exact ⟨1, fun n n_pos ↦ bot_div_of_pos_ne_top (Nat.cast_pos'.2 n_pos) (natCast_ne_top n)⟩
+
+@[simp]
+lemma netEntropyInfEntourage_empty {T : X → X} {U : Set (X × X)} :
+ netEntropyInfEntourage T ∅ U = ⊥ :=
+ eq_bot_mono (netEntropyInfEntourage_le_netEntropyEntourage T ∅ U) netEntropyEntourage_empty
+
+lemma netEntropyInfEntourage_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) :
+ 0 ≤ netEntropyInfEntourage T F U :=
+ (le_iInf fun n ↦ div_nonneg (log_netMaxcard_nonneg T h U n) (Nat.cast_nonneg' n)).trans
+ iInf_le_liminf
+
+lemma netEntropyEntourage_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) :
+ 0 ≤ netEntropyEntourage T F U :=
+ (netEntropyInfEntourage_nonneg T h U).trans (netEntropyInfEntourage_le_netEntropyEntourage T F U)
+
+lemma netEntropyInfEntourage_univ (T : X → X) {F : Set X} (h : F.Nonempty) :
+ netEntropyInfEntourage T F univ = 0 := by simp [netEntropyInfEntourage, netMaxcard_univ T h]
+
+lemma netEntropyEntourage_univ (T : X → X) {F : Set X} (h : F.Nonempty) :
+ netEntropyEntourage T F univ = 0 := by simp [netEntropyEntourage, netMaxcard_univ T h]
+
+lemma netEntropyInfEntourage_le_coverEntropyInfEntourage (T : X → X) (F : Set X) {U : Set (X × X)}
+ (U_symm : SymmetricRel U) :
+ netEntropyInfEntourage T F U ≤ coverEntropyInfEntourage T F U :=
+ (liminf_le_liminf) (Eventually.of_forall fun n ↦ (div_le_div_right_of_nonneg (Nat.cast_nonneg' n)
+ (log_monotone (ENat.toENNReal_le.2 (netMaxcard_le_coverMincard T F U_symm n)))))
+
+lemma coverEntropyInfEntourage_le_netEntropyInfEntourage (T : X → X) (F : Set X) {U : Set (X × X)}
+ (U_rfl : idRel ⊆ U) (U_symm : SymmetricRel U) :
+ coverEntropyInfEntourage T F (U ○ U) ≤ netEntropyInfEntourage T F U := by
+ refine (liminf_le_liminf) (Eventually.of_forall fun n ↦ ?_)
+ apply div_le_div_right_of_nonneg (Nat.cast_nonneg' n) (log_monotone _)
+ exact ENat.toENNReal_le.2 (coverMincard_le_netMaxcard T F U_rfl U_symm n)
+
+lemma netEntropyEntourage_le_coverEntropyEntourage (T : X → X) (F : Set X) {U : Set (X × X)}
+ (U_symm : SymmetricRel U) :
+ netEntropyEntourage T F U ≤ coverEntropyEntourage T F U := by
+ refine (limsup_le_limsup) (Eventually.of_forall fun n ↦ ?_)
+ apply div_le_div_right_of_nonneg (Nat.cast_nonneg' n) (log_monotone _)
+ exact ENat.toENNReal_le.2 (netMaxcard_le_coverMincard T F U_symm n)
+
+lemma coverEntropyEntourage_le_netEntropyEntourage (T : X → X) (F : Set X) {U : Set (X × X)}
+ (U_rfl : idRel ⊆ U) (U_symm : SymmetricRel U) :
+ coverEntropyEntourage T F (U ○ U) ≤ netEntropyEntourage T F U := by
+ refine (limsup_le_limsup) (Eventually.of_forall fun n ↦ ?_)
+ apply div_le_div_right_of_nonneg (Nat.cast_nonneg' n) (log_monotone _)
+ exact ENat.toENNReal_le.2 (coverMincard_le_netMaxcard T F U_rfl U_symm n)
+
+/-! ### Relationship with entropy via covers -/
+
+variable [UniformSpace X] (T : X → X) (F : Set X)
+
+/-- Bowen-Dinaburg's definition of topological entropy using nets is
+ `⨆ U ∈ 𝓤 X, netEntropyEntourage T F U`. This quantity is the same as the topological entropy using
+ covers, so there is no need to define a new notion of topological entropy. This version of the
+ theorem relates the `liminf` versions of topological entropy.-/
+theorem coverEntropyInf_eq_iSup_netEntropyInfEntourage :
+ coverEntropyInf T F = ⨆ U ∈ 𝓤 X, netEntropyInfEntourage T F U := by
+ apply le_antisymm <;> refine iSup₂_le fun U U_uni ↦ ?_
+ · rcases (comp_symm_mem_uniformity_sets U_uni) with ⟨V, V_uni, V_symm, V_comp_U⟩
+ apply (coverEntropyInfEntourage_antitone T F V_comp_U).trans (le_iSup₂_of_le V V_uni _)
+ exact coverEntropyInfEntourage_le_netEntropyInfEntourage T F (refl_le_uniformity V_uni) V_symm
+ · apply (netEntropyInfEntourage_antitone T F (symmetrizeRel_subset_self U)).trans
+ apply (le_iSup₂ (symmetrizeRel U) (symmetrize_mem_uniformity U_uni)).trans'
+ exact netEntropyInfEntourage_le_coverEntropyInfEntourage T F (symmetric_symmetrizeRel U)
+
+/-- Bowen-Dinaburg's definition of topological entropy using nets is
+ `⨆ U ∈ 𝓤 X, netEntropyEntourage T F U`. This quantity is the same as the topological entropy using
+ covers, so there is no need to define a new notion of topological entropy. This version of the
+ theorem relates the `limsup` versions of topological entropy.-/
+theorem coverEntropy_eq_iSup_netEntropyEntourage :
+ coverEntropy T F = ⨆ U ∈ 𝓤 X, netEntropyEntourage T F U := by
+ apply le_antisymm <;> refine iSup₂_le fun U U_uni ↦ ?_
+ · rcases (comp_symm_mem_uniformity_sets U_uni) with ⟨V, V_uni, V_symm, V_comp_U⟩
+ apply (coverEntropyEntourage_antitone T F V_comp_U).trans (le_iSup₂_of_le V V_uni _)
+ exact coverEntropyEntourage_le_netEntropyEntourage T F (refl_le_uniformity V_uni) V_symm
+ · apply (netEntropyEntourage_antitone T F (symmetrizeRel_subset_self U)).trans
+ apply (le_iSup₂ (symmetrizeRel U) (symmetrize_mem_uniformity U_uni)).trans'
+ exact netEntropyEntourage_le_coverEntropyEntourage T F (symmetric_symmetrizeRel U)
+
+lemma coverEntropyInf_eq_iSup_basis_netEntropyInfEntourage {ι : Sort*} {p : ι → Prop}
+ {s : ι → Set (X × X)} (h : (𝓤 X).HasBasis p s) (T : X → X) (F : Set X) :
+ coverEntropyInf T F = ⨆ (i : ι) (_ : p i), netEntropyInfEntourage T F (s i) := by
+ rw [coverEntropyInf_eq_iSup_netEntropyInfEntourage T F]
+ apply (iSup₂_mono' fun i h_i ↦ ⟨s i, HasBasis.mem_of_mem h h_i, le_refl _⟩).antisymm'
+ refine iSup₂_le fun U U_uni ↦ ?_
+ rcases (HasBasis.mem_iff h).1 U_uni with ⟨i, h_i, si_U⟩
+ apply (netEntropyInfEntourage_antitone T F si_U).trans
+ exact le_iSup₂ (f := fun (i : ι) (_ : p i) ↦ netEntropyInfEntourage T F (s i)) i h_i
+
+lemma coverEntropy_eq_iSup_basis_netEntropyEntourage {ι : Sort*} {p : ι → Prop}
+ {s : ι → Set (X × X)} (h : (𝓤 X).HasBasis p s) (T : X → X) (F : Set X) :
+ coverEntropy T F = ⨆ (i : ι) (_ : p i), netEntropyEntourage T F (s i) := by
+ rw [coverEntropy_eq_iSup_netEntropyEntourage T F]
+ apply (iSup₂_mono' fun i h_i ↦ ⟨s i, HasBasis.mem_of_mem h h_i, le_refl _⟩).antisymm'
+ refine iSup₂_le fun U U_uni ↦ ?_
+ rcases (HasBasis.mem_iff h).1 U_uni with ⟨i, h_i, si_U⟩
+ apply (netEntropyEntourage_antitone T F si_U).trans _
+ exact le_iSup₂ (f := fun (i : ι) (_ : p i) ↦ netEntropyEntourage T F (s i)) i h_i
+
+lemma netEntropyInfEntourage_le_coverEntropyInf {U : Set (X × X)} (h : U ∈ 𝓤 X) :
+ netEntropyInfEntourage T F U ≤ coverEntropyInf T F :=
+ coverEntropyInf_eq_iSup_netEntropyInfEntourage T F ▸
+ le_iSup₂ (f := fun (U : Set (X × X)) (_ : U ∈ 𝓤 X) ↦ netEntropyInfEntourage T F U) U h
+
+lemma netEntropyEntourage_le_coverEntropy {U : Set (X × X)} (h : U ∈ 𝓤 X) :
+ netEntropyEntourage T F U ≤ coverEntropy T F :=
+ coverEntropy_eq_iSup_netEntropyEntourage T F ▸
+ le_iSup₂ (f := fun (U : Set (X × X)) (_ : U ∈ 𝓤 X) ↦ netEntropyEntourage T F U) U h
+
+end Dynamics
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 e83645c2902e6..f5504ce434121 100644
--- a/Mathlib/FieldTheory/Adjoin.lean
+++ b/Mathlib/FieldTheory/Adjoin.lean
@@ -28,7 +28,7 @@ For example, `Algebra.adjoin K {x}` might not include `x⁻¹`.
- `F⟮α⟯`: adjoin a single element `α` to `F` (in scope `IntermediateField`).
-/
-open FiniteDimensional Polynomial
+open Module Polynomial
namespace IntermediateField
@@ -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]
@@ -252,6 +309,14 @@ theorem map_iSup {ι : Sort*} (f : E →ₐ[F] K) (s : ι → IntermediateField
(iSup s).map f = ⨆ i, (s i).map f :=
(gc_map_comap f).l_iSup
+theorem map_inf (s t : IntermediateField F E) (f : E →ₐ[F] K) :
+ (s ⊓ t).map f = s.map f ⊓ t.map f := SetLike.coe_injective (Set.image_inter f.injective)
+
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : E →ₐ[F] K) (s : ι → IntermediateField F E) :
+ (iInf s).map f = ⨅ i, (s i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective f.injective).image_iInter_eq (s := SetLike.coe ∘ s)
+
theorem _root_.AlgHom.fieldRange_eq_map (f : E →ₐ[F] K) :
f.fieldRange = IntermediateField.map f ⊤ :=
SetLike.ext' Set.image_univ.symm
@@ -353,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) :
@@ -388,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) :
@@ -463,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)
@@ -553,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
@@ -837,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
@@ -864,7 +912,7 @@ theorem adjoin_natCast (n : ℕ) : F⟮(n : E)⟯ = ⊥ :=
section AdjoinRank
-open FiniteDimensional Module
+open Module Module
variable {K L : IntermediateField F E}
@@ -998,6 +1046,11 @@ theorem adjoinRootEquivAdjoin_apply_root (h : IsIntegral F α) :
adjoinRootEquivAdjoin F h (AdjoinRoot.root (minpoly F α)) = AdjoinSimple.gen F α :=
AdjoinRoot.lift_root (aeval_gen_minpoly F α)
+@[simp]
+theorem adjoinRootEquivAdjoin_symm_apply_gen (h : IsIntegral F α) :
+ (adjoinRootEquivAdjoin F h).symm (AdjoinSimple.gen F α) = AdjoinRoot.root (minpoly F α) := by
+ rw [AlgEquiv.symm_apply_eq, adjoinRootEquivAdjoin_apply_root]
+
theorem adjoin_root_eq_top (p : K[X]) [Fact (Irreducible p)] : K⟮AdjoinRoot.root p⟯ = ⊤ :=
(eq_adjoin_of_eq_algebra_adjoin K _ ⊤ (AdjoinRoot.adjoinRoot_eq_top (f := p)).symm).symm
@@ -1030,7 +1083,7 @@ theorem isAlgebraic_adjoin_simple {x : L} (hx : IsIntegral K x) : Algebra.IsAlge
have := adjoin.finiteDimensional hx; Algebra.IsAlgebraic.of_finite K K⟮x⟯
theorem adjoin.finrank {x : L} (hx : IsIntegral K x) :
- FiniteDimensional.finrank K K⟮x⟯ = (minpoly K x).natDegree := by
+ Module.finrank K K⟮x⟯ = (minpoly K x).natDegree := by
rw [PowerBasis.finrank (adjoin.powerBasis hx : _)]
rfl
@@ -1101,6 +1154,14 @@ theorem _root_.minpoly.degree_le (x : L) [FiniteDimensional K L] :
(minpoly K x).degree ≤ finrank K L :=
degree_le_of_natDegree_le (minpoly.natDegree_le x)
+/-- If `x : L` is an integral element in a field extension `L` over `K`, then the degree of the
+ minimal polynomial of `x` over `K` divides `[L : K]`.-/
+theorem _root_.minpoly.degree_dvd {x : L} (hx : IsIntegral K x) :
+ (minpoly K x).natDegree ∣ finrank K L := by
+ rw [dvd_iff_exists_eq_mul_left, ← IntermediateField.adjoin.finrank hx]
+ use finrank K⟮x⟯ L
+ rw [mul_comm, finrank_mul_finrank]
+
-- TODO: generalize to `Sort`
/-- A compositum of algebraic extensions is algebraic -/
theorem isAlgebraic_iSup {ι : Type*} {t : ι → IntermediateField K L}
@@ -1156,12 +1217,12 @@ theorem card_algHom_adjoin_integral (h : IsIntegral F α) (h_sep : IsSeparable F
exact h_sep
-- Apparently `K⟮root f⟯ →+* K⟮root f⟯` is expensive to unify during instance synthesis.
-open FiniteDimensional AdjoinRoot in
+open Module AdjoinRoot in
/-- Let `f, g` be monic polynomials over `K`. If `f` is irreducible, and `g(x) - α` is irreducible
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 :=
@@ -1204,7 +1265,7 @@ theorem _root_.Polynomial.irreducible_comp {f g : K[X]} (hfm : f.Monic) (hgm : g
rw [← finrank_top', ← this, adjoin.finrank]
exact IsIntegral.of_finite _ _
· simp [← key₂]
- have := FiniteDimensional.finrank_mul_finrank K K⟮aeval (root p) g⟯ Kx
+ have := Module.finrank_mul_finrank K K⟮aeval (root p) g⟯ Kx
rwa [key₁', key₂', (AdjoinRoot.powerBasis hp₁.ne_zero).finrank, powerBasis_dim, eq_comm] at this
end AdjoinIntegralElement
@@ -1423,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 498e3b8d326c7..f054c960147ca 100644
--- a/Mathlib/FieldTheory/Cardinality.lean
+++ b/Mathlib/FieldTheory/Cardinality.lean
@@ -43,8 +43,8 @@ theorem Fintype.isPrimePow_card_of_field {α} [Fintype α] [Field α] : IsPrimeP
let b := IsNoetherian.finsetBasis (ZMod p) α
rw [Module.card_fintype b, ZMod.card, isPrimePow_pow_iff]
· exact hp.1.isPrimePow
- rw [← FiniteDimensional.finrank_eq_card_basis b]
- exact FiniteDimensional.finrank_pos.ne'
+ rw [← Module.finrank_eq_card_basis b]
+ exact Module.finrank_pos.ne'
/-- A `Fintype` can be given a field structure iff its cardinality is a prime power. -/
theorem Fintype.nonempty_field_iff {α} [Fintype α] : Nonempty (Field α) ↔ IsPrimePow ‖α‖ := by
@@ -59,21 +59,14 @@ 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
rw [Cardinal.isPrimePow_iff]
cases' fintypeOrInfinite α with h h
· simpa only [Cardinal.mk_fintype, Nat.cast_inj, exists_eq_left',
- (Cardinal.nat_lt_aleph0 _).not_le, false_or_iff] using Fintype.nonempty_field_iff
- · simpa only [← Cardinal.infinite_iff, h, true_or_iff, iff_true_iff] using Infinite.nonempty_field
+ (Cardinal.nat_lt_aleph0 _).not_le, false_or] using Fintype.nonempty_field_iff
+ · simpa only [← Cardinal.infinite_iff, h, true_or, iff_true] using Infinite.nonempty_field
diff --git a/Mathlib/FieldTheory/Differential/Basic.lean b/Mathlib/FieldTheory/Differential/Basic.lean
new file mode 100644
index 0000000000000..05c4742401057
--- /dev/null
+++ b/Mathlib/FieldTheory/Differential/Basic.lean
@@ -0,0 +1,92 @@
+/-
+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.Algebra.EuclideanDomain.Field
+import Mathlib.RingTheory.Derivation.DifferentialRing
+import Mathlib.RingTheory.LocalRing.Basic
+import Mathlib.Tactic.FieldSimp
+
+/-!
+# Differential Fields
+
+This file defines the logarithmic derivative `Differential.logDeriv` and proves properties of it.
+This is defined algebraically, compared to `logDeriv` which is analytical.
+-/
+
+namespace Differential
+
+open algebraMap
+
+variable {R : Type*} [Field R] [Differential R] (a b : R)
+
+/--
+The logarithmic derivative of a is a′ / a.
+-/
+def logDeriv : R := a′ / a
+
+@[simp]
+lemma logDeriv_zero : logDeriv (0 : R) = 0 := by
+ simp [logDeriv]
+
+@[simp]
+lemma logDeriv_one : logDeriv (1 : R) = 0 := by
+ simp [logDeriv]
+
+lemma logDeriv_mul (ha : a ≠ 0) (hb : b ≠ 0) : logDeriv (a * b) = logDeriv a + logDeriv b := by
+ unfold logDeriv
+ field_simp
+ ring
+
+lemma logDeriv_div (ha : a ≠ 0) (hb : b ≠ 0) : logDeriv (a / b) = logDeriv a - logDeriv b := by
+ unfold logDeriv
+ field_simp [Derivation.leibniz_div, smul_sub]
+ ring
+
+@[simp]
+lemma logDeriv_pow (n : ℕ) (a : R) : logDeriv (a ^ n) = n * logDeriv a := by
+ induction n with
+ | zero => simp
+ | succ n h2 =>
+ obtain rfl | hb := eq_or_ne a 0
+ · simp
+ · rw [Nat.cast_add, Nat.cast_one, add_mul, one_mul, ← h2, pow_succ, logDeriv_mul] <;>
+ simp [hb]
+
+lemma logDeriv_eq_zero : logDeriv a = 0 ↔ a′ = 0 :=
+ ⟨fun h ↦ by simp only [logDeriv, div_eq_zero_iff] at h; rcases h with h|h <;> simp [h],
+ fun h ↦ by unfold logDeriv at *; simp [h]⟩
+
+lemma logDeriv_multisetProd {ι : Type*} (s : Multiset ι) {f : ι → R} (h : ∀ x ∈ s, f x ≠ 0) :
+ logDeriv (s.map f).prod = (s.map fun x ↦ logDeriv (f x)).sum := by
+ induction s using Multiset.induction_on
+ · simp
+ · rename_i h₂
+ simp only [Function.comp_apply, Multiset.map_cons, Multiset.sum_cons, Multiset.prod_cons]
+ rw [← h₂]
+ · apply logDeriv_mul
+ · simp [h]
+ · simp_all
+ · simp_all
+
+lemma logDeriv_prod (ι : Type*) (s : Finset ι) (f : ι → R) (h : ∀ x ∈ s, f x ≠ 0) :
+ logDeriv (∏ x ∈ s, f x) = ∑ x ∈ s, logDeriv (f x) := logDeriv_multisetProd _ h
+
+lemma logDeriv_prod_of_eq_zero (ι : Type*) (s : Finset ι) (f : ι → R) (h : ∀ x ∈ s, f x = 0) :
+ logDeriv (∏ x ∈ s, f x) = ∑ x ∈ s, logDeriv (f x) := by
+ unfold logDeriv
+ simp_all
+
+lemma logDeriv_algebraMap {F K : Type*} [Field F] [Field K] [Differential F] [Differential K]
+ [Algebra F K] [DifferentialAlgebra F K]
+ (a : F) : logDeriv (algebraMap F K a) = algebraMap F K (logDeriv a) := by
+ unfold logDeriv
+ simp [deriv_algebraMap]
+
+@[norm_cast]
+lemma _root_.algebraMap.coe_logDeriv {F K : Type*} [Field F] [Field K] [Differential F]
+ [Differential K] [Algebra F K] [DifferentialAlgebra F K]
+ (a : F) : logDeriv a = logDeriv (a : K) := (logDeriv_algebraMap a).symm
+
+end Differential
diff --git a/Mathlib/FieldTheory/Finite/Basic.lean b/Mathlib/FieldTheory/Finite/Basic.lean
index a6f4ffff2c1aa..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]
@@ -293,7 +293,7 @@ theorem sum_pow_lt_card_sub_one (i : ℕ) (h : i < q - 1) : ∑ x : K, x ^ i = 0
let φ : Kˣ ↪ K := ⟨fun x ↦ x, Units.ext⟩
have : univ.map φ = univ \ {0} := by
ext x
- simpa only [mem_map, mem_univ, Function.Embedding.coeFn_mk, true_and_iff, mem_sdiff,
+ simpa only [mem_map, mem_univ, Function.Embedding.coeFn_mk, true_and, mem_sdiff,
mem_singleton, φ] using isUnit_iff_ne_zero
calc
∑ x : K, x ^ i = ∑ x ∈ univ \ {(0 : K)}, x ^ i := by
@@ -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
@@ -455,9 +453,9 @@ variable {V : Type*} [Fintype K] [DivisionRing K] [AddCommGroup V] [Module K V]
-- should this go in a namespace?
-- finite_dimensional would be natural,
-- but we don't assume it...
-theorem card_eq_pow_finrank [Fintype V] : Fintype.card V = q ^ FiniteDimensional.finrank K V := by
+theorem card_eq_pow_finrank [Fintype V] : Fintype.card V = q ^ Module.finrank K V := by
let b := IsNoetherian.finsetBasis K V
- rw [Module.card_fintype b, ← FiniteDimensional.finrank_eq_card_basis b]
+ rw [Module.card_fintype b, ← Module.finrank_eq_card_basis b]
end
diff --git a/Mathlib/FieldTheory/Finite/GaloisField.lean b/Mathlib/FieldTheory/Finite/GaloisField.lean
index baca752d4d5c6..e3868fc90d591 100644
--- a/Mathlib/FieldTheory/Finite/GaloisField.lean
+++ b/Mathlib/FieldTheory/Finite/GaloisField.lean
@@ -3,10 +3,10 @@ Copyright (c) 2021 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Aaron Anderson, Alex J. Best, Johan Commelin, Eric Rodriguez, Ruben Van de Velde
-/
+import Mathlib.Algebra.Algebra.ZMod
import Mathlib.Algebra.CharP.Algebra
-import Mathlib.Data.ZMod.Algebra
import Mathlib.FieldTheory.Finite.Basic
-import Mathlib.FieldTheory.Galois
+import Mathlib.FieldTheory.Galois.Basic
import Mathlib.FieldTheory.SplittingField.IsSplittingField
/-!
@@ -88,7 +88,7 @@ instance : Fintype (GaloisField p n) := by
dsimp only [GaloisField]
exact FiniteDimensional.fintypeOfFintype (ZMod p) (GaloisField p n)
-theorem finrank {n} (h : n ≠ 0) : FiniteDimensional.finrank (ZMod p) (GaloisField p n) = n := by
+theorem finrank {n} (h : n ≠ 0) : Module.finrank (ZMod p) (GaloisField p n) = n := by
set g_poly := (X ^ p ^ n - X : (ZMod p)[X])
have hp : 1 < p := h_prime.out.one_lt
have aux : g_poly ≠ 0 := FiniteField.X_pow_card_pow_sub_X_ne_zero _ h hp
@@ -114,7 +114,7 @@ theorem finrank {n} (h : n ≠ 0) : FiniteDimensional.finrank (ZMod p) (GaloisFi
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,19 +127,19 @@ theorem finrank {n} (h : n ≠ 0) : FiniteDimensional.finrank (ZMod p) (GaloisFi
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
let b := IsNoetherian.finsetBasis (ZMod p) (GaloisField p n)
- rw [Module.card_fintype b, ← FiniteDimensional.finrank_eq_card_basis b, ZMod.card, finrank p h]
+ rw [Module.card_fintype b, ← Module.finrank_eq_card_basis b, ZMod.card, finrank p h]
theorem splits_zmod_X_pow_sub_X : Splits (RingHom.id (ZMod p)) (X ^ p - X) := by
have hp : 1 < p := h_prime.out.one_lt
diff --git a/Mathlib/FieldTheory/Finite/Polynomial.lean b/Mathlib/FieldTheory/Finite/Polynomial.lean
index 8207de7d06c14..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
@@ -215,8 +209,8 @@ instance [Finite σ] : FiniteDimensional K (R σ K) := by
simpa only [rank_R] using Cardinal.nat_lt_aleph0 (Fintype.card (σ → K)))
open Classical in
-theorem finrank_R [Fintype σ] : FiniteDimensional.finrank K (R σ K) = Fintype.card (σ → K) :=
- FiniteDimensional.finrank_eq_of_rank_eq (rank_R σ K)
+theorem finrank_R [Fintype σ] : Module.finrank K (R σ K) = Fintype.card (σ → K) :=
+ Module.finrank_eq_of_rank_eq (rank_R σ K)
-- Porting note: was `(evalᵢ σ K).range`.
theorem range_evalᵢ [Finite σ] : range (evalᵢ σ K) = ⊤ := by
@@ -228,7 +222,7 @@ theorem ker_evalₗ [Finite σ] : ker (evalᵢ σ K) = ⊥ := by
cases nonempty_fintype σ
refine (ker_eq_bot_iff_range_eq_top_of_finrank_eq_finrank ?_).mpr (range_evalᵢ σ K)
classical
- rw [FiniteDimensional.finrank_fintype_fun_eq_card, finrank_R]
+ rw [Module.finrank_fintype_fun_eq_card, finrank_R]
theorem eq_zero_of_eval_eq_zero [Finite σ] (p : MvPolynomial σ K) (h : ∀ v : σ → K, eval v p = 0)
(hp : p ∈ restrictDegree σ K (Fintype.card K - 1)) : p = 0 :=
diff --git a/Mathlib/FieldTheory/Finiteness.lean b/Mathlib/FieldTheory/Finiteness.lean
index 6c2e5621a9272..d6cc69e04c7ae 100644
--- a/Mathlib/FieldTheory/Finiteness.lean
+++ b/Mathlib/FieldTheory/Finiteness.lean
@@ -72,7 +72,7 @@ theorem coeSort_finsetBasisIndex [IsNoetherian K V] :
/-- In a noetherian module over a division ring, there exists a finite basis.
This is indexed by the `Finset` `IsNoetherian.finsetBasisIndex`.
This is in contrast to the result `finite_basis_index (Basis.ofVectorSpace K V)`,
-which provides a set and a `Set.finite`.
+which provides a set and a `Set.Finite`.
-/
noncomputable def finsetBasis [IsNoetherian K V] : Basis (finsetBasisIndex K V) K V :=
(Basis.ofVectorSpace K V).reindex (by rw [coeSort_finsetBasisIndex])
diff --git a/Mathlib/FieldTheory/Fixed.lean b/Mathlib/FieldTheory/Fixed.lean
index bf86498f3027a..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
@@ -30,7 +30,7 @@ element of `G`, where `G` is a group that acts on `F`.
noncomputable section
-open MulAction Finset FiniteDimensional
+open MulAction Finset Module
universe u v w
@@ -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.lean b/Mathlib/FieldTheory/Galois/Basic.lean
similarity index 96%
rename from Mathlib/FieldTheory/Galois.lean
rename to Mathlib/FieldTheory/Galois/Basic.lean
index 259a8533aa662..3f571ef51fa06 100644
--- a/Mathlib/FieldTheory/Galois.lean
+++ b/Mathlib/FieldTheory/Galois/Basic.lean
@@ -24,7 +24,7 @@ In this file we define Galois extensions as extensions which are both separable
- `IntermediateField.fixingSubgroup_fixedField` : If `E/F` is finite dimensional (but not
necessarily Galois) then `fixingSubgroup (fixedField H) = H`
-- `IntermediateField.fixedField_fixingSubgroup`: If `E/F` is finite dimensional and Galois
+- `IsGalois.fixedField_fixingSubgroup`: If `E/F` is finite dimensional and Galois
then `fixedField (fixingSubgroup K) = K`
Together, these two results prove the Galois correspondence.
@@ -35,7 +35,7 @@ Together, these two results prove the Galois correspondence.
open scoped Polynomial IntermediateField
-open FiniteDimensional AlgEquiv
+open Module AlgEquiv
section
@@ -391,18 +391,12 @@ theorem tfae [FiniteDimensional F E] : List.TFAE [
IntermediateField.fixedField (⊤ : Subgroup (E ≃ₐ[F] E)) = ⊥,
Fintype.card (E ≃ₐ[F] E) = finrank F E,
∃ p : F[X], p.Separable ∧ p.IsSplittingField F E] := by
- tfae_have 1 → 2
- · exact fun h => OrderIso.map_bot (@intermediateFieldEquivSubgroup F _ E _ _ _ h).symm
- tfae_have 1 → 3
- · intro; exact card_aut_eq_finrank F E
- tfae_have 1 → 4
- · intro; exact is_separable_splitting_field F E
- tfae_have 2 → 1
- · exact of_fixedField_eq_bot F E
- tfae_have 3 → 1
- · exact of_card_aut_eq_finrank F E
- tfae_have 4 → 1
- · rintro ⟨h, hp1, _⟩; exact of_separable_splitting_field hp1
+ tfae_have 1 → 2 := fun h ↦ OrderIso.map_bot (@intermediateFieldEquivSubgroup F _ E _ _ _ h).symm
+ tfae_have 1 → 3 := fun _ ↦ card_aut_eq_finrank F E
+ tfae_have 1 → 4 := fun _ ↦ is_separable_splitting_field F E
+ tfae_have 2 → 1 := of_fixedField_eq_bot F E
+ tfae_have 3 → 1 := of_card_aut_eq_finrank F E
+ tfae_have 4 → 1 := fun ⟨h, hp1, _⟩ ↦ of_separable_splitting_field hp1
tfae_finish
end IsGalois
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 99eab922d6a3d..fadc8889330f0 100644
--- a/Mathlib/FieldTheory/IntermediateField/Algebraic.lean
+++ b/Mathlib/FieldTheory/IntermediateField/Algebraic.lean
@@ -13,22 +13,40 @@ import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition
# Results on finite dimensionality and algebraicity of intermediate fields.
-/
-open FiniteDimensional
+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)
-instance finiteDimensional_left [FiniteDimensional K L] : FiniteDimensional K F :=
- left K F L
-
-instance finiteDimensional_right [FiniteDimensional K L] : FiniteDimensional F L :=
- right K F L
+instance finiteDimensional_left [FiniteDimensional K L] : FiniteDimensional K F := .left K F L
+instance finiteDimensional_right [FiniteDimensional K L] : FiniteDimensional F L := .right K F L
@[simp]
theorem rank_eq_rank_subalgebra : Module.rank K F.toSubalgebra = Module.rank K F :=
@@ -89,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 27b94d1b6a535..d58f8dcbc128b 100644
--- a/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean
+++ b/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean
@@ -79,7 +79,7 @@ theorem spanEval_ne_top : spanEval k ≠ ⊤ := by
rw [map_one, Finsupp.linearCombination_apply, Finsupp.sum, map_sum, Finset.sum_eq_zero] at hv
· exact zero_ne_one hv
intro j hj
- rw [smul_eq_mul, map_mul, toSplittingField_evalXSelf (s := v.support) hj,
+ rw [smul_eq_mul, map_mul, toSplittingField_evalXSelf _ (s := v.support) hj,
mul_zero]
/-- A random maximal ideal that contains `spanEval k` -/
@@ -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) :
@@ -250,8 +241,7 @@ theorem Step.isIntegral (n) : ∀ z : Step k n, IsIntegral k z := by
apply @RingHom.IsIntegral.trans (Step k 0) (Step k a) (Step k (a + 1)) _ _ _
(toStepOfLE k 0 a (a.zero_le : 0 ≤ a)) (toStepSucc k a) _
· intro z
- have := AdjoinMonic.isIntegral (Step k a) (z : Step k (a + 1))
- convert this
+ convert AdjoinMonic.isIntegral (Step k a) (z : Step k (a + 1))
· convert h -- Porting note: This times out at 500000
instance toStepOfLE.directedSystem : DirectedSystem (Step k) fun i j h => toStepOfLE k i j h :=
@@ -405,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)))
@@ -413,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 1a9f0ce2972f9..99b41accb1cf2 100644
--- a/Mathlib/FieldTheory/IsAlgClosed/Classification.lean
+++ b/Mathlib/FieldTheory/IsAlgClosed/Classification.lean
@@ -3,9 +3,9 @@ Copyright (c) 2022 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes
-/
-import Mathlib.Algebra.Polynomial.Cardinal
+import Mathlib.Algebra.Algebra.ZMod
import Mathlib.Algebra.MvPolynomial.Cardinal
-import Mathlib.Data.ZMod.Algebra
+import Mathlib.Algebra.Polynomial.Cardinal
import Mathlib.FieldTheory.IsAlgClosed.Basic
import Mathlib.RingTheory.AlgebraicIndependent
@@ -48,13 +48,13 @@ 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
simp? at h says simp only [Set.coe_setOf, ne_eq, Set.mem_setOf_eq, Sigma.mk.inj_iff] at h
refine (Subtype.heq_iff_coe_eq ?_).1 h.2
- simp only [h.1, iff_self_iff, forall_true_iff]
+ simp only [h.1, forall_true_iff]
/-- The cardinality of an algebraic extension is at most the maximum of the cardinality
of the base ring or `ℵ₀` -/
@@ -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 70d3708472eb5..5c6d7928dc1a4 100644
--- a/Mathlib/FieldTheory/IsPerfectClosure.lean
+++ b/Mathlib/FieldTheory/IsPerfectClosure.lean
@@ -60,7 +60,7 @@ perfect ring, perfect closure, purely inseparable
-/
-open FiniteDimensional Polynomial IntermediateField Field
+open Module Polynomial IntermediateField Field
noncomputable section
@@ -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 a986c4144c374..d7d9c870dda5a 100644
--- a/Mathlib/FieldTheory/IsSepClosed.lean
+++ b/Mathlib/FieldTheory/IsSepClosed.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jz Pan
-/
import Mathlib.FieldTheory.IsAlgClosed.AlgebraicClosure
-import Mathlib.FieldTheory.Galois
+import Mathlib.FieldTheory.Galois.Basic
/-!
# Separably Closed Field
@@ -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 18d9b02736673..c5751d36c7ff4 100644
--- a/Mathlib/FieldTheory/KrullTopology.lean
+++ b/Mathlib/FieldTheory/KrullTopology.lean
@@ -3,7 +3,7 @@ Copyright (c) 2022 Sebastian Monnet. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sebastian Monnet
-/
-import Mathlib.FieldTheory.Galois
+import Mathlib.FieldTheory.Galois.Basic
import Mathlib.Topology.Algebra.FilterBasis
import Mathlib.Topology.Algebra.OpenSubgroup
import Mathlib.Tactic.ByContra
@@ -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 65eb3d88e45c4..095253e93171d 100644
--- a/Mathlib/FieldTheory/KummerExtension.lean
+++ b/Mathlib/FieldTheory/KummerExtension.lean
@@ -5,7 +5,7 @@ Authors: Andrew Yang
-/
import Mathlib.RingTheory.RootsOfUnity.Basic
import Mathlib.RingTheory.AdjoinRoot
-import Mathlib.FieldTheory.Galois
+import Mathlib.FieldTheory.Galois.Basic
import Mathlib.LinearAlgebra.Eigenspace.Minpoly
import Mathlib.RingTheory.Norm.Basic
/-!
@@ -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
@@ -272,6 +272,11 @@ theorem Polynomial.separable_X_pow_sub_C_of_irreducible : (X ^ n - C a).Separabl
AdjoinRoot.algebraMap_eq,
X_pow_sub_C_eq_prod (hζ.map_of_injective (algebraMap K _).injective) hn
(root_X_pow_sub_C_pow n a), separable_prod_X_sub_C_iff']
+ #adaptation_note
+ /--
+ After https://github.com/leanprover/lean4/pull/5376 we need to provide this helper instance.
+ -/
+ have : MonoidHomClass (K →+* K[n√a]) K K[n√a] := inferInstance
exact (hζ.map_of_injective (algebraMap K K[n√a]).injective).injOn_pow_mul
(root_X_pow_sub_C_ne_zero (lt_of_le_of_ne (show 1 ≤ n from hn) (Ne.symm hn')) _)
@@ -364,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
@@ -375,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
@@ -530,7 +534,7 @@ lemma isGalois_of_isSplittingField_X_pow_sub_C : IsGalois K L :=
IsGalois.of_separable_splitting_field (separable_X_pow_sub_C_of_irreducible hζ a H)
include hζ H in
-lemma finrank_of_isSplittingField_X_pow_sub_C : FiniteDimensional.finrank K L = n := by
+lemma finrank_of_isSplittingField_X_pow_sub_C : Module.finrank K L = n := by
have := Polynomial.IsSplittingField.finiteDimensional L (X ^ n - C a)
have := isGalois_of_isSplittingField_X_pow_sub_C hζ H L
have hn := Nat.pos_iff_ne_zero.mpr (ne_zero_of_irreducible_X_pow_sub_C H)
@@ -545,9 +549,9 @@ end IsSplittingField
section IsCyclic
variable {L} [Field L] [Algebra K L] [FiniteDimensional K L]
-variable (hK : (primitiveRoots (FiniteDimensional.finrank K L) K).Nonempty)
+variable (hK : (primitiveRoots (Module.finrank K L) K).Nonempty)
-open FiniteDimensional
+open Module
variable (K L)
include hK in
@@ -623,7 +627,7 @@ lemma isSplittingField_X_pow_sub_C_of_root_adjoin_eq_top
end IsCyclic
-open FiniteDimensional in
+open Module in
/--
Suppose `L/K` is a finite extension of dimension `n`, and `K` contains all `n`-th roots of unity.
Then `L/K` is cyclic iff
@@ -631,21 +635,18 @@ Then `L/K` is cyclic iff
`L = K[α]` for some `αⁿ ∈ K`.
-/
lemma isCyclic_tfae (K L) [Field K] [Field L] [Algebra K L] [FiniteDimensional K L]
- (hK : (primitiveRoots (FiniteDimensional.finrank K L) K).Nonempty) :
+ (hK : (primitiveRoots (Module.finrank K L) K).Nonempty) :
List.TFAE [
IsGalois K L ∧ IsCyclic (L ≃ₐ[K] L),
∃ a : K, Irreducible (X ^ (finrank K L) - C a) ∧
IsSplittingField K L (X ^ (finrank K L) - C a),
∃ (α : L), α ^ (finrank K L) ∈ Set.range (algebraMap K L) ∧ K⟮α⟯ = ⊤] := by
tfae_have 1 → 3
- · intro ⟨inst₁, inst₂⟩
- exact exists_root_adjoin_eq_top_of_isCyclic K L hK
+ | ⟨inst₁, inst₂⟩ => exists_root_adjoin_eq_top_of_isCyclic K L hK
tfae_have 3 → 2
- · intro ⟨α, ⟨a, ha⟩, hα⟩
- exact ⟨a, irreducible_X_pow_sub_C_of_root_adjoin_eq_top ha.symm hα,
+ | ⟨α, ⟨a, ha⟩, hα⟩ => ⟨a, irreducible_X_pow_sub_C_of_root_adjoin_eq_top ha.symm hα,
isSplittingField_X_pow_sub_C_of_root_adjoin_eq_top hK ha.symm hα⟩
tfae_have 2 → 1
- · intro ⟨a, H, inst⟩
- exact ⟨isGalois_of_isSplittingField_X_pow_sub_C hK H L,
+ | ⟨a, H, inst⟩ => ⟨isGalois_of_isSplittingField_X_pow_sub_C hK H L,
isCyclic_of_isSplittingField_X_pow_sub_C hK H L⟩
tfae_finish
diff --git a/Mathlib/FieldTheory/Minpoly/Basic.lean b/Mathlib/FieldTheory/Minpoly/Basic.lean
index bff61c9cc012d..356b47cef750e 100644
--- a/Mathlib/FieldTheory/Minpoly/Basic.lean
+++ b/Mathlib/FieldTheory/Minpoly/Basic.lean
@@ -58,10 +58,13 @@ 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
- refine dif_ctx_congr (isIntegral_algHom_iff _ hf) (fun _ => ?_) fun _ => rfl
- simp_rw [← Polynomial.aeval_def, aeval_algHom, AlgHom.comp_apply, _root_.map_eq_zero_iff f hf]
+ simp_rw [minpoly, isIntegral_algHom_iff _ hf, ← Polynomial.aeval_def, aeval_algHom,
+ AlgHom.comp_apply, _root_.map_eq_zero_iff f hf]
theorem algebraMap_eq {B} [CommRing B] [Algebra A B] [Algebra B B'] [IsScalarTower A B B']
(h : Function.Injective (algebraMap B B')) (x : B) :
diff --git a/Mathlib/FieldTheory/Minpoly/Field.lean b/Mathlib/FieldTheory/Minpoly/Field.lean
index 32d3a549998d0..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 ?_
@@ -127,22 +127,47 @@ theorem eq_of_irreducible [Nontrivial B] {p : A[X]} (hp1 : Irreducible p)
· rw [aeval_mul, hp2, zero_mul]
· rwa [Polynomial.Monic, leadingCoeff_mul, leadingCoeff_C, mul_inv_cancel₀]
-theorem add_algebraMap {B : Type*} [CommRing B] [Algebra A B] {x : B} (hx : IsIntegral A x)
+theorem add_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
- refine (minpoly.unique _ _ ((minpoly.monic hx).comp_X_sub_C _) ?_ fun q qmo hq => ?_).symm
- · simp [aeval_comp]
- · have : (Polynomial.aeval x) (q.comp (X + C a)) = 0 := by simpa [aeval_comp] using hq
- have H := minpoly.min A x (qmo.comp_X_add_C _) this
- rw [degree_eq_natDegree qmo.ne_zero,
- degree_eq_natDegree ((minpoly.monic hx).comp_X_sub_C _).ne_zero, natDegree_comp,
- natDegree_X_sub_C, mul_one]
- rwa [degree_eq_natDegree (minpoly.ne_zero hx),
- degree_eq_natDegree (qmo.comp_X_add_C _).ne_zero, natDegree_comp,
- natDegree_X_add_C, mul_one] at H
-
-theorem sub_algebraMap {B : Type*} [CommRing B] [Algebra A B] {x : B} (hx : IsIntegral A x)
+ by_cases hx : IsIntegral A x
+ · refine (minpoly.unique _ _ ((minpoly.monic hx).comp_X_sub_C _) ?_ fun q qmo hq => ?_).symm
+ · simp [aeval_comp]
+ · have : (Polynomial.aeval x) (q.comp (X + C a)) = 0 := by simpa [aeval_comp] using hq
+ have H := minpoly.min A x (qmo.comp_X_add_C _) this
+ rw [degree_eq_natDegree qmo.ne_zero,
+ degree_eq_natDegree ((minpoly.monic hx).comp_X_sub_C _).ne_zero, natDegree_comp,
+ natDegree_X_sub_C, mul_one]
+ rwa [degree_eq_natDegree (minpoly.ne_zero hx),
+ degree_eq_natDegree (qmo.comp_X_add_C _).ne_zero, natDegree_comp,
+ natDegree_X_add_C, mul_one] at H
+ · rw [minpoly.eq_zero hx, minpoly.eq_zero, zero_comp]
+ 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)
(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 hx (-a)
+ simpa [sub_eq_add_neg] using add_algebraMap x (-a)
+
+theorem neg {B : Type*} [CommRing B] [Algebra A B] (x : B) :
+ minpoly A (- x) = (-1) ^ (natDegree (minpoly A x)) * (minpoly A x).comp (- X) := by
+ by_cases hx : IsIntegral A x
+ · refine (minpoly.unique _ _ ((minpoly.monic hx).neg_one_pow_natDegree_mul_comp_neg_X)
+ ?_ fun q qmo hq => ?_).symm
+ · simp [aeval_comp]
+ · have : (Polynomial.aeval x) ((-1) ^ q.natDegree * q.comp (- X)) = 0 := by
+ simpa [aeval_comp] using hq
+ have H := minpoly.min A x qmo.neg_one_pow_natDegree_mul_comp_neg_X this
+ have n1 := ((minpoly.monic hx).neg_one_pow_natDegree_mul_comp_neg_X).ne_zero
+ have n2 := qmo.neg_one_pow_natDegree_mul_comp_neg_X.ne_zero
+ rw [degree_eq_natDegree qmo.ne_zero,
+ degree_eq_natDegree n1, natDegree_mul (by simp) (right_ne_zero_of_mul n1), natDegree_comp]
+ rw [degree_eq_natDegree (minpoly.ne_zero hx),
+ degree_eq_natDegree qmo.neg_one_pow_natDegree_mul_comp_neg_X.ne_zero,
+ natDegree_mul (by simp) (right_ne_zero_of_mul n2), natDegree_comp] at H
+ simpa using H
+ · rw [minpoly.eq_zero hx, minpoly.eq_zero, zero_comp]
+ · simp only [natDegree_zero, pow_zero, mul_zero]
+ · exact IsIntegral.neg_iff.not.mpr hx
section AlgHomFintype
@@ -154,11 +179,9 @@ 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 (FiniteDimensional.finBasis F E : _ → E)) :
+ (x : range (Module.finBasis F E : _ → E)) :
{ l : K // l ∈ (minpoly F x.1).aroots K } :=
⟨φ x, by
rw [mem_roots_map (minpoly.ne_zero_of_finite F x.val),
@@ -169,14 +192,14 @@ theorem aux_inj_roots_of_min_poly : Injective (rootsOfMinPolyPiType F E K) := by
-- needs explicit coercion on the RHS
suffices (f : E →ₗ[F] K) = (g : E →ₗ[F] K) by rwa [DFunLike.ext'_iff] at this ⊢
rw [funext_iff] at h
- exact LinearMap.ext_on (FiniteDimensional.finBasis F E).span_eq fun e he =>
+ exact LinearMap.ext_on (Module.finBasis F E).span_eq fun e he =>
Subtype.ext_iff.mp (h ⟨e, he⟩)
/-- Given field extensions `E/F` and `K/F`, with `E/F` finite, there are finitely many `F`-algebra
homomorphisms `E →ₐ[K] K`. -/
noncomputable instance AlgHom.fintype : Fintype (E →ₐ[F] K) :=
@Fintype.ofInjective _ _
- (Fintype.subtypeProd (finite_range (FiniteDimensional.finBasis F E)) fun e =>
+ (Fintype.subtypeProd (finite_range (Module.finBasis F E)) fun e =>
(minpoly F e).aroots K)
_ (aux_inj_roots_of_min_poly F E K)
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/Minpoly/IsIntegrallyClosed.lean b/Mathlib/FieldTheory/Minpoly/IsIntegrallyClosed.lean
index 5abd2d46ef12c..3db3147d29b05 100644
--- a/Mathlib/FieldTheory/Minpoly/IsIntegrallyClosed.lean
+++ b/Mathlib/FieldTheory/Minpoly/IsIntegrallyClosed.lean
@@ -186,4 +186,24 @@ theorem _root_.PowerBasis.ofGenMemAdjoin'_gen (B : PowerBasis R S) (hint : IsInt
end AdjoinRoot
+section Subring
+
+variable {K L : Type*} [Field K] [Field L] [Algebra K L]
+
+variable (A : Subring K) [IsIntegrallyClosed A] [IsFractionRing A K]
+
+-- Implementation note: `inferInstance` does not work for these.
+instance : Algebra A (integralClosure A L) := Subalgebra.algebra (integralClosure A L)
+instance : SMul A (integralClosure A L) := Algebra.toSMul
+instance : IsScalarTower A ((integralClosure A L)) L :=
+ IsScalarTower.subalgebra' A L L (integralClosure A L)
+
+/-- The minimal polynomial of `x : L` over `K` agrees with its minimal polynomial over the
+integrally closed subring `A`. -/
+theorem ofSubring (x : integralClosure A L) :
+ Polynomial.map (algebraMap A K) (minpoly A x) = minpoly K (x : L) :=
+ eq_comm.mpr (isIntegrallyClosed_eq_field_fractions K L (IsIntegralClosure.isIntegral A L x))
+
+end Subring
+
end minpoly
diff --git a/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean b/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean
index c327e135c3ddd..fae1bec1703c0 100644
--- a/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean
+++ b/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean
@@ -20,7 +20,7 @@ See `traceForm_dualBasis_powerBasis_eq`.
- `span_coeff_minpolyDiv`: The coefficients of `minpolyDiv` spans `R`.
-/
-open Polynomial FiniteDimensional
+open Polynomial Module
variable (R K) {L S} [CommRing R] [Field K] [Field L] [CommRing S] [Algebra R S] [Algebra K L]
variable (x : S)
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/PolynomialGaloisGroup.lean b/Mathlib/FieldTheory/PolynomialGaloisGroup.lean
index 159fca2636398..ef2d383b8d52b 100644
--- a/Mathlib/FieldTheory/PolynomialGaloisGroup.lean
+++ b/Mathlib/FieldTheory/PolynomialGaloisGroup.lean
@@ -3,7 +3,7 @@ Copyright (c) 2020 Thomas Browning, Patrick Lutz. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Thomas Browning, Patrick Lutz
-/
-import Mathlib.FieldTheory.Galois
+import Mathlib.FieldTheory.Galois.Basic
/-!
# Galois Groups of Polynomials
@@ -41,7 +41,7 @@ noncomputable section
open scoped Polynomial
-open FiniteDimensional
+open Module
namespace Polynomial
@@ -384,10 +384,10 @@ theorem prime_degree_dvd_card [CharZero F] (p_irr : Irreducible p) (p_deg : p.na
let α : p.SplittingField :=
rootOfSplits (algebraMap F p.SplittingField) (SplittingField.splits p) hp
have hα : IsIntegral F α := .of_finite F α
- use FiniteDimensional.finrank F⟮α⟯ p.SplittingField
+ use Module.finrank F⟮α⟯ p.SplittingField
suffices (minpoly F α).natDegree = p.natDegree by
letI _ : AddCommGroup F⟮α⟯ := Ring.toAddCommGroup
- rw [← FiniteDimensional.finrank_mul_finrank F F⟮α⟯ p.SplittingField,
+ rw [← Module.finrank_mul_finrank F F⟮α⟯ p.SplittingField,
IntermediateField.adjoin.finrank hα, this]
suffices minpoly F α ∣ p by
have key := (minpoly.irreducible hα).dvd_symm p_irr this
diff --git a/Mathlib/FieldTheory/PrimitiveElement.lean b/Mathlib/FieldTheory/PrimitiveElement.lean
index 65b6d1707f19d..09b73357bf4f2 100644
--- a/Mathlib/FieldTheory/PrimitiveElement.lean
+++ b/Mathlib/FieldTheory/PrimitiveElement.lean
@@ -36,7 +36,7 @@ exists_adjoin_simple_eq_top
noncomputable section
-open FiniteDimensional Polynomial IntermediateField
+open Module Polynomial IntermediateField
namespace Field
@@ -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 := finite_of_finite F E
+ haveI : Finite E := Module.finite_of_finite F
exists_primitive_element_of_finite_top F E
end PrimitiveElementFinite
@@ -367,7 +367,7 @@ section iff
namespace Field
-open FiniteDimensional IntermediateField Polynomial Algebra Set
+open Module IntermediateField Polynomial Algebra Set
variable (F : Type*) {E : Type*} [Field F] [Field E] [Algebra F E] [FiniteDimensional F E]
diff --git a/Mathlib/FieldTheory/PurelyInseparable.lean b/Mathlib/FieldTheory/PurelyInseparable.lean
index a4608eb8e72f9..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
/-!
@@ -127,19 +128,22 @@ separable degree, degree, separable closure, purely inseparable
-/
-open FiniteDimensional Polynomial IntermediateField Field Finsupp
+open Module Polynomial IntermediateField Field Finsupp
noncomputable section
universe u v w
-variable (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E]
-variable (K : Type w) [Field K] [Algebra F K]
-
section IsPurelyInseparable
+variable (F : Type u) (E : Type v) [CommRing F] [Ring E] [Algebra F E]
+variable (K : Type w) [Ring K] [Algebra F K]
+
/-- Typeclass for purely inseparable field extensions: an algebraic extension `E / F` is purely
-inseparable if and only if the minimal polynomial of every element of `E ∖ F` is not separable. -/
+inseparable if and only if the minimal polynomial of every element of `E ∖ F` is not separable.
+
+We define this for general (commutative) rings and only assume `F` and `E` are fields
+if this is needed for a proof. -/
class IsPurelyInseparable : Prop where
isIntegral : Algebra.IsIntegral F E
inseparable' (x : E) : IsSeparable F x → x ∈ (algebraMap F E).range
@@ -150,7 +154,7 @@ variable {E} in
theorem IsPurelyInseparable.isIntegral' [IsPurelyInseparable F E] (x : E) : IsIntegral F x :=
Algebra.IsIntegral.isIntegral _
-theorem IsPurelyInseparable.isAlgebraic [IsPurelyInseparable F E] :
+theorem IsPurelyInseparable.isAlgebraic [Nontrivial F] [IsPurelyInseparable F E] :
Algebra.IsAlgebraic F E := inferInstance
variable {E}
@@ -163,7 +167,7 @@ variable {F K}
theorem isPurelyInseparable_iff : IsPurelyInseparable F E ↔ ∀ x : E,
IsIntegral F x ∧ (IsSeparable F x → x ∈ (algebraMap F E).range) :=
- ⟨fun h x ↦ ⟨h.isIntegral' x, h.inseparable' x⟩, fun h ↦ ⟨⟨fun x ↦ (h x).1⟩, fun x ↦ (h x).2⟩⟩
+ ⟨fun h x ↦ ⟨h.isIntegral' _ x, h.inseparable' x⟩, fun h ↦ ⟨⟨fun x ↦ (h x).1⟩, fun x ↦ (h x).2⟩⟩
/-- Transfer `IsPurelyInseparable` across an `AlgEquiv`. -/
theorem AlgEquiv.isPurelyInseparable (e : K ≃ₐ[F] E) [IsPurelyInseparable F K] :
@@ -179,7 +183,9 @@ theorem AlgEquiv.isPurelyInseparable_iff (e : K ≃ₐ[F] E) :
/-- If `E / F` is an algebraic extension, `F` is separably closed,
then `E / F` is purely inseparable. -/
-theorem Algebra.IsAlgebraic.isPurelyInseparable_of_isSepClosed [Algebra.IsAlgebraic F E]
+theorem Algebra.IsAlgebraic.isPurelyInseparable_of_isSepClosed
+ {F : Type u} {E : Type v} [Field F] [Ring E] [IsDomain E] [Algebra F E]
+ [Algebra.IsAlgebraic F E]
[IsSepClosed F] : IsPurelyInseparable F E :=
⟨inferInstance, fun x h ↦ minpoly.mem_range_of_degree_eq_one F x <|
IsSepClosed.degree_eq_one_of_irreducible F (minpoly.irreducible
@@ -194,27 +200,37 @@ theorem IsPurelyInseparable.surjective_algebraMap_of_isSeparable
/-- If `E / F` is both purely inseparable and separable, then `algebraMap F E` is bijective. -/
theorem IsPurelyInseparable.bijective_algebraMap_of_isSeparable
+ [Nontrivial E] [NoZeroSMulDivisors F E]
[IsPurelyInseparable F E] [Algebra.IsSeparable F E] : Function.Bijective (algebraMap F E) :=
- ⟨(algebraMap F E).injective, surjective_algebraMap_of_isSeparable F E⟩
+ ⟨NoZeroSMulDivisors.algebraMap_injective F E, surjective_algebraMap_of_isSeparable F E⟩
variable {F E} in
+/-- If a subalgebra of `E / F` is both purely inseparable and separable, then it is equal
+to `F`. -/
+theorem Subalgebra.eq_bot_of_isPurelyInseparable_of_isSeparable (L : Subalgebra F E)
+ [IsPurelyInseparable F L] [Algebra.IsSeparable F L] : L = ⊥ := bot_unique fun x hx ↦ by
+ obtain ⟨y, hy⟩ := IsPurelyInseparable.surjective_algebraMap_of_isSeparable F L ⟨x, hx⟩
+ exact ⟨y, congr_arg (Subalgebra.val _) hy⟩
+
/-- If an intermediate field of `E / F` is both purely inseparable and separable, then it is equal
to `F`. -/
-theorem IntermediateField.eq_bot_of_isPurelyInseparable_of_isSeparable (L : IntermediateField F E)
+theorem IntermediateField.eq_bot_of_isPurelyInseparable_of_isSeparable
+ {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] (L : IntermediateField F E)
[IsPurelyInseparable F L] [Algebra.IsSeparable F L] : L = ⊥ := bot_unique fun x hx ↦ by
obtain ⟨y, hy⟩ := IsPurelyInseparable.surjective_algebraMap_of_isSeparable F L ⟨x, hx⟩
exact ⟨y, congr_arg (algebraMap L E) hy⟩
/-- If `E / F` is purely inseparable, then the separable closure of `F` in `E` is
equal to `F`. -/
-theorem separableClosure.eq_bot_of_isPurelyInseparable [IsPurelyInseparable F E] :
+theorem separableClosure.eq_bot_of_isPurelyInseparable
+ (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] [IsPurelyInseparable F E] :
separableClosure F E = ⊥ :=
bot_unique fun x h ↦ IsPurelyInseparable.inseparable F x (mem_separableClosure_iff.1 h)
-variable {F E} in
/-- If `E / F` is an algebraic extension, then the separable closure of `F` in `E` is
equal to `F` if and only if `E / F` is purely inseparable. -/
-theorem separableClosure.eq_bot_iff [Algebra.IsAlgebraic F E] :
+theorem separableClosure.eq_bot_iff
+ {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] [Algebra.IsAlgebraic F E] :
separableClosure F E = ⊥ ↔ IsPurelyInseparable F E :=
⟨fun h ↦ isPurelyInseparable_iff.2 fun x ↦ ⟨Algebra.IsIntegral.isIntegral x, fun hs ↦ by
simpa only [h] using mem_separableClosure_iff.2 hs⟩, fun _ ↦ eq_bot_of_isPurelyInseparable F E⟩
@@ -222,12 +238,15 @@ theorem separableClosure.eq_bot_iff [Algebra.IsAlgebraic F E] :
instance isPurelyInseparable_self : IsPurelyInseparable F F :=
⟨inferInstance, fun x _ ↦ ⟨x, rfl⟩⟩
-variable {E}
+section
+
+variable (F : Type u) {E : Type v} [Field F] [Ring E] [IsDomain E] [Algebra F E]
+variable (q : ℕ) [ExpChar F q] (x : E)
/-- A field extension `E / F` of exponential characteristic `q` is purely inseparable
if and only if for every element `x` of `E`, there exists a natural number `n` such that
`x ^ (q ^ n)` is contained in `F`. -/
-theorem isPurelyInseparable_iff_pow_mem (q : ℕ) [ExpChar F q] :
+theorem isPurelyInseparable_iff_pow_mem :
IsPurelyInseparable F E ↔ ∀ x : E, ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by
rw [isPurelyInseparable_iff]
refine ⟨fun h x ↦ ?_, fun h x ↦ ?_⟩
@@ -238,16 +257,19 @@ theorem isPurelyInseparable_iff_pow_mem (q : ℕ) [ExpChar F q] :
have halg : IsIntegral F x := by_contra fun h' ↦ by
simp only [minpoly.eq_zero h', natSepDegree_zero, zero_ne_one] at hdeg
refine ⟨halg, fun hsep ↦ ?_⟩
- rw [hsep.natSepDegree_eq_natDegree, ← adjoin.finrank halg,
- IntermediateField.finrank_eq_one_iff] at hdeg
- simpa only [hdeg] using mem_adjoin_simple_self F x
+ rwa [hsep.natSepDegree_eq_natDegree, minpoly.natDegree_eq_one_iff] at hdeg
-theorem IsPurelyInseparable.pow_mem (q : ℕ) [ExpChar F q] [IsPurelyInseparable F E] (x : E) :
+theorem IsPurelyInseparable.pow_mem [IsPurelyInseparable F E] :
∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range :=
(isPurelyInseparable_iff_pow_mem F q).1 ‹_› x
+end
+
end IsPurelyInseparable
+variable (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E]
+variable (K : Type w) [Field K] [Algebra F K]
+
section perfectClosure
/-- The relative perfect closure of `F` in `E`, consists of the elements `x` of `E` such that there
@@ -434,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`,
@@ -583,7 +617,7 @@ if `E` is purely inseparable over it. -/
theorem separableClosure_le (L : IntermediateField F E)
[h : IsPurelyInseparable L E] : separableClosure F E ≤ L := fun x hx ↦ by
obtain ⟨y, rfl⟩ := h.inseparable' _ <|
- IsSeparable.of_isScalarTower L (mem_separableClosure_iff.1 hx)
+ IsSeparable.tower_top L (mem_separableClosure_iff.1 hx)
exact y.2
/-- If `E / F` is algebraic, then an intermediate field of `E / F` contains the
@@ -646,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)
@@ -735,7 +769,7 @@ private theorem LinearIndependent.map_pow_expChar_pow_of_fd_isSeparable
have h' := h.coe_range
let ι' := h'.extend (Set.range v).subset_univ
let b : Basis ι' F E := Basis.extend h'
- letI : Fintype ι' := fintypeBasisIndex b
+ letI : Fintype ι' := FiniteDimensional.fintypeBasisIndex b
have H := linearIndependent_of_top_le_span_of_card_eq_finrank
(span_map_pow_expChar_pow_eq_top_of_isSeparable q n b.span_eq).ge
(finrank_eq_card_basis b).symm
@@ -790,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
@@ -824,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
@@ -1050,7 +1084,7 @@ theorem minpoly.map_eq_of_isSeparable_of_isPurelyInseparable (x : K)
have hi' : IsIntegral E x := IsIntegral.tower_top hi
refine eq_of_monic_of_dvd_of_natDegree_le (monic hi') ((monic hi).map (algebraMap F E))
(dvd_map_of_isScalarTower F E x) (le_of_eq ?_)
- have hsep' := IsSeparable.of_isScalarTower E hsep
+ have hsep' := IsSeparable.tower_top E hsep
haveI := (isSeparable_adjoin_simple_iff_isSeparable _ _).2 hsep
haveI := (isSeparable_adjoin_simple_iff_isSeparable _ _).2 hsep'
have := Algebra.IsSeparable.isAlgebraic F F⟮x⟯
diff --git a/Mathlib/FieldTheory/RatFunc/AsPolynomial.lean b/Mathlib/FieldTheory/RatFunc/AsPolynomial.lean
index 12d1f729cadc0..14a02db0ca588 100644
--- a/Mathlib/FieldTheory/RatFunc/AsPolynomial.lean
+++ b/Mathlib/FieldTheory/RatFunc/AsPolynomial.lean
@@ -213,7 +213,7 @@ end Polynomial
namespace RatFunc
-open scoped DiscreteValuation
+open scoped Multiplicative
open Polynomial
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 fddc5fbc1dcee..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
/-!
@@ -22,7 +23,7 @@ properties about separable polynomials here.
* `IsSeparable K x`: an element `x` is separable over `K` iff the minimal polynomial of `x`
over `K` is separable.
* `Algebra.IsSeparable K L`: `L` is separable over `K` iff every element in `L` is separable
-over `K`
+over `K`.
-/
@@ -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`. -/
@@ -503,7 +525,7 @@ open Polynomial
section CommRing
-variable (F K : Type*) [CommRing F] [Ring K] [Algebra F K]
+variable (F L K : Type*) [CommRing F] [Ring K] [Algebra F K]
-- TODO: refactor to allow transcendental extensions?
-- See: https://en.wikipedia.org/wiki/Separable_extension#Separability_of_transcendental_extensions
@@ -514,7 +536,7 @@ variable (F K : Type*) [CommRing F] [Ring K] [Algebra F K]
variable {K} in
/--
An element `x` of an algebra `K` over a commutative ring `F` is said to be *separable*, if its
-minimal polynamial over `K` is separable. Note that the minimal polynomial of any element not
+minimal polynomial over `K` is separable. Note that the minimal polynomial of any element not
integral over `F` is defined to be `0`, which is not a separable polynomial.
-/
def IsSeparable (x : K) : Prop := Polynomial.Separable (minpoly F x)
@@ -547,6 +569,11 @@ theorem IsSeparable.isIntegral {x : K} (h : IsSeparable F x) : IsIntegral F x :=
theorem Algebra.IsSeparable.isIntegral [Algebra.IsSeparable F K] : ∀ x : K, IsIntegral F x :=
fun x ↦ _root_.IsSeparable.isIntegral (Algebra.IsSeparable.isSeparable F x)
+variable (K) in
+instance Algebra.IsSeparable.isAlgebraic [Nontrivial F] [Algebra.IsSeparable F K] :
+ Algebra.IsAlgebraic F K :=
+ ⟨fun x ↦ (Algebra.IsSeparable.isIntegral F x).isAlgebraic⟩
+
variable {F}
theorem Algebra.isSeparable_iff :
@@ -554,84 +581,165 @@ theorem Algebra.isSeparable_iff :
⟨fun _ x => ⟨Algebra.IsSeparable.isIntegral F x, Algebra.IsSeparable.isSeparable F x⟩,
fun h => ⟨fun x => (h x).2⟩⟩
-variable {E : Type*} [Ring E] [Algebra F E] (e : K ≃ₐ[F] E)
+variable {E : Type*}
+
+section AlgEquiv
+
+variable [Ring E] [Algebra F E] (e : K ≃ₐ[F] E)
include e
+/-- Transfer `IsSeparable` across an `AlgEquiv`. -/
+theorem AlgEquiv.isSeparable_iff {x : K} : IsSeparable F (e x) ↔ IsSeparable F x := by
+ simp only [IsSeparable, minpoly.algEquiv_eq e x]
+
/-- Transfer `Algebra.IsSeparable` across an `AlgEquiv`. -/
-theorem AlgEquiv.isSeparable [Algebra.IsSeparable F K] : Algebra.IsSeparable F E :=
- ⟨fun _ ↦
- by rw [IsSeparable, ← minpoly.algEquiv_eq e.symm]; exact Algebra.IsSeparable.isSeparable F _⟩
+theorem AlgEquiv.Algebra.isSeparable [Algebra.IsSeparable F K] : Algebra.IsSeparable F E :=
+ ⟨fun _ ↦ e.symm.isSeparable_iff.mp (Algebra.IsSeparable.isSeparable _ _)⟩
-theorem AlgEquiv.isSeparable_iff : Algebra.IsSeparable F K ↔ Algebra.IsSeparable F E :=
- ⟨fun _ ↦ e.isSeparable, fun _ ↦ e.symm.isSeparable⟩
+@[deprecated (since := "2024-08-06")]
+alias AlgEquiv.isSeparable := AlgEquiv.Algebra.isSeparable
-variable (F K)
+theorem AlgEquiv.Algebra.isSeparable_iff : Algebra.IsSeparable F K ↔ Algebra.IsSeparable F E :=
+ ⟨fun _ ↦ AlgEquiv.Algebra.isSeparable e, fun _ ↦ AlgEquiv.Algebra.isSeparable e.symm⟩
-instance Algebra.IsSeparable.isAlgebraic [Nontrivial F] [Algebra.IsSeparable F K] :
- Algebra.IsAlgebraic F K :=
- ⟨fun x ↦ (Algebra.IsSeparable.isIntegral F x).isAlgebraic⟩
+end AlgEquiv
+
+section IsScalarTower
+
+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
+over `L`. -/
+theorem IsSeparable.tower_top
+ {x : E} (h : IsSeparable F x) : IsSeparable L x :=
+ h.map.of_dvd (minpoly.dvd_map_of_isScalarTower _ _ _)
+
+variable (F E) in
+theorem Algebra.isSeparable_tower_top_of_isSeparable [Algebra.IsSeparable F E] :
+ Algebra.IsSeparable L E :=
+ ⟨fun x ↦ IsSeparable.tower_top _ (Algebra.IsSeparable.isSeparable F x)⟩
+
+@[deprecated (since := "2024-08-06")]
+alias IsSeparable.of_isScalarTower := Algebra.isSeparable_tower_top_of_isSeparable
+
+end IsScalarTower
end CommRing
-instance Algebra.isSeparable_self (F : Type*) [Field F] : Algebra.IsSeparable F F :=
- ⟨fun x => by
- rw [IsSeparable, minpoly.eq_X_sub_C']
- exact separable_X_sub_C⟩
+section Field
+
+variable (F : Type*) [Field F] {K E E' : Type*}
+
+section IsIntegral
+
+variable [Ring K] [Algebra F K]
+
+variable {F} in
+theorem isSeparable_algebraMap (x : F) : IsSeparable F (algebraMap F K x) :=
+ Polynomial.Separable.of_dvd (Polynomial.separable_X_sub_C (x := x))
+ (minpoly.dvd F (algebraMap F K x) (by simp only [map_sub, aeval_X, aeval_C, sub_self]))
+
+instance Algebra.isSeparable_self : Algebra.IsSeparable F F :=
+ ⟨isSeparable_algebraMap⟩
+
+variable [IsDomain K] [Algebra.IsIntegral F K] [CharZero F]
+
+theorem IsSeparable.of_integral (x : K) : IsSeparable F x :=
+ (minpoly.irreducible <| Algebra.IsIntegral.isIntegral x).separable
-- See note [lower instance priority]
-/-- A finite field extension in characteristic 0 is separable. -/
-instance (priority := 100) Algebra.IsSeparable.of_finite (F K : Type*) [Field F] [Field K]
- [Algebra F K] [FiniteDimensional F K] [CharZero F] : Algebra.IsSeparable F K :=
- ⟨fun x => (minpoly.irreducible <| .of_finite F x).separable⟩
-
-section IsSeparableTower
-
-/-- If `R / K / A` is an extension tower, `x : R` is separable over `A`, then it's also separable
-over `K`. -/
-theorem IsSeparable.of_isScalarTower {A : Type*} [CommRing A]
- (K : Type*) [Field K] [Algebra A K] {R : Type*} [CommRing R] [Algebra A R] [Algebra K R]
- [IsScalarTower A K R] {x : R} (h : IsSeparable A x) : IsSeparable K x :=
- h.map.of_dvd (minpoly.dvd_map_of_isScalarTower _ _ _)
+variable (K) in
+/-- A integral field extension in characteristic 0 is separable. -/
+protected instance (priority := 100) Algebra.IsSeparable.of_integral : Algebra.IsSeparable F K :=
+ ⟨_root_.IsSeparable.of_integral _⟩
-variable (F K E : Type*) [Field F] [Field K] [Field E] [Algebra F K] [Algebra F E] [Algebra K E]
- [IsScalarTower F K E]
+end IsIntegral
-theorem Algebra.isSeparable_tower_top_of_isSeparable [Algebra.IsSeparable F E] :
- Algebra.IsSeparable K E :=
- ⟨fun x ↦ IsSeparable.of_isScalarTower _ (Algebra.IsSeparable.isSeparable F x)⟩
+section IsScalarTower
-theorem Algebra.isSeparable_tower_bot_of_isSeparable [h : Algebra.IsSeparable F E] :
- Algebra.IsSeparable F K :=
- ⟨fun x ↦
+variable [Field K] [Ring E] [Algebra F K] [Algebra F E] [Algebra K E]
+ [Nontrivial E] [IsScalarTower F K E]
+
+variable {F} in
+/-- If `E / K / F` is a scalar tower and `algebraMap K E x` is separable over `F`, then `x` is
+``
+also separable over `F`. -/
+theorem IsSeparable.tower_bot {x : K} (h : IsSeparable F (algebraMap K E x)) : IsSeparable F x :=
have ⟨_q, hq⟩ :=
minpoly.dvd F x
((aeval_algebraMap_eq_zero_iff _ _ _).mp (minpoly.aeval F ((algebraMap K E) x)))
- (Eq.mp (congrArg Separable hq) (h.isSeparable _)).of_mul_left⟩
+ (Eq.mp (congrArg Separable hq) h).of_mul_left
+
+variable (K E) in
+theorem Algebra.isSeparable_tower_bot_of_isSeparable [h : Algebra.IsSeparable F E] :
+ Algebra.IsSeparable F K :=
+ ⟨fun _ ↦ IsSeparable.tower_bot (h.isSeparable _ _)⟩
-variable {E}
+end IsScalarTower
-theorem Algebra.IsSeparable.of_algHom (E' : Type*) [Field E'] [Algebra F E'] (f : E →ₐ[F] E')
- [Algebra.IsSeparable F E'] : Algebra.IsSeparable F E := by
- letI : Algebra E E' := RingHom.toAlgebra f.toRingHom
+section
+
+variable [Field E] [Field E'] [Algebra F E] [Algebra F E']
+ (f : E →ₐ[F] E')
+include f
+
+variable {F} in
+theorem IsSeparable.of_algHom {x : E} (h : IsSeparable F (f x)) : IsSeparable F x := by
+ let _ : Algebra E E' := RingHom.toAlgebra f.toRingHom
haveI : IsScalarTower F E E' := IsScalarTower.of_algebraMap_eq fun x => (f.commutes x).symm
- exact Algebra.isSeparable_tower_bot_of_isSeparable F E E'
+ exact h.tower_bot
-lemma Algebra.IsSeparable.of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Field B₁]
- [Field A₂] [Field B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂)
+
+variable (E') in
+theorem Algebra.IsSeparable.of_algHom [Algebra.IsSeparable F E'] : Algebra.IsSeparable F E :=
+ ⟨fun x => (Algebra.IsSeparable.isSeparable F (f x)).of_algHom⟩
+
+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
+
+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₁))
- [Algebra.IsSeparable A₁ B₁] : Algebra.IsSeparable A₂ B₂ := by
+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) }
- haveI := Algebra.isSeparable_tower_top_of_isSeparable A₁ A₂ B₁
- exact Algebra.IsSeparable.of_algHom _ _ e.symm.toAlgHom
+ 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₂ :=
+ ⟨fun x ↦ (e₂.apply_symm_apply x) ▸ _root_.IsSeparable.of_equiv_equiv e₁ e₂ he
+ (Algebra.IsSeparable.isSeparable _ _)⟩
-end IsSeparableTower
+end AlgEquiv
section CardAlgHom
diff --git a/Mathlib/FieldTheory/SeparableClosure.lean b/Mathlib/FieldTheory/SeparableClosure.lean
index 35439789c6f2a..68110800b109d 100644
--- a/Mathlib/FieldTheory/SeparableClosure.lean
+++ b/Mathlib/FieldTheory/SeparableClosure.lean
@@ -59,7 +59,7 @@ separable degree, degree, separable closure
-/
-open FiniteDimensional Polynomial IntermediateField Field
+open Module Polynomial IntermediateField Field
noncomputable section
@@ -115,7 +115,7 @@ theorem separableClosure.map_eq_of_separableClosure_eq_bot [Algebra E K] [IsScal
(separableClosure F E).map (IsScalarTower.toAlgHom F E K) = separableClosure F K := by
refine le_antisymm (map_le_of_algHom _) (fun x hx ↦ ?_)
obtain ⟨y, rfl⟩ := mem_bot.1 <| h ▸ mem_separableClosure_iff.2
- (IsSeparable.of_isScalarTower E <| mem_separableClosure_iff.1 hx)
+ (IsSeparable.tower_top E <| mem_separableClosure_iff.1 hx)
exact ⟨y, (map_mem_separableClosure_iff <| IsScalarTower.toAlgHom F E K).mp hx, rfl⟩
/-- If `i` is an `F`-algebra isomorphism of `E` and `K`, then the image of `separableClosure F E`
@@ -170,7 +170,8 @@ theorem separableClosure.separableClosure_eq_bot :
theorem separableClosure.normalClosure_eq_self :
normalClosure F (separableClosure F E) E = separableClosure F E :=
le_antisymm (normalClosure_le_iff.2 fun i ↦
- haveI : Algebra.IsSeparable F i.fieldRange := (AlgEquiv.ofInjectiveField i).isSeparable
+ have : Algebra.IsSeparable F i.fieldRange :=
+ (AlgEquiv.Algebra.isSeparable (AlgEquiv.ofInjectiveField i))
le_separableClosure F E _) (le_normalClosure _)
/-- If `E` is normal over `F`, then the separable closure of `F` in `E` is Galois (i.e.
@@ -219,7 +220,7 @@ theorem separableClosure.eq_top_iff : separableClosure F E = ⊤ ↔ Algebra.IsS
`separableClosure E K`. -/
theorem separableClosure.le_restrictScalars [Algebra E K] [IsScalarTower F E K] :
separableClosure F K ≤ (separableClosure E K).restrictScalars F :=
- fun _ h ↦ IsSeparable.of_isScalarTower E h
+ fun _ ↦ IsSeparable.tower_top E
/-- If `K / E / F` is a field extension tower, such that `E / F` is separable, then
`separableClosure F K` is equal to `separableClosure E K`. -/
diff --git a/Mathlib/FieldTheory/SeparableDegree.lean b/Mathlib/FieldTheory/SeparableDegree.lean
index e9e5e31f32d7d..ec3dbd6aa4fb7 100644
--- a/Mathlib/FieldTheory/SeparableDegree.lean
+++ b/Mathlib/FieldTheory/SeparableDegree.lean
@@ -67,7 +67,7 @@ This file contains basics about the separable degree of a field extension.
if `K / E / F` is a field extension tower, such that `K / E` is algebraic,
then there is a non-canonical bijection `Field.Emb F E × Field.Emb E K ≃ Field.Emb F K`.
In particular, the separable degrees satisfy the tower law: $[E:F]_s [K:E]_s = [K:F]_s$
- (see also `FiniteDimensional.finrank_mul_finrank`).
+ (see also `Module.finrank_mul_finrank`).
- `Polynomial.natSepDegree_le_natDegree`: the separable degree of a polynomial is smaller than
its degree.
@@ -118,7 +118,7 @@ separable degree, degree, polynomial
-/
-open FiniteDimensional Polynomial IntermediateField Field
+open Module Polynomial IntermediateField Field
noncomputable section
@@ -208,7 +208,7 @@ def embEquivOfAdjoinSplits {S : Set E} (hS : adjoin F S = ⊤)
(hS ▸ isAlgebraic_adjoin (S := S) fun x hx ↦ (hK x hx).1)
have halg := (topEquiv (F := F) (E := E)).isAlgebraic
Classical.choice <| Function.Embedding.antisymm
- (halg.algHomEmbeddingOfSplits (fun _ ↦ splits_of_mem_adjoin F (S := S) hK (hS ▸ mem_top)) _)
+ (halg.algHomEmbeddingOfSplits (fun _ ↦ splits_of_mem_adjoin F E (S := S) hK (hS ▸ mem_top)) _)
(halg.algHomEmbeddingOfSplits (fun _ ↦ IsAlgClosed.splits_codomain _) _)
/-- The `Field.finSepDegree F E` is equal to the cardinality of `E →ₐ[F] K`
@@ -246,7 +246,7 @@ def embProdEmbOfIsAlgebraic [Algebra E K] [IsScalarTower F E K] [Algebra.IsAlgeb
/-- If `K / E / F` is a field extension tower, such that `K / E` is algebraic, then their
separable degrees satisfy the tower law
-$[E:F]_s [K:E]_s = [K:F]_s$. See also `FiniteDimensional.finrank_mul_finrank`. -/
+$[E:F]_s [K:E]_s = [K:F]_s$. See also `Module.finrank_mul_finrank`. -/
theorem finSepDegree_mul_finSepDegree_of_isAlgebraic
[Algebra E K] [IsScalarTower F E K] [Algebra.IsAlgebraic E K] :
finSepDegree F E * finSepDegree E K = finSepDegree F K := by
@@ -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
@@ -589,7 +589,7 @@ end Polynomial
namespace minpoly
-variable {F E}
+variable {F : Type u} {E : Type v} [Field F] [Ring E] [IsDomain E] [Algebra F E]
variable (q : ℕ) [hF : ExpChar F q] {x : E}
/-- The minimal polynomial of an element of `E / F` of exponential characteristic `q` has
@@ -632,17 +632,18 @@ separable degree one if and only if the minimal polynomial is of the form
theorem natSepDegree_eq_one_iff_eq_X_sub_C_pow : (minpoly F x).natSepDegree = 1 ↔
∃ n : ℕ, (minpoly F x).map (algebraMap F E) = (X - C x) ^ q ^ n := by
haveI := expChar_of_injective_algebraMap (algebraMap F E).injective q
- haveI := expChar_of_injective_algebraMap (NoZeroSMulDivisors.algebraMap_injective E E[X]) q
+ haveI := expChar_of_injective_ringHom (C_injective (R := E)) q
refine ⟨fun h ↦ ?_, fun ⟨n, h⟩ ↦ (natSepDegree_eq_one_iff_pow_mem q).2 ?_⟩
· obtain ⟨n, y, h⟩ := (natSepDegree_eq_one_iff_eq_X_pow_sub_C q).1 h
have hx := congr_arg (Polynomial.aeval x) h.symm
rw [minpoly.aeval, map_sub, map_pow, aeval_X, aeval_C, sub_eq_zero, eq_comm] at hx
use n
- rw [h, Polynomial.map_sub, Polynomial.map_pow, map_X, map_C, hx, map_pow, ← sub_pow_expChar_pow]
+ rw [h, Polynomial.map_sub, Polynomial.map_pow, map_X, map_C, hx, map_pow,
+ ← 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
- exact ⟨n, -(minpoly F x).coeff 0, by rw [map_neg, h]; ring1⟩
+ 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
@@ -700,7 +701,7 @@ theorem finSepDegree_dvd_finrank : finSepDegree F E ∣ finrank F E := by
set M := L⟮x⟯
have := Algebra.IsAlgebraic.of_finite L M
rwa [finSepDegree_mul_finSepDegree_of_isAlgebraic F L M,
- FiniteDimensional.finrank_mul_finrank F L M] at hdvd
+ Module.finrank_mul_finrank F L M] at hdvd
rw [finrank_of_infinite_dimensional hfd]
exact dvd_zero _
@@ -730,11 +731,11 @@ theorem finSepDegree_eq_finrank_of_isSeparable [Algebra.IsSeparable F E] :
simp only at h ⊢
have heq : _ * _ = _ * _ := congr_arg₂ (· * ·) h <|
(finSepDegree_adjoin_simple_eq_finrank_iff L E x (IsAlgebraic.of_finite L x)).2 <|
- IsSeparable.of_isScalarTower L (Algebra.IsSeparable.isSeparable F x)
+ IsSeparable.tower_top L (Algebra.IsSeparable.isSeparable F x)
set M := L⟮x⟯
have := Algebra.IsAlgebraic.of_finite L M
rwa [finSepDegree_mul_finSepDegree_of_isAlgebraic F L M,
- FiniteDimensional.finrank_mul_finrank F L M] at heq
+ Module.finrank_mul_finrank F L M] at heq
alias Algebra.IsSeparable.finSepDegree_eq := finSepDegree_eq_finrank_of_isSeparable
@@ -748,7 +749,7 @@ theorem finSepDegree_eq_finrank_iff [FiniteDimensional F E] :
(finSepDegree_adjoin_simple_le_finrank F E x halg) <| le_of_not_lt fun h ↦ ?_
have := Nat.mul_lt_mul_of_lt_of_le' h (finSepDegree_le_finrank F⟮x⟯ E) Fin.size_pos'
rw [finSepDegree_mul_finSepDegree_of_isAlgebraic F F⟮x⟯ E,
- FiniteDimensional.finrank_mul_finrank F F⟮x⟯ E] at this
+ Module.finrank_mul_finrank F F⟮x⟯ E] at this
linarith only [heq, this]⟩, fun _ ↦ finSepDegree_eq_finrank_of_isSeparable F E⟩
end Field
@@ -795,7 +796,7 @@ theorem IsSeparable.of_algebra_isSeparable_of_isSeparable [Algebra E K] [IsScala
have := finSepDegree_mul_finSepDegree_of_isAlgebraic F E' E'⟮x⟯
rw [finSepDegree_eq_finrank_of_isSeparable F E',
finSepDegree_eq_finrank_of_isSeparable E' E'⟮x⟯,
- FiniteDimensional.finrank_mul_finrank F E' E'⟮x⟯,
+ Module.finrank_mul_finrank F E' E'⟮x⟯,
eq_comm, finSepDegree_eq_finrank_iff F E'⟮x⟯] at this
change Algebra.IsSeparable F (restrictScalars F E'⟮x⟯) at this
exact isSeparable_of_mem_isSeparable F K hx
@@ -812,7 +813,7 @@ theorem IntermediateField.isSeparable_adjoin_pair_of_isSeparable {x y : E}
(hx : IsSeparable F x) (hy : IsSeparable F y) :
Algebra.IsSeparable F F⟮x, y⟯ := by
rw [← adjoin_simple_adjoin_simple]
- replace hy := IsSeparable.of_isScalarTower F⟮x⟯ hy
+ replace hy := IsSeparable.tower_top F⟮x⟯ hy
rw [← isSeparable_adjoin_simple_iff_isSeparable] at hx hy
exact Algebra.IsSeparable.trans F F⟮x⟯ F⟮x⟯⟮y⟯
@@ -841,6 +842,19 @@ theorem isSeparable_add {x y : E} (hx : IsSeparable F x) (hy : IsSeparable F y)
isSeparable_of_mem_isSeparable F E <| F⟮x, y⟯.add_mem (subset_adjoin F _ (.inl rfl))
(subset_adjoin F _ (.inr rfl))
+/-- If `x` is a separable elements, then `-x` is also a separable element. -/
+theorem isSeparable_neg {x : E} (hx : IsSeparable F x) :
+ IsSeparable F (-x) :=
+ haveI := (isSeparable_adjoin_simple_iff_isSeparable F E).2 hx
+ isSeparable_of_mem_isSeparable F E <| F⟮x⟯.neg_mem <| mem_adjoin_simple_self F x
+
+/-- If `x` and `y` are both separable elements, then `x - y` is also a separable element. -/
+theorem isSeparable_sub {x y : E} (hx : IsSeparable F x) (hy : IsSeparable F y) :
+ IsSeparable F (x - y) :=
+ haveI := isSeparable_adjoin_pair_of_isSeparable F E hx hy
+ isSeparable_of_mem_isSeparable F E <| F⟮x, y⟯.sub_mem (subset_adjoin F _ (.inl rfl))
+ (subset_adjoin F _ (.inr rfl))
+
/-- If `x` is a separable element, then `x⁻¹` is also a separable element. -/
theorem isSeparable_inv {x : E} (hx : IsSeparable F x) : IsSeparable F x⁻¹ :=
haveI := (isSeparable_adjoin_simple_iff_isSeparable F E).2 hx
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/FieldTheory/Tower.lean b/Mathlib/FieldTheory/Tower.lean
index 4a4720b3cb6aa..297650824b8be 100644
--- a/Mathlib/FieldTheory/Tower.lean
+++ b/Mathlib/FieldTheory/Tower.lean
@@ -15,7 +15,7 @@ We prove that given `IsScalarTower F K A`, if `A` is finite as a module over `F`
In particular these conditions hold when `A`, `F`, and `K` are fields.
-The formulas for the dimensions are given elsewhere by `FiniteDimensional.finrank_mul_finrank`.
+The formulas for the dimensions are given elsewhere by `Module.finrank_mul_finrank`.
## Tags
diff --git a/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean b/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean
index 1a4c7dfdf186b..eb38b5464c6a8 100644
--- a/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean
+++ b/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean
@@ -22,7 +22,7 @@ This file defines oriented angles in Euclidean affine spaces.
noncomputable section
-open FiniteDimensional Complex
+open Module Complex
open scoped Affine EuclideanGeometry Real RealInnerProductSpace ComplexConjugate
@@ -620,9 +620,9 @@ 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_iff, Prod.ext_iff] at hp
+ simp_rw [s, Set.mem_image, Set.mem_prod, Set.mem_univ, true_and, Prod.ext_iff] at hp
obtain ⟨q₁, q₅, q₂⟩ := p
dsimp only at hp ⊢
obtain ⟨⟨⟨q, hq⟩, v⟩, hv, rfl, rfl, rfl⟩ := hp
@@ -638,7 +638,7 @@ theorem _root_.Collinear.oangle_sign_of_sameRay_vsub {p₁ p₂ p₃ p₄ : P} (
exact smul_vsub_rev_mem_vectorSpan_pair _ _ _
have hsp : ∀ p : P × P × P, p ∈ s → ∡ p.1 p.2.1 p.2.2 ≠ 0 ∧ ∡ p.1 p.2.1 p.2.2 ≠ π := by
intro p hp
- simp_rw [s, Set.mem_image, Set.mem_prod, Set.mem_setOf, Set.mem_univ, true_and_iff,
+ simp_rw [s, Set.mem_image, Set.mem_prod, Set.mem_setOf, Set.mem_univ, true_and,
Prod.ext_iff] at hp
obtain ⟨q₁, q₅, q₂⟩ := p
dsimp only at hp ⊢
@@ -656,13 +656,13 @@ theorem _root_.Collinear.oangle_sign_of_sameRay_vsub {p₁ p₂ p₃ p₄ : P} (
rw [direction_affineSpan]
exact smul_vsub_rev_mem_vectorSpan_pair _ _ _
have hp₁p₂s : (p₁, p₅, p₂) ∈ s := by
- simp_rw [s, Set.mem_image, Set.mem_prod, Set.mem_setOf, Set.mem_univ, true_and_iff,
+ simp_rw [s, Set.mem_image, Set.mem_prod, Set.mem_setOf, Set.mem_univ, true_and,
Prod.ext_iff]
refine ⟨⟨⟨p₁, left_mem_affineSpan_pair ℝ _ _⟩, p₂ -ᵥ p₁⟩,
⟨SameRay.rfl, vsub_ne_zero.2 hp₁p₂.symm⟩, ?_⟩
simp
have hp₃p₄s : (p₃, p₅, p₄) ∈ s := by
- simp_rw [s, Set.mem_image, Set.mem_prod, Set.mem_setOf, Set.mem_univ, true_and_iff,
+ simp_rw [s, Set.mem_image, Set.mem_prod, Set.mem_setOf, Set.mem_univ, true_and,
Prod.ext_iff]
refine ⟨⟨⟨p₃, hc.mem_affineSpan_of_mem_of_ne (Set.mem_insert _ _)
(Set.mem_insert_of_mem _ (Set.mem_insert _ _))
@@ -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 fb641332e085a..3e26c839b61d6 100644
--- a/Mathlib/Geometry/Euclidean/Angle/Oriented/Basic.lean
+++ b/Mathlib/Geometry/Euclidean/Angle/Oriented/Basic.lean
@@ -31,7 +31,7 @@ modulo `2 * π` as equalities of `(2 : ℤ) • θ`.
noncomputable section
-open FiniteDimensional Complex
+open Module Complex
open scoped Real RealInnerProductSpace ComplexConjugate
@@ -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/Oriented/RightAngle.lean b/Mathlib/Geometry/Euclidean/Angle/Oriented/RightAngle.lean
index d634919578060..8ca1f21c9b812 100644
--- a/Mathlib/Geometry/Euclidean/Angle/Oriented/RightAngle.lean
+++ b/Mathlib/Geometry/Euclidean/Angle/Oriented/RightAngle.lean
@@ -25,7 +25,7 @@ open scoped RealInnerProductSpace
namespace Orientation
-open FiniteDimensional
+open Module
variable {V : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V]
variable [hd2 : Fact (finrank ℝ V = 2)] (o : Orientation ℝ V (Fin 2))
@@ -519,7 +519,7 @@ end Orientation
namespace EuclideanGeometry
-open FiniteDimensional
+open Module
variable {V : Type*} {P : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P]
[NormedAddTorsor V P] [hd2 : Fact (finrank ℝ V = 2)] [Module.Oriented ℝ V (Fin 2)]
diff --git a/Mathlib/Geometry/Euclidean/Angle/Oriented/Rotation.lean b/Mathlib/Geometry/Euclidean/Angle/Oriented/Rotation.lean
index b933762e6b4a6..734899c867f50 100644
--- a/Mathlib/Geometry/Euclidean/Angle/Oriented/Rotation.lean
+++ b/Mathlib/Geometry/Euclidean/Angle/Oriented/Rotation.lean
@@ -20,7 +20,7 @@ This file defines rotations by oriented angles in real inner product spaces.
noncomputable section
-open FiniteDimensional Complex
+open Module Complex
open scoped Real RealInnerProductSpace ComplexConjugate
@@ -65,9 +65,8 @@ def rotation (θ : Real.Angle) : V ≃ₗᵢ[ℝ] V :=
· simp only [o.rightAngleRotation_rightAngleRotation, o.rotationAux_apply,
Function.comp_apply, id, LinearEquiv.coe_coe, LinearIsometry.coe_toLinearMap,
LinearIsometryEquiv.coe_toLinearEquiv, map_smul, map_sub, LinearMap.coe_comp,
- LinearMap.id_coe, LinearMap.smul_apply, LinearMap.sub_apply, ← mul_smul, add_smul,
- smul_add, smul_neg, smul_sub, mul_comm, sq]
- abel
+ LinearMap.id_coe, LinearMap.smul_apply, LinearMap.sub_apply]
+ module
· simp)
(by
ext x
@@ -75,10 +74,8 @@ def rotation (θ : Real.Angle) : V ≃ₗᵢ[ℝ] V :=
· simp only [o.rightAngleRotation_rightAngleRotation, o.rotationAux_apply,
Function.comp_apply, id, LinearEquiv.coe_coe, LinearIsometry.coe_toLinearMap,
LinearIsometryEquiv.coe_toLinearEquiv, map_add, map_smul, LinearMap.coe_comp,
- LinearMap.id_coe, LinearMap.smul_apply, LinearMap.sub_apply,
- add_smul, smul_neg, smul_sub, smul_smul]
- ring_nf
- abel
+ LinearMap.id_coe, LinearMap.smul_apply, LinearMap.sub_apply]
+ module
· simp)
theorem rotation_apply (θ : Real.Angle) (x : V) :
@@ -104,8 +101,7 @@ theorem rotation_eq_matrix_toLin (θ : Real.Angle) {x : V} (hx : x ≠ 0) :
/-- The determinant of `rotation` (as a linear map) is equal to `1`. -/
@[simp]
theorem det_rotation (θ : Real.Angle) : LinearMap.det (o.rotation θ).toLinearMap = 1 := by
- haveI : Nontrivial V :=
- FiniteDimensional.nontrivial_of_finrank_eq_succ (@Fact.out (finrank ℝ V = 2) _)
+ haveI : Nontrivial V := nontrivial_of_finrank_eq_succ (@Fact.out (finrank ℝ V = 2) _)
obtain ⟨x, hx⟩ : ∃ x, x ≠ (0 : V) := exists_ne (0 : V)
rw [o.rotation_eq_matrix_toLin θ hx]
simpa [sq] using θ.cos_sq_add_sin_sq
@@ -146,11 +142,9 @@ theorem rotation_pi_div_two : o.rotation (π / 2 : ℝ) = J := by
@[simp]
theorem rotation_rotation (θ₁ θ₂ : Real.Angle) (x : V) :
o.rotation θ₁ (o.rotation θ₂ x) = o.rotation (θ₁ + θ₂) x := by
- simp only [o.rotation_apply, ← mul_smul, Real.Angle.cos_add, Real.Angle.sin_add, add_smul,
- sub_smul, LinearIsometryEquiv.trans_apply, smul_add, LinearIsometryEquiv.map_add,
- LinearIsometryEquiv.map_smul, rightAngleRotation_rightAngleRotation, smul_neg]
- ring_nf
- abel
+ simp only [o.rotation_apply, Real.Angle.cos_add, Real.Angle.sin_add, LinearIsometryEquiv.map_add,
+ LinearIsometryEquiv.trans_apply, map_smul, rightAngleRotation_rightAngleRotation]
+ module
/-- Rotating twice is equivalent to rotating by the sum of the angles. -/
@[simp]
@@ -338,8 +332,7 @@ theorem oangle_eq_iff_eq_pos_smul_rotation_or_eq_zero {x y : V} (θ : Real.Angle
theorem exists_linearIsometryEquiv_eq_of_det_pos {f : V ≃ₗᵢ[ℝ] V}
(hd : 0 < LinearMap.det (f.toLinearEquiv : V →ₗ[ℝ] V)) :
∃ θ : Real.Angle, f = o.rotation θ := by
- haveI : Nontrivial V :=
- FiniteDimensional.nontrivial_of_finrank_eq_succ (@Fact.out (finrank ℝ V = 2) _)
+ haveI : Nontrivial V := nontrivial_of_finrank_eq_succ (@Fact.out (finrank ℝ V = 2) _)
obtain ⟨x, hx⟩ : ∃ x, x ≠ (0 : V) := exists_ne (0 : V)
use o.oangle x (f x)
apply LinearIsometryEquiv.toLinearEquiv_injective
diff --git a/Mathlib/Geometry/Euclidean/Angle/Sphere.lean b/Mathlib/Geometry/Euclidean/Angle/Sphere.lean
index dd2a20922dbdb..17315a1b24430 100644
--- a/Mathlib/Geometry/Euclidean/Angle/Sphere.lean
+++ b/Mathlib/Geometry/Euclidean/Angle/Sphere.lean
@@ -16,7 +16,7 @@ This file proves results about angles in circles and spheres.
noncomputable section
-open FiniteDimensional Complex
+open Module Complex
open scoped EuclideanGeometry Real RealInnerProductSpace ComplexConjugate
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/Angle/Unoriented/RightAngle.lean b/Mathlib/Geometry/Euclidean/Angle/Unoriented/RightAngle.lean
index a85b10c3cdb58..03de613c6af8b 100644
--- a/Mathlib/Geometry/Euclidean/Angle/Unoriented/RightAngle.lean
+++ b/Mathlib/Geometry/Euclidean/Angle/Unoriented/RightAngle.lean
@@ -121,7 +121,7 @@ theorem cos_angle_add_of_inner_eq_zero {x y : V} (h : ⟪x, y⟫ = 0) :
Real.cos (angle x (x + y)) = ‖x‖ / ‖x + y‖ := by
rw [angle_add_eq_arccos_of_inner_eq_zero h,
Real.cos_arccos (le_trans (by norm_num) (div_nonneg (norm_nonneg _) (norm_nonneg _)))
- (div_le_one_of_le _ (norm_nonneg _))]
+ (div_le_one_of_le₀ _ (norm_nonneg _))]
rw [mul_self_le_mul_self_iff (norm_nonneg _) (norm_nonneg _),
norm_add_sq_eq_norm_sq_add_norm_sq_real h]
exact le_add_of_nonneg_right (mul_self_nonneg _)
@@ -131,7 +131,7 @@ theorem sin_angle_add_of_inner_eq_zero {x y : V} (h : ⟪x, y⟫ = 0) (h0 : x
Real.sin (angle x (x + y)) = ‖y‖ / ‖x + y‖ := by
rw [angle_add_eq_arcsin_of_inner_eq_zero h h0,
Real.sin_arcsin (le_trans (by norm_num) (div_nonneg (norm_nonneg _) (norm_nonneg _)))
- (div_le_one_of_le _ (norm_nonneg _))]
+ (div_le_one_of_le₀ _ (norm_nonneg _))]
rw [mul_self_le_mul_self_iff (norm_nonneg _) (norm_nonneg _),
norm_add_sq_eq_norm_sq_add_norm_sq_real h]
exact le_add_of_nonneg_left (mul_self_nonneg _)
diff --git a/Mathlib/Geometry/Euclidean/Basic.lean b/Mathlib/Geometry/Euclidean/Basic.lean
index 3431ffc86bbca..d39b79aad2703 100644
--- a/Mathlib/Geometry/Euclidean/Basic.lean
+++ b/Mathlib/Geometry/Euclidean/Basic.lean
@@ -113,8 +113,9 @@ another point. -/
theorem dist_smul_vadd_eq_dist {v : V} (p₁ p₂ : P) (hv : v ≠ 0) (r : ℝ) :
dist (r • v +ᵥ p₁) p₂ = dist p₁ p₂ ↔ r = 0 ∨ r = -2 * ⟪v, p₁ -ᵥ p₂⟫ / ⟪v, v⟫ := by
conv_lhs =>
- rw [← mul_self_inj_of_nonneg dist_nonneg dist_nonneg, dist_smul_vadd_sq, ← sub_eq_zero,
- add_sub_assoc, dist_eq_norm_vsub V p₁ p₂, ← real_inner_self_eq_norm_mul_norm, sub_self]
+ rw [← mul_self_inj_of_nonneg dist_nonneg dist_nonneg, dist_smul_vadd_sq, mul_assoc,
+ ← sub_eq_zero, add_sub_assoc, dist_eq_norm_vsub V p₁ p₂, ← real_inner_self_eq_norm_mul_norm,
+ sub_self]
have hvi : ⟪v, v⟫ ≠ 0 := by simpa using hv
have hd : discrim ⟪v, v⟫ (2 * ⟪v, p₁ -ᵥ p₂⟫) 0 = 2 * ⟪v, p₁ -ᵥ p₂⟫ * (2 * ⟪v, p₁ -ᵥ p₂⟫) := by
rw [discrim]
@@ -124,7 +125,7 @@ theorem dist_smul_vadd_eq_dist {v : V} (p₁ p₂ : P) (hv : v ≠ 0) (r : ℝ)
mul_div_assoc]
norm_num
-open AffineSubspace FiniteDimensional
+open AffineSubspace Module
/-- Distances `r₁` `r₂` of `p` from two different points `c₁` `c₂` determine at
most two points `p₁` `p₂` in a two-dimensional subspace containing those points
@@ -150,7 +151,7 @@ theorem eq_of_dist_eq_of_dist_eq_of_mem_of_finrank_eq_two {s : AffineSubspace
· rw [real_inner_comm]
exact ho
have hbs : Submodule.span ℝ (Set.range b) = s.direction := by
- refine eq_of_le_of_finrank_eq ?_ ?_
+ refine Submodule.eq_of_le_of_finrank_eq ?_ ?_
· rw [Submodule.span_le, Set.range_subset_iff]
intro i
fin_cases i
@@ -171,13 +172,13 @@ theorem eq_of_dist_eq_of_dist_eq_of_mem_of_finrank_eq_two {s : AffineSubspace
exact ⟨t₁, t₂, hv⟩
rcases hv (p -ᵥ p₁) (vsub_mem_direction hps hp₁s) with ⟨t₁, t₂, hpt⟩
simp only [hpt, inner_add_right, inner_smul_right, ho, mul_zero, add_zero,
- mul_eq_zero, inner_self_eq_zero, vsub_eq_zero_iff_eq, hc.symm, or_false_iff] at hop
+ mul_eq_zero, inner_self_eq_zero, vsub_eq_zero_iff_eq, hc.symm, or_false] at hop
rw [hop, zero_smul, zero_add, ← eq_vadd_iff_vsub_eq] at hpt
subst hpt
have hp' : (p₂ -ᵥ p₁ : V) ≠ 0 := by simp [hp.symm]
have hp₂ : dist ((1 : ℝ) • (p₂ -ᵥ p₁) +ᵥ p₁) c₁ = r₁ := by simp [hp₂c₁]
rw [← hp₁c₁, dist_smul_vadd_eq_dist _ _ hp'] at hpc₁ hp₂
- simp only [one_ne_zero, false_or_iff] at hp₂
+ simp only [one_ne_zero, false_or] at hp₂
rw [hp₂.symm] at hpc₁
cases' hpc₁ with hpc₁ hpc₁ <;> simp [hpc₁]
@@ -352,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 137f90c80106a..bd9d26e0df104 100644
--- a/Mathlib/Geometry/Euclidean/Circumcenter.lean
+++ b/Mathlib/Geometry/Euclidean/Circumcenter.lean
@@ -316,11 +316,11 @@ theorem eq_circumradius_of_dist_eq {n : ℕ} (s : Simplex ℝ P n) {p : P}
r = s.circumradius := by
have h := s.circumsphere_unique_dist_eq.2 ⟨p, r⟩
simp only [hp, hr, forall_const, eq_self_iff_true, subset_sphere, Sphere.ext_iff,
- Set.forall_mem_range, mem_sphere, true_and_iff] at h
+ Set.forall_mem_range, mem_sphere] at h
-- Porting note: added the next three lines (`simp` less powerful)
rw [subset_sphere (s := ⟨p, r⟩)] at h
simp only [hp, hr, forall_const, eq_self_iff_true, subset_sphere, Sphere.ext_iff,
- Set.forall_mem_range, mem_sphere, true_and_iff] at h
+ Set.forall_mem_range, mem_sphere, true_and] at h
exact h.2
/-- The circumradius is non-negative. -/
@@ -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 :
@@ -667,7 +667,7 @@ end Affine
namespace EuclideanGeometry
-open Affine AffineSubspace FiniteDimensional
+open Affine AffineSubspace Module
variable {V : Type*} {P : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P]
[NormedAddTorsor V P]
@@ -866,7 +866,7 @@ theorem eq_or_eq_reflection_of_dist_eq {n : ℕ} {s : Simplex ℝ P n} {p p₁ p
by_cases hp : p = s.orthogonalProjectionSpan p
· rw [Simplex.orthogonalProjectionSpan] at hp
rw [hp₁, hp₂, ← hp]
- simp only [true_or_iff, eq_self_iff_true, smul_zero, vsub_self]
+ simp only [true_or, eq_self_iff_true, smul_zero, vsub_self]
· have hz : ⟪p -ᵥ orthogonalProjection span_s p, p -ᵥ orthogonalProjection span_s p⟫ ≠ 0 := by
simpa only [Ne, vsub_eq_zero_iff_eq, inner_self_eq_zero] using hp
rw [mul_left_inj' hz, mul_self_eq_mul_self_iff] at hd₁
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 6343ce224c3da..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
@@ -344,7 +344,7 @@ theorem vectorSpan_isOrtho_altitude_direction {n : ℕ} (s : Simplex ℝ P (n +
rw [direction_altitude]
exact (Submodule.isOrtho_orthogonal_right _).mono_right inf_le_left
-open FiniteDimensional
+open Module
/-- An altitude is finite-dimensional. -/
instance finiteDimensional_direction_altitude {n : ℕ} (s : Simplex ℝ P (n + 1)) (i : Fin (n + 2)) :
@@ -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,
@@ -392,7 +392,7 @@ theorem affineSpan_pair_eq_altitude_iff {n : ℕ} (s : Simplex ℝ P (n + 1)) (i
rw [vectorSpan_eq_span_vsub_set_left_ne ℝ (Set.mem_insert _ _),
Set.insert_diff_of_mem _ (Set.mem_singleton _),
Set.diff_singleton_eq_self fun h => hne (Set.mem_singleton_iff.1 h), Set.image_singleton]
- refine eq_of_le_of_finrank_eq ?_ ?_
+ refine Submodule.eq_of_le_of_finrank_eq ?_ ?_
· rw [Submodule.span_le]
simpa using h
· rw [finrank_direction_altitude, finrank_span_set_eq_card]
@@ -404,7 +404,7 @@ end Simplex
namespace Triangle
-open EuclideanGeometry Finset Simplex AffineSubspace FiniteDimensional
+open EuclideanGeometry Finset Simplex AffineSubspace Module
variable {V : Type*} {P : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P]
[NormedAddTorsor V P]
@@ -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
@@ -548,7 +540,8 @@ theorem altitude_replace_orthocenter_eq_affineSpan {t₁ t₂ : Triangle ℝ P}
have he : affineSpan ℝ (Set.range t₂.points) = affineSpan ℝ (Set.range t₁.points) := by
refine ext_of_direction_eq ?_
⟨t₁.points i₃, mem_affineSpan ℝ ⟨j₃, h₃⟩, mem_affineSpan ℝ (Set.mem_range_self _)⟩
- refine eq_of_le_of_finrank_eq (direction_le (spanPoints_subset_coe_of_subset_coe ?_)) ?_
+ refine Submodule.eq_of_le_of_finrank_eq (direction_le (spanPoints_subset_coe_of_subset_coe ?_))
+ ?_
· have hu : (Finset.univ : Finset (Fin 3)) = {j₁, j₂, j₃} := by
clear h₁ h₂ h₃
-- Porting note (#11043): was `decide!`
@@ -602,7 +595,7 @@ end Affine
namespace EuclideanGeometry
-open Affine AffineSubspace FiniteDimensional
+open Affine AffineSubspace Module
variable {V : Type*} {P : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P]
[NormedAddTorsor V P]
@@ -706,7 +699,7 @@ theorem affineSpan_of_orthocentricSystem {s : Set P} (ho : OrthocentricSystem s)
⟨p 0, mem_affineSpan ℝ (Set.mem_range_self _), mem_affineSpan ℝ (hps (Set.mem_range_self _))⟩
have hfd : FiniteDimensional ℝ (affineSpan ℝ s).direction := by rw [hs]; infer_instance
haveI := hfd
- refine eq_of_le_of_finrank_eq (direction_le (affineSpan_mono ℝ hps)) ?_
+ refine Submodule.eq_of_le_of_finrank_eq (direction_le (affineSpan_mono ℝ hps)) ?_
rw [hs, direction_affineSpan, direction_affineSpan, ha.finrank_vectorSpan (Fintype.card_fin _),
t.independent.finrank_vectorSpan (Fintype.card_fin _)]
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 20d5711b81e4d..c4e42b8477423 100644
--- a/Mathlib/Geometry/Euclidean/Sphere/Basic.lean
+++ b/Mathlib/Geometry/Euclidean/Sphere/Basic.lean
@@ -33,7 +33,7 @@ namespace EuclideanGeometry
variable {V : Type*} (P : Type*)
-open FiniteDimensional
+open Module
/-- A `Sphere P` bundles a `center` and `radius`. This definition does not require the radius to
be positive; that should be given as a hypothesis to lemmas that require it. -/
@@ -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/Euclidean/Triangle.lean b/Mathlib/Geometry/Euclidean/Triangle.lean
index 5a28ab76286ee..9e2ab6a89582d 100644
--- a/Mathlib/Geometry/Euclidean/Triangle.lean
+++ b/Mathlib/Geometry/Euclidean/Triangle.lean
@@ -295,7 +295,7 @@ theorem angle_add_angle_add_angle_eq_pi {p1 p2 p3 : P} (h2 : p2 ≠ p1) (h3 : p3
/-- The **sum of the angles of a triangle** (possibly degenerate, where the triangle is a line),
oriented angles at point. -/
theorem oangle_add_oangle_add_oangle_eq_pi [Module.Oriented ℝ V (Fin 2)]
- [Fact (FiniteDimensional.finrank ℝ V = 2)] {p1 p2 p3 : P} (h21 : p2 ≠ p1) (h32 : p3 ≠ p2)
+ [Fact (Module.finrank ℝ V = 2)] {p1 p2 p3 : P} (h21 : p2 ≠ p1) (h32 : p3 ≠ p2)
(h13 : p1 ≠ p3) : ∡ p1 p2 p3 + ∡ p2 p3 p1 + ∡ p3 p1 p2 = π := by
simpa only [neg_vsub_eq_vsub_rev] using
positiveOrientation.oangle_add_cyc3_neg_left (vsub_ne_zero.mpr h21) (vsub_ne_zero.mpr h32)
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 296acd0490652..9a1ab30e1daa9 100644
--- a/Mathlib/Geometry/Manifold/AnalyticManifold.lean
+++ b/Mathlib/Geometry/Manifold/AnalyticManifold.lean
@@ -3,10 +3,7 @@ Copyright (c) 2023 Michael Lee. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Michael Lee, Geoffrey Irving
-/
-import Mathlib.Analysis.Analytic.Composition
import Mathlib.Analysis.Analytic.Constructions
-import Mathlib.Analysis.Analytic.Linear
-import Mathlib.Analysis.Analytic.Within
import Mathlib.Analysis.Calculus.FDeriv.Analytic
import Mathlib.Geometry.Manifold.SmoothManifoldWithCorners
@@ -20,7 +17,7 @@ interior and smooth everywhere (including at the boundary). The definition mirr
analytic manifolds are smooth manifolds.
Completeness is required throughout, but this is nonessential: it is due to many of the lemmas about
-AnalyticWithinOn` requiring completeness for ease of proof.
+AnalyticOn` requiring completeness for ease of proof.
-/
noncomputable section
@@ -31,8 +28,8 @@ open scoped Manifold Filter Topology
variable {𝕜 : Type*} [NontriviallyNormedField 𝕜]
-variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] [CompleteSpace E] {H : Type*}
- [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) {M : Type*} [TopologicalSpace M]
+variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*}
+ [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M]
/-!
## `analyticGroupoid`
@@ -44,11 +41,12 @@ 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 `AnalyticWithinOn` when read in `E` through `I`. Using `AnalyticWithinOn`
-rather than `AnalyticOn` gives us meaningful definitions at boundary points. -/
+`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. -/
def analyticPregroupoid : Pregroupoid H where
- property f s := AnalyticWithinOn 𝕜 (I ∘ f ∘ I.symm) (I.symm ⁻¹' s ∩ range I)
+ property f s := AnalyticOn 𝕜 (I ∘ f ∘ I.symm) (I.symm ⁻¹' s ∩ range I)
comp {f g u v} hf hg _ _ _ := by
have : I ∘ (g ∘ f) ∘ I.symm = (I ∘ g ∘ I.symm) ∘ I ∘ f ∘ I.symm := by ext x; simp
simp only [this]
@@ -57,12 +55,12 @@ def analyticPregroupoid : Pregroupoid H where
· rintro x ⟨hx1, _⟩
simpa only [mfld_simps] using hx1.2
id_mem := by
- apply (analyticOn_id 𝕜).analyticWithinOn.congr
+ apply analyticOn_id.congr
rintro x ⟨_, hx2⟩
obtain ⟨y, hy⟩ := mem_range.1 hx2
simp only [mfld_simps, ← hy]
locality {f u} _ H := by
- apply analyticWithinOn_of_locally_analyticWithinOn
+ apply analyticOn_of_locally_analyticOn
rintro y ⟨hy1, hy2⟩
obtain ⟨x, hx⟩ := mem_range.1 hy2
simp only [mfld_simps, ← hx] at hy1 ⊢
@@ -77,9 +75,10 @@ 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 `AnalyticWithinOn` when read in `E` through `I`. Using `AnalyticWithinOn`
-rather than `AnalyticOn` gives us meaningful definitions at boundary points. -/
+`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. -/
def analyticGroupoid : StructureGroupoid H :=
(analyticPregroupoid I).groupoid
@@ -87,10 +86,10 @@ def analyticGroupoid : StructureGroupoid H :=
theorem ofSet_mem_analyticGroupoid {s : Set H} (hs : IsOpen s) :
PartialHomeomorph.ofSet s hs ∈ analyticGroupoid I := by
rw [analyticGroupoid, mem_groupoid_of_pregroupoid]
- suffices h : AnalyticWithinOn 𝕜 (I ∘ I.symm) (I.symm ⁻¹' s ∩ range I) by
+ suffices h : AnalyticOn 𝕜 (I ∘ I.symm) (I.symm ⁻¹' s ∩ range I) by
simp [h, analyticPregroupoid]
- have hi : AnalyticWithinOn 𝕜 id (univ : Set E) := (analyticOn_id _).analyticWithinOn
- exact (hi.mono (subset_univ _)).congr (fun x hx ↦ (I.right_inv hx.2).symm)
+ have hi : AnalyticOn 𝕜 id (univ : Set E) := analyticOn_id
+ exact (hi.mono (subset_univ _)).congr (fun x hx ↦ I.right_inv hx.2)
/-- The composition of a partial homeomorphism from `H` to `M` and its inverse belongs to
the analytic groupoid. -/
@@ -98,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) :=
@@ -106,40 +105,40 @@ 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} :
f ∈ analyticGroupoid I ↔
- AnalyticWithinOn 𝕜 (I ∘ f ∘ I.symm) (I.symm ⁻¹' f.source ∩ range I) ∧
- AnalyticWithinOn 𝕜 (I ∘ f.symm ∘ I.symm) (I.symm ⁻¹' f.target ∩ range I) := by
+ AnalyticOn 𝕜 (I ∘ f ∘ I.symm) (I.symm ⁻¹' f.source ∩ range I) ∧
+ AnalyticOn 𝕜 (I ∘ f.symm ∘ I.symm) (I.symm ⁻¹' f.target ∩ range I) := by
rfl
/-- The analytic groupoid on a boundaryless charted space modeled on a complete vector space
consists of the partial homeomorphisms which are analytic and have analytic inverse. -/
theorem mem_analyticGroupoid_of_boundaryless [I.Boundaryless] (e : PartialHomeomorph H H) :
- e ∈ analyticGroupoid I ↔ AnalyticOn 𝕜 (I ∘ e ∘ I.symm) (I '' e.source) ∧
- AnalyticOn 𝕜 (I ∘ e.symm ∘ I.symm) (I '' e.target) := by
+ e ∈ analyticGroupoid I ↔ AnalyticOnNhd 𝕜 (I ∘ e ∘ I.symm) (I '' e.source) ∧
+ AnalyticOnNhd 𝕜 (I ∘ e.symm ∘ I.symm) (I '' e.target) := by
simp only [mem_analyticGroupoid, I.range_eq_univ, inter_univ, I.image_eq]
- rw [IsOpen.analyticWithinOn_iff_analyticOn, IsOpen.analyticWithinOn_iff_analyticOn]
+ rw [IsOpen.analyticOn_iff_analyticOnNhd, IsOpen.analyticOn_iff_analyticOnNhd]
· exact I.continuous_symm.isOpen_preimage _ e.open_target
· exact I.continuous_symm.isOpen_preimage _ e.open_source
/-- `analyticGroupoid` is closed under products -/
theorem analyticGroupoid_prod {E A : Type} [NormedAddCommGroup E] [NormedSpace 𝕜 E]
- [CompleteSpace E] [TopologicalSpace A] {F B : Type} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
- [CompleteSpace F] [TopologicalSpace B] {I : ModelWithCorners 𝕜 E A} {J : ModelWithCorners 𝕜 F B}
+ [TopologicalSpace A] {F B : Type} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
+ [TopologicalSpace B] {I : ModelWithCorners 𝕜 E A} {J : ModelWithCorners 𝕜 F B}
{f : PartialHomeomorph A A} {g : PartialHomeomorph B B}
(fa : f ∈ analyticGroupoid I) (ga : g ∈ analyticGroupoid J) :
f.prod g ∈ analyticGroupoid (I.prod J) := by
have pe : range (I.prod J) = (range I).prod (range J) := I.range_prod
simp only [mem_analyticGroupoid, Function.comp, image_subset_iff] at fa ga ⊢
- exact ⟨AnalyticWithinOn.prod
- (fa.1.comp (analyticOn_fst _).analyticWithinOn fun _ m ↦ ⟨m.1.1, (pe ▸ m.2).1⟩)
- (ga.1.comp (analyticOn_snd _).analyticWithinOn fun _ m ↦ ⟨m.1.2, (pe ▸ m.2).2⟩),
- AnalyticWithinOn.prod
- (fa.2.comp (analyticOn_fst _).analyticWithinOn fun _ m ↦ ⟨m.1.1, (pe ▸ m.2).1⟩)
- (ga.2.comp (analyticOn_snd _).analyticWithinOn fun _ m ↦ ⟨m.1.2, (pe ▸ m.2).2⟩)⟩
+ exact ⟨AnalyticOn.prod
+ (fa.1.comp analyticOn_fst fun _ m ↦ ⟨m.1.1, (pe ▸ m.2).1⟩)
+ (ga.1.comp analyticOn_snd fun _ m ↦ ⟨m.1.2, (pe ▸ m.2).2⟩),
+ AnalyticOn.prod
+ (fa.2.comp analyticOn_fst fun _ m ↦ ⟨m.1.1, (pe ▸ m.2).1⟩)
+ (ga.2.comp analyticOn_snd fun _ m ↦ ⟨m.1.2, (pe ▸ m.2).2⟩)⟩
end analyticGroupoid
@@ -155,8 +154,8 @@ instance AnalyticManifold.self : AnalyticManifold 𝓘(𝕜, E) E where
/-- `M × N` is an analytic manifold if `M` and `N` are -/
instance AnalyticManifold.prod {E A : Type} [NormedAddCommGroup E] [NormedSpace 𝕜 E]
- [CompleteSpace E] [TopologicalSpace A] {F B : Type} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
- [CompleteSpace F] [TopologicalSpace B] {I : ModelWithCorners 𝕜 E A} {J : ModelWithCorners 𝕜 F B}
+ [TopologicalSpace A] {F B : Type} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
+ [TopologicalSpace B] {I : ModelWithCorners 𝕜 E A} {J : ModelWithCorners 𝕜 F B}
{M : Type} [TopologicalSpace M] [ChartedSpace A M] [m : AnalyticManifold I M]
{N : Type} [TopologicalSpace N] [ChartedSpace B N] [n : AnalyticManifold J N] :
AnalyticManifold (I.prod J) (M × N) where
@@ -167,7 +166,8 @@ instance AnalyticManifold.prod {E A : Type} [NormedAddCommGroup E] [NormedSpace
(n.toHasGroupoid.compatible hf2 hg2)
/-- Analytic manifolds are smooth manifolds. -/
-instance AnalyticManifold.smoothManifoldWithCorners [ChartedSpace H M] [cm : AnalyticManifold I M] :
+instance AnalyticManifold.smoothManifoldWithCorners [ChartedSpace H M]
+ [cm : AnalyticManifold I M] [CompleteSpace E] :
SmoothManifoldWithCorners I M where
compatible := by
intro f g hf hg
diff --git a/Mathlib/Geometry/Manifold/BumpFunction.lean b/Mathlib/Geometry/Manifold/BumpFunction.lean
index d32ef29050ef2..fa6698b53773a 100644
--- a/Mathlib/Geometry/Manifold/BumpFunction.lean
+++ b/Mathlib/Geometry/Manifold/BumpFunction.lean
@@ -34,7 +34,7 @@ variable {E : Type uE} [NormedAddCommGroup E] [NormedSpace ℝ E]
{H : Type uH} [TopologicalSpace H] {I : ModelWithCorners ℝ E H} {M : Type uM} [TopologicalSpace M]
[ChartedSpace H M]
-open Function Filter FiniteDimensional Set Metric
+open Function Filter Module Set Metric
open scoped Topology Manifold
@@ -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 ac0ff5b1c6d65..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,16 +59,17 @@ 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_iff, 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 ?_ ?_
+ 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)
+ ((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,
- true_and_iff]
+ true_and]
exact mem_range_self _
· filter_upwards [A]
rintro x' ⟨-, hfx'⟩
@@ -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 3dba3c04792f4..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 =>
@@ -96,7 +92,7 @@ protected theorem ContMDiffAt.mfderiv {x₀ : N} (f : N → M → M') (g : N →
rw [contMDiffAt_iff] at hf hg
simp_rw [Function.comp_def, uncurry, extChartAt_prod, PartialEquiv.prod_coe_symm,
ModelWithCorners.range_prod] at hf ⊢
- refine ContDiffWithinAt.fderivWithin ?_ hg.2 I.unique_diff hmn (mem_range_self _) ?_
+ refine ContDiffWithinAt.fderivWithin ?_ hg.2 I.uniqueDiffOn hmn (mem_range_self _) ?_
· simp_rw [extChartAt_to_inv]; exact hf.2
· rw [← image_subset_iff]
rintro _ ⟨x, -, rfl⟩
@@ -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.unique_diff _ <| mem_range_self _)
+ 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⟩⟩`.
@@ -577,7 +571,7 @@ theorem tangentMap_tangentBundle_pure [Is : SmoothManifoldWithCorners I M] (p :
· simp
· exact differentiableAt_id'
· exact differentiableAt_const _
- · exact ModelWithCorners.unique_diff_at_image I
+ · exact ModelWithCorners.uniqueDiffWithinAt_image I
· exact differentiableAt_id'.prod (differentiableAt_const _)
simp (config := { unfoldPartialApp := true }) only [Bundle.zeroSection, tangentMap, mfderiv, A,
if_pos, chartAt, FiberBundle.chartedSpace_chartAt, TangentBundle.trivializationAt_apply,
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 2c6f481393275..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)
@@ -447,7 +445,7 @@ variable (I) (e : E ≃ₘ[𝕜] E')
def transDiffeomorph (I : ModelWithCorners 𝕜 E H) (e : E ≃ₘ[𝕜] E') : ModelWithCorners 𝕜 E' H where
toPartialEquiv := I.toPartialEquiv.trans e.toEquiv.toPartialEquiv
source_eq := by simp
- unique_diff' := by simp [range_comp e, I.unique_diff]
+ uniqueDiffOn' := by simp [range_comp e, I.uniqueDiffOn]
continuous_toFun := e.continuous.comp I.continuous
continuous_invFun := I.continuous_symm.comp e.symm.continuous
@@ -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 32997ffec1950..9b54f975c0526 100644
--- a/Mathlib/Geometry/Manifold/Instances/Real.lean
+++ b/Mathlib/Geometry/Manifold/Instances/Real.lean
@@ -134,9 +134,9 @@ 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
- unique_diff' := by
+ uniqueDiffOn' := by
have : UniqueDiffOn ℝ _ :=
UniqueDiffOn.pi (Fin n) (fun _ => ℝ) _ _ fun i (_ : i ∈ ({0} : Set (Fin n))) =>
uniqueDiffOn_Ici 0
@@ -151,15 +151,15 @@ model for manifolds with corners -/
def modelWithCornersEuclideanQuadrant (n : ℕ) :
ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanQuadrant n) where
toFun := Subtype.val
- invFun x := ⟨fun i => max (x i) 0, fun i => by simp only [le_refl, or_true_iff, le_max_iff]⟩
+ invFun x := ⟨fun i => max (x i) 0, fun i => by simp only [le_refl, or_true, le_max_iff]⟩
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
- unique_diff' := by
+ uniqueDiffOn' := by
have this : UniqueDiffOn ℝ _ :=
UniqueDiffOn.univ_pi (Fin n) (fun _ => ℝ) _ fun _ => uniqueDiffOn_Ici 0
simpa only [pi_univ_Ici] using this
@@ -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 21821c1f74e99..d6924e2d45735 100644
--- a/Mathlib/Geometry/Manifold/Instances/Sphere.lean
+++ b/Mathlib/Geometry/Manifold/Instances/Sphere.lean
@@ -11,6 +11,7 @@ import Mathlib.Analysis.InnerProductSpace.PiL2
import Mathlib.Geometry.Manifold.Algebra.LieGroup
import Mathlib.Geometry.Manifold.Instances.Real
import Mathlib.Geometry.Manifold.MFDeriv.Basic
+import Mathlib.Tactic.Module
/-!
# Manifold structure on the sphere
@@ -66,7 +67,7 @@ variable {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℝ E]
noncomputable section
-open Metric FiniteDimensional Function
+open Metric Module Function
open scoped Manifold
@@ -161,7 +162,7 @@ theorem contDiff_stereoInvFunAux : ContDiff ℝ ⊤ (stereoInvFunAux v) := by
have h₁ : ContDiff ℝ ⊤ fun w : E => (‖w‖ ^ 2 + 4)⁻¹ := by
refine (h₀.add contDiff_const).inv ?_
intro x
- nlinarith
+ positivity
have h₂ : ContDiff ℝ ⊤ fun w => (4 : ℝ) • w + (‖w‖ ^ 2 - 4) • v := by
refine (contDiff_const.smul contDiff_id).add ?_
exact (h₀.sub contDiff_const).smul contDiff_const
@@ -177,15 +178,16 @@ theorem stereoInvFun_apply (hv : ‖v‖ = 1) (w : (ℝ ∙ v)ᗮ) :
(stereoInvFun hv w : E) = (‖w‖ ^ 2 + 4)⁻¹ • ((4 : ℝ) • w + (‖w‖ ^ 2 - 4) • v) :=
rfl
+open scoped InnerProductSpace in
theorem stereoInvFun_ne_north_pole (hv : ‖v‖ = 1) (w : (ℝ ∙ v)ᗮ) :
stereoInvFun hv w ≠ (⟨v, by simp [hv]⟩ : sphere (0 : E) 1) := by
refine Subtype.coe_ne_coe.1 ?_
rw [← inner_lt_one_iff_real_of_norm_one _ hv]
· have hw : ⟪v, w⟫_ℝ = 0 := Submodule.mem_orthogonal_singleton_iff_inner_right.mp w.2
have hw' : (‖(w : E)‖ ^ 2 + 4)⁻¹ * (‖(w : E)‖ ^ 2 - 4) < 1 := by
- refine (inv_mul_lt_iff' ?_).mpr ?_
- · nlinarith
- linarith
+ rw [inv_mul_lt_iff₀']
+ · linarith
+ positivity
simpa [real_inner_comm, inner_add_right, inner_smul_right, real_inner_self_eq_norm_mul_norm, hw,
hv] using hw'
· simpa using stereoInvFunAux_mem hv w.2
@@ -193,6 +195,8 @@ theorem stereoInvFun_ne_north_pole (hv : ‖v‖ = 1) (w : (ℝ ∙ v)ᗮ) :
theorem continuous_stereoInvFun (hv : ‖v‖ = 1) : Continuous (stereoInvFun hv) :=
continuous_induced_rng.2 (contDiff_stereoInvFunAux.continuous.comp continuous_subtype_val)
+open scoped InnerProductSpace in
+attribute [-simp] AddSubgroupClass.coe_norm Submodule.coe_norm in
theorem stereo_left_inv (hv : ‖v‖ = 1) {x : sphere (0 : E) 1} (hx : (x : E) ≠ v) :
stereoInvFun hv (stereoToFun v x) = x := by
ext
@@ -210,57 +214,35 @@ theorem stereo_left_inv (hv : ‖v‖ = 1) {x : sphere (0 : E) 1} (hx : (x : E)
· simp [← split]
· simp [norm_smul, hv, ← sq, sq_abs]
· exact sq _
- -- two facts which will be helpful for clearing denominators in the main calculation
- have ha : 1 - a ≠ 0 := by
+ -- a fact which will be helpful for clearing denominators in the main calculation
+ have ha : 0 < 1 - a := by
have : a < 1 := (inner_lt_one_iff_real_of_norm_one hv (by simp)).mpr hx.symm
linarith
- -- the core of the problem is these two algebraic identities:
- have h₁ : (2 ^ 2 / (1 - a) ^ 2 * ‖y‖ ^ 2 + 4)⁻¹ * 4 * (2 / (1 - a)) = 1 := by
- -- TODO(#15486): used to be `field_simp`, but was really slow
- -- replaced by `simp only ...` to speed up. Reinstate `field_simp` once it is faster.
- simp (disch := field_simp_discharge) only [AddSubgroupClass.coe_norm, div_mul_eq_mul_div,
- div_add', inv_div, mul_div_assoc', div_div, div_eq_iff, one_mul]
- simp only [Submodule.coe_norm] at *; nlinarith only [pythag]
- have h₂ : (2 ^ 2 / (1 - a) ^ 2 * ‖y‖ ^ 2 + 4)⁻¹ * (2 ^ 2 / (1 - a) ^ 2 * ‖y‖ ^ 2 - 4) = a := by
- -- TODO(#15486): used to be `field_simp`, but was really slow
- -- replaced by `simp only ...` to speed up. Reinstate `field_simp` once it is faster.
- simp (disch := field_simp_discharge) only [AddSubgroupClass.coe_norm, div_mul_eq_mul_div,
- div_add', inv_div, div_sub', mul_div_assoc', div_div, div_eq_iff]
- transitivity (1 - a) ^ 2 * (a * (2 ^ 2 * ‖y‖ ^ 2 + 4 * (1 - a) ^ 2))
- · congr
- simp only [Submodule.coe_norm] at *
- nlinarith only [pythag]
- ring!
- convert
- congr_arg₂ Add.add (congr_arg (fun t => t • (y : E)) h₁) (congr_arg (fun t => t • v) h₂) using 1
- · simp only [innerSL_apply, norm_smul, norm_div, RCLike.norm_ofNat, Real.norm_eq_abs,
- AddSubgroupClass.coe_norm, mul_pow, div_pow, sq_abs, SetLike.val_smul, mul_smul, a]
- -- Porting note: used to be simp only [split, add_comm] but get maxRec errors
- rw [split, add_comm]
- ac_rfl
- -- Porting note: this branch did not exit in ml3
- · rw [split, add_comm]
- congr
- dsimp
- rw [one_smul]
+ rw [split, Submodule.coe_smul_of_tower]
+ simp only [norm_smul, norm_div, RCLike.norm_ofNat, Real.norm_eq_abs, abs_of_nonneg ha.le]
+ match_scalars
+ · field_simp
+ linear_combination 4 * (1 - a) * pythag
+ · field_simp
+ linear_combination 4 * (a - 1) ^ 3 * pythag
theorem stereo_right_inv (hv : ‖v‖ = 1) (w : (ℝ ∙ v)ᗮ) : stereoToFun v (stereoInvFun hv w) = w := by
- have : 2 / (1 - (‖(w : E)‖ ^ 2 + 4)⁻¹ * (‖(w : E)‖ ^ 2 - 4)) * (‖(w : E)‖ ^ 2 + 4)⁻¹ * 4 = 1 := by
- -- TODO(#15486): used to be `field_simp`, but was really slow
- -- replaced by `simp only ...` to speed up. Reinstate `field_simp` once it is faster.
- simp (disch := field_simp_discharge) only [inv_eq_one_div, div_mul_eq_mul_div, one_mul,
- sub_div', add_sub_sub_cancel, div_div_eq_mul_div, mul_div_assoc', mul_one, div_div,
- div_eq_iff]
- ring
- convert congr_arg (· • w) this
- · have h₁ : orthogonalProjection (ℝ ∙ v)ᗮ v = 0 :=
- orthogonalProjection_orthogonalComplement_singleton_eq_zero v
- -- Porting note: was innerSL _ and now just inner
- have h₃ : inner v w = (0 : ℝ) := Submodule.mem_orthogonal_singleton_iff_inner_right.mp w.2
- -- Porting note: was innerSL _ and now just inner
- have h₄ : inner v v = (1 : ℝ) := by simp [real_inner_self_eq_norm_mul_norm, hv]
- simp [h₁, h₃, h₄, ContinuousLinearMap.map_add, ContinuousLinearMap.map_smul, mul_smul]
- · simp
+ simp only [stereoToFun, stereoInvFun, stereoInvFunAux, smul_add, map_add, map_smul, innerSL_apply,
+ orthogonalProjection_mem_subspace_eq_self]
+ have h₁ : orthogonalProjection (ℝ ∙ v)ᗮ v = 0 :=
+ orthogonalProjection_orthogonalComplement_singleton_eq_zero v
+ -- Porting note: was innerSL _ and now just inner
+ have h₂ : inner v w = (0 : ℝ) := Submodule.mem_orthogonal_singleton_iff_inner_right.mp w.2
+ -- Porting note: was innerSL _ and now just inner
+ have h₃ : inner v v = (1 : ℝ) := by simp [real_inner_self_eq_norm_mul_norm, hv]
+ rw [h₁, h₂, h₃]
+ match_scalars
+ -- TODO(#15486): used to be `field_simp`, but was really slow
+ -- replaced by `simp only ...` to speed up. Reinstate `field_simp` once it is faster.
+ simp (disch := field_simp_discharge) only [add_div', add_sub_sub_cancel, div_div,
+ div_div_eq_mul_div, div_eq_iff, div_mul_eq_mul_div, inv_eq_one_div,
+ mul_div_assoc', mul_one, mul_zero, one_mul, smul_eq_mul, sub_div', zero_add, zero_div, zero_mul]
+ ring
/-- Stereographic projection from the unit sphere in `E`, centred at a unit vector `v` in `E`;
this is the version as a partial homeomorphism. -/
@@ -372,6 +354,8 @@ end ChartedSpace
section SmoothManifold
+open scoped InnerProductSpace
+
theorem sphere_ext_iff (u v : sphere (0 : E) 1) : u = v ↔ ⟪(u : E), v⟫_ℝ = 1 := by
simp [Subtype.ext_iff, inner_eq_one_iff_of_norm_one]
@@ -405,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,
@@ -455,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
@@ -493,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 01130e726c4b7..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 -/
@@ -266,7 +268,7 @@ lemma IsIntegralCurveAt.comp_mul_ne_zero (hγ : IsIntegralCurveAt γ v t₀) {a
convert h.comp_mul a
ext t
rw [mem_setOf_eq, Metric.mem_ball, Metric.mem_ball, Real.dist_eq, Real.dist_eq,
- lt_div_iff (abs_pos.mpr ha), ← abs_mul, sub_mul, div_mul_cancel₀ _ ha]
+ lt_div_iff₀ (abs_pos.mpr ha), ← abs_mul, sub_mul, div_mul_cancel₀ _ ha]
lemma isIntegralCurveAt_comp_mul_ne_zero {a : ℝ} (ha : a ≠ 0) :
IsIntegralCurveAt γ v t₀ ↔ IsIntegralCurveAt (γ ∘ (· * a)) (a • v) (t₀ / a) := by
@@ -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 0fff8f9f28819..1a9bf211ea412 100644
--- a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean
+++ b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean
@@ -68,7 +68,7 @@ structure LocalInvariantProp (P : (H → H') → Set H → H → Prop) : Prop wh
left_invariance' : ∀ {s x f} {e' : PartialHomeomorph H' H'},
e' ∈ G' → s ⊆ f ⁻¹' e'.source → f x ∈ e'.source → P f s x → P (e' ∘ f) s x
-variable {G G'} {P : (H → H') → Set H → H → Prop} {s t u : Set H} {x : H}
+variable {G G'} {P : (H → H') → Set H → H → Prop}
variable (hG : G.LocalInvariantProp G' P)
include hG
@@ -272,8 +272,8 @@ theorem liftPropWithinAt_indep_chart_aux (he : e ∈ G.maximalAtlas M) (xe : x
(xf : g x ∈ f.source) (hf' : f' ∈ G'.maximalAtlas M') (xf' : g x ∈ f'.source)
(hgs : ContinuousWithinAt g s x) :
P (f ∘ g ∘ e.symm) (e.symm ⁻¹' s) (e x) ↔ P (f' ∘ g ∘ e'.symm) (e'.symm ⁻¹' s) (e' x) := by
- rw [← Function.comp.assoc, hG.liftPropWithinAt_indep_chart_source_aux (f ∘ g) he xe he' xe',
- Function.comp.assoc, hG.liftPropWithinAt_indep_chart_target_aux xe' hf xf hf' xf' hgs]
+ rw [← Function.comp_assoc, hG.liftPropWithinAt_indep_chart_source_aux (f ∘ g) he xe he' xe',
+ Function.comp_assoc, hG.liftPropWithinAt_indep_chart_target_aux xe' hf xf hf' xf' hgs]
theorem liftPropWithinAt_indep_chart [HasGroupoid M G] [HasGroupoid M' G']
(he : e ∈ G.maximalAtlas M) (xe : x ∈ e.source) (hf : f ∈ G'.maximalAtlas M')
@@ -292,9 +292,9 @@ theorem liftPropWithinAt_indep_chart_source [HasGroupoid M G] (he : e ∈ G.maxi
rw [liftPropWithinAt_self_source, liftPropWithinAt_iff',
e.symm.continuousWithinAt_iff_continuousWithinAt_comp_right xe, e.symm_symm]
refine and_congr Iff.rfl ?_
- rw [Function.comp_apply, e.left_inv xe, ← Function.comp.assoc,
+ rw [Function.comp_apply, e.left_inv xe, ← Function.comp_assoc,
hG.liftPropWithinAt_indep_chart_source_aux (chartAt _ (g x) ∘ g) (chart_mem_maximalAtlas G x)
- (mem_chart_source _ x) he xe, Function.comp.assoc]
+ (mem_chart_source _ x) he xe, Function.comp_assoc]
/-- A version of `liftPropWithinAt_indep_chart`, only for the target. -/
theorem liftPropWithinAt_indep_chart_target [HasGroupoid M' G'] (hf : f ∈ G'.maximalAtlas M')
@@ -302,7 +302,7 @@ theorem liftPropWithinAt_indep_chart_target [HasGroupoid M' G'] (hf : f ∈ G'.m
LiftPropWithinAt P g s x ↔ ContinuousWithinAt g s x ∧ LiftPropWithinAt P (f ∘ g) s x := by
rw [liftPropWithinAt_self_target, liftPropWithinAt_iff', and_congr_right_iff]
intro hg
- simp_rw [(f.continuousAt xf).comp_continuousWithinAt hg, true_and_iff]
+ simp_rw [(f.continuousAt xf).comp_continuousWithinAt hg, true_and]
exact hG.liftPropWithinAt_indep_chart_target_aux (mem_chart_source _ _)
(chart_mem_maximalAtlas _ _) (mem_chart_source _ _) hf xf hg
@@ -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]
@@ -430,7 +430,7 @@ theorem liftPropOn_of_liftProp (mono : ∀ ⦃s x t⦄ ⦃f : H → H'⦄, t ⊆
theorem liftPropAt_of_mem_maximalAtlas [HasGroupoid M G] (hG : G.LocalInvariantProp G Q)
(hQ : ∀ y, Q id univ y) (he : e ∈ maximalAtlas M G) (hx : x ∈ e.source) : LiftPropAt Q e x := by
simp_rw [LiftPropAt, hG.liftPropWithinAt_indep_chart he hx G.id_mem_maximalAtlas (mem_univ _),
- (e.continuousAt hx).continuousWithinAt, true_and_iff]
+ (e.continuousAt hx).continuousWithinAt, true_and]
exact hG.congr' (e.eventually_right_inverse' hx) (hQ _)
theorem liftPropOn_of_mem_maximalAtlas [HasGroupoid M G] (hG : G.LocalInvariantProp G Q)
@@ -482,7 +482,7 @@ theorem liftPropOn_of_mem_groupoid (hG : G.LocalInvariantProp G Q) (hQ : ∀ y,
theorem liftProp_id (hG : G.LocalInvariantProp G Q) (hQ : ∀ y, Q id univ y) :
LiftProp Q (id : M → M) := by
- simp_rw [liftProp_iff, continuous_id, true_and_iff]
+ simp_rw [liftProp_iff, continuous_id, true_and]
exact fun x ↦ hG.congr' ((chartAt H x).eventually_right_inverse <| mem_chart_target H x) (hQ _)
theorem liftPropAt_iff_comp_subtype_val (hG : LocalInvariantProp G G' P) {U : Opens M}
@@ -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 5161781aac7d7..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 f9b96b110f3fc..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,12 +42,12 @@ 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
simp only [preimage_univ, univ_inter]
- exact I.unique_diff _ (mem_range_self _)
+ exact I.uniqueDiffOn _ (mem_range_self _)
variable {I}
@@ -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 75f5779ee5a46..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 =
@@ -324,20 +322,18 @@ theorem MDifferentiableAt.mfderiv_prod {f : M → M'} {g : M → M''} {x : M}
classical
simp_rw [mfderiv, if_pos (hf.prod_mk hg), if_pos hf, if_pos hg]
exact hf.differentiableWithinAt_writtenInExtChartAt.fderivWithin_prod
- hg.differentiableWithinAt_writtenInExtChartAt (I.unique_diff _ (mem_range_self _))
-
-variable (I I' I'')
+ hg.differentiableWithinAt_writtenInExtChartAt (I.uniqueDiffOn _ (mem_range_self _))
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 23d818e090332..db39ef95a11c9 100644
--- a/Mathlib/Geometry/Manifold/PartitionOfUnity.lean
+++ b/Mathlib/Geometry/Manifold/PartitionOfUnity.lean
@@ -57,7 +57,7 @@ smooth bump function, partition of unity
universe uι uE uH uM uF
-open Function Filter FiniteDimensional Set
+open Function Filter Module Set
open scoped Topology Manifold
noncomputable section
@@ -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)
@@ -752,7 +751,7 @@ theorem exists_msmooth_support_eq_eq_one_iff
· exact f_diff.div₀ (f_diff.add g_diff) (fun x ↦ ne_of_gt (A x))
-- show that the range is included in `[0, 1]`
· refine range_subset_iff.2 (fun x ↦ ⟨div_nonneg (f_pos x) (A x).le, ?_⟩)
- apply div_le_one_of_le _ (A x).le
+ apply div_le_one_of_le₀ _ (A x).le
simpa only [le_add_iff_nonneg_right] using g_pos x
-- show that the support is `s`
· have B : support (fun x ↦ f x + g x) = univ := eq_univ_of_forall (fun x ↦ (A x).ne')
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 b252d909311ac..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
@@ -138,7 +148,7 @@ structure ModelWithCorners (𝕜 : Type*) [NontriviallyNormedField 𝕜] (E : Ty
[NormedAddCommGroup E] [NormedSpace 𝕜 E] (H : Type*) [TopologicalSpace H] extends
PartialEquiv H E where
source_eq : source = univ
- unique_diff' : UniqueDiffOn 𝕜 toPartialEquiv.target
+ uniqueDiffOn' : UniqueDiffOn 𝕜 toPartialEquiv.target
continuous_toFun : Continuous toFun := by continuity
continuous_invFun : Continuous invFun := by continuity
@@ -149,7 +159,7 @@ def modelWithCornersSelf (𝕜 : Type*) [NontriviallyNormedField 𝕜] (E : Type
[NormedAddCommGroup E] [NormedSpace 𝕜 E] : ModelWithCorners 𝕜 E E where
toPartialEquiv := PartialEquiv.refl E
source_eq := rfl
- unique_diff' := uniqueDiffOn_univ
+ uniqueDiffOn' := uniqueDiffOn_univ
continuous_toFun := continuous_id
continuous_invFun := continuous_id
@@ -236,8 +246,11 @@ theorem target_eq : I.target = range (I : H → E) := by
rw [← image_univ, ← I.source_eq]
exact I.image_source_eq_target.symm
-protected theorem unique_diff : UniqueDiffOn 𝕜 (range I) :=
- I.target_eq ▸ I.unique_diff'
+protected theorem uniqueDiffOn : UniqueDiffOn 𝕜 (range I) :=
+ I.target_eq ▸ I.uniqueDiffOn'
+
+@[deprecated (since := "2024-09-30")]
+protected alias unique_diff := ModelWithCorners.uniqueDiffOn
@[simp, mfld_simps]
protected theorem left_inv (x : H) : I.symm (I x) = x := by refine I.left_inv' ?_; simp
@@ -267,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
@@ -290,17 +306,26 @@ theorem symm_map_nhdsWithin_image {x : H} {s : Set H} : map I.symm (𝓝[I '' s]
theorem symm_map_nhdsWithin_range (x : H) : map I.symm (𝓝[range I] I x) = 𝓝 x := by
rw [← I.map_nhds_eq, map_map, I.symm_comp_self, map_id]
-theorem unique_diff_preimage {s : Set H} (hs : IsOpen s) :
+theorem uniqueDiffOn_preimage {s : Set H} (hs : IsOpen s) :
UniqueDiffOn 𝕜 (I.symm ⁻¹' s ∩ range I) := by
rw [inter_comm]
- exact I.unique_diff.inter (hs.preimage I.continuous_invFun)
+ exact I.uniqueDiffOn.inter (hs.preimage I.continuous_invFun)
+
+@[deprecated (since := "2024-09-30")]
+alias unique_diff_preimage := uniqueDiffOn_preimage
-theorem unique_diff_preimage_source {β : Type*} [TopologicalSpace β] {e : PartialHomeomorph H β} :
+theorem uniqueDiffOn_preimage_source {β : Type*} [TopologicalSpace β] {e : PartialHomeomorph H β} :
UniqueDiffOn 𝕜 (I.symm ⁻¹' e.source ∩ range I) :=
- I.unique_diff_preimage e.open_source
+ I.uniqueDiffOn_preimage e.open_source
+
+@[deprecated (since := "2024-09-30")]
+alias unique_diff_preimage_source := uniqueDiffOn_preimage_source
+
+theorem uniqueDiffWithinAt_image {x : H} : UniqueDiffWithinAt 𝕜 (range I) (I x) :=
+ I.uniqueDiffOn _ (mem_range_self _)
-theorem unique_diff_at_image {x : H} : UniqueDiffWithinAt 𝕜 (range I) (I x) :=
- I.unique_diff _ (mem_range_self _)
+@[deprecated (since := "2024-09-30")]
+alias unique_diff_at_image := uniqueDiffWithinAt_image
theorem symm_continuousWithinAt_comp_right_iff {X} [TopologicalSpace X] {f : H → X} {s : Set H}
{x : H} :
@@ -309,7 +334,7 @@ theorem symm_continuousWithinAt_comp_right_iff {X} [TopologicalSpace X] {f : H
· have := h.comp I.continuousWithinAt (mapsTo_preimage _ _)
simp_rw [preimage_inter, preimage_preimage, I.left_inv, preimage_id', preimage_range,
inter_univ] at this
- rwa [Function.comp.assoc, I.symm_comp_self] at this
+ rwa [Function.comp_assoc, I.symm_comp_self] at this
· rw [← I.left_inv x] at h; exact h.comp I.continuousWithinAt_symm inter_subset_left
protected theorem locallyCompactSpace [LocallyCompactSpace E] (I : ModelWithCorners 𝕜 E H) :
@@ -326,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
@@ -369,9 +394,9 @@ def ModelWithCorners.prod {𝕜 : Type u} [NontriviallyNormedField 𝕜] {E : Ty
invFun := fun x => (I.symm x.1, I'.symm x.2)
source := { x | x.1 ∈ I.source ∧ x.2 ∈ I'.source }
source_eq := by simp only [setOf_true, mfld_simps]
- unique_diff' := I.unique_diff'.prod I'.unique_diff'
- continuous_toFun := I.continuous_toFun.prod_map I'.continuous_toFun
- continuous_invFun := I.continuous_invFun.prod_map I'.continuous_invFun }
+ uniqueDiffOn' := I.uniqueDiffOn'.prod I'.uniqueDiffOn'
+ continuous_toFun := I.continuous_toFun.prodMap I'.continuous_toFun
+ continuous_invFun := I.continuous_invFun.prodMap I'.continuous_invFun }
/-- Given a finite family of `ModelWithCorners` `I i` on `(E i, H i)`, we define the model with
corners `pi I` on `(Π i, E i, ModelPi H)`. See note [Manifold type tags] for explanation about
@@ -382,7 +407,7 @@ def ModelWithCorners.pi {𝕜 : Type u} [NontriviallyNormedField 𝕜] {ι : Typ
ModelWithCorners 𝕜 (∀ i, E i) (ModelPi H) where
toPartialEquiv := PartialEquiv.pi fun i => (I i).toPartialEquiv
source_eq := by simp only [pi_univ, mfld_simps]
- unique_diff' := UniqueDiffOn.pi ι E _ _ fun i _ => (I i).unique_diff'
+ uniqueDiffOn' := UniqueDiffOn.pi ι E _ _ fun i _ => (I i).uniqueDiffOn'
continuous_toFun := continuous_pi fun i => (I i).continuous.comp (continuous_apply i)
continuous_invFun := continuous_pi fun i => (I i).continuous_symm.comp (continuous_apply i)
@@ -395,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]
@@ -471,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
@@ -514,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
@@ -545,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
@@ -562,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']
@@ -591,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
@@ -645,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 _
@@ -654,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'
@@ -696,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 :=
@@ -728,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
@@ -743,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]
@@ -783,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 ?_
@@ -797,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
@@ -805,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]
@@ -834,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 :=
@@ -843,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} :
@@ -856,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}
@@ -910,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
@@ -925,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]
@@ -965,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`. -/
@@ -1009,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)
@@ -1017,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⟩
@@ -1027,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]
@@ -1039,86 +1065,88 @@ 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]
- exact I.unique_diff_preimage (chartAt H x).open_target
+ exact I.uniqueDiffOn_preimage (chartAt H x).open_target
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
@@ -1128,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. -/
@@ -1246,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]
@@ -1351,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/FiberwiseLinear.lean b/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean
index 4b107cd53d598..2a0e077c860aa 100644
--- a/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean
+++ b/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean
@@ -122,7 +122,7 @@ theorem SmoothFiberwiseLinear.locality_aux₁ (e : PartialHomeomorph (B × F) (B
have hu' : ∀ p : e.source, (p : B × F).fst ∈ u p := by
intro p
have : (p : B × F) ∈ e.source ∩ s p := ⟨p.prop, hsp p⟩
- simpa only [hesu, mem_prod, mem_univ, and_true_iff] using this
+ simpa only [hesu, mem_prod, mem_univ, and_true] using this
have heu : ∀ p : e.source, ∀ q : B × F, q.fst ∈ u p → q ∈ e.source := by
intro p q hq
have : q ∈ u p ×ˢ (univ : Set F) := ⟨hq, trivial⟩
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 ff5840676376f..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.MFDeriv.Basic
-import Mathlib.Topology.ContinuousFunction.Basic
import Mathlib.Geometry.Manifold.Algebra.LieGroup
+import Mathlib.Geometry.Manifold.MFDeriv.Basic
+import Mathlib.Topology.ContinuousMap.Basic
+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 fed71bc4299df..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. -/
@@ -55,17 +58,17 @@ theorem contDiffOn_fderiv_coord_change (i j : atlas H M) :
have h : ((i.1.extend I).symm ≫ j.1.extend I).source ⊆ range I := by
rw [i.1.extend_coord_change_source]; apply image_subset_range
intro x hx
- refine (ContDiffWithinAt.fderivWithin_right ?_ I.unique_diff 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 (ContDiffWithinAt.fderivWithin_right ?_ I.uniqueDiffOn le_top <| h hx).mono h
+ 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
```
@@ -84,36 +87,34 @@ def tangentBundleCore : VectorBundleCore 𝕜 M E (atlas H M) where
coordChange_self i x hx v := by
simp only
rw [Filter.EventuallyEq.fderivWithin_eq, fderivWithin_id', ContinuousLinearMap.id_apply]
- · exact I.unique_diff_at_image
- · filter_upwards [i.1.extend_target_mem_nhdsWithin I hx] with y hy
+ · exact I.uniqueDiffWithinAt_image
+ · 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.unique_diff_at_image
- · rw [Function.comp_apply, i.1.extend_left_inv I hxi]
+ · exact I.uniqueDiffWithinAt_image
+ · 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 e99bb7ea3797f..8106c8dd8e80c 100644
--- a/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean
+++ b/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean
@@ -31,7 +31,7 @@ variable {ι : Type uι} {E : Type uE} [NormedAddCommGroup E] [NormedSpace ℝ E
[FiniteDimensional ℝ E] {H : Type uH} [TopologicalSpace H] {I : ModelWithCorners ℝ E H}
{M : Type uM} [TopologicalSpace M] [ChartedSpace H M] [SmoothManifoldWithCorners I M]
-open Function Filter FiniteDimensional Set
+open Function Filter Module Set
open scoped Manifold
noncomputable section
@@ -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 5c5349f4adc95..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']
@@ -167,7 +167,7 @@ noncomputable def invApp (U : Opens X) :
@[simp, reassoc]
theorem inv_naturality {U V : (Opens X)ᵒᵖ} (i : U ⟶ V) :
- X.presheaf.map i ≫ H.invApp (unop V) =
+ X.presheaf.map i ≫ H.invApp _ (unop V) =
invApp f (unop U) ≫ Y.presheaf.map (opensFunctor f |>.op.map i) := by
simp only [invApp, ← Category.assoc]
rw [IsIso.comp_inv_eq]
@@ -179,11 +179,11 @@ theorem inv_naturality {U V : (Opens X)ᵒᵖ} (i : U ⟶ V) :
instance (U : Opens X) : IsIso (invApp f U) := by delta invApp; infer_instance
theorem inv_invApp (U : Opens X) :
- inv (H.invApp U) =
+ inv (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])) := by
- rw [← cancel_epi (H.invApp U), IsIso.hom_inv_id]
+ rw [← cancel_epi (H.invApp _ U), IsIso.hom_inv_id]
delta invApp
simp [← Functor.map_comp]
@@ -195,7 +195,7 @@ theorem invApp_app (U : Opens X) :
@[simp, reassoc]
theorem app_invApp (U : Opens Y) :
- f.c.app (op U) ≫ H.invApp ((Opens.map f.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.base U.1)).op :
op U ⟶ op (opensFunctor f |>.obj ((Opens.map f.base).obj U))) := by
@@ -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,8 +243,8 @@ 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) :
- (PresheafedSpace.IsOpenImmersion.ofRestrict X h).invApp U = 𝟙 _ := by
+ {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]
change X.presheaf.map _ = X.presheaf.map _
@@ -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,11 +286,11 @@ 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 =>
- hf.invApp (unop U) ≫
+ hf.invApp _ (unop U) ≫
g.c.app (op (hf.base_open.isOpenMap.functor.obj (unop U))) ≫
Y.presheaf.map
(eqToHom
@@ -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 }
@@ -772,21 +772,21 @@ noncomputable def invApp (U : Opens X) :
@[reassoc (attr := simp)]
theorem inv_naturality {U V : (Opens X)ᵒᵖ} (i : U ⟶ V) :
- X.presheaf.map i ≫ H.invApp (unop V) =
- H.invApp (unop U) ≫ Y.presheaf.map (opensFunctor f |>.op.map i) :=
+ X.presheaf.map i ≫ H.invApp _ (unop V) =
+ H.invApp _ (unop U) ≫ Y.presheaf.map (opensFunctor f |>.op.map i) :=
PresheafedSpace.IsOpenImmersion.inv_naturality f i
-instance (U : Opens X) : IsIso (H.invApp U) := by delta invApp; infer_instance
+instance (U : Opens X) : IsIso (H.invApp _ U) := by delta invApp; infer_instance
theorem inv_invApp (U : Opens X) :
- inv (H.invApp U) =
+ inv (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.inv_invApp f U
@[reassoc (attr := simp)]
theorem invApp_app (U : Opens X) :
- H.invApp U ≫ f.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 U
@@ -794,7 +794,7 @@ attribute [elementwise] invApp_app
@[reassoc (attr := simp)]
theorem app_invApp (U : Opens Y) :
- f.c.app (op U) ≫ H.invApp ((Opens.map f.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.base U.1)).op :
op U ⟶ op (opensFunctor f |>.obj ((Opens.map f.base).obj U))) :=
@@ -812,13 +812,13 @@ 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) :
- (SheafedSpace.IsOpenImmersion.ofRestrict X h).invApp U = 𝟙 _ :=
+ {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
/-- An open immersion is an iso if the underlying continuous map is epi. -/
@@ -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,10 +1157,10 @@ 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)
+ SheafedSpace.IsOpenImmersion.of_stalk_iso _ hf (H := stalk_iso)
end OfStalkIso
@@ -1180,21 +1186,21 @@ noncomputable def invApp (U : Opens X) :
@[reassoc (attr := simp)]
theorem inv_naturality {U V : (Opens X)ᵒᵖ} (i : U ⟶ V) :
- X.presheaf.map i ≫ H.invApp (unop V) =
- H.invApp (unop U) ≫ Y.presheaf.map (opensFunctor f |>.op.map i) :=
+ X.presheaf.map i ≫ H.invApp _ (unop V) =
+ H.invApp _ (unop U) ≫ Y.presheaf.map (opensFunctor f |>.op.map i) :=
PresheafedSpace.IsOpenImmersion.inv_naturality f.1 i
-instance (U : Opens X) : IsIso (H.invApp U) := by delta invApp; infer_instance
+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)) ≫
+ inv (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.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) :
- (LocallyRingedSpace.IsOpenImmersion.ofRestrict X h).invApp U = 𝟙 _ :=
+ {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 b87c5e3e9a630..366aeeda7b4b0 100644
--- a/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean
+++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Topology.Sheaves.Presheaf
import Mathlib.CategoryTheory.Adjunction.FullyFaithful
@@ -58,7 +58,7 @@ attribute [coe] PresheafedSpace.carrier
-- Porting note: we add this instance, as Lean does not reliably use the `CoeOut` instance above
-- in downstream files.
-instance : CoeSort (PresheafedSpace C) Type* where coe := fun X => X.carrier
+instance : CoeSort (PresheafedSpace C) Type* where coe X := X.carrier
-- Porting note: the following lemma is removed because it is a syntactic tauto
/-@[simp]
@@ -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 b5ac976467db8..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,16 +143,15 @@ 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. -/
@[simp, reassoc]
theorem f_invApp_f_app (i j k : D.J) (U : Opens (D.V (i, j)).carrier) :
- (D.f_open i j).invApp U ≫ (D.f i k).c.app _ =
+ (D.f_open i j).invApp _ U ≫ (D.f i k).c.app _ =
(π₁ i, j, k).c.app (op U) ≫
(π₂⁻¹ i, j, k) (unop _) ≫
(D.V _).presheaf.map
@@ -161,7 +163,7 @@ theorem f_invApp_f_app (i j k : D.J) (U : Opens (D.V (i, j)).carrier) :
apply pullback_base)) := by
have := PresheafedSpace.congr_app (@pullback.condition _ _ _ _ _ (D.f i j) (D.f i k) _)
dsimp only [comp_c_app] at this
- rw [← cancel_epi (inv ((D.f_open i j).invApp U)), IsIso.inv_hom_id_assoc,
+ rw [← cancel_epi (inv ((D.f_open i j).invApp _ U)), IsIso.inv_hom_id_assoc,
IsOpenImmersion.inv_invApp]
simp_rw [Category.assoc]
erw [(π₁ i, j, k).c.naturality_assoc, reassoc_of% this, ← Functor.map_comp_assoc,
@@ -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,17 +261,17 @@ 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 _) ≫
+ (D.f_open j i).invApp _ (unop _) ≫
(𝖣.U j).presheaf.map (eqToHom (D.ι_image_preimage_eq i j U)).op
theorem opensImagePreimageMap_app' (i j k : D.J) (U : Opens (D.U i).carrier) :
@@ -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_π]
@@ -436,11 +438,27 @@ abbrev ιInvAppπEqMap {i : D.J} (U : Opens (D.U i).carrier) :=
theorem π_ιInvApp_π (i j : D.J) (U : Opens (D.U i).carrier) :
D.diagramOverOpenπ U i ≫ D.ιInvAppπEqMap U ≫ D.ιInvApp U ≫ D.diagramOverOpenπ U j =
D.diagramOverOpenπ U j := by
- -- Porting note: originally, the proof of monotonicity was left a blank and proved in the end
- -- but Lean 4 doesn't like this any more, so the proof is restructured
- rw [← @cancel_mono (f := (componentwiseDiagram 𝖣.diagram.multispan _).map
- (Quiver.Hom.op (WalkingMultispan.Hom.snd (i, j))) ≫ 𝟙 _) _ _ (by
- rw [Category.comp_id]
+ rw [← @cancel_mono
+ (f := (componentwiseDiagram 𝖣.diagram.multispan _).map
+ (Quiver.Hom.op (WalkingMultispan.Hom.snd (i, j))) ≫ 𝟙 _) ..]
+ · simp_rw [Category.assoc]
+ rw [limit.w_assoc]
+ erw [limit.lift_π_assoc]
+ rw [Category.comp_id, Category.comp_id]
+ change _ ≫ _ ≫ (_ ≫ _) ≫ _ = _
+ rw [congr_app (D.t_id _), id_c_app]
+ simp_rw [Category.assoc]
+ rw [← Functor.map_comp_assoc]
+ -- Porting note (#11224): change `rw` to `erw`
+ erw [IsOpenImmersion.inv_naturality_assoc]
+ erw [IsOpenImmersion.app_invApp_assoc]
+ iterate 3 rw [← Functor.map_comp_assoc]
+ rw [NatTrans.naturality_assoc]
+ erw [← (D.V (i, j)).presheaf.map_comp]
+ convert
+ limit.w (componentwiseDiagram 𝖣.diagram.multispan _)
+ (Quiver.Hom.op (WalkingMultispan.Hom.fst (i, j)))
+ · rw [Category.comp_id]
apply (config := { allowSynthFailures := true }) mono_comp
change Mono ((_ ≫ D.f j i).c.app _)
rw [comp_c_app]
@@ -448,24 +466,7 @@ theorem π_ιInvApp_π (i j : D.J) (U : Opens (D.U i).carrier) :
· erw [D.ι_image_preimage_eq i j U]
infer_instance
· have : IsIso (D.t i j).c := by apply c_isIso_of_iso
- infer_instance)]
- simp_rw [Category.assoc]
- rw [limit.w_assoc]
- erw [limit.lift_π_assoc]
- rw [Category.comp_id, Category.comp_id]
- change _ ≫ _ ≫ (_ ≫ _) ≫ _ = _
- rw [congr_app (D.t_id _), id_c_app]
- simp_rw [Category.assoc]
- rw [← Functor.map_comp_assoc]
- -- Porting note (#11224): change `rw` to `erw`
- erw [IsOpenImmersion.inv_naturality_assoc]
- erw [IsOpenImmersion.app_invApp_assoc]
- iterate 3 rw [← Functor.map_comp_assoc]
- rw [NatTrans.naturality_assoc]
- erw [← (D.V (i, j)).presheaf.map_comp]
- convert
- limit.w (componentwiseDiagram 𝖣.diagram.multispan _)
- (Quiver.Hom.op (WalkingMultispan.Hom.fst (i, j)))
+ infer_instance
/-- `ιInvApp` is the inverse of `D.ι i` on `U`. -/
theorem π_ιInvApp_eq_id (i : D.J) (U : Opens (D.U i).carrier) :
@@ -492,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`.
@@ -662,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 91683f96c4d14..6f94368b8f4a6 100644
--- a/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean
+++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Geometry.RingedSpace.PresheafedSpace
import Mathlib.Topology.Category.TopCat.Limits.Basic
@@ -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 5ec030cd1628c..4a94f1819e128 100644
--- a/Mathlib/Geometry/RingedSpace/SheafedSpace.lean
+++ b/Mathlib/Geometry/RingedSpace/SheafedSpace.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Geometry.RingedSpace.PresheafedSpace.HasColimits
import Mathlib.Geometry.RingedSpace.Stalks
@@ -47,7 +47,7 @@ namespace SheafedSpace
instance coeCarrier : CoeOut (SheafedSpace C) TopCat where coe X := X.carrier
instance coeSort : CoeSort (SheafedSpace C) Type* where
- coe := fun X => X.1
+ coe X := X.1
/-- Extract the `sheaf C (X : Top)` from a `SheafedSpace C`. -/
def sheaf (X : SheafedSpace C) : Sheaf C (X : TopCat) :=
@@ -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 2bff8fe9dea93..8f6f8f792d874 100644
--- a/Mathlib/Geometry/RingedSpace/Stalks.lean
+++ b/Mathlib/Geometry/RingedSpace/Stalks.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Geometry.RingedSpace.PresheafedSpace
import Mathlib.CategoryTheory.Limits.Final
@@ -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 51b0cfca00034..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
@@ -125,7 +127,7 @@ theorem commutator_subset_ker : commutator G ≤ f.ker := by
/-- If `f : G → A` is a group homomorphism to an abelian group, then `lift f` is the unique map
from the abelianization of a `G` to `A` that factors through `f`. -/
def lift : (G →* A) ≃ (Abelianization G →* A) where
- toFun f := QuotientGroup.lift _ f fun _ h => f.mem_ker.2 <| commutator_subset_ker _ h
+ toFun f := QuotientGroup.lift _ f fun _ h => MonoidHom.mem_ker.2 <| commutator_subset_ker _ h
invFun F := F.comp of
left_inv _ := MonoidHom.ext fun _ => rfl
right_inv _ := MonoidHom.ext fun x => QuotientGroup.induction_on x fun _ => rfl
@@ -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 77957e91b3685..a84d8e3053217 100644
--- a/Mathlib/GroupTheory/Archimedean.lean
+++ b/Mathlib/GroupTheory/Archimedean.lean
@@ -25,73 +25,84 @@ is cyclic. (There are several other methods one could use to prove this fact, i
algebraic methods, but none seem to exist in mathlib as of writing. The closest is
`Subgroup.is_cyclic`, but that has not been transferred to `AddSubgroup`.)
+The file also supports multiplicative groups via `MulArchimedean`.
+
The result is also used in `Topology.Instances.Real` as an ingredient in the classification of
subgroups of `ℝ`.
-/
open Set
-variable {G : Type*} [LinearOrderedAddCommGroup G] [Archimedean G]
+variable {G : Type*} [LinearOrderedCommGroup G] [MulArchimedean G]
-/-- Given a subgroup `H` of a decidable linearly ordered archimedean abelian group `G`, if there
-exists a minimal element `a` of `H ∩ G_{>0}` then `H` is generated by `a`. -/
-theorem AddSubgroup.cyclic_of_min {H : AddSubgroup G} {a : G}
- (ha : IsLeast { g : G | g ∈ H ∧ 0 < g } a) : H = AddSubgroup.closure {a} := by
+/-- Given a subgroup `H` of a decidable linearly ordered mul-archimedean abelian group `G`, if there
+exists a minimal element `a` of `H ∩ G_{>1}` then `H` is generated by `a`. -/
+@[to_additive AddSubgroup.cyclic_of_min "Given a subgroup `H` of a decidable linearly ordered
+archimedean abelian group `G`, if there exists a minimal element `a` of `H ∩ G_{>0}` then `H` is
+generated by `a`. "]
+theorem Subgroup.cyclic_of_min {H : Subgroup G} {a : G}
+ (ha : IsLeast { g : G | g ∈ H ∧ 1 < g } a) : H = closure {a} := by
obtain ⟨⟨a_in, a_pos⟩, a_min⟩ := ha
refine le_antisymm ?_ (H.closure_le.mpr <| by simp [a_in])
intro g g_in
- obtain ⟨k, ⟨nonneg, lt⟩, _⟩ := existsUnique_zsmul_near_of_pos' a_pos g
- have h_zero : g - k • a = 0 := by
+ obtain ⟨k, ⟨nonneg, lt⟩, _⟩ := existsUnique_zpow_near_of_one_lt a_pos g
+ have h_zero : g / (a ^ k) = 1 := by
by_contra h
- have h : a ≤ g - k • a := by
+ have h : a ≤ g / (a ^ k) := by
refine a_min ⟨?_, ?_⟩
- · exact AddSubgroup.sub_mem H g_in (AddSubgroup.zsmul_mem H a_in k)
- · exact lt_of_le_of_ne nonneg (Ne.symm h)
- have h' : ¬a ≤ g - k • a := not_le.mpr lt
+ · exact Subgroup.div_mem H g_in (Subgroup.zpow_mem H a_in k)
+ · exact lt_of_le_of_ne (by simpa using nonneg) (Ne.symm h)
+ have h' : ¬a ≤ g / (a ^ k) := not_le.mpr (by simpa [zpow_add_one, div_lt_iff_lt_mul'] using lt)
contradiction
- simp [sub_eq_zero.mp h_zero, AddSubgroup.mem_closure_singleton]
+ simp [div_eq_one.mp h_zero, mem_closure_singleton]
-/-- If a nontrivial additive subgroup of a linear ordered additive commutative group is disjoint
-with the interval `Set.Ioo 0 a` for some positive `a`, then the set of positive elements of this
+/-- If a nontrivial subgroup of a linear ordered commutative group is disjoint
+with the interval `Set.Ioo 1 a` for some `1 < a`, then the set of elements greater than 1 of this
group admits the least element. -/
-theorem AddSubgroup.exists_isLeast_pos {H : AddSubgroup G} (hbot : H ≠ ⊥) {a : G} (h₀ : 0 < a)
- (hd : Disjoint (H : Set G) (Ioo 0 a)) : ∃ b, IsLeast { g : G | g ∈ H ∧ 0 < g } b := by
+@[to_additive "If a nontrivial additive subgroup of a linear ordered additive commutative group is
+disjoint with the interval `Set.Ioo 0 a` for some positive `a`, then the set of positive elements of
+this group admits the least element."]
+theorem Subgroup.exists_isLeast_one_lt {H : Subgroup G} (hbot : H ≠ ⊥) {a : G} (h₀ : 1 < a)
+ (hd : Disjoint (H : Set G) (Ioo 1 a)) : ∃ b, IsLeast { g : G | g ∈ H ∧ 1 < g } b := by
-- todo: move to a lemma?
- have hex : ∀ g > 0, ∃ n : ℕ, g ∈ Ioc (n • a) ((n + 1) • a) := fun g hg => by
- rcases existsUnique_add_zsmul_mem_Ico h₀ 0 (g - a) with ⟨m, ⟨hm, hm'⟩, -⟩
- simp only [zero_add, sub_le_iff_le_add, sub_add_cancel, ← add_one_zsmul] at hm hm'
+ have hex : ∀ g > 1, ∃ n : ℕ, g ∈ Ioc (a ^ n) (a ^ (n + 1)) := fun g hg => by
+ rcases existsUnique_mul_zpow_mem_Ico h₀ 1 (g / a) with ⟨m, ⟨hm, hm'⟩, -⟩
+ simp only [one_mul, div_le_iff_le_mul, div_mul_cancel, ← zpow_add_one] at hm hm'
lift m to ℕ
- · rw [← Int.lt_add_one_iff, ← zsmul_lt_zsmul_iff h₀, zero_zsmul]
+ · rw [← Int.lt_add_one_iff, ← zpow_lt_zpow_iff h₀, zpow_zero]
exact hg.trans_le hm
- · simp only [← Nat.cast_succ, natCast_zsmul] at hm hm'
+ · simp only [← Nat.cast_succ, zpow_natCast] at hm hm'
exact ⟨m, hm', hm⟩
- have : ∃ n : ℕ, Set.Nonempty (H ∩ Ioc (n • a) ((n + 1) • a)) := by
- rcases (bot_or_exists_ne_zero H).resolve_left hbot with ⟨g, hgH, hg₀⟩
- rcases hex |g| (abs_pos.2 hg₀) with ⟨n, hn⟩
- exact ⟨n, _, (@abs_mem_iff (AddSubgroup G) G _ _).2 hgH, hn⟩
+ have : ∃ n : ℕ, Set.Nonempty (H ∩ Ioc (a ^ n) (a ^ (n + 1))) := by
+ rcases (bot_or_exists_ne_one H).resolve_left hbot with ⟨g, hgH, hg₀⟩
+ rcases hex |g|ₘ (one_lt_mabs.2 hg₀) with ⟨n, hn⟩
+ exact ⟨n, _, (@mabs_mem_iff (Subgroup G) G _ _).2 hgH, hn⟩
classical rcases Nat.findX this with ⟨n, ⟨x, hxH, hnx, hxn⟩, hmin⟩
by_contra hxmin
simp only [IsLeast, not_and, mem_setOf_eq, mem_lowerBounds, not_exists, not_forall,
not_le] at hxmin
- rcases hxmin x ⟨hxH, (nsmul_nonneg h₀.le _).trans_lt hnx⟩ with ⟨y, ⟨hyH, hy₀⟩, hxy⟩
+ rcases hxmin x ⟨hxH, (one_le_pow_of_one_le' h₀.le _).trans_lt hnx⟩ with ⟨y, ⟨hyH, hy₀⟩, hxy⟩
rcases hex y hy₀ with ⟨m, hm⟩
cases' lt_or_le m n with hmn hnm
· exact hmin m hmn ⟨y, hyH, hm⟩
- · refine disjoint_left.1 hd (sub_mem hxH hyH) ⟨sub_pos.2 hxy, sub_lt_iff_lt_add'.2 ?_⟩
- calc x ≤ (n + 1) • a := hxn
- _ ≤ (m + 1) • a := nsmul_le_nsmul_left h₀.le (add_le_add_right hnm _)
- _ = m • a + a := succ_nsmul _ _
- _ < y + a := add_lt_add_right hm.1 _
+ · refine disjoint_left.1 hd (div_mem hxH hyH) ⟨one_lt_div'.2 hxy, div_lt_iff_lt_mul'.2 ?_⟩
+ calc x ≤ a^ (n + 1) := hxn
+ _ ≤ a ^ (m + 1) := pow_le_pow_right' h₀.le (add_le_add_right hnm _)
+ _ = a ^ m * a := pow_succ _ _
+ _ < y * a := mul_lt_mul_right' hm.1 _
-/-- If an additive subgroup of a linear ordered additive commutative group is disjoint with the
-interval `Set.Ioo 0 a` for some positive `a`, then this is a cyclic subgroup. -/
-theorem AddSubgroup.cyclic_of_isolated_zero {H : AddSubgroup G} {a : G} (h₀ : 0 < a)
- (hd : Disjoint (H : Set G) (Ioo 0 a)) : ∃ b, H = closure {b} := by
+/-- If a subgroup of a linear ordered commutative group is disjoint with the
+interval `Set.Ioo 1 a` for some `1 < a`, then this is a cyclic subgroup. -/
+@[to_additive AddSubgroup.cyclic_of_isolated_zero "If an additive subgroup of a linear ordered
+additive commutative group is disjoint with the interval `Set.Ioo 0 a` for some positive `a`, then
+this is a cyclic subgroup."]
+theorem Subgroup.cyclic_of_isolated_one {H : Subgroup G} {a : G} (h₀ : 1 < a)
+ (hd : Disjoint (H : Set G) (Ioo 1 a)) : ∃ b, H = closure {b} := by
rcases eq_or_ne H ⊥ with rfl | hbot
- · exact ⟨0, closure_singleton_zero.symm⟩
- · exact (exists_isLeast_pos hbot h₀ hd).imp fun _ => cyclic_of_min
+ · exact ⟨1, closure_singleton_one.symm⟩
+ · exact (exists_isLeast_one_lt hbot h₀ hd).imp fun _ => cyclic_of_min
/-- 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 8185d5ab476bd..cf344500028b4 100644
--- a/Mathlib/GroupTheory/ArchimedeanDensely.lean
+++ b/Mathlib/GroupTheory/ArchimedeanDensely.lean
@@ -4,11 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yakov Pechersky
-/
import Mathlib.GroupTheory.Archimedean
+import Mathlib.Algebra.Group.Equiv.TypeTags
import Mathlib.Algebra.Group.Subgroup.Pointwise
+import Mathlib.Algebra.Order.Group.TypeTags
import Mathlib.Algebra.Order.Hom.Monoid
/-!
-# Archimedean groups are either discrete or densely ordere
+# Archimedean groups are either discrete or densely ordered
This file proves a few additional facts about linearly ordered additive groups which satisfy the
`Archimedean` property --
@@ -19,7 +21,7 @@ They are placed here in a separate file (rather than incorporated as a continuat
`GroupTheory.Archimedean`) because they rely on some imports from pointwise lemmas.
-/
-open Set
+open Multiplicative Set
-- no earlier file imports the necessary requirements for the next two
@@ -32,25 +34,15 @@ This is the stronger version of `AddSubgroup.mem_closure_singleton`."]
lemma Subgroup.mem_closure_singleton_iff_existsUnique_zpow {G : Type*}
[LinearOrderedCommGroup G] {a b : G} (ha : a ≠ 1) :
b ∈ closure {a} ↔ ∃! k : ℤ, a ^ k = b := by
- constructor <;> intro h
- · wlog ha : 1 < a generalizing a b
- · simp only [not_lt] at ha
- rcases ha.eq_or_lt with rfl|ha
- · contradiction
- specialize @this a⁻¹ b (by simpa) (by simpa) (by simpa)
- simp only [inv_zpow'] at this
- obtain ⟨k, rfl, hk'⟩ := this
- refine ⟨-k, rfl, ?_⟩
- intro y hy
- rw [← neg_eq_iff_eq_neg]
- exact hk' _ (by simpa using hy)
- · rw [mem_closure_singleton] at h
- obtain ⟨k, hk⟩ := h
- refine ⟨k, hk, ?_⟩
- rintro l rfl
- rwa [← zpow_right_inj ha, eq_comm]
- · rw [mem_closure_singleton]
- exact h.exists
+ rw [mem_closure_singleton]
+ constructor
+ · suffices Function.Injective (a ^ · : ℤ → G) by
+ rintro ⟨m, rfl⟩
+ exact ⟨m, rfl, fun k hk ↦ this hk⟩
+ rcases ha.lt_or_lt with ha | ha
+ · exact (zpow_right_strictAnti ha).injective
+ · exact (zpow_right_strictMono ha).injective
+ · exact fun h ↦ h.exists
open Subgroup in
/-- In two linearly ordered groups, the closure of an element of one group
@@ -114,12 +106,13 @@ noncomputable def LinearOrderedCommGroup.closure_equiv_closure {G G' : Type*}
generalize_proofs A B C D
simp [zpow_le_zpow_iff ypos, ← zpow_le_zpow_iff xpos, A.choose_spec, B.choose_spec]
-variable {G : Type*} [LinearOrderedAddCommGroup G] [Archimedean G]
+variable {G : Type*} [LinearOrderedCommGroup G] [MulArchimedean G]
-lemma AddSubgroup.isLeast_closure_iff_eq_abs {a b : G} :
- IsLeast {y : G | y ∈ closure ({a} : Set G) ∧ 0 < y} b ↔ b = |a| ∧ 0 < b := by
+@[to_additive]
+lemma Subgroup.isLeast_of_closure_iff_eq_mabs {a b : G} :
+ IsLeast {y : G | y ∈ closure ({a} : Set G) ∧ 1 < y} b ↔ b = |a|ₘ ∧ 1 < b := by
constructor <;> intro h
- · have := cyclic_of_min h
+ · have := Subgroup.cyclic_of_min h
have ha : a ∈ closure ({b} : Set G) := by
simp [← this]
rw [mem_closure_singleton] at ha
@@ -128,31 +121,32 @@ lemma AddSubgroup.isLeast_closure_iff_eq_abs {a b : G} :
simp only [mem_closure_singleton, mem_setOf_eq, ← mul_zsmul] at this
obtain ⟨m, hm⟩ := this.left
have key : m * n = 1 := by
- rw [← zsmul_left_inj this.right, hm, one_zsmul]
+ rw [← zpow_right_inj this.right, zpow_mul', hm, zpow_one]
rw [Int.mul_eq_one_iff_eq_one_or_neg_one] at key
rw [eq_comm]
rcases key with ⟨rfl, rfl⟩|⟨rfl, rfl⟩ <;>
- simp [this.right.le, this.right]
- · wlog ha : 0 ≤ a generalizing a
- · convert @this (-a) ?_ (by simpa using le_of_not_le ha) using 4
+ simp [this.right.le, this.right, mabs]
+ · wlog ha : 1 ≤ a generalizing a
+ · convert @this (a⁻¹) ?_ (by simpa using le_of_not_le ha) using 4
· simp
- · simpa using h
- rw [abs_eq_self.mpr ha] at h
+ · rwa [mabs_inv]
+ rw [mabs, sup_eq_left.mpr ((inv_le_one'.mpr ha).trans ha)] at h
rcases h with ⟨rfl, h⟩
refine ⟨?_, ?_⟩
· simp [h]
· intro x
simp only [mem_closure_singleton, mem_setOf_eq, and_imp, forall_exists_index]
rintro k rfl hk
- rw [← one_zsmul b, ← mul_zsmul, mul_one, zsmul_le_zsmul_iff h, ← zero_add 1,
+ rw [← zpow_one b, ← zpow_mul, one_mul, zpow_le_zpow_iff h, ← zero_add 1,
← Int.lt_iff_add_one_le]
contrapose! hk
- rw [← Left.nonneg_neg_iff, ← neg_zsmul]
- exact zsmul_nonneg ha (by simp [hk])
+ rw [← Left.one_le_inv_iff, ← zpow_neg]
+ exact one_le_zpow ha (by simp [hk])
/-- If an element of a linearly ordered archimedean additive group is the least positive element,
then the whole group is isomorphic (and order-isomorphic) to the integers. -/
-noncomputable def LinearOrderedAddCommGroup.int_orderAddMonoidIso_of_isLeast_pos {x : G}
+noncomputable def LinearOrderedAddCommGroup.int_orderAddMonoidIso_of_isLeast_pos {G : Type*}
+ [LinearOrderedAddCommGroup G] [Archimedean G] {x : G}
(h : IsLeast {y : G | 0 < y} x) : G ≃+o ℤ := by
have : IsLeast {y : G | y ∈ (⊤ : AddSubgroup G) ∧ 0 < y} x := by simpa using h
replace this := AddSubgroup.cyclic_of_min this
@@ -169,10 +163,19 @@ noncomputable def LinearOrderedAddCommGroup.int_orderAddMonoidIso_of_isLeast_pos
let f := closure_equiv_closure x (1 : ℤ) (by simp [h.left.ne'])
exact ((((e.trans e').trans f).trans g').trans g : G ≃+o ℤ)
-variable (G) in
+/-- If an element of a linearly ordered mul-archimedean group is the least element greater than 1,
+then the whole group is isomorphic (and order-isomorphic) to the multiplicative integers. -/
+@[to_additive existing LinearOrderedAddCommGroup.int_orderAddMonoidIso_of_isLeast_pos]
+noncomputable def LinearOrderedCommGroup.multiplicative_int_orderMonoidIso_of_isLeast_one_lt
+ {x : G} (h : IsLeast {y : G | 1 < y} x) : G ≃*o Multiplicative ℤ := by
+ have : IsLeast {y : Additive G | 0 < y} (.ofMul x) := h
+ let f' := LinearOrderedAddCommGroup.int_orderAddMonoidIso_of_isLeast_pos (G := Additive G) this
+ exact ⟨AddEquiv.toMultiplicative' f', by simp⟩
+
/-- Any linearly ordered archimedean additive group is either isomorphic (and order-isomorphic)
to the integers, or is densely ordered. -/
-lemma LinearOrderedAddCommGroup.discrete_or_denselyOrdered :
+lemma LinearOrderedAddCommGroup.discrete_or_denselyOrdered (G : Type*)
+ [LinearOrderedAddCommGroup G] [Archimedean G] :
Nonempty (G ≃+o ℤ) ∨ DenselyOrdered G := by
by_cases H : ∃ x, IsLeast {y : G | 0 < y} x
· obtain ⟨x, hx⟩ := H
@@ -187,3 +190,110 @@ lemma LinearOrderedAddCommGroup.discrete_or_denselyOrdered :
refine ⟨x + z, ?_, ?_⟩
· 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. -/
+@[to_additive existing]
+lemma LinearOrderedCommGroup.discrete_or_denselyOrdered :
+ Nonempty (G ≃*o Multiplicative ℤ) ∨ DenselyOrdered G := by
+ refine (LinearOrderedAddCommGroup.discrete_or_denselyOrdered (Additive G)).imp ?_ id
+ rintro ⟨f, hf⟩
+ exact ⟨AddEquiv.toMultiplicative' f, hf⟩
+
+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₀ˣ), ?_, ?_⟩
+ · simp [zero_lt_iff]
+ · rw [Units.val_lt_val]
+ simp [hz]
+ · obtain ⟨z, hz, hz'⟩ := H.dense (Units.mk0 x hx.ne') (Units.mk0 y (hx.trans h).ne')
+ (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 50ea33f499459..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⟩
@@ -68,19 +68,19 @@ theorem commProb_pos [h : Nonempty M] : 0 < commProb M :=
(pow_pos (Nat.cast_pos.mpr Finite.card_pos) 2)
theorem commProb_le_one : commProb M ≤ 1 := by
- refine div_le_one_of_le ?_ (sq_nonneg (Nat.card M : ℚ))
+ refine div_le_one_of_le₀ ?_ (sq_nonneg (Nat.card M : ℚ))
rw [← Nat.cast_pow, Nat.cast_le, sq, ← Nat.card_prod]
apply Finite.card_subtype_le
variable {M}
theorem commProb_eq_one_iff [h : Nonempty M] :
- commProb M = 1 ↔ Commutative ((· * ·) : M → M → M) := by
+ commProb M = 1 ↔ Std.Commutative ((· * ·) : M → M → M) := by
haveI := Fintype.ofFinite M
rw [commProb, ← Set.coe_setOf, Nat.card_eq_fintype_card, Nat.card_eq_fintype_card]
rw [div_eq_one_iff_eq, ← Nat.cast_pow, Nat.cast_inj, sq, ← card_prod,
set_fintype_card_eq_univ_iff, Set.eq_univ_iff_forall]
- · exact ⟨fun h x y ↦ h (x, y), fun h x ↦ h x.1 x.2⟩
+ · exact ⟨fun h ↦ ⟨fun x y ↦ h (x, y)⟩, fun h x ↦ h.comm x.1 x.2⟩
· exact pow_ne_zero 2 (Nat.cast_ne_zero.mpr card_ne_zero)
variable (G : Type*) [Group G]
@@ -118,8 +118,8 @@ theorem Subgroup.commProb_quotient_le [H.Normal] : commProb (G ⧸ H) ≤ commPr
variable (G)
theorem inv_card_commutator_le_commProb : (↑(Nat.card (commutator G)))⁻¹ ≤ commProb G :=
- (inv_pos_le_iff_one_le_mul (Nat.cast_pos.mpr Finite.card_pos)).mpr
- (le_trans (ge_of_eq (commProb_eq_one_iff.mpr (Abelianization.commGroup G).mul_comm))
+ (inv_le_iff_one_le_mul₀ (Nat.cast_pos.mpr Finite.card_pos)).mpr
+ (le_trans (ge_of_eq (commProb_eq_one_iff.mpr ⟨(Abelianization.commGroup G).mul_comm⟩))
(commutator G).commProb_quotient_le)
-- Construction of group with commuting probability 1/n
@@ -131,6 +131,7 @@ lemma commProb_odd {n : ℕ} (hn : Odd n) :
qify [show 2 ∣ n + 3 by rw [Nat.dvd_iff_mod_eq_zero, Nat.add_mod, Nat.odd_iff.mp hn]]
rw [div_div, ← mul_assoc]
congr
+ norm_num
private lemma div_two_lt {n : ℕ} (h0 : n ≠ 0) : n / 2 < n :=
Nat.div_lt_self (Nat.pos_of_ne_zero h0) (lt_add_one 1)
@@ -141,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 a3011ab4ba7d6..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,137 +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⟩
-
--- Porting note: upgraded to FunLike
-/-- 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' := fun 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`. -/
@@ -200,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,
@@ -333,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
@@ -672,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
@@ -807,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
@@ -850,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**. -/
@@ -935,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 e0f94293ea1b6..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
@@ -364,7 +364,7 @@ theorem rcons_inj {i} : Function.Injective (rcons : Pair M i → Word M) := by
rw [← he] at h'
exact h' rfl
· have : m = m' ∧ w.toList = w'.toList := by
- simpa [cons, rcons, dif_neg hm, dif_neg hm', true_and_iff, eq_self_iff_true, Subtype.mk_eq_mk,
+ simpa [cons, rcons, dif_neg hm, dif_neg hm', eq_self_iff_true, Subtype.mk_eq_mk,
heq_iff_eq, ← Subtype.ext_iff_val] using he
rcases this with ⟨rfl, h⟩
congr
diff --git a/Mathlib/GroupTheory/Coset/Basic.lean b/Mathlib/GroupTheory/Coset/Basic.lean
index 2be6433c200fc..1466feedeb685 100644
--- a/Mathlib/GroupTheory/Coset/Basic.lean
+++ b/Mathlib/GroupTheory/Coset/Basic.lean
@@ -1,11 +1,14 @@
/-
Copyright (c) 2018 Mitchell Rowett. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mitchell Rowett, Scott Morrison
+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,98 +281,42 @@ 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)
-/- 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]⟩
+/-- Given a subgroup `s`, the function that sends a subgroup `t` to the pair consisting of
+its intersection with `s` and its image in the quotient `α ⧸ s` is strictly monotone, even though
+it is not injective in general. -/
+@[to_additive QuotientAddGroup.strictMono_comap_prod_image "Given an additive subgroup `s`,
+the function that sends an additive subgroup `t` to the pair consisting of
+its intersection with `s` and its image in the quotient `α ⧸ s`
+is strictly monotone, even though it is not injective in general."]
+theorem strictMono_comap_prod_image :
+ StrictMono fun t : Subgroup α ↦ (t.comap s.subtype, mk (s := s) '' t) := by
+ refine fun t₁ t₂ h ↦ ⟨⟨Subgroup.comap_mono h.1, Set.image_mono h.1⟩,
+ mt (fun ⟨le1, le2⟩ a ha ↦ ?_) h.2⟩
+ obtain ⟨a', h', eq⟩ := le2 ⟨_, ha, rfl⟩
+ 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
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
@@ -455,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
@@ -475,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)
@@ -502,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]
@@ -688,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 79fd105a82f88..df9e2e1b9a667 100644
--- a/Mathlib/GroupTheory/Coset/Card.lean
+++ b/Mathlib/GroupTheory/Coset/Card.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Mitchell Rowett. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mitchell Rowett, Scott Morrison
+Authors: Mitchell Rowett, Kim Morrison
-/
import Mathlib.GroupTheory.Coset.Basic
import Mathlib.SetTheory.Cardinal.Finite
@@ -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/Coxeter/Inversion.lean b/Mathlib/GroupTheory/Coxeter/Inversion.lean
index b07693855316a..18946d5bd27dc 100644
--- a/Mathlib/GroupTheory/Coxeter/Inversion.lean
+++ b/Mathlib/GroupTheory/Coxeter/Inversion.lean
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mitchell Lee
-/
import Mathlib.GroupTheory.Coxeter.Length
-import Mathlib.Data.ZMod.Parity
import Mathlib.Data.List.GetD
/-!
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 126c81594b8d8..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
@@ -131,7 +131,7 @@ theorem mk_eq_of_doset_eq {H K : Subgroup G} {a b : G} (h : doset a H K = doset
rw [eq]
exact mem_doset.mp (h.symm ▸ mem_doset_self H K b)
-theorem disjoint_out' {H K : Subgroup G} {a b : Quotient H.1 K} :
+theorem disjoint_out' {H K : Subgroup G} {a b : Quotient H K} :
a ≠ b → Disjoint (doset a.out' H K) (doset b.out' (H : Set G) K) := by
contrapose!
intro h
@@ -140,7 +140,7 @@ theorem disjoint_out' {H K : Subgroup G} {a b : Quotient H.1 K} :
theorem union_quotToDoset (H K : Subgroup G) : ⋃ q, quotToDoset H K q = Set.univ := by
ext x
simp only [Set.mem_iUnion, quotToDoset, mem_doset, SetLike.mem_coe, exists_prop, Set.mem_univ,
- iff_true_iff]
+ iff_true]
use mk H K x
obtain ⟨h, k, h3, h4, h5⟩ := mk_out'_eq_mul H K x
refine ⟨h⁻¹, H.inv_mem h3, k⁻¹, K.inv_mem h4, ?_⟩
@@ -172,19 +172,17 @@ theorem doset_union_leftCoset (H K : Subgroup G) (a : G) :
simp only [hxy, ← mul_assoc, hy, one_mul, inv_mul_cancel, Subgroup.coe_mk, inv_mul_cancel_right]
theorem left_bot_eq_left_quot (H : Subgroup G) :
- Quotient (⊥ : Subgroup G).1 (H : Set G) = (G ⧸ H) := by
+ Quotient (⊥ : Subgroup G) (H : Set G) = (G ⧸ H) := by
unfold Quotient
congr
ext
simp_rw [← bot_rel_eq_leftRel H]
- rfl
theorem right_bot_eq_right_quot (H : Subgroup G) :
- Quotient (H.1 : Set G) (⊥ : Subgroup G) = _root_.Quotient (QuotientGroup.rightRel H) := by
+ Quotient (H : Set G) (⊥ : Subgroup G) = _root_.Quotient (QuotientGroup.rightRel H) := by
unfold Quotient
congr
ext
simp_rw [← rel_bot_eq_right_group_rel H]
- rfl
end Doset
diff --git a/Mathlib/GroupTheory/Exponent.lean b/Mathlib/GroupTheory/Exponent.lean
index 94ce55d4cf069..f408bce7cb363 100644
--- a/Mathlib/GroupTheory/Exponent.lean
+++ b/Mathlib/GroupTheory/Exponent.lean
@@ -452,7 +452,7 @@ theorem exists_orderOf_eq_exponent (hG : ExponentExists G) : ∃ g : G, orderOf
rw [(Commute.all _ g).orderOf_mul_eq_mul_orderOf_of_coprime hcoprime, hpk',
hg, ha, hk, pow_add, pow_add, pow_one, ← mul_assoc, ← mul_assoc,
Nat.div_mul_cancel, mul_assoc, lt_mul_iff_one_lt_right <| hG.orderOf_pos t, ← pow_succ]
- · exact one_lt_pow hp.one_lt a.succ_ne_zero
+ · exact one_lt_pow₀ hp.one_lt a.succ_ne_zero
· exact hpk
@[to_additive]
diff --git a/Mathlib/GroupTheory/FiniteAbelian.lean b/Mathlib/GroupTheory/FiniteAbelian.lean
index 0e74393883b9e..8ac8ceb36aec7 100644
--- a/Mathlib/GroupTheory/FiniteAbelian.lean
+++ b/Mathlib/GroupTheory/FiniteAbelian.lean
@@ -148,7 +148,7 @@ lemma equiv_directSum_zmod_of_finite' (G : Type*) [AddCommGroup G] [Finite G] :
refine ⟨{i : ι // n i ≠ 0}, inferInstance, fun i ↦ p i ^ n i, ?_,
⟨e.trans (directSumNeZeroMulEquiv ι _ _).symm⟩⟩
rintro ⟨i, hi⟩
- exact one_lt_pow (hp _).one_lt hi
+ exact one_lt_pow₀ (hp _).one_lt hi
theorem finite_of_fg_torsion [hG' : AddGroup.FG G] (hG : AddMonoid.IsTorsion G) : Finite G :=
@Module.finite_of_fg_torsion _ _ _ (Module.Finite.iff_addGroup_fg.mpr hG') <|
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/FixedPointFree.lean b/Mathlib/GroupTheory/FixedPointFree.lean
index 2f9fb7c2c40f9..a91326561faf5 100644
--- a/Mathlib/GroupTheory/FixedPointFree.lean
+++ b/Mathlib/GroupTheory/FixedPointFree.lean
@@ -54,8 +54,8 @@ theorem prod_pow_eq_one (hφ : FixedPointFree φ) {n : ℕ} (hn : φ^[n] = _root
theorem coe_eq_inv_of_sq_eq_one (hφ : FixedPointFree φ) (h2 : φ^[2] = _root_.id) : ⇑φ = (·⁻¹) := by
ext g
- have key : 1 * g * φ g = 1 := hφ.prod_pow_eq_one h2 g
- rwa [one_mul, ← inv_eq_iff_mul_eq_one, eq_comm] at key
+ have key : g * φ g = 1 := by simpa [List.range_succ] using hφ.prod_pow_eq_one h2 g
+ rwa [← inv_eq_iff_mul_eq_one, eq_comm] at key
section Involutive
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/FreeAbelianGroupFinsupp.lean b/Mathlib/GroupTheory/FreeAbelianGroupFinsupp.lean
index 8cc24301aaf7c..477433e03185a 100644
--- a/Mathlib/GroupTheory/FreeAbelianGroupFinsupp.lean
+++ b/Mathlib/GroupTheory/FreeAbelianGroupFinsupp.lean
@@ -153,7 +153,7 @@ theorem support_zsmul (k : ℤ) (h : k ≠ 0) (a : FreeAbelianGroup X) :
support (k • a) = support a := by
ext x
simp only [mem_support_iff, AddMonoidHom.map_zsmul]
- simp only [h, zsmul_int_int, false_or_iff, Ne, mul_eq_zero]
+ simp only [h, zsmul_int_int, false_or, Ne, mul_eq_zero]
@[simp]
theorem support_nsmul (k : ℕ) (h : k ≠ 0) (a : FreeAbelianGroup X) :
diff --git a/Mathlib/GroupTheory/FreeGroup/Basic.lean b/Mathlib/GroupTheory/FreeGroup/Basic.lean
index 0718b7ca18057..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
@@ -128,7 +127,7 @@ theorem not_step_nil : ¬Step [] L := by
generalize h' : [] = L'
intro h
cases' h with L₁ L₂
- simp [List.nil_eq_append] at h'
+ simp [List.nil_eq_append_iff] at h'
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
@@ -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."]
@@ -287,7 +286,8 @@ theorem red_iff_irreducible {x1 b1 x2 b2} (h : (x1, b1) ≠ (x2, b2)) :
generalize eq : [(x1, not b1), (x2, b2)] = L'
intro L h'
cases h'
- simp [List.cons_eq_append, List.nil_eq_append] at eq
+ simp only [List.cons_eq_append_iff, List.cons.injEq, Prod.mk.injEq, and_false,
+ List.nil_eq_append_iff, exists_const, or_self, or_false, List.cons_ne_nil] at eq
rcases eq with ⟨rfl, ⟨rfl, rfl⟩, ⟨rfl, rfl⟩, rfl⟩
simp at h
@@ -368,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₂ :=
@@ -528,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
@@ -568,10 +574,10 @@ 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 := one_mul _
+ left_inv f := List.prod_singleton
right_inv g :=
MonoidHom.ext <| by
rintro ⟨L⟩
@@ -592,7 +598,7 @@ theorem lift.mk : lift f (mk L) = List.prod (L.map fun x => cond x.2 (f x.1) (f
@[to_additive (attr := simp)]
theorem lift.of {x} : lift f (of x) = f x :=
- one_mul _
+ List.prod_singleton
@[to_additive]
theorem lift.unique (g : FreeGroup α →* β) (hg : ∀ x, g (FreeGroup.of x) = f x) {x} :
@@ -838,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
@@ -855,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
@@ -910,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
@@ -1055,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⟩
@@ -1064,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
@@ -1125,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 α]
@@ -1146,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
@@ -1157,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/Pointwise.lean b/Mathlib/GroupTheory/GroupAction/Pointwise.lean
index 091782116de91..4a0bf768bba53 100644
--- a/Mathlib/GroupTheory/GroupAction/Pointwise.lean
+++ b/Mathlib/GroupTheory/GroupAction/Pointwise.lean
@@ -4,8 +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, Antoine Chambert-Loir
-/
-
-import Mathlib.Data.Set.Pointwise.SMul
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
import Mathlib.GroupTheory.GroupAction.Hom
/-!
diff --git a/Mathlib/GroupTheory/GroupAction/Quotient.lean b/Mathlib/GroupTheory/GroupAction/Quotient.lean
index 7f128130a1471..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
@@ -363,6 +364,48 @@ instance finite_quotient_of_finite_quotient_of_finite_quotient {H : Subgroup α}
rw [(equivSubgroupOrbits β H).finite_iff]
infer_instance
+/-- Given a group acting freely and transitively, an equivalence between the orbits under the
+action of a subgroup and the quotient group. -/
+@[to_additive "Given an additive group acting freely and transitively, an equivalence between the
+orbits under the action of an additive subgroup and the quotient group."]
+noncomputable def equivSubgroupOrbitsQuotientGroup [IsPretransitive α β]
+ (free : ∀ y : β, MulAction.stabilizer α y = ⊥) (H : Subgroup α) :
+ 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_apply] at h
+ rw [Quotient.eq'', leftRel_eq]
+ dsimp only
+ rcases h with ⟨g, rfl⟩
+ dsimp only
+ suffices (exists_smul_eq α (g • y₂) x).choose = (exists_smul_eq α y₂ x).choose * g⁻¹ by
+ simp [this]
+ rw [← inv_mul_eq_one, ← Subgroup.mem_bot, ← free ((g : α) • y₂)]
+ simp only [mem_stabilizer_iff, smul_smul, mul_assoc, InvMemClass.coe_inv, inv_mul_cancel,
+ mul_one]
+ rw [← smul_smul, (exists_smul_eq α y₂ x).choose_spec, inv_smul_eq_iff,
+ (exists_smul_eq α ((g : α) • y₂) x).choose_spec])
+ invFun := fun q ↦ q.liftOn' (fun g ↦ ⟦g⁻¹ • x⟧) (by
+ intro g₁ g₂ h
+ rw [leftRel_eq] at h
+ simp only
+ 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_apply]
+ convert mem_orbit_self _
+ rw [inv_smul_eq_iff, (exists_smul_eq α y x).choose_spec]
+ right_inv := fun g ↦ by
+ induction' g using Quotient.inductionOn' with g
+ simp only [Quotient.liftOn'_mk'', Quotient.liftOn'_mk, QuotientGroup.mk]
+ rw [Quotient.eq'', leftRel_eq]
+ simp only
+ 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]
+
end MulAction
theorem ConjClasses.card_carrier {G : Type*} [Group G] [Fintype G] (g : G)
diff --git a/Mathlib/GroupTheory/GroupAction/Ring.lean b/Mathlib/GroupTheory/GroupAction/Ring.lean
index 1d669771f20c3..8b637c59b69f7 100644
--- a/Mathlib/GroupTheory/GroupAction/Ring.lean
+++ b/Mathlib/GroupTheory/GroupAction/Ring.lean
@@ -3,8 +3,8 @@ 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.Group.Action.Defs
import Mathlib.Algebra.Ring.Defs
+import Mathlib.Algebra.SMulWithZero
/-!
# Commutativity and associativity of action of integers on rings
@@ -21,6 +21,9 @@ open scoped Int
variable {α : Type*}
+instance NonUnitalNonAssocSemiring.toDistribSMul [NonUnitalNonAssocSemiring α] :
+ DistribSMul α α where smul_add := mul_add
+
/-- Note that `AddMonoid.nat_smulCommClass` requires stronger assumptions on `α`. -/
instance NonUnitalNonAssocSemiring.nat_smulCommClass [NonUnitalNonAssocSemiring α] :
SMulCommClass ℕ α α where
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 d0f3000e1c542..bda425911ec09 100644
--- a/Mathlib/GroupTheory/GroupAction/Support.lean
+++ b/Mathlib/GroupTheory/GroupAction/Support.lean
@@ -3,7 +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.Data.Set.Pointwise.SMul
+import Mathlib.Algebra.Group.Action.Basic
+import Mathlib.Algebra.Group.Pointwise.Set.Basic
/-!
# Support of an element under an action action
@@ -43,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 0fc048268ebf6..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) ⟨?_, ?_⟩)
@@ -158,9 +159,9 @@ theorem index_eq_two_iff : H.index = 2 ↔ ∃ a, ∀ b, Xor' (b * a ∈ H) (b
@[to_additive]
theorem mul_mem_iff_of_index_two (h : H.index = 2) {a b : G} : a * b ∈ H ↔ (a ∈ H ↔ b ∈ H) := by
- by_cases ha : a ∈ H; · simp only [ha, true_iff_iff, mul_mem_cancel_left ha]
- by_cases hb : b ∈ H; · simp only [hb, iff_true_iff, mul_mem_cancel_right hb]
- simp only [ha, hb, iff_self_iff, iff_true_iff]
+ by_cases ha : a ∈ H; · simp only [ha, true_iff, mul_mem_cancel_left ha]
+ by_cases hb : b ∈ H; · simp only [hb, iff_true, mul_mem_cancel_right hb]
+ simp only [ha, hb, iff_true]
rcases index_eq_two_iff.1 h with ⟨c, hc⟩
refine (hc _).or.resolve_left ?_
rwa [mul_assoc, mul_mem_cancel_right ((hc _).or.resolve_right hb)]
@@ -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 988928ee6d456..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'`,
@@ -548,7 +546,7 @@ theorem mk'_spec' (x) (y : S) : f.toMap y * f.mk' x y = f.toMap x := by rw [mul_
@[to_additive]
theorem eq_mk'_iff_mul_eq {x} {y : S} {z} : z = f.mk' x y ↔ z * f.toMap y = f.toMap x :=
- ⟨fun H ↦ by rw [H, mk'_spec], fun H ↦ by erw [mul_inv_right, H]⟩
+ ⟨fun H ↦ by rw [H, mk'_spec], fun H ↦ by rw [mk', mul_inv_right, H]⟩
@[to_additive]
theorem mk'_eq_iff_eq_mul {x} {y : S} {z} : f.mk' x y = z ↔ f.toMap x = z * f.toMap y := by
@@ -773,9 +771,7 @@ theorem lift_comp : (f.lift hg).comp f.toMap = g := by ext; exact f.lift_eq hg _
@[to_additive (attr := simp)]
theorem lift_of_comp (j : N →* P) : f.lift (f.isUnit_comp j) = j := by
ext
- rw [lift_spec]
- show j _ = j _ * _
- erw [← j.map_mul, sec_spec']
+ simp_rw [lift_spec, MonoidHom.comp_apply, ← j.map_mul, sec_spec']
@[to_additive]
theorem epic_of_localizationMap {j k : N →* P} (h : ∀ a, j.comp f.toMap a = k.comp f.toMap a) :
@@ -834,8 +830,8 @@ theorem lift_surjective_iff :
obtain ⟨z, hz⟩ := H v
obtain ⟨x, hx⟩ := f.surj z
use x
- rw [← hz, f.eq_mk'_iff_mul_eq.2 hx, lift_mk', mul_assoc, mul_comm _ (g ↑x.2)]
- erw [IsUnit.mul_liftRight_inv (g.restrict S) hg, mul_one]
+ rw [← hz, f.eq_mk'_iff_mul_eq.2 hx, lift_mk', mul_assoc, mul_comm _ (g ↑x.2),
+ ← MonoidHom.restrict_apply, IsUnit.mul_liftRight_inv (g.restrict S) hg, mul_one]
· intro H v
obtain ⟨x, hx⟩ := H v
use f.mk' x.1 x.2
@@ -997,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
@@ -1131,9 +1036,9 @@ of `AddCommMonoid`s, `k ∘ f` is a Localization map for `M` at `S`."]
def ofMulEquivOfLocalizations (k : N ≃* P) : LocalizationMap S P :=
(k.toMonoidHom.comp f.toMap).toLocalizationMap (fun y ↦ isUnit_comp f k.toMonoidHom y)
(fun v ↦
- let ⟨z, hz⟩ := k.toEquiv.surjective v
+ let ⟨z, hz⟩ := k.surjective v
let ⟨x, hx⟩ := f.surj z
- ⟨x, show v * k _ = k _ by rw [← hx, map_mul, ← hz]; rfl⟩)
+ ⟨x, show v * k _ = k _ by rw [← hx, map_mul, ← hz]⟩)
fun x y ↦ (k.apply_eq_iff_eq.trans f.eq_iff_exists).1
@[to_additive (attr := simp)]
@@ -1162,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
@@ -1172,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
@@ -1203,18 +1106,17 @@ def ofMulEquivOfDom {k : P ≃* M} (H : T.map k.toMonoidHom = S) : LocalizationM
⟨z, hz⟩)
(fun z ↦
let ⟨x, hx⟩ := f.surj z
- let ⟨v, hv⟩ := k.toEquiv.surjective x.1
- let ⟨w, hw⟩ := k.toEquiv.surjective x.2
- ⟨(v, ⟨w, H' ▸ show k w ∈ S from hw.symm ▸ x.2.2⟩),
- show z * f.toMap (k.toEquiv w) = f.toMap (k.toEquiv v) by erw [hv, hw, hx]⟩)
- fun x y ↦
- show f.toMap _ = f.toMap _ → _ by
- erw [f.eq_iff_exists]
- exact
- fun ⟨c, hc⟩ ↦
- let ⟨d, hd⟩ := k.toEquiv.surjective c
- ⟨⟨d, H' ▸ show k d ∈ S from hd.symm ▸ c.2⟩, by
- erw [← hd, ← map_mul k, ← map_mul k] at hc; exact k.toEquiv.injective hc⟩
+ let ⟨v, hv⟩ := k.surjective x.1
+ let ⟨w, hw⟩ := k.surjective x.2
+ ⟨(v, ⟨w, H' ▸ show k w ∈ S from hw.symm ▸ x.2.2⟩), by
+ simp_rw [MonoidHom.comp_apply, MulEquiv.toMonoidHom_eq_coe, MonoidHom.coe_coe, hv, hw, hx]⟩)
+ fun x y ↦ by
+ rw [MonoidHom.comp_apply, MonoidHom.comp_apply, MulEquiv.toMonoidHom_eq_coe,
+ MonoidHom.coe_coe, f.eq_iff_exists]
+ rintro ⟨c, hc⟩
+ let ⟨d, hd⟩ := k.surjective c
+ refine ⟨⟨d, H' ▸ show k d ∈ S from hd.symm ▸ c.2⟩, ?_⟩
+ rw [← hd, ← map_mul k, ← map_mul k] at hc; exact k.injective hc
@[to_additive (attr := simp)]
theorem ofMulEquivOfDom_apply {k : P ≃* M} (H : T.map k.toMonoidHom = S) (x) :
@@ -1326,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 _ _
@@ -1365,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
@@ -1384,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
@@ -1435,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 a4b435fb7cba6..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`. -/
@@ -285,13 +315,14 @@ instance lowerCentralSeries_normal (n : ℕ) : Normal (lowerCentralSeries G n) :
theorem lowerCentralSeries_antitone : Antitone (lowerCentralSeries G) := by
refine antitone_nat_of_succ_le fun n x hx => ?_
simp only [mem_lowerCentralSeries_succ_iff, exists_prop, mem_top, exists_true_left,
- true_and_iff] at hx
+ 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
@@ -811,16 +842,15 @@ theorem isNilpotent_of_finite_tfae :
∀ (p : ℕ) (_hp : Fact p.Prime) (P : Sylow p G), (↑P : Subgroup G).Normal,
Nonempty
((∀ p : (Nat.card G).primeFactors, ∀ P : Sylow p G, (↑P : Subgroup G)) ≃* G)] := by
- tfae_have 1 → 2
- · exact @normalizerCondition_of_isNilpotent _ _
+ tfae_have 1 → 2 := @normalizerCondition_of_isNilpotent _ _
tfae_have 2 → 3
- · exact fun h H => NormalizerCondition.normal_of_coatom H h
+ | h, H => NormalizerCondition.normal_of_coatom H h
tfae_have 3 → 4
- · intro h p _ P; exact Sylow.normal_of_all_max_subgroups_normal h _
+ | h, p, _, P => Sylow.normal_of_all_max_subgroups_normal h _
tfae_have 4 → 5
- · exact fun h => Nonempty.intro (Sylow.directProductOfNormal fun {p hp hP} => h p hp hP)
+ | h => Nonempty.intro (Sylow.directProductOfNormal fun {p hp hP} => h p hp hP)
tfae_have 5 → 1
- · rintro ⟨e⟩; exact isNilpotent_of_product_of_sylow_group e
+ | ⟨e⟩ => isNilpotent_of_product_of_sylow_group e
tfae_finish
@[deprecated (since := "2024-06-05")] alias isNilpotent_of_finite_tFAE := isNilpotent_of_finite_tfae
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 462873bca532e..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 _
@@ -717,7 +733,7 @@ automatic in the case of a finite cancellative monoid. -/
`addOrderOf_nsmul` but with one assumption less which is automatic in the case of a
finite cancellative additive monoid."]
theorem orderOf_pow (x : G) : orderOf (x ^ n) = orderOf x / gcd (orderOf x) n :=
- (isOfFinOrder_of_finite _).orderOf_pow _
+ (isOfFinOrder_of_finite _).orderOf_pow ..
@[to_additive]
theorem mem_powers_iff_mem_range_orderOf [DecidableEq G] :
@@ -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
@@ -1031,8 +1047,8 @@ theorem orderOf_abs_ne_one (h : |x| ≠ 1) : orderOf x = 0 := by
intro n hn hx
replace hx : |x| ^ n = 1 := by simpa only [abs_one, abs_pow] using congr_arg abs hx
cases' h.lt_or_lt with h h
- · exact ((pow_lt_one (abs_nonneg x) h hn.ne').ne hx).elim
- · exact ((one_lt_pow h hn.ne').ne' hx).elim
+ · exact ((pow_lt_one₀ (abs_nonneg x) h hn.ne').ne hx).elim
+ · exact ((one_lt_pow₀ h hn.ne').ne' hx).elim
theorem LinearOrderedRing.orderOf_le_two : orderOf x ≤ 2 := by
cases' ne_or_eq |x| 1 with h h
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 ea820704dd164..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,9 +134,9 @@ 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)⟩
+ hk.symm ▸ one_lt_pow₀ (Fact.out (p := p.Prime)).one_lt (ne_of_gt hk0)⟩
variable {α : Type*} [MulAction G α]
@@ -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⟩
@@ -337,7 +337,7 @@ theorem cyclic_center_quotient_of_card_eq_prime_sq (hG : Nat.card G = p ^ 2) :
/-- A group of order `p ^ 2` is commutative. See also `IsPGroup.commutative_of_card_eq_prime_sq`
for just the proof that `∀ a b, a * b = b * a` -/
def commGroupOfCardEqPrimeSq (hG : Nat.card G = p ^ 2) : CommGroup G :=
- @commGroupOfCycleCenterQuotient _ _ _ _ (cyclic_center_quotient_of_card_eq_prime_sq hG) _
+ @commGroupOfCyclicCenterQuotient _ _ _ _ (cyclic_center_quotient_of_card_eq_prime_sq hG) _
(QuotientGroup.ker_mk' (center G)).le
/-- A group of order `p ^ 2` is commutative. See also `IsPGroup.commGroupOfCardEqPrimeSq`
diff --git a/Mathlib/GroupTheory/Perm/Basic.lean b/Mathlib/GroupTheory/Perm/Basic.lean
index 4ff40a3a4a271..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)
@@ -396,7 +396,7 @@ theorem ofSubtype_apply_of_not_mem (f : Perm (Subtype p)) (ha : ¬p a) : ofSubty
theorem mem_iff_ofSubtype_apply_mem (f : Perm (Subtype p)) (x : α) :
p x ↔ p ((ofSubtype f : α → α) x) :=
if h : p x then by
- simpa only [h, true_iff_iff, MonoidHom.coe_mk, ofSubtype_apply_of_mem f h] using (f ⟨x, h⟩).2
+ simpa only [h, true_iff, MonoidHom.coe_mk, ofSubtype_apply_of_mem f h] using (f ⟨x, h⟩).2
else by simp [h, ofSubtype_apply_of_not_mem f h]
@[simp]
@@ -404,6 +404,16 @@ theorem subtypePerm_ofSubtype (f : Perm (Subtype p)) :
subtypePerm (ofSubtype f) (mem_iff_ofSubtype_apply_mem f) = f :=
Equiv.ext fun x => Subtype.coe_injective (ofSubtype_apply_coe f x)
+theorem ofSubtype_subtypePerm_of_mem {p : α → Prop} [DecidablePred p]
+ {g : Perm α} (hg : ∀ (x : α), p x ↔ p (g x))
+ {a : α} (ha : p a) : (ofSubtype (g.subtypePerm hg)) a = g a :=
+ ofSubtype_apply_of_mem (g.subtypePerm hg) ha
+
+theorem ofSubtype_subtypePerm_of_not_mem {p : α → Prop} [DecidablePred p]
+ {g : Perm α} (hg : ∀ (x : α), p x ↔ p (g x))
+ {a : α} (ha : ¬ p a) : (ofSubtype (g.subtypePerm hg)) a = a :=
+ ofSubtype_apply_of_not_mem (g.subtypePerm hg) ha
+
/-- Permutations on a subtype are equivalent to permutations on the original type that fix pointwise
the rest. -/
@[simps]
diff --git a/Mathlib/GroupTheory/Perm/Closure.lean b/Mathlib/GroupTheory/Perm/Closure.lean
index 6fa1105deb178..9564bafaf6fcc 100644
--- a/Mathlib/GroupTheory/Perm/Closure.lean
+++ b/Mathlib/GroupTheory/Perm/Closure.lean
@@ -40,7 +40,7 @@ theorem closure_isCycle : closure { σ : Perm β | IsCycle σ } = ⊤ := by
variable [DecidableEq α] [Fintype α]
-theorem closure_cycle_adjacent_swap {σ : Perm α} (h1 : IsCycle σ) (h2 : σ.support = ⊤) (x : α) :
+theorem closure_cycle_adjacent_swap {σ : Perm α} (h1 : IsCycle σ) (h2 : σ.support = univ) (x : α) :
closure ({σ, swap x (σ x)} : Set (Perm α)) = ⊤ := by
let H := closure ({σ, swap x (σ x)} : Set (Perm α))
have h3 : σ ∈ H := subset_closure (Set.mem_insert σ _)
@@ -51,8 +51,7 @@ theorem closure_cycle_adjacent_swap {σ : Perm α} (h1 : IsCycle σ) (h2 : σ.su
| zero => exact subset_closure (Set.mem_insert_of_mem _ (Set.mem_singleton _))
| succ n ih =>
convert H.mul_mem (H.mul_mem h3 ih) (H.inv_mem h3)
- simp_rw [mul_swap_eq_swap_mul, mul_inv_cancel_right, pow_succ']
- rfl
+ simp_rw [mul_swap_eq_swap_mul, mul_inv_cancel_right, pow_succ', coe_mul, comp_apply]
have step2 : ∀ n : ℕ, swap x ((σ ^ n) x) ∈ H := by
intro n
induction n with
@@ -70,9 +69,9 @@ theorem closure_cycle_adjacent_swap {σ : Perm α} (h1 : IsCycle σ) (h2 : σ.su
exact H.mul_mem (H.mul_mem (step1 n) ih) (step1 n)
have step3 : ∀ y : α, swap x y ∈ H := by
intro y
- have hx : x ∈ (⊤ : Finset α) := Finset.mem_univ x
+ have hx : x ∈ univ := Finset.mem_univ x
rw [← h2, mem_support] at hx
- have hy : y ∈ (⊤ : Finset α) := Finset.mem_univ y
+ have hy : y ∈ univ := Finset.mem_univ y
rw [← h2, mem_support] at hy
cases' IsCycle.exists_pow_eq h1 hx hy with n hn
rw [← hn]
@@ -97,7 +96,7 @@ theorem closure_cycle_coprime_swap {n : ℕ} {σ : Perm α} (h0 : Nat.Coprime n
closure ({σ, swap x ((σ ^ n) x)} : Set (Perm α)) = ⊤ := by
rw [← Finset.card_univ, ← h2, ← h1.orderOf] at h0
cases' exists_pow_eq_self_of_coprime h0 with m hm
- have h2' : (σ ^ n).support = ⊤ := Eq.trans (support_pow_coprime h0) h2
+ have h2' : (σ ^ n).support = univ := Eq.trans (support_pow_coprime h0) h2
have h1' : IsCycle ((σ ^ n) ^ (m : ℤ)) := by rwa [← hm] at h1
replace h1' : IsCycle (σ ^ n) :=
h1'.of_pow (le_trans (support_pow_le σ n) (ge_of_eq (congr_arg support hm)))
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/ConjAct.lean b/Mathlib/GroupTheory/Perm/ConjAct.lean
new file mode 100644
index 0000000000000..33786abcf6552
--- /dev/null
+++ b/Mathlib/GroupTheory/Perm/ConjAct.lean
@@ -0,0 +1,64 @@
+/-
+Copyright (c) 2024 Antoine Chambert-Loir. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Antoine Chambert-Loir
+-/
+import Mathlib.Algebra.Group.Pointwise.Finset.Basic
+import Mathlib.GroupTheory.GroupAction.ConjAct
+import Mathlib.GroupTheory.Perm.Cycle.Basic
+import Mathlib.GroupTheory.Perm.Cycle.Factors
+import Mathlib.GroupTheory.Perm.Support
+/-! # Some lemmas pertaining to the action of `ConjAct (Perm α)` on `Perm α`
+
+We prove some lemmas related to the action of `ConjAct (Perm α)` on `Perm α`:
+
+Let `α` be a decidable fintype.
+
+* `conj_support_eq` relates the support of `k • g` with that of `g`
+
+* `cycleFactorsFinset_conj_eq`, `mem_cycleFactorsFinset_conj'`
+ and `cycleFactorsFinset_conj` relate the set of cycles of `g`, `g.cycleFactorsFinset`,
+ with that for `k • g`
+
+-/
+
+namespace Equiv.Perm
+
+open scoped Pointwise
+
+variable {α : Type*} [DecidableEq α] [Fintype α]
+
+/-- `a : α` belongs to the support of `k • g` iff
+ `k⁻¹ * a` belongs to the support of `g` -/
+theorem mem_conj_support (k : ConjAct (Perm α)) (g : Perm α) (a : α) :
+ a ∈ (k • g).support ↔ ConjAct.ofConjAct k⁻¹ a ∈ g.support := by
+ simp only [mem_support, ConjAct.smul_def, not_iff_not, coe_mul,
+ Function.comp_apply, ConjAct.ofConjAct_inv]
+ apply Equiv.apply_eq_iff_eq_symm_apply
+
+theorem cycleFactorsFinset_conj (g k : Perm α) :
+ (ConjAct.toConjAct k • g).cycleFactorsFinset =
+ Finset.map (MulAut.conj k).toEquiv.toEmbedding g.cycleFactorsFinset := by
+ ext c
+ rw [ConjAct.smul_def, ConjAct.ofConjAct_toConjAct, Finset.mem_map_equiv,
+ ← mem_cycleFactorsFinset_conj g k]
+ simp only [MulEquiv.toEquiv_eq_coe, MulEquiv.coe_toEquiv_symm, MulAut.conj_symm_apply]
+ group
+
+/-- A permutation `c` is a cycle of `g` iff `k • c` is a cycle of `k • g` -/
+@[simp]
+theorem mem_cycleFactorsFinset_conj'
+ (k : ConjAct (Perm α)) (g c : Perm α) :
+ k • c ∈ (k • g).cycleFactorsFinset ↔ c ∈ g.cycleFactorsFinset := by
+ simp only [ConjAct.smul_def]
+ apply mem_cycleFactorsFinset_conj g k
+
+theorem cycleFactorsFinset_conj_eq
+ (k : ConjAct (Perm α)) (g : Perm α) :
+ cycleFactorsFinset (k • g) = k • cycleFactorsFinset g := by
+ ext c
+ rw [← mem_cycleFactorsFinset_conj' k⁻¹ (k • g) c]
+ simp only [inv_smul_smul]
+ exact Finset.inv_smul_mem_iff
+
+end Equiv.Perm
diff --git a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean
index e57ccd1bc59bb..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)
@@ -359,9 +359,10 @@ theorem isCycle_swap_mul_aux₁ {α : Type*} [DecidableEq α] :
∀ (n : ℕ) {b x : α} {f : Perm α} (_ : (swap x (f x) * f) b ≠ b) (_ : (f ^ n) (f x) = b),
∃ i : ℤ, ((swap x (f x) * f) ^ i) (f x) = b := by
intro n
- induction' n with n hn
- · exact fun _ h => ⟨0, h⟩
- · intro b x f hb h
+ induction n with
+ | zero => exact fun _ h => ⟨0, h⟩
+ | succ n hn =>
+ intro b x f hb h
exact if hfbx : f x = b then ⟨0, hfbx⟩
else
have : f b ≠ b ∧ b ≠ x := ne_and_ne_of_swap_mul_apply_ne_self hb
@@ -379,9 +380,10 @@ theorem isCycle_swap_mul_aux₂ {α : Type*} [DecidableEq α] :
∀ (n : ℤ) {b x : α} {f : Perm α} (_ : (swap x (f x) * f) b ≠ b) (_ : (f ^ n) (f x) = b),
∃ i : ℤ, ((swap x (f x) * f) ^ i) (f x) = b := by
intro n
- induction' n with n n
- · exact isCycle_swap_mul_aux₁ n
- · intro b x f hb h
+ induction n with
+ | ofNat n => exact isCycle_swap_mul_aux₁ n
+ | negSucc n =>
+ intro b x f hb h
exact if hfbx' : f x = b then ⟨0, hfbx'⟩
else
have : f b ≠ b ∧ b ≠ x := ne_and_ne_of_swap_mul_apply_ne_self hb
@@ -436,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]
@@ -450,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
@@ -470,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
@@ -643,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
@@ -663,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)
@@ -768,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)]
@@ -787,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]
@@ -929,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 ⊢
@@ -957,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,
@@ -976,12 +976,149 @@ 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
+
+namespace Equiv.Perm
+
+theorem subtypePerm_apply_pow_of_mem {g : Perm α} {s : Finset α}
+ (hs : ∀ x : α, x ∈ s ↔ g x ∈ s) {n : ℕ} {x : α} (hx : x ∈ s) :
+ ((g.subtypePerm hs ^ n) (⟨x, hx⟩ : s) : α) = (g ^ n) x := by
+ simp only [subtypePerm_pow, subtypePerm_apply]
+
+theorem subtypePerm_apply_zpow_of_mem {g : Perm α} {s : Finset α}
+ (hs : ∀ x : α, x ∈ s ↔ g x ∈ s) {i : ℤ} {x : α} (hx : x ∈ s) :
+ ((g.subtypePerm hs ^ i) (⟨x, hx⟩ : s) : α) = (g ^ i) x := by
+ simp only [subtypePerm_zpow, subtypePerm_apply]
+
+variable [Fintype α] [DecidableEq α]
+
+/-- Restrict a permutation to its support -/
+def subtypePermOfSupport (c : Perm α) : Perm c.support :=
+ subtypePerm c fun _ : α => apply_mem_support.symm
+
+/-- Restrict a permutation to a Finset containing its support -/
+def subtypePerm_of_support_le (c : Perm α) {s : Finset α}
+ (hcs : c.support ⊆ s) : Equiv.Perm s :=
+ subtypePerm c (isInvariant_of_support_le hcs)
+
+/-- Support of a cycle is nonempty -/
+theorem IsCycle.nonempty_support {g : Perm α} (hg : g.IsCycle) :
+ g.support.Nonempty := by
+ rw [Finset.nonempty_iff_ne_empty, ne_eq, support_eq_empty_iff]
+ exact IsCycle.ne_one hg
+
+/-- Centralizer of a cycle is a power of that cycle on the cycle -/
+theorem IsCycle.commute_iff' {g c : Perm α} (hc : c.IsCycle) :
+ Commute g c ↔
+ ∃ hc' : ∀ x : α, x ∈ c.support ↔ g x ∈ c.support,
+ subtypePerm g hc' ∈ Subgroup.zpowers c.subtypePermOfSupport := by
+ constructor
+ · intro hgc
+ have hgc' := mem_support_iff_of_commute hgc
+ use hgc'
+ obtain ⟨a, ha⟩ := IsCycle.nonempty_support hc
+ obtain ⟨i, hi⟩ := hc.sameCycle (mem_support.mp ha) (mem_support.mp ((hgc' a).mp ha))
+ use i
+ ext ⟨x, hx⟩
+ simp only [subtypePermOfSupport, Subtype.coe_mk, subtypePerm_apply]
+ rw [subtypePerm_apply_zpow_of_mem]
+ obtain ⟨j, rfl⟩ := hc.sameCycle (mem_support.mp ha) (mem_support.mp hx)
+ simp only [← mul_apply, Commute.eq (Commute.zpow_right hgc j)]
+ rw [← zpow_add, add_comm i j, zpow_add]
+ simp only [mul_apply, EmbeddingLike.apply_eq_iff_eq]
+ exact hi
+ · rintro ⟨hc', ⟨i, hi⟩⟩
+ ext x
+ simp only [coe_mul, Function.comp_apply]
+ by_cases hx : x ∈ c.support
+ · suffices hi' : ∀ x ∈ c.support, g x = (c ^ i) x by
+ rw [hi' x hx, hi' (c x) (apply_mem_support.mpr hx)]
+ simp only [← mul_apply, ← zpow_add_one, ← zpow_one_add, add_comm]
+ intro x hx
+ have hix := Perm.congr_fun hi ⟨x, hx⟩
+ simp only [← Subtype.coe_inj, subtypePermOfSupport, Subtype.coe_mk, subtypePerm_apply,
+ subtypePerm_apply_zpow_of_mem] at hix
+ exact hix.symm
+ · rw [not_mem_support.mp hx, eq_comm, ← not_mem_support]
+ contrapose! hx
+ exact (hc' x).mpr hx
+
+/-- A permutation `g` commutes with a cycle `c` if and only if
+ `c.support` is invariant under `g`, and `g` acts on it as a power of `c`. -/
+theorem IsCycle.commute_iff {g c : Perm α} (hc : c.IsCycle) :
+ Commute g c ↔
+ ∃ hc' : ∀ x : α, x ∈ c.support ↔ g x ∈ c.support,
+ ofSubtype (subtypePerm g hc') ∈ Subgroup.zpowers c := by
+ simp_rw [hc.commute_iff', Subgroup.mem_zpowers_iff]
+ refine exists_congr fun hc' => exists_congr fun k => ?_
+ rw [subtypePermOfSupport, subtypePerm_zpow c k]
+ simp only [Perm.ext_iff, subtypePerm_apply, Subtype.mk.injEq, Subtype.forall]
+ apply forall_congr'
+ intro a
+ by_cases ha : a ∈ c.support
+ · rw [imp_iff_right ha, ofSubtype_subtypePerm_of_mem hc' ha]
+ · rw [iff_true_left (fun b ↦ (ha b).elim), ofSubtype_apply_of_not_mem, ← not_mem_support]
+ · exact Finset.not_mem_mono (support_zpow_le c k) ha
+ · exact ha
+
+theorem zpow_eq_ofSubtype_subtypePerm_iff
+ {g c : Equiv.Perm α} {s : Finset α}
+ (hg : ∀ x, x ∈ s ↔ g x ∈ s) (hc : c.support ⊆ s) (n : ℤ) :
+ c ^ n = ofSubtype (g.subtypePerm hg) ↔
+ c.subtypePerm (isInvariant_of_support_le hc) ^ n = g.subtypePerm hg := by
+ constructor
+ · intro h
+ ext ⟨x, hx⟩
+ simp only [Perm.congr_fun h x, subtypePerm_apply_zpow_of_mem, Subtype.coe_mk, subtypePerm_apply]
+ rw [ofSubtype_apply_of_mem]
+ · simp only [Subtype.coe_mk, subtypePerm_apply]
+ · exact hx
+ · intro h; ext x
+ rw [← h]
+ by_cases hx : x ∈ s
+ · rw [ofSubtype_apply_of_mem (subtypePerm c _ ^ n) hx,
+ subtypePerm_zpow, subtypePerm_apply]
+ · rw [ofSubtype_apply_of_not_mem (subtypePerm c _ ^ n) hx,
+ ← not_mem_support]
+ exact fun hx' ↦ hx (hc (support_zpow_le _ _ hx'))
+
+theorem cycle_zpow_mem_support_iff {g : Perm α}
+ (hg : g.IsCycle) {n : ℤ} {x : α} (hx : g x ≠ x) :
+ (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]
+ apply lt_of_lt_of_le _ (IsCycle.two_le_card_support hg); norm_num
+ simp only [← hg.orderOf] at div_euc
+ obtain ⟨m, hm⟩ := Int.eq_ofNat_of_zero_le div_euc.2.1
+ simp only [hm, Nat.cast_nonneg, Nat.cast_lt, true_and] at div_euc
+ rw [← div_euc.1, zpow_add g]
+ simp only [hm, Nat.cast_eq_zero, zpow_natCast, coe_mul, comp_apply,zpow_mul,
+ pow_orderOf_eq_one, one_zpow, coe_one, id_eq]
+ have : (g ^ m) x = x ↔ g ^ m = 1 := by
+ constructor
+ · intro hgm
+ simp only [IsCycle.pow_eq_one_iff hg]
+ use x
+ · intro hgm
+ simp only [hgm, coe_one, id_eq]
+ rw [this]
+ by_cases hm0 : m = 0
+ · simp only [hm0, pow_zero, Nat.cast_zero]
+ · simp only [Nat.cast_eq_zero, hm0, iff_false]
+ exact pow_ne_one_of_lt_orderOf hm0 div_euc.2
+
+end Perm
+
+end Equiv
diff --git a/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean b/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean
index 57afc2d245faf..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`.
@@ -316,7 +316,7 @@ theorem toList_formPerm_nontrivial (l : List α) (hl : 2 ≤ l.length) (hn : Nod
· refine ext_getElem (by simp) fun k hk hk' => ?_
simp only [get_eq_getElem, formPerm_pow_apply_getElem _ hn, zero_add, getElem_map,
getElem_range, Nat.mod_eq_of_lt hk']
- · simpa [hs] using get_mem _ _ _
+ · simp [hs]
theorem toList_formPerm_isRotated_self (l : List α) (hl : 2 ≤ l.length) (hn : Nodup l) (x : α)
(hx : x ∈ l) : toList (formPerm l) x ~r l := by
@@ -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 48526c90ffbdf..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 : α) :
@@ -225,7 +225,7 @@ theorem mem_support_cycleOf_iff [DecidableEq α] [Fintype α] :
simp [hx]
· rw [mem_support, cycleOf_apply]
split_ifs with hy
- · simp only [hx, hy, iff_true_iff, Ne, not_false_iff, and_self_iff, mem_support]
+ · simp only [hx, hy, Ne, not_false_iff, and_self_iff, mem_support]
rcases hy with ⟨k, rfl⟩
rw [← not_mem_support]
simpa using hx
@@ -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'
@@ -291,6 +291,18 @@ theorem SameCycle.exists_pow_eq [DecidableEq α] [Fintype α] (f : Perm α) (h :
rw [not_mem_support] at hx
rw [pow_apply_eq_self_of_apply_eq_self hx, zpow_apply_eq_self_of_apply_eq_self hx]
+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 = 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]
+ rw [← Int.dvd_iff_emod_eq_zero]
+ rw [← cycleOf_zpow_apply_self g x, cycle_zpow_mem_support_iff]
+ · rw [← Int.dvd_iff_emod_eq_zero]
+ · exact isCycle_cycleOf g hx
+ · simp only [mem_support, cycleOf_apply_self]; exact hx
+
end CycleOf
@@ -308,7 +320,7 @@ def cycleFactorsAux [DecidableEq α] [Fintype α] (l : List α) (f : Perm α)
{ l : List (Perm α) // l.prod = f ∧ (∀ g ∈ l, IsCycle g) ∧ l.Pairwise Disjoint } :=
match l with
| [] => ⟨[], by
- { simp only [imp_false, List.Pairwise.nil, List.not_mem_nil, forall_const, and_true_iff,
+ { simp only [imp_false, List.Pairwise.nil, List.not_mem_nil, forall_const, and_true,
forall_prop_of_false, Classical.not_not, not_false_iff, List.prod_nil] at *
ext
simp [*]}⟩
@@ -489,6 +501,11 @@ theorem cycleOf_mem_cycleFactorsFinset_iff {f : Perm α} {x : α} :
· rw [cycleOf_apply_of_not_sameCycle H] at hy
contradiction
+lemma cycleOf_ne_one_iff_mem_cycleFactorsFinset {g : Equiv.Perm α} {x : α} :
+ g.cycleOf x ≠ 1 ↔ g.cycleOf x ∈ g.cycleFactorsFinset := by
+ rw [Equiv.Perm.cycleOf_mem_cycleFactorsFinset_iff, Equiv.Perm.mem_support,
+ ne_eq, Equiv.Perm.cycleOf_eq_one_iff]
+
theorem mem_cycleFactorsFinset_support_le {p f : Perm α} (h : p ∈ cycleFactorsFinset f) :
p.support ≤ f.support := by
rw [mem_cycleFactorsFinset_iff] at h
@@ -575,6 +592,73 @@ theorem cycle_is_cycleOf {f c : Equiv.Perm α} {a : α} (ha : a ∈ c.support)
Equiv.Perm.not_mem_support.mp
(Finset.disjoint_left.mp (Equiv.Perm.Disjoint.disjoint_support hfc) ha)
+
+theorem eq_cycleOf_of_mem_cycleFactorsFinset_iff
+ (g c : Perm α) (hc : c ∈ g.cycleFactorsFinset) (x : α) :
+ c = g.cycleOf x ↔ x ∈ c.support := by
+ refine ⟨?_, (cycle_is_cycleOf · hc)⟩
+ rintro rfl
+ rw [mem_support, cycleOf_apply_self, ne_eq, ← cycleOf_eq_one_iff]
+ exact (mem_cycleFactorsFinset_iff.mp hc).left.ne_one
+
+/-- A permutation `c` is a cycle of `g` iff `k * c * k⁻¹` is a cycle of `k * g * k⁻¹` -/
+theorem mem_cycleFactorsFinset_conj (g k c : Perm α) :
+ k * c * k⁻¹ ∈ (k * g * k⁻¹).cycleFactorsFinset ↔ c ∈ g.cycleFactorsFinset := by
+ suffices imp_lemma : ∀ {g k c : Perm α},
+ c ∈ g.cycleFactorsFinset → k * c * k⁻¹ ∈ (k * g * k⁻¹).cycleFactorsFinset by
+ refine ⟨fun h ↦ ?_, imp_lemma⟩
+ have aux : ∀ h : Perm α, h = k⁻¹ * (k * h * k⁻¹) * k := fun _ ↦ by group
+ rw [aux g, aux c]
+ exact imp_lemma h
+ intro g k c
+ simp only [mem_cycleFactorsFinset_iff]
+ apply And.imp IsCycle.conj
+ intro hc a ha
+ simp only [coe_mul, Function.comp_apply, EmbeddingLike.apply_eq_iff_eq]
+ apply hc
+ rw [mem_support] at ha ⊢
+ contrapose! ha
+ simp only [mul_smul, ← Perm.smul_def] at ha ⊢
+ rw [ha]
+ simp only [Perm.smul_def, apply_inv_self]
+
+/-- If a permutation commutes with every cycle of `g`, then it commutes with `g`
+
+NB. The converse is false. Commuting with every cycle of `g` means that we belong
+to the kernel of the action of `Equiv.Perm α` on `g.cycleFactorsFinset` -/
+theorem commute_of_mem_cycleFactorsFinset_commute (k g : Perm α)
+ (hk : ∀ c ∈ g.cycleFactorsFinset, Commute k c) :
+ Commute k g := by
+ rw [← cycleFactorsFinset_noncommProd g (cycleFactorsFinset_mem_commute g)]
+ apply Finset.noncommProd_commute
+ simpa only [id_eq] using hk
+
+/-- The cycles of a permutation commute with it -/
+theorem self_mem_cycle_factors_commute {g c : Perm α}
+ (hc : c ∈ g.cycleFactorsFinset) : Commute c g := by
+ apply commute_of_mem_cycleFactorsFinset_commute
+ intro c' hc'
+ by_cases hcc' : c = c'
+ · rw [hcc']
+ · apply g.cycleFactorsFinset_mem_commute hc hc'; exact hcc'
+
+/-- If `c` and `d` are cycles of `g`, then `d` stabilizes the support of `c` -/
+theorem mem_support_cycle_of_cycle {g d c : Perm α}
+ (hc : c ∈ g.cycleFactorsFinset) (hd : d ∈ g.cycleFactorsFinset) :
+ ∀ x : α, x ∈ c.support ↔ d x ∈ c.support := by
+ intro x
+ simp only [mem_support, not_iff_not]
+ by_cases h : c = d
+ · rw [← h, EmbeddingLike.apply_eq_iff_eq]
+ · rw [← Perm.mul_apply,
+ Commute.eq (cycleFactorsFinset_mem_commute g hc hd h),
+ mul_apply, EmbeddingLike.apply_eq_iff_eq]
+
+/-- If a permutation is a cycle of `g`, then its support is invariant under `g`-/
+theorem mem_cycleFactorsFinset_support {g c : Perm α} (hc : c ∈ g.cycleFactorsFinset) (a : α) :
+ a ∈ c.support ↔ g a ∈ c.support :=
+ mem_support_iff_of_commute (self_mem_cycle_factors_commute hc).symm a
+
end CycleFactorsFinset
@[elab_as_elim]
@@ -644,6 +728,39 @@ theorem cycleFactorsFinset_mul_inv_mem_eq_sdiff [DecidableEq α] [Fintype α] {f
· exact fun H =>
not_mem_empty _ (hd.disjoint_cycleFactorsFinset.le_bot (mem_inter_of_mem H hf))
+theorem IsCycle.forall_commute_iff [DecidableEq α] [Fintype α] (g z : Perm α) :
+ (∀ c ∈ g.cycleFactorsFinset, Commute z c) ↔
+ ∀ c ∈ g.cycleFactorsFinset,
+ ∃ (hc : ∀ x : α, x ∈ c.support ↔ z x ∈ c.support),
+ ofSubtype (subtypePerm z hc) ∈ Subgroup.zpowers c := by
+ apply forall_congr'
+ intro c
+ apply imp_congr_right
+ intro hc
+ exact IsCycle.commute_iff (mem_cycleFactorsFinset_iff.mp hc).1
+
+/-- A permutation restricted to the support of a cycle factor is that cycle factor -/
+theorem subtypePerm_on_cycleFactorsFinset [DecidableEq α] [Fintype α]
+ {g c : Perm α} (hc : c ∈ g.cycleFactorsFinset) :
+ g.subtypePerm (mem_cycleFactorsFinset_support hc) = c.subtypePermOfSupport := by
+ ext ⟨x, hx⟩
+ simp only [subtypePerm_apply, Subtype.coe_mk, subtypePermOfSupport]
+ exact ((mem_cycleFactorsFinset_iff.mp hc).2 x hx).symm
+
+theorem commute_iff_of_mem_cycleFactorsFinset [DecidableEq α] [Fintype α]{g k c : Equiv.Perm α}
+ (hc : c ∈ g.cycleFactorsFinset) :
+ Commute k c ↔
+ ∃ hc' : ∀ x : α, x ∈ c.support ↔ k x ∈ c.support,
+ k.subtypePerm hc' ∈ Subgroup.zpowers
+ (g.subtypePerm (mem_cycleFactorsFinset_support hc)) := by
+ rw [IsCycle.commute_iff' (mem_cycleFactorsFinset_iff.mp hc).1]
+ apply exists_congr
+ intro hc'
+ simp only [Subgroup.mem_zpowers_iff]
+ apply exists_congr
+ intro n
+ rw [Equiv.Perm.subtypePerm_on_cycleFactorsFinset hc]
+
end cycleFactors
end Perm
diff --git a/Mathlib/GroupTheory/Perm/Cycle/Type.lean b/Mathlib/GroupTheory/Perm/Cycle/Type.lean
index 34e77ea5584a0..c690004e7f541 100644
--- a/Mathlib/GroupTheory/Perm/Cycle/Type.lean
+++ b/Mathlib/GroupTheory/Perm/Cycle/Type.lean
@@ -134,6 +134,11 @@ theorem sum_cycleType (σ : Perm α) : σ.cycleType.sum = σ.support.card := by
| base_cycles σ hσ => rw [hσ.cycleType, sum_coe, List.sum_singleton]
| induction_disjoint σ τ hd _ hσ hτ => rw [hd.cycleType, sum_add, hσ, hτ, hd.card_support_mul]
+theorem card_fixedPoints (σ : Equiv.Perm α) :
+ Fintype.card (Function.fixedPoints σ) = Fintype.card α - σ.cycleType.sum := by
+ rw [Equiv.Perm.sum_cycleType, ← Finset.card_compl, Fintype.card_ofFinset]
+ congr; aesop
+
theorem sign_of_cycleType' (σ : Perm α) :
sign σ = (σ.cycleType.map fun n => -(-1 : ℤˣ) ^ n).prod := by
induction σ using cycle_induction_on with
@@ -456,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 716f2084d8364..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
@@ -29,6 +29,8 @@ Let `α` and `ι` by types and let `f : α → ι`
the cardinality of the type of permutations preserving `p` :
`Fintype.card {g : Perm α // f ∘ g = f} = ∏ i, (Fintype.card {a // f a = i})!`.
+* Without `Fintype ι`, `DomMulAct.stabilizer_card' p` gives an equivalent
+ formula, where the product is restricted to `Finset.univ.image f`.
-/
variable {α ι : Type*} {f : α → ι}
@@ -75,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}
@@ -86,22 +88,62 @@ lemma stabilizerMulEquiv_apply (g : (stabilizer (Perm α)ᵈᵐᵃ f)ᵐᵒᵖ)
section Fintype
-variable [Fintype α] [Fintype ι] [DecidableEq α] [DecidableEq ι]
+variable [Fintype α]
open Nat
variable (f)
/-- The cardinality of the type of permutations preserving a function -/
-theorem stabilizer_card :
+theorem stabilizer_card [DecidableEq α] [DecidableEq ι] [Fintype ι] :
Fintype.card {g : Perm α // f ∘ g = f} = ∏ i, (Fintype.card {a // f a = i})! := by
-- rewriting via Nat.card because Fintype instance is not found
- rw [← Nat.card_eq_fintype_card, Nat.card_congr (subtypeEquiv mk fun _ ↦ ?_),
+ rw [← Nat.card_eq_fintype_card,
+ Nat.card_congr (subtypeEquiv mk fun _ ↦ ?_),
Nat.card_congr MulOpposite.opEquiv,
Nat.card_congr (DomMulAct.stabilizerMulEquiv f).toEquiv, Nat.card_pi]
· exact Finset.prod_congr rfl fun i _ ↦ by rw [Nat.card_eq_fintype_card, Fintype.card_perm]
· rfl
+/-- The cardinality of the set of permutations preserving a function -/
+theorem stabilizer_ncard [Fintype ι] :
+ Set.ncard {g : Perm α | f ∘ g = f} = ∏ i, (Set.ncard {a | f a = i})! := by
+ classical
+ simp only [← Set.Nat.card_coe_set_eq, Set.coe_setOf, card_eq_fintype_card]
+ exact stabilizer_card f
+
+variable [DecidableEq α] [DecidableEq ι]
+
+/-- The cardinality of the type of permutations preserving a function
+ (without the finiteness assumption on target)-/
+theorem stabilizer_card':
+ Fintype.card {g : Perm α // f ∘ g = f} =
+ ∏ i in Finset.univ.image f, (Fintype.card ({a // f a = i}))! := by
+ set φ : α → Finset.univ.image f :=
+ Set.codRestrict f (Finset.univ.image f) (fun a => by simp)
+ suffices ∀ g : Perm α, f ∘ g = f ↔ φ ∘ g = φ by
+ simp only [this, stabilizer_card]
+ apply Finset.prod_bij (fun g _ => g.val)
+ · exact fun g _ => Finset.coe_mem g
+ · exact fun g _ g' _ => SetCoe.ext
+ · exact fun g hg => by
+ rw [Finset.mem_image] at hg
+ obtain ⟨a, _, rfl⟩ := hg
+ use ⟨f a, by simp only [Finset.mem_image, Finset.mem_univ, true_and, exists_apply_eq_apply]⟩
+ simp only [Finset.univ_eq_attach, Finset.mem_attach, exists_const]
+ · intro i _
+ apply congr_arg
+ apply Fintype.card_congr
+ apply Equiv.subtypeEquiv (Equiv.refl α)
+ intro a
+ rw [refl_apply, ← Subtype.coe_inj]
+ simp only [φ, Set.val_codRestrict_apply]
+ · intro g
+ simp only [funext_iff]
+ apply forall_congr'
+ intro a
+ simp only [Function.comp_apply, φ, ← Subtype.coe_inj, Set.val_codRestrict_apply]
+
end Fintype
end DomMulAct
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 7e6e532bb4f4d..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
@@ -47,7 +48,7 @@ def modSwap (i j : α) : Setoid (Perm α) :=
noncomputable instance {α : Type*} [Fintype α] [DecidableEq α] (i j : α) :
DecidableRel (modSwap i j).r :=
- fun _ _ => Or.decidable
+ fun _ _ => inferInstanceAs (Decidable (_ ∨ _))
/-- Given a list `l : List α` and a permutation `f : Perm α` such that the nonfixed points of `f`
are in `l`, recursively factors `f` as a product of transpositions. -/
@@ -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.
@@ -159,7 +160,7 @@ def finPairsLT (n : ℕ) : Finset (Σ_ : Fin n, Fin n) :=
(univ : Finset (Fin n)).sigma fun a => (range a).attachFin fun _ hm => (mem_range.1 hm).trans a.2
theorem mem_finPairsLT {n : ℕ} {a : Σ_ : Fin n, Fin n} : a ∈ finPairsLT n ↔ a.2 < a.1 := by
- simp only [finPairsLT, Fin.lt_iff_val_lt_val, true_and_iff, mem_attachFin, mem_range, mem_univ,
+ simp only [finPairsLT, Fin.lt_iff_val_lt_val, true_and, mem_attachFin, mem_range, mem_univ,
mem_sigma]
/-- `signAux σ` is the sign of a permutation on `Fin n`, defined as the parity of the number of
@@ -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₂ => ?_)
@@ -255,7 +256,7 @@ private theorem signAux_swap_zero_one' (n : ℕ) : signAux (swap (0 : Fin (n + 2
rcases a₁.zero_le.eq_or_lt with (rfl | H)
· exact absurd a₂.zero_le ha₁.not_le
rcases a₂.zero_le.eq_or_lt with (rfl | H')
- · simp only [and_true_iff, eq_self_iff_true, heq_iff_eq, mem_singleton, Sigma.mk.inj_iff] at ha₂
+ · simp only [and_true, eq_self_iff_true, heq_iff_eq, mem_singleton, Sigma.mk.inj_iff] at ha₂
have : 1 < a₁ := lt_of_le_of_ne (Nat.succ_le_of_lt ha₁)
(Ne.symm (by intro h; apply ha₂; simp [h]))
have h01 : Equiv.swap (0 : Fin (n + 2)) 1 0 = 1 := by simp
@@ -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]
@@ -417,7 +418,7 @@ theorem sign_trans_trans_symm [DecidableEq β] [Fintype β] (f : Perm β) (e :
theorem sign_prod_list_swap {l : List (Perm α)} (hl : ∀ g ∈ l, IsSwap g) :
sign l.prod = (-1) ^ l.length := by
have h₁ : l.map sign = List.replicate l.length (-1) :=
- List.eq_replicate.2
+ List.eq_replicate_iff.2
⟨by simp, fun u hu =>
let ⟨g, hg⟩ := List.mem_map.1 hu
hg.2 ▸ (hl _ hg.1).sign_eq⟩
@@ -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 _ _)
@@ -526,7 +527,7 @@ theorem prod_prodExtendRight {α : Type*} [DecidableEq α] (σ : α → Perm β)
· rw [← ha'] at *
refine Or.inl ⟨l.mem_cons_self a, ?_⟩
rw [prodExtendRight_apply_eq]
- · refine Or.inr ⟨fun h => not_or_of_not ha' not_mem_l ((List.mem_cons).mp h), ?_⟩
+ · refine Or.inr ⟨fun h => not_or_intro ha' not_mem_l ((List.mem_cons).mp h), ?_⟩
rw [prodExtendRight_apply_ne _ ha']
section congr
diff --git a/Mathlib/GroupTheory/Perm/Support.lean b/Mathlib/GroupTheory/Perm/Support.lean
index 63593ca5a6715..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
@@ -279,7 +278,7 @@ theorem coe_support_eq_set_support (f : Perm α) : (f.support : Set α) = { x |
@[simp]
theorem support_eq_empty_iff {σ : Perm α} : σ.support = ∅ ↔ σ = 1 := by
- simp_rw [Finset.ext_iff, mem_support, Finset.not_mem_empty, iff_false_iff, not_not,
+ simp_rw [Finset.ext_iff, mem_support, Finset.not_mem_empty, iff_false, not_not,
Equiv.Perm.ext_iff, one_apply]
@[simp]
@@ -296,6 +295,12 @@ theorem support_congr (h : f.support ⊆ g.support) (h' : ∀ x ∈ g.support, f
· rw [not_mem_support.mp hx, ← not_mem_support]
exact fun H => hx (h H)
+/-- If g and c commute, then g stabilizes the support of c -/
+theorem mem_support_iff_of_commute {g c : Perm α} (hgc : Commute g c) (x : α) :
+ x ∈ c.support ↔ g x ∈ c.support := by
+ simp only [mem_support, not_iff_not, ← mul_apply]
+ rw [← hgc, mul_apply, Equiv.apply_eq_iff_eq]
+
theorem support_mul_le (f g : Perm α) : (f * g).support ≤ f.support ⊔ g.support := fun x => by
simp only [sup_eq_union]
rw [mem_union, mem_support, mem_support, mem_support, mul_apply, ← not_and_or, not_imp_not]
@@ -322,15 +327,43 @@ 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]
--- @[simp] -- Porting note (#10618): simp can prove this
+/-- The support of a permutation is invariant -/
+theorem isInvariant_of_support_le {c : Perm α} {s : Finset α} (hcs : c.support ≤ s) (x : α) :
+ x ∈ s ↔ c x ∈ s := by
+ by_cases hx' : x ∈ c.support
+ · simp only [hcs hx', true_iff, hcs (apply_mem_support.mpr hx')]
+ · rw [not_mem_support.mp hx']
+
+/-- A permutation c is the extension of a restriction of g to s
+ iff its support is contained in s and its restriction is that of g -/
+lemma ofSubtype_eq_iff {g c : Equiv.Perm α} {s : Finset α}
+ (hg : ∀ x, x ∈ s ↔ g x ∈ s) :
+ ofSubtype (g.subtypePerm hg) = c ↔
+ c.support ≤ s ∧
+ ∀ (hc' : ∀ x, x ∈ s ↔ c x ∈ s), c.subtypePerm hc' = g.subtypePerm hg := by
+ simp only [Equiv.ext_iff, subtypePerm_apply, Subtype.mk.injEq, Subtype.forall]
+ constructor
+ · intro h
+ constructor
+ · intro a ha
+ by_contra ha'
+ rw [mem_support, ← h a, ofSubtype_apply_of_not_mem (p := (· ∈ s)) _ ha'] at ha
+ exact ha rfl
+ · intro _ a ha
+ rw [← h a, ofSubtype_apply_of_mem (p := (· ∈ s)) _ ha, subtypePerm_apply]
+ · rintro ⟨hc, h⟩ a
+ specialize h (isInvariant_of_support_le hc)
+ by_cases ha : a ∈ s
+ · rw [h a ha, ofSubtype_apply_of_mem (p := (· ∈ s)) _ ha, subtypePerm_apply]
+ · rw [ofSubtype_apply_of_not_mem (p := (· ∈ s)) _ ha, eq_comm, ← not_mem_support]
+ exact Finset.not_mem_mono hc ha
+
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]
@@ -390,7 +423,7 @@ theorem support_swap_iff (x y : α) : support (swap x y) = {x, y} ↔ x ≠ y :=
theorem support_swap_mul_swap {x y z : α} (h : List.Nodup [x, y, z]) :
support (swap x y * swap y z) = {x, y, z} := by
- simp only [List.not_mem_nil, and_true_iff, List.mem_cons, not_false_iff, List.nodup_cons,
+ simp only [List.not_mem_nil, and_true, List.mem_cons, not_false_iff, List.nodup_cons,
List.mem_singleton, and_self_iff, List.nodup_nil] at h
push_neg at h
apply le_antisymm
@@ -487,53 +520,52 @@ theorem support_extend_domain (f : α ≃ Subtype p) {g : Perm α} :
rw [eq_symm_apply]
exact Subtype.coe_injective ha
· rw [extendDomain_apply_not_subtype _ _ pb]
- simp only [not_exists, false_iff_iff, not_and, eq_self_iff_true, not_true]
+ simp only [not_exists, false_iff, not_and, eq_self_iff_true, not_true]
rintro a _ rfl
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
@@ -552,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
@@ -560,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
@@ -573,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
@@ -590,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
@@ -610,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 492c52f336a3f..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
@@ -66,11 +66,11 @@ local notation "F" => FreeGroup.lift f
theorem closure_rels_subset_ker (h : ∀ r ∈ rels, FreeGroup.lift f r = 1) :
Subgroup.normalClosure rels ≤ MonoidHom.ker F :=
- Subgroup.normalClosure_le_normal fun x w ↦ (MonoidHom.mem_ker _).2 (h x w)
+ Subgroup.normalClosure_le_normal fun x w ↦ MonoidHom.mem_ker.2 (h x w)
theorem to_group_eq_one_of_mem_closure (h : ∀ r ∈ rels, FreeGroup.lift f r = 1) :
∀ x ∈ Subgroup.normalClosure rels, F x = 1 :=
- fun _ w ↦ (MonoidHom.mem_ker _).1 <| closure_rels_subset_ker h w
+ fun _ w ↦ MonoidHom.mem_ker.1 <| closure_rels_subset_ker h w
/-- The extension of a map `f : α → G` that satisfies the given relations to a group homomorphism
from `PresentedGroup rels → G`. -/
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 a2f47594605f9..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,224 +49,19 @@ 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
-
-/-- 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
+@[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
variable (φ : G →* H)
@@ -320,7 +70,7 @@ open MonoidHom
/-- The induced map from the quotient by the kernel to the codomain. -/
@[to_additive "The induced map from the quotient by the kernel to the codomain."]
def kerLift : G ⧸ ker φ →* H :=
- lift _ φ fun _g => φ.mem_ker.mp
+ lift _ φ fun _g => mem_ker.mp
@[to_additive (attr := simp)]
theorem kerLift_mk (g : G) : (kerLift φ) g = φ g :=
@@ -340,7 +90,7 @@ theorem kerLift_injective : Injective (kerLift φ) := fun a b =>
/-- The induced map from the quotient by the kernel to the range. -/
@[to_additive "The induced map from the quotient by the kernel to the range."]
def rangeKerLift : G ⧸ ker φ →* φ.range :=
- lift _ φ.rangeRestrict fun g hg => (mem_ker _).mp <| by rwa [ker_rangeRestrict]
+ lift _ φ.rangeRestrict fun g hg => mem_ker.mp <| by rwa [ker_rangeRestrict]
@[to_additive]
theorem rangeKerLift_injective : Injective (rangeKerLift φ) := fun a b =>
@@ -427,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)
@@ -519,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 62c45fdc3df9e..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,33 +403,29 @@ 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
refine IH m hm.2 (hm.1.trans hd) (Finset.card_pos.2 ⟨a ^ (d / m), ?_⟩)
- simp only [mem_filter, mem_univ, orderOf_pow a, ha, true_and_iff,
+ 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")]
@@ -512,10 +506,10 @@ open Subgroup
variable {G : Type*} {H : Type*} [Group G] [Group H]
/-- A group is commutative if the quotient by the center is cyclic.
- Also see `commGroup_of_cycle_center_quotient` for the `CommGroup` instance. -/
+ Also see `commGroupOfCyclicCenterQuotient` for the `CommGroup` instance. -/
@[to_additive
"A group is commutative if the quotient by the center is cyclic.
- Also see `addCommGroup_of_cycle_center_quotient` for the `AddCommGroup` instance."]
+ Also see `addCommGroupOfCyclicCenterQuotient` for the `AddCommGroup` instance."]
theorem commutative_of_cyclic_center_quotient [IsCyclic H] (f : G →* H) (hf : f.ker ≤ center G)
(a b : G) : a * b = b * a :=
let ⟨⟨x, y, (hxy : f y = x)⟩, (hx : ∀ a : f.range, a ∈ zpowers _)⟩ :=
@@ -539,9 +533,9 @@ theorem commutative_of_cyclic_center_quotient [IsCyclic H] (f : G →* H) (hf :
alias commutative_of_add_cyclic_center_quotient := commutative_of_addCyclic_center_quotient
/-- A group is commutative if the quotient by the center is cyclic. -/
-@[to_additive commutativeOfAddCycleCenterQuotient
+@[to_additive
"A group is commutative if the quotient by the center is cyclic."]
-def commGroupOfCycleCenterQuotient [IsCyclic H] (f : G →* H) (hf : f.ker ≤ center G) :
+def commGroupOfCyclicCenterQuotient [IsCyclic H] (f : G →* H) (hf : f.ker ≤ center G) :
CommGroup G :=
{ show Group G by infer_instance with mul_comm := commutative_of_cyclic_center_quotient f hf }
@@ -656,7 +650,7 @@ lemma not_isCyclic_iff_exponent_eq_prime [Group α] {p : ℕ} (hp : p.Prime)
let _inst : Fintype α := @Fintype.ofFinite α <| Nat.finite_of_card_ne_zero <| by aesop
have hα' : Fintype.card α = p ^ 2 := by simpa using hα
have := (Fintype.one_lt_card_iff_nontrivial (α := α)).mp <|
- hα' ▸ one_lt_pow hp.one_lt two_ne_zero
+ hα' ▸ one_lt_pow₀ hp.one_lt two_ne_zero
/- in the forward direction, we apply `exponent_eq_prime_iff`, and the reverse direction follows
immediately because if `α` has exponent `p`, it has no element of order `p ^ 2`. -/
refine ⟨fun h_cyc ↦ (Monoid.exponent_eq_prime_iff hp).mpr fun g hg ↦ ?_, fun h_exp h_cyc ↦ by
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 9e505a267b935..2c301f72a0d33 100644
--- a/Mathlib/GroupTheory/Torsion.lean
+++ b/Mathlib/GroupTheory/Torsion.lean
@@ -91,7 +91,7 @@ theorem IsTorsion.of_surjective {f : G →* H} (hf : Function.Surjective f) (tG
theorem IsTorsion.extension_closed {f : G →* H} (hN : N = f.ker) (tH : IsTorsion H)
(tN : IsTorsion N) : IsTorsion G := fun g => by
obtain ⟨ngn, ngnpos, hngn⟩ := (tH <| f g).exists_pow_eq_one
- have hmem := f.mem_ker.mpr ((f.map_pow g ngn).trans hngn)
+ have hmem := MonoidHom.mem_ker.mpr ((f.map_pow g ngn).trans hngn)
lift g ^ ngn to N using hN.symm ▸ hmem with gn h
obtain ⟨nn, nnpos, hnn⟩ := (tN gn).exists_pow_eq_one
exact isOfFinOrder_iff_pow_eq_one.mpr <| ⟨ngn * nn, mul_pos ngnpos nnpos, by
@@ -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 fc6135c7832d0..32cb637b4877d 100644
--- a/Mathlib/Init.lean
+++ b/Mathlib/Init.lean
@@ -1,7 +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/CoreM.lean b/Mathlib/Lean/CoreM.lean
index 9a1cceb3fcd0a..475e0a4f41f08 100644
--- a/Mathlib/Lean/CoreM.lean
+++ b/Mathlib/Lean/CoreM.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Tactic.ToExpr
diff --git a/Mathlib/Lean/Expr.lean b/Mathlib/Lean/Expr.lean
index f95a20189c59f..fa0ec85aea5d0 100644
--- a/Mathlib/Lean/Expr.lean
+++ b/Mathlib/Lean/Expr.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2019 Robert Y. Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Simon Hudon, Scott Morrison, Keeley Hoek, Robert Y. Lewis, Floris van Doorn
+Authors: Mario Carneiro, Simon Hudon, Kim Morrison, Keeley Hoek, Robert Y. Lewis, Floris van Doorn
-/
import Mathlib.Lean.Expr.Basic
import Mathlib.Lean.Expr.ReplaceRec
diff --git a/Mathlib/Lean/Expr/Basic.lean b/Mathlib/Lean/Expr/Basic.lean
index cd4f02368e68b..02701a1fb4c6d 100644
--- a/Mathlib/Lean/Expr/Basic.lean
+++ b/Mathlib/Lean/Expr/Basic.lean
@@ -1,13 +1,12 @@
/-
Copyright (c) 2019 Robert Y. Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Simon Hudon, Scott Morrison, Keeley Hoek, Robert Y. Lewis,
+Authors: Mario Carneiro, Simon Hudon, Kim Morrison, Keeley Hoek, Robert Y. Lewis,
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/Lean/Expr/ReplaceRec.lean b/Mathlib/Lean/Expr/ReplaceRec.lean
index 80f1f08324276..185dbe0ba8785 100644
--- a/Mathlib/Lean/Expr/ReplaceRec.lean
+++ b/Mathlib/Lean/Expr/ReplaceRec.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2019 Robert Y. Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Simon Hudon, Scott Morrison, Keeley Hoek, Robert Y. Lewis,
+Authors: Mario Carneiro, Simon Hudon, Kim Morrison, Keeley Hoek, Robert Y. Lewis,
Floris van Doorn, Edward Ayers
-/
import Lean.Expr
diff --git a/Mathlib/Lean/LocalContext.lean b/Mathlib/Lean/LocalContext.lean
index 5bc891c5cdf0b..3c410ec6b63e6 100644
--- a/Mathlib/Lean/LocalContext.lean
+++ b/Mathlib/Lean/LocalContext.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Lean.LocalContext
diff --git a/Mathlib/Lean/Meta/Basic.lean b/Mathlib/Lean/Meta/Basic.lean
index a8066da2f4022..71d36a1cdcc99 100644
--- a/Mathlib/Lean/Meta/Basic.lean
+++ b/Mathlib/Lean/Meta/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Lean.Meta.AppBuilder
diff --git a/Mathlib/Lean/Meta/DiscrTree.lean b/Mathlib/Lean/Meta/DiscrTree.lean
index c20618862b96c..4698847cefc5a 100644
--- a/Mathlib/Lean/Meta/DiscrTree.lean
+++ b/Mathlib/Lean/Meta/DiscrTree.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Lean.Meta.DiscrTree
diff --git a/Mathlib/Lean/Meta/Simp.lean b/Mathlib/Lean/Meta/Simp.lean
index 19d5c973616f2..5f38f103a0dcc 100644
--- a/Mathlib/Lean/Meta/Simp.lean
+++ b/Mathlib/Lean/Meta/Simp.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Gabriel Ebner, Floris van Doorn
+Authors: Kim Morrison, Gabriel Ebner, Floris van Doorn
-/
import Mathlib.Init
import Lean.Elab.Tactic.Simp
diff --git a/Mathlib/Lean/Name.lean b/Mathlib/Lean/Name.lean
index 268d785610641..4f3b4e06b54e3 100644
--- a/Mathlib/Lean/Name.lean
+++ b/Mathlib/Lean/Name.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Lean.Meta.Match.MatcherInfo
diff --git a/Mathlib/Lean/PrettyPrinter/Delaborator.lean b/Mathlib/Lean/PrettyPrinter/Delaborator.lean
index bcc547afa2239..557bdf947198a 100644
--- a/Mathlib/Lean/PrettyPrinter/Delaborator.lean
+++ b/Mathlib/Lean/PrettyPrinter/Delaborator.lean
@@ -14,13 +14,6 @@ namespace Lean.PrettyPrinter.Delaborator
open Lean.Meta Lean.SubExpr SubExpr
-namespace SubExpr
-
-variable {α : Type} [Inhabited α]
-variable {m : Type → Type} [Monad m]
-
-end SubExpr
-
/-- Assuming the current expression in a lambda or pi,
descend into the body using an unused name generated from the binder's name.
Provides `d` with both `Syntax` for the bound name as an identifier
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 b66ea39b78a5a..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 :=
@@ -565,6 +560,13 @@ theorem lineMap_vsub_lineMap (p₁ p₂ p₃ p₄ : P1) (c : k) :
lineMap p₁ p₂ c -ᵥ lineMap p₃ p₄ c = lineMap (p₁ -ᵥ p₃) (p₂ -ᵥ p₄) c :=
((fst : P1 × P1 →ᵃ[k] P1) -ᵥ (snd : P1 × P1 →ᵃ[k] P1)).apply_lineMap (_, _) (_, _) c
+@[simp] lemma lineMap_lineMap_right (p₀ p₁ : P1) (c d : k) :
+ lineMap p₀ (lineMap p₀ p₁ c) d = lineMap p₀ p₁ (d * c) := by simp [lineMap_apply, mul_smul]
+
+@[simp] lemma lineMap_lineMap_left (p₀ p₁ : P1) (c d : k) :
+ lineMap (lineMap p₀ p₁ c) p₁ d = lineMap p₀ p₁ (1 - (1 - d) * (1 - c)) := by
+ simp_rw [lineMap_apply_one_sub, ← lineMap_apply_one_sub p₁, lineMap_lineMap_right]
+
/-- Decomposition of an affine map in the special case when the point space and vector space
are the same. -/
theorem decomp (f : V1 →ᵃ[k] V2) : (f : V1 → V2) = ⇑f.linear + fun _ => f 0 := by
@@ -696,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/Basis.lean b/Mathlib/LinearAlgebra/AffineSpace/Basis.lean
index 878ac8fe1f82c..ee7f13ec2dba6 100644
--- a/Mathlib/LinearAlgebra/AffineSpace/Basis.lean
+++ b/Mathlib/LinearAlgebra/AffineSpace/Basis.lean
@@ -311,7 +311,7 @@ instance [SMul G G'] [IsScalarTower G G' V] : IsScalarTower G G' (AffineBasis ι
@[simp] lemma coord_smul (a : G) (b : AffineBasis ι k V) (i : ι) :
(a • b).coord i = (b.coord i).comp (DistribMulAction.toLinearEquiv _ _ a).symm.toAffineMap := by
- ext v; simp [coord]
+ ext v; simp [map_sub, coord]
/-- TODO: generalize to include `SMul (P ≃ᵃ[k] P) (AffineBasis ι k P)`, which acts on `P` with a
`VAdd` version of a `DistribMulAction`. -/
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 e59a26e0c1ce5..0ef068c764695 100644
--- a/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean
+++ b/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean
@@ -23,20 +23,21 @@ subspaces of affine spaces.
noncomputable section
open Affine
+open scoped Finset
section AffineSpace'
variable (k : Type*) {V : Type*} {P : Type*}
variable {ι : Type*}
-open AffineSubspace FiniteDimensional Module
+open AffineSubspace Module
variable [DivisionRing k] [AddCommGroup V] [Module k V] [AffineSpace V P]
/-- The `vectorSpan` of a finite set is finite-dimensional. -/
theorem finiteDimensional_vectorSpan_of_finite {s : Set P} (h : Set.Finite s) :
FiniteDimensional k (vectorSpan k s) :=
- span_of_finite k <| h.vsub h
+ .span_of_finite k <| h.vsub h
/-- The `vectorSpan` of a family indexed by a `Fintype` is
finite-dimensional. -/
@@ -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]
@@ -202,7 +203,7 @@ theorem finrank_vectorSpan_le_iff_not_affineIndependent [Fintype ι] (p : ι →
variable {k}
lemma AffineIndependent.card_le_finrank_succ [Fintype ι] {p : ι → P} (hp : AffineIndependent k p) :
- Fintype.card ι ≤ FiniteDimensional.finrank k (vectorSpan k (Set.range p)) + 1 := by
+ Fintype.card ι ≤ Module.finrank k (vectorSpan k (Set.range p)) + 1 := by
cases isEmpty_or_nonempty ι
· simp [Fintype.card_eq_zero]
rw [← tsub_le_iff_right]
@@ -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
@@ -224,7 +225,7 @@ lemma AffineIndependent.card_le_card_of_subset_affineSpan {s t : Finset V}
have direction_le := AffineSubspace.direction_le (affineSpan_mono k hst)
rw [AffineSubspace.affineSpan_coe, direction_affineSpan, direction_affineSpan,
← @Subtype.range_coe _ (s : Set V), ← @Subtype.range_coe _ (t : Set V)] at direction_le
- have finrank_le := add_le_add_right (Submodule.finrank_le_finrank_of_le direction_le) 1
+ have finrank_le := add_le_add_right (Submodule.finrank_mono direction_le) 1
-- We use `erw` to elide the difference between `↥s` and `↥(s : Set V)}`
erw [hs.finrank_vectorSpan_add_one] at finrank_le
simpa using finrank_le.trans <| finrank_vectorSpan_range_add_one_le _ _
@@ -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,9 +256,9 @@ 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 :=
- eq_of_le_of_finrank_eq hle <| hi.finrank_vectorSpan_image_finset hc
+ Submodule.eq_of_le_of_finrank_eq hle <| hi.finrank_vectorSpan_image_finset hc
/-- If the `vectorSpan` of a finite affinely independent
family lies in a submodule with dimension one less than its
@@ -266,7 +267,7 @@ theorem AffineIndependent.vectorSpan_eq_of_le_of_card_eq_finrank_add_one [Fintyp
(hi : AffineIndependent k p) {sm : Submodule k V} [FiniteDimensional k sm]
(hle : vectorSpan k (Set.range p) ≤ sm) (hc : Fintype.card ι = finrank k sm + 1) :
vectorSpan k (Set.range p) = sm :=
- eq_of_le_of_finrank_eq hle <| hi.finrank_vectorSpan hc
+ Submodule.eq_of_le_of_finrank_eq hle <| hi.finrank_vectorSpan hc
/-- If the `affineSpan` of a finite subset of an affinely independent
family lies in an affine subspace whose direction has dimension one
@@ -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
@@ -371,7 +372,7 @@ alias ⟨Collinear.finrank_le_one, _⟩ := collinear_iff_finrank_le_one
/-- A subset of a collinear set is collinear. -/
theorem Collinear.subset {s₁ s₂ : Set P} (hs : s₁ ⊆ s₂) (h : Collinear k s₂) : Collinear k s₁ :=
- (rank_le_of_submodule (vectorSpan k s₁) (vectorSpan k s₂) (vectorSpan_mono k hs)).trans h
+ (Submodule.rank_mono (vectorSpan_mono k hs)).trans h
/-- The `vectorSpan` of collinear points is finite-dimensional. -/
theorem Collinear.finiteDimensional_vectorSpan {s : Set P} (h : Collinear k s) :
@@ -634,7 +635,7 @@ alias ⟨Coplanar.finrank_le_two, _⟩ := coplanar_iff_finrank_le_two
/-- A subset of a coplanar set is coplanar. -/
theorem Coplanar.subset {s₁ s₂ : Set P} (hs : s₁ ⊆ s₂) (h : Coplanar k s₂) : Coplanar k s₁ :=
- (rank_le_of_submodule (vectorSpan k s₁) (vectorSpan k s₂) (vectorSpan_mono k hs)).trans h
+ (Submodule.rank_mono (vectorSpan_mono k hs)).trans h
/-- Collinear points are coplanar. -/
theorem Collinear.coplanar {s : Set P} (h : Collinear k s) : Coplanar k s :=
@@ -669,7 +670,7 @@ section DivisionRing
variable {k : Type*} {V : Type*} {P : Type*}
-open AffineSubspace FiniteDimensional Module
+open AffineSubspace Module Module
variable [DivisionRing k] [AddCommGroup V] [Module k V] [AffineSpace V P]
@@ -764,12 +765,12 @@ protected theorem finite_set [FiniteDimensional k V] {s : Set ι} (b : AffineBas
finite_set_of_fin_dim_affineIndependent k b.ind
theorem card_eq_finrank_add_one [Fintype ι] (b : AffineBasis ι k P) :
- Fintype.card ι = FiniteDimensional.finrank k V + 1 :=
+ Fintype.card ι = Module.finrank k V + 1 :=
have : FiniteDimensional k V := b.finiteDimensional
b.ind.affineSpan_eq_top_iff_card_eq_finrank_add_one.mp b.tot
theorem exists_affineBasis_of_finiteDimensional [Fintype ι] [FiniteDimensional k V]
- (h : Fintype.card ι = FiniteDimensional.finrank k V + 1) : Nonempty (AffineBasis ι k P) := by
+ (h : Fintype.card ι = Module.finrank k V + 1) : Nonempty (AffineBasis ι k P) := by
obtain ⟨s, b, hb⟩ := AffineBasis.exists_affineBasis k V P
lift s to Finset P using b.finite_set
refine ⟨b.reindex <| Fintype.equivOfCardEq ?_⟩
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 3c306db16e0ea..6fc8b20955e39 100644
--- a/Mathlib/LinearAlgebra/Alternating/Basic.lean
+++ b/Mathlib/LinearAlgebra/Alternating/Basic.lean
@@ -88,15 +88,11 @@ section Coercions
instance instFunLike : FunLike (M [⋀^ι]→ₗ[R] N) (ι → M) N where
coe f := f.toFun
- coe_injective' := fun f g h ↦ by
+ coe_injective' f g h := by
rcases f with ⟨⟨_, _, _⟩, _⟩
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]
@@ -603,8 +631,8 @@ theorem map_perm [DecidableEq ι] [Fintype ι] (v : ι → M) (σ : Equiv.Perm
-- Porting note: `apply` → `induction'`
induction' σ using Equiv.Perm.swap_induction_on' with s x y hxy hI
· simp
- · -- Porting note: `← Function.comp.assoc` & `-Equiv.Perm.sign_swap'` are required.
- simpa [← Function.comp.assoc, g.map_swap (v ∘ s) hxy,
+ · -- Porting note: `← Function.comp_assoc` & `-Equiv.Perm.sign_swap'` are required.
+ simpa [← Function.comp_assoc, g.map_swap (v ∘ s) hxy,
Equiv.Perm.sign_swap hxy, -Equiv.Perm.sign_swap'] using hI
theorem map_congr_perm [DecidableEq ι] [Fintype ι] (σ : Equiv.Perm ι) :
@@ -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 7ae6931a6aa29..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,8 +225,8 @@ 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
- [@Finset.filter_congr _ _ (fun a => @Quotient.decidableEq _ _
+ 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)
(Quotient.mk'' σ)) _ (s := Finset.univ)
diff --git a/Mathlib/LinearAlgebra/Basis/Basic.lean b/Mathlib/LinearAlgebra/Basis/Basic.lean
index 67204421b86e3..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.
@@ -280,7 +276,7 @@ protected noncomputable def span : Basis ι R (span R (range v)) :=
rfl
have h₂ : map (Submodule.subtype (span R (range v))) (span R (range fun i => ⟨v i, this i⟩)) =
span R (range v) := by
- rw [← span_image, Submodule.coeSubtype]
+ rw [← span_image, Submodule.coe_subtype]
-- Porting note: why doesn't `rw [h₁]` work here?
exact congr_arg _ h₁
have h₃ : (x : M) ∈ map (Submodule.subtype (span R (range v)))
diff --git a/Mathlib/LinearAlgebra/Basis/Cardinality.lean b/Mathlib/LinearAlgebra/Basis/Cardinality.lean
index fb70ac8a04ff1..64108a9f48908 100644
--- a/Mathlib/LinearAlgebra/Basis/Cardinality.lean
+++ b/Mathlib/LinearAlgebra/Basis/Cardinality.lean
@@ -3,7 +3,8 @@ 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, Alexander Bentkamp, Kim Morrison
-/
-import Mathlib.LinearAlgebra.Basis.Basic
+import Mathlib.LinearAlgebra.Basis.Defs
+import Mathlib.LinearAlgebra.LinearIndependent
import Mathlib.SetTheory.Cardinal.Cofinality
/-!
@@ -14,11 +15,13 @@ section Finite
open Basis Cardinal Set Submodule Finsupp
-universe u v v' v'' u₁' w w'
+universe u v w w'
-variable {R : Type u} {M M₁ : Type v} {M' : Type v'} {ι : Type w}
-variable [Ring R] [AddCommGroup M] [AddCommGroup M'] [AddCommGroup M₁] [Nontrivial R]
-variable [Module R M] [Module R M'] [Module R M₁]
+variable {R : Type u} {M : Type v}
+
+section Semiring
+
+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
@@ -51,7 +54,7 @@ lemma basis_finite_of_finite_spans (w : Set M) (hw : w.Finite) (s : span R w =
intro x m
rw [← b.linearCombination_repr x, span_image_eq_map_linearCombination, Submodule.mem_map]
use b.repr x
- simp only [and_true_iff, eq_self_iff_true, Finsupp.mem_supported]
+ simp only [and_true, eq_self_iff_true, Finsupp.mem_supported]
rw [Finset.coe_subset, ← Finset.le_iff_subset]
exact Finset.le_sup (f := fun x : w ↦ (b.repr ↑x).support) (Finset.mem_univ (⟨x, m⟩ : w))
-- Thus this finite subset of the basis elements spans the entire module.
@@ -63,7 +66,14 @@ lemma basis_finite_of_finite_spans (w : Set M) (hw : w.Finite) (s : span R w =
rw [k]
exact mem_top
-- giving the desire contradiction.
- exact b.linearIndependent.not_mem_span_image nm k'
+ simp only [self_mem_span_image, Finset.mem_coe, bS] at k'
+ exact nm k'
+
+end Semiring
+
+section Ring
+
+variable [Ring R] [AddCommGroup M] [Nontrivial R] [Module R M]
-- From [Les familles libres maximales d'un module ont-elles le meme cardinal?][lazarus1973]
/-- Over any ring `R`, if `b` is a basis for a module `M`,
@@ -153,4 +163,6 @@ theorem infinite_basis_le_maximal_linearIndependent {ι : Type w} (b : Basis ι
{κ : Type w} (v : κ → M) (i : LinearIndependent R v) (m : i.Maximal) : #ι ≤ #κ :=
Cardinal.lift_le.mp (infinite_basis_le_maximal_linearIndependent' b v i m)
+end Ring
+
end Finite
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/Orthogonal.lean b/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean
index f4d1dcbf680e7..bff969f2c534c 100644
--- a/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean
+++ b/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean
@@ -283,7 +283,7 @@ lemma ker_restrict_eq_of_codisjoint {p q : Submodule R M} (hpq : Codisjoint p q)
{B : LinearMap.BilinForm R M} (hB : ∀ x ∈ p, ∀ y ∈ q, B x y = 0) :
LinearMap.ker (B.restrict p) = (LinearMap.ker B).comap p.subtype := by
ext ⟨z, hz⟩
- simp only [LinearMap.mem_ker, Submodule.mem_comap, Submodule.coeSubtype]
+ simp only [LinearMap.mem_ker, Submodule.mem_comap, Submodule.coe_subtype]
refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩
· ext w
obtain ⟨x, hx, y, hy, rfl⟩ := Submodule.exists_add_eq_of_codisjoint hpq w
@@ -294,7 +294,7 @@ lemma ker_restrict_eq_of_codisjoint {p q : Submodule R M} (hpq : Codisjoint p q)
lemma inf_orthogonal_self_le_ker_restrict {W : Submodule R M} (b₁ : B.IsRefl) :
W ⊓ B.orthogonal W ≤ (LinearMap.ker <| B.restrict W).map W.subtype := by
rintro v ⟨hv : v ∈ W, hv' : v ∈ B.orthogonal W⟩
- simp only [Submodule.mem_map, mem_ker, restrict_apply, Submodule.coeSubtype, Subtype.exists,
+ simp only [Submodule.mem_map, mem_ker, restrict_apply, Submodule.coe_subtype, Subtype.exists,
exists_and_left, exists_prop, exists_eq_right_right]
refine ⟨?_, hv⟩
ext ⟨w, hw⟩
@@ -302,7 +302,7 @@ lemma inf_orthogonal_self_le_ker_restrict {W : Submodule R M} (b₁ : B.IsRefl)
variable [FiniteDimensional K V]
-open FiniteDimensional Submodule
+open Module Submodule
variable {B : BilinForm K V}
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 b9e49faf0456c..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
@@ -37,16 +38,15 @@ variable {R : Type*} [Semiring R] {S : Type*} [Semiring S]
variable {R₂ : Type*} [Semiring R₂] {S₂ : Type*} [Semiring S₂]
variable {M : Type*} {N : Type*} {P : Type*}
variable {M₂ : Type*} {N₂ : Type*} {P₂ : Type*}
-variable {Nₗ : Type*} {Pₗ : Type*}
-variable {M' : Type*} {N' : Type*} {P' : Type*}
+variable {Pₗ : Type*}
+variable {M' : Type*} {P' : Type*}
variable [AddCommMonoid M] [AddCommMonoid N] [AddCommMonoid P]
-variable [AddCommMonoid M₂] [AddCommMonoid N₂] [AddCommMonoid P₂]
-variable [AddCommMonoid Nₗ] [AddCommMonoid Pₗ]
-variable [AddCommGroup M'] [AddCommGroup N'] [AddCommGroup P']
+variable [AddCommMonoid M₂] [AddCommMonoid N₂] [AddCommMonoid P₂] [AddCommMonoid Pₗ]
+variable [AddCommGroup M'] [AddCommGroup P']
variable [Module R M] [Module S N] [Module R₂ P] [Module S₂ P]
variable [Module R M₂] [Module S N₂] [Module R P₂] [Module S₂ P₂]
variable [Module R Pₗ] [Module S Pₗ]
-variable [Module R M'] [Module S N'] [Module R₂ P'] [Module S₂ P']
+variable [Module R M'] [Module R₂ P'] [Module S₂ P']
variable [SMulCommClass S₂ R₂ P] [SMulCommClass S R Pₗ] [SMulCommClass S₂ R₂ P']
variable [SMulCommClass S₂ R P₂]
variable {ρ₁₂ : R →+* R₂} {σ₁₂ : S →+* S₂}
@@ -103,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.
@@ -376,14 +376,11 @@ end CommSemiring
section CommRing
-variable {R R₂ S S₂ M N P : Type*}
-variable {Mₗ Nₗ Pₗ : Type*}
-variable [CommRing R] [CommRing S] [CommRing R₂] [CommRing S₂]
+variable {R M : Type*} [CommRing R]
section AddCommGroup
-variable [AddCommGroup M] [AddCommGroup N] [AddCommGroup P]
-variable [Module R M] [Module S N] [Module R₂ P] [Module S₂ P]
+variable [AddCommGroup M] [Module R M]
theorem lsmul_injective [NoZeroSMulDivisors R M] {x : R} (hx : x ≠ 0) :
Function.Injective (lsmul R M x) :=
diff --git a/Mathlib/LinearAlgebra/Charpoly/Basic.lean b/Mathlib/LinearAlgebra/Charpoly/Basic.lean
index eff887d7c175d..a54a424f7f68e 100644
--- a/Mathlib/LinearAlgebra/Charpoly/Basic.lean
+++ b/Mathlib/LinearAlgebra/Charpoly/Basic.lean
@@ -51,7 +51,7 @@ section Coeff
theorem charpoly_monic : f.charpoly.Monic :=
Matrix.charpoly_monic _
-open FiniteDimensional in
+open Module in
lemma charpoly_natDegree [Nontrivial R] [StrongRankCondition R] :
natDegree (charpoly f) = finrank R M := by
rw [charpoly, Matrix.charpoly_natDegree_eq_dim, finrank_eq_card_chooseBasisIndex]
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 4359ba5b328d0..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)
@@ -154,7 +153,7 @@ theorem evenOdd_induction (n : ZMod 2) {motive : ∀ x, x ∈ evenOdd Q n → Pr
motive (ι Q m₁ * ι Q m₂ * x)
(zero_add n ▸ SetLike.mul_mem_graded (ι_mul_ι_mem_evenOdd_zero Q m₁ m₂) hx))
(x : CliffordAlgebra Q) (hx : x ∈ evenOdd Q n) : motive x hx := by
- apply Submodule.iSup_induction' (C := motive) _ (range_ι_pow 0 (Submodule.zero_mem _)) add
+ apply Submodule.iSup_induction' (C := motive) _ _ (range_ι_pow 0 (Submodule.zero_mem _)) add
refine Subtype.rec ?_
simp_rw [ZMod.natCast_eq_iff, add_comm n.val]
rintro n' ⟨k, rfl⟩ xv
@@ -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
@@ -213,9 +212,8 @@ theorem odd_induction {P : ∀ x, x ∈ evenOdd Q 1 → Prop}
P (CliffordAlgebra.ι Q m₁ * CliffordAlgebra.ι Q m₂ * x)
(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
+ refine evenOdd_induction _ _ (motive := P) (fun ιv => ?_) add ι_mul_ι_mul x hx
+ simp_rw [ZMod.val_one, pow_one]
rintro ⟨v, rfl⟩
exact ι v
diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Prod.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Prod.lean
index 1e9ee43c0a118..e06d940aa2396 100644
--- a/Mathlib/LinearAlgebra/CliffordAlgebra/Prod.lean
+++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Prod.lean
@@ -116,7 +116,7 @@ def ofProd : CliffordAlgebra (Q₁.prod Q₂) →ₐ[R] (evenOdd Q₁ ᵍ⊗[R]
∘ₗ (evenOdd Q₂ 1).subtype ∘ₗ (ι Q₂).codRestrict _ (ι_mem_evenOdd_one Q₂)),
fun m => by
simp_rw [LinearMap.coprod_apply, LinearMap.coe_comp, Function.comp_apply,
- AlgHom.toLinearMap_apply, QuadraticMap.prod_apply, Submodule.coeSubtype,
+ AlgHom.toLinearMap_apply, QuadraticMap.prod_apply, Submodule.coe_subtype,
GradedTensorProduct.includeLeft_apply, GradedTensorProduct.includeRight_apply, map_add,
add_mul, mul_add, GradedTensorProduct.algebraMap_def,
GradedTensorProduct.tmul_one_mul_one_tmul, GradedTensorProduct.tmul_one_mul_coe_tmul,
diff --git a/Mathlib/LinearAlgebra/Coevaluation.lean b/Mathlib/LinearAlgebra/Coevaluation.lean
index bd0df67099a43..31b64ef5ce5f8 100644
--- a/Mathlib/LinearAlgebra/Coevaluation.lean
+++ b/Mathlib/LinearAlgebra/Coevaluation.lean
@@ -25,7 +25,7 @@ noncomputable section
section coevaluation
-open TensorProduct FiniteDimensional
+open TensorProduct Module
open TensorProduct
diff --git a/Mathlib/LinearAlgebra/Contraction.lean b/Mathlib/LinearAlgebra/Contraction.lean
index 8ba1276a30496..0e7e5c811a68a 100644
--- a/Mathlib/LinearAlgebra/Contraction.lean
+++ b/Mathlib/LinearAlgebra/Contraction.lean
@@ -201,7 +201,7 @@ section CommRing
variable [CommRing R]
variable [AddCommGroup M] [AddCommGroup N] [AddCommGroup P] [AddCommGroup Q]
variable [Module R M] [Module R N] [Module R P] [Module R Q]
-variable [Free R M] [Finite R M] [Free R N] [Finite R N]
+variable [Free R M] [Module.Finite R M] [Free R N] [Module.Finite R N]
/-- When `M` is a finite free module, the map `lTensorHomToHomLTensor` is an equivalence. Note
that `lTensorHomEquivHomLTensor` is not defined directly in terms of
diff --git a/Mathlib/LinearAlgebra/CrossProduct.lean b/Mathlib/LinearAlgebra/CrossProduct.lean
index f6ba8092be836..8fb6567b4ec21 100644
--- a/Mathlib/LinearAlgebra/CrossProduct.lean
+++ b/Mathlib/LinearAlgebra/CrossProduct.lean
@@ -141,3 +141,27 @@ theorem jacobi_cross (u v w : Fin 3 → R) : u ×₃ (v ×₃ w) + v ×₃ (w ×
lie_jacobi u v w
end LeibnizProperties
+
+-- this can also be proved via `Matrix.dotProduct_eq_zero_iff` and `triple_product_eq_det`, but
+-- that would require much heavier imports.
+lemma crossProduct_ne_zero_iff_linearIndependent {F : Type*} [Field F] {v w : Fin 3 → F} :
+ crossProduct v w ≠ 0 ↔ LinearIndependent F ![v, w] := by
+ rw [not_iff_comm]
+ by_cases hv : v = 0
+ · rw [hv, map_zero, LinearMap.zero_apply, eq_self, iff_true]
+ exact fun h ↦ h.ne_zero 0 rfl
+ constructor
+ · rw [LinearIndependent.pair_iff' hv, not_forall_not]
+ rintro ⟨a, rfl⟩
+ rw [LinearMap.map_smul, cross_self, smul_zero]
+ have hv' : v = ![v 0, v 1, v 2] := by simp [← List.ofFn_inj]
+ have hw' : w = ![w 0, w 1, w 2] := by simp [← List.ofFn_inj]
+ intro h1 h2
+ simp_rw [cross_apply, cons_eq_zero_iff, zero_empty, and_true, sub_eq_zero] at h1
+ have h20 := LinearIndependent.pair_iff.mp h2 (- w 0) (v 0)
+ have h21 := LinearIndependent.pair_iff.mp h2 (- w 1) (v 1)
+ have h22 := LinearIndependent.pair_iff.mp h2 (- w 2) (v 2)
+ rw [neg_smul, neg_add_eq_zero, hv', hw', smul_vec3, smul_vec3, ← hv', ← hw'] at h20 h21 h22
+ simp only [smul_eq_mul, mul_comm (w 0), mul_comm (w 1), mul_comm (w 2), h1] at h20 h21 h22
+ rw [hv', cons_eq_zero_iff, cons_eq_zero_iff, cons_eq_zero_iff, zero_empty] at hv
+ exact hv ⟨(h20 trivial).2, (h21 trivial).2, (h22 trivial).2, rfl⟩
diff --git a/Mathlib/LinearAlgebra/DFinsupp.lean b/Mathlib/LinearAlgebra/DFinsupp.lean
index fde50b6846a2f..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
@@ -299,7 +308,7 @@ theorem biSup_eq_range_dfinsupp_lsum (p : ι → Prop) [DecidablePred p] (S : ι
apply le_antisymm
· refine iSup₂_le fun i hi y hy => ⟨DFinsupp.single i ⟨y, hy⟩, ?_⟩
rw [LinearMap.comp_apply, filterLinearMap_apply, filter_single_pos _ _ hi]
- simp only [lsum_apply_apply, sumAddHom_single, LinearMap.toAddMonoidHom_coe, coeSubtype]
+ simp only [lsum_apply_apply, sumAddHom_single, LinearMap.toAddMonoidHom_coe, coe_subtype]
· rintro x ⟨v, rfl⟩
refine dfinsupp_sumAddHom_mem _ _ _ fun i _ => ?_
refine mem_iSup_of_mem i ?_
@@ -319,10 +328,10 @@ 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, coeSubtype]
+ LinearMap.toAddMonoidHom_coe, coe_subtype]
theorem mem_biSup_iff_exists_dfinsupp (p : ι → Prop) [DecidablePred p] (S : ι → Submodule R N)
(x : N) :
@@ -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 984b62e9b92a4..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
@@ -231,15 +231,15 @@ theorem det_id : LinearMap.det (LinearMap.id : M →ₗ[A] M) = 1 :=
@[simp]
theorem det_smul {𝕜 : Type*} [Field 𝕜] {M : Type*} [AddCommGroup M] [Module 𝕜 M] (c : 𝕜)
(f : M →ₗ[𝕜] M) :
- LinearMap.det (c • f) = c ^ FiniteDimensional.finrank 𝕜 M * LinearMap.det f := by
+ LinearMap.det (c • f) = c ^ Module.finrank 𝕜 M * LinearMap.det f := by
by_cases H : ∃ s : Finset M, Nonempty (Basis s 𝕜 M)
· have : FiniteDimensional 𝕜 M := by
rcases H with ⟨s, ⟨hs⟩⟩
exact FiniteDimensional.of_fintype_basis hs
- simp only [← det_toMatrix (FiniteDimensional.finBasis 𝕜 M), LinearEquiv.map_smul,
+ simp only [← det_toMatrix (Module.finBasis 𝕜 M), LinearEquiv.map_smul,
Fintype.card_fin, Matrix.det_smul]
· classical
- have : FiniteDimensional.finrank 𝕜 M = 0 := finrank_eq_zero_of_not_exists_basis H
+ have : Module.finrank 𝕜 M = 0 := finrank_eq_zero_of_not_exists_basis H
simp [coe_det, H, this]
theorem det_zero' {ι : Type*} [Finite ι] [Nonempty ι] (b : Basis ι A M) :
@@ -253,7 +253,7 @@ and `0` otherwise. We give a formula that also works in infinite dimension, wher
the determinant to be `1`. -/
@[simp]
theorem det_zero {𝕜 : Type*} [Field 𝕜] {M : Type*} [AddCommGroup M] [Module 𝕜 M] :
- LinearMap.det (0 : M →ₗ[𝕜] M) = (0 : 𝕜) ^ FiniteDimensional.finrank 𝕜 M := by
+ LinearMap.det (0 : M →ₗ[𝕜] M) = (0 : 𝕜) ^ Module.finrank 𝕜 M := by
simp only [← zero_smul 𝕜 (1 : M →ₗ[𝕜] M), det_smul, mul_one, MonoidHom.map_one]
theorem det_eq_one_of_subsingleton [Subsingleton M] (f : M →ₗ[R] M) :
@@ -263,14 +263,14 @@ theorem det_eq_one_of_subsingleton [Subsingleton M] (f : M →ₗ[R] M) :
exact Matrix.det_isEmpty
theorem det_eq_one_of_finrank_eq_zero {𝕜 : Type*} [Field 𝕜] {M : Type*} [AddCommGroup M]
- [Module 𝕜 M] (h : FiniteDimensional.finrank 𝕜 M = 0) (f : M →ₗ[𝕜] M) :
+ [Module 𝕜 M] (h : Module.finrank 𝕜 M = 0) (f : M →ₗ[𝕜] M) :
LinearMap.det (f : M →ₗ[𝕜] M) = 1 := by
classical
refine @LinearMap.det_cases M _ 𝕜 _ _ _ (fun t => t = 1) f ?_ rfl
intro s b
have : IsEmpty s := by
rw [← Fintype.card_eq_zero_iff]
- exact (FiniteDimensional.finrank_eq_card_basis b).symm.trans h
+ exact (Module.finrank_eq_card_basis b).symm.trans h
exact Matrix.det_isEmpty
/-- Conjugating a linear map by a linear equiv does not change its determinant. -/
@@ -423,8 +423,8 @@ theorem LinearEquiv.coe_ofIsUnitDet {f : M →ₗ[R] M'} {v : Basis ι R M} {v'
determinant is nonzero. -/
abbrev LinearMap.equivOfDetNeZero {𝕜 : Type*} [Field 𝕜] {M : Type*} [AddCommGroup M] [Module 𝕜 M]
[FiniteDimensional 𝕜 M] (f : M →ₗ[𝕜] M) (hf : LinearMap.det f ≠ 0) : M ≃ₗ[𝕜] M :=
- have : IsUnit (LinearMap.toMatrix (FiniteDimensional.finBasis 𝕜 M)
- (FiniteDimensional.finBasis 𝕜 M) f).det := by
+ have : IsUnit (LinearMap.toMatrix (Module.finBasis 𝕜 M)
+ (Module.finBasis 𝕜 M) f).det := by
rw [LinearMap.det_toMatrix]
exact isUnit_iff_ne_zero.2 hf
LinearEquiv.ofIsUnitDet this
@@ -558,7 +558,7 @@ theorem Basis.det_reindex' {ι' : Type*} [Fintype ι'] [DecidableEq ι'] (b : Ba
theorem Basis.det_reindex_symm {ι' : Type*} [Fintype ι'] [DecidableEq ι'] (b : Basis ι R M)
(v : ι → M) (e : ι' ≃ ι) : (b.reindex e.symm).det (v ∘ e) = b.det v := by
- rw [Basis.det_reindex, Function.comp.assoc, e.self_comp_symm, Function.comp_id]
+ rw [Basis.det_reindex, Function.comp_assoc, e.self_comp_symm, Function.comp_id]
@[simp]
theorem Basis.det_map (b : Basis ι R M) (f : M ≃ₗ[R] M') (v : ι → M') :
@@ -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/Basic.lean b/Mathlib/LinearAlgebra/Dimension/Basic.lean
index 673047ce643a6..6da291d1211aa 100644
--- a/Mathlib/LinearAlgebra/Dimension/Basic.lean
+++ b/Mathlib/LinearAlgebra/Dimension/Basic.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Scott Morrison
+Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Kim Morrison
-/
import Mathlib.LinearAlgebra.LinearIndependent
@@ -93,15 +93,6 @@ theorem cardinal_le_rank' {s : Set M}
end LinearIndependent
-@[deprecated (since := "2023-12-27")]
-alias cardinal_lift_le_rank_of_linearIndependent := LinearIndependent.cardinal_lift_le_rank
-@[deprecated (since := "2023-12-27")]
-alias cardinal_lift_le_rank_of_linearIndependent' := LinearIndependent.cardinal_lift_le_rank
-@[deprecated (since := "2023-12-27")]
-alias cardinal_le_rank_of_linearIndependent := LinearIndependent.cardinal_le_rank
-@[deprecated (since := "2023-12-27")]
-alias cardinal_le_rank_of_linearIndependent' := LinearIndependent.cardinal_le_rank'
-
section SurjectiveInjective
section Module
@@ -285,11 +276,12 @@ theorem lift_rank_map_le (f : M →ₗ[R] M') (p : Submodule R M) :
theorem rank_map_le (f : M →ₗ[R] M₁) (p : Submodule R M) :
Module.rank R (p.map f) ≤ Module.rank R p := by simpa using lift_rank_map_le f p
-theorem rank_le_of_submodule (s t : Submodule R M) (h : s ≤ t) :
- Module.rank R s ≤ Module.rank R t :=
+lemma Submodule.rank_mono {s t : Submodule R M} (h : s ≤ t) : Module.rank R s ≤ Module.rank R t :=
(Submodule.inclusion h).rank_le_of_injective fun ⟨x, _⟩ ⟨y, _⟩ eq =>
Subtype.eq <| show x = y from Subtype.ext_iff_val.1 eq
+@[deprecated (since := "2024-09-30")] alias rank_le_of_submodule := Submodule.rank_mono
+
/-- Two linearly equivalent vector spaces have the same dimension, a version with different
universes. -/
theorem LinearEquiv.lift_rank_eq (f : M ≃ₗ[R] M') :
@@ -331,9 +323,11 @@ theorem rank_range_of_surjective (f : M →ₗ[R] M') (h : Surjective f) :
Module.rank R (LinearMap.range f) = Module.rank R M' := by
rw [LinearMap.range_eq_top.2 h, rank_top]
-theorem rank_submodule_le (s : Submodule R M) : Module.rank R s ≤ Module.rank R M := by
+theorem Submodule.rank_le (s : Submodule R M) : Module.rank R s ≤ Module.rank R M := by
rw [← rank_top R M]
- exact rank_le_of_submodule _ _ le_top
+ exact rank_mono le_top
+
+@[deprecated (since := "2024-10-02")] alias rank_submodule_le := Submodule.rank_le
theorem LinearMap.lift_rank_le_of_surjective (f : M →ₗ[R] M') (h : Surjective f) :
lift.{v} (Module.rank R M') ≤ lift.{v'} (Module.rank R M) := by
diff --git a/Mathlib/LinearAlgebra/Dimension/Constructions.lean b/Mathlib/LinearAlgebra/Dimension/Constructions.lean
index f34b954448f30..fb4695c2deb46 100644
--- a/Mathlib/LinearAlgebra/Dimension/Constructions.lean
+++ b/Mathlib/LinearAlgebra/Dimension/Constructions.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Scott Morrison, Chris Hughes, Anne Baanen
+Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Kim Morrison, Chris Hughes, Anne Baanen
-/
import Mathlib.LinearAlgebra.Dimension.Free
import Mathlib.Algebra.Module.Torsion
@@ -35,7 +35,7 @@ universe u v v' u₁' w w'
variable {R S : Type u} {M : Type v} {M' : Type v'} {M₁ : Type v}
variable {ι : Type w} {ι' : Type w'} {η : Type u₁'} {φ : η → Type*}
-open Cardinal Basis Submodule Function Set FiniteDimensional DirectSum
+open Basis Cardinal DirectSum Function Module Set Submodule
variable [Ring R] [CommRing S] [AddCommGroup M] [AddCommGroup M'] [AddCommGroup M₁]
variable [Module R M]
@@ -142,7 +142,7 @@ theorem rank_prod' : Module.rank R (M × M₁) = Module.rank R M + Module.rank R
/-- The finrank of `M × M'` is `(finrank R M) + (finrank R M')`. -/
@[simp]
-theorem FiniteDimensional.finrank_prod [Module.Finite R M] [Module.Finite R M'] :
+theorem Module.finrank_prod [Module.Finite R M] [Module.Finite R M'] :
finrank R (M × M') = finrank R M + finrank R M' := by
simp [finrank, rank_lt_aleph0 R M, rank_lt_aleph0 R M']
@@ -183,33 +183,48 @@ 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
open Fintype
-namespace FiniteDimensional
+namespace Module
@[simp]
theorem finrank_finsupp {ι : Type v} [Fintype ι] : finrank R (ι →₀ M) = card ι * finrank R M := by
@@ -229,12 +244,12 @@ 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 FiniteDimensional
+end Module
end Finsupp
@@ -260,13 +275,13 @@ theorem rank_pi [Finite η] : Module.rank R (∀ i, φ i) =
variable (R)
/-- The finrank of `(ι → R)` is `Fintype.card ι`. -/
-theorem FiniteDimensional.finrank_pi {ι : Type v} [Fintype ι] :
+theorem Module.finrank_pi {ι : Type v} [Fintype ι] :
finrank R (ι → R) = Fintype.card ι := by
simp [finrank]
--TODO: this should follow from `LinearEquiv.finrank_eq`, that is over a field.
/-- The finrank of a finite product is the sum of the finranks. -/
-theorem FiniteDimensional.finrank_pi_fintype
+theorem Module.finrank_pi_fintype
{ι : Type v} [Fintype ι] {M : ι → Type w} [∀ i : ι, AddCommGroup (M i)]
[∀ i : ι, Module R (M i)] [∀ i : ι, Module.Free R (M i)] [∀ i : ι, Module.Finite R (M i)] :
finrank R (∀ i, M i) = ∑ i, finrank R (M i) := by
@@ -294,12 +309,11 @@ variable (R)
/-- The vector space of functions on a `Fintype ι` has finrank equal to the cardinality of `ι`. -/
@[simp]
-theorem FiniteDimensional.finrank_fintype_fun_eq_card : finrank R (η → R) = Fintype.card η :=
+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 FiniteDimensional.finrank_fin_fun {n : ℕ} : finrank R (Fin n → R) = n := by simp
+theorem Module.finrank_fin_fun {n : ℕ} : finrank R (Fin n → R) = n := by simp
variable {R}
@@ -343,7 +357,7 @@ theorem rank_tensorProduct' :
/-- The `S`-finrank of `M ⊗[R] M'` is `(finrank S M) * (finrank R M')`. -/
@[simp]
-theorem FiniteDimensional.finrank_tensorProduct :
+theorem Module.finrank_tensorProduct :
finrank R (M ⊗[S] M') = finrank R M * finrank S M' := by simp [finrank]
end TensorProduct
@@ -352,7 +366,7 @@ section SubmoduleRank
section
-open FiniteDimensional
+open Module
namespace Submodule
@@ -372,7 +386,7 @@ variable [StrongRankCondition R]
/-- The dimension of a submodule is bounded by the dimension of the ambient space. -/
theorem Submodule.finrank_le [Module.Finite R M] (s : Submodule R M) :
finrank R s ≤ finrank R M :=
- toNat_le_toNat (rank_submodule_le s) (rank_lt_aleph0 _ _)
+ toNat_le_toNat (Submodule.rank_le s) (rank_lt_aleph0 _ _)
/-- The dimension of a quotient is bounded by the dimension of the ambient space. -/
theorem Submodule.finrank_quotient_le [Module.Finite R M] (s : Submodule R M) :
@@ -386,12 +400,12 @@ theorem Submodule.finrank_map_le
finrank R (p.map f) ≤ finrank R p :=
finrank_le_finrank_of_rank_le_rank (lift_rank_map_le _ _) (rank_lt_aleph0 _ _)
-theorem Submodule.finrank_le_finrank_of_le {s t : Submodule R M} [Module.Finite R t] (hst : s ≤ t) :
+theorem Submodule.finrank_mono {s t : Submodule R M} [Module.Finite R t] (hst : s ≤ t) :
finrank R s ≤ finrank R t :=
- calc
- finrank R s = finrank R (s.comap t.subtype) :=
- (Submodule.comapSubtypeEquivOfLe hst).finrank_eq.symm
- _ ≤ finrank R t := Submodule.finrank_le _
+ Cardinal.toNat_le_toNat (Submodule.rank_mono hst) (rank_lt_aleph0 R ↥t)
+
+@[deprecated (since := "2024-09-30")]
+alias Submodule.finrank_le_finrank_of_le := Submodule.finrank_mono
end
@@ -413,7 +427,7 @@ theorem rank_span_finset_le (s : Finset M) : Module.rank R (span R (s : Set M))
theorem rank_span_of_finset (s : Finset M) : Module.rank R (span R (s : Set M)) < ℵ₀ :=
(rank_span_finset_le s).trans_lt (Cardinal.nat_lt_aleph0 _)
-open Submodule FiniteDimensional
+open Submodule Module
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/DivisionRing.lean b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean
index c18b030de59b8..cf1afda61d172 100644
--- a/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean
+++ b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean
@@ -2,7 +2,7 @@
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen,
-Scott Morrison, Chris Hughes, Anne Baanen, Junyan Xu
+Kim Morrison, Chris Hughes, Anne Baanen, Junyan Xu
-/
import Mathlib.LinearAlgebra.Basis.VectorSpace
import Mathlib.LinearAlgebra.Dimension.Finite
@@ -12,7 +12,7 @@ import Mathlib.LinearAlgebra.Dimension.RankNullity
/-!
# Dimension of vector spaces
-In this file we provide results about `Module.rank` and `FiniteDimensional.finrank` of vector spaces
+In this file we provide results about `Module.rank` and `Module.finrank` of vector spaces
over division rings.
## Main statements
@@ -112,7 +112,7 @@ end Module
section Basis
-open FiniteDimensional
+open Module
variable [DivisionRing K] [AddCommGroup V] [Module K V]
diff --git a/Mathlib/LinearAlgebra/Dimension/Finite.lean b/Mathlib/LinearAlgebra/Dimension/Finite.lean
index 48217a2ace216..8cce5dddc805b 100644
--- a/Mathlib/LinearAlgebra/Dimension/Finite.lean
+++ b/Mathlib/LinearAlgebra/Dimension/Finite.lean
@@ -1,12 +1,13 @@
/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Scott Morrison
+Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Kim Morrison
-/
import Mathlib.Algebra.Module.Torsion
import Mathlib.SetTheory.Cardinal.Cofinality
import Mathlib.LinearAlgebra.FreeModule.Finite.Basic
import Mathlib.LinearAlgebra.Dimension.StrongRankCondition
+import Mathlib.LinearAlgebra.Dimension.Constructions
/-!
# Conditions for rank to be finite
@@ -26,7 +27,7 @@ variable [Module R M] [Module R M'] [Module R M₁]
attribute [local instance] nontrivial_of_invariantBasisNumber
-open Cardinal Basis Submodule Function Set FiniteDimensional
+open Basis Cardinal Function Module Set Submodule
theorem rank_le {n : ℕ}
(H : ∀ s : Finset M, (LinearIndependent R fun i : s => (i : M)) → s.card ≤ n) :
@@ -191,15 +192,6 @@ theorem setFinite [Module.Finite R M] {b : Set M}
end LinearIndependent
-@[deprecated (since := "2023-12-27")]
-alias cardinal_mk_le_finrank_of_linearIndependent := LinearIndependent.cardinal_mk_le_finrank
-@[deprecated (since := "2023-12-27")]
-alias fintype_card_le_finrank_of_linearIndependent := LinearIndependent.fintype_card_le_finrank
-@[deprecated (since := "2023-12-27")]
-alias finset_card_le_finrank_of_linearIndependent := LinearIndependent.finset_card_le_finrank
-@[deprecated (since := "2023-12-27")]
-alias Module.Finite.lt_aleph0_of_linearIndependent := LinearIndependent.lt_aleph0_of_finite
-
lemma exists_set_linearIndependent_of_lt_rank {n : Cardinal} (hn : n < Module.rank R M) :
∃ s : Set M, #s = n ∧ LinearIndependent R ((↑) : s → M) := by
obtain ⟨⟨s, hs⟩, hs'⟩ := exists_lt_of_lt_ciSup' (hn.trans_eq (Module.rank_def R M))
@@ -241,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 :=
@@ -363,7 +355,7 @@ variable [Nontrivial R]
/-- A (finite dimensional) space that is a subsingleton has zero `finrank`. -/
@[nontriviality]
-theorem FiniteDimensional.finrank_zero_of_subsingleton [Subsingleton M] :
+theorem Module.finrank_zero_of_subsingleton [Subsingleton M] :
finrank R M = 0 := by
rw [finrank, rank_subsingleton', _root_.map_zero]
@@ -374,12 +366,12 @@ section
variable [NoZeroSMulDivisors R M]
/-- A finite dimensional space is nontrivial if it has positive `finrank`. -/
-theorem FiniteDimensional.nontrivial_of_finrank_pos (h : 0 < finrank R M) : Nontrivial M :=
+theorem Module.nontrivial_of_finrank_pos (h : 0 < finrank R M) : Nontrivial M :=
rank_pos_iff_nontrivial.mp (lt_rank_of_lt_finrank h)
/-- A finite dimensional space is nontrivial if it has `finrank` equal to the successor of a
natural number. -/
-theorem FiniteDimensional.nontrivial_of_finrank_eq_succ {n : ℕ}
+theorem Module.nontrivial_of_finrank_eq_succ {n : ℕ}
(hn : finrank R M = n.succ) : Nontrivial M :=
nontrivial_of_finrank_pos (R := R) (by rw [hn]; exact n.succ_pos)
@@ -398,31 +390,31 @@ section StrongRankCondition
variable [StrongRankCondition R] [Module.Finite R M]
/-- A finite rank torsion-free module has positive `finrank` iff it has a nonzero element. -/
-theorem FiniteDimensional.finrank_pos_iff_exists_ne_zero [NoZeroSMulDivisors R M] :
+theorem Module.finrank_pos_iff_exists_ne_zero [NoZeroSMulDivisors R M] :
0 < finrank R M ↔ ∃ x : M, x ≠ 0 := by
rw [← @rank_pos_iff_exists_ne_zero R M, ← finrank_eq_rank]
norm_cast
/-- An `R`-finite torsion-free module has positive `finrank` iff it is nontrivial. -/
-theorem FiniteDimensional.finrank_pos_iff [NoZeroSMulDivisors R M] :
+theorem Module.finrank_pos_iff [NoZeroSMulDivisors R M] :
0 < finrank R M ↔ Nontrivial M := by
rw [← rank_pos_iff_nontrivial (R := R), ← finrank_eq_rank]
norm_cast
/-- A nontrivial finite dimensional space has positive `finrank`. -/
-theorem FiniteDimensional.finrank_pos [NoZeroSMulDivisors R M] [h : Nontrivial M] :
+theorem Module.finrank_pos [NoZeroSMulDivisors R M] [h : Nontrivial M] :
0 < finrank R M :=
finrank_pos_iff.mpr h
-/-- See `FiniteDimensional.finrank_zero_iff`
+/-- See `Module.finrank_zero_iff`
for the stronger version with `NoZeroSMulDivisors R M`. -/
-theorem FiniteDimensional.finrank_eq_zero_iff :
+theorem Module.finrank_eq_zero_iff :
finrank R M = 0 ↔ ∀ x : M, ∃ a : R, a ≠ 0 ∧ a • x = 0 := by
rw [← rank_eq_zero_iff (R := R), ← finrank_eq_rank]
norm_cast
/-- The `StrongRankCondition` is automatic. See `commRing_strongRankCondition`. -/
-theorem FiniteDimensional.finrank_eq_zero_iff_isTorsion {R} [CommRing R] [StrongRankCondition R]
+theorem Module.finrank_eq_zero_iff_isTorsion {R} [CommRing R] [StrongRankCondition R]
[IsDomain R] [Module R M] [Module.Finite R M] :
finrank R M = 0 ↔ Module.IsTorsion R M := by
rw [← rank_eq_zero_iff_isTorsion (R := R), ← finrank_eq_rank]
@@ -430,14 +422,22 @@ theorem FiniteDimensional.finrank_eq_zero_iff_isTorsion {R} [CommRing R] [Strong
/-- A finite dimensional space has zero `finrank` iff it is a subsingleton.
This is the `finrank` version of `rank_zero_iff`. -/
-theorem FiniteDimensional.finrank_zero_iff [NoZeroSMulDivisors R M] :
+theorem Module.finrank_zero_iff [NoZeroSMulDivisors R M] :
finrank R M = 0 ↔ Subsingleton M := by
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 FiniteDimensional.finrank_eq_zero_of_rank_eq_zero (h : Module.rank R M = 0) :
+theorem Module.finrank_eq_zero_of_rank_eq_zero (h : Module.rank R M = 0) :
finrank R M = 0 := by
delta finrank
rw [h, zero_toNat]
@@ -463,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 9bf3954c81775..b702b49f38f5c 100644
--- a/Mathlib/LinearAlgebra/Dimension/Finrank.lean
+++ b/Mathlib/LinearAlgebra/Dimension/Finrank.lean
@@ -13,7 +13,7 @@ Definition of the rank of a module, or dimension of a vector space, as a natural
## Main definitions
-Defined is `FiniteDimensional.finrank`, the dimension of a finite dimensional space, returning a
+Defined is `Module.finrank`, the dimension of a finite dimensional space, returning a
`Nat`, as opposed to `Module.rank`, which returns a `Cardinal`. When the space has infinite
dimension, its `finrank` is by convention set to `0`.
@@ -38,7 +38,7 @@ open Cardinal Submodule Module Function
variable {R : Type u} {M : Type v} {N : Type w}
variable [Ring R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N]
-namespace FiniteDimensional
+namespace Module
section Ring
@@ -48,10 +48,15 @@ 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)
+@[deprecated (since := "2024-10-01")] protected alias _root_.FiniteDimensional.finrank := finrank
+
theorem finrank_eq_of_rank_eq {n : ℕ} (h : Module.rank R M = ↑n) : finrank R M = n := by
apply_fun toNat at h
rw [toNat_natCast] at h
@@ -92,9 +97,9 @@ theorem finrank_le_finrank_of_rank_le_rank
end Ring
-end FiniteDimensional
+end Module
-open FiniteDimensional
+open Module
namespace LinearEquiv
diff --git a/Mathlib/LinearAlgebra/Dimension/Free.lean b/Mathlib/LinearAlgebra/Dimension/Free.lean
index 3b06f6f965e75..af3007b4da717 100644
--- a/Mathlib/LinearAlgebra/Dimension/Free.lean
+++ b/Mathlib/LinearAlgebra/Dimension/Free.lean
@@ -14,7 +14,7 @@ import Mathlib.SetTheory.Cardinal.Finsupp
## Main result
- `LinearEquiv.nonempty_equiv_iff_lift_rank_eq`:
Two free modules are isomorphic iff they have the same dimension.
-- `FiniteDimensional.finBasis`:
+- `Module.finBasis`:
An arbitrary basis of a finite free module indexed by `Fin n` given `finrank R M = n`.
-/
@@ -24,7 +24,7 @@ noncomputable section
universe u v v' w
-open Cardinal Basis Submodule Function Set DirectSum FiniteDimensional
+open Cardinal Basis Submodule Function Set DirectSum Module
section Tower
@@ -57,7 +57,7 @@ theorem rank_mul_rank (A : Type v) [AddCommGroup A]
/-- Tower law: if `A` is a `K`-module and `K` is an extension of `F` then
$\operatorname{rank}_F(A) = \operatorname{rank}_F(K) * \operatorname{rank}_K(A)$. -/
-theorem FiniteDimensional.finrank_mul_finrank : finrank F K * finrank K A = finrank F A := by
+theorem Module.finrank_mul_finrank : finrank F K * finrank K A = finrank F A := by
simp_rw [finrank]
rw [← toNat_lift.{w} (Module.rank F K), ← toNat_lift.{v} (Module.rank K A), ← toNat_mul,
lift_rank_mul_lift_rank, toNat_lift]
@@ -79,7 +79,7 @@ theorem rank_eq_card_chooseBasisIndex : Module.rank R M = #(ChooseBasisIndex R M
(chooseBasis R M).mk_eq_rank''.symm
/-- The finrank of a free module `M` over `R` is the cardinality of `ChooseBasisIndex R M`. -/
-theorem _root_.FiniteDimensional.finrank_eq_card_chooseBasisIndex [Module.Finite R M] :
+theorem _root_.Module.finrank_eq_card_chooseBasisIndex [Module.Finite R M] :
finrank R M = Fintype.card (ChooseBasisIndex R M) := by
simp [finrank, rank_eq_card_chooseBasisIndex]
@@ -161,35 +161,30 @@ noncomputable def LinearEquiv.ofFinrankEq [Module.Finite R M] [Module.Finite R M
variable {M M'}
+namespace Module
+
/-- See `rank_lt_aleph0` for the inverse direction without `Module.Free R M`. -/
-lemma Module.rank_lt_alpeh0_iff :
- Module.rank R M < ℵ₀ ↔ Module.Finite R M := by
+lemma rank_lt_aleph0_iff : Module.rank R M < ℵ₀ ↔ Module.Finite R M := by
rw [Free.rank_eq_card_chooseBasisIndex, mk_lt_aleph0_iff]
exact ⟨fun h ↦ Finite.of_basis (Free.chooseBasis R M),
fun I ↦ Finite.of_fintype (Free.ChooseBasisIndex R M)⟩
-theorem FiniteDimensional.finrank_of_not_finite
- (h : ¬Module.Finite R M) :
- finrank R M = 0 := by
- rw [finrank, toNat_eq_zero, ← not_lt, Module.rank_lt_alpeh0_iff]
+theorem finrank_of_not_finite (h : ¬Module.Finite R M) : finrank R M = 0 := by
+ rw [finrank, toNat_eq_zero, ← not_lt, Module.rank_lt_aleph0_iff]
exact .inr h
-theorem Module.finite_of_finrank_pos (h : 0 < finrank R M) :
- Module.Finite R M := by
+theorem finite_of_finrank_pos (h : 0 < finrank R M) : Module.Finite R M := by
contrapose h
simp [finrank_of_not_finite h]
-theorem Module.finite_of_finrank_eq_succ {n : ℕ}
- (hn : finrank R M = n.succ) : Module.Finite R M :=
- Module.finite_of_finrank_pos <| by rw [hn]; exact n.succ_pos
+theorem finite_of_finrank_eq_succ {n : ℕ} (hn : finrank R M = n.succ) : Module.Finite R M :=
+ finite_of_finrank_pos <| by rw [hn]; exact n.succ_pos
-theorem Module.finite_iff_of_rank_eq_nsmul {W} [AddCommGroup W]
- [Module R W] [Module.Free R W] {n : ℕ} (hn : n ≠ 0)
- (hVW : Module.rank R M = n • Module.rank R W) :
+theorem finite_iff_of_rank_eq_nsmul {W} [AddCommGroup W] [Module R W] [Module.Free R W] {n : ℕ}
+ (hn : n ≠ 0) (hVW : Module.rank R M = n • Module.rank R W) :
Module.Finite R M ↔ Module.Finite R W := by
- simp only [← rank_lt_alpeh0_iff, hVW, nsmul_lt_aleph0_iff_of_ne_zero hn]
+ simp only [← rank_lt_aleph0_iff, hVW, nsmul_lt_aleph0_iff_of_ne_zero hn]
-namespace FiniteDimensional
variable (R M)
/-- A finite rank free module has a basis indexed by `Fin (finrank R M)`. -/
@@ -220,4 +215,4 @@ theorem basisUnique_repr_eq_zero_iff {ι : Type*} [Unique ι]
(basisUnique ι h).repr.map_eq_zero_iff.mp (Finsupp.ext fun j => Subsingleton.elim i j ▸ hv),
fun hv => by rw [hv, LinearEquiv.map_zero, Finsupp.zero_apply]⟩
-end FiniteDimensional
+end Module
diff --git a/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean b/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean
index 507f9e3b737de..212770aa65383 100644
--- a/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean
+++ b/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean
@@ -17,7 +17,7 @@ and `Mathlib/LinearAlgebra/FiniteDimensional.lean`.
-/
-open Cardinal Submodule Set FiniteDimensional
+open Cardinal Module Module Set Submodule
universe u v
@@ -27,7 +27,7 @@ variable {K : Type u} {V : Type v} [Ring K] [StrongRankCondition K] [AddCommGrou
/-- The `ι` indexed basis on `V`, where `ι` is an empty type and `V` is zero-dimensional.
-See also `FiniteDimensional.finBasis`.
+See also `Module.finBasis`.
-/
noncomputable def Basis.ofRankEqZero [Module.Free K V] {ι : Type*} [IsEmpty ι]
(hV : Module.rank K V = 0) : Basis ι K V :=
@@ -186,7 +186,7 @@ theorem finrank_eq_one_iff [Module.Free K V] (ι : Type*) [Unique ι] :
finrank K V = 1 ↔ Nonempty (Basis ι K V) := by
constructor
· intro h
- exact ⟨basisUnique ι h⟩
+ exact ⟨Module.basisUnique ι h⟩
· rintro ⟨b⟩
simpa using finrank_eq_card_basis b
@@ -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 418403e43f094..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
@@ -34,7 +35,7 @@ abbrev rank (f : V →ₗ[K] V') : Cardinal :=
Module.rank K (LinearMap.range f)
theorem rank_le_range (f : V →ₗ[K] V') : rank f ≤ Module.rank K V' :=
- rank_submodule_le _
+ Submodule.rank_le _
theorem rank_le_domain (f : V →ₗ[K] V₁) : rank f ≤ Module.rank K V :=
rank_range_le _
@@ -46,7 +47,7 @@ theorem rank_zero [Nontrivial K] : rank (0 : V →ₗ[K] V') = 0 := by
variable [AddCommGroup V''] [Module K V'']
theorem rank_comp_le_left (g : V →ₗ[K] V') (f : V' →ₗ[K] V'') : rank (f.comp g) ≤ rank f := by
- refine rank_le_of_submodule _ _ ?_
+ refine Submodule.rank_mono ?_
rw [LinearMap.range_comp]
exact LinearMap.map_le_range
@@ -82,7 +83,7 @@ variable [AddCommGroup V'] [Module K V']
theorem rank_add_le (f g : V →ₗ[K] V') : rank (f + g) ≤ rank f + rank g :=
calc
rank (f + g) ≤ Module.rank K (LinearMap.range f ⊔ LinearMap.range g : Submodule K V') := by
- refine rank_le_of_submodule _ _ ?_
+ refine Submodule.rank_mono ?_
exact LinearMap.range_le_iff_comap.2 <| eq_top_iff'.2 fun x =>
show f x + g x ∈ (LinearMap.range f ⊔ LinearMap.range g : Submodule K V') from
mem_sup.2 ⟨_, ⟨x, rfl⟩, _, ⟨x, rfl⟩, rfl⟩
diff --git a/Mathlib/LinearAlgebra/Dimension/Localization.lean b/Mathlib/LinearAlgebra/Dimension/Localization.lean
index 215eca3c7a657..594d62bba3e1d 100644
--- a/Mathlib/LinearAlgebra/Dimension/Localization.lean
+++ b/Mathlib/LinearAlgebra/Dimension/Localization.lean
@@ -15,9 +15,9 @@ import Mathlib.RingTheory.OreLocalization.OreSet
- `IsLocalizedModule.lift_rank_eq`: `rank_Rₚ Mₚ = rank R M`.
- `rank_quotient_add_rank_of_isDomain`: The **rank-nullity theorem** for commutative domains.
-
-/
-open Cardinal nonZeroDivisors
+
+open Cardinal Module nonZeroDivisors
section CommRing
@@ -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 79cac4a7d7ba4..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⟩⟩
@@ -136,12 +136,12 @@ theorem exists_linearIndependent_pair_of_one_lt_rank [StrongRankCondition R]
[NoZeroSMulDivisors R M] (h : 1 < Module.rank R M) {x : M} (hx : x ≠ 0) :
∃ y, LinearIndependent R ![x, y] := by
obtain ⟨y, hy⟩ := exists_linearIndependent_snoc_of_lt_rank (linearIndependent_unique ![x] hx) h
- have : Fin.snoc ![x] y = ![x, y] := Iff.mp List.ofFn_inj rfl
+ have : Fin.snoc ![x] y = ![x, y] := by simp [Fin.snoc, ← List.ofFn_inj]
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
@@ -171,7 +171,7 @@ theorem Submodule.rank_add_le_rank_add_rank (s t : Submodule R M) :
section Finrank
-open Submodule FiniteDimensional
+open Submodule Module
variable [StrongRankCondition R]
@@ -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 b7d2c4c6e0497..a84c1fb77e7b2 100644
--- a/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean
+++ b/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.LinearAlgebra.Dimension.Finrank
import Mathlib.LinearAlgebra.InvariantBasisNumber
@@ -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,
@@ -376,14 +376,12 @@ theorem Ideal.rank_eq {R S : Type*} [CommRing R] [StrongRankCondition R] [Ring S
((LinearMap.ker_eq_bot (f := (Submodule.subtype I : I →ₗ[R] S))).mpr Subtype.coe_injective)))
(c.card_le_card_of_linearIndependent this)
-open FiniteDimensional
+namespace Module
theorem finrank_eq_nat_card_basis (h : Basis ι R M) :
finrank R M = Nat.card ι := by
rw [Nat.card, ← toNat_lift.{v}, h.mk_eq_rank, toNat_lift, finrank]
-namespace FiniteDimensional
-
/-- If a vector space (or module) has a finite basis, then its dimension (or rank) is equal to the
cardinality of the basis. -/
theorem finrank_eq_card_basis {ι : Type w} [Fintype ι] (h : Basis ι R M) :
@@ -392,8 +390,8 @@ theorem finrank_eq_card_basis {ι : Type w} [Fintype ι] (h : Basis ι R M) :
/-- If a free module is of finite rank, then the cardinality of any basis is equal to its
`finrank`. -/
-theorem _root_.Module.mk_finrank_eq_card_basis [Module.Finite R M]
- {ι : Type w} (h : Basis ι R M) : (finrank R M : Cardinal.{w}) = #ι := by
+theorem mk_finrank_eq_card_basis [Module.Finite R M] {ι : Type w} (h : Basis ι R M) :
+ (finrank R M : Cardinal.{w}) = #ι := by
cases @nonempty_fintype _ (Module.Finite.finite_basis h)
rw [Cardinal.mk_fintype, finrank_eq_card_basis h]
@@ -402,10 +400,6 @@ cardinality of the basis. This lemma uses a `Finset` instead of indexed types. -
theorem finrank_eq_card_finset_basis {ι : Type w} {b : Finset ι} (h : Basis b R M) :
finrank R M = Finset.card b := by rw [finrank_eq_card_basis h, Fintype.card_coe]
-end FiniteDimensional
-
-open FiniteDimensional
-
variable (R)
@[simp]
@@ -415,15 +409,15 @@ theorem rank_self : Module.rank R R = 1 := by
/-- A ring satisfying `StrongRankCondition` (such as a `DivisionRing`) is one-dimensional as a
module over itself. -/
@[simp]
-theorem FiniteDimensional.finrank_self : finrank R R = 1 :=
+theorem finrank_self : finrank R R = 1 :=
finrank_eq_of_rank_eq (by simp)
/-- Given a basis of a ring over itself indexed by a type `ι`, then `ι` is `Unique`. -/
-noncomputable def Basis.unique {ι : Type*} (b : Basis ι R R) : Unique ι := by
- have A : Cardinal.mk ι = ↑(FiniteDimensional.finrank R R) :=
+noncomputable def _root_.Basis.unique {ι : Type*} (b : Basis ι R R) : Unique ι := by
+ have A : Cardinal.mk ι = ↑(Module.finrank R R) :=
(Module.mk_finrank_eq_card_basis b).symm
-- Porting note: replace `algebraMap.coe_one` with `Nat.cast_one`
- simp only [Cardinal.eq_one_iff_unique, FiniteDimensional.finrank_self, Nat.cast_one] at A
+ simp only [Cardinal.eq_one_iff_unique, Module.finrank_self, Nat.cast_one] at A
exact Nonempty.some ((unique_iff_subsingleton_and_nonempty _).2 A)
variable (M)
@@ -436,19 +430,30 @@ 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
-@[deprecated (since := "2024-01-01")]
-protected alias FiniteDimensional.rank_lt_aleph0 := rank_lt_aleph0
+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] :
- ↑(FiniteDimensional.finrank R M) = Module.rank R M := by
- rw [FiniteDimensional.finrank, cast_toNat_of_lt_aleph0 (rank_lt_aleph0 R M)]
+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
-@[deprecated (since := "2024-01-01")]
-protected alias FiniteDimensional.finrank_eq_rank := finrank_eq_rank
+open Module
-variable {R M}
variable {M'} [AddCommGroup M'] [Module R M']
theorem LinearMap.finrank_le_finrank_of_injective [Module.Finite R M'] {f : M →ₗ[R] M'}
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 b4d2e69e8d184..285e6bf70576b 100644
--- a/Mathlib/LinearAlgebra/Dual.lean
+++ b/Mathlib/LinearAlgebra/Dual.lean
@@ -91,6 +91,8 @@ The dual space of an $R$-module $M$ is the $R$-module of $R$-linear maps $M \to
splitting of `V₁`.
-/
+open Module Submodule
+
noncomputable section
namespace Module
@@ -181,7 +183,7 @@ def LinearMap.dualMap (f : M₁ →ₗ[R] M₂) : Dual R M₂ →ₗ[R] Dual R M
-- Porting note: with reducible def need to specify some parameters to transpose explicitly
Module.Dual.transpose (R := R) f
-lemma LinearMap.dualMap_eq_lcomp (f : M₁ →ₗ[R] M₂) : f.dualMap = f.lcomp R := rfl
+lemma LinearMap.dualMap_eq_lcomp (f : M₁ →ₗ[R] M₂) : f.dualMap = f.lcomp R R := rfl
-- Porting note: with reducible def need to specify some parameters to transpose explicitly
theorem LinearMap.dualMap_def (f : M₁ →ₗ[R] M₂) : f.dualMap = Module.Dual.transpose (R := R) f :=
@@ -384,7 +386,7 @@ theorem toDualEquiv_apply (m : M) : b.toDualEquiv m = b.toDual m :=
theorem linearEquiv_dual_iff_finiteDimensional [Field K] [AddCommGroup V] [Module K V] :
Nonempty (V ≃ₗ[K] Dual K V) ↔ FiniteDimensional K V := by
refine ⟨fun ⟨e⟩ ↦ ?_, fun h ↦ ⟨(Module.Free.chooseBasis K V).toDualEquiv⟩⟩
- rw [FiniteDimensional, ← Module.rank_lt_alpeh0_iff]
+ rw [FiniteDimensional, ← Module.rank_lt_aleph0_iff]
by_contra!
apply (lift_rank_lt_rank_dual this).ne
have := e.lift_rank_eq
@@ -449,12 +451,12 @@ theorem eval_range {ι : Type*} [Finite ι] (b : Basis ι R M) :
section
-variable [Finite R M] [Free R M]
+variable [Module.Finite R M] [Free R M]
instance dual_free : Free R (Dual R M) :=
Free.of_basis (Free.chooseBasis R M).dualBasis
-instance dual_finite : Finite R (Dual R M) :=
+instance dual_finite : Module.Finite R (Dual R M) :=
Finite.of_basis (Free.chooseBasis R M).dualBasis
end
@@ -482,7 +484,7 @@ universe uK uV
variable {K : Type uK} {V : Type uV}
variable [CommRing K] [AddCommGroup V] [Module K V] [Module.Free K V]
-open Module Module.Dual Submodule LinearMap Cardinal Basis FiniteDimensional
+open Module Module.Dual Submodule LinearMap Cardinal Basis Module
section
@@ -540,7 +542,7 @@ theorem nontrivial_dual_iff :
instance instNontrivialDual [Nontrivial V] : Nontrivial (Dual K V) :=
(nontrivial_dual_iff K).mpr inferInstance
-theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
+theorem finite_dual_iff : Module.Finite K (Dual K V) ↔ Module.Finite K V := by
constructor <;> intro h
· obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
nontriviality K
@@ -578,7 +580,8 @@ class IsReflexive : Prop where
lemma bijective_dual_eval [IsReflexive R M] : Bijective (Dual.eval R M) :=
IsReflexive.bijective_dual_eval'
-instance IsReflexive.of_finite_of_free [Finite R M] [Free R M] : IsReflexive R M where
+/-- See also `Module.instFiniteDimensionalOfIsReflexive` for the converse over a field. -/
+instance IsReflexive.of_finite_of_free [Module.Finite R M] [Free R M] : IsReflexive R M where
bijective_dual_eval' := ⟨LinearMap.ker_eq_bot.mp (Free.chooseBasis R M).eval_ker,
LinearMap.range_eq_top.mp (Free.chooseBasis R M).eval_range⟩
@@ -601,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⟩
@@ -648,6 +673,22 @@ instance _root_.MulOpposite.instModuleIsReflexive : IsReflexive R (MulOpposite M
instance _root_.ULift.instModuleIsReflexive.{w} : IsReflexive R (ULift.{w} M) :=
equiv ULift.moduleEquiv.symm
+instance instFiniteDimensionalOfIsReflexive (K V : Type*)
+ [Field K] [AddCommGroup V] [Module K V] [IsReflexive K V] :
+ FiniteDimensional K V := by
+ rw [FiniteDimensional, ← rank_lt_aleph0_iff]
+ by_contra! contra
+ suffices lift (Module.rank K V) < Module.rank K (Dual K (Dual K V)) by
+ have heq := lift_rank_eq_of_equiv_equiv (R := K) (R' := K) (M := V) (M' := Dual K (Dual K V))
+ (ZeroHom.id K) (evalEquiv K V) bijective_id (fun r v ↦ (evalEquiv K V).map_smul _ _)
+ rw [← lift_umax, heq, lift_id'] at this
+ exact lt_irrefl _ this
+ have h₁ : lift (Module.rank K V) < Module.rank K (Dual K V) := lift_rank_lt_rank_dual contra
+ have h₂ : Module.rank K (Dual K V) < Module.rank K (Dual K (Dual K V)) := by
+ convert lift_rank_lt_rank_dual <| le_trans (by simpa) h₁.le
+ rw [lift_id']
+ exact lt_trans h₁ h₂
+
end IsReflexive
end Module
@@ -671,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
@@ -1057,7 +1153,7 @@ theorem dualEquivDual_apply (φ : Module.Dual K W) :
section
-open FiniteDimensional
+open FiniteDimensional Module
instance instModuleDualFiniteDimensional [FiniteDimensional K V] :
FiniteDimensional K (Module.Dual K V) := by
@@ -1096,7 +1192,7 @@ noncomputable def quotEquivAnnihilator (W : Subspace K V) : (V ⧸ W) ≃ₗ[K]
-- refine' LinearEquiv.quot_equiv_of_equiv _ (Basis.ofVectorSpace K V).toDualEquiv
-- exact (Basis.ofVectorSpace K W).toDualEquiv.trans W.dual_equiv_dual
-open FiniteDimensional
+open Module
@[simp]
theorem finrank_dualCoannihilator_eq {Φ : Subspace K (Module.Dual K V)} :
@@ -1164,12 +1260,12 @@ def dualCopairing (W : Submodule R M) : W.dualAnnihilator →ₗ[R] M ⧸ W →
exact (mem_dualAnnihilator φ).mp hφ w hw)
-- Porting note: helper instance
-instance (W : Submodule R M) : FunLike (W.dualAnnihilator) M R :=
- { coe := fun φ => φ.val,
- coe_injective' := fun φ ψ h => by
- ext
- simp only [Function.funext_iff] at h
- exact h _ }
+instance (W : Submodule R M) : FunLike (W.dualAnnihilator) M R where
+ coe φ := φ.val
+ coe_injective' φ ψ h := by
+ ext
+ simp only [funext_iff] at h
+ exact h _
@[simp]
theorem dualCopairing_apply {W : Submodule R M} (φ : W.dualAnnihilator) (x : M) :
@@ -1231,7 +1327,7 @@ theorem dualQuotEquivDualAnnihilator_symm_apply_mk (W : Submodule R M) (φ : W.d
rfl
theorem finite_dualAnnihilator_iff {W : Submodule R M} [Free R (M ⧸ W)] :
- Finite R W.dualAnnihilator ↔ Finite R (M ⧸ W) :=
+ Module.Finite R W.dualAnnihilator ↔ Module.Finite R (M ⧸ W) :=
(Finite.equiv_iff W.dualQuotEquivDualAnnihilator.symm).trans (finite_dual_iff R)
open LinearMap in
@@ -1324,7 +1420,6 @@ lemma range_eq_top_of_ne_zero :
rw [eq_top_iff]
exact fun x _ ↦ ⟨x • (f v)⁻¹ • v, by simp [inv_mul_cancel₀ hv]⟩
-open FiniteDimensional
variable [FiniteDimensional K V₁]
lemma finrank_ker_add_one_of_ne_zero :
@@ -1479,7 +1574,7 @@ end Subspace
section FiniteDimensional
-open FiniteDimensional LinearMap
+open Module LinearMap
namespace LinearMap
@@ -1610,7 +1705,7 @@ theorem dualAnnihilator_dualAnnihilator_eq_map (W : Subspace K V) [FiniteDimensi
haveI := e1.finiteDimensional
let e2 := (Free.chooseBasis K _).toDualEquiv ≪≫ₗ W.dualAnnihilator.dualQuotEquivDualAnnihilator
haveI := LinearEquiv.finiteDimensional (V₂ := W.dualAnnihilator.dualAnnihilator) e2
- rw [FiniteDimensional.eq_of_le_of_finrank_eq (map_le_dualAnnihilator_dualAnnihilator W)]
+ rw [eq_of_le_of_finrank_eq (map_le_dualAnnihilator_dualAnnihilator W)]
rw [← (equivMapOfInjective _ (eval_apply_injective K (V := V)) W).finrank_eq, e1.finrank_eq]
exact e2.finrank_eq
diff --git a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean
index b10d365990732..05c1324d366e9 100644
--- a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean
+++ b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean
@@ -53,261 +53,567 @@ namespace Module
namespace End
-open FiniteDimensional Set
+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 `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_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 [genEigenspace, OrderHom.coe_mk, LinearMap.mem_ker, iSup_subtype',
+ Submodule.mem_iSup_of_directed _ this, LinearMap.mem_ker, Subtype.exists, exists_prop]
+
+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 ((genEigenspace f μ).monotone.comp aux).directed_le
+
+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
+ exact (f - μ • 1).iterateKer.monotone hl hx
+ · intro hx
+ exact ⟨k, le_rfl, hx⟩
+
+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 genEigenspace_nat {f : End R M} {μ : R} {k : ℕ} :
+ f.genEigenspace μ k = LinearMap.ker ((f - μ • 1) ^ k) := by
+ ext; simp [mem_genEigenspace_nat]
+
+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 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 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_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 `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 genEigenspace_zero {f : End R M} {μ : R} :
+ f.genEigenspace μ 0 = ⊥ := by
+ ext; apply mem_genEigenspace_zero
+
+@[simp]
+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.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.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.genEigenspace μ k ≠ ⊥`.
+
+For `k = 1`, this means that `μ` is an eigenvalue of `f`. -/
+def HasUnifEigenvalue (f : End R M) (μ : R) (k : ℕ∞) : Prop :=
+ 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
+`μ : R` that satisfy `f.HasUnifEigenvalue μ k`.
+
+For `k = 1` this is the type of all eigenvalues of `f`. -/
+def UnifEigenvalues (f : End R M) (k : ℕ∞) : Type _ :=
+ { μ : R // f.HasUnifEigenvalue μ k }
+
+/-- The underlying value of a bundled eigenvalue. -/
+@[coe]
+def UnifEigenvalues.val (f : Module.End R M) (k : ℕ∞) : UnifEigenvalues f k → R := Subtype.val
+
+instance UnifEigenvalues.instCoeOut {f : Module.End R M} (k : ℕ∞) :
+ CoeOut (UnifEigenvalues f k) R where
+ coe := UnifEigenvalues.val f k
+
+instance UnivEigenvalues.instDecidableEq [DecidableEq R] (f : Module.End R M) (k : ℕ∞) :
+ DecidableEq (UnifEigenvalues f k) :=
+ inferInstanceAs (DecidableEq (Subtype (fun x : R ↦ f.HasUnifEigenvalue x k)))
+
+lemma HasUnifEigenvector.hasUnifEigenvalue {f : End R M} {μ : R} {k : ℕ∞} {x : M}
+ (h : f.HasUnifEigenvector μ k x) : f.HasUnifEigenvalue μ k := by
+ rw [HasUnifEigenvalue, Submodule.ne_bot_iff]
+ use x; exact h
+
+lemma HasUnifEigenvector.apply_eq_smul {f : End R M} {μ : R} {x : M}
+ (hx : f.HasUnifEigenvector μ 1 x) : f x = μ • x :=
+ 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
+ induction n <;> simp [*, pow_succ f, hv.apply_eq_smul, smul_smul, pow_succ' μ]
+
+theorem HasUnifEigenvalue.exists_hasUnifEigenvector
+ {f : End R M} {μ : R} {k : ℕ∞} (hμ : f.HasUnifEigenvalue μ k) :
+ ∃ v, f.HasUnifEigenvector μ k v :=
+ Submodule.exists_mem_ne_zero_of_ne_bot hμ
+
+lemma HasUnifEigenvalue.pow {f : End R M} {μ : R} (h : f.HasUnifEigenvalue μ 1) (n : ℕ) :
+ (f ^ n).HasUnifEigenvalue (μ ^ n) 1 := by
+ rw [HasUnifEigenvalue, Submodule.ne_bot_iff]
+ obtain ⟨m : M, hm⟩ := h.exists_hasUnifEigenvector
+ exact ⟨m, by simpa [mem_genEigenspace_one] using hm.pow_apply n, hm.2⟩
+
+/-- A nilpotent endomorphism has nilpotent eigenvalues.
+
+See also `LinearMap.isNilpotent_trace_of_isNilpotent`. -/
+lemma HasUnifEigenvalue.isNilpotent_of_isNilpotent [NoZeroSMulDivisors R M] {f : End R M}
+ (hfn : IsNilpotent f) {μ : R} (hf : f.HasUnifEigenvalue μ 1) :
+ IsNilpotent μ := by
+ obtain ⟨m : M, hm⟩ := hf.exists_hasUnifEigenvector
+ obtain ⟨n : ℕ, hn : f ^ n = 0⟩ := hfn
+ exact ⟨n, by simpa [hn, hm.2, eq_comm (a := (0 : M))] using hm.pow_apply n⟩
+
+lemma HasUnifEigenvalue.mem_spectrum {f : End R M} {μ : R} (hμ : HasUnifEigenvalue f μ 1) :
+ μ ∈ spectrum R f := by
+ refine spectrum.mem_iff.mpr fun h_unit ↦ ?_
+ set f' := LinearMap.GeneralLinearGroup.toLinearEquiv h_unit.unit
+ rcases hμ.exists_hasUnifEigenvector with ⟨v, hv⟩
+ refine hv.2 ((LinearMap.ker_eq_bot'.mp f'.ker) v (?_ : μ • v - f v = 0))
+ rw [hv.apply_eq_smul, sub_self]
+
+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, genEigenspace_one, ne_eq, not_iff_not]
+ simp [Submodule.ext_iff, LinearMap.mem_ker]
+
+alias ⟨_, HasUnifEigenvalue.of_mem_spectrum⟩ := hasUnifEigenvalue_iff_mem_spectrum
+
+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
+ 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]
+
+/-- 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 genEigenrange (f : End R M) (μ : R) (k : ℕ∞) : Submodule R M :=
+ ⨅ l : ℕ, ⨅ (_ : l ≤ k), LinearMap.range ((f - μ • 1) ^ l)
+
+lemma genEigenrange_nat {f : End R M} {μ : R} {k : ℕ} :
+ f.genEigenrange μ k = LinearMap.range ((f - μ • 1) ^ k) := by
+ ext x
+ simp only [genEigenrange, Nat.cast_le, Submodule.mem_iInf, LinearMap.mem_range]
+ constructor
+ · intro h
+ exact h _ le_rfl
+ · rintro ⟨x, rfl⟩ i hi
+ have : k = i + (k - i) := by omega
+ rw [this, pow_add]
+ exact ⟨_, rfl⟩
+
+/-- The exponent of a generalized eigenvalue is never 0. -/
+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, 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.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 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.genEigenspace μ).comp <| WithTop.coeOrderHom.toOrderHom
+ convert this using 1
+ 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 genEigenspace_le_genEigenspace_maxUnifEigenspaceIndex [IsNoetherian R M] (f : End R M)
+ (μ : R) (k : ℕ∞) :
+ 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 genEigenspace_eq_genEigenspace_maxUnifEigenspaceIndex_of_le [IsNoetherian R M]
+ (f : End R M) (μ : R) {k : ℕ} (hk : maxUnifEigenspaceIndex f μ ≤ k) :
+ f.genEigenspace μ k = f.genEigenspace μ (maxUnifEigenspaceIndex f μ) :=
+ le_antisymm
+ (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`. -/
+lemma HasUnifEigenvalue.le {f : End R M} {μ : R} {k m : ℕ∞}
+ (hm : k ≤ m) (hk : f.HasUnifEigenvalue μ k) :
+ f.HasUnifEigenvalue μ m := by
+ unfold HasUnifEigenvalue at *
+ contrapose! hk
+ rw [← le_bot_iff, ← hk]
+ exact (f.genEigenspace _).monotone hm
+
+/-- A generalized eigenvalue for some exponent `k` is also
+ a generalized eigenvalue for positive exponents. -/
+lemma HasUnifEigenvalue.lt {f : End R M} {μ : R} {k m : ℕ∞}
+ (hm : 0 < m) (hk : f.HasUnifEigenvalue μ k) :
+ f.HasUnifEigenvalue μ m := by
+ apply HasUnifEigenvalue.le (k := 1) (Order.one_le_iff_pos.mpr hm)
+ intro contra; apply hk
+ rw [genEigenspace_one, LinearMap.ker_eq_bot] at contra
+ rw [eq_bot_iff]
+ intro x 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]
+ exact Function.Injective.iterate contra l
+
+/-- Generalized eigenvalues are actually just eigenvalues. -/
+@[simp]
+lemma hasUnifEigenvalue_iff_hasUnifEigenvalue_one {f : End R M} {μ : R} {k : ℕ∞} (hk : 0 < k) :
+ f.HasUnifEigenvalue μ k ↔ f.HasUnifEigenvalue μ 1 :=
+ ⟨HasUnifEigenvalue.lt zero_lt_one, HasUnifEigenvalue.lt hk⟩
+
+lemma maxUnifEigenspaceIndex_le_finrank [FiniteDimensional K V] (f : End K V) (μ : K) :
+ maxUnifEigenspaceIndex f μ ≤ finrank K V := by
+ apply Nat.sInf_le
+ intro n hn
+ apply le_antisymm
+ · 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 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 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) :=
+ le_antisymm
+ (genEigenspace_le_genEigenspace_finrank _ _ _)
+ ((f.genEigenspace μ).monotone <| by simpa using 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
+ intro x 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
+ use l, hl
+ rw [← LinearMap.comp_apply, ← LinearMap.mul_eq_comp, h.eq, LinearMap.mul_eq_comp,
+ LinearMap.comp_apply, hx, map_zero]
+
+/-- The restriction of `f - μ • 1` to the `k`-fold generalized `μ`-eigenspace is nilpotent. -/
+lemma isNilpotent_restrict_genEigenspace_nat (f : End R M) (μ : R) (k : ℕ)
+ (h : MapsTo (f - μ • (1 : End R M))
+ (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_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_genEigenspace_top [IsNoetherian R M] (f : End R M) (μ : R)
+ (h : MapsTo (f - μ • (1 : End R M))
+ (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
+ 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])-/
-def eigenspace (f : End R M) (μ : R) : Submodule R M :=
- LinearMap.ker (f - algebraMap R (End R M) μ)
+abbrev eigenspace (f : End R M) (μ : R) : Submodule R M :=
+ f.genEigenspace μ 1
+
+lemma eigenspace_def {f : End R M} {μ : R} :
+ f.eigenspace μ = LinearMap.ker (f - μ • 1) := by
+ rw [eigenspace, genEigenspace_one]
@[simp]
-theorem eigenspace_zero (f : End R M) : f.eigenspace 0 = LinearMap.ker f := by simp [eigenspace]
+theorem eigenspace_zero (f : End R M) : f.eigenspace 0 = LinearMap.ker f := by
+ 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]) -/
-def HasEigenvector (f : End R M) (μ : R) (x : M) : Prop :=
- x ∈ eigenspace f μ ∧ x ≠ 0
+abbrev HasEigenvector (f : End R M) (μ : R) (x : M) : Prop :=
+ HasUnifEigenvector f μ 1 x
+
+lemma hasEigenvector_iff {f : End R M} {μ : R} {x : M} :
+ f.HasEigenvector μ x ↔ x ∈ f.eigenspace μ ∧ x ≠ 0 := Iff.rfl
/-- A scalar `μ` is an eigenvalue for a linear map `f` if there are nonzero vectors `x`
such that `f x = μ • x`. (Def 5.5 of [axler2015]) -/
-def HasEigenvalue (f : End R M) (a : R) : Prop :=
- eigenspace f a ≠ ⊥
+abbrev HasEigenvalue (f : End R M) (a : R) : Prop :=
+ HasUnifEigenvalue f a 1
+
+lemma hasEigenvalue_iff {f : End R M} {μ : R} :
+ f.HasEigenvalue μ ↔ f.eigenspace μ ≠ ⊥ := Iff.rfl
/-- The eigenvalues of the endomorphism `f`, as a subtype of `R`. -/
-def Eigenvalues (f : End R M) : Type _ :=
- { μ : R // f.HasEigenvalue μ }
+abbrev Eigenvalues (f : End R M) : Type _ :=
+ UnifEigenvalues f 1
@[coe]
-def Eigenvalues.val (f : Module.End R M) : Eigenvalues f → R := Subtype.val
-
-instance Eigenvalues.instCoeOut {f : Module.End R M} : CoeOut (Eigenvalues f) R where
- coe := Eigenvalues.val f
-
-instance Eigenvalues.instDecidableEq [DecidableEq R] (f : Module.End R M) :
- DecidableEq (Eigenvalues f) :=
- inferInstanceAs (DecidableEq (Subtype (fun x : R => HasEigenvalue f x)))
+abbrev Eigenvalues.val (f : Module.End R M) : Eigenvalues f → R := UnifEigenvalues.val f 1
theorem hasEigenvalue_of_hasEigenvector {f : End R M} {μ : R} {x : M} (h : HasEigenvector f μ x) :
- HasEigenvalue f μ := by
- rw [HasEigenvalue, Submodule.ne_bot_iff]
- use x; exact h
+ HasEigenvalue f μ :=
+ h.hasUnifEigenvalue
-theorem mem_eigenspace_iff {f : End R M} {μ : R} {x : M} : x ∈ eigenspace f μ ↔ f x = μ • x := by
- rw [eigenspace, LinearMap.mem_ker, LinearMap.sub_apply, algebraMap_end_apply, sub_eq_zero]
+theorem mem_eigenspace_iff {f : End R M} {μ : R} {x : M} : x ∈ eigenspace f μ ↔ f x = μ • x :=
+ mem_genEigenspace_one
+nonrec
theorem HasEigenvector.apply_eq_smul {f : End R M} {μ : R} {x : M} (hx : f.HasEigenvector μ x) :
f x = μ • x :=
- mem_eigenspace_iff.mp hx.1
+ hx.apply_eq_smul
+nonrec
theorem HasEigenvector.pow_apply {f : End R M} {μ : R} {v : M} (hv : f.HasEigenvector μ v) (n : ℕ) :
- (f ^ n) v = μ ^ n • v := by
- induction n <;> simp [*, pow_succ f, hv.apply_eq_smul, smul_smul, pow_succ' μ]
+ (f ^ n) v = μ ^ n • v :=
+ hv.pow_apply n
theorem HasEigenvalue.exists_hasEigenvector {f : End R M} {μ : R} (hμ : f.HasEigenvalue μ) :
∃ v, f.HasEigenvector μ v :=
Submodule.exists_mem_ne_zero_of_ne_bot hμ
+nonrec
lemma HasEigenvalue.pow {f : End R M} {μ : R} (h : f.HasEigenvalue μ) (n : ℕ) :
- (f ^ n).HasEigenvalue (μ ^ n) := by
- rw [HasEigenvalue, Submodule.ne_bot_iff]
- obtain ⟨m : M, hm⟩ := h.exists_hasEigenvector
- exact ⟨m, by simpa [mem_eigenspace_iff] using hm.pow_apply n, hm.2⟩
+ (f ^ n).HasEigenvalue (μ ^ n) :=
+ h.pow n
/-- A nilpotent endomorphism has nilpotent eigenvalues.
See also `LinearMap.isNilpotent_trace_of_isNilpotent`. -/
+nonrec
lemma HasEigenvalue.isNilpotent_of_isNilpotent [NoZeroSMulDivisors R M] {f : End R M}
(hfn : IsNilpotent f) {μ : R} (hf : f.HasEigenvalue μ) :
- IsNilpotent μ := by
- obtain ⟨m : M, hm⟩ := hf.exists_hasEigenvector
- obtain ⟨n : ℕ, hn : f ^ n = 0⟩ := hfn
- exact ⟨n, by simpa [hn, hm.2, eq_comm (a := (0 : M))] using hm.pow_apply n⟩
+ IsNilpotent μ :=
+ hf.isNilpotent_of_isNilpotent hfn
+nonrec
theorem HasEigenvalue.mem_spectrum {f : End R M} {μ : R} (hμ : HasEigenvalue f μ) :
- μ ∈ spectrum R f := by
- refine spectrum.mem_iff.mpr fun h_unit => ?_
- set f' := LinearMap.GeneralLinearGroup.toLinearEquiv h_unit.unit
- rcases hμ.exists_hasEigenvector with ⟨v, hv⟩
- refine hv.2 ((LinearMap.ker_eq_bot'.mp f'.ker) v (?_ : μ • v - f v = 0))
- rw [hv.apply_eq_smul, sub_self]
+ μ ∈ spectrum R f :=
+ hμ.mem_spectrum
theorem hasEigenvalue_iff_mem_spectrum [FiniteDimensional K V] {f : End K V} {μ : K} :
- f.HasEigenvalue μ ↔ μ ∈ spectrum K f := by
- rw [spectrum.mem_iff, IsUnit.sub_iff, LinearMap.isUnit_iff_ker_eq_bot, HasEigenvalue, eigenspace]
+ f.HasEigenvalue μ ↔ μ ∈ spectrum K f :=
+ hasUnifEigenvalue_iff_mem_spectrum
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) :=
- calc
- eigenspace f (a / b) = eigenspace f (b⁻¹ * a) := by rw [div_eq_mul_inv, mul_comm]
- _ = LinearMap.ker (f - (b⁻¹ * a) • LinearMap.id) := by rw [eigenspace]; rfl
- _ = LinearMap.ker (f - b⁻¹ • a • LinearMap.id) := by rw [smul_smul]
- _ = LinearMap.ker (f - b⁻¹ • algebraMap K (End K V) a) := rfl
- _ = LinearMap.ker (b • (f - b⁻¹ • algebraMap K (End K V) a)) := by
- rw [LinearMap.ker_smul _ b hb]
- _ = LinearMap.ker (b • f - algebraMap K (End K V) a) := by rw [smul_sub, smul_inv_smul₀ 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 := LinearMap.ker ((f - algebraMap R (End R M) μ) ^ k)
- monotone' k m hm := by
- simp only [← pow_sub_mul_pow _ hm]
- exact
- LinearMap.ker_le_ker_comp ((f - algebraMap R (End R M) μ) ^ k)
- ((f - algebraMap R (End R M) μ) ^ (m - k))
-
-@[simp]
-theorem mem_genEigenspace (f : End R M) (μ : R) (k : ℕ) (m : M) :
- m ∈ f.genEigenspace μ k ↔ ((f - μ • (1 : End R M)) ^ k) m = 0 := Iff.rfl
+ genEigenspace_div f a b hb
-@[simp]
-theorem genEigenspace_zero (f : End R M) (k : ℕ) :
- f.genEigenspace 0 k = LinearMap.ker (f ^ k) := by
- simp [Module.End.genEigenspace]
+@[deprecated genEigenspace_nat (since := "2024-10-28")]
+lemma genEigenspace_def (f : End R M) (μ : R) (k : ℕ) :
+ 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])-/
-def HasGenEigenvector (f : End R M) (μ : R) (k : ℕ) (x : M) : Prop :=
- x ≠ 0 ∧ x ∈ genEigenspace f μ k
+abbrev HasGenEigenvector (f : End R M) (μ : R) (k : ℕ) (x : M) : Prop :=
+ HasUnifEigenvector f μ k x
+
+lemma hasGenEigenvector_iff {f : End R M} {μ : R} {k : ℕ} {x : M} :
+ f.HasGenEigenvector μ k x ↔ x ∈ f.genEigenspace μ k ∧ x ≠ 0 := Iff.rfl
/-- A scalar `μ` is a generalized eigenvalue for a linear map `f` and an exponent `k ∈ ℕ` if there
are generalized eigenvectors for `f`, `k`, and `μ`. -/
-def HasGenEigenvalue (f : End R M) (μ : R) (k : ℕ) : Prop :=
- genEigenspace f μ k ≠ ⊥
+abbrev HasGenEigenvalue (f : End R M) (μ : R) (k : ℕ) : Prop :=
+ HasUnifEigenvalue f μ k
+
+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`. -/
-def genEigenrange (f : End R M) (μ : R) (k : ℕ) : Submodule R M :=
- LinearMap.range ((f - algebraMap R (End R M) μ) ^ 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) :=
+ genEigenrange_nat
/-- The exponent of a generalized eigenvalue is never 0. -/
theorem exp_ne_zero_of_hasGenEigenvalue {f : End R M} {μ : R} {k : ℕ}
- (h : f.HasGenEigenvalue μ k) : k ≠ 0 := by
- rintro rfl
- exact h LinearMap.ker_id
+ (h : f.HasGenEigenvalue μ k) : k ≠ 0 :=
+ HasUnifEigenvalue.exp_ne_zero h
/-- The union of the kernels of `(f - μ • id) ^ k` over all `k`. -/
-def maxGenEigenspace (f : End R M) (μ : R) : Submodule R M :=
- ⨆ k, f.genEigenspace μ k
+abbrev maxGenEigenspace (f : End R M) (μ : R) : Submodule R M :=
+ 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 :=
+ (iSup_genEigenspace_eq f μ).symm
theorem genEigenspace_le_maximal (f : End R M) (μ : R) (k : ℕ) :
f.genEigenspace μ k ≤ f.maxGenEigenspace μ :=
- le_iSup _ _
+ (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 := by
- simp only [maxGenEigenspace, ← mem_genEigenspace, Submodule.mem_iSup_of_chain]
+ m ∈ f.maxGenEigenspace μ ↔ ∃ k : ℕ, ((f - μ • (1 : End R M)) ^ k) m = 0 :=
+ 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
meaningful. -/
-noncomputable def maxGenEigenspaceIndex (f : End R M) (μ : R) :=
- monotonicSequenceLimitIndex (f.genEigenspace μ)
+noncomputable abbrev maxGenEigenspaceIndex (f : End R M) (μ : R) :=
+ maxUnifEigenspaceIndex f μ
/-- For an endomorphism of a Noetherian module, the maximal eigenspace is always of the form kernel
`(f - μ • id) ^ k` for some `k`. -/
-theorem maxGenEigenspace_eq [h : IsNoetherian R M] (f : End R M) (μ : R) :
+theorem maxGenEigenspace_eq [IsNoetherian R M] (f : End R M) (μ : R) :
maxGenEigenspace f μ = f.genEigenspace μ (maxGenEigenspaceIndex f μ) :=
- h.wf.iSup_eq_monotonicSequenceLimit (f.genEigenspace μ)
+ genEigenspace_top_eq_maxUnifEigenspaceIndex _ _
/-- A generalized eigenvalue for some exponent `k` is also
a generalized eigenvalue for exponents larger than `k`. -/
theorem hasGenEigenvalue_of_hasGenEigenvalue_of_le {f : End R M} {μ : R} {k : ℕ}
{m : ℕ} (hm : k ≤ m) (hk : f.HasGenEigenvalue μ k) :
- f.HasGenEigenvalue μ m := by
- unfold HasGenEigenvalue at *
- contrapose! hk
- rw [← le_bot_iff, ← hk]
- exact (f.genEigenspace μ).monotone hm
+ f.HasGenEigenvalue μ m :=
+ hk.le <| by simpa using hm
/-- 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.genEigenspace μ).monotone (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)
- (hμ : f.HasEigenvalue μ) : f.HasGenEigenvalue μ k := by
- apply hasGenEigenvalue_of_hasGenEigenvalue_of_le hk
- rw [HasGenEigenvalue, genEigenspace, OrderHom.coe_mk, pow_one]
- exact hμ
+ (hμ : f.HasEigenvalue μ) : f.HasGenEigenvalue μ k :=
+ hμ.lt <| by simpa using hk
/-- All generalized eigenvalues are eigenvalues. -/
theorem hasEigenvalue_of_hasGenEigenvalue {f : End R M} {μ : R} {k : ℕ}
- (hμ : f.HasGenEigenvalue μ k) : f.HasEigenvalue μ := by
- intro contra; apply hμ
- erw [LinearMap.ker_eq_bot] at contra ⊢; rw [LinearMap.coe_pow]
- exact Function.Injective.iterate contra k
+ (hμ : f.HasGenEigenvalue μ k) : f.HasEigenvalue μ :=
+ hμ.lt zero_lt_one
/-- Generalized eigenvalues are actually just eigenvalues. -/
@[simp]
theorem hasGenEigenvalue_iff_hasEigenvalue {f : End R M} {μ : R} {k : ℕ} (hk : 0 < k) :
f.HasGenEigenvalue μ k ↔ f.HasEigenvalue μ :=
- ⟨hasEigenvalue_of_hasGenEigenvalue, hasGenEigenvalue_of_hasEigenvalue hk⟩
+ 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) :=
- ker_pow_le_ker_pow_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 _ _)
+ 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 μ
-/-- 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) :=
- ker_pow_eq_ker_pow_finrank_of_le 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 mapsTo_maxGenEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) :
+ 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
- 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 ↑(⨆ 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. -/
lemma isNilpotent_restrict_sub_algebraMap (f : End R M) (μ : R) (k : ℕ)
(h : MapsTo (f - algebraMap R (End R M) μ)
(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_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)
+ (h : MapsTo (f - algebraMap R (End R M) μ)
+ ↑(f.maxGenEigenspace μ) ↑(f.maxGenEigenspace μ) :=
+ mapsTo_maxGenEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ) :
IsNilpotent ((f - algebraMap R (End R M) μ).restrict h) := by
- use k
- ext
- simp [LinearMap.restrict_apply, LinearMap.pow_restrict _]
+ apply isNilpotent_restrict_of_le (q := f.genEigenspace μ (maxUnifEigenspaceIndex f μ))
+ _ (isNilpotent_restrict_genEigenspace_nat f μ (maxUnifEigenspaceIndex f μ))
+ rw [maxGenEigenspace_eq]
+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
- obtain ⟨l, hl⟩ : ∃ l, ⨆ k, f.genEigenspace μ k = f.genEigenspace μ l :=
- ⟨_, maxGenEigenspace_eq f μ⟩
- use l
- ext ⟨x, hx⟩
- simpa [hl, LinearMap.restrict_apply, LinearMap.pow_restrict _] using hx
+ apply isNilpotent_restrict_of_le (q := f.genEigenspace μ (maxUnifEigenspaceIndex f μ))
+ _ (isNilpotent_restrict_genEigenspace_nat f μ (maxUnifEigenspaceIndex f μ))
+ apply iSup_le
+ intro k
+ apply genEigenspace_le_genEigenspace_maxUnifEigenspaceIndex
lemma disjoint_genEigenspace [NoZeroSMulDivisors R M]
- (f : End R M) {μ₁ μ₂ : R} (hμ : μ₁ ≠ μ₂) (k l : ℕ) :
+ (f : End R M) {μ₁ μ₂ : R} (hμ : μ₁ ≠ μ₂) (k l : ℕ∞) :
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]
@@ -321,34 +627,48 @@ lemma disjoint_genEigenspace [NoZeroSMulDivisors R M]
(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₁) _ ⟨l, ?_⟩ ⟨k, ?_⟩
+ 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]
- all_goals ext ⟨x, _, _⟩; simpa [LinearMap.restrict_apply, LinearMap.pow_restrict _] using ‹_›
+ 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_iSup_genEigenspace [NoZeroSMulDivisors R M]
- (f : End R M) {μ₁ μ₂ : R} (hμ : μ₁ ≠ μ₂) :
- Disjoint (⨆ k, f.genEigenspace μ₁ k) (⨆ k, f.genEigenspace μ₂ k) := by
- simp_rw [(f.genEigenspace μ₁).mono.directed_le.disjoint_iSup_left,
- (f.genEigenspace μ₂).mono.directed_le.disjoint_iSup_right]
- exact 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)
+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_iSup_genEigenspace contra
+ 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_genEigenspace f hμ ⊤ ⊤
+
+lemma injOn_maxGenEigenspace [NoZeroSMulDivisors R M] (f : End R M) :
+ InjOn (f.maxGenEigenspace ·) {μ | f.maxGenEigenspace μ ≠ ⊥} :=
+ injOn_genEigenspace f ⊤
+
+@[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) :
- CompleteLattice.Independent (fun μ ↦ ⨆ k, f.genEigenspace μ k) := by
+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
- simp_rw [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
@@ -360,33 +680,43 @@ theorem independent_genEigenspace [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⟩
+ 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. -/
@@ -394,7 +724,7 @@ theorem eigenvectors_linearIndependent' {ι : Type*} [NoZeroSMulDivisors R M]
(f : End R M) (μ : ι → R) (hμ : Function.Injective μ) (v : ι → M)
(h_eigenvec : ∀ i, f.HasEigenvector (μ i) (v i)) : LinearIndependent R v :=
f.eigenspaces_independent.comp hμ |>.linearIndependent _
- (fun i => h_eigenvec i |>.left) (fun i => h_eigenvec i |>.right)
+ (fun i ↦ h_eigenvec i |>.left) (fun i ↦ h_eigenvec i |>.right)
/-- Eigenvectors corresponding to distinct eigenvalues of a linear operator are linearly
independent. (Lemma 5.10 of [axler2015])
@@ -405,27 +735,45 @@ theorem eigenvectors_linearIndependent' {ι : Type*} [NoZeroSMulDivisors R M]
theorem eigenvectors_linearIndependent [NoZeroSMulDivisors R M]
(f : End R M) (μs : Set R) (xs : μs → M)
(h_eigenvec : ∀ μ : μs, f.HasEigenvector μ (xs μ)) : LinearIndependent R xs :=
- f.eigenvectors_linearIndependent' (fun μ : μs => μ) Subtype.coe_injective _ h_eigenvec
+ f.eigenvectors_linearIndependent' (fun μ : μs ↦ μ) Subtype.coe_injective _ h_eigenvec
/-- 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, 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]
+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 μ₂)) :
+ MapsTo (f.restrict hf)
+ (maxGenEigenspace (g.restrict hg) μ₁)
+ (maxGenEigenspace (g.restrict hg) μ₂) := by
+ intro x hx
+ simp_rw [SetLike.mem_coe, mem_maxGenEigenspace, ← LinearMap.restrict_smul_one _,
+ LinearMap.restrict_sub _, LinearMap.pow_restrict _, LinearMap.restrict_apply,
+ Submodule.mk_eq_zero, ← mem_maxGenEigenspace] at hx ⊢
+ exact h hx
+
/-- If `p` is an invariant submodule of an endomorphism `f`, then the `μ`-eigenspace of the
restriction of `f` to `p` is a submodule of the `μ`-eigenspace of `f`. -/
theorem eigenspace_restrict_le_eigenspace (f : End R M) {p : Submodule R M} (hfp : ∀ x ∈ p, f x ∈ p)
@@ -440,16 +788,17 @@ theorem generalized_eigenvec_disjoint_range_ker [FiniteDimensional K V] (f : End
(f.genEigenspace μ (finrank K V)) := by
have h :=
calc
- Submodule.comap ((f - algebraMap _ _ μ) ^ finrank K V)
+ Submodule.comap ((f - μ • 1) ^ finrank K V)
(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, ← LinearMap.ker_comp]; rfl
- _ = f.genEigenspace μ (finrank K V + finrank K V) := by rw [← pow_add]; 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, LinearMap.range_eq_map,
- Submodule.map_inf_eq_map_inf_comap, top_inf_eq, h]
+ rw [genEigenspace_eq_genEigenspace_finrank_of_le]; omega
+ 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`,
@@ -468,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 : ℕ} :
@@ -476,68 +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]; 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 := 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/Minpoly.lean b/Mathlib/LinearAlgebra/Eigenspace/Minpoly.lean
index 95510728e054f..70c17ee7b2097 100644
--- a/Mathlib/LinearAlgebra/Eigenspace/Minpoly.lean
+++ b/Mathlib/LinearAlgebra/Eigenspace/Minpoly.lean
@@ -21,7 +21,7 @@ namespace Module
namespace End
-open Polynomial FiniteDimensional
+open Polynomial Module
open scoped Polynomial
@@ -68,7 +68,7 @@ variable {f} {μ : K}
theorem hasEigenvalue_of_isRoot (h : (minpoly K f).IsRoot μ) : f.HasEigenvalue μ := by
cases' dvd_iff_isRoot.2 h with p hp
- rw [HasEigenvalue, eigenspace]
+ rw [hasEigenvalue_iff, eigenspace_def]
intro con
cases' (LinearMap.isUnit_iff_ker_eq_bot _).2 con with u hu
have p_ne_0 : p ≠ 0 := by
@@ -78,7 +78,7 @@ theorem hasEigenvalue_of_isRoot (h : (minpoly K f).IsRoot μ) : f.HasEigenvalue
have : (aeval f) p = 0 := by
have h_aeval := minpoly.aeval K f
revert h_aeval
- simp [hp, ← hu]
+ simp [hp, ← hu, Algebra.algebraMap_eq_smul_one]
have h_deg := minpoly.degree_le_of_ne_zero K f p_ne_0 this
rw [hp, degree_mul, degree_X_sub_C, Polynomial.degree_eq_natDegree p_ne_0] at h_deg
norm_cast at h_deg
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 03cddde5f1423..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, ← (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 b6dd72733e4de..76112cc06a755 100644
--- a/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean
+++ b/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean
@@ -38,23 +38,27 @@ generalized eigenspaces span the whole space.
eigenspace, eigenvector, eigenvalue, eigen
-/
-open Set Function Module FiniteDimensional
+open Set Function Module Module
variable {K V : Type*} [Field K] [AddCommGroup V] [Module K V]
{R M : Type*} [CommRing R] [AddCommGroup M] [Module R M]
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, 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
@@ -99,61 +103,74 @@ theorem iSup_genEigenspace_eq_top [IsAlgClosed K] [FiniteDimensional K V] (f : E
apply pos_finrank_genEigenspace_of_hasEigenvalue hμ₀ (Nat.zero_lt_succ n)
-- 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_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 μ₁ μ₂
@@ -166,55 +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₂ μ')
- exact 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 ⊢
- rw [LinearMap.ker_noncommProd_eq_of_supIndep_ker _ _ <| this.supIndep' (m.support.erase μ),
- ← Finset.sup_eq_iSup]
- exact Finset.supIndep_iff_disjoint_erase.mp (this.supIndep' m.support) μ hμ
+ 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]
+ · 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
+
+/-- 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 4cc93bd2b2b32..21e08bdf55996 100644
--- a/Mathlib/LinearAlgebra/Eigenspace/Zero.lean
+++ b/Mathlib/LinearAlgebra/Eigenspace/Zero.lean
@@ -33,7 +33,7 @@ variable {R K M : Type*} [CommRing R] [IsDomain R] [Field K] [AddCommGroup M]
variable [Module R M] [Module.Finite R M] [Module.Free R M]
variable [Module K M] [Module.Finite K M]
-open FiniteDimensional Module.Free Polynomial
+open Module Module.Free Polynomial
lemma IsNilpotent.charpoly_eq_X_pow_finrank (φ : Module.End R M) (h : IsNilpotent φ) :
φ.charpoly = X ^ finrank R M := by
@@ -52,15 +52,14 @@ lemma charpoly_nilpotent_tfae [IsNoetherian R M] (φ : Module.End R M) :
φ.charpoly = X ^ finrank R M,
∀ m : M, ∃ (n : ℕ), (φ ^ n) m = 0,
natTrailingDegree φ.charpoly = finrank R M ] := by
- tfae_have 1 → 2
- · apply IsNilpotent.charpoly_eq_X_pow_finrank
+ tfae_have 1 → 2 := IsNilpotent.charpoly_eq_X_pow_finrank _
tfae_have 2 → 3
- · intro h m
+ | h, m => by
use finrank R M
suffices φ ^ finrank R M = 0 by simp only [this, LinearMap.zero_apply]
simpa only [h, map_pow, aeval_X] using φ.aeval_self_charpoly
tfae_have 3 → 1
- · intro h
+ | h => by
obtain ⟨n, hn⟩ := Filter.eventually_atTop.mp <| φ.eventually_iSup_ker_pow_eq
use n
ext x
@@ -68,8 +67,8 @@ lemma charpoly_nilpotent_tfae [IsNoetherian R M] (φ : Module.End R M) :
obtain ⟨k, hk⟩ := h x
rw [← mem_ker] at hk
exact Submodule.mem_iSup_of_mem _ hk
- tfae_have 2 ↔ 4
- · rw [← φ.charpoly_natDegree, φ.charpoly_monic.eq_X_pow_iff_natTrailingDegree_eq_natDegree]
+ tfae_have 2 ↔ 4 := by
+ rw [← φ.charpoly_natDegree, φ.charpoly_monic.eq_X_pow_iff_natTrailingDegree_eq_natDegree]
tfae_finish
lemma charpoly_eq_X_pow_iff [IsNoetherian R M] (φ : Module.End R M) :
@@ -85,27 +84,25 @@ lemma hasEigenvalue_zero_tfae (φ : Module.End K M) :
LinearMap.det φ = 0,
⊥ < ker φ,
∃ (m : M), m ≠ 0 ∧ φ m = 0 ] := by
- tfae_have 1 ↔ 2
- · exact Module.End.hasEigenvalue_iff_isRoot
- tfae_have 2 → 3
- · obtain ⟨F, hF⟩ := minpoly_dvd_charpoly φ
+ tfae_have 1 ↔ 2 := Module.End.hasEigenvalue_iff_isRoot
+ tfae_have 2 → 3 := by
+ obtain ⟨F, hF⟩ := minpoly_dvd_charpoly φ
simp only [IsRoot.def, constantCoeff_apply, coeff_zero_eq_eval_zero, hF, eval_mul]
intro h; rw [h, zero_mul]
- tfae_have 3 → 4
- · rw [← LinearMap.det_toMatrix (chooseBasis K M), Matrix.det_eq_sign_charpoly_coeff,
+ tfae_have 3 → 4 := by
+ rw [← LinearMap.det_toMatrix (chooseBasis K M), Matrix.det_eq_sign_charpoly_coeff,
constantCoeff_apply, charpoly]
intro h; rw [h, mul_zero]
- tfae_have 4 → 5
- · exact bot_lt_ker_of_det_eq_zero
- tfae_have 5 → 6
- · contrapose!
+ tfae_have 4 → 5 := bot_lt_ker_of_det_eq_zero
+ tfae_have 5 → 6 := by
+ contrapose!
simp only [not_bot_lt_iff, eq_bot_iff]
intro h x
simp only [mem_ker, Submodule.mem_bot]
contrapose!
apply h
tfae_have 6 → 1
- · rintro ⟨x, h1, h2⟩
+ | ⟨x, h1, h2⟩ => by
apply Module.End.hasEigenvalue_of_hasEigenvector ⟨_, h1⟩
simpa only [Module.End.eigenspace_zero, mem_ker] using h2
tfae_finish
@@ -135,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, Module.End.genEigenspace]
+ 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]
@@ -163,7 +160,7 @@ lemma finrank_maxGenEigenspace (φ : Module.End K M) :
apply b.ext
simp only [Basis.prod_apply, coe_inl, coe_inr, prodMap_apply, LinearEquiv.conj_apply,
LinearEquiv.symm_symm, Submodule.coe_prodEquivOfIsCompl, coe_comp, LinearEquiv.coe_coe,
- Function.comp_apply, coprod_apply, Submodule.coeSubtype, map_add, Sum.forall, Sum.elim_inl,
+ Function.comp_apply, coprod_apply, Submodule.coe_subtype, map_add, Sum.forall, Sum.elim_inl,
map_zero, ZeroMemClass.coe_zero, add_zero, LinearEquiv.eq_symm_apply, and_self,
Submodule.coe_prodEquivOfIsCompl', restrict_coe_apply, implies_true, Sum.elim_inr, zero_add,
e, V, W, ψ, F, G, b]
diff --git a/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean b/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean
index 3b3ed5d5dab30..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]
@@ -299,8 +305,8 @@ theorem ιMulti_apply {n : ℕ} (v : Fin n → M) : ιMulti R n v = (List.ofFn f
rfl
@[simp]
-theorem ιMulti_zero_apply (v : Fin 0 → M) : ιMulti R 0 v = 1 :=
- rfl
+theorem ιMulti_zero_apply (v : Fin 0 → M) : ιMulti R 0 v = 1 := by
+ simp [ιMulti]
@[simp]
theorem ιMulti_succ_apply {n : ℕ} (v : Fin n.succ → M) :
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 8aec07c6ff9dd..3b375180e50b1 100644
--- a/Mathlib/LinearAlgebra/FiniteDimensional.lean
+++ b/Mathlib/LinearAlgebra/FiniteDimensional.lean
@@ -27,20 +27,12 @@ variable {K : Type u} {V : Type v}
namespace Submodule
-open IsNoetherian FiniteDimensional
+open IsNoetherian Module
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 < ⊤) :
@@ -116,7 +108,7 @@ end FiniteDimensional
namespace LinearMap
-open FiniteDimensional
+open Module
section DivisionRing
@@ -142,7 +134,7 @@ end DivisionRing
end LinearMap
-open FiniteDimensional
+open Module
namespace LinearMap
diff --git a/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean b/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean
index 7209c69493247..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
/-!
@@ -27,7 +28,7 @@ that all these points of view are equivalent, with the following lemmas
- `fintypeBasisIndex` states that a finite-dimensional
vector space has a finite basis
-- `FiniteDimensional.finBasis` and `FiniteDimensional.finBasisOfFinrankEq`
+- `Module.finBasis` and `Module.finBasisOfFinrankEq`
are bases for finite dimensional vector spaces, where the index type
is `Fin` (in `Mathlib.LinearAlgebra.Dimension.Free`)
- `of_fintype_basis` states that the existence of a basis indexed by a
@@ -70,7 +71,7 @@ Plenty of the results hold for general fg modules or notherian modules, and they
universe u v v' w
-open Cardinal Submodule Module Function
+open Cardinal Function IsNoetherian Module Submodule
/-- `FiniteDimensional` vector spaces are defined to be finite modules.
Use `FiniteDimensional.of_fintype_basis` to prove finite dimension from another definition. -/
@@ -80,11 +81,6 @@ abbrev FiniteDimensional (K V : Type*) [DivisionRing K] [AddCommGroup V] [Module
variable {K : Type u} {V : Type v}
namespace FiniteDimensional
-
-open IsNoetherian
-
-section DivisionRing
-
variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂]
[Module K V₂]
@@ -112,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. -/
@@ -145,10 +136,8 @@ theorem of_finite_basis {ι : Type w} {s : Set ι} (h : Basis s K V) (hs : Set.F
instance finiteDimensional_submodule [FiniteDimensional K V] (S : Submodule K V) :
FiniteDimensional K S := by
letI : IsNoetherian K V := iff_fg.2 ?_
- · exact
- iff_fg.1
- (IsNoetherian.iff_rank_lt_aleph0.2
- (lt_of_le_of_lt (rank_submodule_le _) (_root_.rank_lt_aleph0 K V)))
+ · exact iff_fg.1 <| IsNoetherian.iff_rank_lt_aleph0.2 <|
+ (Submodule.rank_le _).trans_lt (rank_lt_aleph0 K V)
· infer_instance
/-- A quotient of a finite-dimensional space is also finite-dimensional. -/
@@ -156,18 +145,6 @@ instance finiteDimensional_quotient [FiniteDimensional K V] (S : Submodule K V)
FiniteDimensional K (V ⧸ S) :=
Module.Finite.quotient K S
-variable (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. -/
-theorem finrank_eq_rank' [FiniteDimensional K V] : (finrank K V : Cardinal.{v}) = Module.rank K V :=
- finrank_eq_rank _ _
-
-variable {K V}
-
-theorem finrank_of_infinite_dimensional (h : ¬FiniteDimensional K V) : finrank K V = 0 :=
- FiniteDimensional.finrank_of_not_finite h
-
theorem of_finrank_pos (h : 0 < finrank K V) : FiniteDimensional K V :=
Module.finite_of_finrank_pos h
@@ -181,6 +158,23 @@ theorem of_fact_finrank_eq_succ (n : ℕ) [hn : Fact (finrank K V = n + 1)] :
FiniteDimensional K V :=
of_finrank_eq_succ hn.out
+end FiniteDimensional
+
+namespace Module
+
+variable (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. -/
+theorem finrank_eq_rank' [FiniteDimensional K V] : (finrank K V : Cardinal.{v}) = Module.rank K V :=
+ finrank_eq_rank _ _
+
+variable {K V}
+
+theorem finrank_of_infinite_dimensional (h : ¬FiniteDimensional K V) : finrank K V = 0 :=
+ Module.finrank_of_not_finite h
+
theorem finiteDimensional_iff_of_rank_eq_nsmul {W} [AddCommGroup W] [Module K W] {n : ℕ}
(hn : n ≠ 0) (hVW : Module.rank K V = n • Module.rank K W) :
FiniteDimensional K V ↔ FiniteDimensional K W :=
@@ -192,11 +186,16 @@ theorem finrank_eq_card_basis' [FiniteDimensional K V] {ι : Type w} (h : Basis
(finrank K V : Cardinal.{w}) = #ι :=
Module.mk_finrank_eq_card_basis h
+end Module
+
+namespace FiniteDimensional
+section DivisionRing
+variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂]
+ [Module K V₂]
+
theorem _root_.LinearIndependent.lt_aleph0_of_finiteDimensional {ι : Type w} [FiniteDimensional K V]
{v : ι → V} (h : LinearIndependent K v) : #ι < ℵ₀ :=
h.lt_aleph0_of_finite
-@[deprecated (since := "2023-12-27")]
-alias lt_aleph0_of_linearIndependent := LinearIndependent.lt_aleph0_of_finiteDimensional
/-- If a submodule has maximal dimension in a finite dimensional space, then it is equal to the
whole space. -/
@@ -221,7 +220,7 @@ theorem _root_.Submodule.eq_top_of_finrank_eq [FiniteDimensional K V] {S : Submo
(by
rw [Set.card_image_of_injective _ Subtype.coe_injective, ← finrank_eq_card_basis bS, ←
finrank_eq_card_basis b, h])
- rw [← b.span_eq, b_eq, Basis.coe_extend, Subtype.range_coe, ← this, ← Submodule.coeSubtype,
+ rw [← b.span_eq, b_eq, Basis.coe_extend, Subtype.range_coe, ← this, ← Submodule.coe_subtype,
span_image]
have := bS.span_eq
rw [bS_eq, Basis.coe_ofVectorSpace, Subtype.range_coe] at this
@@ -254,8 +253,6 @@ section
open Finset
-section
-
variable {L : Type*} [LinearOrderedField L]
variable {W : Type v} [AddCommGroup W] [Module L W]
@@ -271,16 +268,14 @@ theorem exists_relation_sum_zero_pos_coefficient_of_finrank_succ_lt_card [Finite
exact ⟨f, sum, total, exists_pos_of_sum_zero_of_exists_nonzero f total nonzero⟩
-end
-
end
/-- In a vector space with dimension 1, each set {v} is a basis for `v ≠ 0`. -/
@[simps repr_apply]
noncomputable def basisSingleton (ι : Type*) [Unique ι] (h : finrank K V = 1) (v : V)
(hv : v ≠ 0) : Basis ι K V :=
- let b := FiniteDimensional.basisUnique ι h
- let h : b.repr v default ≠ 0 := mt FiniteDimensional.basisUnique_repr_eq_zero_iff.mp hv
+ let b := Module.basisUnique ι h
+ let h : b.repr v default ≠ 0 := mt Module.basisUnique_repr_eq_zero_iff.mp hv
Basis.ofRepr
{ toFun := fun w => Finsupp.single default (b.repr w default / b.repr v default)
invFun := fun f => f default • v
@@ -326,8 +321,6 @@ section ZeroRank
variable [DivisionRing K] [AddCommGroup V] [Module K V]
-open FiniteDimensional
-
theorem FiniteDimensional.of_rank_eq_nat {n : ℕ} (h : Module.rank K V = n) :
FiniteDimensional K V :=
Module.finite_of_rank_eq_nat h
@@ -350,7 +343,7 @@ alias finiteDimensional_of_rank_eq_one := FiniteDimensional.of_rank_eq_one
variable (K V)
instance finiteDimensional_bot : FiniteDimensional K (⊥ : Submodule K V) :=
- of_rank_eq_zero <| by simp
+ .of_rank_eq_zero <| by simp
variable {K V}
@@ -358,7 +351,7 @@ end ZeroRank
namespace Submodule
-open IsNoetherian FiniteDimensional
+open IsNoetherian Module
section DivisionRing
@@ -374,8 +367,7 @@ theorem finiteDimensional_of_le {S₁ S₂ : Submodule K V} [FiniteDimensional K
FiniteDimensional K S₁ :=
haveI : IsNoetherian K S₂ := iff_fg.2 inferInstance
iff_fg.1
- (IsNoetherian.iff_rank_lt_aleph0.2
- (lt_of_le_of_lt (rank_le_of_submodule _ _ h) (rank_lt_aleph0 K S₂)))
+ (IsNoetherian.iff_rank_lt_aleph0.2 ((Submodule.rank_mono h).trans_lt (rank_lt_aleph0 K S₂)))
/-- The inf of two submodules, the first finite-dimensional, is
finite-dimensional. -/
@@ -424,7 +416,7 @@ end Submodule
namespace LinearEquiv
-open FiniteDimensional
+open Module
variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂]
[Module K V₂]
@@ -434,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
@@ -449,12 +438,8 @@ instance finiteDimensional_finsupp {ι : Type*} [Finite ι] [FiniteDimensional K
end
-namespace FiniteDimensional
-
-section DivisionRing
-
-variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂]
- [Module K V₂]
+namespace Submodule
+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. -/
@@ -470,33 +455,29 @@ theorem eq_of_le_of_finrank_eq {S₁ S₂ : Submodule K V} [FiniteDimensional K
(hd : finrank K S₁ = finrank K S₂) : S₁ = S₂ :=
eq_of_le_of_finrank_le hle hd.ge
-section Subalgebra
+end Submodule
+
+namespace Subalgebra
variable {K L : Type*} [Field K] [Ring L] [Algebra K L] {F E : Subalgebra K L}
[hfin : FiniteDimensional K E]
/-- If a subalgebra is contained in a finite-dimensional
subalgebra with the same or smaller dimension, they are equal. -/
-theorem _root_.Subalgebra.eq_of_le_of_finrank_le (h_le : F ≤ E)
- (h_finrank : finrank K E ≤ finrank K F) : F = E :=
+theorem eq_of_le_of_finrank_le (h_le : F ≤ E) (h_finrank : finrank K E ≤ finrank K F) : F = E :=
haveI : Module.Finite K (Subalgebra.toSubmodule E) := hfin
- Subalgebra.toSubmodule_injective <| FiniteDimensional.eq_of_le_of_finrank_le h_le h_finrank
+ toSubmodule_injective <| Submodule.eq_of_le_of_finrank_le h_le h_finrank
/-- If a subalgebra is contained in a finite-dimensional
subalgebra with the same dimension, they are equal. -/
-theorem _root_.Subalgebra.eq_of_le_of_finrank_eq (h_le : F ≤ E)
- (h_finrank : finrank K F = finrank K E) : F = E :=
- Subalgebra.eq_of_le_of_finrank_le h_le h_finrank.ge
+theorem eq_of_le_of_finrank_eq (h_le : F ≤ E) (h_finrank : finrank K F = finrank K E) : F = E :=
+ eq_of_le_of_finrank_le h_le h_finrank.ge
end Subalgebra
-end DivisionRing
-
-end FiniteDimensional
-
namespace LinearMap
-open FiniteDimensional
+open Module
section DivisionRing
@@ -507,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. -/
@@ -600,7 +581,7 @@ end LinearMap
namespace LinearEquiv
-open FiniteDimensional
+open Module
variable [DivisionRing K] [AddCommGroup V] [Module K V]
variable [FiniteDimensional K V]
@@ -647,14 +628,14 @@ theorem isUnit_iff_range_eq_top [FiniteDimensional K V] (f : V →ₗ[K] V) :
end LinearMap
-open Module FiniteDimensional
+open FiniteDimensional Module
section
variable [DivisionRing K] [AddCommGroup V] [Module K V]
theorem finrank_zero_iff_forall_zero [FiniteDimensional K V] : finrank K V = 0 ↔ ∀ x : V, x = 0 :=
- FiniteDimensional.finrank_zero_iff.trans (subsingleton_iff_forall_eq 0)
+ Module.finrank_zero_iff.trans (subsingleton_iff_forall_eq 0)
/-- If `ι` is an empty type and `V` is zero-dimensional, there is a unique `ι`-indexed basis. -/
noncomputable def basisOfFinrankZero [FiniteDimensional K V] {ι : Type*} [IsEmpty ι]
@@ -679,36 +660,26 @@ noncomputable def divisionRingOfFiniteDimensional (F K : Type*) [Field F] [Ring
inv x :=
letI := Classical.decEq K
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
+ 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
-
-namespace Submodule
-
-section DivisionRing
-
-variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂]
- [Module K V₂]
-
-theorem finrank_mono [FiniteDimensional K V] : Monotone fun s : Submodule K V => finrank K s :=
- fun _ _ => finrank_le_finrank_of_le
-
-end DivisionRing
-
-end Submodule
+end
section DivisionRing
variable [DivisionRing K] [AddCommGroup V] [Module K V]
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 fe713da58c68c..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}
@@ -365,7 +365,7 @@ theorem supported_iUnion {δ : Type*} (s : δ → Set α) :
· exact zero_mem _
· refine fun x a l _ _ => add_mem ?_
by_cases h : ∃ i, x ∈ s i
- · simp only [mem_comap, coe_comp, coeSubtype, Function.comp_apply, restrictDom_apply,
+ · simp only [mem_comap, coe_comp, coe_subtype, Function.comp_apply, restrictDom_apply,
mem_iUnion, h, filter_single_of_pos]
cases' h with i hi
exact le_iSup (fun i => supported M R (s i)) i (single_mem_supported R _ hi)
@@ -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/FinsuppVectorSpace.lean b/Mathlib/LinearAlgebra/FinsuppVectorSpace.lean
index 6c96e6b6ad6ae..a25ac55d3ce5c 100644
--- a/Mathlib/LinearAlgebra/FinsuppVectorSpace.lean
+++ b/Mathlib/LinearAlgebra/FinsuppVectorSpace.lean
@@ -110,8 +110,7 @@ theorem coe_basis {φ : ι → Type*} (b : ∀ i, Basis (φ i) R M) :
Finsupp.single_apply_left sigma_mk_injective]
· have : Sigma.mk i x ≠ Sigma.mk j y := fun h' => h <| congrArg (fun s => s.fst) h'
-- Porting note: previously `this` not needed
- simp only [basis_repr, single_apply, h, this, false_and_iff, if_false, LinearEquiv.map_zero,
- zero_apply]
+ simp only [basis_repr, single_apply, h, this, if_false, LinearEquiv.map_zero, zero_apply]
/-- The basis on `ι →₀ M` with basis vectors `fun i ↦ single i 1`. -/
@[simps]
diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean
index b79eba46aca11..d9da43ef8b1b4 100644
--- a/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean
+++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean
@@ -20,16 +20,9 @@ We provide some instances for finite and free modules.
universe u v w
-variable (R : Type u) (M : Type v) (N : Type w)
-
-namespace Module.Free
-
-section Ring
-
-variable [Ring R] [AddCommGroup M] [Module R M] [Module.Free R M]
-
/-- If a free module is finite, then the arbitrary basis is finite. -/
-noncomputable instance ChooseBasisIndex.fintype [Module.Finite R M] :
+noncomputable instance Module.Free.ChooseBasisIndex.fintype (R : Type u) (M : Type v)
+ [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
@@ -38,28 +31,21 @@ noncomputable instance ChooseBasisIndex.fintype [Module.Finite R M] :
infer_instance
· exact Module.Finite.finite_basis (chooseBasis _ _)
-end Ring
-
-section CommRing
-
-variable [CommRing R] [AddCommGroup M] [Module R M] [Module.Free R M]
-variable [AddCommGroup N] [Module R N] [Module.Free R N]
-variable {R}
-
/-- A free module with a basis indexed by a `Fintype` is finite. -/
-theorem _root_.Module.Finite.of_basis {R M ι : Type*} [Semiring R] [AddCommMonoid M] [Module R M]
+theorem Module.Finite.of_basis {R M ι : Type*} [Semiring R] [AddCommMonoid M] [Module R M]
[_root_.Finite ι] (b : Basis ι R M) : Module.Finite R M := by
cases nonempty_fintype ι
classical
refine ⟨⟨Finset.univ.image b, ?_⟩⟩
simp only [Set.image_univ, Finset.coe_univ, Finset.coe_image, Basis.span_eq]
-instance _root_.Module.Finite.matrix {ι₁ ι₂ : 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 _)
-
-end CommRing
+ exact Module.Finite.of_basis <| (Free.chooseBasis _ _).matrix _ _
-end Module.Free
+example {ι₁ ι₂ R : Type*} [Semiring R] [Finite ι₁] [Finite ι₂] :
+ Module.Finite R (Matrix ι₁ ι₂ R) := inferInstance
diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean
index d0b35b5f4be62..27e40eb067043 100644
--- a/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean
+++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean
@@ -26,7 +26,7 @@ variable (R : Type u) (S : Type u') (M : Type v) (N : Type w)
open Module.Free (chooseBasis ChooseBasisIndex)
-open FiniteDimensional (finrank)
+open Module (finrank)
section Ring
@@ -46,27 +46,27 @@ instance Module.Finite.linearMap [Module.Finite S N] : Module.Finite S (M →ₗ
variable [StrongRankCondition R] [StrongRankCondition S] [Module.Free S N]
open Cardinal
-theorem FiniteDimensional.rank_linearMap :
+theorem Module.rank_linearMap :
Module.rank S (M →ₗ[R] N) = lift.{w} (Module.rank R M) * lift.{v} (Module.rank S N) := by
rw [(linearMapEquivFun R S M N).rank_eq, rank_fun_eq_lift_mul,
← finrank_eq_card_chooseBasisIndex, ← finrank_eq_rank R, lift_natCast]
/-- The finrank of `M →ₗ[R] N` as an `S`-module is `(finrank R M) * (finrank S N)`. -/
-theorem FiniteDimensional.finrank_linearMap :
+theorem Module.finrank_linearMap :
finrank S (M →ₗ[R] N) = finrank R M * finrank S N := by
simp_rw [finrank, rank_linearMap, toNat_mul, toNat_lift]
variable [Module R S] [SMulCommClass R S S]
-theorem FiniteDimensional.rank_linearMap_self :
+theorem Module.rank_linearMap_self :
Module.rank S (M →ₗ[R] S) = lift.{u'} (Module.rank R M) := by
rw [rank_linearMap, rank_self, lift_one, mul_one]
-theorem FiniteDimensional.finrank_linearMap_self : finrank S (M →ₗ[R] S) = finrank R M := by
+theorem Module.finrank_linearMap_self : finrank S (M →ₗ[R] S) = finrank R M := by
rw [finrank_linearMap, finrank_self, mul_one]
@[deprecated (since := "2024-01-12")]
-alias FiniteDimensional.finrank_linear_map' := FiniteDimensional.finrank_linearMap_self
+alias Module.finrank_linear_map' := Module.finrank_linearMap_self
end Ring
@@ -84,12 +84,12 @@ theorem cardinal_mk_algHom_le_rank : #(M →ₐ[K] L) ≤ lift.{v} (Module.rank
convert (linearIndependent_algHom_toLinearMap K M L).cardinal_lift_le_rank
· rw [lift_id]
· have := Module.nontrivial K L
- rw [lift_id, FiniteDimensional.rank_linearMap_self]
+ rw [lift_id, Module.rank_linearMap_self]
theorem card_algHom_le_finrank : Nat.card (M →ₐ[K] L) ≤ finrank K M := by
convert toNat_le_toNat (cardinal_mk_algHom_le_rank K M L) ?_
· rw [toNat_lift, finrank]
- · rw [lift_lt_aleph0]; have := Module.nontrivial K L; apply rank_lt_aleph0
+ · rw [lift_lt_aleph0]; have := Module.nontrivial K L; apply Module.rank_lt_aleph0
end AlgHom
diff --git a/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean b/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean
index 44870709f726a..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
@@ -114,9 +114,9 @@ noncomputable def quotientEquivDirectSum :
theorem finrank_quotient_eq_sum {ι} [Fintype ι] (b : Basis ι R S) [Nontrivial F]
[∀ i, Module.Free F (R ⧸ span ({I.smithCoeffs b hI i} : Set R))]
[∀ i, Module.Finite F (R ⧸ span ({I.smithCoeffs b hI i} : Set R))] :
- FiniteDimensional.finrank F (S ⧸ I) =
- ∑ i, FiniteDimensional.finrank F (R ⧸ span ({I.smithCoeffs b hI i} : Set R)) := by
+ Module.finrank F (S ⧸ I) =
+ ∑ i, Module.finrank F (R ⧸ span ({I.smithCoeffs b hI i} : Set R)) := by
-- slow, and dot notation doesn't work
- rw [LinearEquiv.finrank_eq <| quotientEquivDirectSum F b hI, FiniteDimensional.finrank_directSum]
+ rw [LinearEquiv.finrank_eq <| quotientEquivDirectSum F b hI, Module.finrank_directSum]
end Ideal
diff --git a/Mathlib/LinearAlgebra/FreeModule/Norm.lean b/Mathlib/LinearAlgebra/FreeModule/Norm.lean
index 39bb414d9ce5c..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
@@ -71,7 +71,7 @@ instance (b : Basis ι F[X] S) {I : Ideal S} (hI : I ≠ ⊥) (i : ι) :
`F`-vector space is the degree of the norm of `f` relative to `F[X]`. -/
theorem finrank_quotient_span_eq_natDegree_norm [Algebra F S] [IsScalarTower F F[X] S]
(b : Basis ι F[X] S) {f : S} (hf : f ≠ 0) :
- FiniteDimensional.finrank F (S ⧸ span ({f} : Set S)) = (Algebra.norm F[X] f).natDegree := by
+ Module.finrank F (S ⧸ span ({f} : Set S)) = (Algebra.norm F[X] f).natDegree := by
haveI := Fintype.ofFinite ι
have h := span_singleton_eq_bot.not.2 hf
rw [natDegree_eq_of_degree_eq
diff --git a/Mathlib/LinearAlgebra/FreeModule/PID.lean b/Mathlib/LinearAlgebra/FreeModule/PID.lean
index ea581374ba3ee..3e5251f600539 100644
--- a/Mathlib/LinearAlgebra/FreeModule/PID.lean
+++ b/Mathlib/LinearAlgebra/FreeModule/PID.lean
@@ -234,7 +234,7 @@ theorem Submodule.basis_of_pid_aux [Finite ι] {O : Type*} [AddCommGroup O] [Mod
rw [LinearMap.mem_ker] at hx'
have hc' : (c • ⟨y', y'M⟩ + ⟨x, xM⟩ : M) = 0 := by exact @Subtype.coe_injective O (· ∈ M) _ _ hc
simpa only [LinearMap.map_add, LinearMap.map_zero, LinearMap.map_smul, smul_eq_mul, add_zero,
- mul_eq_zero, ϕy'_ne_zero, hx', or_false_iff] using congr_arg ϕ hc'
+ mul_eq_zero, ϕy'_ne_zero, hx', or_false] using congr_arg ϕ hc'
-- And `a • y'` is orthogonal to `N'`.
have ay'_ortho_N' : ∀ (c : R), ∀ z ∈ N', c • a • y' + z = 0 → c = 0 := by
intro c z zN' hc
@@ -251,7 +251,7 @@ theorem Submodule.basis_of_pid_aux [Finite ι] {O : Type*} [AddCommGroup O] [Mod
refine ⟨-b, Submodule.mem_map.mpr ⟨⟨_, N.sub_mem zN (N.smul_mem b yN)⟩, ?_, ?_⟩⟩
· refine LinearMap.mem_ker.mpr (show ϕ (⟨z, N_le_M zN⟩ - b • ⟨y, N_le_M yN⟩) = 0 from ?_)
rw [LinearMap.map_sub, LinearMap.map_smul, hb, ϕy_eq, smul_eq_mul, mul_comm, sub_self]
- · simp only [sub_eq_add_neg, neg_smul, coeSubtype]
+ · simp only [sub_eq_add_neg, neg_smul, coe_subtype]
-- And extend a basis for `M'` with `y'`
intro m' hn'm' bM'
refine ⟨Nat.succ_le_succ hn'm', ?_, ?_⟩
@@ -270,7 +270,7 @@ theorem Submodule.basis_of_pid_aux [Finite ι] {O : Type*} [AddCommGroup O] [Mod
· simp only [Fin.cons_zero, Fin.castLE_zero]
exact a_smul_y'.symm
· rw [Fin.castLE_succ]
- simp only [Fin.cons_succ, Function.comp_apply, coe_inclusion, map_coe, coeSubtype, h i]
+ simp only [Fin.cons_succ, Function.comp_apply, coe_inclusion, map_coe, coe_subtype, h i]
/-- A submodule of a free `R`-module of finite rank is also a free `R`-module of finite rank,
if `R` is a principal ideal domain.
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 2e8c75c44c9d9..21a217aa2d30c 100644
--- a/Mathlib/LinearAlgebra/InvariantBasisNumber.lean
+++ b/Mathlib/LinearAlgebra/InvariantBasisNumber.lean
@@ -1,10 +1,10 @@
/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel, Scott Morrison
+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 7a9bb31cd43fa..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.
@@ -83,7 +83,7 @@ theorem quotientInfEquivSupQuotient_surjective (p p' : Submodule R M) :
rw [← range_eq_top, quotientInfToSupQuotient, range_liftQ, eq_top_iff']
rintro ⟨x, hx⟩; rcases mem_sup.1 hx with ⟨y, hy, z, hz, rfl⟩
use ⟨y, hy⟩; apply (Submodule.Quotient.eq _).2
- simp only [mem_comap, map_sub, coeSubtype, coe_inclusion, sub_add_cancel_left, neg_mem_iff, hz]
+ simp only [mem_comap, map_sub, coe_subtype, coe_inclusion, sub_add_cancel_left, neg_mem_iff, hz]
/--
Second Isomorphism Law : the canonical map from `p/(p ∩ p')` to `(p+p')/p'` as a linear isomorphism.
@@ -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.coeSubtype]
+ (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 982898e6d7590..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
@@ -145,7 +146,7 @@ theorem basisDivisor_self : basisDivisor x x = 0 := by
simp only [basisDivisor, sub_self, inv_zero, map_zero, zero_mul]
theorem basisDivisor_inj (hxy : basisDivisor x y = 0) : x = y := by
- simp_rw [basisDivisor, mul_eq_zero, X_sub_C_ne_zero, or_false_iff, C_eq_zero, inv_eq_zero,
+ simp_rw [basisDivisor, mul_eq_zero, X_sub_C_ne_zero, or_false, C_eq_zero, inv_eq_zero,
sub_eq_zero] at hxy
exact hxy
@@ -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 20c9c3b4316e4..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,
@@ -311,8 +311,8 @@ theorem linearIndependent_left_of_flat (H : M.LinearDisjoint N) [Module.Flat R N
{ι : Type*} {m : ι → M} (hm : LinearIndependent R m) : LinearMap.ker (mulLeftMap N m) = ⊥ := by
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
+ ← Function.comp_assoc, EquivLike.injective_comp]
+ 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,
@@ -332,8 +332,8 @@ theorem linearIndependent_right_of_flat (H : M.LinearDisjoint N) [Module.Flat R
{ι : Type*} {n : ι → N} (hn : LinearIndependent R n) : LinearMap.ker (mulRightMap M n) = ⊥ := by
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
+ ← Function.comp_assoc, EquivLike.injective_comp]
+ 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
@@ -512,7 +512,7 @@ if any two elements of `↥(M ⊓ N)` are commutative, then the rank of `↥(M
theorem rank_inf_le_one_of_commute_of_flat (hf : Module.Flat R M ∨ Module.Flat R N)
(hc : ∀ (m n : ↥(M ⊓ N)), Commute m.1 n.1) : Module.rank R ↥(M ⊓ N) ≤ 1 := by
nontriviality R
- refine rank_le fun s h ↦ ?_
+ refine _root_.rank_le fun s h ↦ ?_
by_contra hs
rw [not_le, ← Fintype.card_coe, Fintype.one_lt_card_iff_nontrivial] at hs
obtain ⟨a, b, hab⟩ := hs.exists_pair_ne
diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean
index 3a13689ce7686..1c1b164bab895 100644
--- a/Mathlib/LinearAlgebra/LinearIndependent.lean
+++ b/Mathlib/LinearAlgebra/LinearIndependent.lean
@@ -11,7 +11,8 @@ import Mathlib.Tactic.FinCases
import Mathlib.Tactic.LinearCombination
import Mathlib.Lean.Expr.ExtraRecognizers
import Mathlib.Data.Set.Subsingleton
-import Mathlib.Tactic.Abel
+import Mathlib.Tactic.Module
+import Mathlib.Tactic.NoncommRing
/-!
@@ -21,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
@@ -69,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
@@ -85,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
@@ -119,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 ↔
@@ -143,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'' :
@@ -185,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} :
@@ -216,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 :
@@ -247,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,
@@ -259,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]
@@ -276,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 ⊢
@@ -290,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
@@ -355,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) :
@@ -411,8 +430,8 @@ theorem linearIndependent_comp_subtype {s : Set ι} :
Set.subset_def, Finset.mem_coe]
constructor
· intro h l hl₁ hl₂
- have := h (l.subtypeDomain s) ((Finsupp.sum_subtypeDomain_index hl₁).trans hl₂)
- exact (Finsupp.subtypeDomain_eq_zero_iff hl₁).1 this
+ exact (Finsupp.subtypeDomain_eq_zero_iff hl₁).1 <|
+ h (l.subtypeDomain s) ((Finsupp.sum_subtypeDomain_index hl₁).trans hl₂)
· intro h l hl
refine Finsupp.embDomain_eq_zero.1 (h (l.embDomain <| Function.Embedding.subtype s) ?_ ?_)
· suffices ∀ i hi, ¬l ⟨i, hi⟩ = 0 → i ∈ s by simpa
@@ -461,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]
@@ -514,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
@@ -591,15 +586,13 @@ theorem LinearIndependent.units_smul {v : ι → M} (hv : LinearIndependent R v)
exact (hgs i hi).symm ▸ zero_smul _ _
· rw [← hsum, Finset.sum_congr rfl _]
intros
- erw [Pi.smul_apply, smul_assoc]
- rfl
+ rw [Pi.smul_apply', smul_assoc, Units.smul_def]
lemma LinearIndependent.eq_of_pair {x y : M} (h : LinearIndependent R ![x, y])
{s t s' t' : R} (h' : s • x + t • y = s' • x + t' • y) : s = s' ∧ t = t' := by
have : (s - s') • x + (t - t') • y = 0 := by
- rw [← sub_eq_zero_of_eq h', ← sub_eq_zero]
- simp only [sub_smul]
- abel
+ rw [← sub_eq_zero_of_eq h']
+ match_scalars <;> noncomm_ring
simpa [sub_eq_zero] using h.eq_zero_of_pair this
lemma LinearIndependent.eq_zero_of_pair' {x y : M} (h : LinearIndependent R ![x, y])
@@ -617,8 +610,7 @@ lemma LinearIndependent.linear_combination_pair_of_det_ne_zero {R M : Type*} [Co
apply LinearIndependent.pair_iff.2 (fun s t hst ↦ ?_)
have H : (s * a + t * c) • x + (s * b + t * d) • y = 0 := by
convert hst using 1
- simp only [_root_.add_smul, smul_add, smul_smul]
- abel
+ module
have I1 : s * a + t * c = 0 := (h.eq_zero_of_pair H).1
have I2 : s * b + t * d = 0 := (h.eq_zero_of_pair H).2
have J1 : (a * d - b * c) * s = 0 := by linear_combination d * I1 - c * I2
@@ -633,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
@@ -821,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]
@@ -935,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
@@ -1016,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
@@ -1112,11 +1102,10 @@ theorem linearIndependent_monoidHom (G : Type*) [Monoid G] (L : Type*) [CommRing
rw [Finset.sum_insert has, Finset.sum_insert has]
_ =
(∑ i ∈ insert a s, g i * i (x * y)) -
- ∑ i ∈ insert a s, a x * (g i * i y) :=
- congr
- (congr_arg Sub.sub
- (Finset.sum_congr rfl fun i _ => by rw [i.map_mul, mul_assoc]))
- (Finset.sum_congr rfl fun _ _ => by rw [mul_assoc, mul_left_comm])
+ ∑ i ∈ insert a s, a x * (g i * i y) := by
+ congrm ∑ i ∈ insert a s, ?_ - ∑ i ∈ insert a s, ?_
+ · rw [map_mul, mul_assoc]
+ · rw [mul_assoc, mul_left_comm]
_ =
(∑ i ∈ insert a s, (g i • (i : G → L))) (x * y) -
a x * (∑ i ∈ insert a s, (g i • (i : G → L))) y := by
@@ -1188,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
@@ -1216,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
@@ -1232,7 +1220,7 @@ theorem mem_span_insert_exchange :
have a0 : a ≠ 0 := by
rintro rfl
simp_all
- simp [a0, smul_add, smul_smul]
+ match_scalars <;> simp [a0]
theorem linearIndependent_iff_not_mem_span :
LinearIndependent K v ↔ ∀ i, v i ∉ span K (v '' (univ \ {i})) := by
@@ -1255,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⟩⟩
@@ -1306,8 +1294,8 @@ theorem LinearIndependent.pair_iff' {x y : V} (hx : x ≠ 0) :
by_cases ht : t = 0
· exact ⟨by simpa [ht, hx] using hst, ht⟩
apply_fun (t⁻¹ • ·) at hst
- simp only [smul_add, smul_smul, inv_mul_cancel₀ ht, one_smul, smul_zero] at hst
- cases H (-(t⁻¹ * s)) (by rwa [neg_smul, neg_eq_iff_eq_neg, eq_neg_iff_add_eq_zero])
+ simp only [smul_add, smul_smul, inv_mul_cancel₀ ht] at hst
+ cases H (-(t⁻¹ * s)) <| by linear_combination (norm := match_scalars <;> noncomm_ring) -hst
theorem linearIndependent_fin_cons {n} {v : Fin n → V} :
LinearIndependent K (Fin.cons x v : Fin (n + 1) → V) ↔
@@ -1404,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 a22821e0e63c5..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 -/
@@ -847,7 +846,7 @@ theorem le_graph_of_le {f g : E →ₗ.[R] F} (h : f ≤ g) : f.graph ≤ g.grap
rw [mem_graph_iff] at hx ⊢
cases' hx with y hx
use ⟨y, h.1 y.2⟩
- simp only [hx, Submodule.coe_mk, eq_self_iff_true, true_and_iff]
+ simp only [hx, Submodule.coe_mk, eq_self_iff_true, true_and]
convert hx.2 using 1
refine (h.2 ?_).symm
simp only [hx.1, Submodule.coe_mk]
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 b814a9748abac..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
@@ -495,8 +494,8 @@ theorem adjugate_adjugate (A : Matrix n n α) (h : Fintype.card n ≠ 1) :
let A' := mvPolynomialX n n ℤ
suffices adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A' by
rw [← mvPolynomialX_mapMatrix_aeval ℤ A, ← AlgHom.map_adjugate, ← AlgHom.map_adjugate, this,
- ← AlgHom.map_det, ← map_pow (MvPolynomial.aeval _), AlgHom.mapMatrix_apply,
- AlgHom.mapMatrix_apply, Matrix.map_smul' _ _ _ (_root_.map_mul _)]
+ ← AlgHom.map_det, ← map_pow (MvPolynomial.aeval fun p : n × n ↦ A p.1 p.2),
+ AlgHom.mapMatrix_apply, AlgHom.mapMatrix_apply, Matrix.map_smul' _ _ _ (_root_.map_mul _)]
have h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1 := by simp [h_card]
have is_reg : IsSMulRegular (MvPolynomial (n × n) ℤ) (det A') := fun x y =>
mul_left_cancel₀ (det_mvPolynomialX_ne_zero n ℤ)
diff --git a/Mathlib/LinearAlgebra/Matrix/BilinearForm.lean b/Mathlib/LinearAlgebra/Matrix/BilinearForm.lean
index 1c8964c5c90ae..6ba3a7550fedf 100644
--- a/Mathlib/LinearAlgebra/Matrix/BilinearForm.lean
+++ b/Mathlib/LinearAlgebra/Matrix/BilinearForm.lean
@@ -3,10 +3,6 @@ Copyright (c) 2020 Anne Baanen. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Anne Baanen, Kexing Ying
-/
-import Mathlib.LinearAlgebra.Matrix.Basis
-import Mathlib.LinearAlgebra.Matrix.Nondegenerate
-import Mathlib.LinearAlgebra.Matrix.NonsingularInverse
-import Mathlib.LinearAlgebra.Matrix.ToLinearEquiv
import Mathlib.LinearAlgebra.BilinearForm.Properties
import Mathlib.LinearAlgebra.Matrix.SesquilinearForm
@@ -25,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
@@ -39,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
@@ -57,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'
@@ -94,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'])
@@ -198,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]
@@ -234,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,
@@ -305,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] :
@@ -322,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
@@ -331,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
@@ -342,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' :
@@ -351,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' :
@@ -368,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
@@ -424,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 c998bad25a879..401caa2ef1eff 100644
--- a/Mathlib/LinearAlgebra/Matrix/Block.lean
+++ b/Mathlib/LinearAlgebra/Matrix/Block.lean
@@ -62,7 +62,7 @@ theorem blockTriangular_reindex_iff {b : n → α} {e : m ≃ n} :
· convert h.submatrix
simp only [reindex_apply, submatrix_submatrix, submatrix_id_id, Equiv.symm_comp_self]
· convert h.submatrix
- simp only [comp.assoc b e e.symm, Equiv.self_comp_symm, comp_id]
+ simp only [comp_assoc b e e.symm, Equiv.self_comp_symm, comp_id]
protected theorem BlockTriangular.transpose :
M.BlockTriangular b → Mᵀ.BlockTriangular (toDual ∘ b) :=
@@ -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 cffadee4baad5..f2f8e2eff0c0c 100644
--- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Basic.lean
+++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Basic.lean
@@ -1,9 +1,10 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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/Coeff.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean
index 1fcd2932b0cee..4a0d9f53997f4 100644
--- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean
+++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean
@@ -204,7 +204,7 @@ lemma derivative_det_one_add_X_smul_aux {n} (M : Matrix (Fin n) (Fin n) R) :
rw [det_eq_zero_of_column_eq_zero 0, eval_zero, mul_zero]
intro j
rw [submatrix_apply, Fin.succAbove_of_castSucc_lt, one_apply_ne]
- · exact (bne_iff_ne (Fin.succ j) (Fin.castSucc 0)).mp rfl
+ · exact (bne_iff_ne (a := Fin.succ j) (b := Fin.castSucc 0)).mp rfl
· rw [Fin.castSucc_zero]; exact lt_of_le_of_ne (Fin.zero_le _) hi.symm
· exact fun H ↦ (H <| Finset.mem_univ _).elim
@@ -214,7 +214,7 @@ lemma derivative_det_one_add_X_smul (M : Matrix n n R) :
let e := Matrix.reindexLinearEquiv R R (Fintype.equivFin n) (Fintype.equivFin n)
rw [← Matrix.det_reindexLinearEquiv_self R[X] (Fintype.equivFin n)]
convert derivative_det_one_add_X_smul_aux (e M)
- · ext; simp [e]
+ · ext; simp [map_add, e]
· delta trace
rw [← (Fintype.equivFin n).symm.sum_comp]
simp_rw [e, reindexLinearEquiv_apply, reindex_apply, diag_apply, submatrix_apply]
@@ -326,7 +326,8 @@ lemma reverse_charpoly (M : Matrix n n R) :
← mul_one (Fintype.card n : ℤ), ← T_pow, map_pow, invert_T, mul_comm]
rw [← det_smul, smul_sub, scalar_apply, ← diagonal_smul, Pi.smul_def, smul_eq_mul, ht,
diagonal_one, invert.map_det]
- simp [t, map_smul', smul_eq_diagonal_mul]
+ simp [map_sub, _root_.map_one, _root_.map_mul, t, map_smul', smul_eq_diagonal_mul]
+
@[simp] lemma eval_charpolyRev :
eval 0 M.charpolyRev = 1 := by
diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/Eigs.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Eigs.lean
index ccd5c26310966..4eb330442505f 100644
--- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Eigs.lean
+++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Eigs.lean
@@ -58,7 +58,7 @@ namespace Matrix
theorem det_eq_prod_roots_charpoly_of_splits (hAps : A.charpoly.Splits (RingHom.id R)) :
A.det = (Matrix.charpoly A).roots.prod := by
rw [det_eq_sign_charpoly_coeff, ← charpoly_natDegree_eq_dim A,
- Polynomial.prod_roots_eq_coeff_zero_of_monic_of_split A.charpoly_monic hAps, ← mul_assoc,
+ Polynomial.prod_roots_eq_coeff_zero_of_monic_of_splits A.charpoly_monic hAps, ← mul_assoc,
← pow_two, pow_right_comm, neg_one_sq, one_pow, one_mul]
theorem trace_eq_sum_roots_charpoly_of_splits (hAps : A.charpoly.Splits (RingHom.id R)) :
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 85a32f9416529..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_iff, 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)
@@ -183,14 +179,14 @@ theorem det_mul_left_comm (M N P : Matrix m m R) : det (M * (N * P)) = det (N *
theorem det_mul_right_comm (M N P : Matrix m m R) : det (M * N * P) = det (M * P * N) := by
rw [Matrix.mul_assoc, Matrix.mul_assoc, det_mul, det_mul_comm N P, ← det_mul]
--- TODO(mathlib4#6607): fix elaboration so that the ascription isn't needed
+-- TODO(mathlib4#6607): fix elaboration so `val` isn't needed
theorem det_units_conj (M : (Matrix m m R)ˣ) (N : Matrix m m R) :
- det ((M : Matrix _ _ _) * N * (↑M⁻¹ : Matrix _ _ _)) = det N := by
+ det (M.val * N * M⁻¹.val) = det N := by
rw [det_mul_right_comm, Units.mul_inv, one_mul]
--- TODO(mathlib4#6607): fix elaboration so that the ascription isn't needed
+-- TODO(mathlib4#6607): fix elaboration so `val` isn't needed
theorem det_units_conj' (M : (Matrix m m R)ˣ) (N : Matrix m m R) :
- det ((↑M⁻¹ : Matrix _ _ _) * N * (↑M : Matrix _ _ _)) = det N :=
+ det (M⁻¹.val * N * ↑M.val) = det N :=
det_units_conj M⁻¹ N
/-- Transposing a matrix preserves the determinant. -/
@@ -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⟩⟩
@@ -747,7 +742,7 @@ theorem det_fin_one_of (a : R) : det !![a] = a :=
theorem det_fin_two (A : Matrix (Fin 2) (Fin 2) R) : det A = A 0 0 * A 1 1 - A 0 1 * A 1 0 := by
simp only [det_succ_row_zero, det_unique, Fin.default_eq_zero, submatrix_apply,
Fin.succ_zero_eq_one, Fin.sum_univ_succ, Fin.val_zero, Fin.zero_succAbove, univ_unique,
- Fin.val_succ, Fin.coe_fin_one, Fin.succ_succAbove_zero, sum_singleton]
+ Fin.val_succ, Fin.val_eq_zero, Fin.succ_succAbove_zero, sum_singleton]
ring
@[simp]
@@ -763,7 +758,7 @@ theorem det_fin_three (A : Matrix (Fin 3) (Fin 3) R) :
simp only [det_succ_row_zero, ← Nat.not_even_iff_odd, submatrix_apply, Fin.succ_zero_eq_one,
submatrix_submatrix, det_unique, Fin.default_eq_zero, comp_apply, Fin.succ_one_eq_two,
Fin.sum_univ_succ, Fin.val_zero, Fin.zero_succAbove, univ_unique, Fin.val_succ,
- Fin.coe_fin_one, Fin.succ_succAbove_zero, sum_singleton, Fin.succ_succAbove_one, even_add_self]
+ Fin.val_eq_zero, Fin.succ_succAbove_zero, sum_singleton, Fin.succ_succAbove_one, even_add_self]
ring
end Matrix
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 8d2b791e900da..92453f4171360 100644
--- a/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Card.lean
+++ b/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Card.lean
@@ -27,7 +27,7 @@ variable {K V : Type*} [DivisionRing K] [AddCommGroup V] [Module K V]
variable [Fintype K] [Finite V]
local notation "q" => Fintype.card K
-local notation "n" => FiniteDimensional.finrank K V
+local notation "n" => Module.finrank K V
attribute [local instance] Fintype.ofFinite in
open Fintype in
@@ -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. -/
@@ -86,8 +86,8 @@ theorem card_GL_field :
rcases Nat.eq_zero_or_pos n with rfl | hn
· simp [Nat.card_eq_fintype_card]
· rw [Nat.card_congr (equiv_GL_linearindependent n hn), card_linearIndependent,
- FiniteDimensional.finrank_fintype_fun_eq_card, Fintype.card_fin]
- simp only [FiniteDimensional.finrank_fintype_fun_eq_card, Fintype.card_fin, le_refl]
+ Module.finrank_fintype_fun_eq_card, Fintype.card_fin]
+ simp only [Module.finrank_fintype_fun_eq_card, Fintype.card_fin, le_refl]
end field
diff --git a/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Defs.lean b/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Defs.lean
index 50c1c2dfc8bb0..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) :=
@@ -137,6 +137,10 @@ def map (f : R →+* S) : GL n R →* GL n S := Units.map <| (RingHom.mapMatrix
theorem map_id : map (RingHom.id R) = MonoidHom.id (GL n R) :=
rfl
+@[simp]
+protected lemma map_apply (f : R →+* S) (i j : n) (g : GL n R) : map f g i j = f (g i j) := by
+ rfl
+
@[simp]
theorem map_comp (f : T →+* R) (g : R →+* S) :
map (g.comp f) = (map g).comp (map (n := n) f) :=
@@ -147,6 +151,44 @@ theorem map_comp_apply (f : T →+* R) (g : R →+* S) (x : GL n T) :
(map g).comp (map f) x = map g (map f x) :=
rfl
+variable (f : R →+* S)
+
+@[simp]
+protected lemma map_one : map f (1 : GL n R) = 1 := by
+ ext
+ simp only [_root_.map_one, Units.val_one]
+
+protected lemma map_mul (g h : GL n R) : map f (g * h) = map f g * map f h := by
+ ext
+ simp only [_root_.map_mul, Units.val_mul]
+
+protected lemma map_inv (g : GL n R) : map f g⁻¹ = (map f g)⁻¹ := by
+ ext
+ simp only [_root_.map_inv, coe_units_inv]
+
+protected lemma map_det (g : GL n R) : Matrix.GeneralLinearGroup.det (map f g) =
+ Units.map f (Matrix.GeneralLinearGroup.det g) := by
+ ext
+ simp only [map, RingHom.mapMatrix_apply, Units.inv_eq_val_inv, Matrix.coe_units_inv,
+ Matrix.GeneralLinearGroup.val_det_apply, Units.coe_map, MonoidHom.coe_coe]
+ exact Eq.symm (RingHom.map_det f g.1)
+
+lemma map_mul_map_inv (g : GL n R) : map f g * map f g⁻¹ = 1 := by
+ simp only [map_inv, mul_inv_cancel]
+
+lemma map_inv_mul_map (g : GL n R) : map f g⁻¹ * map f g = 1 := by
+ simp only [map_inv, inv_mul_cancel]
+
+@[simp]
+lemma coe_map_mul_map_inv (g : GL n R) : g.val.map f * g.val⁻¹.map f = 1 := by
+ rw [← Matrix.map_mul]
+ simp only [isUnits_det_units, mul_nonsing_inv, map_zero, _root_.map_one, Matrix.map_one]
+
+@[simp]
+lemma coe_map_inv_mul_map (g : GL n R) : g.val⁻¹.map f * g.val.map f = 1 := by
+ rw [← Matrix.map_mul]
+ simp only [isUnits_det_units, nonsing_inv_mul, map_zero, _root_.map_one, Matrix.map_one]
+
end GeneralLinearGroup
namespace SpecialLinearGroup
diff --git a/Mathlib/LinearAlgebra/Matrix/Gershgorin.lean b/Mathlib/LinearAlgebra/Matrix/Gershgorin.lean
index 39a98afe5cabe..06f6a65c35c43 100644
--- a/Mathlib/LinearAlgebra/Matrix/Gershgorin.lean
+++ b/Mathlib/LinearAlgebra/Matrix/Gershgorin.lean
@@ -37,7 +37,7 @@ theorem eigenvalue_mem_ball {μ : K} (hμ : Module.End.HasEigenvalue (Matrix.toL
refine (h_i ▸ Finset.le_sup' (fun i => ‖v i‖) (Finset.mem_univ j)).trans ?_
exact norm_le_zero_iff.mpr h_nz
have h_le : ∀ j, ‖v j * (v i)⁻¹‖ ≤ 1 := fun j => by
- rw [norm_mul, norm_inv, mul_inv_le_iff' (norm_pos_iff.mpr h_nz), one_mul]
+ rw [norm_mul, norm_inv, mul_inv_le_iff₀ (norm_pos_iff.mpr h_nz), one_mul]
exact h_i ▸ Finset.le_sup' (fun i => ‖v i‖) (Finset.mem_univ j)
simp_rw [mem_closedBall_iff_norm']
refine ⟨i, ?_⟩
@@ -62,7 +62,7 @@ theorem det_ne_zero_of_sum_row_lt_diag (h : ∀ k, ∑ j ∈ Finset.univ.erase k
suffices ∃ k, 0 ∈ Metric.closedBall (A k k) (∑ j ∈ Finset.univ.erase k, ‖A k j‖) by
exact this.imp (fun a h ↦ by rwa [mem_closedBall_iff_norm', sub_zero] at h)
refine eigenvalue_mem_ball ?_
- rw [Module.End.HasEigenvalue, Module.End.eigenspace_zero, ne_comm]
+ rw [Module.End.hasEigenvalue_iff, Module.End.eigenspace_zero, ne_comm]
exact ne_of_lt (LinearMap.bot_lt_ker_of_det_eq_zero (by rwa [LinearMap.det_toLin']))
/-- If `A` is a column strictly dominant diagonal matrix, then it's determinant is nonzero. -/
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 336209008ab7e..70a529e030dc1 100644
--- a/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean
+++ b/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean
@@ -7,7 +7,9 @@ Authors: Jon Bannon, Jireh Loreaux
import Mathlib.LinearAlgebra.Matrix.Spectrum
import Mathlib.LinearAlgebra.Eigenspace.Matrix
import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unique
-import Mathlib.Topology.ContinuousFunction.Units
+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/InvariantBasisNumber.lean b/Mathlib/LinearAlgebra/Matrix/InvariantBasisNumber.lean
index 5509163c9fd47..a424543278ed7 100644
--- a/Mathlib/LinearAlgebra/Matrix/InvariantBasisNumber.lean
+++ b/Mathlib/LinearAlgebra/Matrix/InvariantBasisNumber.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.LinearAlgebra.Matrix.ToLin
import Mathlib.LinearAlgebra.InvariantBasisNumber
diff --git a/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean b/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean
index e91010d1bc343..41e80c3f6b369 100644
--- a/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean
+++ b/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean
@@ -175,6 +175,20 @@ theorem det_ne_zero_of_right_inverse [Nontrivial α] (h : A * B = 1) : A.det ≠
end Invertible
+
+section
+
+variable [Fintype m] [Fintype n] [DecidableEq m] [DecidableEq n] [CommRing α]
+
+/-- A version of `mul_eq_one_comm` that works for square matrices with rectangular types. -/
+theorem mul_eq_one_comm_of_equiv {A : Matrix m n α} {B : Matrix n m α} (e : m ≃ n) :
+ A * B = 1 ↔ B * A = 1 := by
+ refine (reindex e e).injective.eq_iff.symm.trans ?_
+ rw [reindex_apply, reindex_apply, submatrix_one_equiv, ← submatrix_mul_equiv _ _ _ (.refl _),
+ mul_eq_one_comm, submatrix_mul_equiv, coe_refl, submatrix_id_id]
+
+end
+
section Inv
variable [Fintype n] [DecidableEq n] [CommRing α]
@@ -456,6 +470,10 @@ theorem nonsing_inv_nonsing_inv (h : IsUnit A.det) : A⁻¹⁻¹ = A :=
theorem isUnit_nonsing_inv_det_iff {A : Matrix n n α} : IsUnit A⁻¹.det ↔ IsUnit A.det := by
rw [Matrix.det_nonsing_inv, isUnit_ring_inverse]
+@[simp]
+theorem isUnit_nonsing_inv_iff {A : Matrix n n α} : IsUnit A⁻¹ ↔ IsUnit A := by
+ simp_rw [isUnit_iff_isUnit_det, isUnit_nonsing_inv_det_iff]
+
-- `IsUnit.invertible` lifts the proposition `IsUnit A` to a constructive inverse of `A`.
/-- A version of `Matrix.invertibleOfDetInvertible` with the inverse defeq to `A⁻¹` that is
therefore noncomputable. -/
@@ -593,6 +611,42 @@ theorem inv_diagonal (v : n → α) : (diagonal v)⁻¹ = diagonal (Ring.inverse
end Diagonal
+/-- The inverse of a 1×1 or 0×0 matrix is always diagonal.
+
+While we could write this as `of fun _ _ => Ring.inverse (A default default)` on the RHS, this is
+less useful because:
+
+* It wouldn't work for 0×0 matrices.
+* More things are true about diagonal matrices than constant matrices, and so more lemmas exist.
+
+`Matrix.diagonal_unique` can be used to reach this form, while `Ring.inverse_eq_inv` can be used
+to replace `Ring.inverse` with `⁻¹`.
+-/
+@[simp]
+theorem inv_subsingleton [Subsingleton m] [Fintype m] [DecidableEq m] (A : Matrix m m α) :
+ A⁻¹ = diagonal fun i => Ring.inverse (A i i) := by
+ rw [inv_def, adjugate_subsingleton, smul_one_eq_diagonal]
+ congr! with i
+ exact det_eq_elem_of_subsingleton _ _
+
+section Woodbury
+
+variable [Fintype m] [DecidableEq m]
+variable (A : Matrix n n α) (U : Matrix n m α) (C : Matrix m m α) (V : Matrix m n α)
+
+/-- The **Woodbury Identity** (`⁻¹` version). -/
+theorem add_mul_mul_inv_eq_sub (hA : IsUnit A) (hC : IsUnit C) (hAC : IsUnit (C⁻¹ + V * A⁻¹ * U)) :
+ (A + U * C * V)⁻¹ = A⁻¹ - A⁻¹ * U * (C⁻¹ + V * A⁻¹ * U)⁻¹ * V * A⁻¹ := by
+ obtain ⟨_⟩ := hA.nonempty_invertible
+ obtain ⟨_⟩ := hC.nonempty_invertible
+ obtain ⟨iAC⟩ := hAC.nonempty_invertible
+ simp only [← invOf_eq_nonsing_inv] at iAC
+ letI := invertibleAddMulMul A U C V
+ simp only [← invOf_eq_nonsing_inv]
+ apply invOf_add_mul_mul
+
+end Woodbury
+
@[simp]
theorem inv_inv_inv (A : Matrix n n α) : A⁻¹⁻¹⁻¹ = A⁻¹ := by
by_cases h : IsUnit A.det
@@ -722,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/Polynomial.lean b/Mathlib/LinearAlgebra/Matrix/Polynomial.lean
index 72e1f37352e62..64469ff133624 100644
--- a/Mathlib/LinearAlgebra/Matrix/Polynomial.lean
+++ b/Mathlib/LinearAlgebra/Matrix/Polynomial.lean
@@ -38,7 +38,7 @@ theorem natDegree_det_X_add_C_le (A B : Matrix n n α) :
rw [det_apply]
refine (natDegree_sum_le _ _).trans ?_
refine Multiset.max_le_of_forall_le _ _ ?_
- simp only [forall_apply_eq_imp_iff, true_and_iff, Function.comp_apply, Multiset.map_map,
+ simp only [forall_apply_eq_imp_iff, true_and, Function.comp_apply, Multiset.map_map,
Multiset.mem_map, exists_imp, Finset.mem_univ_val]
intro g
calc
diff --git a/Mathlib/LinearAlgebra/Matrix/PosDef.lean b/Mathlib/LinearAlgebra/Matrix/PosDef.lean
index 941af97a89e99..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
@@ -450,6 +450,25 @@ theorem det_pos [DecidableEq n] {M : Matrix n n 𝕜} (hM : M.PosDef) : 0 < det
intro i _
simpa using hM.eigenvalues_pos i
+theorem isUnit [DecidableEq n] {M : Matrix n n 𝕜} (hM : M.PosDef) : IsUnit M :=
+ isUnit_iff_isUnit_det _ |>.2 <| hM.det_pos.ne'.isUnit
+
+protected theorem inv [DecidableEq n] {M : Matrix n n 𝕜} (hM : M.PosDef) : M⁻¹.PosDef := by
+ refine ⟨hM.isHermitian.inv, fun x hx => ?_⟩
+ have := hM.2 (M⁻¹ *ᵥ x) ((Matrix.mulVec_injective_iff_isUnit.mpr ?_ |>.ne_iff' ?_).2 hx)
+ · let _inst := hM.isUnit.invertible
+ rwa [star_mulVec, mulVec_mulVec, Matrix.mul_inv_of_invertible, one_mulVec,
+ ← star_pos_iff, ← star_mulVec, ← star_dotProduct] at this
+ · simpa using hM.isUnit
+ · simp
+
+@[simp]
+theorem _root_.Matrix.posDef_inv_iff [DecidableEq n] {M : Matrix n n 𝕜} :
+ M⁻¹.PosDef ↔ M.PosDef :=
+ ⟨fun h =>
+ letI := (Matrix.isUnit_nonsing_inv_iff.1 <| h.isUnit).invertible
+ Matrix.inv_inv_of_invertible M ▸ h.inv, (·.inv)⟩
+
end PosDef
end Matrix
diff --git a/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean b/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean
index 13e2bba24b39b..8e620f838f3f0 100644
--- a/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean
+++ b/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean
@@ -559,8 +559,7 @@ theorem Matrix.isAdjointPair_equiv (P : Matrix n n R) (h : IsUnit P) :
let v := Pᵀ.nonsingInvUnit (P.isUnit_det_transpose h')
let x := A₁ᵀ * Pᵀ * J
let y := J * P * A₂
- -- TODO(mathlib4#6607): fix elaboration so `val` isn't needed
- suffices x * u.val = v.val * y ↔ (v⁻¹).val * x = y * (u⁻¹).val by
+ suffices x * u = v * y ↔ v⁻¹ * x = y * u⁻¹ by
dsimp only [Matrix.IsAdjointPair]
simp only [Matrix.transpose_mul]
simp only [← mul_assoc, P.transpose_nonsing_inv]
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 1e018cf22f592..86b9568b2b0d9 100644
--- a/Mathlib/LinearAlgebra/Matrix/Trace.lean
+++ b/Mathlib/LinearAlgebra/Matrix/Trace.lean
@@ -103,13 +103,14 @@ 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) :
trace (blockDiagonal M) = ∑ i, trace (M i) := by
- simp [blockDiagonal, trace, Finset.sum_comm (γ := n)]
+ simp [blockDiagonal, trace, Finset.sum_comm (γ := n), Fintype.sum_prod_type]
lemma trace_blockDiagonal' [DecidableEq p] {m : p → Type*} [∀ i, Fintype (m i)]
(M : ∀ i, Matrix (m i) (m i) 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/Matrix/Transvection.lean b/Mathlib/LinearAlgebra/Matrix/Transvection.lean
index c360c3c4d9f0f..9a13c74d20d49 100644
--- a/Mathlib/LinearAlgebra/Matrix/Transvection.lean
+++ b/Mathlib/LinearAlgebra/Matrix/Transvection.lean
@@ -101,7 +101,7 @@ theorem updateRow_eq_transvection [Finite n] (c : R) :
StdBasisMatrix.apply_of_ne]
· simp only [updateRow_ne, transvection, ha, Ne.symm ha, StdBasisMatrix.apply_of_ne, add_zero,
Algebra.id.smul_eq_mul, Ne, not_false_iff, DMatrix.add_apply, Pi.smul_apply,
- mul_zero, false_and_iff, add_apply]
+ mul_zero, false_and, add_apply]
variable [Fintype n]
@@ -424,7 +424,7 @@ theorem listTransvecCol_mul_last_col (hM : M (inr unit) (inr unit) ≠ 0) (i : F
rcases le_or_lt (n + 1) i with (hi | hi)
· simp only [hi, n.le_succ.trans hi, if_true]
· rw [if_neg, if_neg]
- · simpa only [hni.symm, not_le, or_false_iff] using Nat.lt_succ_iff_lt_or_eq.1 hi
+ · simpa only [hni.symm, not_le, or_false] using Nat.lt_succ_iff_lt_or_eq.1 hi
· simpa only [not_le] using hi
| self =>
simp only [length_listTransvecCol, le_refl, List.drop_eq_nil_of_le, List.prod_nil,
@@ -500,7 +500,7 @@ theorem mul_listTransvecRow_last_row (hM : M (inr unit) (inr unit) ≠ 0) (i : F
· simp [hi, n.le_succ.trans hi, if_true]
· rw [if_neg, if_neg]
· simpa only [not_le] using hi
- · simpa only [hni.symm, not_le, or_false_iff] using Nat.lt_succ_iff_lt_or_eq.1 hi
+ · simpa only [hni.symm, not_le, or_false] using Nat.lt_succ_iff_lt_or_eq.1 hi
/-- Multiplying by all the matrices either in `listTransvecCol M` and `listTransvecRow M` kills
all the coefficients in the last row but the last one. -/
diff --git a/Mathlib/LinearAlgebra/Multilinear/Basic.lean b/Mathlib/LinearAlgebra/Multilinear/Basic.lean
index 417f0dde15dc6..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,10 +104,9 @@ 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' := fun f g h ↦ by cases f; cases g; cases h; rfl
+ coe_injective' f g h := by cases f; cases g; cases h; rfl
initialize_simps_projections MultilinearMap (toFun → apply)
@@ -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,28 +444,23 @@ 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
-- If one of the sets is empty, then all the sums are zero
by_cases Ai_empty : ∃ i, A i = ∅
- · rcases Ai_empty with ⟨i, hi⟩
- have : ∑ j ∈ A i, g i j = 0 := by rw [hi, Finset.sum_empty]
- rw [f.map_coord_zero i this]
- have : piFinset A = ∅ := by
- refine Finset.eq_empty_of_forall_not_mem fun r hr => ?_
- have : r i ∈ A i := mem_piFinset.mp hr i
- simp [hi] at this
- rw [this, Finset.sum_empty]
+ · obtain ⟨i, hi⟩ : ∃ i, ∑ j ∈ A i, g i j = 0 := Ai_empty.imp fun i hi ↦ by simp [hi]
+ have hpi : piFinset A = ∅ := by simpa
+ rw [f.map_coord_zero i hi, hpi, Finset.sum_empty]
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
@@ -487,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₂})
@@ -522,7 +514,7 @@ theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ i,
simpa [C] using hj
rw [this]
simp only [B, mem_sdiff, eq_self_iff_true, not_true, not_false_iff, Finset.mem_singleton,
- update_same, and_false_iff]
+ update_same, and_false]
· simp [hi]
have Beq :
Function.update (fun i => ∑ j ∈ A i, g i j) i₀ (∑ j ∈ B i₀, g i₀ j) = fun i =>
@@ -542,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₀))
@@ -553,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
@@ -793,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₂)
@@ -841,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 })]
@@ -910,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 {ι₁ ι₂} (σ : ι₁ ≃ ι₂) :
@@ -1009,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₂
@@ -1213,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
@@ -1287,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,
@@ -1302,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]
@@ -1432,25 +1460,21 @@ theorem MultilinearMap.uncurry_curryLeft (f : MultilinearMap R M M₂) :
variable (R M M₂)
-/-- The space of multilinear maps on `∀ (i : Fin (n+1)), M i` is canonically isomorphic to
+/-- The space of multilinear maps on `Π (i : Fin (n+1)), M i` is canonically isomorphic to
the space of linear maps from `M 0` to the space of multilinear maps on
-`∀ (i : Fin n), M i.succ`, by separating the first variable. We register this isomorphism as a
+`Π (i : Fin n), M i.succ`, by separating the first variable. We register this isomorphism as a
linear isomorphism in `multilinearCurryLeftEquiv R M M₂`.
-The direct and inverse maps are given by `f.uncurryLeft` and `f.curryLeft`. Use these
+The direct and inverse maps are given by `f.curryLeft` and `f.uncurryLeft`. Use these
unless you need the full framework of linear equivs. -/
def multilinearCurryLeftEquiv :
- (M 0 →ₗ[R] MultilinearMap R (fun i : Fin n => M i.succ) M₂) ≃ₗ[R] MultilinearMap R M M₂ where
- toFun := LinearMap.uncurryLeft
- map_add' f₁ f₂ := by
- ext m
- rfl
- map_smul' c f := by
- ext m
- rfl
- invFun := MultilinearMap.curryLeft
- left_inv := LinearMap.curry_uncurryLeft
- right_inv := MultilinearMap.uncurry_curryLeft
+ MultilinearMap R M M₂ ≃ₗ[R] (M 0 →ₗ[R] MultilinearMap R (fun i : Fin n => M i.succ) M₂) where
+ toFun := MultilinearMap.curryLeft
+ map_add' _ _ := rfl
+ map_smul' _ _ := rfl
+ invFun := LinearMap.uncurryLeft
+ left_inv := MultilinearMap.uncurry_curryLeft
+ right_inv := LinearMap.curry_uncurryLeft
variable {R M M₂}
@@ -1542,27 +1566,22 @@ theorem MultilinearMap.uncurry_curryRight (f : MultilinearMap R M M₂) :
variable (R M M₂)
-/-- The space of multilinear maps on `∀ (i : Fin (n+1)), M i` is canonically isomorphic to
-the space of linear maps from the space of multilinear maps on `∀ (i : Fin n), M (castSucc i)` to
+/-- The space of multilinear maps on `Π (i : Fin (n+1)), M i` is canonically isomorphic to
+the space of linear maps from the space of multilinear maps on `Π (i : Fin n), M (castSucc i)` to
the space of linear maps on `M (last n)`, by separating the last variable. We register this
isomorphism as a linear isomorphism in `multilinearCurryRightEquiv R M M₂`.
-The direct and inverse maps are given by `f.uncurryRight` and `f.curryRight`. Use these
+The direct and inverse maps are given by `f.curryRight` and `f.uncurryRight`. Use these
unless you need the full framework of linear equivs. -/
def multilinearCurryRightEquiv :
- MultilinearMap R (fun i : Fin n => M (castSucc i)) (M (last n) →ₗ[R] M₂) ≃ₗ[R]
- MultilinearMap R M M₂ where
- toFun := MultilinearMap.uncurryRight
- map_add' f₁ f₂ := by
- ext m
- rfl
- map_smul' c f := by
- ext m
- rw [smul_apply]
- rfl
- invFun := MultilinearMap.curryRight
- left_inv := MultilinearMap.curry_uncurryRight
- right_inv := MultilinearMap.uncurry_curryRight
+ MultilinearMap R M M₂ ≃ₗ[R]
+ MultilinearMap R (fun i : Fin n => M (castSucc i)) (M (last n) →ₗ[R] M₂) where
+ toFun := MultilinearMap.curryRight
+ map_add' _ _ := rfl
+ map_smul' _ _ := rfl
+ invFun := MultilinearMap.uncurryRight
+ left_inv := MultilinearMap.uncurry_curryRight
+ right_inv := MultilinearMap.curry_uncurryRight
namespace MultilinearMap
@@ -1656,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
@@ -1665,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 =
@@ -1682,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) =
@@ -1698,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)
@@ -1709,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 ?_
@@ -1725,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/FiniteDimensional.lean b/Mathlib/LinearAlgebra/Multilinear/FiniteDimensional.lean
index 918241ffc7e57..5127794e5fa7f 100644
--- a/Mathlib/LinearAlgebra/Multilinear/FiniteDimensional.lean
+++ b/Mathlib/LinearAlgebra/Multilinear/FiniteDimensional.lean
@@ -40,8 +40,8 @@ private theorem free_and_finite_fin (n : ℕ) (N : Fin n → Type*) [∀ i, AddC
Module.Finite R (N 0 →ₗ[R] MultilinearMap R (fun i : Fin n => N i.succ) M₂) by
cases this
exact
- ⟨Module.Free.of_equiv (multilinearCurryLeftEquiv R N M₂),
- Module.Finite.equiv (multilinearCurryLeftEquiv R N M₂)⟩
+ ⟨Module.Free.of_equiv (multilinearCurryLeftEquiv R N M₂).symm,
+ Module.Finite.equiv (multilinearCurryLeftEquiv R N M₂).symm⟩
cases ih fun i => N i.succ
exact ⟨Module.Free.linearMap _ _ _ _, Module.Finite.linearMap _ _ _ _⟩
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/Orientation.lean b/Mathlib/LinearAlgebra/Orientation.lean
index 68891b346f5df..549ff52629c7b 100644
--- a/Mathlib/LinearAlgebra/Orientation.lean
+++ b/Mathlib/LinearAlgebra/Orientation.lean
@@ -326,7 +326,7 @@ namespace Orientation
variable [Fintype ι]
-open FiniteDimensional
+open FiniteDimensional Module
/-- If the index type has cardinality equal to the finite dimension, any two orientations are
equal or negations. -/
diff --git a/Mathlib/LinearAlgebra/PerfectPairing.lean b/Mathlib/LinearAlgebra/PerfectPairing.lean
index 8540645d0cf26..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
@@ -140,6 +140,11 @@ def IsReflexive.toPerfectPairingDual : PerfectPairing R (Dual R M) M where
bijectiveLeft := bijective_id
bijectiveRight := bijective_dual_eval R M
+@[simp]
+lemma IsReflexive.toPerfectPairingDual_apply {f : Dual R M} {x : M} :
+ IsReflexive.toPerfectPairingDual (R := R) f x = f x :=
+ rfl
+
variable (e : N ≃ₗ[R] Dual R M)
namespace LinearEquiv
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 4db6ffb5b5ed8..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
@@ -449,7 +449,7 @@ theorem ker_coprod_of_disjoint_range {M₂ : Type*} [AddCommGroup M₂] [Module
rintro ⟨y, z⟩ h
simp only [mem_ker, mem_prod, coprod_apply] at h ⊢
have : f y ∈ (range f) ⊓ (range g) := by
- simp only [true_and_iff, mem_range, mem_inf, exists_apply_eq_apply]
+ simp only [true_and, mem_range, mem_inf, exists_apply_eq_apply]
use -z
rwa [eq_comm, map_neg, ← sub_eq_zero, sub_neg_eq_add]
rw [hd.eq_bot, mem_bot] at this
@@ -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 e730906ab556c..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 _
@@ -393,10 +393,10 @@ theorem eq_conj_prod_map' {f : E →ₗ[R] E} (h : IsProj p f) :
prodMap id 0 ∘ₗ (p.prodEquivOfIsCompl (ker f) h.isCompl).symm.toLinearMap := by
rw [← LinearMap.comp_assoc, LinearEquiv.eq_comp_toLinearMap_symm]
ext x
- · simp only [coe_prodEquivOfIsCompl, comp_apply, coe_inl, coprod_apply, coeSubtype,
+ · simp only [coe_prodEquivOfIsCompl, comp_apply, coe_inl, coprod_apply, coe_subtype,
_root_.map_zero, add_zero, h.map_id x x.2, prodMap_apply, id_apply]
· simp only [coe_prodEquivOfIsCompl, comp_apply, coe_inr, coprod_apply, _root_.map_zero,
- coeSubtype, zero_add, map_coe_ker, prodMap_apply, zero_apply, add_zero]
+ coe_subtype, zero_add, map_coe_ker, prodMap_apply, zero_apply, add_zero]
end IsProj
diff --git a/Mathlib/LinearAlgebra/Projectivization/Basic.lean b/Mathlib/LinearAlgebra/Projectivization/Basic.lean
index fd5d3d6aa6db7..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'
@@ -78,7 +92,7 @@ theorem rep_nonzero (v : ℙ K V) : v.rep ≠ 0 :=
@[simp]
theorem mk_rep (v : ℙ K V) : mk K v.rep v.rep_nonzero = v := Quotient.out_eq' _
-open FiniteDimensional
+open Module
/-- Consider an element of the projectivization as a submodule of `V`. -/
protected def submodule (v : ℙ K V) : Submodule K V :=
diff --git a/Mathlib/LinearAlgebra/Projectivization/Constructions.lean b/Mathlib/LinearAlgebra/Projectivization/Constructions.lean
new file mode 100644
index 0000000000000..fd7470292b540
--- /dev/null
+++ b/Mathlib/LinearAlgebra/Projectivization/Constructions.lean
@@ -0,0 +1,135 @@
+/-
+Copyright (c) 2024 Thomas Browning. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Thomas Browning
+-/
+import Mathlib.LinearAlgebra.CrossProduct
+import Mathlib.LinearAlgebra.Matrix.DotProduct
+import Mathlib.LinearAlgebra.Projectivization.Basic
+
+/-!
+
+# Dot Product and Cross Product on Projective Spaces
+
+This file defines the dot product and cross product on projective spaces.
+
+## Definitions
+- `Projectivization.orthogonal v w` is defined as vanishing of the dot product.
+- `Projectivization.cross v w` for `v w : ℙ F (Fin 3 → F)` is defined as the cross product of
+ `v` and `w` provided that `v ≠ w`. If `v = w`, then the cross product would be zero, so we
+ instead define `cross v v = v`.
+
+-/
+
+variable {F : Type*} [Field F] {m : Type*} [Fintype m]
+
+namespace Projectivization
+
+open scoped LinearAlgebra.Projectivization
+
+section DotProduct
+
+/-- Orthogonality on the projective plane. -/
+def orthogonal : ℙ F (m → F) → ℙ F (m → F) → Prop :=
+ Quotient.lift₂ (fun v w ↦ Matrix.dotProduct v.1 w.1 = 0) (fun _ _ _ _ ⟨_, h1⟩ ⟨_, h2⟩ ↦ by
+ simp_rw [← h1, ← h2, Matrix.dotProduct_smul, Matrix.smul_dotProduct, smul_smul,
+ smul_eq_zero_iff_eq])
+
+lemma orthogonal_mk {v w : m → F} (hv : v ≠ 0) (hw : w ≠ 0) :
+ orthogonal (mk F v hv) (mk F w hw) ↔ Matrix.dotProduct v w = 0 :=
+ Iff.rfl
+
+lemma orthogonal_comm {v w : ℙ F (m → F)} : orthogonal v w ↔ orthogonal w v := by
+ induction' v with v hv
+ induction' w with w hw
+ rw [orthogonal_mk hv hw, orthogonal_mk hw hv, Matrix.dotProduct_comm]
+
+lemma exists_not_self_orthogonal (v : ℙ F (m → F)) : ∃ w, ¬ orthogonal v w := by
+ induction' v with v hv
+ rw [ne_eq, ← Matrix.dotProduct_eq_zero_iff, not_forall] at hv
+ obtain ⟨w, hw⟩ := hv
+ exact ⟨mk F w fun h ↦ hw (by rw [h, Matrix.dotProduct_zero]), hw⟩
+
+lemma exists_not_orthogonal_self (v : ℙ F (m → F)) : ∃ w, ¬ orthogonal w v := by
+ simp only [orthogonal_comm]
+ exact exists_not_self_orthogonal v
+
+end DotProduct
+
+section CrossProduct
+
+lemma mk_eq_mk_iff_crossProduct_eq_zero {v w : Fin 3 → F} (hv : v ≠ 0) (hw : w ≠ 0) :
+ mk F v hv = mk F w hw ↔ crossProduct v w = 0 := by
+ rw [← not_iff_not, mk_eq_mk_iff', not_exists, ← LinearIndependent.pair_iff' hw,
+ ← crossProduct_ne_zero_iff_linearIndependent, ← cross_anticomm, neg_ne_zero]
+
+variable [DecidableEq F]
+
+/-- Cross product on the projective plane. -/
+def cross : ℙ F (Fin 3 → F) → ℙ F (Fin 3 → F) → ℙ F (Fin 3 → F) :=
+ Quotient.map₂' (fun v w ↦ if h : crossProduct v.1 w.1 = 0 then v else ⟨crossProduct v.1 w.1, h⟩)
+ (fun _ _ ⟨a, ha⟩ _ _ ⟨b, hb⟩ ↦ by
+ simp_rw [← ha, ← hb, LinearMap.map_smul_of_tower, LinearMap.smul_apply, smul_smul,
+ mul_comm b a, smul_eq_zero_iff_eq]
+ split_ifs
+ · use a
+ · use a * b)
+
+lemma cross_mk {v w : Fin 3 → F} (hv : v ≠ 0) (hw : w ≠ 0) :
+ cross (mk F v hv) (mk F w hw) =
+ if h : crossProduct v w = 0 then mk F v hv else mk F (crossProduct v w) h := by
+ change Quotient.mk'' _ = _
+ split_ifs with h <;> simp only [h] <;> rfl
+
+lemma cross_mk_of_cross_eq_zero {v w : Fin 3 → F} (hv : v ≠ 0) (hw : w ≠ 0)
+ (h : crossProduct v w = 0) :
+ cross (mk F v hv) (mk F w hw) = mk F v hv := by
+ rw [cross_mk, dif_pos h]
+
+lemma cross_mk_of_cross_ne_zero {v w : Fin 3 → F} (hv : v ≠ 0) (hw : w ≠ 0)
+ (h : crossProduct v w ≠ 0) :
+ cross (mk F v hv) (mk F w hw) = mk F (crossProduct v w) h := by
+ rw [cross_mk, dif_neg h]
+
+lemma cross_self (v : ℙ F (Fin 3 → F)) : cross v v = v := by
+ induction' v with v hv
+ rw [cross_mk_of_cross_eq_zero]
+ rw [← mk_eq_mk_iff_crossProduct_eq_zero hv]
+
+lemma cross_mk_of_ne {v w : Fin 3 → F} (hv : v ≠ 0) (hw : w ≠ 0) (h : mk F v hv ≠ mk F w hw) :
+ cross (mk F v hv) (mk F w hw) = mk F (crossProduct v w)
+ (mt (mk_eq_mk_iff_crossProduct_eq_zero hv hw).mpr h) := by
+ rw [cross_mk_of_cross_ne_zero]
+
+lemma cross_comm (v w : ℙ F (Fin 3 → F)) : cross v w = cross w v := by
+ rcases eq_or_ne v w with rfl | h
+ · rfl
+ · induction' v with v hv
+ induction' w with w hw
+ rw [cross_mk_of_ne hv hw h, cross_mk_of_ne hw hv h.symm, mk_eq_mk_iff_crossProduct_eq_zero,
+ ← cross_anticomm v w, map_neg, _root_.cross_self, neg_zero]
+
+theorem cross_orthogonal_left {v w : ℙ F (Fin 3 → F)} (h : v ≠ w) :
+ (cross v w).orthogonal v := by
+ induction' v with v hv
+ induction' w with w hw
+ rw [cross_mk_of_ne hv hw h, orthogonal_mk, Matrix.dotProduct_comm, dot_self_cross]
+
+theorem cross_orthogonal_right {v w : ℙ F (Fin 3 → F)} (h : v ≠ w) :
+ (cross v w).orthogonal w := by
+ rw [cross_comm]
+ exact cross_orthogonal_left h.symm
+
+theorem orthogonal_cross_left {v w : ℙ F (Fin 3 → F)} (h : v ≠ w) :
+ v.orthogonal (cross v w) := by
+ rw [orthogonal_comm]
+ exact cross_orthogonal_left h
+
+lemma orthogonal_cross_right {v w : ℙ F (Fin 3 → F)} (h : v ≠ w) :
+ w.orthogonal (cross v w) := by
+ rw [orthogonal_comm]
+ exact cross_orthogonal_right h
+
+end CrossProduct
+
+end Projectivization
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 caedda89e57e7..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 :=
@@ -854,15 +870,15 @@ theorem associated_toQuadraticMap (B : BilinMap R M R) (x y : M) :
theorem associated_left_inverse (h : B₁.IsSymm) : associatedHom S B₁.toQuadraticMap = B₁ :=
LinearMap.ext₂ fun x y => by
- rw [associated_toQuadraticMap, ← h.eq x y, RingHom.id_apply, ← two_mul, ← smul_mul_assoc,
- smul_eq_mul, invOf_mul_self, one_mul]
+ rw [associated_toQuadraticMap, ← h.eq x y, RingHom.id_apply]
+ match_scalars
+ linear_combination invOf_mul_self' (2:R)
-- Porting note: moved from below to golf the next theorem
theorem associated_eq_self_apply (x : M) : associatedHom S Q x x = Q x := by
- rw [associated_apply, map_add_self, ← three_add_one_eq_four, ← two_add_one_eq_three, add_smul,
- add_smul, one_smul, add_sub_cancel_right, add_sub_cancel_right, two_smul, ← two_smul R,
- ← smul_assoc]
- simp only [smul_eq_mul, invOf_mul_self', one_smul]
+ rw [associated_apply, map_add_self]
+ match_scalars
+ linear_combination invOf_mul_self' (2:R)
theorem toQuadraticMap_associated : (associatedHom S Q).toQuadraticMap = Q :=
QuadraticMap.ext <| associated_eq_self_apply S Q
@@ -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,10 +1196,10 @@ 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 FiniteDimensional
+open Module
variable {V : Type u} {K : Type v} [Field K] [AddCommGroup V] [Module K V]
variable [FiniteDimensional K V]
@@ -1194,7 +1213,7 @@ theorem exists_orthogonal_basis [hK : Invertible (2 : K)] {B : LinearMap.BilinFo
haveI := finrank_pos_iff.1 (hd.symm ▸ Nat.succ_pos d : 0 < finrank K V)
-- either the bilinear form is trivial or we can pick a non-null `x`
obtain rfl | hB₁ := eq_or_ne B 0
- · let b := FiniteDimensional.finBasis K V
+ · let b := Module.finBasis K V
rw [hd] at b
exact ⟨b, fun i j _ => rfl⟩
obtain ⟨x, hx⟩ := exists_bilinForm_self_ne_zero hB₁ hB₂
@@ -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
@@ -1288,8 +1307,7 @@ theorem basisRepr_eq_of_iIsOrtho {R M} [CommRing R] [AddCommGroup M] [Module R M
smul_eq_mul, smul_eq_mul]
ring_nf
· intro i _ hij
- rw [LinearMap.map_smul, LinearMap.map_smul₂,
- show associatedHom R Q (v i) (v j) = 0 from hv₂ hij, smul_eq_mul, smul_eq_mul,
- mul_zero, mul_zero]
+ rw [LinearMap.map_smul, LinearMap.map_smul₂, hv₂ hij]
+ module
end QuadraticMap
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 3285feacba1f0..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
@@ -70,7 +70,7 @@ noncomputable def isometryEquivSumSquaresUnits (w : ι → Units ℂ) :
the sum of squares, i.e. `weightedSumSquares` with weight `fun (i : ι) => 1`. -/
theorem equivalent_sum_squares {M : Type*} [AddCommGroup M] [Module ℂ M] [FiniteDimensional ℂ M]
(Q : QuadraticForm ℂ M) (hQ : (associated (R := ℂ) Q).SeparatingLeft) :
- Equivalent Q (weightedSumSquares ℂ (1 : Fin (FiniteDimensional.finrank ℂ M) → ℂ)) :=
+ Equivalent Q (weightedSumSquares ℂ (1 : Fin (Module.finrank ℂ M) → ℂ)) :=
let ⟨w, ⟨hw₁⟩⟩ := Q.equivalent_weightedSumSquares_units_of_nondegenerate' hQ
⟨hw₁.trans (isometryEquivSumSquaresUnits w)⟩
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/IsometryEquiv.lean b/Mathlib/LinearAlgebra/QuadraticForm/IsometryEquiv.lean
index ff5c68946f2d8..567af287573fc 100644
--- a/Mathlib/LinearAlgebra/QuadraticForm/IsometryEquiv.lean
+++ b/Mathlib/LinearAlgebra/QuadraticForm/IsometryEquiv.lean
@@ -141,7 +141,7 @@ variable [Field K] [Invertible (2 : K)] [AddCommGroup V] [Module K V]
/-- Given an orthogonal basis, a quadratic form is isometrically equivalent with a weighted sum of
squares. -/
noncomputable def isometryEquivWeightedSumSquares (Q : QuadraticForm K V)
- (v : Basis (Fin (FiniteDimensional.finrank K V)) K V)
+ (v : Basis (Fin (Module.finrank K V)) K V)
(hv₁ : (associated (R := K) Q).IsOrthoᵢ v) :
Q.IsometryEquiv (weightedSumSquares K fun i => Q (v i)) := by
let iso := Q.isometryEquivBasisRepr v
@@ -154,13 +154,13 @@ variable [FiniteDimensional K V]
open LinearMap.BilinForm
theorem equivalent_weightedSumSquares (Q : QuadraticForm K V) :
- ∃ w : Fin (FiniteDimensional.finrank K V) → K, Equivalent Q (weightedSumSquares K w) :=
+ ∃ w : Fin (Module.finrank K V) → K, Equivalent Q (weightedSumSquares K w) :=
let ⟨v, hv₁⟩ := exists_orthogonal_basis (associated_isSymm _ Q)
⟨_, ⟨Q.isometryEquivWeightedSumSquares v hv₁⟩⟩
theorem equivalent_weightedSumSquares_units_of_nondegenerate' (Q : QuadraticForm K V)
(hQ : (associated (R := K) Q).SeparatingLeft) :
- ∃ w : Fin (FiniteDimensional.finrank K V) → Kˣ, Equivalent Q (weightedSumSquares K w) := by
+ ∃ w : Fin (Module.finrank K V) → Kˣ, Equivalent Q (weightedSumSquares K w) := by
obtain ⟨v, hv₁⟩ := exists_orthogonal_basis (associated_isSymm K Q)
have hv₂ := hv₁.not_isOrtho_basis_self_of_separatingLeft hQ
simp_rw [LinearMap.IsOrtho, associated_eq_self_apply] at hv₂
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 7ec3a6f4947d8..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
@@ -53,7 +52,7 @@ noncomputable def isometryEquivSignWeightedSumSquares (w : ι → ℝ) :
sum of squares with the weights being ±1, `SignType` version. -/
theorem equivalent_sign_ne_zero_weighted_sum_squared {M : Type*} [AddCommGroup M] [Module ℝ M]
[FiniteDimensional ℝ M] (Q : QuadraticForm ℝ M) (hQ : (associated (R := ℝ) Q).SeparatingLeft) :
- ∃ w : Fin (FiniteDimensional.finrank ℝ M) → SignType,
+ ∃ w : Fin (Module.finrank ℝ M) → SignType,
(∀ i, w i ≠ 0) ∧ Equivalent Q (weightedSumSquares ℝ fun i ↦ (w i : ℝ)) :=
let ⟨w, ⟨hw₁⟩⟩ := Q.equivalent_weightedSumSquares_units_of_nondegenerate' hQ
⟨sign ∘ ((↑) : ℝˣ → ℝ) ∘ w, fun i => sign_ne_zero.2 (w i).ne_zero,
@@ -63,7 +62,7 @@ theorem equivalent_sign_ne_zero_weighted_sum_squared {M : Type*} [AddCommGroup M
sum of squares with the weights being ±1. -/
theorem equivalent_one_neg_one_weighted_sum_squared {M : Type*} [AddCommGroup M] [Module ℝ M]
[FiniteDimensional ℝ M] (Q : QuadraticForm ℝ M) (hQ : (associated (R := ℝ) Q).SeparatingLeft) :
- ∃ w : Fin (FiniteDimensional.finrank ℝ M) → ℝ,
+ ∃ w : Fin (Module.finrank ℝ M) → ℝ,
(∀ i, w i = -1 ∨ w i = 1) ∧ Equivalent Q (weightedSumSquares ℝ w) :=
let ⟨w, hw₀, hw⟩ := Q.equivalent_sign_ne_zero_weighted_sum_squared hQ
⟨(w ·), fun i ↦ by cases hi : w i <;> simp_all, hw⟩
@@ -72,7 +71,7 @@ theorem equivalent_one_neg_one_weighted_sum_squared {M : Type*} [AddCommGroup M]
sum of squares with the weights being ±1 or 0, `SignType` version. -/
theorem equivalent_signType_weighted_sum_squared {M : Type*} [AddCommGroup M] [Module ℝ M]
[FiniteDimensional ℝ M] (Q : QuadraticForm ℝ M) :
- ∃ w : Fin (FiniteDimensional.finrank ℝ M) → SignType,
+ ∃ w : Fin (Module.finrank ℝ M) → SignType,
Equivalent Q (weightedSumSquares ℝ fun i ↦ (w i : ℝ)) :=
let ⟨w, ⟨hw₁⟩⟩ := Q.equivalent_weightedSumSquares
⟨sign ∘ w, ⟨hw₁.trans (isometryEquivSignWeightedSumSquares w)⟩⟩
@@ -81,7 +80,7 @@ theorem equivalent_signType_weighted_sum_squared {M : Type*} [AddCommGroup M] [M
sum of squares with the weights being ±1 or 0. -/
theorem equivalent_one_zero_neg_one_weighted_sum_squared {M : Type*} [AddCommGroup M] [Module ℝ M]
[FiniteDimensional ℝ M] (Q : QuadraticForm ℝ M) :
- ∃ w : Fin (FiniteDimensional.finrank ℝ M) → ℝ,
+ ∃ w : Fin (Module.finrank ℝ M) → ℝ,
(∀ i, w i = -1 ∨ w i = 0 ∨ w i = 1) ∧ Equivalent Q (weightedSumSquares ℝ w) :=
let ⟨w, hw⟩ := Q.equivalent_signType_weighted_sum_squared
⟨(w ·), fun i ↦ by cases h : w i <;> simp [h], hw⟩
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 62%
rename from Mathlib/LinearAlgebra/Quotient.lean
rename to Mathlib/LinearAlgebra/Quotient/Basic.lean
index 61d6fd9576a2a..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,35 +112,15 @@ 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 (A : Submodule R M) : Function.Surjective A.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
+ p.toAddSubgroup (a := m₁.toAddSubgroup) (b := m₂.toAddSubgroup)
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₂ :=
@@ -310,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₂ :=
@@ -352,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
@@ -454,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
@@ -531,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]
@@ -544,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 117d5b1c1a242..cf4501ff16800 100644
--- a/Mathlib/LinearAlgebra/Ray.lean
+++ b/Mathlib/LinearAlgebra/Ray.lean
@@ -6,6 +6,7 @@ Authors: Joseph Myers
import Mathlib.Algebra.Order.Module.Algebra
import Mathlib.LinearAlgebra.LinearIndependent
import Mathlib.Algebra.Ring.Subring.Units
+import Mathlib.Tactic.Positivity
/-!
# Rays in modules
@@ -106,7 +107,7 @@ lemma sameRay_nonneg_smul_right (v : M) (h : 0 ≤ a) : SameRay R v (a • v) :=
· rw [← algebraMap_smul R a v, h, zero_smul]
exact zero_right _
· refine Or.inr <| Or.inr ⟨algebraMap S R a, 1, h, by nontriviality R; exact zero_lt_one, ?_⟩
- rw [algebraMap_smul, one_smul]
+ module
/-- A nonnegative multiple of a vector is in the same ray as that vector. -/
lemma sameRay_nonneg_smul_left (v : M) (ha : 0 ≤ a) : SameRay R (a • v) v :=
@@ -170,9 +171,8 @@ theorem add_left (hx : SameRay R x z) (hy : SameRay R y z) : SameRay R (x + y) z
rcases hx.exists_pos hx₀ hz₀ with ⟨rx, rz₁, hrx, hrz₁, Hx⟩
rcases hy.exists_pos hy₀ hz₀ with ⟨ry, rz₂, hry, hrz₂, Hy⟩
refine Or.inr (Or.inr ⟨rx * ry, ry * rz₁ + rx * rz₂, mul_pos hrx hry, ?_, ?_⟩)
- · apply_rules [add_pos, mul_pos]
- · simp only [mul_smul, smul_add, add_smul, ← Hx, ← Hy]
- rw [smul_comm]
+ · positivity
+ · convert congr(ry • $Hx + rx • $Hy) using 1 <;> module
/-- If `y` and `z` are on the same ray as `x`, then so is `y + z`. -/
theorem add_right (hy : SameRay R x y) (hz : SameRay R x z) : SameRay R x (y + z) :=
@@ -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⟩⟧
@@ -466,7 +465,7 @@ theorem sameRay_smul_right_iff {v : M} {r : R} : SameRay R v (r • v) ↔ 0 ≤
is positive. -/
theorem sameRay_smul_right_iff_of_ne {v : M} (hv : v ≠ 0) {r : R} (hr : r ≠ 0) :
SameRay R v (r • v) ↔ 0 < r := by
- simp only [sameRay_smul_right_iff, hv, or_false_iff, hr.symm.le_iff_lt]
+ simp only [sameRay_smul_right_iff, hv, or_false, hr.symm.le_iff_lt]
@[simp]
theorem sameRay_smul_left_iff {v : M} {r : R} : SameRay R (r • v) v ↔ 0 ≤ r ∨ v = 0 :=
@@ -484,7 +483,7 @@ theorem sameRay_neg_smul_right_iff {v : M} {r : R} : SameRay R (-v) (r • v)
theorem sameRay_neg_smul_right_iff_of_ne {v : M} {r : R} (hv : v ≠ 0) (hr : r ≠ 0) :
SameRay R (-v) (r • v) ↔ r < 0 := by
- simp only [sameRay_neg_smul_right_iff, hv, or_false_iff, hr.le_iff_lt]
+ simp only [sameRay_neg_smul_right_iff, hv, or_false, hr.le_iff_lt]
@[simp]
theorem sameRay_neg_smul_left_iff {v : M} {r : R} : SameRay R (r • v) (-v) ↔ r ≤ 0 ∨ v = 0 :=
@@ -531,11 +530,11 @@ theorem sameRay_or_sameRay_neg_iff_not_linearIndependent {x y : M} :
rcases lt_trichotomy (m 1) 0 with (hm1 | hm1 | hm1)
· refine
Or.inr (Or.inr (Or.inr ⟨-m 0, -m 1, Left.neg_pos_iff.2 hm0, Left.neg_pos_iff.2 hm1, ?_⟩))
- rw [neg_smul_neg, neg_smul, hm, neg_neg]
+ linear_combination (norm := module) -hm
· exfalso
simp [hm1, hx, hm0.ne] at hm
· refine Or.inl (Or.inr (Or.inr ⟨-m 0, m 1, Left.neg_pos_iff.2 hm0, hm1, ?_⟩))
- rw [neg_smul, hm, neg_neg]
+ linear_combination (norm := module) -hm
· exfalso
simp [hm0, hy, hm1.ne] at hm
· rw [Fin.exists_fin_two] at hmne
diff --git a/Mathlib/LinearAlgebra/Reflection.lean b/Mathlib/LinearAlgebra/Reflection.lean
index 2d07ea2bd6890..d807bcfeec42e 100644
--- a/Mathlib/LinearAlgebra/Reflection.lean
+++ b/Mathlib/LinearAlgebra/Reflection.lean
@@ -70,7 +70,7 @@ lemma preReflection_apply_self (h : f x = 2) :
lemma involutive_preReflection (h : f x = 2) :
Involutive (preReflection x f) :=
- fun y ↦ by simp [h, smul_sub, two_smul, preReflection_apply]
+ fun y ↦ by simp [map_sub, h, smul_sub, two_smul, preReflection_apply]
lemma preReflection_preReflection (g : Dual R M) (h : f x = 2) :
preReflection (preReflection x f y) (preReflection f (Dual.eval R M x) g) =
diff --git a/Mathlib/LinearAlgebra/RootSystem/Basic.lean b/Mathlib/LinearAlgebra/RootSystem/Basic.lean
index 1dea08280f5c7..4aba11c944d5e 100644
--- a/Mathlib/LinearAlgebra/RootSystem/Basic.lean
+++ b/Mathlib/LinearAlgebra/RootSystem/Basic.lean
@@ -120,8 +120,8 @@ protected lemma ext [CharZero R] [NoZeroSMulDivisors R M]
ext i j
refine P₁.root.injective ?_
conv_rhs => rw [hr]
- rw [root_reflection_perm, root_reflection_perm]
- simp only [hr, he, hc', reflection_apply]
+ simp only [root_reflection_perm, reflection_apply, coroot']
+ simp only [hr, he, hc']
suffices P₁.coroot = P₂.coroot by
cases' P₁ with p₁; cases' P₂ with p₂; cases p₁; cases p₂; congr; exact hp this
have := NoZeroSMulDivisors.int_of_charZero R M
@@ -254,7 +254,7 @@ private lemma coroot_eq_coreflection_of_root_eq_of_span_eq_top [CharZero R] [NoZ
have hk₀ : root k ≠ 0 := fun h ↦ by simpa [h, ← PerfectPairing.toLin_apply] using hp k
apply p.bijectiveRight.injective
apply Dual.eq_of_preReflection_mapsTo hk₀ (finite_range root) hsp (hp k) (hs k)
- · simp [α, β, α', β', sα, sβ, sα', hk, preReflection_apply, hp i, hp j, mul_two,
+ · simp [map_sub, α, β, α', β', sα, sβ, sα', hk, preReflection_apply, hp i, hp j, mul_two,
mul_comm (p α β')]
ring -- v4.7.0-rc1 issues
· rw [hk, hij]
diff --git a/Mathlib/LinearAlgebra/RootSystem/Defs.lean b/Mathlib/LinearAlgebra/RootSystem/Defs.lean
index 92c4a2374be6d..420de4b340130 100644
--- a/Mathlib/LinearAlgebra/RootSystem/Defs.lean
+++ b/Mathlib/LinearAlgebra/RootSystem/Defs.lean
@@ -32,7 +32,6 @@ This file contains basic definitions for root systems and root data.
## TODO
* Base change of root pairings (may need flatness; perhaps should go in a different file).
- * Isomorphism of root pairings.
* Crystallographic root systems are isomorphic to base changes of root systems over `ℤ`: Take
`M₀` and `N₀` to be the `ℤ`-span of roots and coroots.
@@ -51,7 +50,6 @@ between roots and coroots is (implicitly) included and the coroots are included
Empirically this seems to be by far the most convenient design and by providing extensionality
lemmas expressing the uniqueness we expect to get the best of both worlds.
-
Furthermore, we require roots and coroots to be injections from a base indexing type `ι` rather than
subsets of their codomains. This design was chosen to avoid the bijection between roots and coroots
being a dependently-typed object. A third option would be to have the roots and coroots be subsets
@@ -88,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. -/
@@ -112,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
@@ -123,7 +121,7 @@ variable {ι R M N}
variable (P : RootPairing ι R M N) (i j : ι)
lemma ne_zero [CharZero R] : (P.root i : M) ≠ 0 :=
- fun h ↦ by simpa [h] using P.root_coroot_two i
+ fun h ↦ by simpa [h, map_zero] using P.root_coroot_two i
lemma ne_zero' [CharZero R] : (P.coroot i : N) ≠ 0 :=
fun h ↦ by simpa [h] using P.root_coroot_two i
@@ -146,13 +144,27 @@ protected def flip : RootPairing ι R N M :=
lemma flip_flip : P.flip.flip = P :=
rfl
+/-- Roots written as functionals on the coweight space. -/
+abbrev root' (i : ι) : Dual R N := P.toPerfectPairing (P.root i)
+
+/-- Coroots written as functionals on the weight space. -/
+abbrev coroot' (i : ι) : Dual R M := P.toPerfectPairing.flip (P.coroot i)
+
/-- This is the pairing between roots and coroots. -/
-def pairing : R := P.toPerfectPairing (P.root i) (P.coroot j)
+def pairing : R := P.root' i (P.coroot j)
@[simp]
lemma root_coroot_eq_pairing : P.toPerfectPairing (P.root i) (P.coroot j) = P.pairing i j :=
rfl
+@[simp]
+lemma root'_coroot_eq_pairing : P.root' i (P.coroot j) = P.pairing i j :=
+ rfl
+
+@[simp]
+lemma root_coroot'_eq_pairing : P.coroot' i (P.root j) = P.pairing j i :=
+ rfl
+
lemma coroot_root_eq_pairing : P.toLin.flip (P.coroot i) (P.root j) = P.pairing j i := by
simp
@@ -178,7 +190,7 @@ theorem mapsTo_reflection_root :
exact P.root_reflection_perm i j ▸ mem_range_self (P.reflection_perm i j)
lemma reflection_apply (x : M) :
- P.reflection i x = x - (P.toPerfectPairing x (P.coroot i)) • P.root i :=
+ P.reflection i x = x - (P.coroot' i x) • P.root i :=
rfl
lemma reflection_apply_root :
@@ -253,7 +265,7 @@ theorem mapsTo_coreflection_coroot :
exact P.coroot_reflection_perm i j ▸ mem_range_self (P.reflection_perm i j)
lemma coreflection_apply (f : N) :
- P.coreflection i f = f - (P.toPerfectPairing (P.root i) f) • P.coroot i :=
+ P.coreflection i f = f - (P.root' i) f • P.coroot i :=
rfl
lemma coreflection_apply_coroot :
@@ -295,7 +307,7 @@ lemma coreflection_eq_flip_reflection :
lemma reflection_dualMap_eq_coreflection :
(P.reflection i).dualMap ∘ₗ P.toLin.flip = P.toLin.flip ∘ₗ P.coreflection i := by
ext n m
- simp [coreflection_apply, reflection_apply, mul_comm (P.toPerfectPairing m (P.coroot i))]
+ simp [map_sub, coreflection_apply, reflection_apply, mul_comm (P.toPerfectPairing m (P.coroot i))]
lemma coroot_eq_coreflection_of_root_eq
{i j k : ι} (hk : P.root k = P.reflection i (P.root j)) :
@@ -303,10 +315,42 @@ lemma coroot_eq_coreflection_of_root_eq
rw [← P.root_reflection_perm, EmbeddingLike.apply_eq_iff_eq] at hk
rw [← P.coroot_reflection_perm, hk]
+lemma coroot'_reflection_perm {i j : ι} :
+ P.coroot' (P.reflection_perm i j) = P.coroot' j ∘ₗ P.reflection i := by
+ ext y
+ simp [coreflection_apply_coroot, reflection_apply, map_sub, mul_comm]
+
+lemma coroot'_reflection {i j : ι} (y : M) :
+ P.coroot' j (P.reflection i y) = P.coroot' (P.reflection_perm i j) y :=
+ (LinearMap.congr_fun P.coroot'_reflection_perm y).symm
+
+lemma pairing_reflection_perm (i j k : ι) :
+ P.pairing j (P.reflection_perm i k) = P.pairing (P.reflection_perm i j) k := by
+ simp only [pairing, root', coroot_reflection_perm, root_reflection_perm]
+ simp only [coreflection_apply_coroot, map_sub, map_smul, smul_eq_mul,
+ reflection_apply_root]
+ simp only [← toLin_toPerfectPairing, map_smul, LinearMap.smul_apply, map_sub, map_smul,
+ LinearMap.sub_apply, smul_eq_mul]
+ simp only [PerfectPairing.toLin_apply, root'_coroot_eq_pairing, sub_right_inj, mul_comm]
+
+@[simp]
+lemma pairing_reflection_perm_self_left (P : RootPairing ι R M N) (i j : ι) :
+ P.pairing (P.reflection_perm i i) j = - P.pairing i j := by
+ rw [pairing, root', ← reflection_perm_root, root'_coroot_eq_pairing, pairing_same, two_smul,
+ sub_add_cancel_left, ← toLin_toPerfectPairing, LinearMap.map_neg₂, toLin_toPerfectPairing,
+ root'_coroot_eq_pairing]
+
+@[simp]
+lemma pairing_reflection_perm_self_right (i j : ι) :
+ P.pairing i (P.reflection_perm j j) = - P.pairing i j := by
+ rw [pairing, ← reflection_perm_coroot, root_coroot_eq_pairing, pairing_same, two_smul,
+ sub_add_cancel_left, ← toLin_toPerfectPairing, map_neg, toLin_toPerfectPairing,
+ root_coroot_eq_pairing]
+
/-- A root pairing is said to be crystallographic if the pairing between a root and coroot is
always an integer. -/
def IsCrystallographic : Prop :=
- ∀ i, MapsTo (P.toPerfectPairing (P.root i)) (range P.coroot) (zmultiples (1 : R))
+ ∀ i, MapsTo (P.root' i) (range P.coroot) (zmultiples (1 : R))
lemma isCrystallographic_iff :
P.IsCrystallographic ↔ ∀ i j, ∃ z : ℤ, z = P.pairing i j := by
@@ -433,7 +477,7 @@ lemma two_nsmul_reflection_eq_of_perm_eq (hij : P.reflection_perm i = P.reflecti
2 • ⇑(P.reflection i) = 2 • P.reflection j := by
ext x
suffices 2 • P.toLin x (P.coroot i) • P.root i = 2 • P.toLin x (P.coroot j) • P.root j by
- simpa [reflection_apply]
+ simpa [reflection_apply, smul_sub]
calc 2 • P.toLin x (P.coroot i) • P.root i
= P.toLin x (P.coroot i) • ((2 : R) • P.root i) := ?_
_ = P.toLin x (P.coroot i) • (P.pairing i j • P.root j) := ?_
@@ -457,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
@@ -488,12 +532,12 @@ lemma IsOrthogonal.symm : IsOrthogonal P i j ↔ IsOrthogonal P j i := by
simp only [IsOrthogonal, and_comm]
lemma isOrthogonal_comm (h : IsOrthogonal P i j) : Commute (P.reflection i) (P.reflection j) := by
- rw [Commute, SemiconjBy]
+ rw [commute_iff_eq]
ext v
replace h : P.pairing i j = 0 ∧ P.pairing j i = 0 := by simpa [IsOrthogonal] using h
erw [LinearMap.mul_apply, LinearMap.mul_apply]
- simp only [LinearEquiv.coe_coe, reflection_apply, map_sub, map_smul, root_coroot_eq_pairing,
- zero_smul, sub_zero, toLin_toPerfectPairing, h]
+ simp only [LinearEquiv.coe_coe, reflection_apply, PerfectPairing.flip_apply_apply, map_sub,
+ map_smul, root_coroot_eq_pairing, h, zero_smul, sub_zero]
abel
end RootPairing
diff --git a/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean b/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean
new file mode 100644
index 0000000000000..d495f1b08bbcc
--- /dev/null
+++ b/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean
@@ -0,0 +1,137 @@
+/-
+Copyright (c) 2024 Scott Carnahan. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Scott Carnahan
+-/
+import Mathlib.LinearAlgebra.RootSystem.Defs
+import Mathlib.Algebra.Ring.SumsOfSquares
+
+/-!
+# The canonical bilinear form on a finite root pairing
+Given a finite root pairing, we define a canonical map from weight space to coweight space, and the
+corresponding bilinear form. This form is symmetric and Weyl-invariant, and if the base ring is
+linearly ordered, then the form is root-positive, positive-semidefinite on the weight space, and
+positive-definite on the span of roots.
+From these facts, it is easy to show that Coxeter weights in a finite root pairing are bounded
+above by 4. Thus, the pairings of roots and coroots in a crystallographic root pairing are
+restricted to a small finite set of possibilities.
+Another application is to the faithfulness of the Weyl group action on roots, and finiteness of the
+Weyl group.
+
+## Main definitions:
+ * `Polarization`: A distinguished linear map from the weight space to the coweight space.
+ * `RootForm` : The bilinear form on weight space corresponding to `Polarization`.
+
+## References:
+ * SGAIII Exp. XXI
+ * Bourbaki, Lie groups and Lie algebras
+
+## Main results:
+ * `polarization_self_sum_of_squares` : The inner product of any weight vector is a sum of squares.
+ * `rootForm_reflection_reflection_apply` : `RootForm` is invariant with respect
+ to reflections.
+ * `rootForm_self_smul_coroot`: The inner product of a root with itself times the
+ corresponding coroot is equal to two times Polarization applied to the root.
+
+## TODO (possibly in other files)
+ * Positivity and nondegeneracy
+ * Weyl-invariance
+ * Faithfulness of Weyl group action, and finiteness of Weyl group, for finite root systems.
+ * Relation to Coxeter weight. In particular, positivity constraints for finite root pairings mean
+ we restrict to weights between 0 and 4.
+-/
+
+open Function
+open Module hiding reflection
+
+noncomputable section
+
+variable {ι R M N : Type*}
+
+namespace RootPairing
+
+section CommRing
+
+variable [Fintype ι] [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N]
+(P : RootPairing ι R M N)
+
+/-- An invariant linear map from weight space to coweight space. -/
+def Polarization : M →ₗ[R] N :=
+ ∑ i, LinearMap.toSpanSingleton R N (P.coroot i) ∘ₗ P.coroot' i
+
+@[simp]
+lemma Polarization_apply (x : M) :
+ P.Polarization x = ∑ i, P.coroot' i x • P.coroot i := by
+ simp [Polarization]
+
+/-- An invariant linear map from coweight space to weight space. -/
+def CoPolarization : N →ₗ[R] M :=
+ ∑ i, LinearMap.toSpanSingleton R M (P.root i) ∘ₗ P.root' i
+
+@[simp]
+lemma CoPolarization_apply (x : N) :
+ P.CoPolarization x = ∑ i, P.root' i x • P.root i := by
+ simp [CoPolarization]
+
+lemma CoPolarization_eq : P.CoPolarization = P.flip.Polarization :=
+ rfl
+
+/-- An invariant inner product on the weight space. -/
+def RootForm : LinearMap.BilinForm R M :=
+ ∑ i, (P.coroot' i).smulRight (P.coroot' i)
+
+/-- An invariant inner product on the coweight space. -/
+def CorootForm : LinearMap.BilinForm R N :=
+ ∑ i, (P.root' i).smulRight (P.root' i)
+
+lemma rootForm_apply_apply (x y : M) : P.RootForm x y =
+ ∑ (i : ι), P.coroot' i x * P.coroot' i y := by
+ simp [RootForm]
+
+lemma rootForm_symmetric :
+ LinearMap.IsSymm P.RootForm := by
+ simp [LinearMap.IsSymm, mul_comm, rootForm_apply_apply]
+
+@[simp]
+lemma rootForm_reflection_reflection_apply (i : ι) (x y : M) :
+ P.RootForm (P.reflection i x) (P.reflection i y) = P.RootForm x y := by
+ simp only [rootForm_apply_apply, coroot'_reflection]
+ exact Fintype.sum_equiv (P.reflection_perm i)
+ (fun j ↦ (P.coroot' (P.reflection_perm i j) x) * (P.coroot' (P.reflection_perm i j) y))
+ (fun j ↦ P.coroot' j x * P.coroot' j y) (congrFun rfl)
+
+/-- This is SGA3 XXI Lemma 1.2.1 (10), key for proving nondegeneracy and positivity. -/
+lemma rootForm_self_smul_coroot (i : ι) :
+ (P.RootForm (P.root i) (P.root i)) • P.coroot i = 2 • P.Polarization (P.root i) := by
+ have hP : P.Polarization (P.root i) =
+ ∑ j : ι, P.pairing i (P.reflection_perm i j) • P.coroot (P.reflection_perm i j) := by
+ simp_rw [Polarization_apply, root_coroot'_eq_pairing]
+ exact (Fintype.sum_equiv (P.reflection_perm i)
+ (fun j ↦ P.pairing i (P.reflection_perm i j) • P.coroot (P.reflection_perm i j))
+ (fun j ↦ P.pairing i j • P.coroot j) (congrFun rfl)).symm
+ rw [two_nsmul]
+ nth_rw 2 [hP]
+ rw [Polarization_apply]
+ simp only [root_coroot'_eq_pairing, pairing_reflection_perm, pairing_reflection_perm_self_left,
+ ← reflection_perm_coroot, smul_sub, neg_smul, sub_neg_eq_add]
+ rw [Finset.sum_add_distrib, ← add_assoc, ← sub_eq_iff_eq_add]
+ simp only [rootForm_apply_apply, LinearMap.coe_comp, comp_apply, Polarization_apply,
+ root_coroot_eq_pairing, map_sum, LinearMapClass.map_smul, Finset.sum_neg_distrib, ← smul_assoc]
+ rw [Finset.sum_smul, add_neg_eq_zero.mpr rfl]
+ exact sub_eq_zero_of_eq rfl
+
+lemma corootForm_self_smul_root (i : ι) :
+ (P.CorootForm (P.coroot i) (P.coroot i)) • P.root i = 2 • P.CoPolarization (P.coroot i) :=
+ rootForm_self_smul_coroot (P.flip) i
+
+lemma rootForm_self_sum_of_squares (x : M) :
+ IsSumSq (P.RootForm x x) :=
+ P.rootForm_apply_apply x x ▸ isSumSq_sum_mul_self Finset.univ _
+
+lemma rootForm_root_self (j : ι) :
+ P.RootForm (P.root j) (P.root j) = ∑ (i : ι), (P.pairing j i) * (P.pairing j i) := by
+ simp [rootForm_apply_apply]
+
+end CommRing
+
+end RootPairing
diff --git a/Mathlib/LinearAlgebra/RootSystem/Hom.lean b/Mathlib/LinearAlgebra/RootSystem/Hom.lean
index 0b686f2f8d847..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
@@ -74,39 +115,459 @@ def Hom.comp {ι₁ M₁ N₁ ι₂ M₂ N₂ : Type*} [AddCommGroup M₁] [Modu
root_weightMap := by
ext i
simp only [LinearMap.coe_comp, Equiv.coe_trans]
- rw [comp.assoc, f.root_weightMap, ← comp.assoc, g.root_weightMap, comp.assoc]
+ rw [comp_assoc, f.root_weightMap, ← comp_assoc, g.root_weightMap, comp_assoc]
coroot_coweightMap := by
ext i
simp only [LinearMap.coe_comp, Equiv.symm_trans_apply]
- rw [comp.assoc, g.coroot_coweightMap, ← comp.assoc, f.coroot_coweightMap, comp.assoc]
+ rw [comp_assoc, g.coroot_coweightMap, ← comp_assoc, f.coroot_coweightMap, comp_assoc]
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
@@ -116,8 +577,32 @@ def Hom.reflection (P : RootPairing ι R M N) (i : ι) : Hom P P where
PerfectPairing.toDualRight_apply, LinearMap.dualMap_apply, PerfectPairing.flip_apply_apply,
LinearEquiv.comp_coe, LinearEquiv.trans_apply]
rw [RootPairing.reflection_apply, RootPairing.coreflection_apply]
- simp [← PerfectPairing.toLin_apply, mul_comm]
+ simp only [← PerfectPairing.toLin_apply, map_sub, map_smul, LinearMap.sub_apply,
+ toLin_toPerfectPairing, LinearMap.smul_apply, smul_eq_mul, sub_right_inj]
+ 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
new file mode 100644
index 0000000000000..ae27ada2167b0
--- /dev/null
+++ b/Mathlib/LinearAlgebra/RootSystem/OfBilinear.lean
@@ -0,0 +1,182 @@
+/-
+Copyright (c) 2024 Scott Carnahan. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Scott Carnahan
+-/
+import Mathlib.LinearAlgebra.RootSystem.Defs
+
+/-!
+# Root pairings made from bilinear forms
+A common construction of root systems is given by taking the set of all vectors in an integral
+lattice for which reflection yields an automorphism of the lattice. In this file, we generalize
+this construction, replacing the ring of integers with an arbitrary commutative ring and the
+integral lattice with an arbitrary reflexive module equipped with a bilinear form.
+
+## Main definitions:
+ * `LinearMap.IsReflective`: Length is a regular value of `R`, and reflection is definable.
+ * `LinearMap.IsReflective.coroot`: The coroot corresponding to a reflective vector.
+ * `RootPairing.of_Bilinear`: The root pairing whose roots are reflective vectors.
+
+## TODO
+ * properties
+-/
+
+open Set Function Module
+
+noncomputable section
+
+variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M]
+
+namespace LinearMap
+
+/-- A vector `x` is reflective with respect to a bilinear form if multiplication by its norm is
+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 where
+ regular : IsRegular (B x x)
+ dvd_two_mul : ∀ y, B x x ∣ 2 * B x y
+
+variable (B : M →ₗ[R] M →ₗ[R] R) {x : M}
+
+namespace IsReflective
+
+lemma of_dvd_two [IsDomain R] [NeZero (2 : R)] (hx : B x x ∣ 2) :
+ IsReflective B x where
+ regular := isRegular_of_ne_zero <| fun contra ↦ by simp [contra, two_ne_zero (α := R)] at hx
+ dvd_two_mul y := hx.mul_right (B x y)
+
+variable (hx : IsReflective B x)
+
+/-- The coroot attached to a reflective vector. -/
+def coroot : M →ₗ[R] R where
+ toFun y := (hx.2 y).choose
+ map_add' a b := by
+ refine hx.1.1 ?_
+ simp only
+ rw [← (hx.2 (a + b)).choose_spec, mul_add, ← (hx.2 a).choose_spec, ← (hx.2 b).choose_spec,
+ map_add, mul_add]
+ map_smul' r a := by
+ refine hx.1.1 ?_
+ simp only [RingHom.id_apply]
+ rw [← (hx.2 (r • a)).choose_spec, smul_eq_mul, mul_left_comm, ← (hx.2 a).choose_spec, map_smul,
+ two_mul, smul_eq_mul, two_mul, mul_add]
+
+@[simp]
+lemma apply_self_mul_coroot_apply {y : M} : B x x * coroot B hx y = 2 * B x y :=
+ (hx.dvd_two_mul y).choose_spec.symm
+
+@[simp]
+lemma smul_coroot : B x x • coroot B hx = 2 • B x := by
+ ext y
+ simp [smul_apply, smul_eq_mul, nsmul_eq_mul, Nat.cast_ofNat, apply_self_mul_coroot_apply]
+
+@[simp]
+lemma coroot_apply_self : coroot B hx x = 2 :=
+ hx.regular.left <| by simp [mul_comm _ (B x x)]
+
+lemma isOrthogonal_reflection (hSB : LinearMap.IsSymm B) :
+ B.IsOrthogonal (Module.reflection (coroot_apply_self B hx)) := by
+ intro y z
+ simp only [LinearEquiv.coe_coe, reflection_apply, LinearMap.map_sub, map_smul, sub_apply,
+ smul_apply, smul_eq_mul]
+ refine hx.1.1 ?_
+ simp only [mul_sub, ← mul_assoc, apply_self_mul_coroot_apply]
+ rw [sub_eq_iff_eq_add, ← hSB x y, RingHom.id_apply, mul_assoc _ _ (B x x), mul_comm _ (B x x),
+ apply_self_mul_coroot_apply]
+ ring
+
+lemma reflective_reflection (hSB : LinearMap.IsSymm B) {y : M}
+ (hx : IsReflective B x) (hy : IsReflective B y) :
+ IsReflective B (Module.reflection (coroot_apply_self B hx) y) := by
+ constructor
+ · rw [← LinearEquiv.coe_coe, isOrthogonal_reflection B hx hSB]
+ exact hy.1
+ · intro z
+ have hz : Module.reflection (coroot_apply_self B hx)
+ (Module.reflection (coroot_apply_self B hx) z) = z := by
+ exact (LinearEquiv.eq_symm_apply (Module.reflection (coroot_apply_self B hx))).mp rfl
+ rw [← hz, ← LinearEquiv.coe_coe, isOrthogonal_reflection B hx hSB,
+ isOrthogonal_reflection B hx hSB]
+ exact hy.2 _
+
+end IsReflective
+
+end LinearMap
+
+namespace RootPairing
+
+open LinearMap IsReflective
+
+/-- The root pairing given by all reflective vectors for a bilinear form. -/
+def ofBilinear [IsReflexive R M] (B : M →ₗ[R] M →ₗ[R] R) (hNB : LinearMap.Nondegenerate B)
+ (hSB : LinearMap.IsSymm B) (h2 : IsRegular (2 : R)) :
+ RootPairing {x : M | IsReflective B x} R M (Dual R M) where
+ toPerfectPairing := (IsReflexive.toPerfectPairingDual (R := R) (M := M)).flip
+ root := Embedding.subtype fun x ↦ IsReflective B x
+ coroot :=
+ { toFun := fun x => IsReflective.coroot B x.2
+ inj' := by
+ intro x y hxy
+ simp only [mem_setOf_eq] at hxy -- x* = y*
+ have h1 : ∀ z, IsReflective.coroot B x.2 z = IsReflective.coroot B y.2 z :=
+ fun z => congrFun (congrArg DFunLike.coe hxy) z
+ have h2x : ∀ z, B x x * IsReflective.coroot B x.2 z =
+ B x x * IsReflective.coroot B y.2 z :=
+ fun z => congrArg (HMul.hMul ((B x) x)) (h1 z)
+ have h2y : ∀ z, B y y * IsReflective.coroot B x.2 z =
+ B y y * IsReflective.coroot B y.2 z :=
+ fun z => congrArg (HMul.hMul ((B y) y)) (h1 z)
+ simp_rw [apply_self_mul_coroot_apply B x.2] at h2x -- 2(x,z) = (x,x)y*(z)
+ simp_rw [apply_self_mul_coroot_apply B y.2] at h2y -- (y,y)x*(z) = 2(y,z)
+ have h2xy : B x x = B y y := by
+ refine h2.1 ?_
+ dsimp only
+ specialize h2x y
+ rw [coroot_apply_self] at h2x
+ specialize h2y x
+ rw [coroot_apply_self] at h2y
+ rw [mul_comm, ← h2x, ← hSB, RingHom.id_apply, ← h2y, mul_comm]
+ rw [Subtype.ext_iff_val, ← sub_eq_zero]
+ refine hNB.1 _ (fun z => ?_)
+ rw [map_sub, LinearMap.sub_apply, sub_eq_zero]
+ refine h2.1 ?_
+ dsimp only
+ rw [h2x z, ← h2y z, hxy, h2xy] }
+ root_coroot_two x := by
+ dsimp only [coe_setOf, Embedding.coe_subtype, PerfectPairing.toLin_apply, mem_setOf_eq, id_eq,
+ eq_mp_eq_cast, RingHom.id_apply, eq_mpr_eq_cast, cast_eq, LinearMap.sub_apply,
+ Embedding.coeFn_mk, PerfectPairing.flip_apply_apply]
+ exact coroot_apply_self B x.2
+ reflection_perm x :=
+ { toFun := fun y => ⟨(Module.reflection (coroot_apply_self B x.2) y),
+ reflective_reflection B hSB x.2 y.2⟩
+ invFun := fun y => ⟨(Module.reflection (coroot_apply_self B x.2) y),
+ reflective_reflection B hSB x.2 y.2⟩
+ left_inv := by
+ intro y
+ simp [involutive_reflection (coroot_apply_self B x.2) y]
+ right_inv := by
+ intro y
+ simp [involutive_reflection (coroot_apply_self B x.2) y] }
+ reflection_perm_root x y := by
+ simp [Module.reflection_apply]
+ reflection_perm_coroot x y := by
+ simp only [coe_setOf, mem_setOf_eq, Embedding.coeFn_mk, Embedding.coe_subtype,
+ PerfectPairing.flip_apply_apply, IsReflexive.toPerfectPairingDual_apply, Equiv.coe_fn_mk]
+ ext z
+ simp only [LinearMap.sub_apply, LinearMap.smul_apply, smul_eq_mul]
+ refine y.2.1.1 ?_
+ simp only [mem_setOf_eq, PerfectPairing.flip_apply_apply, mul_sub,
+ apply_self_mul_coroot_apply B y.2, ← mul_assoc]
+ rw [← isOrthogonal_reflection B x.2 hSB y y, apply_self_mul_coroot_apply, ← hSB z, ← hSB z,
+ RingHom.id_apply, RingHom.id_apply, LinearEquiv.coe_coe, Module.reflection_apply, map_sub,
+ mul_sub, sub_eq_sub_iff_comm, sub_left_inj]
+ refine x.2.1.1 ?_
+ simp only [mem_setOf_eq, map_smul, smul_eq_mul]
+ rw [← mul_assoc _ _ (B z x), ← mul_assoc _ _ (B z x), mul_left_comm,
+ apply_self_mul_coroot_apply B x.2, mul_left_comm (B x x), apply_self_mul_coroot_apply B x.2,
+ ← hSB x y, RingHom.id_apply, ← hSB x z, RingHom.id_apply]
+ ring
+
+end RootPairing
diff --git a/Mathlib/LinearAlgebra/RootSystem/RootPositive.lean b/Mathlib/LinearAlgebra/RootSystem/RootPositive.lean
index ccf50330e9a81..e9d55f92f8209 100644
--- a/Mathlib/LinearAlgebra/RootSystem/RootPositive.lean
+++ b/Mathlib/LinearAlgebra/RootSystem/RootPositive.lean
@@ -55,7 +55,7 @@ lemma two_mul_apply_root_root :
2 * B (P.root i) (P.root j) = P.pairing i j * B (P.root j) (P.root j) := by
rw [two_mul, ← eq_sub_iff_add_eq]
nth_rw 1 [← IsRootPositive.apply_reflection_eq (P := P) (B := B) j (P.root i) (P.root j)]
- rw [reflection_apply, reflection_apply_self, root_coroot_eq_pairing, LinearMap.map_sub₂,
+ rw [reflection_apply, reflection_apply_self, root_coroot'_eq_pairing, LinearMap.map_sub₂,
LinearMap.map_smul₂, smul_eq_mul, LinearMap.map_neg, LinearMap.map_neg, mul_neg, neg_sub_neg]
@[simp]
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 ea02d0bd4374e..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,32 +112,91 @@ 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
rw [← aeval_X (R := R) f]; rw [← aeval_X_pow (R := R) f] at h0
rw [← RingHom.mem_ker, ← AEval.annihilator_eq_ker_aeval (M := M)] at h0 ⊢
- exact hs.annihilator_isRadical ⟨n, 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
@@ -145,7 +242,7 @@ theorem IsSemisimple.minpoly_squarefree : Squarefree (minpoly K f) :=
protected theorem IsSemisimple.aeval (p : K[X]) : (aeval f p).IsSemisimple :=
let R := K[X] ⧸ Ideal.span {minpoly K f}
- have : Finite K R :=
+ have : Module.Finite K R :=
(AdjoinRoot.powerBasis' <| minpoly.monic <| Algebra.IsIntegral.isIntegral f).finite
have : IsReduced R := (Ideal.isRadical_iff_quotient_reduced _).mp <|
span_minpoly_eq_annihilator K f ▸ hf.annihilator_isRadical
@@ -174,9 +271,9 @@ theorem IsSemisimple.of_mem_adjoin_pair {a : End K M} (ha : a ∈ Algebra.adjoin
a.IsSemisimple := by
let R := K[X] ⧸ Ideal.span {minpoly K f}
let S := AdjoinRoot ((minpoly K g).map <| algebraMap K R)
- have : Finite K R :=
+ have : Module.Finite K R :=
(AdjoinRoot.powerBasis' <| minpoly.monic <| Algebra.IsIntegral.isIntegral f).finite
- have : Finite R S :=
+ have : Module.Finite R S :=
(AdjoinRoot.powerBasis' <| (minpoly.monic <| Algebra.IsIntegral.isIntegral g).map _).finite
#adaptation_note
/--
@@ -187,7 +284,7 @@ theorem IsSemisimple.of_mem_adjoin_pair {a : End K M} (ha : a ∈ Algebra.adjoin
-/
set_option maxSynthPendingDepth 2 in
have : IsScalarTower K R S := .of_algebraMap_eq fun _ ↦ rfl
- have : Finite K S := .trans R S
+ have : Module.Finite K S := .trans R S
have : IsArtinianRing R := .of_finite K R
have : IsReduced R := (Ideal.isRadical_iff_quotient_reduced _).mp <|
span_minpoly_eq_annihilator K f ▸ hf.annihilator_isRadical
diff --git a/Mathlib/LinearAlgebra/SesquilinearForm.lean b/Mathlib/LinearAlgebra/SesquilinearForm.lean
index e1ee9539064ba..99617d933657d 100644
--- a/Mathlib/LinearAlgebra/SesquilinearForm.lean
+++ b/Mathlib/LinearAlgebra/SesquilinearForm.lean
@@ -458,6 +458,37 @@ theorem IsAdjointPair.smul (c : R) (h : IsAdjointPair B B' f g) :
end AddCommGroup
+section OrthogonalMap
+
+variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M]
+ (B : LinearMap.BilinForm R M) (f : Module.End R M)
+
+/-- A linear transformation `f` is orthogonal with respect to a bilinear form `B` if `B` is
+bi-invariant with respect to `f`. -/
+def IsOrthogonal : Prop :=
+ ∀ x y, B (f x) (f y) = B x y
+
+variable {B f}
+
+@[simp]
+lemma _root_.LinearEquiv.isAdjointPair_symm_iff {f : M ≃ₗ[R] M} :
+ LinearMap.IsAdjointPair B B f f.symm ↔ B.IsOrthogonal f :=
+ ⟨fun hf x y ↦ by simpa using hf x (f y), fun hf x y ↦ by simpa using hf x (f.symm y)⟩
+
+lemma isOrthogonal_of_forall_apply_same
+ (h : IsLeftRegular (2 : R)) (hB : B.IsSymm) (hf : ∀ x, B (f x) (f x) = B x x) :
+ B.IsOrthogonal f := by
+ intro x y
+ suffices 2 * B (f x) (f y) = 2 * B x y from h this
+ have := hf (x + y)
+ simp only [map_add, add_apply, hf x, hf y, show B y x = B x y from hB.eq y x] at this
+ rw [show B (f y) (f x) = B (f x) (f y) from hB.eq (f y) (f x)] at this
+ simp only [add_assoc, add_right_inj] at this
+ simp only [← add_assoc, add_left_inj] at this
+ simpa only [← two_mul] using this
+
+end OrthogonalMap
+
end AdjointPair
/-! ### Self-adjoint pairs -/
diff --git a/Mathlib/LinearAlgebra/Span.lean b/Mathlib/LinearAlgebra/Span.lean
index 8ff62644c2b01..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
@@ -74,7 +75,7 @@ theorem subset_span : s ⊆ span R s := fun _ h => mem_span.2 fun _ hp => hp h
theorem span_le {p} : span R s ≤ p ↔ s ⊆ p :=
⟨Subset.trans subset_span, fun ss _ h => mem_span.1 h _ ss⟩
-theorem span_mono (h : s ⊆ t) : span R s ≤ span R t :=
+@[gcongr] theorem span_mono (h : s ⊆ t) : span R s ≤ span R t :=
span_le.2 <| Subset.trans h subset_span
theorem span_monotone : Monotone (span R : Set M → Submodule R M) := fun _ _ => span_mono
@@ -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/TensorAlgebra/ToTensorPower.lean b/Mathlib/LinearAlgebra/TensorAlgebra/ToTensorPower.lean
index 12adf5ad0f2b0..e37eea1ee4fdd 100644
--- a/Mathlib/LinearAlgebra/TensorAlgebra/ToTensorPower.lean
+++ b/Mathlib/LinearAlgebra/TensorAlgebra/ToTensorPower.lean
@@ -32,8 +32,8 @@ theorem toTensorAlgebra_tprod {n} (x : Fin n → M) :
@[simp]
theorem toTensorAlgebra_gOne :
- TensorPower.toTensorAlgebra (@GradedMonoid.GOne.one _ (fun n => ⨂[R]^n M) _ _) = 1 :=
- TensorPower.toTensorAlgebra_tprod _
+ TensorPower.toTensorAlgebra (@GradedMonoid.GOne.one _ (fun n => ⨂[R]^n M) _ _) = 1 := by
+ simp [GradedMonoid.GOne.one, TensorPower.toTensorAlgebra_tprod]
@[simp]
theorem toTensorAlgebra_gMul {i j} (a : (⨂[R]^i) M) (b : (⨂[R]^j) M) :
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 bcb3daf37d060..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
@@ -449,7 +449,7 @@ variable (R M N)
/-- The simple (aka pure) elements span the tensor product. -/
theorem span_tmul_eq_top : Submodule.span R { t : M ⊗[R] N | ∃ m n, m ⊗ₜ n = t } = ⊤ := by
- ext t; simp only [Submodule.mem_top, iff_true_iff]
+ ext t; simp only [Submodule.mem_top, iff_true]
refine t.induction_on ?_ ?_ ?_
· exact Submodule.zero_mem _
· intro m n
@@ -614,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 d06c680fb6859..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]
@@ -220,7 +220,7 @@ theorem tmul_coe_mul_one_tmul {j₁ : ι} (a₁ : A) (b₁ : ℬ j₁) (b₂ : B
theorem tmul_one_mul_one_tmul (a₁ : A) (b₂ : B) :
(a₁ ᵍ⊗ₜ[R] (1 : B) * (1 : A) ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) = (a₁ : A) ᵍ⊗ₜ (b₂ : B) := by
convert tmul_coe_mul_zero_coe_tmul 𝒜 ℬ
- a₁ (@GradedMonoid.GOne.one _ (ℬ ·) _ _) (@GradedMonoid.GOne.one _ (𝒜 ·) _ _) b₂
+ a₁ (GradedMonoid.GOne.one (A := (ℬ ·))) (GradedMonoid.GOne.one (A := (𝒜 ·))) b₂
· rw [SetLike.coe_gOne, mul_one]
· rw [SetLike.coe_gOne, one_mul]
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 608cd74b64296..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
@@ -547,7 +471,7 @@ lemma Ideal.map_includeLeft_eq (I : Ideal A) :
simp only [map_zero, smul_eq_mul, mul_zero]
| tmul x y =>
use (a • x) ⊗ₜ[R] (b * y)
- simp only [LinearMap.lTensor_tmul, Submodule.coeSubtype, smul_eq_mul, tmul_mul_tmul]
+ simp only [LinearMap.lTensor_tmul, Submodule.coe_subtype, smul_eq_mul, tmul_mul_tmul]
with_unfolding_all rfl
| add x y hx hy =>
obtain ⟨x', hx'⟩ := hx
@@ -566,7 +490,7 @@ lemma Ideal.map_includeLeft_eq (I : Ideal A) :
rw [map_zero]
apply zero_mem
| tmul a b =>
- simp only [LinearMap.rTensor_tmul, Submodule.coeSubtype]
+ simp only [LinearMap.rTensor_tmul, Submodule.coe_subtype]
suffices (a : A) ⊗ₜ[R] b = ((1 : A) ⊗ₜ[R] b) * ((a : A) ⊗ₜ[R] (1 : B)) by
simp only [AddSubsemigroup.mem_carrier, AddSubmonoid.mem_toSubsemigroup,
Submodule.mem_toAddSubmonoid, Submodule.restrictScalars_mem]
@@ -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
@@ -615,7 +539,7 @@ lemma Ideal.map_includeRight_eq (I : Ideal B) :
simp only [map_zero, smul_eq_mul, mul_zero]
| tmul x y =>
use (a * x) ⊗ₜ[R] (b •y)
- simp only [LinearMap.lTensor_tmul, Submodule.coeSubtype, smul_eq_mul, tmul_mul_tmul]
+ simp only [LinearMap.lTensor_tmul, Submodule.coe_subtype, smul_eq_mul, tmul_mul_tmul]
rfl
| add x y hx hy =>
obtain ⟨x', hx'⟩ := hx
@@ -634,7 +558,7 @@ lemma Ideal.map_includeRight_eq (I : Ideal B) :
rw [map_zero]
apply zero_mem
| tmul a b =>
- simp only [LinearMap.lTensor_tmul, Submodule.coeSubtype]
+ simp only [LinearMap.lTensor_tmul, Submodule.coe_subtype]
suffices a ⊗ₜ[R] (b : B) = (a ⊗ₜ[R] (1 : B)) * ((1 : A) ⊗ₜ[R] (b : B)) by
rw [this]
simp only [AddSubsemigroup.mem_carrier, AddSubmonoid.mem_toSubsemigroup,
diff --git a/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean b/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean
index 2ec0b351ea9e9..83b52e58279fd 100644
--- a/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean
+++ b/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean
@@ -36,7 +36,7 @@ mainly used in the definition of linearly disjointness.
open scoped TensorProduct
-open FiniteDimensional
+open Module
noncomputable section
@@ -194,7 +194,7 @@ theorem rank_sup_le_of_free [Module.Free R A] [Module.Free R B] :
exact rank_range_le (A.mulMap B).toLinearMap
/-- If `A` and `B` are subalgebras of a commutative `R`-algebra `S`, both of them are
-free `R`-algebras, then the `FiniteDimensional.finrank` of `A ⊔ B` is less than or equal to
+free `R`-algebras, then the `Module.finrank` of `A ⊔ B` is less than or equal to
the product of that of `A` and `B`. -/
theorem finrank_sup_le_of_free [Module.Free R A] [Module.Free R B] :
finrank R ↥(A ⊔ B) ≤ finrank R A * finrank R B := by
@@ -206,7 +206,7 @@ theorem finrank_sup_le_of_free [Module.Free R A] [Module.Free R B] :
wlog hA : ¬ Module.Finite R A generalizing A B
· have := this B A (fun h' ↦ h h'.symm) (not_and.1 h (of_not_not hA))
rwa [sup_comm, mul_comm] at this
- rw [← Module.rank_lt_alpeh0_iff, not_lt] at hA
+ rw [← Module.rank_lt_aleph0_iff, not_lt] at hA
have := LinearMap.rank_le_of_injective _ <| Submodule.inclusion_injective <|
show toSubmodule A ≤ toSubmodule (A ⊔ B) by simp
rw [show finrank R A = 0 from Cardinal.toNat_apply_of_aleph0_le hA,
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 da36cbf10939d..9634e23fe06da 100644
--- a/Mathlib/LinearAlgebra/TensorProduct/Tower.lean
+++ b/Mathlib/LinearAlgebra/TensorProduct/Tower.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johan Commelin, Eric Wieser
+Authors: Kim Morrison, Johan Commelin, Eric Wieser
-/
import Mathlib.Algebra.Algebra.Tower
import Mathlib.LinearAlgebra.TensorProduct.Basic
@@ -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/LinearAlgebra/TensorProduct/Vanishing.lean b/Mathlib/LinearAlgebra/TensorProduct/Vanishing.lean
index dbf016581b5a2..8a6dcf8f11f00 100644
--- a/Mathlib/LinearAlgebra/TensorProduct/Vanishing.lean
+++ b/Mathlib/LinearAlgebra/TensorProduct/Vanishing.lean
@@ -146,7 +146,7 @@ theorem vanishesTrivially_of_sum_tmul_eq_zero (hm : Submodule.span R (Set.range
symm at hkn
simp only [map_sum, finsuppScalarLeft_apply_tmul, zero_smul, Finsupp.single_zero,
Finsupp.sum_single_index, one_smul, Finsupp.finset_sum_apply, Finsupp.single_apply,
- Finset.sum_ite_eq', Finset.mem_univ, ↓reduceIte, rTensor_tmul, coeSubtype, Finsupp.sum_apply,
+ Finset.sum_ite_eq', Finset.mem_univ, ↓reduceIte, rTensor_tmul, coe_subtype, Finsupp.sum_apply,
Finsupp.sum_ite_eq', Finsupp.mem_support_iff, ne_eq, ite_not, en] at hkn
simp only [Finset.univ_eq_attach, Finset.sum_attach ma (fun x ↦ (x.1 : ι →₀ R) i • x.2)]
convert hkn using 2 with x _
@@ -181,11 +181,11 @@ theorem vanishesTrivially_of_sum_tmul_eq_zero_of_rTensor_injective
set m' : ι → span R (Set.range m) := Subtype.coind m mem_M' with m'_eq
have hm' : span R (Set.range m') = ⊤ := by
apply map_injective_of_injective (injective_subtype (span R (Set.range m)))
- rw [Submodule.map_span, Submodule.map_top, range_subtype, coeSubtype, ← Set.range_comp]
+ rw [Submodule.map_span, Submodule.map_top, range_subtype, coe_subtype, ← Set.range_comp]
rfl
have hm'n : ∑ i, m' i ⊗ₜ n i = (0 : span R (Set.range m) ⊗[R] N) := by
apply hm
- simp only [m'_eq, map_sum, rTensor_tmul, coeSubtype, Subtype.coind_coe, _root_.map_zero, hmn]
+ simp only [m'_eq, map_sum, rTensor_tmul, coe_subtype, Subtype.coind_coe, _root_.map_zero, hmn]
have : VanishesTrivially R m' n := vanishesTrivially_of_sum_tmul_eq_zero R hm' hm'n
unfold VanishesTrivially at this ⊢
convert this with κ _ a y j
@@ -218,7 +218,7 @@ theorem rTensor_injective_of_forall_vanishesTrivially
obtain ⟨s, rfl⟩ := exists_finset x
rw [← Finset.sum_attach]
apply sum_tmul_eq_zero_of_vanishesTrivially
- simp only [map_sum, rTensor_tmul, coeSubtype] at hx
+ simp only [map_sum, rTensor_tmul, coe_subtype] at hx
have := hMN ((Finset.sum_attach s _).trans hx)
unfold VanishesTrivially at this ⊢
convert this with κ _ a y j
diff --git a/Mathlib/LinearAlgebra/Trace.lean b/Mathlib/LinearAlgebra/Trace.lean
index d8dfa8fb4f30b..81598681a3b50 100644
--- a/Mathlib/LinearAlgebra/Trace.lean
+++ b/Mathlib/LinearAlgebra/Trace.lean
@@ -25,7 +25,7 @@ universe u v w
namespace LinearMap
open scoped Matrix
-open FiniteDimensional TensorProduct
+open Module TensorProduct
section
diff --git a/Mathlib/LinearAlgebra/Vandermonde.lean b/Mathlib/LinearAlgebra/Vandermonde.lean
index 91ce552c56948..b8de8431c2653 100644
--- a/Mathlib/LinearAlgebra/Vandermonde.lean
+++ b/Mathlib/LinearAlgebra/Vandermonde.lean
@@ -35,7 +35,7 @@ namespace Matrix
/-- `vandermonde v` is the square matrix with `i`th row equal to `1, v i, v i ^ 2, v i ^ 3, ...`.
-/
-def vandermonde {n : ℕ} (v : Fin n → R) : Matrix (Fin n) (Fin n) R := fun i j => v i ^ (j : ℕ)
+def vandermonde {n : ℕ} (v : Fin n → R) : Matrix (Fin n) (Fin n) R := .of fun i j => v i ^ (j : ℕ)
@[simp]
theorem vandermonde_apply {n : ℕ} (v : Fin n → R) (i j) : vandermonde v i j = v i ^ (j : ℕ) :=
@@ -52,7 +52,7 @@ theorem vandermonde_cons {n : ℕ} (v0 : R) (v : Fin n → R) :
simp [pow_succ']
theorem vandermonde_succ {n : ℕ} (v : Fin n.succ → R) :
- vandermonde v =
+ vandermonde v = .of
Fin.cons (fun (j : Fin n.succ) => v 0 ^ (j : ℕ)) fun i =>
Fin.cons 1 fun j => v i.succ * vandermonde (Fin.tail v) i j := by
conv_lhs => rw [← Fin.cons_self_tail v, vandermonde_cons]
@@ -102,11 +102,12 @@ theorem det_vandermonde {n : ℕ} (v : Fin n → R) :
∑ k ∈ Finset.range (j + 1 : ℕ), v i.succ ^ k * v 0 ^ (j - k : ℕ) :=
(det_mul_column (fun i => v (Fin.succ i) - v 0) _)
_ = (∏ i ∈ Finset.univ, (v (Fin.succ i) - v 0)) *
- det fun i j : Fin n => v (Fin.succ i) ^ (j : ℕ) := congr_arg _ ?_
+ det (of fun i j : Fin n => v (Fin.succ i) ^ (j : ℕ)) := congr_arg _ ?_
_ = ∏ i : Fin n.succ, ∏ j ∈ Ioi i, (v j - v i) := by
simp_rw [Fin.prod_univ_succ, Fin.prod_Ioi_zero, Fin.prod_Ioi_succ]
- have h := ih (v ∘ Fin.succ)
- unfold Function.comp at h
+ have h : (of fun i j : Fin n ↦ v i.succ ^ (j : ℕ)).det =
+ ∏ x : Fin n, ∏ y ∈ Ioi x, (v y.succ - v x.succ) := by
+ simpa using ih (v ∘ Fin.succ)
rw [h]
· intro i j
@@ -187,6 +188,7 @@ theorem eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials {n : ℕ
congr
ext k
rw [mul_comm, Matrix.of_apply, RingHom.id_apply]
+ rfl
theorem det_eval_matrixOfPolynomials_eq_det_vandermonde {n : ℕ} (v : Fin n → R) (p : Fin n → R[X])
(h_deg : ∀ i, (p i).natDegree = i) (h_monic : ∀ i, Monic <| p i) :
diff --git a/Mathlib/Logic/Basic.lean b/Mathlib/Logic/Basic.lean
index a0558381b951f..cf41e0848cfdf 100644
--- a/Mathlib/Logic/Basic.lean
+++ b/Mathlib/Logic/Basic.lean
@@ -37,6 +37,8 @@ section Miscellany
-- And.decidable Or.decidable Decidable.false Xor.decidable Iff.decidable Decidable.true
-- Implies.decidable Not.decidable Ne.decidable Bool.decidableEq Decidable.toBool
+-- attribute [refl] HEq.refl -- FIXME This is still rejected after #857
+attribute [trans] Iff.trans HEq.trans heq_of_eq_of_heq
attribute [simp] cast_heq
/-- An identity function with its main argument implicit. This will be printed as `hidden` even
@@ -168,7 +170,7 @@ theorem eq_or_ne {α : Sort*} (x y : α) : x = y ∨ x ≠ y := em <| x = y
theorem ne_or_eq {α : Sort*} (x y : α) : x ≠ y ∨ x = y := em' <| x = y
-theorem by_contradiction {p : Prop} : (¬p → False) → p := Decidable.by_contradiction
+theorem by_contradiction {p : Prop} : (¬p → False) → p := Decidable.byContradiction
theorem by_cases {p q : Prop} (hpq : p → q) (hnpq : ¬p → q) : q :=
if hp : p then hpq hp else hnpq hp
@@ -234,6 +236,11 @@ lemma Iff.ne_right {α β : Sort*} {a b : α} {c d : β} : (a ≠ b ↔ c = d)
/-! ### Declarations about `Xor'` -/
+/-- `Xor' a b` is the exclusive-or of propositions. -/
+def Xor' (a b : Prop) := (a ∧ ¬b) ∨ (b ∧ ¬a)
+
+instance [Decidable a] [Decidable b] : Decidable (Xor' a b) := inferInstanceAs (Decidable (Or ..))
+
@[simp] theorem xor_true : Xor' True = Not := by
simp (config := { unfoldPartialApp := true }) [Xor']
@@ -422,14 +429,20 @@ theorem rec_heq_iff_heq {α β : Sort _} {a b : α} {C : α → Sort*} {x : C a}
theorem heq_rec_iff_heq {α β : Sort _} {a b : α} {C : α → Sort*} {x : β} {y : C a} {e : a = b} :
HEq x (e ▸ y) ↔ HEq x y := by subst e; rfl
+universe u
+variable {α β : Sort u} {e : β = α} {a : α} {b : β}
+
+lemma heq_of_eq_cast (e : β = α) : a = cast e b → HEq a b := by rintro rfl; simp
+
+lemma eq_cast_iff_heq : a = cast e b ↔ HEq a b := ⟨heq_of_eq_cast _, fun h ↦ by cases h; rfl⟩
+
end Equality
/-! ### Declarations about quantifiers -/
section Quantifiers
section Dependent
-variable {α : Sort*} {β : α → Sort*} {γ : ∀ a, β a → Sort*} {δ : ∀ a b, γ a b → Sort*}
- {ε : ∀ a b c, δ a b c → Sort*}
+variable {α : Sort*} {β : α → Sort*} {γ : ∀ a, β a → Sort*}
theorem pi_congr {β' : α → Sort _} (h : ∀ a, β a = β' a) : (∀ a, β a) = ∀ a, β' a :=
(funext h : β = β') ▸ rfl
@@ -455,7 +468,7 @@ theorem Exists₃.imp {p q : ∀ a b, γ a b → Prop} (h : ∀ a b c, p a b c
end Dependent
-variable {α β : Sort*} {p q : α → Prop}
+variable {α β : Sort*} {p : α → Prop}
theorem forall_swap {p : α → β → Prop} : (∀ x y, p x y) ↔ ∀ y x, p x y :=
⟨fun f x y ↦ f y x, fun f x y ↦ f y x⟩
@@ -472,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
@@ -505,15 +522,6 @@ theorem forall₂_true_iff {β : α → Sort*} : (∀ a, β a → True) ↔ True
theorem forall₃_true_iff {β : α → Sort*} {γ : ∀ a, β a → Sort*} :
(∀ (a) (b : β a), γ a b → True) ↔ True := by simp
-@[simp] theorem exists_unique_iff_exists [Subsingleton α] {p : α → Prop} :
- (∃! x, p x) ↔ ∃ x, p x :=
- ⟨fun h ↦ h.exists, Exists.imp fun x hx ↦ ⟨hx, fun y _ ↦ Subsingleton.elim y x⟩⟩
-
--- forall_forall_const is no longer needed
-
-theorem exists_unique_const {b : Prop} (α : Sort*) [i : Nonempty α] [Subsingleton α] :
- (∃! _ : α, b) ↔ b := by simp
-
theorem Decidable.and_forall_ne [DecidableEq α] (a : α) {p : α → Prop} :
(p a ∧ ∀ b, b ≠ a → p b) ↔ ∀ b, p b := by
simp only [← @forall_eq _ p a, ← forall_and, ← or_imp, Decidable.em, forall_const]
@@ -524,12 +532,6 @@ theorem and_forall_ne (a : α) : (p a ∧ ∀ b, b ≠ a → p b) ↔ ∀ b, p b
theorem Ne.ne_or_ne {x y : α} (z : α) (h : x ≠ y) : x ≠ z ∨ y ≠ z :=
not_and_or.1 <| mt (and_imp.2 (· ▸ ·)) h.symm
-@[simp] theorem exists_unique_eq {a' : α} : ∃! a, a = a' := by
- simp only [eq_comm, ExistsUnique, and_self, forall_eq', exists_eq']
-
-@[simp] theorem exists_unique_eq' {a' : α} : ∃! a, a' = a := by
- simp only [ExistsUnique, and_self, forall_eq', exists_eq']
-
@[simp]
theorem exists_apply_eq_apply' (f : α → β) (a' : α) : ∃ a, f a' = f a := ⟨a', rfl⟩
@@ -608,10 +610,6 @@ protected theorem Decidable.forall_or_right {q} {p : α → Prop} [Decidable q]
theorem forall_or_right {q} {p : α → Prop} : (∀ x, p x ∨ q) ↔ (∀ x, p x) ∨ q :=
Decidable.forall_or_right
-theorem exists_unique_prop {p q : Prop} : (∃! _ : p, q) ↔ p ∧ q := by simp
-
-@[simp] theorem exists_unique_false : ¬∃! _ : α, False := fun ⟨_, h, _⟩ ↦ h
-
theorem Exists.fst {b : Prop} {p : b → Prop} : Exists p → b
| ⟨h, _⟩ => h
@@ -628,9 +626,6 @@ theorem Prop.forall_iff {p : Prop → Prop} : (∀ h, p h) ↔ p False ∧ p Tru
theorem exists_iff_of_forall {p : Prop} {q : p → Prop} (h : ∀ h, q h) : (∃ h, q h) ↔ p :=
⟨Exists.fst, fun H ↦ ⟨H, h H⟩⟩
-theorem exists_unique_prop_of_true {p : Prop} {q : p → Prop} (h : p) : (∃! h' : p, q h') ↔ q h :=
- @exists_unique_const (q h) p ⟨h⟩ _
-
theorem exists_prop_of_false {p : Prop} {q : p → Prop} : ¬p → ¬∃ h' : p, q h' :=
mt Exists.fst
@@ -669,29 +664,6 @@ lemma iff_eq_eq {a b : Prop} : (a ↔ b) = (a = b) := propext ⟨propext, Eq.to_
@[simp] theorem forall_true_left (p : True → Prop) : (∀ x, p x) ↔ p True.intro :=
forall_prop_of_true _
-theorem ExistsUnique.elim₂ {α : Sort*} {p : α → Sort*} [∀ x, Subsingleton (p x)]
- {q : ∀ (x) (_ : p x), Prop} {b : Prop} (h₂ : ∃! x, ∃! h : p x, q x h)
- (h₁ : ∀ (x) (h : p x), q x h → (∀ (y) (hy : p y), q y hy → y = x) → b) : b := by
- simp only [exists_unique_iff_exists] at h₂
- apply h₂.elim
- exact fun x ⟨hxp, hxq⟩ H ↦ h₁ x hxp hxq fun y hyp hyq ↦ H y ⟨hyp, hyq⟩
-
-theorem ExistsUnique.intro₂ {α : Sort*} {p : α → Sort*} [∀ x, Subsingleton (p x)]
- {q : ∀ (x : α) (_ : p x), Prop} (w : α) (hp : p w) (hq : q w hp)
- (H : ∀ (y) (hy : p y), q y hy → y = w) : ∃! x, ∃! hx : p x, q x hx := by
- simp only [exists_unique_iff_exists]
- exact ExistsUnique.intro w ⟨hp, hq⟩ fun y ⟨hyp, hyq⟩ ↦ H y hyp hyq
-
-theorem ExistsUnique.exists₂ {α : Sort*} {p : α → Sort*} {q : ∀ (x : α) (_ : p x), Prop}
- (h : ∃! x, ∃! hx : p x, q x hx) : ∃ (x : _) (hx : p x), q x hx :=
- h.exists.imp fun _ hx ↦ hx.exists
-
-theorem ExistsUnique.unique₂ {α : Sort*} {p : α → Sort*} [∀ x, Subsingleton (p x)]
- {q : ∀ (x : α) (_ : p x), Prop} (h : ∃! x, ∃! hx : p x, q x hx) {y₁ y₂ : α}
- (hpy₁ : p y₁) (hqy₁ : q y₁ hpy₁) (hpy₂ : p y₂) (hqy₂ : q y₂ hpy₂) : y₁ = y₂ := by
- simp only [exists_unique_iff_exists] at h
- exact h.unique ⟨hpy₁, hqy₁⟩ ⟨hpy₂, hqy₂⟩
-
end Quantifiers
/-! ### Classical lemmas -/
@@ -702,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
@@ -715,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
@@ -775,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)
@@ -783,7 +753,7 @@ noncomputable def Exists.classicalRecOn {α : Sort*} {p : α → Prop} (h : ∃
/-! ### Declarations about bounded quantifiers -/
section BoundedQuantifiers
-variable {α : Sort*} {r p q : α → Prop} {P Q : ∀ x, p x → Prop} {b : Prop}
+variable {α : Sort*} {r p q : α → Prop} {P Q : ∀ x, p x → Prop}
theorem bex_def : (∃ (x : _) (_ : p x), q x) ↔ ∃ x, p x ∧ q x :=
⟨fun ⟨x, px, qx⟩ ↦ ⟨x, px, qx⟩, fun ⟨x, px, qx⟩ ↦ ⟨x, px, qx⟩⟩
@@ -992,13 +962,29 @@ theorem dite_prop_iff_and {Q : P → Prop} {R : ¬P → Prop} :
dite P Q R ↔ (∀ h, Q h) ∧ (∀ h, R h) := by
by_cases h : P <;> simp [h, forall_prop_of_false, forall_prop_of_true]
+section congr
+
+variable [Decidable Q] {x y u v : α}
+
+theorem if_ctx_congr (h_c : P ↔ Q) (h_t : Q → x = u) (h_e : ¬Q → y = v) : ite P x y = ite Q u v :=
+ match ‹Decidable P›, ‹Decidable Q› with
+ | isFalse _, isFalse h₂ => by simp_all
+ | isTrue _, isTrue h₂ => by simp_all
+ | isFalse h₁, isTrue h₂ => absurd h₂ (Iff.mp (not_congr h_c) h₁)
+ | isTrue h₁, isFalse h₂ => absurd h₁ (Iff.mpr (not_congr h_c) h₂)
+
+theorem if_congr (h_c : P ↔ Q) (h_t : x = u) (h_e : y = v) : ite P x y = ite Q u v :=
+ if_ctx_congr h_c (fun _ ↦ h_t) (fun _ ↦ h_e)
+
+end congr
+
end ite
theorem not_beq_of_ne {α : Type*} [BEq α] [LawfulBEq α] {a b : α} (ne : a ≠ b) : ¬(a == b) :=
fun h => ne (eq_of_beq h)
theorem beq_eq_decide {α : Type*} [BEq α] [LawfulBEq α] {a b : α} : (a == b) = decide (a = b) := by
- rw [← beq_iff_eq a b]
+ rw [← beq_iff_eq (a := a) (b := b)]
cases a == b <;> simp
@[simp] lemma beq_eq_beq {α β : Type*} [BEq α] [LawfulBEq α] [BEq β] [LawfulBEq β] {a₁ a₂ : α}
diff --git a/Mathlib/Logic/Denumerable.lean b/Mathlib/Logic/Denumerable.lean
index 94274fd7d2531..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,13 +288,13 @@ 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
- simp only [h.2, and_true_iff]
+ simp only [h.2, and_true]
exact Or.symm (lt_or_eq_of_le ((@lt_succ_iff_le _ _ _ ⟨m, h.2⟩ _).1 h.1)),
fun h =>
h.elim (fun h => h.symm ▸ ⟨lt_succ_self _, (ofNat s n).prop⟩) fun h =>
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/Array.lean b/Mathlib/Logic/Equiv/Array.lean
index cd9c6fbef7d1f..eb98b0edd323b 100644
--- a/Mathlib/Logic/Equiv/Array.lean
+++ b/Mathlib/Logic/Equiv/Array.lean
@@ -42,7 +42,7 @@ namespace Equiv
/-- The natural equivalence between arrays and lists. -/
def arrayEquivList (α : Type*) : Array α ≃ List α :=
- ⟨Array.data, Array.mk, fun _ => rfl, fun _ => rfl⟩
+ ⟨Array.toList, Array.mk, fun _ => rfl, fun _ => rfl⟩
end Equiv
diff --git a/Mathlib/Logic/Equiv/Basic.lean b/Mathlib/Logic/Equiv/Basic.lean
index 895f65103bc7c..34383fc48d388 100644
--- a/Mathlib/Logic/Equiv/Basic.lean
+++ b/Mathlib/Logic/Equiv/Basic.lean
@@ -51,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
@@ -483,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
@@ -599,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
@@ -628,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`.
@@ -816,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
@@ -829,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`. -/
@@ -1027,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
@@ -1089,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!]
@@ -1165,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
@@ -1210,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. -/
@@ -1359,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
@@ -1371,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
@@ -1579,8 +1579,6 @@ namespace Equiv
section
-variable (P : α → Sort w) (e : α ≃ β)
-
/-- Transport dependent functions through an equivalence of the base space.
-/
@[simps apply, simps (config := .lemmasOnly) symm_apply]
@@ -1689,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
@@ -1733,12 +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
-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⟩
-
-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 f85dc2dee7a75..2650567700550 100644
--- a/Mathlib/Logic/Equiv/Defs.lean
+++ b/Mathlib/Logic/Equiv/Defs.lean
@@ -494,6 +494,23 @@ theorem eq_symm_comp {α β γ} (e : α ≃ β) (f : γ → α) (g : γ → β)
theorem symm_comp_eq {α β γ} (e : α ≃ β) (f : γ → α) (g : γ → β) : e.symm ∘ g = f ↔ g = e ∘ f :=
((Equiv.refl γ).arrowCongr e).symm_apply_eq
+theorem trans_eq_refl_iff_eq_symm {f : α ≃ β} {g : β ≃ α} :
+ f.trans g = Equiv.refl α ↔ f = g.symm := by
+ rw [← Equiv.coe_inj, coe_trans, coe_refl, ← eq_symm_comp, comp_id, Equiv.coe_inj]
+
+theorem trans_eq_refl_iff_symm_eq {f : α ≃ β} {g : β ≃ α} :
+ f.trans g = Equiv.refl α ↔ f.symm = g := by
+ rw [trans_eq_refl_iff_eq_symm]
+ exact ⟨fun h ↦ h ▸ rfl, fun h ↦ h ▸ rfl⟩
+
+theorem eq_symm_iff_trans_eq_refl {f : α ≃ β} {g : β ≃ α} :
+ f = g.symm ↔ f.trans g = Equiv.refl α :=
+ trans_eq_refl_iff_eq_symm.symm
+
+theorem symm_eq_iff_trans_eq_refl {f : α ≃ β} {g : β ≃ α} :
+ f.symm = g ↔ f.trans g = Equiv.refl α :=
+ trans_eq_refl_iff_symm_eq.symm
+
/-- `PUnit` sorts in any two universes are equivalent. -/
def punitEquivPUnit : PUnit.{v} ≃ PUnit.{w} :=
⟨fun _ => .unit, fun _ => .unit, fun ⟨⟩ => rfl, fun ⟨⟩ => rfl⟩
@@ -517,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]
@@ -574,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
@@ -597,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
@@ -699,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
@@ -713,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
@@ -827,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 1d07d2d1b2b25..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
@@ -470,7 +470,7 @@ def Int.divModEquiv (n : ℕ) [NeZero n] : ℤ ≃ ℤ × Fin n where
toFun a := (a / n, ↑(a.natMod n))
invFun p := p.1 * n + ↑p.2
left_inv a := by
- simp_rw [Fin.coe_ofNat_eq_mod, natCast_mod, natMod,
+ simp_rw [Fin.coe_natCast_eq_mod, natCast_mod, natMod,
toNat_of_nonneg (emod_nonneg _ <| natCast_eq_zero.not.2 (NeZero.ne n)), emod_emod,
ediv_add_emod']
right_inv := fun ⟨q, r, hrn⟩ => by
@@ -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/Functor.lean b/Mathlib/Logic/Equiv/Functor.lean
index e0f6ec21b8efa..203a282c37bf9 100644
--- a/Mathlib/Logic/Equiv/Functor.lean
+++ b/Mathlib/Logic/Equiv/Functor.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Simon Hudon, Scott Morrison
+Authors: Johan Commelin, Simon Hudon, Kim Morrison
-/
import Mathlib.Control.Bifunctor
import Mathlib.Logic.Equiv.Defs
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/Option.lean b/Mathlib/Logic/Equiv/Option.lean
index 65c8c77633e6a..9c0c3d02003ee 100644
--- a/Mathlib/Logic/Equiv/Option.lean
+++ b/Mathlib/Logic/Equiv/Option.lean
@@ -130,7 +130,7 @@ theorem some_removeNone_iff {x : α} : some (removeNone e x) = e none ↔ e.symm
· rw [removeNone_some _ ⟨a, h⟩]
have h1 := congr_arg e.symm h
rw [symm_apply_apply] at h1
- simp only [false_iff_iff, apply_eq_iff_eq, reduceCtorEq]
+ simp only [apply_eq_iff_eq, reduceCtorEq]
simp [h1, apply_eq_iff_eq]
@[simp]
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 4c39c97683377..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]
@@ -677,11 +677,13 @@ namespace Finite
attribute [-instance] Fin.instMul
-/-- Any finite group in universe `u` is equivalent to some finite group in universe `0`. -/
-lemma exists_type_zero_nonempty_mulEquiv (G : Type u) [Group G] [Finite G] :
- ∃ (G' : Type) (_ : Group G') (_ : Fintype G'), Nonempty (G ≃* G') := by
+/-- Any finite group in universe `u` is equivalent to some finite group in universe `v`. -/
+lemma exists_type_univ_nonempty_mulEquiv (G : Type u) [Group G] [Finite G] :
+ ∃ (G' : Type v) (_ : Group G') (_ : Fintype G'), Nonempty (G ≃* G') := by
obtain ⟨n, ⟨e⟩⟩ := Finite.exists_equiv_fin G
- letI groupH : Group (Fin n) := Equiv.group e.symm
- exact ⟨Fin n, inferInstance, inferInstance, ⟨MulEquiv.symm <| Equiv.mulEquiv e.symm⟩⟩
+ let f : Fin n ≃ ULift (Fin n) := Equiv.ulift.symm
+ let e : G ≃ ULift (Fin n) := e.trans f
+ letI groupH : Group (ULift (Fin n)) := e.symm.group
+ exact ⟨ULift (Fin n), groupH, inferInstance, ⟨MulEquiv.symm <| e.symm.mulEquiv⟩⟩
end Finite
diff --git a/Mathlib/Logic/ExistsUnique.lean b/Mathlib/Logic/ExistsUnique.lean
new file mode 100644
index 0000000000000..c41ef54d3dac5
--- /dev/null
+++ b/Mathlib/Logic/ExistsUnique.lean
@@ -0,0 +1,140 @@
+/-
+Copyright (c) 2014 Microsoft Corporation. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Leonardo de Moura, Jeremy Avigad, Floris van Doorn
+-/
+import Mathlib.Tactic.TypeStar
+
+/-!
+# `ExistsUnique`
+
+This file defines the `ExistsUnique` predicate, notated as `∃!`, and proves some of its
+basic properties.
+-/
+
+variable {α : Sort*}
+
+/-- For `p : α → Prop`, `ExistsUnique p` means that there exists a unique `x : α` with `p x`. -/
+def ExistsUnique (p : α → Prop) := ∃ x, p x ∧ ∀ y, p y → y = x
+
+namespace Mathlib.Notation
+open Lean
+
+/-- Checks to see that `xs` has only one binder. -/
+def isExplicitBinderSingular (xs : TSyntax ``explicitBinders) : Bool :=
+ match xs with
+ | `(explicitBinders| $_:binderIdent $[: $_]?) => true
+ | `(explicitBinders| ($_:binderIdent : $_)) => true
+ | _ => false
+
+open TSyntax.Compat in
+/--
+`∃! x : α, p x` means that there exists a unique `x` in `α` such that `p x`.
+This is notation for `ExistsUnique (fun (x : α) ↦ p x)`.
+
+This notation does not allow multiple binders like `∃! (x : α) (y : β), p x y`
+as a shorthand for `∃! (x : α), ∃! (y : β), p x y` since it is liable to be misunderstood.
+Often, the intended meaning is instead `∃! q : α × β, p q.1 q.2`.
+-/
+macro "∃!" xs:explicitBinders ", " b:term : term => do
+ if !isExplicitBinderSingular xs then
+ Macro.throwErrorAt xs "\
+ The `ExistsUnique` notation should not be used with more than one binder.\n\
+ \n\
+ The reason for this is that `∃! (x : α), ∃! (y : β), p x y` has a completely different \
+ meaning from `∃! q : α × β, p q.1 q.2`. \
+ To prevent confusion, this notation requires that you be explicit \
+ and use one with the correct interpretation."
+ expandExplicitBinders ``ExistsUnique xs b
+
+/--
+Pretty-printing for `ExistsUnique`, following the same pattern as pretty printing for `Exists`.
+However, it does *not* merge binders.
+-/
+@[app_unexpander ExistsUnique] def unexpandExistsUnique : Lean.PrettyPrinter.Unexpander
+ | `($(_) fun $x:ident ↦ $b) => `(∃! $x:ident, $b)
+ | `($(_) fun ($x:ident : $t) ↦ $b) => `(∃! $x:ident : $t, $b)
+ | _ => throw ()
+
+/--
+`∃! x ∈ s, p x` means `∃! x, x ∈ s ∧ p x`, which is to say that there exists a unique `x ∈ s`
+such that `p x`.
+Similarly, notations such as `∃! x ≤ n, p n` are supported,
+using any relation defined using the `binder_predicate` command.
+-/
+syntax "∃! " binderIdent binderPred ", " term : term
+
+macro_rules
+ | `(∃! $x:ident $p:binderPred, $b) => `(∃! $x:ident, satisfies_binder_pred% $x $p ∧ $b)
+ | `(∃! _ $p:binderPred, $b) => `(∃! x, satisfies_binder_pred% x $p ∧ $b)
+
+end Mathlib.Notation
+
+-- @[intro] -- TODO
+theorem ExistsUnique.intro {p : α → Prop} (w : α)
+ (h₁ : p w) (h₂ : ∀ y, p y → y = w) : ∃! x, p x := ⟨w, h₁, h₂⟩
+
+theorem ExistsUnique.elim {p : α → Prop} {b : Prop}
+ (h₂ : ∃! x, p x) (h₁ : ∀ x, p x → (∀ y, p y → y = x) → b) : b :=
+ Exists.elim h₂ (fun w hw ↦ h₁ w (And.left hw) (And.right hw))
+
+theorem exists_unique_of_exists_of_unique {p : α → Prop}
+ (hex : ∃ x, p x) (hunique : ∀ y₁ y₂, p y₁ → p y₂ → y₁ = y₂) : ∃! x, p x :=
+ Exists.elim hex (fun x px ↦ ExistsUnique.intro x px (fun y (h : p y) ↦ hunique y x h px))
+
+theorem ExistsUnique.exists {p : α → Prop} : (∃! x, p x) → ∃ x, p x | ⟨x, h, _⟩ => ⟨x, h⟩
+
+theorem ExistsUnique.unique {p : α → Prop}
+ (h : ∃! x, p x) {y₁ y₂ : α} (py₁ : p y₁) (py₂ : p y₂) : y₁ = y₂ :=
+ let ⟨_, _, hy⟩ := h; (hy _ py₁).trans (hy _ py₂).symm
+
+-- TODO
+-- attribute [congr] forall_congr'
+-- attribute [congr] exists_congr'
+
+-- @[congr]
+theorem existsUnique_congr {p q : α → Prop} (h : ∀ a, p a ↔ q a) : (∃! a, p a) ↔ ∃! a, q a :=
+ exists_congr fun _ ↦ and_congr (h _) <| forall_congr' fun _ ↦ imp_congr_left (h _)
+
+@[simp] theorem exists_unique_iff_exists [Subsingleton α] {p : α → Prop} :
+ (∃! x, p x) ↔ ∃ x, p x :=
+ ⟨fun h ↦ h.exists, Exists.imp fun x hx ↦ ⟨hx, fun y _ ↦ Subsingleton.elim y x⟩⟩
+
+theorem exists_unique_const {b : Prop} (α : Sort*) [i : Nonempty α] [Subsingleton α] :
+ (∃! _ : α, b) ↔ b := by simp
+
+@[simp] theorem exists_unique_eq {a' : α} : ∃! a, a = a' := by
+ simp only [eq_comm, ExistsUnique, and_self, forall_eq', exists_eq']
+
+@[simp] theorem exists_unique_eq' {a' : α} : ∃! a, a' = a := by
+ simp only [ExistsUnique, and_self, forall_eq', exists_eq']
+
+theorem exists_unique_prop {p q : Prop} : (∃! _ : p, q) ↔ p ∧ q := by simp
+
+@[simp] theorem exists_unique_false : ¬∃! _ : α, False := fun ⟨_, h, _⟩ ↦ h
+
+theorem exists_unique_prop_of_true {p : Prop} {q : p → Prop} (h : p) : (∃! h' : p, q h') ↔ q h :=
+ @exists_unique_const (q h) p ⟨h⟩ _
+
+theorem ExistsUnique.elim₂ {p : α → Sort*} [∀ x, Subsingleton (p x)]
+ {q : ∀ (x) (_ : p x), Prop} {b : Prop} (h₂ : ∃! x, ∃! h : p x, q x h)
+ (h₁ : ∀ (x) (h : p x), q x h → (∀ (y) (hy : p y), q y hy → y = x) → b) : b := by
+ simp only [exists_unique_iff_exists] at h₂
+ apply h₂.elim
+ exact fun x ⟨hxp, hxq⟩ H ↦ h₁ x hxp hxq fun y hyp hyq ↦ H y ⟨hyp, hyq⟩
+
+theorem ExistsUnique.intro₂ {p : α → Sort*} [∀ x, Subsingleton (p x)]
+ {q : ∀ (x : α) (_ : p x), Prop} (w : α) (hp : p w) (hq : q w hp)
+ (H : ∀ (y) (hy : p y), q y hy → y = w) : ∃! x, ∃! hx : p x, q x hx := by
+ simp only [exists_unique_iff_exists]
+ exact ExistsUnique.intro w ⟨hp, hq⟩ fun y ⟨hyp, hyq⟩ ↦ H y hyp hyq
+
+theorem ExistsUnique.exists₂ {p : α → Sort*} {q : ∀ (x : α) (_ : p x), Prop}
+ (h : ∃! x, ∃! hx : p x, q x hx) : ∃ (x : _) (hx : p x), q x hx :=
+ h.exists.imp fun _ hx ↦ hx.exists
+
+theorem ExistsUnique.unique₂ {p : α → Sort*} [∀ x, Subsingleton (p x)]
+ {q : ∀ (x : α) (_ : p x), Prop} (h : ∃! x, ∃! hx : p x, q x hx) {y₁ y₂ : α}
+ (hpy₁ : p y₁) (hqy₁ : q y₁ hpy₁) (hpy₂ : p y₂) (hqy₂ : q y₂ hpy₂) : y₁ = y₂ := by
+ simp only [exists_unique_iff_exists] at h
+ exact h.unique ⟨hpy₁, hqy₁⟩ ⟨hpy₂, hqy₂⟩
diff --git a/Mathlib/Logic/Function/Basic.lean b/Mathlib/Logic/Function/Basic.lean
index 35aaecce63413..58b832fa43354 100644
--- a/Mathlib/Logic/Function/Basic.lean
+++ b/Mathlib/Logic/Function/Basic.lean
@@ -3,9 +3,9 @@ Copyright (c) 2016 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.Init.Algebra.Classes
import Mathlib.Data.Set.Defs
import Mathlib.Logic.Basic
+import Mathlib.Logic.ExistsUnique
import Mathlib.Logic.Nonempty
import Batteries.Tactic.Init
@@ -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 _ _
@@ -329,7 +339,7 @@ theorem LeftInverse.eq_rightInverse {f : α → β} {g₁ g₂ : β → α} (h
(h₂ : RightInverse g₂ f) : g₁ = g₂ :=
calc
g₁ = g₁ ∘ f ∘ g₂ := by rw [h₂.comp_eq_id, comp_id]
- _ = g₂ := by rw [← comp.assoc, h₁.comp_eq_id, id_comp]
+ _ = g₂ := by rw [← comp_assoc, h₁.comp_eq_id, id_comp]
attribute [local instance] Classical.propDecidable
@@ -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. -/
@@ -653,6 +675,10 @@ lemma FactorsThrough.extend_comp {g : α → γ} (e' : β → γ) (hf : FactorsT
extend f g e' ∘ f = g :=
funext fun a => hf.extend_apply e' a
+@[simp]
+lemma extend_const (f : α → β) (c : γ) : extend f (fun _ ↦ c) (fun _ ↦ c) = fun _ ↦ c :=
+ funext fun _ ↦ ite_id _
+
@[simp]
theorem extend_comp (hf : Injective f) (g : α → γ) (e' : β → γ) : extend f g e' ∘ f = g :=
funext fun a ↦ hf.extend_apply g e' a
@@ -668,7 +694,7 @@ theorem Injective.surjective_comp_right [Nonempty γ] (hf : Injective f) :
theorem Bijective.comp_right (hf : Bijective f) : Bijective fun g : β → γ ↦ g ∘ f :=
⟨hf.surjective.injective_comp_right, fun g ↦
⟨g ∘ surjInv hf.surjective,
- by simp only [comp.assoc g _ f, (leftInverse_surjInv hf).comp_eq_id, comp_id]⟩⟩
+ by simp only [comp_assoc g _ f, (leftInverse_surjInv hf).comp_eq_id, comp_id]⟩⟩
end Extend
@@ -818,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 : _)
@@ -872,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`)
@@ -932,7 +958,7 @@ theorem Function.LeftInverse.eq_rec_eq {γ : β → Sort v} {f : α → β} {g :
(h : Function.LeftInverse g f) (C : ∀ a : α, γ (f a)) (a : α) :
-- TODO: mathlib3 uses `(congr_arg f (h a)).rec (C (g (f a)))` for LHS
@Eq.rec β (f (g (f a))) (fun x _ ↦ γ x) (C (g (f a))) (f a) (congr_arg f (h a)) = C a :=
- eq_of_heq <| (eq_rec_heq _ _).trans <| by rw [h]
+ eq_of_heq <| (eqRec_heq _ _).trans <| by rw [h]
theorem Function.LeftInverse.eq_rec_on_eq {γ : β → Sort v} {f : α → β} {g : β → α}
(h : Function.LeftInverse g f) (C : ∀ a : α, γ (f a)) (a : α) :
@@ -950,12 +976,9 @@ if for each pair of distinct points there is a function taking different values
def Set.SeparatesPoints {α β : Type*} (A : Set (α → β)) : Prop :=
∀ ⦃x y : α⦄, x ≠ y → ∃ f ∈ A, (f x : β) ≠ f y
-theorem IsSymmOp.flip_eq (op) [IsSymmOp α β op] : flip op = op :=
- funext fun a ↦ funext fun b ↦ (IsSymmOp.symm_op a b).symm
-
theorem InvImage.equivalence {α : Sort u} {β : Sort v} (r : β → β → Prop) (f : α → β)
(h : Equivalence r) : Equivalence (InvImage r f) :=
- ⟨fun _ ↦ h.1 _, fun w ↦ h.symm w, fun h₁ h₂ ↦ InvImage.trans r f (fun _ _ _ ↦ h.trans) h₁ h₂⟩
+ ⟨fun _ ↦ h.1 _, h.symm, h.trans⟩
instance {α β : Type*} {r : α → β → Prop} {x : α × β} [Decidable (r x.1 x.2)] :
Decidable (uncurry r x) :=
diff --git a/Mathlib/Logic/Function/CompTypeclasses.lean b/Mathlib/Logic/Function/CompTypeclasses.lean
index 7fcd8ca32286c..69d8ee1e0294f 100644
--- a/Mathlib/Logic/Function/CompTypeclasses.lean
+++ b/Mathlib/Logic/Function/CompTypeclasses.lean
@@ -24,7 +24,7 @@ TODO :
section CompTriple
/-- Class of composing triples -/
-class CompTriple {M N P : Type*} (φ : M → N) (ψ : N → P) (χ : outParam (M → P)) : Prop where
+class CompTriple {M N P : Type*} (φ : M → N) (ψ : N → P) (χ : outParam (M → P)) : Prop where
/-- The maps form a commuting triangle -/
comp_eq : ψ.comp φ = χ
diff --git a/Mathlib/Logic/Function/Conjugate.lean b/Mathlib/Logic/Function/Conjugate.lean
index 76dc5be2b2999..69098eb142cbf 100644
--- a/Mathlib/Logic/Function/Conjugate.lean
+++ b/Mathlib/Logic/Function/Conjugate.lean
@@ -31,7 +31,7 @@ def Semiconj (f : α → β) (ga : α → α) (gb : β → β) : Prop :=
namespace Semiconj
-variable {f fab : α → β} {fbc : β → γ} {ga ga' : α → α} {gb gb' : β → β} {gc gc' : γ → γ}
+variable {f fab : α → β} {fbc : β → γ} {ga ga' : α → α} {gb gb' : β → β} {gc : γ → γ}
/-- Definition of `Function.Semiconj` in terms of functional equality. -/
lemma _root_.Function.semiconj_iff_comp_eq : Semiconj f ga gb ↔ f ∘ ga = gb ∘ f := funext_iff.symm
diff --git a/Mathlib/Logic/Function/Defs.lean b/Mathlib/Logic/Function/Defs.lean
index 72aa534f806b9..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
@@ -88,8 +86,9 @@ theorem comp_id (f : α → β) : f ∘ id = f := rfl
@[deprecated (since := "2024-01-14")] alias right_id := comp_id
@[deprecated (since := "2024-01-14")] alias comp.right_id := comp_id
-theorem comp.assoc (f : φ → δ) (g : β → φ) (h : α → β) : (f ∘ g) ∘ h = f ∘ g ∘ h :=
+theorem comp_assoc (f : φ → δ) (g : β → φ) (h : α → β) : (f ∘ g) ∘ h = f ∘ g ∘ h :=
rfl
+@[deprecated (since := "2024-09-24")] alias comp.assoc := comp_assoc
@[deprecated (since := "2024-01-14")] alias comp_const_right := comp_const
@@ -202,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/Function/FiberPartition.lean b/Mathlib/Logic/Function/FiberPartition.lean
new file mode 100644
index 0000000000000..e1463b5d0e46b
--- /dev/null
+++ b/Mathlib/Logic/Function/FiberPartition.lean
@@ -0,0 +1,71 @@
+/-
+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.Data.Set.Basic
+/-!
+
+This file defines the type `f.Fiber` of fibers of a function `f : Y → Z`, and provides some API
+to work with and construct terms of this type.
+
+Note: this API is designed to be useful when defining the counit of the adjunction between
+the functor which takes a set to the condensed set corresponding to locally constant maps to that
+set, and the forgetful functor from the category of condensed sets to the category of sets
+(see PR #14027).
+-/
+
+variable {X Y Z : Type*}
+
+namespace Function
+
+/-- The indexing set of the partition. -/
+def Fiber (f : Y → Z) : Type _ := Set.range (fun (x : Set.range f) ↦ f ⁻¹' {x.val})
+
+namespace Fiber
+
+/--
+Any `a : Fiber f` is of the form `f ⁻¹' {x}` for some `x` in the image of `f`. We define `a.image`
+as an arbitrary such `x`.
+-/
+noncomputable def image (f : Y → Z) (a : Fiber f) : Z := a.2.choose.1
+
+lemma eq_fiber_image (f : Y → Z) (a : Fiber f) : a.1 = f ⁻¹' {a.image} := a.2.choose_spec.symm
+
+/--
+Given `y : Y`, `Fiber.mk f y` is the fiber of `f` that `y` belongs to, as an element of `Fiber f`.
+-/
+def mk (f : Y → Z) (y : Y) : Fiber f := ⟨f ⁻¹' {f y}, by simp⟩
+
+/-- `y : Y` as a term of the type `Fiber.mk f y` -/
+def mkSelf (f : Y → Z) (y : Y) : (mk f y).val := ⟨y, rfl⟩
+
+lemma map_eq_image (f : Y → Z) (a : Fiber f) (x : a.1) : f x = a.image := by
+ have := a.2.choose_spec
+ rw [← Set.mem_singleton_iff, ← Set.mem_preimage]
+ convert x.prop
+
+lemma mk_image (f : Y → Z) (y : Y) : (Fiber.mk f y).image = f y :=
+ (map_eq_image (x := mkSelf f y)).symm
+
+lemma mem_iff_eq_image (f : Y → Z) (y : Y) (a : Fiber f) : y ∈ a.val ↔ f y = a.image :=
+ ⟨fun h ↦ a.map_eq_image _ ⟨y, h⟩, fun h ↦ by rw [a.eq_fiber_image]; exact h⟩
+
+/-- An arbitrary element of `a : Fiber f`. -/
+noncomputable def preimage (f : Y → Z) (a : Fiber f) : Y := a.2.choose.2.choose
+
+lemma map_preimage_eq_image (f : Y → Z) (a : Fiber f) : f a.preimage = a.image :=
+ a.2.choose.2.choose_spec
+
+lemma fiber_nonempty (f : Y → Z) (a : Fiber f) : Set.Nonempty a.val := by
+ refine ⟨preimage f a, ?_⟩
+ rw [mem_iff_eq_image, ← map_preimage_eq_image]
+
+lemma map_preimage_eq_image_map {W : Type*} (f : Y → Z) (g : Z → W) (a : Fiber (g ∘ f)) :
+ g (f a.preimage) = a.image := by rw [← map_preimage_eq_image, comp_apply]
+
+lemma image_eq_image_mk (f : Y → Z) (g : X → Y) (a : Fiber (f ∘ g)) :
+ a.image = (Fiber.mk f (g (a.preimage _))).image := by
+ rw [← map_preimage_eq_image_map _ _ a, mk_image]
+
+end Function.Fiber
diff --git a/Mathlib/Logic/Godel/GodelBetaFunction.lean b/Mathlib/Logic/Godel/GodelBetaFunction.lean
index 4fe1e162e2c5a..52ef094f4d92b 100644
--- a/Mathlib/Logic/Godel/GodelBetaFunction.lean
+++ b/Mathlib/Logic/Godel/GodelBetaFunction.lean
@@ -76,8 +76,7 @@ private lemma pairwise_coprime_coprimes (a : Fin m → ℕ) : Pairwise (Coprime
have hja : j < supOfSeq a := lt_of_lt_of_le j.prop (le_step (le_max_left _ _))
exact coprime_mul_succ
(Nat.succ_le_succ <| le_of_lt ltij)
- (Nat.dvd_factorial
- (by simp [Nat.succ_sub_succ, ltij])
+ (Nat.dvd_factorial (by omega)
(by simpa only [Nat.succ_sub_succ] using le_of_lt (lt_of_le_of_lt (sub_le j i) hja)))
/-- Gödel's Beta Function. This is similar to `(Encodable.decodeList).get i`, but it is easier to
diff --git a/Mathlib/Logic/Lemmas.lean b/Mathlib/Logic/Lemmas.lean
index 1056a7ffc156f..3e92a9dc21060 100644
--- a/Mathlib/Logic/Lemmas.lean
+++ b/Mathlib/Logic/Lemmas.lean
@@ -24,7 +24,7 @@ theorem iff_right_comm {a b c : Prop} : ((a ↔ b) ↔ c) ↔ ((a ↔ c) ↔ b)
protected alias ⟨HEq.eq, Eq.heq⟩ := heq_iff_eq
-variable {α : Sort*} {p q r : Prop} [Decidable p] [Decidable q] {a b c : α}
+variable {α : Sort*} {p q : Prop} [Decidable p] [Decidable q] {a b c : α}
theorem dite_dite_distrib_left {a : p → α} {b : ¬p → q → α} {c : ¬p → ¬q → α} :
(dite p a fun hp ↦ dite q (b hp) (c hp)) =
diff --git a/Mathlib/Logic/Nonempty.lean b/Mathlib/Logic/Nonempty.lean
index 1a52ca02ab2d4..1c8198b9475d3 100644
--- a/Mathlib/Logic/Nonempty.lean
+++ b/Mathlib/Logic/Nonempty.lean
@@ -99,13 +99,6 @@ theorem Nonempty.elim_to_inhabited {α : Sort*} [h : Nonempty α] {p : Prop} (f
p :=
h.elim <| f ∘ Inhabited.mk
-protected instance Prod.instNonempty {α β} [h : Nonempty α] [h2 : Nonempty β] : Nonempty (α × β) :=
- h.elim fun g ↦ h2.elim fun g2 ↦ ⟨⟨g, g2⟩⟩
-
-protected instance Pi.instNonempty {ι : Sort*} {α : ι → Sort*} [∀ i, Nonempty (α i)] :
- Nonempty (∀ i, α i) :=
- ⟨fun _ ↦ Classical.arbitrary _⟩
-
theorem Classical.nonempty_pi {ι} {α : ι → Sort*} : Nonempty (∀ i, α i) ↔ ∀ i, Nonempty (α i) :=
⟨fun ⟨f⟩ a ↦ ⟨f a⟩, @Pi.instNonempty _ _⟩
diff --git a/Mathlib/Logic/Nontrivial/Defs.lean b/Mathlib/Logic/Nontrivial/Defs.lean
index 51b62d4be17b3..e0ac42a17d027 100644
--- a/Mathlib/Logic/Nontrivial/Defs.lean
+++ b/Mathlib/Logic/Nontrivial/Defs.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.Init.Logic
import Mathlib.Logic.Function.Defs
import Mathlib.Tactic.TypeStar
diff --git a/Mathlib/Logic/OpClass.lean b/Mathlib/Logic/OpClass.lean
new file mode 100644
index 0000000000000..6427c0f587784
--- /dev/null
+++ b/Mathlib/Logic/OpClass.lean
@@ -0,0 +1,62 @@
+/-
+Copyright (c) 2014 Microsoft Corporation. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Leonardo de Moura
+-/
+
+import Mathlib.Init
+
+/-!
+# Typeclasses for commuting heterogeneous operations
+
+The three classes in this file are for two-argument functions where one input is of type `α`,
+the output is of type `β` and the other input is of type `α` or `β`.
+They express the property that permuting arguments of type `α` does not change the result.
+
+## Main definitions
+
+* `IsSymmOp`: for `op : α → α → β`, `op a b = op b a`.
+* `LeftCommutative`: for `op : α → β → β`, `op a₁ (op a₂ b) = op a₂ (op a₁ b)`.
+* `RightCommutative`: for `op : β → α → β`, `op (op b a₁) a₂ = op (op b a₂) a₁`.
+-/
+
+universe u v
+
+variable {α : Sort u} {β : Sort v}
+
+/-- `IsSymmOp op` where `op : α → α → β` says that `op` is a symmetric operation,
+i.e. `op a b = op b a`.
+It is the natural generalisation of `Std.Commutative` (`β = α`) and `IsSymm` (`β = Prop`). -/
+class IsSymmOp (op : α → α → β) : Prop where
+ /-- A symmetric operation satisfies `op a b = op b a`. -/
+ symm_op : ∀ a b, op a b = op b a
+
+/-- `LeftCommutative op` where `op : α → β → β` says that `op` is a left-commutative operation,
+i.e. `op a₁ (op a₂ b) = op a₂ (op a₁ b)`. -/
+class LeftCommutative (op : α → β → β) : Prop where
+ /-- A left-commutative operation satisfies `op a₁ (op a₂ b) = op a₂ (op a₁ b)`. -/
+ left_comm : (a₁ a₂ : α) → (b : β) → op a₁ (op a₂ b) = op a₂ (op a₁ b)
+
+/-- `RightCommutative op` where `op : β → α → β` says that `op` is a right-commutative operation,
+i.e. `op (op b a₁) a₂ = op (op b a₂) a₁`. -/
+class RightCommutative (op : β → α → β) : Prop where
+ /-- A right-commutative operation satisfies `op (op b a₁) a₂ = op (op b a₂) a₁`. -/
+ right_comm : (b : β) → (a₁ a₂ : α) → op (op b a₁) a₂ = op (op b a₂) a₁
+
+instance (priority := 100) isSymmOp_of_isCommutative (α : Sort u) (op : α → α → α)
+ [Std.Commutative op] : IsSymmOp op where symm_op := Std.Commutative.comm
+
+theorem IsSymmOp.flip_eq (op : α → α → β) [IsSymmOp op] : flip op = op :=
+ funext fun a ↦ funext fun b ↦ (IsSymmOp.symm_op a b).symm
+
+instance {f : α → β → β} [h : LeftCommutative f] : RightCommutative (fun x y ↦ f y x) :=
+ ⟨fun _ _ _ ↦ (h.left_comm _ _ _).symm⟩
+
+instance {f : β → α → β} [h : RightCommutative f] : LeftCommutative (fun x y ↦ f y x) :=
+ ⟨fun _ _ _ ↦ (h.right_comm _ _ _).symm⟩
+
+instance {f : α → α → α} [hc : Std.Commutative f] [ha : Std.Associative f] : LeftCommutative f :=
+ ⟨fun a b c ↦ by rw [← ha.assoc, hc.comm a, ha.assoc]⟩
+
+instance {f : α → α → α} [hc : Std.Commutative f] [ha : Std.Associative f] : RightCommutative f :=
+ ⟨fun a b c ↦ by rw [ha.assoc, hc.comm b, ha.assoc]⟩
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 1140370051471..93afac58af709 100644
--- a/Mathlib/Logic/Relation.lean
+++ b/Mathlib/Logic/Relation.lean
@@ -100,7 +100,7 @@ theorem Transitive.comap (h : Transitive r) (f : α → β) : Transitive (r on f
fun _ _ _ hab hbc ↦ h hab hbc
theorem Equivalence.comap (h : Equivalence r) (f : α → β) : Equivalence (r on f) :=
- ⟨h.reflexive.comap f, @(h.symmetric.comap f), @(h.transitive.comap f)⟩
+ ⟨fun a ↦ h.refl (f a), h.symm, h.trans⟩
end Comap
@@ -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/Relator.lean b/Mathlib/Logic/Relator.lean
index 7e0f0e054c1ac..17ab1660850b2 100644
--- a/Mathlib/Logic/Relator.lean
+++ b/Mathlib/Logic/Relator.lean
@@ -96,8 +96,8 @@ lemma rel_not : (Iff ⇒ Iff) Not Not :=
lemma bi_total_eq {α : Type u₁} : Relator.BiTotal (@Eq α) :=
{ left := fun a => ⟨a, rfl⟩, right := fun a => ⟨a, rfl⟩ }
-variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*}
-variable {r : α → β → Prop} {p : β → γ → Prop} {q : γ → δ → Prop}
+variable {α : Type*} {β : Type*} {γ : Type*}
+variable {r : α → β → Prop}
lemma LeftUnique.flip (h : LeftUnique r) : RightUnique (flip r) :=
fun _ _ _ h₁ h₂ => h h₁ h₂
@@ -116,7 +116,7 @@ lemma rel_eq {r : α → β → Prop} (hr : BiUnique r) : (r ⇒ r ⇒ (·↔·)
open Function
-variable {α : Type*} {r₁₁ : α → α → Prop} {r₁₂ : α → β → Prop} {r₂₁ : β → α → Prop}
+variable {r₁₁ : α → α → Prop} {r₁₂ : α → β → Prop} {r₂₁ : β → α → Prop}
{r₂₃ : β → γ → Prop} {r₁₃ : α → γ → Prop}
namespace LeftTotal
diff --git a/Mathlib/Logic/Small/Basic.lean b/Mathlib/Logic/Small/Basic.lean
index 902d79ca3fdf2..7024044988faa 100644
--- a/Mathlib/Logic/Small/Basic.lean
+++ b/Mathlib/Logic/Small/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.Small.Defs
import Mathlib.Logic.Equiv.Set
@@ -16,6 +16,10 @@ universe u w v v'
section
+
+-- TODO(timotree3): lower the priority on this instance?
+-- This instance applies to every synthesis problem of the form `Small ↥s` for some set `s`,
+-- but we have lots of instances of `Small` for specific set constructions.
instance small_subtype (α : Type v) [Small.{w} α] (P : α → Prop) : Small.{w} { x // P x } :=
small_map (equivShrink α).subtypeEquivOfSubtype'
diff --git a/Mathlib/Logic/Small/Defs.lean b/Mathlib/Logic/Small/Defs.lean
index c93c2ba60d7d1..51d7142ca561b 100644
--- a/Mathlib/Logic/Small/Defs.lean
+++ b/Mathlib/Logic/Small/Defs.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.Equiv.Defs
import Mathlib.Tactic.MkIffOfInductiveProp
diff --git a/Mathlib/Logic/Small/Group.lean b/Mathlib/Logic/Small/Group.lean
index 3ec5b0486b284..4242a307e776b 100644
--- a/Mathlib/Logic/Small/Group.lean
+++ b/Mathlib/Logic/Small/Group.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.Small.Defs
import Mathlib.Logic.Equiv.TransferInstance
diff --git a/Mathlib/Logic/Small/List.lean b/Mathlib/Logic/Small/List.lean
index ef015f7089a1f..13b6fd0b0469a 100644
--- a/Mathlib/Logic/Small/List.lean
+++ b/Mathlib/Logic/Small/List.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.Small.Basic
import Mathlib.Data.Vector.Basic
diff --git a/Mathlib/Logic/Small/Module.lean b/Mathlib/Logic/Small/Module.lean
index 4280027faf576..8dd1444204daa 100644
--- a/Mathlib/Logic/Small/Module.lean
+++ b/Mathlib/Logic/Small/Module.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.Small.Group
import Mathlib.Logic.Small.Ring
diff --git a/Mathlib/Logic/Small/Ring.lean b/Mathlib/Logic/Small/Ring.lean
index 2c55cfd01e1c5..d64f33557a2c1 100644
--- a/Mathlib/Logic/Small/Ring.lean
+++ b/Mathlib/Logic/Small/Ring.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.Small.Defs
import Mathlib.Logic.Equiv.TransferInstance
diff --git a/Mathlib/Logic/Small/Set.lean b/Mathlib/Logic/Small/Set.lean
index deae0a2f8ca8c..069f25c85eaa0 100644
--- a/Mathlib/Logic/Small/Set.lean
+++ b/Mathlib/Logic/Small/Set.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2024 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Markus Himmel
+Authors: Markus Himmel, Timothy Carlin-Burns
-/
import Mathlib.Data.Set.Lattice
import Mathlib.Logic.Small.Basic
@@ -10,29 +10,111 @@ import Mathlib.Logic.Small.Basic
# Results about `Small` on coerced sets
-/
-universe u v w
+universe u u1 u2 u3 u4
-theorem small_subset {α : Type v} {s t : Set α} (hts : t ⊆ s) [Small.{u} s] : Small.{u} t :=
- let f : t → s := fun x => ⟨x, hts x.prop⟩
- @small_of_injective _ _ _ f fun _ _ hxy => Subtype.ext (Subtype.mk.inj hxy)
+variable {α : Type u1} {β : Type u2} {γ : Type u3} {ι : Type u4}
-instance small_range {α : Type v} {β : Type w} (f : α → β) [Small.{u} α] :
+theorem small_subset {s t : Set α} (hts : t ⊆ s) [Small.{u} s] : Small.{u} t :=
+ small_of_injective (Set.inclusion_injective hts)
+
+instance small_powerset (s : Set α) [Small.{u} s] : Small.{u} (𝒫 s) :=
+ small_map (Equiv.Set.powerset s)
+
+instance small_setProd (s : Set α) (t : Set β) [Small.{u} s] [Small.{u} t] :
+ Small.{u} (s ×ˢ t : Set (α × β)) :=
+ small_of_injective (Equiv.Set.prod s t).injective
+
+instance small_setPi {β : α → Type u2} (s : (a : α) → Set (β a))
+ [Small.{u} α] [∀ a, Small.{u} (s a)] : Small.{u} (Set.pi Set.univ s) :=
+ small_of_injective (Equiv.Set.univPi s).injective
+
+instance small_range (f : α → β) [Small.{u} α] :
Small.{u} (Set.range f) :=
small_of_surjective Set.surjective_onto_range
-instance small_image {α : Type v} {β : Type w} (f : α → β) (S : Set α) [Small.{u} S] :
- Small.{u} (f '' S) :=
+instance small_image (f : α → β) (s : Set α) [Small.{u} s] :
+ Small.{u} (f '' s) :=
small_of_surjective Set.surjective_onto_image
-instance small_union {α : Type v} (s t : Set α) [Small.{u} s] [Small.{u} t] :
+instance small_image2 (f : α → β → γ) (s : Set α) (t : Set β) [Small.{u} s] [Small.{u} t] :
+ Small.{u} (Set.image2 f s t) := by
+ rw [← Set.image_uncurry_prod]
+ infer_instance
+
+theorem small_univ_iff : Small.{u} (@Set.univ α) ↔ Small.{u} α :=
+ small_congr <| Equiv.Set.univ α
+
+instance small_univ [h : Small.{u} α] : Small.{u} (@Set.univ α) :=
+ small_univ_iff.2 h
+
+instance small_union (s t : Set α) [Small.{u} s] [Small.{u} t] :
Small.{u} (s ∪ t : Set α) := by
rw [← Subtype.range_val (s := s), ← Subtype.range_val (s := t), ← Set.Sum.elim_range]
infer_instance
-instance small_iUnion {α : Type v} {ι : Type w} [Small.{u} ι] (s : ι → Set α)
+instance small_iUnion [Small.{u} ι] (s : ι → Set α)
[∀ i, Small.{u} (s i)] : Small.{u} (⋃ i, s i) :=
small_of_surjective <| Set.sigmaToiUnion_surjective _
-instance small_sUnion {α : Type v} (s : Set (Set α)) [Small.{u} s] [∀ t : s, Small.{u} t] :
+instance small_sUnion (s : Set (Set α)) [Small.{u} s] [∀ t : s, Small.{u} t] :
Small.{u} (⋃₀ s) :=
Set.sUnion_eq_iUnion ▸ small_iUnion _
+
+instance small_biUnion (s : Set ι) [Small.{u} s]
+ (f : (i : ι) → i ∈ s → Set α) [∀ i hi, Small.{u} (f i hi)] : Small.{u} (⋃ i, ⋃ hi, f i hi) :=
+ Set.biUnion_eq_iUnion s f ▸ small_iUnion _
+
+instance small_insert (x : α) (s : Set α) [Small.{u} s] :
+ Small.{u} (insert x s : Set α) :=
+ Set.insert_eq x s ▸ small_union.{u} {x} s
+
+instance small_diff (s t : Set α) [Small.{u} s] : Small.{u} (s \ t : Set α) :=
+ small_subset (Set.diff_subset)
+
+instance small_sep (s : Set α) (P : α → Prop) [Small.{u} s] :
+ Small.{u} { x | x ∈ s ∧ P x} :=
+ small_subset (Set.sep_subset s P)
+
+instance small_inter_of_left (s t : Set α) [Small.{u} s] :
+ Small.{u} (s ∩ t : Set α) :=
+ small_subset Set.inter_subset_left
+
+instance small_inter_of_right (s t : Set α) [Small.{u} t] :
+ Small.{u} (s ∩ t : Set α) :=
+ small_subset Set.inter_subset_right
+
+theorem small_iInter (s : ι → Set α) (i : ι)
+ [Small.{u} (s i)] : Small.{u} (⋂ i, s i) :=
+ small_subset (Set.iInter_subset s i)
+
+instance small_iInter' [Nonempty ι] (s : ι → Set α)
+ [∀ i, Small.{u} (s i)] : Small.{u} (⋂ i, s i) :=
+ let ⟨i⟩ : Nonempty ι := inferInstance
+ small_iInter s i
+
+theorem small_sInter {s : Set (Set α)} {t : Set α} (ht : t ∈ s)
+ [Small.{u} t] : Small.{u} (⋂₀ s) :=
+ Set.sInter_eq_iInter ▸ small_iInter _ ⟨t, ht⟩
+
+instance small_sInter' {s : Set (Set α)} [Nonempty s]
+ [∀ t : s, Small.{u} t] : Small.{u} (⋂₀ s) :=
+ let ⟨t⟩ : Nonempty s := inferInstance
+ small_sInter t.prop
+
+theorem small_biInter {s : Set ι} {i : ι} (hi : i ∈ s)
+ (f : (i : ι) → i ∈ s → Set α) [Small.{u} (f i hi)] : Small.{u} (⋂ i, ⋂ hi, f i hi) :=
+ Set.biInter_eq_iInter s f ▸ small_iInter _ ⟨i, hi⟩
+
+instance small_biInter' (s : Set ι) [Nonempty s]
+ (f : (i : ι) → i ∈ s → Set α) [∀ i hi, Small.{u} (f i hi)] : Small.{u} (⋂ i, ⋂ hi, f i hi) :=
+ let ⟨t⟩ : Nonempty s := inferInstance
+ small_biInter t.prop f
+
+theorem small_empty : Small.{u} (∅ : Set α) :=
+ inferInstance
+
+theorem small_single (x : α) : Small.{u} ({x} : Set α) :=
+ inferInstance
+
+theorem small_pair (x y : α) : Small.{u} ({x, y} : Set α) :=
+ inferInstance
diff --git a/Mathlib/Logic/Unique.lean b/Mathlib/Logic/Unique.lean
index 8588f1676e164..5aad9af23a014 100644
--- a/Mathlib/Logic/Unique.lean
+++ b/Mathlib/Logic/Unique.lean
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin
-/
import Mathlib.Logic.IsEmpty
-import Mathlib.Init.Logic
import Mathlib.Tactic.Inhabit
/-!
@@ -142,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*}
@@ -248,7 +251,6 @@ instance {α} [IsEmpty α] : Unique (Option α) :=
end Option
section Subtype
-variable {α : Sort u}
instance Unique.subtypeEq (y : α) : Unique { x // x = y } where
default := ⟨y, rfl⟩
diff --git a/Mathlib/Logic/UnivLE.lean b/Mathlib/Logic/UnivLE.lean
index aad869948aea4..d9f43bcd66b60 100644
--- a/Mathlib/Logic/UnivLE.lean
+++ b/Mathlib/Logic/UnivLE.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Logic.Small.Defs
@@ -14,7 +14,7 @@ in the form `∀ α : Type u, Small.{v} α`.
See the doc-string for the comparison with an alternative stronger definition.
-/
-set_option autoImplicit true
+universe u v w
noncomputable section
@@ -35,7 +35,7 @@ See also `Mathlib.CategoryTheory.UnivLE` for the statement that the stronger def
equivalent to `EssSurj (uliftFunctor : Type v ⥤ Type max u v)`.
-/
@[pp_with_univ]
-abbrev UnivLE.{u, v} : Prop := ∀ α : Type u, Small.{v} α
+abbrev UnivLE : Prop := ∀ α : Type u, Small.{v} α
example : UnivLE.{u, u} := inferInstance
example : UnivLE.{u, u+1} := inferInstance
@@ -43,7 +43,7 @@ example : UnivLE.{0, u} := inferInstance
/- This is useless as an instance due to https://github.com/leanprover/lean4/issues/2297 -/
theorem univLE_max : UnivLE.{u, max u v} := fun α ↦ small_max.{v} α
-theorem Small.trans_univLE.{u, v} (α : Type w) [hα : Small.{u} α] [h : UnivLE.{u, v}] :
+theorem Small.trans_univLE (α : Type w) [hα : Small.{u} α] [h : UnivLE.{u, v}] :
Small.{v} α :=
let ⟨β, ⟨f⟩⟩ := hα.equiv_small
let ⟨_, ⟨g⟩⟩ := (h β).equiv_small
@@ -53,7 +53,7 @@ theorem UnivLE.trans [UnivLE.{u, v}] [UnivLE.{v, w}] : UnivLE.{u, w} :=
fun α ↦ Small.trans_univLE α
/- This is the crucial instance that subsumes `univLE_max`. -/
-instance univLE_of_max [UnivLE.{max u v, v}] : UnivLE.{u, v} := @UnivLE.trans univLE_max.{v,u} ‹_›
+instance univLE_of_max [UnivLE.{max u v, v}] : UnivLE.{u, v} := @UnivLE.trans univLE_max ‹_›
/- When `small_Pi` from `Mathlib.Logic.Small.Basic` is imported, we have : -/
-- example (α : Type u) (β : Type v) [UnivLE.{u, v}] : Small.{v} (α → β) := inferInstance
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 4c6af21ff5643..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)]
@@ -502,9 +505,8 @@ instance (priority := 100) ContinuousSub.measurableSub [Sub γ] [ContinuousSub
measurable_sub_const _ := (continuous_id.sub continuous_const).measurable
@[to_additive]
-instance (priority := 100) TopologicalGroup.measurableInv [Group γ] [TopologicalGroup γ] :
- MeasurableInv γ :=
- ⟨continuous_inv.measurable⟩
+instance (priority := 100) ContinuousInv.measurableInv [Inv γ] [ContinuousInv γ] :
+ MeasurableInv γ := ⟨continuous_inv.measurable⟩
@[to_additive]
instance (priority := 100) ContinuousSMul.measurableSMul {M α} [TopologicalSpace M]
@@ -614,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 42987950d650c..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,25 +94,34 @@ end OrderTopology
section Orders
-variable [TopologicalSpace α] [MeasurableSpace α] [OpensMeasurableSpace α]
-variable [MeasurableSpace δ]
+variable [TopologicalSpace α] {mα : MeasurableSpace α} [OpensMeasurableSpace α]
+variable {mδ : MeasurableSpace δ}
section Preorder
-variable [Preorder α] [OrderClosedTopology α] {a b x : α}
+variable [Preorder α] [OrderClosedTopology α] {a b x : α} {μ : Measure α}
@[simp, measurability]
theorem measurableSet_Ici : MeasurableSet (Ici a) :=
isClosed_Ici.measurableSet
+theorem nullMeasurableSet_Ici : NullMeasurableSet (Ici a) μ :=
+ measurableSet_Ici.nullMeasurableSet
+
@[simp, measurability]
theorem measurableSet_Iic : MeasurableSet (Iic a) :=
isClosed_Iic.measurableSet
+theorem nullMeasurableSet_Iic : NullMeasurableSet (Iic a) μ :=
+ measurableSet_Iic.nullMeasurableSet
+
@[simp, measurability]
theorem measurableSet_Icc : MeasurableSet (Icc a b) :=
isClosed_Icc.measurableSet
+theorem nullMeasurableSet_Icc : NullMeasurableSet (Icc a b) μ :=
+ measurableSet_Icc.nullMeasurableSet
+
instance nhdsWithin_Ici_isMeasurablyGenerated : (𝓝[Ici b] a).IsMeasurablyGenerated :=
measurableSet_Ici.nhdsWithin_isMeasurablyGenerated _
@@ -157,7 +166,7 @@ end PartialOrder
section LinearOrder
-variable [LinearOrder α] [OrderClosedTopology α] {a b x : α}
+variable [LinearOrder α] [OrderClosedTopology α] {a b x : α} {μ : Measure α}
-- we open this locale only here to avoid issues with list being treated as intervals above
open Interval
@@ -166,22 +175,37 @@ open Interval
theorem measurableSet_Iio : MeasurableSet (Iio a) :=
isOpen_Iio.measurableSet
+theorem nullMeasurableSet_Iio : NullMeasurableSet (Iio a) μ :=
+ measurableSet_Iio.nullMeasurableSet
+
@[simp, measurability]
theorem measurableSet_Ioi : MeasurableSet (Ioi a) :=
isOpen_Ioi.measurableSet
+theorem nullMeasurableSet_Ioi : NullMeasurableSet (Ioi a) μ :=
+ measurableSet_Ioi.nullMeasurableSet
+
@[simp, measurability]
theorem measurableSet_Ioo : MeasurableSet (Ioo a b) :=
isOpen_Ioo.measurableSet
+theorem nullMeasurableSet_Ioo : NullMeasurableSet (Ioo a b) μ :=
+ measurableSet_Ioo.nullMeasurableSet
+
@[simp, measurability]
theorem measurableSet_Ioc : MeasurableSet (Ioc a b) :=
measurableSet_Ioi.inter measurableSet_Iic
+theorem nullMeasurableSet_Ioc : NullMeasurableSet (Ioc a b) μ :=
+ measurableSet_Ioc.nullMeasurableSet
+
@[simp, measurability]
theorem measurableSet_Ico : MeasurableSet (Ico a b) :=
measurableSet_Ici.inter measurableSet_Iio
+theorem nullMeasurableSet_Ico : NullMeasurableSet (Ico a b) μ :=
+ measurableSet_Ico.nullMeasurableSet
+
instance nhdsWithin_Ioi_isMeasurablyGenerated : (𝓝[Ioi b] a).IsMeasurablyGenerated :=
measurableSet_Ioi.nhdsWithin_isMeasurablyGenerated _
@@ -275,13 +299,13 @@ 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 α]
[LinearOrder α] [OrderTopology α] :
borel α = .generateFrom { S : Set α | ∃ (l u : α), l < u ∧ Ico l u = S } := by
- simpa only [exists_prop, mem_univ, true_and_iff] using
+ simpa only [exists_prop, mem_univ, true_and] using
(@dense_univ α _).borel_eq_generateFrom_Ico_mem_aux (fun _ _ => mem_univ _) fun _ _ _ _ =>
mem_univ _
@@ -301,13 +325,13 @@ 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 α]
[LinearOrder α] [OrderTopology α] :
borel α = .generateFrom { S : Set α | ∃ l u, l < u ∧ Ioc l u = S } := by
- simpa only [exists_prop, mem_univ, true_and_iff] using
+ simpa only [exists_prop, mem_univ, true_and] using
(@dense_univ α _).borel_eq_generateFrom_Ioc_mem_aux (fun _ _ => mem_univ _) fun _ _ _ _ =>
mem_univ _
@@ -398,15 +422,15 @@ theorem ext_of_Iic {α : Type*} [TopologicalSpace α] {m : MeasurableSpace α}
· rcases exists_countable_dense_bot_top α with ⟨s, hsc, hsd, -, hst⟩
have : DirectedOn (· ≤ ·) s := directedOn_iff_directed.2 (Subtype.mono_coe _).directed_le
simp only [← biSup_measure_Iic hsc (hsd.exists_ge' hst) this, h]
- rw [← Iic_diff_Iic, measure_diff (Iic_subset_Iic.2 hlt.le) measurableSet_Iic.nullMeasurableSet,
- measure_diff (Iic_subset_Iic.2 hlt.le) measurableSet_Iic.nullMeasurableSet, h a, h b]
+ rw [← Iic_diff_Iic, measure_diff (Iic_subset_Iic.2 hlt.le) nullMeasurableSet_Iic,
+ measure_diff (Iic_subset_Iic.2 hlt.le) nullMeasurableSet_Iic, h a, h b]
· rw [← h a]
- exact (measure_lt_top μ _).ne
- · exact (measure_lt_top μ _).ne
+ exact measure_ne_top μ _
+ · exact measure_ne_top μ _
/-- 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
@@ -449,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
@@ -475,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
@@ -544,7 +568,8 @@ theorem Measurable.isLUB_of_mem {ι} [Countable ι] {f : ι → δ → α} {g g'
· simp [hb, hg' hb]
rw [this]
exact Measurable.piecewise hs measurable_const g'_meas
- · let f' : ι → δ → α := fun i ↦ s.piecewise (f i) g'
+ · have : Nonempty ι := ⟨i⟩
+ let f' : ι → δ → α := fun i ↦ s.piecewise (f i) g'
suffices ∀ b, IsLUB { a | ∃ i, f' i b = a } (g b) from
Measurable.isLUB (fun i ↦ Measurable.piecewise hs (hf i) g'_meas) this
intro b
@@ -552,14 +577,7 @@ theorem Measurable.isLUB_of_mem {ι} [Countable ι] {f : ι → δ → α} {g g'
· have A : ∀ i, f' i b = f i b := fun i ↦ by simp [f', hb]
simpa [A] using hg b hb
· have A : ∀ i, f' i b = g' b := fun i ↦ by simp [f', hb]
- have : {a | ∃ (_i : ι), g' b = a} = {g' b} := by
- apply Subset.antisymm
- · rintro - ⟨_j, rfl⟩
- simp only [mem_singleton_iff]
- · rintro - rfl
- exact ⟨i, rfl⟩
- simp only [exists_prop'] at this
- simp [A, this, hg' hb, isLUB_singleton]
+ simp [A, hg' hb, isLUB_singleton]
theorem AEMeasurable.isLUB {ι} {μ : Measure δ} [Countable ι] {f : ι → δ → α} {g : δ → α}
(hf : ∀ i, AEMeasurable (f i) μ) (hg : ∀ᵐ b ∂μ, IsLUB { a | ∃ i, f i b = a } (g b)) :
@@ -703,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]
@@ -712,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]
@@ -726,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']
@@ -744,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
+
+@[deprecated (since := "2024-10-21")]
+alias measurable_sSup := Measurable.sSup
-theorem measurable_sInf {ι} {f : ι → δ → α} {s : Set ι} (hs : s.Countable)
+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
-theorem measurable_biSup {ι} (s : Set ι) {f : ι → δ → α} (hs : s.Countable)
+@[deprecated (since := "2024-10-21")]
+alias measurable_sInf := Measurable.sInf
+
+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)
+
+@[deprecated (since := "2024-10-21")]
+alias measurable_biSup := Measurable.biSup
-theorem aemeasurable_biSup {ι} {μ : Measure δ} (s : Set ι) {f : ι → δ → α} (hs : s.Countable)
+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
@@ -834,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))
@@ -863,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
-/-- `liminf` over `ℕ` is measurable. See `measurable_liminf'` for a version with a general filter.
+@[deprecated (since := "2024-10-21")]
+alias measurable_limsup' := Measurable.limsup'
+
+/-- `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 _
+
+@[deprecated (since := "2024-10-21")]
+alias measurable_liminf := Measurable.liminf
-/-- `limsup` over `ℕ` is measurable. See `measurable_limsup'` for a version with a general filter.
+/-- `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
@@ -905,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 =
@@ -925,8 +991,8 @@ theorem measure_eq_measure_preimage_add_measure_tsum_Ico_zpow {α : Type*} [Meas
ext x
simp only [mem_singleton_iff, mem_union, mem_Ioo, mem_Ioi, mem_preimage]
obtain (H | H) : f x = ∞ ∨ f x < ∞ := eq_or_lt_of_le le_top
- · simp only [H, eq_self_iff_true, or_false_iff, ENNReal.zero_lt_top, not_top_lt, and_false]
- · simp only [H, H.ne, and_true_iff, false_or_iff]
+ · simp only [H, eq_self_iff_true, or_false, ENNReal.zero_lt_top, not_top_lt, and_false]
+ · simp only [H, H.ne, and_true, false_or]
· refine disjoint_left.2 fun x hx h'x => ?_
have : f x < ∞ := h'x.2.2
exact lt_irrefl _ (this.trans_le (le_of_eq hx.2.symm))
diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean
index b566424678fd2..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
@@ -480,12 +478,12 @@ theorem exists_spanning_measurableSet_le {α : Type*} {m : MeasurableSpace α} {
let norm_sets := fun n : ℕ => { x | f x ≤ n }
have norm_sets_spanning : ⋃ n, norm_sets n = Set.univ := by
ext1 x
- simp only [Set.mem_iUnion, Set.mem_setOf_eq, Set.mem_univ, iff_true_iff]
+ simp only [Set.mem_iUnion, Set.mem_setOf_eq, Set.mem_univ, iff_true]
exact exists_nat_ge (f x)
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 ?_
@@ -505,7 +503,7 @@ variable (μ : Measure ℝ) [IsFiniteMeasureOnCompacts μ]
lemma tendsto_measure_Icc_nhdsWithin_right' (b : ℝ) :
Tendsto (fun δ ↦ μ (Icc (b - δ) (b + δ))) (𝓝[>] (0 : ℝ)) (𝓝 (μ {b})) := by
rw [Real.singleton_eq_inter_Icc]
- apply tendsto_measure_biInter_gt (fun r hr ↦ measurableSet_Icc.nullMeasurableSet)
+ apply tendsto_measure_biInter_gt (fun r hr ↦ nullMeasurableSet_Icc)
· intro r s _rpos hrs
exact Icc_subset_Icc (by linarith) (by linarith)
· exact ⟨1, zero_lt_one, isCompact_Icc.measure_ne_top⟩
diff --git a/Mathlib/MeasureTheory/Constructions/Cylinders.lean b/Mathlib/MeasureTheory/Constructions/Cylinders.lean
index dcdfe7b8f1a19..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
@@ -150,11 +152,11 @@ section cylinder
/-- Given a finite set `s` of indices, a cylinder is the preimage of a set `S` of `∀ i : s, α i` by
the projection from `∀ i, α i` to `∀ i : s, α i`. -/
def cylinder (s : Finset ι) (S : Set (∀ i : s, α i)) : Set (∀ i, α i) :=
- (fun (f : ∀ i, α i) (i : s) ↦ f i) ⁻¹' S
+ s.restrict ⁻¹' S
@[simp]
theorem mem_cylinder (s : Finset ι) (S : Set (∀ i : s, α i)) (f : ∀ i, α i) :
- f ∈ cylinder s S ↔ (fun i : s ↦ f i) ∈ S :=
+ f ∈ cylinder s S ↔ s.restrict f ∈ S :=
mem_preimage
@[simp]
@@ -178,7 +180,7 @@ theorem cylinder_eq_empty_iff [h_nonempty : Nonempty (∀ i, α i)] (s : Finset
let f' : ∀ i, α i := fun i ↦ if hi : i ∈ s then f ⟨i, hi⟩ else h_nonempty.some i
have hf' : f' ∈ cylinder s S := by
rw [mem_cylinder]
- simpa only [f', Finset.coe_mem, dif_pos]
+ simpa only [Finset.restrict_def, Finset.coe_mem, dif_pos, f']
rw [h] at hf'
exact not_mem_empty _ hf'
@@ -186,8 +188,8 @@ theorem inter_cylinder (s₁ s₂ : Finset ι) (S₁ : Set (∀ i : s₁, α i))
[DecidableEq ι] :
cylinder s₁ S₁ ∩ cylinder s₂ S₂ =
cylinder (s₁ ∪ s₂)
- ((fun f ↦ fun j : s₁ ↦ f ⟨j, Finset.mem_union_left s₂ j.prop⟩) ⁻¹' S₁ ∩
- (fun f ↦ fun j : s₂ ↦ f ⟨j, Finset.mem_union_right s₁ j.prop⟩) ⁻¹' S₂) := by
+ (Finset.restrict₂ Finset.subset_union_left ⁻¹' S₁ ∩
+ Finset.restrict₂ Finset.subset_union_right ⁻¹' S₂) := by
ext1 f; simp only [mem_inter_iff, mem_cylinder, mem_setOf_eq]; rfl
theorem inter_cylinder_same (s : Finset ι) (S₁ : Set (∀ i : s, α i)) (S₂ : Set (∀ i : s, α i)) :
@@ -198,8 +200,8 @@ theorem union_cylinder (s₁ s₂ : Finset ι) (S₁ : Set (∀ i : s₁, α i))
[DecidableEq ι] :
cylinder s₁ S₁ ∪ cylinder s₂ S₂ =
cylinder (s₁ ∪ s₂)
- ((fun f ↦ fun j : s₁ ↦ f ⟨j, Finset.mem_union_left s₂ j.prop⟩) ⁻¹' S₁ ∪
- (fun f ↦ fun j : s₂ ↦ f ⟨j, Finset.mem_union_right s₁ j.prop⟩) ⁻¹' S₂) := by
+ (Finset.restrict₂ Finset.subset_union_left ⁻¹' S₁ ∪
+ Finset.restrict₂ Finset.subset_union_right ⁻¹' S₂) := by
ext1 f; simp only [mem_union, mem_cylinder, mem_setOf_eq]; rfl
theorem union_cylinder_same (s : Finset ι) (S₁ : Set (∀ i : s, α i)) (S₂ : Set (∀ i : s, α i)) :
@@ -217,7 +219,7 @@ theorem diff_cylinder_same (s : Finset ι) (S T : Set (∀ i : s, α i)) :
theorem eq_of_cylinder_eq_of_subset [h_nonempty : Nonempty (∀ i, α i)] {I J : Finset ι}
{S : Set (∀ i : I, α i)} {T : Set (∀ i : J, α i)} (h_eq : cylinder I S = cylinder J T)
(hJI : J ⊆ I) :
- S = (fun f : ∀ i : I, α i ↦ fun j : J ↦ f ⟨j, hJI j.prop⟩) ⁻¹' T := by
+ S = Finset.restrict₂ hJI ⁻¹' T := by
rw [Set.ext_iff] at h_eq
simp only [mem_cylinder] at h_eq
ext1 f
@@ -225,22 +227,20 @@ theorem eq_of_cylinder_eq_of_subset [h_nonempty : Nonempty (∀ i, α i)] {I J :
classical
specialize h_eq fun i ↦ if hi : i ∈ I then f ⟨i, hi⟩ else h_nonempty.some i
have h_mem : ∀ j : J, ↑j ∈ I := fun j ↦ hJI j.prop
- simp only [Finset.coe_mem, dite_true, h_mem] at h_eq
- exact h_eq
+ simpa only [Finset.restrict_def, Finset.coe_mem, dite_true, h_mem] using h_eq
theorem cylinder_eq_cylinder_union [DecidableEq ι] (I : Finset ι) (S : Set (∀ i : I, α i))
(J : Finset ι) :
cylinder I S =
- cylinder (I ∪ J) ((fun f ↦ fun j : I ↦ f ⟨j, Finset.mem_union_left J j.prop⟩) ⁻¹' S) := by
- ext1 f; simp only [mem_cylinder, mem_preimage]
+ cylinder (I ∪ J) (Finset.restrict₂ Finset.subset_union_left ⁻¹' S) := by
+ ext1 f; simp only [mem_cylinder, Finset.restrict_def, Finset.restrict₂_def, mem_preimage]
theorem disjoint_cylinder_iff [Nonempty (∀ i, α i)] {s t : Finset ι} {S : Set (∀ i : s, α i)}
{T : Set (∀ i : t, α i)} [DecidableEq ι] :
Disjoint (cylinder s S) (cylinder t T) ↔
Disjoint
- ((fun f : ∀ i : (s ∪ t : Finset ι), α i
- ↦ fun j : s ↦ f ⟨j, Finset.mem_union_left t j.prop⟩) ⁻¹' S)
- ((fun f ↦ fun j : t ↦ f ⟨j, Finset.mem_union_right s j.prop⟩) ⁻¹' T) := by
+ (Finset.restrict₂ Finset.subset_union_left ⁻¹' S)
+ (Finset.restrict₂ Finset.subset_union_right ⁻¹' T) := by
simp_rw [Set.disjoint_iff, subset_empty_iff, inter_cylinder, cylinder_eq_empty_iff]
theorem IsClosed.cylinder [∀ i, TopologicalSpace (α i)] (s : Finset ι) {S : Set (∀ i : s, α i)}
@@ -274,6 +274,12 @@ theorem mem_measurableCylinders (t : Set (∀ i, α i)) :
t ∈ measurableCylinders α ↔ ∃ s S, MeasurableSet S ∧ t = cylinder s S := by
simp_rw [measurableCylinders, mem_iUnion, exists_prop, mem_singleton_iff]
+@[measurability]
+theorem _root_.MeasurableSet.of_mem_measurableCylinders {s : Set (Π i, α i)}
+ (hs : s ∈ measurableCylinders α) : MeasurableSet s := by
+ obtain ⟨I, t, mt, rfl⟩ := (mem_measurableCylinders s).1 hs
+ exact mt.cylinder
+
/-- A finset `s` such that `t = cylinder s S`. `S` is given by `measurableCylinders.set`. -/
noncomputable def measurableCylinders.finset (ht : t ∈ measurableCylinders α) : Finset ι :=
((mem_measurableCylinders t).mp ht).choose
@@ -304,8 +310,8 @@ theorem inter_mem_measurableCylinders (hs : s ∈ measurableCylinders α)
obtain ⟨s₂, S₂, hS₂, rfl⟩ := ht
classical
refine ⟨s₁ ∪ s₂,
- (fun f ↦ (fun i ↦ f ⟨i, Finset.mem_union_left s₂ i.prop⟩ : ∀ i : s₁, α i)) ⁻¹' S₁ ∩
- {f | (fun i ↦ f ⟨i, Finset.mem_union_right s₁ i.prop⟩ : ∀ i : s₂, α i) ∈ S₂}, ?_, ?_⟩
+ Finset.restrict₂ Finset.subset_union_left ⁻¹' S₁ ∩
+ {f | Finset.restrict₂ Finset.subset_union_right f ∈ S₂}, ?_, ?_⟩
· refine MeasurableSet.inter ?_ ?_
· exact measurable_pi_lambda _ (fun _ ↦ measurable_pi_apply _) hS₁
· exact measurable_pi_lambda _ (fun _ ↦ measurable_pi_apply _) hS₂
@@ -353,8 +359,83 @@ theorem generateFrom_measurableCylinders :
rintro t ht rfl
refine ⟨{i}, {f | f ⟨i, Finset.mem_singleton_self i⟩ ∈ t i}, measurable_pi_apply _ (ht i), ?_⟩
ext1 x
- simp only [singleton_pi, Function.eval, mem_preimage, mem_cylinder, mem_setOf_eq]
+ simp only [mem_preimage, Function.eval, mem_cylinder, mem_setOf_eq, Finset.restrict]
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 9326504897129..8b8f004c2cbd6 100644
--- a/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean
+++ b/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean
@@ -3,10 +3,10 @@ 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.Algebra.Order.Pointwise
+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
/-!
@@ -27,7 +27,7 @@ for a general nontrivial normed space.
open Set Function Metric MeasurableSpace intervalIntegral
open scoped Pointwise ENNReal NNReal
-local notation "dim" => FiniteDimensional.finrank ℝ
+local notation "dim" => Module.finrank ℝ
noncomputable section
namespace MeasureTheory
@@ -39,7 +39,7 @@ namespace Measure
/-- If `μ` is an additive Haar measure on a normed space `E`,
then `μ.toSphere` is the measure on the unit sphere in `E`
-such that `μ.toSphere s = FiniteDimensional.finrank ℝ E • μ (Set.Ioo (0 : ℝ) 1 • s)`. -/
+such that `μ.toSphere s = Module.finrank ℝ E • μ (Set.Ioo (0 : ℝ) 1 • s)`. -/
def toSphere (μ : Measure E) : Measure (sphere (0 : E) 1) :=
dim E • ((μ.comap (Subtype.val ∘ (homeomorphUnitSphereProd E).symm)).restrict
(univ ×ˢ Iio ⟨1, mem_Ioi.2 one_pos⟩)).fst
@@ -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⟩
@@ -106,7 +106,7 @@ instance (n : ℕ) : SigmaFinite (volumeIoiPow n) :=
/-- The homeomorphism `homeomorphUnitSphereProd E` sends an additive Haar measure `μ`
to the product of `μ.toSphere` and `MeasureTheory.Measure.volumeIoiPow (dim E - 1)`,
-where `dim E = FiniteDimensional.finrank ℝ E` is the dimension of `E`. -/
+where `dim E = Module.finrank ℝ E` is the dimension of `E`. -/
theorem measurePreserving_homeomorphUnitSphereProd :
MeasurePreserving (homeomorphUnitSphereProd E) (μ.comap (↑))
(μ.toSphere.prod (volumeIoiPow (dim E - 1))) := by
@@ -119,7 +119,7 @@ theorem measurePreserving_homeomorphUnitSphereProd :
fun s hs ↦ forall_mem_range.2 fun r ↦ ?_
have : Ioo (0 : ℝ) r = r.1 • Ioo (0 : ℝ) 1 := by
rw [LinearOrderedField.smul_Ioo r.2.out, smul_zero, smul_eq_mul, mul_one]
- have hpos : 0 < dim E := FiniteDimensional.finrank_pos
+ have hpos : 0 < dim E := Module.finrank_pos
rw [(Homeomorph.measurableEmbedding _).map_apply, toSphere_apply' _ hs, volumeIoiPow_apply_Iio,
comap_subtype_coe_apply (measurableSet_singleton _).compl, toSphere_apply_aux, this,
smul_assoc, μ.addHaar_smul_of_nonneg r.2.out.le, Nat.sub_add_cancel hpos, Nat.cast_pred hpos,
@@ -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 12c48b54b7654..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)) :
@@ -211,8 +214,7 @@ variable {δ : Type*} {π : δ → Type*} [∀ x, MeasurableSpace (π x)]
protected def tprod (l : List δ) (μ : ∀ i, Measure (π i)) : Measure (TProd π l) := by
induction' l with i l ih
· exact dirac PUnit.unit
- · have := (μ i).prod (α := π i) ih
- exact this
+ · exact (μ i).prod (α := π i) ih
@[simp]
theorem tprod_nil (μ : ∀ i, Measure (π i)) : Measure.tprod [] μ = dirac PUnit.unit :=
@@ -837,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 f1677d8c92db5..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
@@ -343,7 +354,7 @@ protected lemma AnalyticSet.preimage {X Y : Type*} [TopologicalSpace X] [Topolog
[PolishSpace X] [T2Space Y] {s : Set Y} (hs : AnalyticSet s) {f : X → Y} (hf : Continuous f) :
AnalyticSet (f ⁻¹' s) := by
rcases analyticSet_iff_exists_polishSpace_range.1 hs with ⟨Z, _, _, g, hg, rfl⟩
- have : IsClosed {x : X × Z | f x.1 = g x.2} := isClosed_diagonal.preimage (hf.prod_map hg)
+ have : IsClosed {x : X × Z | f x.1 = g x.2} := isClosed_eq hf.fst' hg.snd'
convert this.analyticSet.image_of_continuous continuous_fst
ext x
simp [eq_comm]
@@ -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/Projective.lean b/Mathlib/MeasureTheory/Constructions/Projective.lean
index 1b5505b2a390d..37ef05c547f45 100644
--- a/Mathlib/MeasureTheory/Constructions/Projective.lean
+++ b/Mathlib/MeasureTheory/Constructions/Projective.lean
@@ -40,18 +40,28 @@ variable {ι : Type*} {α : ι → Type*} [∀ i, MeasurableSpace (α i)]
the projection from `∀ i : I, α i` to `∀ i : J, α i` maps `P I` to `P J`. -/
def IsProjectiveMeasureFamily (P : ∀ J : Finset ι, Measure (∀ j : J, α j)) : Prop :=
∀ (I J : Finset ι) (hJI : J ⊆ I),
- P J = (P I).map (fun (x : ∀ i : I, α i) (j : J) ↦ x ⟨j, hJI j.2⟩)
+ P J = (P I).map (Finset.restrict₂ hJI)
namespace IsProjectiveMeasureFamily
variable {I J : Finset ι}
+lemma eq_zero_of_isEmpty [h : IsEmpty (Π i, α i)]
+ (hP : IsProjectiveMeasureFamily P) (I : Finset ι) :
+ P I = 0 := by
+ classical
+ obtain ⟨i, hi⟩ := isEmpty_pi.mp h
+ rw [hP (insert i I) I (I.subset_insert i)]
+ have : IsEmpty (Π j : ↑(insert i I), α j) := by simp [hi]
+ rw [(P (insert i I)).eq_zero_of_isEmpty]
+ simp
+
/-- Auxiliary lemma for `measure_univ_eq`. -/
lemma measure_univ_eq_of_subset (hP : IsProjectiveMeasureFamily P) (hJI : J ⊆ I) :
P I univ = P J univ := by
classical
have : (univ : Set (∀ i : I, α i)) =
- (fun x : ∀ i : I, α i ↦ fun i : J ↦ x ⟨i, hJI i.2⟩) ⁻¹' (univ : Set (∀ i : J, α i)) := by
+ Finset.restrict₂ hJI ⁻¹' (univ : Set (∀ i : J, α i)) := by
rw [preimage_univ]
rw [this, ← Measure.map_apply _ MeasurableSet.univ]
· rw [hP I J hJI]
@@ -79,7 +89,7 @@ lemma congr_cylinder_of_subset (hP : IsProjectiveMeasureFamily P)
have : (univ : Set ((j : {x // x ∈ ({i} : Finset ι)}) → α j)) = ∅ := by simp [hi_empty]
simp [this]
| inr h =>
- have : S = (fun f : ∀ i : I, α i ↦ fun j : J ↦ f ⟨j, hJI j.prop⟩) ⁻¹' T :=
+ have : S = Finset.restrict₂ hJI ⁻¹' T :=
eq_of_cylinder_eq_of_subset h_eq hJI
rw [hP I J hJI, Measure.map_apply _ hT, this]
exact measurable_pi_lambda _ (fun _ ↦ measurable_pi_apply _)
@@ -89,9 +99,8 @@ lemma congr_cylinder (hP : IsProjectiveMeasureFamily P)
(h_eq : cylinder I S = cylinder J T) :
P I S = P J T := by
classical
- let U := (fun f : ∀ i : (I ∪ J : Finset ι), α i
- ↦ fun j : I ↦ f ⟨j, Finset.mem_union_left J j.prop⟩) ⁻¹' S ∩
- (fun f ↦ fun j : J ↦ f ⟨j, Finset.mem_union_right I j.prop⟩) ⁻¹' T
+ let U := Finset.restrict₂ Finset.subset_union_left ⁻¹' S ∩
+ Finset.restrict₂ Finset.subset_union_right ⁻¹' T
suffices P (I ∪ J) U = P I S ∧ P (I ∪ J) U = P J T from this.1.symm.trans this.2
constructor
· have h_eq_union : cylinder I S = cylinder (I ∪ J) U := by
@@ -107,7 +116,7 @@ end IsProjectiveMeasureFamily
for all `I : Finset ι`, the projection from `∀ i, α i` to `∀ i : I, α i` maps `μ` to `P I`. -/
def IsProjectiveLimit (μ : Measure (∀ i, α i))
(P : ∀ J : Finset ι, Measure (∀ j : J, α j)) : Prop :=
- ∀ I : Finset ι, (μ.map fun x : ∀ i, α i ↦ fun i : I ↦ x i) = P I
+ ∀ I : Finset ι, (μ.map I.restrict) = P I
namespace IsProjectiveLimit
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/Constructions/UnitInterval.lean b/Mathlib/MeasureTheory/Constructions/UnitInterval.lean
index 631b218cfe854..d3ea8002c5a93 100644
--- a/Mathlib/MeasureTheory/Constructions/UnitInterval.lean
+++ b/Mathlib/MeasureTheory/Constructions/UnitInterval.lean
@@ -25,7 +25,7 @@ theorem volume_def : (volume : Measure I) = volume.comap Subtype.val := rfl
instance : IsProbabilityMeasure (volume : Measure I) where
measure_univ := by
- rw [Measure.Subtype.volume_univ measurableSet_Icc.nullMeasurableSet, Real.volume_Icc, sub_zero,
+ rw [Measure.Subtype.volume_univ nullMeasurableSet_Icc, Real.volume_Icc, sub_zero,
ENNReal.ofReal_one]
@[measurability]
diff --git a/Mathlib/MeasureTheory/Covering/Besicovitch.lean b/Mathlib/MeasureTheory/Covering/Besicovitch.lean
index 5fc2bf194df58..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,
@@ -340,7 +340,7 @@ theorem color_lt {i : Ordinal.{u}} (hi : i < p.lastStep) {N : ℕ}
have color_i : p.color i = sInf (univ \ A) := by rw [color]
rw [color_i]
have N_mem : N ∈ univ \ A := by
- simp only [A, not_exists, true_and_iff, exists_prop, mem_iUnion, mem_singleton_iff,
+ simp only [A, not_exists, true_and, exists_prop, mem_iUnion, mem_singleton_iff,
mem_closedBall, not_and, mem_univ, mem_diff, Subtype.exists, Subtype.coe_mk]
intro j ji _
exact (IH j ji (ji.trans hi)).ne'
@@ -356,7 +356,7 @@ theorem color_lt {i : Ordinal.{u}} (hi : i < p.lastStep) {N : ℕ}
intro k hk
rw [← Inf_eq_N] at hk
have : k ∈ A := by
- simpa only [true_and_iff, mem_univ, Classical.not_not, mem_diff] using
+ simpa only [true_and, mem_univ, Classical.not_not, mem_diff] using
Nat.not_mem_of_lt_sInf hk
simp only [mem_iUnion, mem_singleton_iff, exists_prop, Subtype.exists, exists_and_right,
and_assoc] at this
@@ -491,15 +491,15 @@ theorem exist_disjoint_covering_families {N : ℕ} {τ : ℝ} (hτ : 1 < τ)
rw [color_j]
apply csInf_mem
refine ⟨N, ?_⟩
- simp only [A, not_exists, true_and_iff, exists_prop, mem_iUnion, mem_singleton_iff, not_and,
+ simp only [A, not_exists, true_and, exists_prop, mem_iUnion, mem_singleton_iff, not_and,
mem_univ, mem_diff, Subtype.exists, Subtype.coe_mk]
intro k hk _
exact (p.color_lt (hk.trans jy_lt) hN).ne'
- simp only [A, not_exists, true_and_iff, exists_prop, mem_iUnion, mem_singleton_iff, not_and,
+ simp only [A, not_exists, true_and, exists_prop, mem_iUnion, mem_singleton_iff, not_and,
mem_univ, mem_diff, Subtype.exists, Subtype.coe_mk] at h
specialize h jx jxy
contrapose! h
- simpa only [jxi, jyi, and_true_iff, eq_self_iff_true, ← not_disjoint_iff_nonempty_inter] using h
+ simpa only [jxi, jyi, and_true, eq_self_iff_true, ← not_disjoint_iff_nonempty_inter] using h
· -- show that the balls of color at most `N` cover every center.
refine range_subset_iff.2 fun b => ?_
obtain ⟨a, ha⟩ :
@@ -708,7 +708,7 @@ theorem exists_disjoint_closedBall_covering_ae_of_finiteMeasure_aux (μ : Measur
exist_finset_disjoint_balls_large_measure μ hτ hN s' r (fun x hx => (rI x hx).1) fun x hx =>
(rI x hx).2.le
refine ⟨t ∪ Finset.image (fun x => (x, r x)) v, Finset.subset_union_left, ⟨?_, ?_, ?_⟩, ?_⟩
- · simp only [Finset.coe_union, pairwiseDisjoint_union, ht.1, true_and_iff, Finset.coe_image]
+ · simp only [Finset.coe_union, pairwiseDisjoint_union, ht.1, true_and, Finset.coe_image]
constructor
· intro p hp q hq hpq
rcases (mem_image _ _ _).1 hp with ⟨p', p'v, rfl⟩
@@ -781,8 +781,8 @@ theorem exists_disjoint_closedBall_covering_ae_of_finiteMeasure_aux (μ : Measur
rw [ENNReal.div_lt_iff, one_mul]
· conv_lhs => rw [← add_zero (N : ℝ≥0∞)]
exact ENNReal.add_lt_add_left (ENNReal.natCast_ne_top N) zero_lt_one
- · simp only [true_or_iff, add_eq_zero, Ne, not_false_iff, one_ne_zero, and_false_iff]
- · simp only [ENNReal.natCast_ne_top, Ne, not_false_iff, or_true_iff]
+ · simp only [true_or, add_eq_zero, Ne, not_false_iff, one_ne_zero, and_false]
+ · simp only [ENNReal.natCast_ne_top, Ne, not_false_iff, or_true]
rw [zero_mul] at C
apply le_bot_iff.1
exact le_of_tendsto_of_tendsto' tendsto_const_nhds C fun n => (A n).trans (B n)
@@ -921,7 +921,7 @@ theorem exists_closedBall_covering_tsum_measure_le (μ : Measure α) [SFinite μ
refine ⟨t0 ∪ ⋃ i : Fin N, ((↑) : s' → α) '' S i, r, ?_, ?_, ?_, ?_, ?_⟩
-- it remains to check that they have the desired properties
· exact t0_count.union (countable_iUnion fun i => (S_count i).image _)
- · simp only [t0s, true_and_iff, union_subset_iff, image_subset_iff, iUnion_subset_iff]
+ · simp only [t0s, true_and, union_subset_iff, image_subset_iff, iUnion_subset_iff]
intro i x _
exact s's x.2
· intro x hx
@@ -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/BesicovitchVectorSpace.lean b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean
index 97a0b59d00769..2c3bc40927bd3 100644
--- a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean
+++ b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean
@@ -43,7 +43,7 @@ In particular, this number is bounded by `5 ^ dim` by a straightforward measure
universe u
-open Metric Set FiniteDimensional MeasureTheory Filter Fin
+open Metric Set Module MeasureTheory Filter Fin
open scoped ENNReal Topology
@@ -461,13 +461,13 @@ theorem exists_normalized {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) (las
· simp_rw [c', Hj, hij.trans Hj, if_true]
exact exists_normalized_aux1 a lastr hτ δ hδ1 hδ2 i j inej
-- case `2 < ‖c j‖`
- · have H'j : ‖a.c j‖ ≤ 2 ↔ False := by simpa only [not_le, iff_false_iff] using Hj
+ · have H'j : ‖a.c j‖ ≤ 2 ↔ False := by simpa only [not_le, iff_false] using Hj
rcases le_or_lt ‖a.c i‖ 2 with (Hi | Hi)
· -- case `‖c i‖ ≤ 2`
simp_rw [c', Hi, if_true, H'j, if_false]
exact exists_normalized_aux2 a lastc lastr hτ δ hδ1 hδ2 i j inej Hi Hj
· -- case `2 < ‖c i‖`
- have H'i : ‖a.c i‖ ≤ 2 ↔ False := by simpa only [not_le, iff_false_iff] using Hi
+ have H'i : ‖a.c i‖ ≤ 2 ↔ False := by simpa only [not_le, iff_false] using Hi
simp_rw [c', H'i, if_false, H'j, if_false]
exact exists_normalized_aux3 a lastc lastr hτ δ hδ1 i j inej Hi hij
diff --git a/Mathlib/MeasureTheory/Covering/DensityTheorem.lean b/Mathlib/MeasureTheory/Covering/DensityTheorem.lean
index 35d1a28b7705d..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
@@ -69,7 +69,7 @@ theorem closedBall_mem_vitaliFamily_of_dist_le_mul {K : ℝ} {x y : α} {r : ℝ
(rpos : 0 < r) : closedBall y r ∈ (vitaliFamily μ K).setsAt x := by
let R := scalingScaleOf μ (max (4 * K + 3) 3)
simp only [vitaliFamily, VitaliFamily.enlarge, Vitali.vitaliFamily, mem_union, mem_setOf_eq,
- isClosed_ball, true_and_iff, (nonempty_ball.2 rpos).mono ball_subset_interior_closedBall,
+ isClosed_ball, true_and, (nonempty_ball.2 rpos).mono ball_subset_interior_closedBall,
measurableSet_closedBall]
/- The measure is doubling on scales smaller than `R`. Therefore, we treat differently small
and large balls. For large balls, this follows directly from the enlargement we used in the
@@ -123,7 +123,7 @@ theorem tendsto_closedBall_filterAt {K : ℝ} {x : α} {ι : Type*} {l : Filter
apply (((Metric.tendsto_nhds.mp δlim _ (div_pos hε hK)).and δpos).and xmem).mono
rintro j ⟨⟨hjε, hj₀ : 0 < δ j⟩, hx⟩ y hy
replace hjε : (K + 1) * δ j < ε := by
- simpa [abs_eq_self.mpr hj₀.le] using (lt_div_iff' hK).mp hjε
+ simpa [abs_eq_self.mpr hj₀.le] using (lt_div_iff₀' hK).mp hjε
simp only [mem_closedBall] at hx hy ⊢
linarith [dist_triangle_right y x (w j)]
@@ -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 abe8892caee43..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
@@ -245,7 +246,7 @@ theorem ae_tendsto_div : ∀ᵐ x ∂μ, ∃ c, Tendsto (fun a => ρ a / μ a) (
intro x h1x _
apply h1x.mono fun a ha => ?_
refine (ENNReal.div_le_iff_le_mul ?_ (Or.inr (bot_le.trans_lt ha).ne')).1 ha.le
- simp only [ENNReal.coe_ne_top, Ne, or_true_iff, not_false_iff]
+ simp only [ENNReal.coe_ne_top, Ne, or_true, not_false_iff]
· simp only [and_imp, exists_prop, not_frequently, not_and, not_lt, not_le, not_eventually,
mem_setOf_eq, mem_compl_iff, not_forall]
intro x _ h2x
@@ -324,7 +325,7 @@ theorem exists_measurable_supersets_limRatio {p q : ℝ≥0} (hpq : p < q) :
(toMeasurable μ sᶜ ∪ ⋃ n, toMeasurable (ρ + μ) (w n)) ⊆
toMeasurable μ sᶜ ∪
⋃ (m) (n), toMeasurable (ρ + μ) (u m) ∩ toMeasurable (ρ + μ) (w n) := by
- simp only [inter_union_distrib_left, union_inter_distrib_right, true_and_iff,
+ simp only [inter_union_distrib_left, union_inter_distrib_right, true_and,
subset_union_left, union_subset_iff, inter_self]
refine ⟨?_, ?_, ?_⟩
· exact inter_subset_right.trans subset_union_left
@@ -368,7 +369,7 @@ theorem exists_measurable_supersets_limRatio {p q : ℝ≥0} (hpq : p < q) :
apply I.frequently.mono fun a ha => ?_
rw [coe_nnreal_smul_apply]
refine (ENNReal.div_le_iff_le_mul ?_ (Or.inr (bot_le.trans_lt ha).ne')).1 ha.le
- simp only [ENNReal.coe_ne_top, Ne, or_true_iff, not_false_iff]
+ simp only [ENNReal.coe_ne_top, Ne, or_true, not_false_iff]
_ = p * μ (toMeasurable (ρ + μ) (u m) ∩ toMeasurable (ρ + μ) (w n)) := by
simp only [coe_nnreal_smul_apply,
measure_toMeasurable_add_inter_right (measurableSet_toMeasurable _ _) I]
@@ -448,7 +449,7 @@ theorem measure_le_mul_of_subset_limRatioMeas_lt {p : ℝ≥0} {s : Set α}
apply I.frequently.mono fun a ha => ?_
rw [coe_nnreal_smul_apply]
refine (ENNReal.div_le_iff_le_mul ?_ (Or.inr (bot_le.trans_lt ha).ne')).1 ha.le
- simp only [ENNReal.coe_ne_top, Ne, or_true_iff, not_false_iff]
+ simp only [ENNReal.coe_ne_top, Ne, or_true, not_false_iff]
/-- If, for all `x` in a set `s`, one has frequently `q < ρ a / μ a`, then `q * μ s ≤ ρ s`, as
proved in `measure_le_of_frequently_le`. Since `ρ a / μ a` tends almost everywhere to
@@ -485,7 +486,7 @@ theorem measure_limRatioMeas_top : μ {x | v.limRatioMeas hρ x = ∞} = 0 := by
intro y hy
have : v.limRatioMeas hρ y = ∞ := hy.1
simp only [this, ENNReal.coe_lt_top, mem_setOf_eq]
- · simp only [(zero_lt_one.trans_le hq).ne', true_or_iff, ENNReal.coe_eq_zero, Ne,
+ · simp only [(zero_lt_one.trans_le hq).ne', true_or, ENNReal.coe_eq_zero, Ne,
not_false_iff]
have B : Tendsto (fun q : ℝ≥0 => (q : ℝ≥0∞)⁻¹ * ρ s) atTop (𝓝 (∞⁻¹ * ρ s)) := by
apply ENNReal.Tendsto.mul_const _ (Or.inr ρs)
@@ -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 ⁻¹' {∞}) +
@@ -649,8 +650,8 @@ theorem withDensity_limRatioMeas_eq : μ.withDensity (v.limRatioMeas hρ) = ρ :
((t : ℝ≥0∞) ^ 2 * ρ s : ℝ≥0∞)) (𝓝[>] 1) (𝓝 ((1 : ℝ≥0∞) ^ 2 * ρ s)) := by
refine ENNReal.Tendsto.mul ?_ ?_ tendsto_const_nhds ?_
· exact ENNReal.Tendsto.pow (ENNReal.tendsto_coe.2 nhdsWithin_le_nhds)
- · simp only [one_pow, ENNReal.coe_one, true_or_iff, Ne, not_false_iff, one_ne_zero]
- · simp only [one_pow, ENNReal.coe_one, Ne, or_true_iff, ENNReal.one_ne_top, not_false_iff]
+ · simp only [one_pow, ENNReal.coe_one, true_or, Ne, not_false_iff, one_ne_zero]
+ · simp only [one_pow, ENNReal.coe_one, Ne, or_true, ENNReal.one_ne_top, not_false_iff]
simp only [one_pow, one_mul, ENNReal.coe_one] at this
refine ge_of_tendsto this ?_
filter_upwards [self_mem_nhdsWithin] with _ ht
@@ -659,7 +660,7 @@ theorem withDensity_limRatioMeas_eq : μ.withDensity (v.limRatioMeas hρ) = ρ :
Tendsto (fun t : ℝ≥0 => (t : ℝ≥0∞) * μ.withDensity (v.limRatioMeas hρ) s) (𝓝[>] 1)
(𝓝 ((1 : ℝ≥0∞) * μ.withDensity (v.limRatioMeas hρ) s)) := by
refine ENNReal.Tendsto.mul_const (ENNReal.tendsto_coe.2 nhdsWithin_le_nhds) ?_
- simp only [ENNReal.coe_one, true_or_iff, Ne, not_false_iff, one_ne_zero]
+ simp only [ENNReal.coe_one, true_or, Ne, not_false_iff, one_ne_zero]
simp only [one_mul, ENNReal.coe_one] at this
refine ge_of_tendsto this ?_
filter_upwards [self_mem_nhdsWithin] with _ ht
@@ -809,7 +810,7 @@ theorem ae_tendsto_lintegral_nnnorm_sub_div'_of_integrable {f : α → E} (hf :
_ < ∞ + ∞ :=
haveI I : Integrable ((A.set n).indicator fun _ : α => c) μ := by
simp only [integrable_indicator_iff (IsOpen.measurableSet (A.set_mem n)),
- integrableOn_const, A.finite n, or_true_iff]
+ integrableOn_const, A.finite n, or_true]
ENNReal.add_lt_add hf.2 I.2
filter_upwards [main, v.ae_eventually_measure_pos] with x hx h'x
have M :
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 5928bb689a9c9..817189a085c43 100644
--- a/Mathlib/MeasureTheory/Covering/Vitali.lean
+++ b/Mathlib/MeasureTheory/Covering/Vitali.lean
@@ -112,7 +112,7 @@ theorem exists_disjoint_subfamily_covering_enlargment (B : ι → Set α) (t : S
· refine ⟨a, ⟨hat, a_disj⟩, ?_⟩
simpa only [← mzero, zero_div] using δnonneg a hat
· have I : m / τ < m := by
- rw [div_lt_iff (zero_lt_one.trans hτ)]
+ rw [div_lt_iff₀ (zero_lt_one.trans hτ)]
conv_lhs => rw [← mul_one m]
exact (mul_lt_mul_left mpos).2 hτ
rcases exists_lt_of_lt_csSup (Anonempty.image _) I with ⟨x, xA, hx⟩
@@ -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 3891d1175c65d..77cd7b8a79759 100644
--- a/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean
+++ b/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean
@@ -229,7 +229,7 @@ private theorem exists_subset_restrict_nonpos' (hi₁ : MeasurableSet i) (hi₂
have hmeas : MeasurableSet (⋃ (l : ℕ) (_ : l < k), restrictNonposSeq s i l) :=
MeasurableSet.iUnion fun _ => MeasurableSet.iUnion fun _ => restrictNonposSeq_measurableSet _
refine ⟨i \ ⋃ l < k, restrictNonposSeq s i l, hi₁.diff hmeas, Set.diff_subset, hk₂, ?_⟩
- rw [of_diff hmeas hi₁, s.of_disjoint_iUnion_nat]
+ rw [of_diff hmeas hi₁, s.of_disjoint_iUnion]
· have h₁ : ∀ l < k, 0 ≤ s (restrictNonposSeq s i l) := by
intro l hl
refine le_of_lt (measure_of_restrictNonposSeq h _ ?_)
@@ -247,7 +247,7 @@ private theorem exists_subset_restrict_nonpos' (hi₁ : MeasurableSet i) (hi₂
rw [Set.mem_iUnion, exists_prop, and_iff_right_iff_imp]
exact fun _ => h
· convert le_of_eq s.empty.symm
- ext; simp only [exists_prop, Set.mem_empty_iff_false, Set.mem_iUnion, not_and, iff_false_iff]
+ ext; simp only [exists_prop, Set.mem_empty_iff_false, Set.mem_iUnion, not_and, iff_false]
exact fun h' => False.elim (h h')
· intro; exact MeasurableSet.iUnion fun _ => restrictNonposSeq_measurableSet _
· intro a b hab
@@ -276,7 +276,7 @@ theorem exists_subset_restrict_nonpos (hi : s i < 0) :
simp only [exists_prop, Set.mem_iUnion, and_congr_left_iff]
exact fun _ => Nat.lt_succ_iff.symm
have h₁ : s i = s A + ∑' l, s (restrictNonposSeq s i l) := by
- rw [hA, ← s.of_disjoint_iUnion_nat, add_comm, of_add_of_diff]
+ rw [hA, ← s.of_disjoint_iUnion, add_comm, of_add_of_diff]
· exact MeasurableSet.iUnion fun _ => restrictNonposSeq_measurableSet _
exacts [hi₁, Set.iUnion_subset fun _ => restrictNonposSeq_subset _, fun _ =>
restrictNonposSeq_measurableSet _, restrictNonposSeq_disjoint]
@@ -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/Decomposition/UnsignedHahn.lean b/Mathlib/MeasureTheory/Decomposition/UnsignedHahn.lean
index de9f47a8ba7a8..1e85f61f04295 100644
--- a/Mathlib/MeasureTheory/Decomposition/UnsignedHahn.lean
+++ b/Mathlib/MeasureTheory/Decomposition/UnsignedHahn.lean
@@ -30,9 +30,8 @@ variable {α : Type*} [MeasurableSpace α] {μ ν : Measure α}
/-- **Hahn decomposition theorem** -/
theorem hahn_decomposition [IsFiniteMeasure μ] [IsFiniteMeasure ν] :
- ∃ s,
- MeasurableSet s ∧
- (∀ t, MeasurableSet t → t ⊆ s → ν t ≤ μ t) ∧ ∀ t, MeasurableSet t → t ⊆ sᶜ → μ t ≤ ν t := by
+ ∃ s, MeasurableSet s ∧ (∀ t, MeasurableSet t → t ⊆ s → ν t ≤ μ t) ∧
+ ∀ t, MeasurableSet t → t ⊆ sᶜ → μ t ≤ ν t := by
let d : Set α → ℝ := fun s => ((μ s).toNNReal : ℝ) - (ν s).toNNReal
let c : Set ℝ := d '' { s | MeasurableSet s }
let γ : ℝ := sSup c
@@ -50,7 +49,8 @@ theorem hahn_decomposition [IsFiniteMeasure μ] [IsFiniteMeasure ν] :
have d_Union (s : ℕ → Set α) (hm : Monotone s) :
Tendsto (fun n => d (s n)) atTop (𝓝 (d (⋃ n, s n))) := by
refine Tendsto.sub ?_ ?_ <;>
- refine NNReal.tendsto_coe.2 <| (ENNReal.tendsto_toNNReal ?_).comp <| tendsto_measure_iUnion hm
+ refine NNReal.tendsto_coe.2 <| (ENNReal.tendsto_toNNReal ?_).comp <|
+ tendsto_measure_iUnion_atTop hm
· exact hμ _
· exact hν _
have d_Inter (s : ℕ → Set α) (hs : ∀ n, MeasurableSet (s n)) (hm : ∀ n m, n ≤ m → s m ⊆ s n) :
diff --git a/Mathlib/MeasureTheory/Function/AEEqFun.lean b/Mathlib/MeasureTheory/Function/AEEqFun.lean
index 77d4374b0ee83..000e0416082a7 100644
--- a/Mathlib/MeasureTheory/Function/AEEqFun.lean
+++ b/Mathlib/MeasureTheory/Function/AEEqFun.lean
@@ -5,7 +5,7 @@ Authors: Johannes Hölzl, Zhouhang Zhou
-/
import Mathlib.MeasureTheory.Integral.Lebesgue
import Mathlib.Order.Filter.Germ.Basic
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.Topology.ContinuousMap.Algebra
import Mathlib.MeasureTheory.Function.StronglyMeasurable.Basic
/-!
diff --git a/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean b/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean
index bb4121b69171b..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
@@ -180,7 +180,7 @@ theorem ae_le_of_forall_setLIntegral_le_of_sigmaFinite₀ [SigmaFinite μ]
have B : (∫⁻ x in s, g x ∂μ) ≠ ∞ :=
(setLIntegral_lt_top_of_le_nnreal s_lt_top.ne ⟨N, fun _ h ↦ h.1.2⟩).ne
have : (ε : ℝ≥0∞) * μ s ≤ 0 := ENNReal.le_of_add_le_add_left B A
- simpa only [ENNReal.coe_eq_zero, nonpos_iff_eq_zero, mul_eq_zero, εpos.ne', false_or_iff]
+ simpa only [ENNReal.coe_eq_zero, nonpos_iff_eq_zero, mul_eq_zero, εpos.ne', false_or]
obtain ⟨u, _, u_pos, u_lim⟩ :
∃ u : ℕ → ℝ≥0, StrictAnti u ∧ (∀ n, 0 < u n) ∧ Tendsto u atTop (𝓝 0) :=
exists_seq_strictAnti_tendsto (0 : ℝ≥0)
@@ -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 04cb417cd938d..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']
@@ -109,7 +109,7 @@ theorem condexp_of_sigmaFinite (hm : m ≤ m0) [hμm : SigmaFinite (μ.trim hm)]
else aestronglyMeasurable'_condexpL1.mk (condexpL1 hm μ f)
else 0 := by
rw [condexp, dif_pos hm]
- simp only [hμm, Ne, true_and_iff]
+ simp only [hμm, Ne, true_and]
by_cases hf : Integrable f μ
· rw [dif_pos hf, if_pos hf]
· rw [dif_neg hf, if_neg hf]
@@ -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 779e0ed7f4ba6..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
@@ -176,11 +176,11 @@ theorem condexpIndL1_of_measurableSet_of_measure_ne_top (hs : MeasurableSet s) (
theorem condexpIndL1_of_measure_eq_top (hμs : μ s = ∞) (x : G) : condexpIndL1 hm μ s x = 0 := by
simp only [condexpIndL1, hμs, eq_self_iff_true, not_true, Ne, dif_neg, not_false_iff,
- and_false_iff]
+ and_false]
theorem condexpIndL1_of_not_measurableSet (hs : ¬MeasurableSet s) (x : G) :
condexpIndL1 hm μ s x = 0 := by
- simp only [condexpIndL1, hs, dif_neg, not_false_iff, false_and_iff]
+ simp only [condexpIndL1, hs, dif_neg, not_false_iff, false_and]
theorem condexpIndL1_add (x y : G) :
condexpIndL1 hm μ s (x + y) = condexpIndL1 hm μ s x + condexpIndL1 hm μ s y := 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/ContinuousMapDense.lean b/Mathlib/MeasureTheory/Function/ContinuousMapDense.lean
index be9517c3b1db9..633e66b2ab991 100644
--- a/Mathlib/MeasureTheory/Function/ContinuousMapDense.lean
+++ b/Mathlib/MeasureTheory/Function/ContinuousMapDense.lean
@@ -120,7 +120,7 @@ theorem exists_continuous_eLpNorm_sub_le_of_closed [μ.OuterRegular] (hp : p ≠
have : eLpNorm (v.indicator fun _x => (1 : ℝ)) p μ < ⊤ := by
refine (eLpNorm_indicator_const_le _ _).trans_lt ?_
simp only [lt_top_iff_ne_top, hμv.ne, nnnorm_one, ENNReal.coe_one, one_div, one_mul, Ne,
- ENNReal.rpow_eq_top_iff, inv_lt_zero, false_and_iff, or_false_iff, not_and, not_lt,
+ ENNReal.rpow_eq_top_iff, inv_lt_zero, false_and, or_false, not_and, not_lt,
ENNReal.toReal_nonneg, imp_true_iff]
refine (eLpNorm_mono fun x => ?_).trans_lt this
by_cases hx : x ∈ v
diff --git a/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean b/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean
index 00e13342ecf7e..f9a7daf12fa48 100644
--- a/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean
+++ b/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean
@@ -203,12 +203,13 @@ theorem TendstoInMeasure.exists_seq_tendsto_ae (hfg : TendstoInMeasure μ f atTo
refine ⟨max N (k - 1), fun n hn_ge => lt_of_le_of_lt ?_ hk_lt_ε⟩
specialize hNx n ((le_max_left _ _).trans hn_ge)
have h_inv_n_le_k : (2 : ℝ)⁻¹ ^ n ≤ 2 * (2 : ℝ)⁻¹ ^ k := by
- rw [mul_comm, ← inv_mul_le_iff' (zero_lt_two' ℝ)]
+ rw [mul_comm, ← inv_mul_le_iff₀' (zero_lt_two' ℝ)]
conv_lhs =>
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
@@ -306,7 +307,7 @@ theorem tendstoInMeasure_of_tendsto_eLpNorm_top {E} [NormedAddCommGroup E] {f :
specialize hfg (ENNReal.ofReal δ / 2)
(ENNReal.div_pos_iff.2 ⟨(ENNReal.ofReal_pos.2 hδ).ne.symm, ENNReal.two_ne_top⟩)
refine hfg.mono fun n hn => ?_
- simp only [true_and_iff, gt_iff_lt, zero_tsub, zero_le, zero_add, Set.mem_Icc,
+ simp only [gt_iff_lt, zero_tsub, zero_le, zero_add, Set.mem_Icc,
Pi.sub_apply] at *
have : essSup (fun x : α => (‖f n x - g x‖₊ : ℝ≥0∞)) μ < ENNReal.ofReal δ :=
lt_of_le_of_lt hn
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 999cef7eab633..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,15 +29,14 @@ 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 α}
section ConditionallyCompleteLattice
-variable [ConditionallyCompleteLattice β]
+variable [ConditionallyCompleteLattice β] {f : α → β}
/-- Essential supremum of `f` with respect to measure `μ`: the smallest `c : β` such that
`f x ≤ c` a.e. -/
@@ -68,6 +68,40 @@ theorem essSup_const (c : β) (hμ : μ ≠ 0) : essSup (fun _ : α => c) μ = c
theorem essInf_const (c : β) (hμ : μ ≠ 0) : essInf (fun _ : α => c) μ = c :=
have := NeZero.mk hμ; essInf_const' _
+section SMul
+variable {R : Type*} [Zero R] [SMulWithZero R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞]
+ [NoZeroSMulDivisors R ℝ≥0∞] {c : R}
+
+@[simp]
+lemma essSup_smul_measure (hc : c ≠ 0) (f : α → β) : essSup f (c • μ) = essSup f μ := by
+ simp_rw [essSup, Measure.ae_smul_measure_eq hc]
+
+end SMul
+
+variable [Nonempty α]
+
+lemma essSup_eq_ciSup (hμ : ∀ a, μ {a} ≠ 0) (hf : BddAbove (Set.range f)) :
+ essSup f μ = ⨆ a, f a := by rw [essSup, ae_eq_top.2 hμ, limsup_top_eq_ciSup hf]
+
+lemma essInf_eq_ciInf (hμ : ∀ a, μ {a} ≠ 0) (hf : BddBelow (Set.range f)) :
+ essInf f μ = ⨅ a, f a := by rw [essInf, ae_eq_top.2 hμ, liminf_top_eq_ciInf hf]
+
+variable [MeasurableSingletonClass α]
+
+@[simp] lemma essSup_count_eq_ciSup (hf : BddAbove (Set.range f)) :
+ essSup f .count = ⨆ a, f a := essSup_eq_ciSup (by simp) hf
+
+@[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
@@ -172,15 +206,11 @@ theorem essInf_antitone_measure {f : α → β} (hμν : μ ≪ ν) : essInf f
refine liminf_le_liminf_of_le (Measure.ae_le_iff_absolutelyContinuous.mpr hμν) ?_ ?_
all_goals isBoundedDefault
-theorem essSup_smul_measure {f : α → β} {c : ℝ≥0∞} (hc : c ≠ 0) :
- essSup f (c • μ) = essSup f μ := by
- simp_rw [essSup, Measure.ae_smul_measure_eq hc]
-
lemma essSup_eq_iSup (hμ : ∀ a, μ {a} ≠ 0) (f : α → β) : essSup f μ = ⨆ i, f i := by
- rw [essSup, ae_eq_top.2 hμ, limsup_top]
+ rw [essSup, ae_eq_top.2 hμ, limsup_top_eq_iSup]
lemma essInf_eq_iInf (hμ : ∀ a, μ {a} ≠ 0) (f : α → β) : essInf f μ = ⨅ i, f i := by
- rw [essInf, ae_eq_top.2 hμ, liminf_top]
+ rw [essInf, ae_eq_top.2 hμ, liminf_top_eq_iInf]
@[simp] lemma essSup_count [MeasurableSingletonClass α] (f : α → β) : essSup f .count = ⨆ i, f i :=
essSup_eq_iSup (by simp) _
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 38f7a8882415c..77a1878659c77 100644
--- a/Mathlib/MeasureTheory/Function/Jacobian.lean
+++ b/Mathlib/MeasureTheory/Function/Jacobian.lean
@@ -87,7 +87,7 @@ Change of variables in integrals
[Fremlin, *Measure Theory* (volume 2)][fremlin_vol2]
-/
-open MeasureTheory MeasureTheory.Measure Metric Filter Set FiniteDimensional Asymptotics
+open MeasureTheory MeasureTheory.Measure Metric Filter Set Module Asymptotics
TopologicalSpace
open scoped NNReal ENNReal Topology Pointwise
@@ -377,7 +377,7 @@ theorem addHaar_image_le_mul_of_det_lt (A : E →L[ℝ] E) {m : ℝ≥0}
have L : Tendsto (fun a => (m : ℝ≥0∞) * (μ s + a)) (𝓝[>] 0) (𝓝 (m * (μ s + 0))) := by
apply Tendsto.mono_left _ nhdsWithin_le_nhds
apply ENNReal.Tendsto.const_mul (tendsto_const_nhds.add tendsto_id)
- simp only [ENNReal.coe_ne_top, Ne, or_true_iff, not_false_iff]
+ simp only [ENNReal.coe_ne_top, Ne, or_true, not_false_iff]
rw [add_zero] at L
exact ge_of_tendsto L J
@@ -420,10 +420,10 @@ theorem mul_le_addHaar_image_of_lt_det (A : E →L[ℝ] E) {m : ℝ≥0}
-- record smallness conditions for `δ` that will be needed to apply `hδ₀` below.
have L1 : ∀ᶠ δ in 𝓝 (0 : ℝ≥0), Subsingleton E ∨ δ < ‖(B.symm : E →L[ℝ] E)‖₊⁻¹ := by
by_cases h : Subsingleton E
- · simp only [h, true_or_iff, eventually_const]
- simp only [h, false_or_iff]
+ · simp only [h, true_or, eventually_const]
+ simp only [h, false_or]
apply Iio_mem_nhds
- simpa only [h, false_or_iff, inv_pos] using B.subsingleton_or_nnnorm_symm_pos
+ simpa only [h, false_or, inv_pos] using B.subsingleton_or_nnnorm_symm_pos
have L2 :
∀ᶠ δ in 𝓝 (0 : ℝ≥0), ‖(B.symm : E →L[ℝ] E)‖₊ * (‖(B.symm : E →L[ℝ] E)‖₊⁻¹ - δ)⁻¹ * δ < δ₀ := by
have :
@@ -448,7 +448,7 @@ theorem mul_le_addHaar_image_of_lt_det (A : E →L[ℝ] E) {m : ℝ≥0}
mul_comm, ← ENNReal.coe_inv mpos.ne']
· apply Or.inl
simpa only [ENNReal.coe_eq_zero, Ne] using mpos.ne'
- · simp only [ENNReal.coe_ne_top, true_or_iff, Ne, not_false_iff]
+ · simp only [ENNReal.coe_ne_top, true_or, Ne, not_false_iff]
-- as `f⁻¹` is well approximated by `B⁻¹`, the conclusion follows from `hδ₀`
-- and our choice of `δ`.
exact hδ₀ _ _ ((hf'.to_inv h1δ).mono_num h2δ.le)
@@ -806,7 +806,7 @@ theorem addHaar_image_le_lintegral_abs_det_fderiv_aux1 (hs : MeasurableSet s)
rw [dist_eq_norm]
calc
‖B - A‖ ≤ (min δ δ'' : ℝ≥0) := hB
- _ ≤ δ'' := by simp only [le_refl, NNReal.coe_min, min_le_iff, or_true_iff]
+ _ ≤ δ'' := by simp only [le_refl, NNReal.coe_min, min_le_iff, or_true]
_ < δ' := half_lt_self δ'pos
· intro t g htg
exact h t g (htg.mono_num (min_le_left _ _))
@@ -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
@@ -941,7 +941,7 @@ theorem lintegral_abs_det_fderiv_le_addHaar_image_aux1 (hs : MeasurableSet s)
refine ⟨min δ δ'', lt_min δpos (half_pos δ'pos), ?_, ?_⟩
· intro B hB
apply I'' _ (hB.trans _)
- simp only [le_refl, NNReal.coe_min, min_le_iff, or_true_iff]
+ simp only [le_refl, NNReal.coe_min, min_le_iff, or_true]
· intro t g htg
rcases eq_or_ne (μ t) ∞ with (ht | ht)
· simp only [ht, εpos.ne', ENNReal.mul_top, ENNReal.coe_eq_zero, le_top, Ne,
@@ -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
@@ -1155,7 +1155,7 @@ theorem integrableOn_image_iff_integrableOn_abs_det_fderiv_smul (hs : Measurable
IntegrableOn g (f '' s) μ ↔ IntegrableOn (fun x => |(f' x).det| • g (f x)) s μ := by
rw [IntegrableOn, ← restrict_map_withDensity_abs_det_fderiv_eq_addHaar μ hs hf' hf,
(measurableEmbedding_of_fderivWithin hs hf' hf).integrable_map_iff]
- simp only [Set.restrict_eq, ← Function.comp.assoc, ENNReal.ofReal]
+ simp only [Set.restrict_eq, ← Function.comp_assoc, ENNReal.ofReal]
rw [← (MeasurableEmbedding.subtype_coe hs).integrable_map_iff, map_comap_subtype_coe hs,
restrict_withDensity hs, integrable_withDensity_iff_integrable_coe_smul₀]
· simp_rw [IntegrableOn, Real.coe_toNNReal _ (abs_nonneg _), Function.comp_apply]
@@ -1185,7 +1185,7 @@ theorem det_one_smulRight {𝕜 : Type*} [NormedField 𝕜] (v : 𝕜) :
Algebra.id.smul_eq_mul, one_mul, ContinuousLinearMap.coe_smul', Pi.smul_apply, mul_one]
rw [this, ContinuousLinearMap.det, ContinuousLinearMap.coe_smul,
ContinuousLinearMap.one_def, ContinuousLinearMap.coe_id, LinearMap.det_smul,
- FiniteDimensional.finrank_self, LinearMap.det_id, pow_one, mul_one]
+ Module.finrank_self, LinearMap.det_id, pow_one, mul_one]
/-- Integrability in the change of variable formula for differentiable functions (one-variable
version): if a function `f` is injective and differentiable on a measurable set `s ⊆ ℝ`, then a
diff --git a/Mathlib/MeasureTheory/Function/L1Space.lean b/Mathlib/MeasureTheory/Function/L1Space.lean
index 8951025e6bfb6..87c029742d760 100644
--- a/Mathlib/MeasureTheory/Function/L1Space.lean
+++ b/Mathlib/MeasureTheory/Function/L1Space.lean
@@ -438,9 +438,13 @@ theorem integrable_const [IsFiniteMeasure μ] (c : β) : Integrable (fun _ : α
integrable_const_iff.2 <| Or.inr <| measure_lt_top _ _
@[simp]
-theorem Integrable.of_finite [Finite α] [MeasurableSpace α] [MeasurableSingletonClass α]
- (μ : Measure α) [IsFiniteMeasure μ] (f : α → β) : Integrable (fun a ↦ f a) μ :=
- ⟨(StronglyMeasurable.of_finite f).aestronglyMeasurable, .of_finite⟩
+lemma Integrable.of_finite [Finite α] [MeasurableSingletonClass α] [IsFiniteMeasure μ] {f : α → β} :
+ Integrable f μ := ⟨.of_finite, .of_finite⟩
+
+/-- This lemma is a special case of `Integrable.of_finite`. -/
+-- Eternal deprecation for discoverability, don't remove
+@[deprecated Integrable.of_finite, nolint deprecatedNoSince]
+lemma Integrable.of_isEmpty [IsEmpty α] {f : α → β} : Integrable f μ := .of_finite
@[deprecated (since := "2024-02-05")] alias integrable_of_fintype := Integrable.of_finite
@@ -878,8 +882,7 @@ theorem integrable_withDensity_iff_integrable_coe_smul {f : α → ℝ≥0} (hf
{g : α → E} :
Integrable g (μ.withDensity fun x => f x) ↔ Integrable (fun x => (f x : ℝ) • g x) μ := by
by_cases H : AEStronglyMeasurable (fun x : α => (f x : ℝ) • g x) μ
- · simp only [Integrable, aestronglyMeasurable_withDensity_iff hf, HasFiniteIntegral, H,
- true_and_iff]
+ · simp only [Integrable, aestronglyMeasurable_withDensity_iff hf, HasFiniteIntegral, H]
rw [lintegral_withDensity_eq_lintegral_mul₀' hf.coe_nnreal_ennreal.aemeasurable]
· rw [iff_iff_eq]
congr
@@ -889,7 +892,7 @@ theorem integrable_withDensity_iff_integrable_coe_smul {f : α → ℝ≥0} (hf
convert H.ennnorm using 1
ext1 x
simp only [nnnorm_smul, NNReal.nnnorm_eq, coe_mul]
- · simp only [Integrable, aestronglyMeasurable_withDensity_iff hf, H, false_and_iff]
+ · simp only [Integrable, aestronglyMeasurable_withDensity_iff hf, H, false_and]
theorem integrable_withDensity_iff_integrable_smul {f : α → ℝ≥0} (hf : Measurable f) {g : α → E} :
Integrable g (μ.withDensity fun x => f x) ↔ Integrable (fun x => f x • g x) μ :=
@@ -1372,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/LocallyIntegrable.lean b/Mathlib/MeasureTheory/Function/LocallyIntegrable.lean
index 7ef4263f03c4a..0d8110dc76977 100644
--- a/Mathlib/MeasureTheory/Function/LocallyIntegrable.lean
+++ b/Mathlib/MeasureTheory/Function/LocallyIntegrable.lean
@@ -127,10 +127,10 @@ theorem LocallyIntegrableOn.aestronglyMeasurable [SecondCountableTopology X]
rw [this, aestronglyMeasurable_iUnion_iff]
exact fun i : ℕ => (hu i).aestronglyMeasurable
-/-- If `s` is either open, or closed, then `f` is locally integrable on `s` iff it is integrable on
-every compact subset contained in `s`. -/
+/-- If `s` is locally closed (e.g. open or closed), then `f` is locally integrable on `s` iff it is
+integrable on every compact subset contained in `s`. -/
theorem locallyIntegrableOn_iff [LocallyCompactSpace X] (hs : IsLocallyClosed s) :
- LocallyIntegrableOn f s μ ↔ ∀ (k : Set X), k ⊆ s → (IsCompact k → IntegrableOn f k μ) := by
+ LocallyIntegrableOn f s μ ↔ ∀ (k : Set X), k ⊆ s → IsCompact k → IntegrableOn f k μ := by
refine ⟨fun hf k hk ↦ hf.integrableOn_compact_subset hk, fun hf x hx ↦ ?_⟩
rcases hs with ⟨U, Z, hU, hZ, rfl⟩
rcases exists_compact_subset hU hx.1 with ⟨K, hK, hxK, hKU⟩
@@ -498,7 +498,7 @@ theorem MonotoneOn.integrableOn_of_measure_ne_top (hmono : MonotoneOn f s) {a b
have : IsBounded (f '' s) := Metric.isBounded_of_bddAbove_of_bddBelow habove hbelow
rcases isBounded_iff_forall_norm_le.mp this with ⟨C, hC⟩
have A : IntegrableOn (fun _ => C) s μ := by
- simp only [hs.lt_top, integrableOn_const, or_true_iff]
+ simp only [hs.lt_top, integrableOn_const, or_true]
exact
Integrable.mono' A (aemeasurable_restrict_of_monotoneOn h's hmono).aestronglyMeasurable
((ae_restrict_iff' h's).mpr <| ae_of_all _ fun y hy => hC (f y) (mem_image_of_mem f hy))
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 e7150f18e4c57..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, *]
@@ -404,18 +404,18 @@ theorem eLpNorm_const_lt_top_iff {p : ℝ≥0∞} {c : F} (hp_ne_zero : p ≠ 0)
eLpNorm (fun _ : α => c) p μ < ∞ ↔ c = 0 ∨ μ Set.univ < ∞ := by
have hp : 0 < p.toReal := ENNReal.toReal_pos hp_ne_zero hp_ne_top
by_cases hμ : μ = 0
- · simp only [hμ, Measure.coe_zero, Pi.zero_apply, or_true_iff, ENNReal.zero_lt_top,
+ · simp only [hμ, Measure.coe_zero, Pi.zero_apply, or_true, ENNReal.zero_lt_top,
eLpNorm_measure_zero]
by_cases hc : c = 0
- · simp only [hc, true_or_iff, eq_self_iff_true, ENNReal.zero_lt_top, eLpNorm_zero']
+ · simp only [hc, true_or, eq_self_iff_true, ENNReal.zero_lt_top, eLpNorm_zero']
rw [eLpNorm_const' c hp_ne_zero hp_ne_top]
by_cases hμ_top : μ Set.univ = ∞
· simp [hc, hμ_top, hp]
rw [ENNReal.mul_lt_top_iff]
- simp only [true_and_iff, one_div, ENNReal.rpow_eq_zero_iff, hμ, false_or_iff, or_false_iff,
+ simp only [true_and, one_div, ENNReal.rpow_eq_zero_iff, hμ, false_or, or_false,
ENNReal.coe_lt_top, nnnorm_eq_zero, ENNReal.coe_eq_zero,
- MeasureTheory.Measure.measure_univ_eq_zero, hp, inv_lt_zero, hc, and_false_iff, false_and_iff,
- inv_pos, or_self_iff, hμ_top, Ne.lt_top hμ_top, iff_true_iff]
+ MeasureTheory.Measure.measure_univ_eq_zero, hp, inv_lt_zero, hc, false_and,
+ inv_pos, or_self_iff, hμ_top, Ne.lt_top hμ_top, iff_true]
exact ENNReal.rpow_lt_top_of_nonneg (inv_nonneg.mpr hp.le) hμ_top
@[deprecated (since := "2024-07-27")]
@@ -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
@@ -794,10 +801,16 @@ theorem eLpNorm'_smul_measure {p : ℝ} (hp : 0 ≤ p) {f : α → F} (c : ℝ
@[deprecated (since := "2024-07-27")]
alias snorm'_smul_measure := eLpNorm'_smul_measure
-theorem eLpNormEssSup_smul_measure {f : α → F} {c : ℝ≥0∞} (hc : c ≠ 0) :
+section SMul
+variable {R : Type*} [Zero R] [SMulWithZero R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞]
+ [NoZeroSMulDivisors R ℝ≥0∞] {c : R}
+
+@[simp] lemma eLpNormEssSup_smul_measure (hc : c ≠ 0) (f : α → F) :
eLpNormEssSup f (c • μ) = eLpNormEssSup f μ := by
simp_rw [eLpNormEssSup]
- exact essSup_smul_measure hc
+ exact essSup_smul_measure hc _
+
+end SMul
@[deprecated (since := "2024-07-27")]
alias snormEssSup_smul_measure := eLpNormEssSup_smul_measure
@@ -1107,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
@@ -1267,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
@@ -1319,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/ChebyshevMarkov.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/ChebyshevMarkov.lean
index 32599fde917d0..6248e4a2c5925 100644
--- a/Mathlib/MeasureTheory/Function/LpSeminorm/ChebyshevMarkov.lean
+++ b/Mathlib/MeasureTheory/Function/LpSeminorm/ChebyshevMarkov.lean
@@ -34,7 +34,7 @@ theorem mul_meas_ge_le_pow_eLpNorm (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞
have : 1 / p.toReal * p.toReal = 1 := by
refine one_div_mul_cancel ?_
rw [Ne, ENNReal.toReal_eq_zero_iff]
- exact not_or_of_not hp_ne_zero hp_ne_top
+ exact not_or_intro hp_ne_zero hp_ne_top
rw [← ENNReal.rpow_one (ε * μ { x | ε ≤ (‖f x‖₊ : ℝ≥0∞) ^ p.toReal }), ← this, ENNReal.rpow_mul]
gcongr
exact pow_mul_meas_ge_le_eLpNorm μ hp_ne_zero hp_ne_top hf ε
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 c44471de29253..adb2b6dba2e06 100644
--- a/Mathlib/MeasureTheory/Function/LpSpace.lean
+++ b/Mathlib/MeasureTheory/Function/LpSpace.lean
@@ -13,7 +13,7 @@ import Mathlib.MeasureTheory.Function.LpSeminorm.TriangleInequality
import Mathlib.MeasureTheory.Measure.OpenPos
import Mathlib.MeasureTheory.Measure.Typeclasses
import Mathlib.Analysis.NormedSpace.OperatorNorm.NormedSpace
-import Mathlib.Topology.ContinuousFunction.Compact
+import Mathlib.Topology.ContinuousMap.Compact
import Mathlib.Order.Filter.IndicatorFunction
/-!
@@ -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'.uniformEmbedding 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 90386bdd03776..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,9 +979,9 @@ 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_iff, exists_prop,
+ 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']
variable {m : MeasurableSpace α} [Zero β] [Zero γ] {μ : Measure α} {f : α →ₛ β}
diff --git a/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean b/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean
index 679c905a01e48..920ebf5d42e0d 100644
--- a/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean
+++ b/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean
@@ -23,7 +23,7 @@ by a sequence of simple functions.
measurable and `Memℒp` (for `p < ∞`), then the simple functions
`SimpleFunc.approxOn f hf s 0 h₀ n` may be considered as elements of `Lp E p μ`, and they tend
in Lᵖ to `f`.
-* `Lp.simpleFunc.denseEmbedding`: the embedding `coeToLp` of the `Lp` simple functions into
+* `Lp.simpleFunc.isDenseEmbedding`: the embedding `coeToLp` of the `Lp` simple functions into
`Lp` is dense.
* `Lp.simpleFunc.induction`, `Lp.induction`, `Memℒp.induction`, `Integrable.induction`: to prove
a predicate for all elements of one of these classes of functions, it suffices to check that it
@@ -299,7 +299,7 @@ theorem measure_preimage_lt_top_of_memℒp (hp_pos : p ≠ 0) (hp_ne_top : p ≠
· suffices h_empty : f ⁻¹' {y} = ∅ by
rw [h_empty, measure_empty]; exact ENNReal.coe_lt_top
ext1 x
- rw [Set.mem_preimage, Set.mem_singleton_iff, mem_empty_iff_false, iff_false_iff]
+ rw [Set.mem_preimage, Set.mem_singleton_iff, mem_empty_iff_false, iff_false]
refine fun hxy => hyf ?_
rw [mem_range, Set.mem_range]
exact ⟨x, hxy⟩
@@ -679,16 +679,21 @@ variable [Fact (1 ≤ p)]
protected theorem uniformContinuous : UniformContinuous ((↑) : Lp.simpleFunc E p μ → Lp E p μ) :=
uniformContinuous_comap
-protected theorem uniformEmbedding : UniformEmbedding ((↑) : Lp.simpleFunc E p μ → Lp E p μ) :=
- uniformEmbedding_comap Subtype.val_injective
+lemma isUniformEmbedding : IsUniformEmbedding ((↑) : Lp.simpleFunc E p μ → Lp E p μ) :=
+ isUniformEmbedding_comap Subtype.val_injective
-protected theorem uniformInducing : UniformInducing ((↑) : Lp.simpleFunc E p μ → Lp E p μ) :=
- simpleFunc.uniformEmbedding.toUniformInducing
+@[deprecated (since := "2024-10-01")] alias uniformEmbedding := isUniformEmbedding
-protected theorem denseEmbedding (hp_ne_top : p ≠ ∞) :
- DenseEmbedding ((↑) : Lp.simpleFunc E p μ → Lp E p μ) := by
+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
borelize E
- apply simpleFunc.uniformEmbedding.denseEmbedding
+ apply simpleFunc.isUniformEmbedding.isDenseEmbedding
intro f
rw [mem_closure_iff_seq_limit]
have hfi' : Memℒp f p μ := Lp.memℒp f
@@ -703,13 +708,16 @@ protected theorem denseEmbedding (hp_ne_top : p ≠ ∞) :
convert SimpleFunc.tendsto_approxOn_range_Lp hp_ne_top (Lp.stronglyMeasurable f).measurable hfi'
rw [toLp_coeFn f (Lp.memℒp f)]
-protected theorem denseInducing (hp_ne_top : p ≠ ∞) :
- DenseInducing ((↑) : Lp.simpleFunc E p μ → Lp E p μ) :=
- (simpleFunc.denseEmbedding hp_ne_top).toDenseInducing
+@[deprecated (since := "2024-09-30")]
+alias denseEmbedding := isDenseEmbedding
+
+protected theorem isDenseInducing (hp_ne_top : p ≠ ∞) :
+ IsDenseInducing ((↑) : Lp.simpleFunc E p μ → Lp E p μ) :=
+ (simpleFunc.isDenseEmbedding hp_ne_top).toIsDenseInducing
protected theorem denseRange (hp_ne_top : p ≠ ∞) :
DenseRange ((↑) : Lp.simpleFunc E p μ → Lp E p μ) :=
- (simpleFunc.denseInducing hp_ne_top).dense
+ (simpleFunc.isDenseInducing hp_ne_top).dense
protected theorem dense (hp_ne_top : p ≠ ∞) : Dense (Lp.simpleFunc E p μ : Set (Lp E p μ)) := by
simpa only [denseRange_subtype_val] using simpleFunc.denseRange (E := E) (μ := μ) hp_ne_top
@@ -734,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 _ _
@@ -773,7 +780,7 @@ theorem denseRange_coeSimpleFuncNonnegToLpNonneg [hp : Fact (1 ≤ p)] (hp_ne_to
rw [mem_closure_iff_seq_limit]
have hg_memℒp : Memℒp (g : α → G) p μ := Lp.memℒp (g : Lp G p μ)
have zero_mem : (0 : G) ∈ (range (g : α → G) ∪ {0} : Set G) ∩ { y | 0 ≤ y } := by
- simp only [union_singleton, mem_inter_iff, mem_insert_iff, eq_self_iff_true, true_or_iff,
+ simp only [union_singleton, mem_inter_iff, mem_insert_iff, eq_self_iff_true, true_or,
mem_setOf_eq, le_refl, and_self_iff]
have : SeparableSpace ((range (g : α → G) ∪ {0}) ∩ { y | 0 ≤ y } : Set G) := by
apply IsSeparable.separableSpace
diff --git a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean
index b2fb9342d5eb9..08b42756f8fae 100644
--- a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean
+++ b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean
@@ -127,7 +127,7 @@ theorem SimpleFunc.stronglyMeasurable {α β} {_ : MeasurableSpace α} [Topologi
@[nontriviality]
theorem StronglyMeasurable.of_finite [Finite α] {_ : MeasurableSpace α}
[MeasurableSingletonClass α] [TopologicalSpace β]
- (f : α → β) : StronglyMeasurable f :=
+ {f : α → β} : StronglyMeasurable f :=
⟨fun _ => SimpleFunc.ofFinite f, fun _ => tendsto_const_nhds⟩
@[deprecated (since := "2024-02-05")]
@@ -136,7 +136,7 @@ alias stronglyMeasurable_of_fintype := StronglyMeasurable.of_finite
@[deprecated StronglyMeasurable.of_finite (since := "2024-02-06")]
theorem stronglyMeasurable_of_isEmpty [IsEmpty α] {_ : MeasurableSpace α} [TopologicalSpace β]
(f : α → β) : StronglyMeasurable f :=
- .of_finite f
+ .of_finite
theorem stronglyMeasurable_const {α β} {_ : MeasurableSpace α} [TopologicalSpace β] {b : β} :
StronglyMeasurable fun _ : α => b :=
@@ -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]
@@ -887,7 +887,7 @@ theorem stronglyMeasurable_of_measurableSpace_le_on {α E} {m m₂ : MeasurableS
exact MeasurableSet.empty
ext1 y
simp only [mem_inter_iff, mem_preimage, mem_singleton_iff, mem_compl_iff,
- mem_empty_iff_false, iff_false_iff, not_and, not_not_mem]
+ mem_empty_iff_false, iff_false, not_and, not_not_mem]
refine Function.mtr fun hys => ?_
rw [hg_seq_zero y hys n]
exact Ne.symm hx
@@ -1108,7 +1108,7 @@ variable {m : MeasurableSpace α} {μ ν : Measure α} [TopologicalSpace β] [To
{f g : α → β}
lemma of_finite [DiscreteMeasurableSpace α] [Finite α] : AEStronglyMeasurable f μ :=
- ⟨_, .of_finite _, ae_eq_rfl⟩
+ ⟨_, .of_finite, ae_eq_rfl⟩
section Mk
@@ -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/UnifTight.lean b/Mathlib/MeasureTheory/Function/UnifTight.lean
index cc50e8c1de965..deaea6b197602 100644
--- a/Mathlib/MeasureTheory/Function/UnifTight.lean
+++ b/Mathlib/MeasureTheory/Function/UnifTight.lean
@@ -76,7 +76,8 @@ namespace UnifTight
theorem eventually_cofinite_indicator (hf : UnifTight f p μ) {ε : ℝ≥0∞} (hε : ε ≠ 0) :
∀ᶠ s in μ.cofinite.smallSets, ∀ i, eLpNorm (s.indicator (f i)) p μ ≤ ε := by
- by_cases hε_top : ε = ∞; subst hε_top; simp
+ by_cases hε_top : ε = ∞
+ · subst hε_top; simp
rcases hf (pos_iff_ne_zero.2 (toNNReal_ne_zero.mpr ⟨hε,hε_top⟩)) with ⟨s, hμs, hfs⟩
refine (eventually_smallSets' ?_).2 ⟨sᶜ, ?_, fun i ↦ (coe_toNNReal hε_top) ▸ hfs i⟩
· intro s t hst ht i
diff --git a/Mathlib/MeasureTheory/Function/UniformIntegrable.lean b/Mathlib/MeasureTheory/Function/UniformIntegrable.lean
index b55ab2cc0293d..cd1ec970e0581 100644
--- a/Mathlib/MeasureTheory/Function/UniformIntegrable.lean
+++ b/Mathlib/MeasureTheory/Function/UniformIntegrable.lean
@@ -213,7 +213,7 @@ theorem Memℒp.integral_indicator_norm_ge_le (hf : Memℒp f 1 μ) (hmeas : Str
· assumption
rw [ENNReal.tendsto_atTop_zero] at this
obtain ⟨M, hM⟩ := this (ENNReal.ofReal ε) (ENNReal.ofReal_pos.2 hε)
- simp only [true_and_iff, zero_tsub, zero_le, sub_zero, zero_add, coe_nnnorm,
+ simp only [zero_tsub, zero_le, sub_zero, zero_add, coe_nnnorm,
Set.mem_Icc] at hM
refine ⟨M, ?_⟩
convert hM M le_rfl
@@ -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/Action.lean b/Mathlib/MeasureTheory/Group/Action.lean
index 28b06957d5abb..04f432bce67b9 100644
--- a/Mathlib/MeasureTheory/Group/Action.lean
+++ b/Mathlib/MeasureTheory/Group/Action.lean
@@ -226,23 +226,17 @@ theorem smulInvariantMeasure_tfae :
∀ (c : G) (s), μ (c • s) = μ s,
∀ c : G, Measure.map (c • ·) μ = μ,
∀ c : G, MeasurePreserving (c • ·) μ μ] := by
- tfae_have 1 ↔ 2
- · exact ⟨fun h => h.1, fun h => ⟨h⟩⟩
- tfae_have 1 → 6
- · intro h c
- exact (measurePreserving_smul c μ).map_eq
- tfae_have 6 → 7
- · exact fun H c => ⟨measurable_const_smul c, H c⟩
- tfae_have 7 → 4
- · exact fun H c => (H c).measure_preimage_emb (measurableEmbedding_const_smul c)
+ tfae_have 1 ↔ 2 := ⟨fun h => h.1, fun h => ⟨h⟩⟩
+ tfae_have 1 → 6 := fun h c => (measurePreserving_smul c μ).map_eq
+ tfae_have 6 → 7 := fun H c => ⟨measurable_const_smul c, H c⟩
+ tfae_have 7 → 4 := fun H c => (H c).measure_preimage_emb (measurableEmbedding_const_smul c)
tfae_have 4 → 5
- · exact fun H c s => by
- rw [← preimage_smul_inv]
- apply H
- tfae_have 5 → 3
- · exact fun H c s _ => H c s
+ | H, c, s => by
+ rw [← preimage_smul_inv]
+ apply H
+ tfae_have 5 → 3 := fun H c s _ => H c s
tfae_have 3 → 2
- · intro H c s hs
+ | H, c, s, hs => by
rw [preimage_smul]
exact H c⁻¹ s hs
tfae_finish
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/Defs.lean b/Mathlib/MeasureTheory/Group/Defs.lean
index 35caa44a94cae..c68e87b9ad78f 100644
--- a/Mathlib/MeasureTheory/Group/Defs.lean
+++ b/Mathlib/MeasureTheory/Group/Defs.lean
@@ -82,15 +82,20 @@ class IsAddRightInvariant [Add G] (μ : Measure G) : Prop where
class IsMulRightInvariant [Mul G] (μ : Measure G) : Prop where
map_mul_right_eq_self : ∀ g : G, map (· * g) μ = μ
-variable [Mul G] {μ : Measure G}
+variable {μ : Measure G}
@[to_additive]
-instance IsMulLeftInvariant.smulInvariantMeasure [IsMulLeftInvariant μ] :
+instance IsMulLeftInvariant.smulInvariantMeasure [Mul G] [IsMulLeftInvariant μ] :
SMulInvariantMeasure G G μ :=
⟨fun _x _s hs => measure_preimage_of_map_eq_self (map_mul_left_eq_self _) hs.nullMeasurableSet⟩
@[to_additive]
-instance IsMulRightInvariant.toSMulInvariantMeasure_op [μ.IsMulRightInvariant] :
+instance [Monoid G] (s : Submonoid G) [IsMulLeftInvariant μ] :
+ SMulInvariantMeasure {x // x ∈ s} G μ :=
+ ⟨fun ⟨x, _⟩ _ h ↦ IsMulLeftInvariant.smulInvariantMeasure.1 x h⟩
+
+@[to_additive]
+instance IsMulRightInvariant.toSMulInvariantMeasure_op [Mul G] [μ.IsMulRightInvariant] :
SMulInvariantMeasure Gᵐᵒᵖ G μ :=
⟨fun _x _s hs => measure_preimage_of_map_eq_self (map_mul_right_eq_self _) hs.nullMeasurableSet⟩
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/GeometryOfNumbers.lean b/Mathlib/MeasureTheory/Group/GeometryOfNumbers.lean
index fb1be755747f1..4f7644744e85c 100644
--- a/Mathlib/MeasureTheory/Group/GeometryOfNumbers.lean
+++ b/Mathlib/MeasureTheory/Group/GeometryOfNumbers.lean
@@ -36,7 +36,7 @@ Hermann Minkowski.
namespace MeasureTheory
-open ENNReal FiniteDimensional MeasureTheory MeasureTheory.Measure Set Filter
+open ENNReal Module MeasureTheory MeasureTheory.Measure Set Filter
open scoped Pointwise NNReal
@@ -134,7 +134,7 @@ theorem exists_ne_zero_mem_lattice_of_measure_mul_two_pow_le_measure [NormedAddC
rw [show μ s < _ ↔ 1 * μ s < _ by rw [one_mul]]
refine (mul_lt_mul_right h_mes (ne_of_lt h_cpt.measure_lt_top)).mpr ?_
rw [ofReal_pow (NNReal.coe_nonneg _)]
- refine one_lt_pow ?_ (ne_of_gt finrank_pos)
+ refine one_lt_pow₀ ?_ (ne_of_gt finrank_pos)
simp [(exists_seq_strictAnti_tendsto (0 : ℝ≥0)).choose_spec.2.1 n]
end MeasureTheory
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 7d2ff6e601dcc..1dbf773aa37b2 100644
--- a/Mathlib/MeasureTheory/Group/Measure.lean
+++ b/Mathlib/MeasureTheory/Group/Measure.lean
@@ -3,15 +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.Dynamics.Ergodic.MeasurePreserving
-import Mathlib.GroupTheory.GroupAction.Hom
-import Mathlib.MeasureTheory.Constructions.Prod.Basic
import Mathlib.MeasureTheory.Group.Action
-import Mathlib.MeasureTheory.Group.MeasurableEquiv
-import Mathlib.MeasureTheory.Measure.OpenPos
-import Mathlib.MeasureTheory.Measure.Regular
-import Mathlib.Topology.ContinuousFunction.CocompactMap
-import Mathlib.Topology.Homeomorph
+import Mathlib.MeasureTheory.Measure.Prod
+import Mathlib.Topology.ContinuousMap.CocompactMap
/-!
# Measures on Groups
@@ -34,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
@@ -524,7 +518,7 @@ theorem null_iff_of_isMulLeftInvariant [Regular μ] {s : Set G} (hs : IsOpen s)
μ s = 0 ↔ s = ∅ ∨ μ = 0 := by
rcases eq_zero_or_neZero μ with rfl|hμ
· simp
- · simp only [or_false_iff, hs.measure_eq_zero_iff μ, NeZero.ne μ]
+ · simp only [or_false, hs.measure_eq_zero_iff μ, NeZero.ne μ]
@[to_additive]
theorem measure_ne_zero_iff_nonempty_of_isMulLeftInvariant [Regular μ] (hμ : μ ≠ 0) {s : Set G}
@@ -781,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 775c06472f6f6..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. -/
@@ -243,7 +243,7 @@ theorem absolutelyContinuous_of_isMulLeftInvariant [IsMulLeftInvariant ν] (hν
refine AbsolutelyContinuous.mk fun s sm hνs => ?_
have h1 := measure_mul_lintegral_eq μ ν sm 1 measurable_one
simp_rw [Pi.one_apply, lintegral_one, mul_one, (measure_mul_right_null ν _).mpr hνs,
- lintegral_zero, mul_eq_zero (M₀ := ℝ≥0∞), measure_univ_eq_zero.not.mpr hν, or_false_iff] at h1
+ lintegral_zero, mul_eq_zero (M₀ := ℝ≥0∞), measure_univ_eq_zero.not.mpr hν, or_false] at h1
exact h1
section SigmaFinite
@@ -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 e26b72d02951b..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]
@@ -1044,7 +1040,7 @@ theorem integral_eq_lintegral_of_nonneg_ae {f : α → ℝ} (hf : 0 ≤ᵐ[μ] f
· exact measurable_ofReal.comp_aemeasurable hfm.aemeasurable.neg
rw [h_min, zero_toReal, _root_.sub_zero]
· rw [integral_undef hfi]
- simp_rw [Integrable, hfm, hasFiniteIntegral_iff_norm, lt_top_iff_ne_top, Ne, true_and_iff,
+ simp_rw [Integrable, hfm, hasFiniteIntegral_iff_norm, lt_top_iff_ne_top, Ne, true_and,
Classical.not_not] at hfi
have : ∫⁻ a : α, ENNReal.ofReal (f a) ∂μ = ∫⁻ a, ENNReal.ofReal ‖f a‖ ∂μ := by
refine lintegral_congr_ae (hf.mono fun a h => ?_)
@@ -1123,7 +1119,7 @@ theorem integral_nonpos {f : α → ℝ} (hf : f ≤ 0) : ∫ a, f a ∂μ ≤ 0
theorem integral_eq_zero_iff_of_nonneg_ae {f : α → ℝ} (hf : 0 ≤ᵐ[μ] f) (hfi : Integrable f μ) :
∫ x, f x ∂μ = 0 ↔ f =ᵐ[μ] 0 := by
simp_rw [integral_eq_lintegral_of_nonneg_ae hf hfi.1, ENNReal.toReal_eq_zero_iff,
- ← ENNReal.not_lt_top, ← hasFiniteIntegral_iff_ofReal hf, hfi.2, not_true_eq_false, or_false_iff]
+ ← ENNReal.not_lt_top, ← hasFiniteIntegral_iff_ofReal hf, hfi.2, not_true_eq_false, or_false]
-- Porting note: split into parts, to make `rw` and `simp` work
rw [lintegral_eq_zero_iff']
· rw [← hf.le_iff_eq, Filter.EventuallyEq, Filter.EventuallyLE]
@@ -1472,6 +1468,9 @@ theorem integral_zero_measure {m : MeasurableSpace α} (f : α → G) :
theorem setIntegral_zero_measure (f : α → G) {μ : Measure α} {s : Set α} (hs : μ s = 0) :
∫ x in s, f x ∂μ = 0 := Measure.restrict_eq_zero.mpr hs ▸ integral_zero_measure f
+lemma integral_of_isEmpty [IsEmpty α] {f : α → G} : ∫ x, f x ∂μ = 0 :=
+ μ.eq_zero_of_isEmpty ▸ integral_zero_measure _
+
theorem integral_finset_sum_measure {ι} {m : MeasurableSpace α} {f : α → G} {μ : ι → Measure α}
{s : Finset ι} (hf : ∀ i ∈ s, Integrable f (μ i)) :
∫ a, f a ∂(∑ i ∈ s, μ i) = ∑ i ∈ s, ∫ a, f a ∂μ i := by
@@ -1575,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
@@ -1785,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/FundThmCalculus.lean b/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean
index d84c9db973bd2..4a55c25968c90 100644
--- a/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean
+++ b/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean
@@ -591,7 +591,7 @@ theorem integral_hasStrictFDerivAt_of_tendsto_ae (hf : IntervalIntegrable f volu
(continuous_snd.snd.tendsto ((a, b), (a, b)))
(continuous_fst.snd.tendsto ((a, b), (a, b)))
refine (this.congr_left ?_).trans_isBigO ?_
- · intro x; simp [sub_smul]; abel
+ · intro x; simp [sub_smul]
· exact isBigO_fst_prod.norm_left.add isBigO_snd_prod.norm_left
/-- **Fundamental theorem of calculus-1**, strict differentiability in both endpoints.
@@ -794,7 +794,7 @@ theorem integral_hasFDerivWithinAt_of_tendsto_ae (hf : IntervalIntegrable f volu
(tendsto_const_pure.mono_right FTCFilter.pure_le : Tendsto _ _ (𝓝[s] a)) tendsto_fst
(tendsto_const_pure.mono_right FTCFilter.pure_le : Tendsto _ _ (𝓝[t] b)) tendsto_snd
refine .of_isLittleO <| (this.congr_left ?_).trans_isBigO ?_
- · intro x; simp [sub_smul]; abel
+ · intro x; simp [sub_smul]
· exact isBigO_fst_prod.norm_left.add isBigO_snd_prod.norm_left
/-- Let `f` be a measurable function integrable on `a..b`. The function `(u, v) ↦ ∫ x in u..v, f x`
@@ -1002,7 +1002,7 @@ theorem sub_le_integral_of_hasDeriv_right_of_le_Ico (hab : a ≤ b)
_ ≤ ∫ w in t..u, (G' w).toReal := by
rw [intervalIntegral.integral_of_le hu.1.le, ← integral_Icc_eq_integral_Ioc]
apply setIntegral_mono_ae_restrict
- · simp only [integrableOn_const, Real.volume_Icc, ENNReal.ofReal_lt_top, or_true_iff]
+ · simp only [integrableOn_const, Real.volume_Icc, ENNReal.ofReal_lt_top, or_true]
· exact IntegrableOn.mono_set G'int I
· have C1 : ∀ᵐ x : ℝ ∂volume.restrict (Icc t u), G' x < ∞ :=
ae_mono (Measure.restrict_mono I le_rfl) G'lt_top
@@ -1252,10 +1252,10 @@ theorem intervalIntegrable_deriv_of_nonneg (hcont : ContinuousOn g (uIcc a b))
(hpos : ∀ x ∈ Ioo (min a b) (max a b), 0 ≤ g' x) : IntervalIntegrable g' volume a b := by
rcases le_total a b with hab | hab
· simp only [uIcc_of_le, min_eq_left, max_eq_right, hab, IntervalIntegrable, hab,
- Ioc_eq_empty_of_le, integrableOn_empty, and_true_iff] at hcont hderiv hpos ⊢
+ Ioc_eq_empty_of_le, integrableOn_empty, and_true] at hcont hderiv hpos ⊢
exact integrableOn_deriv_of_nonneg hcont hderiv hpos
· simp only [uIcc_of_ge, min_eq_right, max_eq_left, hab, IntervalIntegrable, Ioc_eq_empty_of_le,
- integrableOn_empty, true_and_iff] at hcont hderiv hpos ⊢
+ integrableOn_empty, true_and] at hcont hderiv hpos ⊢
exact integrableOn_deriv_of_nonneg hcont hderiv hpos
/-!
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/Indicator.lean b/Mathlib/MeasureTheory/Integral/Indicator.lean
index fb1889b30f770..071281c1dc5e1 100644
--- a/Mathlib/MeasureTheory/Integral/Indicator.lean
+++ b/Mathlib/MeasureTheory/Integral/Indicator.lean
@@ -39,21 +39,25 @@ variable {ι : Type*} (L : Filter ι) [IsCountablyGenerated L] {As : ι → Set
/-- If the indicators of measurable sets `Aᵢ` tend pointwise to the indicator of a set `A`
and we eventually have `Aᵢ ⊆ B` for some set `B` of finite measure, then the measures of `Aᵢ`
tend to the measure of `A`. -/
-lemma tendsto_measure_of_tendsto_indicator [NeBot L] {μ : Measure α}
+lemma tendsto_measure_of_tendsto_indicator {μ : Measure α}
(As_mble : ∀ i, MeasurableSet (As i)) {B : Set α} (B_mble : MeasurableSet B)
(B_finmeas : μ B ≠ ∞) (As_le_B : ∀ᶠ i in L, As i ⊆ B)
(h_lim : ∀ x, ∀ᶠ i in L, x ∈ As i ↔ x ∈ A) :
Tendsto (fun i ↦ μ (As i)) L (𝓝 (μ A)) := by
+ rcases L.eq_or_neBot with rfl | _
+ · exact tendsto_bot
apply tendsto_measure_of_ae_tendsto_indicator L ?_ As_mble B_mble B_finmeas As_le_B
(ae_of_all μ h_lim)
exact measurableSet_of_tendsto_indicator L As_mble h_lim
/-- If `μ` is a finite measure and the indicators of measurable sets `Aᵢ` tend pointwise to
the indicator of a set `A`, then the measures `μ Aᵢ` tend to the measure `μ A`. -/
-lemma tendsto_measure_of_tendsto_indicator_of_isFiniteMeasure [NeBot L]
+lemma tendsto_measure_of_tendsto_indicator_of_isFiniteMeasure
(μ : Measure α) [IsFiniteMeasure μ] (As_mble : ∀ i, MeasurableSet (As i))
(h_lim : ∀ x, ∀ᶠ i in L, x ∈ As i ↔ x ∈ A) :
Tendsto (fun i ↦ μ (As i)) L (𝓝 (μ A)) := by
+ rcases L.eq_or_neBot with rfl | _
+ · exact tendsto_bot
apply tendsto_measure_of_ae_tendsto_indicator_of_isFiniteMeasure L ?_ As_mble (ae_of_all μ h_lim)
exact measurableSet_of_tendsto_indicator L As_mble h_lim
diff --git a/Mathlib/MeasureTheory/Integral/IntegrableOn.lean b/Mathlib/MeasureTheory/Integral/IntegrableOn.lean
index 20ef2efcbbe01..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 : α → β}
@@ -622,7 +622,7 @@ theorem integrableOn_Icc_iff_integrableOn_Ioc' (ha : μ {a} ≠ ∞) :
IntegrableOn f (Icc a b) μ ↔ IntegrableOn f (Ioc a b) μ := by
by_cases hab : a ≤ b
· rw [← Ioc_union_left hab, integrableOn_union,
- eq_true (integrableOn_singleton_iff.mpr <| Or.inr ha.lt_top), and_true_iff]
+ eq_true (integrableOn_singleton_iff.mpr <| Or.inr ha.lt_top), and_true]
· rw [Icc_eq_empty hab, Ioc_eq_empty]
contrapose! hab
exact hab.le
@@ -631,7 +631,7 @@ theorem integrableOn_Icc_iff_integrableOn_Ico' (hb : μ {b} ≠ ∞) :
IntegrableOn f (Icc a b) μ ↔ IntegrableOn f (Ico a b) μ := by
by_cases hab : a ≤ b
· rw [← Ico_union_right hab, integrableOn_union,
- eq_true (integrableOn_singleton_iff.mpr <| Or.inr hb.lt_top), and_true_iff]
+ eq_true (integrableOn_singleton_iff.mpr <| Or.inr hb.lt_top), and_true]
· rw [Icc_eq_empty hab, Ico_eq_empty]
contrapose! hab
exact hab.le
@@ -640,14 +640,14 @@ theorem integrableOn_Ico_iff_integrableOn_Ioo' (ha : μ {a} ≠ ∞) :
IntegrableOn f (Ico a b) μ ↔ IntegrableOn f (Ioo a b) μ := by
by_cases hab : a < b
· rw [← Ioo_union_left hab, integrableOn_union,
- eq_true (integrableOn_singleton_iff.mpr <| Or.inr ha.lt_top), and_true_iff]
+ eq_true (integrableOn_singleton_iff.mpr <| Or.inr ha.lt_top), and_true]
· rw [Ioo_eq_empty hab, Ico_eq_empty hab]
theorem integrableOn_Ioc_iff_integrableOn_Ioo' (hb : μ {b} ≠ ∞) :
IntegrableOn f (Ioc a b) μ ↔ IntegrableOn f (Ioo a b) μ := by
by_cases hab : a < b
· rw [← Ioo_union_right hab, integrableOn_union,
- eq_true (integrableOn_singleton_iff.mpr <| Or.inr hb.lt_top), and_true_iff]
+ eq_true (integrableOn_singleton_iff.mpr <| Or.inr hb.lt_top), and_true]
· rw [Ioo_eq_empty hab, Ioc_eq_empty hab]
theorem integrableOn_Icc_iff_integrableOn_Ioo' (ha : μ {a} ≠ ∞) (hb : μ {b} ≠ ∞) :
@@ -657,12 +657,12 @@ theorem integrableOn_Icc_iff_integrableOn_Ioo' (ha : μ {a} ≠ ∞) (hb : μ {b
theorem integrableOn_Ici_iff_integrableOn_Ioi' (hb : μ {b} ≠ ∞) :
IntegrableOn f (Ici b) μ ↔ IntegrableOn f (Ioi b) μ := by
rw [← Ioi_union_left, integrableOn_union,
- eq_true (integrableOn_singleton_iff.mpr <| Or.inr hb.lt_top), and_true_iff]
+ eq_true (integrableOn_singleton_iff.mpr <| Or.inr hb.lt_top), and_true]
theorem integrableOn_Iic_iff_integrableOn_Iio' (hb : μ {b} ≠ ∞) :
IntegrableOn f (Iic b) μ ↔ IntegrableOn f (Iio b) μ := by
rw [← Iio_union_right, integrableOn_union,
- eq_true (integrableOn_singleton_iff.mpr <| Or.inr hb.lt_top), and_true_iff]
+ eq_true (integrableOn_singleton_iff.mpr <| Or.inr hb.lt_top), and_true]
variable [NoAtoms μ]
diff --git a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean
index 902812d6d999d..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.uniformEmbedding_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.uniformEmbedding_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 0acaf9efc4688..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`. -/
@@ -878,7 +878,7 @@ theorem integral_const_of_cdf [CompleteSpace E] [IsFiniteMeasure μ] (c : E) :
∫ _ in a..b, c ∂μ = ((μ (Iic b)).toReal - (μ (Iic a)).toReal) • c := by
simp only [sub_smul, ← setIntegral_const]
refine (integral_Iic_sub_Iic ?_ ?_).symm <;>
- simp only [integrableOn_const, measure_lt_top, or_true_iff]
+ simp only [integrableOn_const, measure_lt_top, or_true]
theorem integral_eq_integral_of_support_subset {a b} (h : support f ⊆ Ioc a b) :
∫ x in a..b, f x ∂μ = ∫ x, f x ∂μ := by
@@ -936,9 +936,9 @@ theorem integral_pos_iff_support_of_nonneg_ae' (hf : 0 ≤ᵐ[μ.restrict (Ι a
(0 < ∫ x in a..b, f x ∂μ) ↔ a < b ∧ 0 < μ (support f ∩ Ioc a b) := by
cases' lt_or_le a b with hab hba
· rw [uIoc_of_le hab.le] at hf
- simp only [hab, true_and_iff, integral_of_le hab.le,
+ simp only [hab, true_and, integral_of_le hab.le,
setIntegral_pos_iff_support_of_nonneg_ae hf hfi.1]
- · suffices (∫ x in a..b, f x ∂μ) ≤ 0 by simp only [this.not_lt, hba.not_lt, false_and_iff]
+ · suffices (∫ x in a..b, f x ∂μ) ≤ 0 by simp only [this.not_lt, hba.not_lt, false_and]
rw [integral_of_ge hba, neg_nonpos]
rw [uIoc_comm, uIoc_of_le hba] at hf
exact integral_nonneg_of_ae hf
@@ -1021,6 +1021,12 @@ theorem abs_integral_le_integral_abs (hab : a ≤ b) :
|∫ x in a..b, f x ∂μ| ≤ ∫ x in a..b, |f x| ∂μ := by
simpa only [← Real.norm_eq_abs] using norm_integral_le_integral_norm hab
+lemma integral_pos (hab : a < b)
+ (hfc : ContinuousOn f (Icc a b)) (hle : ∀ x ∈ Ioc a b, 0 ≤ f x) (hlt : ∃ c ∈ Icc a b, 0 < f c) :
+ 0 < ∫ x in a..b, f x :=
+ (integral_lt_integral_of_continuousOn_of_le_of_exists_lt hab
+ continuousOn_const hfc hle hlt).trans_eq' (by simp)
+
section Mono
theorem integral_mono_interval {c d} (hca : c ≤ a) (hab : a ≤ b) (hbd : b ≤ d)
@@ -1069,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 e0771f0991c48..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₁ :
@@ -141,7 +141,7 @@ theorem lintegral_comp_eq_lintegral_meas_le_mul_of_measurable_of_sigmaFinite
· simp only [h_copy, h h', indicator_of_not_mem, not_false_iff, mem_Ici, not_le, mul_zero]
· have : s ∉ Ioi (0 : ℝ) := h'
simp only [this, h', indicator_of_not_mem, not_false_iff, mul_zero,
- zero_mul, mem_Ioc, false_and_iff]
+ zero_mul, mem_Ioc, false_and]
simp_rw [aux₁]
rw [lintegral_const_mul']
swap
@@ -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:
@@ -548,7 +547,7 @@ lemma Integrable.integral_eq_integral_Ioc_meas_le {f : α → ℝ} {M : ℝ}
∫ ω, f ω ∂μ = ∫ t in Ioc 0 M, ENNReal.toReal (μ {a : α | t ≤ f a}) := by
rw [f_intble.integral_eq_integral_meas_le f_nn]
rw [setIntegral_eq_of_subset_of_ae_diff_eq_zero
- measurableSet_Ioi.nullMeasurableSet Ioc_subset_Ioi_self ?_]
+ nullMeasurableSet_Ioi Ioc_subset_Ioi_self ?_]
apply Eventually.of_forall (fun t ht ↦ ?_)
have htM : M < t := by simp_all only [mem_diff, mem_Ioi, mem_Ioc, not_and, not_le]
have obs : μ {a | M < f a} = 0 := by
diff --git a/Mathlib/MeasureTheory/Integral/Lebesgue.lean b/Mathlib/MeasureTheory/Integral/Lebesgue.lean
index f41a9e5db44de..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
@@ -358,7 +357,7 @@ theorem lintegral_iSup {f : ℕ → α → ℝ≥0∞} (hf : ∀ n, Measurable (
have eq : ∀ p, rs.map c ⁻¹' {p} = ⋃ n, rs.map c ⁻¹' {p} ∩ { a | p ≤ f n a } := by
intro p
rw [← inter_iUnion]; nth_rw 1 [← inter_univ (map c rs ⁻¹' {p})]
- refine Set.ext fun x => and_congr_right fun hx => true_iff_iff.2 ?_
+ refine Set.ext fun x => and_congr_right fun hx => (iff_of_eq (true_iff _)).2 ?_
by_cases p_eq : p = 0
· simp [p_eq]
simp only [coe_map, mem_preimage, Function.comp_apply, mem_singleton_iff] at hx
@@ -385,8 +384,7 @@ theorem lintegral_iSup {f : ℕ → α → ℝ≥0∞} (hf : ∀ n, Measurable (
_ = ∑ r ∈ (rs.map c).range, r * μ (⋃ n, rs.map c ⁻¹' {r} ∩ { a | r ≤ f n a }) := by
simp only [(eq _).symm]
_ = ∑ r ∈ (rs.map c).range, ⨆ n, r * μ (rs.map c ⁻¹' {r} ∩ { a | r ≤ f n a }) :=
- (Finset.sum_congr rfl fun x _ => by
- rw [measure_iUnion_eq_iSup (mono x).directed_le, ENNReal.mul_iSup])
+ Finset.sum_congr rfl fun x _ => by rw [(mono x).measure_iUnion, ENNReal.mul_iSup]
_ = ⨆ n, ∑ r ∈ (rs.map c).range, r * μ (rs.map c ⁻¹' {r} ∩ { a | r ≤ f n a }) := by
refine ENNReal.finsetSum_iSup_of_monotone fun p i j h ↦ ?_
gcongr _ * μ ?_
@@ -531,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 _
@@ -758,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']
@@ -766,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 :=
@@ -861,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 <|
@@ -1013,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 =>
@@ -1098,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 -/
@@ -1114,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 ?_)
@@ -1134,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
@@ -1821,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`
@@ -1883,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
@@ -1924,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) ?_
@@ -1967,8 +1981,8 @@ theorem SimpleFunc.exists_lt_lintegral_simpleFunc_of_lt_lintegral {m : Measurabl
simp only [hc, ENNReal.coe_zero, zero_mul, not_lt_zero] at hL
have : L / c < μ s := by
rwa [ENNReal.div_lt_iff, mul_comm]
- · simp only [c_ne_zero, Ne, ENNReal.coe_eq_zero, not_false_iff, true_or_iff]
- · simp only [Ne, coe_ne_top, not_false_iff, true_or_iff]
+ · simp only [c_ne_zero, Ne, ENNReal.coe_eq_zero, not_false_iff, true_or]
+ · simp only [Ne, coe_ne_top, not_false_iff, true_or]
obtain ⟨t, ht, ts, mlt, t_top⟩ :
∃ t : Set α, MeasurableSet t ∧ t ⊆ s ∧ L / ↑c < μ t ∧ μ t < ∞ :=
Measure.exists_subset_measure_lt_top hs this
@@ -1982,8 +1996,8 @@ theorem SimpleFunc.exists_lt_lintegral_simpleFunc_of_lt_lintegral {m : Measurabl
piecewise_eq_indicator, ENNReal.coe_indicator, Function.const_apply, lintegral_indicator,
lintegral_const, Measure.restrict_apply', univ_inter]
rwa [mul_comm, ← ENNReal.div_lt_iff]
- · simp only [c_ne_zero, Ne, ENNReal.coe_eq_zero, not_false_iff, true_or_iff]
- · simp only [Ne, coe_ne_top, not_false_iff, true_or_iff]
+ · simp only [c_ne_zero, Ne, ENNReal.coe_eq_zero, not_false_iff, true_or]
+ · simp only [Ne, coe_ne_top, not_false_iff, true_or]
· replace hL : L < ∫⁻ x, f₁ x ∂μ + ∫⁻ x, f₂ x ∂μ := by
rwa [← lintegral_add_left f₁.measurable.coe_nnreal_ennreal]
by_cases hf₁ : ∫⁻ x, f₁ x ∂μ = 0
@@ -1996,8 +2010,7 @@ theorem SimpleFunc.exists_lt_lintegral_simpleFunc_of_lt_lintegral {m : Measurabl
rcases h₁ hL with ⟨g, g_le, g_top, gL⟩
refine ⟨g, fun x => (g_le x).trans ?_, g_top, gL⟩
simp only [SimpleFunc.coe_add, Pi.add_apply, le_add_iff_nonneg_right, zero_le']
- obtain ⟨L₁, L₂, hL₁, hL₂, hL⟩ :
- ∃ L₁ L₂ : ℝ≥0∞, (L₁ < ∫⁻ x, f₁ x ∂μ) ∧ (L₂ < ∫⁻ x, f₂ x ∂μ) ∧ L < L₁ + L₂ :=
+ obtain ⟨L₁, hL₁, L₂, hL₂, hL⟩ : ∃ L₁ < ∫⁻ x, f₁ x ∂μ, ∃ L₂ < ∫⁻ x, f₂ x ∂μ, L < L₁ + L₂ :=
ENNReal.exists_lt_add_of_lt_add hL hf₁ hf₂
rcases h₁ hL₁ with ⟨g₁, g₁_le, g₁_top, hg₁⟩
rcases h₂ hL₂ with ⟨g₂, g₂_le, g₂_top, hg₂⟩
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 39a15c80e968f..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)
@@ -312,7 +311,7 @@ theorem lintegral_Lp_mul_le_Lq_mul_Lr {α} [MeasurableSpace α] {p q r : ℝ} (h
let p2 := q / p
let q2 := p2.conjExponent
have hp2q2 : p2.IsConjExponent q2 :=
- .conjExponent (by simp [p2, q2, _root_.lt_div_iff, hpq, hp0_lt])
+ .conjExponent (by simp [p2, q2, _root_.lt_div_iff₀, hpq, hp0_lt])
calc
(∫⁻ a : α, (f * g) a ^ p ∂μ) ^ (1 / p) = (∫⁻ a : α, f a ^ p * g a ^ p ∂μ) ^ (1 / p) := by
simp_rw [Pi.mul_apply, ENNReal.mul_rpow_of_nonneg _ _ hp0]
diff --git a/Mathlib/MeasureTheory/Integral/PeakFunction.lean b/Mathlib/MeasureTheory/Integral/PeakFunction.lean
index 8db2aa64138ec..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
@@ -392,7 +392,7 @@ theorem tendsto_setIntegral_pow_smul_of_unique_maximum_of_isCompact_of_continuou
### Peak functions of the form `x ↦ c ^ dim * φ (c x)`
-/
-open FiniteDimensional Bornology
+open Module Bornology
variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] [FiniteDimensional ℝ F]
[MeasurableSpace F] [BorelSpace F] {μ : Measure F} [IsAddHaarMeasure μ]
@@ -438,7 +438,7 @@ theorem tendsto_integral_comp_smul_smul_of_integrable
simp [norm_smul, abs_of_pos cpos, mul_pow]; ring
_ < δ ^ finrank ℝ F * ε := by
apply hM
- rw [div_lt_iff δpos] at hc
+ rw [div_lt_iff₀ δpos] at hc
simp only [mem_compl_iff, mem_closedBall, dist_zero_right, norm_smul, Real.norm_eq_abs,
abs_of_nonneg cpos.le, not_le, gt_iff_lt]
exact hc.trans_le (by gcongr)
diff --git a/Mathlib/MeasureTheory/Integral/Periodic.lean b/Mathlib/MeasureTheory/Integral/Periodic.lean
index 892fa83114568..90abdbcb2baaf 100644
--- a/Mathlib/MeasureTheory/Integral/Periodic.lean
+++ b/Mathlib/MeasureTheory/Integral/Periodic.lean
@@ -35,17 +35,17 @@ protected theorem AddCircle.measurable_mk' {a : ℝ} :
theorem isAddFundamentalDomain_Ioc {T : ℝ} (hT : 0 < T) (t : ℝ)
(μ : Measure ℝ := by volume_tac) :
IsAddFundamentalDomain (AddSubgroup.zmultiples T) (Ioc t (t + T)) μ := by
- refine IsAddFundamentalDomain.mk' measurableSet_Ioc.nullMeasurableSet fun x => ?_
+ refine IsAddFundamentalDomain.mk' nullMeasurableSet_Ioc fun x => ?_
have : Bijective (codRestrict (fun n : ℤ => n • T) (AddSubgroup.zmultiples T) _) :=
- (Equiv.ofInjective (fun n : ℤ => n • T) (zsmul_strictMono_left hT).injective).bijective
+ (Equiv.ofInjective (fun n : ℤ => n • T) (zsmul_left_strictMono hT).injective).bijective
refine this.existsUnique_iff.2 ?_
simpa only [add_comm x] using existsUnique_add_zsmul_mem_Ioc hT x t
theorem isAddFundamentalDomain_Ioc' {T : ℝ} (hT : 0 < T) (t : ℝ) (μ : Measure ℝ := by volume_tac) :
IsAddFundamentalDomain (AddSubgroup.op <| .zmultiples T) (Ioc t (t + T)) μ := by
- refine IsAddFundamentalDomain.mk' measurableSet_Ioc.nullMeasurableSet fun x => ?_
+ refine IsAddFundamentalDomain.mk' nullMeasurableSet_Ioc fun x => ?_
have : Bijective (codRestrict (fun n : ℤ => n • T) (AddSubgroup.zmultiples T) _) :=
- (Equiv.ofInjective (fun n : ℤ => n • T) (zsmul_strictMono_left hT).injective).bijective
+ (Equiv.ofInjective (fun n : ℤ => n • T) (zsmul_left_strictMono hT).injective).bijective
refine (AddSubgroup.equivOp _).bijective.comp this |>.existsUnique_iff.2 ?_
simpa using existsUnique_add_zsmul_mem_Ioc hT x t
@@ -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 87e289fa69c30..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
@@ -61,7 +61,7 @@ along one of the variables (using either the Lebesgue or Bochner integral) is me
theorem measurableSet_integrable [SFinite ν] ⦃f : α → β → E⦄
(hf : StronglyMeasurable (uncurry f)) : MeasurableSet {x | Integrable (f x) ν} := by
- simp_rw [Integrable, hf.of_uncurry_left.aestronglyMeasurable, true_and_iff]
+ simp_rw [Integrable, hf.of_uncurry_left.aestronglyMeasurable, true_and]
exact measurableSet_lt (Measurable.lintegral_prod_right hf.ennnorm) measurable_const
section
@@ -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 20a484f42774c..da3bb92699829 100644
--- a/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean
+++ b/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean
@@ -3,7 +3,7 @@ Copyright (c) 2022 Jesse Reimann. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jesse Reimann, Kalle Kytölä
-/
-import Mathlib.Topology.ContinuousFunction.Bounded
+import Mathlib.Topology.ContinuousMap.Bounded
import Mathlib.Topology.Sets.Compacts
/-!
@@ -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 f7e029875e697..49b3978cb0252 100644
--- a/Mathlib/MeasureTheory/Integral/SetIntegral.lean
+++ b/Mathlib/MeasureTheory/Integral/SetIntegral.lean
@@ -7,7 +7,7 @@ import Mathlib.MeasureTheory.Integral.IntegrableOn
import Mathlib.MeasureTheory.Integral.Bochner
import Mathlib.MeasureTheory.Function.LocallyIntegrable
import Mathlib.Topology.MetricSpace.ThickenedIndicator
-import Mathlib.Topology.ContinuousFunction.ContinuousMapZero
+import Mathlib.Topology.ContinuousMap.ContinuousMapZero
import Mathlib.Analysis.NormedSpace.HahnBanach.SeparatingDual
/-!
@@ -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 ∂μ :=
@@ -228,7 +246,7 @@ theorem tendsto_setIntegral_of_monotone {ι : Type*} [Countable ι] [Semilattice
refine Metric.nhds_basis_closedBall.tendsto_right_iff.2 fun ε ε0 => ?_
lift ε to ℝ≥0 using ε0.le
have : ∀ᶠ i in atTop, ν (s i) ∈ Icc (ν S - ε) (ν S + ε) :=
- tendsto_measure_iUnion h_mono (ENNReal.Icc_mem_nhds hfi'.ne (ENNReal.coe_pos.2 ε0).ne')
+ tendsto_measure_iUnion_atTop h_mono (ENNReal.Icc_mem_nhds hfi'.ne (ENNReal.coe_pos.2 ε0).ne')
filter_upwards [this] with i hi
rw [mem_closedBall_iff_norm', ← integral_diff (hsm i) hfi hsub, ← coe_nnnorm, NNReal.coe_le_coe, ←
ENNReal.coe_le_coe]
@@ -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,14 +389,14 @@ 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]
intro h'x
by_cases xs : x ∈ s
· simp only [xs, hts xs]
- · simp only [xs, iff_false_iff]
+ · simp only [xs, iff_false]
intro xt
exact h'x (hx ⟨xt, xs⟩)
_ = ∫ x in s ∩ k, f x ∂μ + ∫ x in s \ k, f x ∂μ := by
@@ -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 μ]
@@ -1260,7 +1284,7 @@ variable [NormedSpace ℝ F] [NormedSpace ℝ E]
theorem integral_comp_comm (L : E ≃L[𝕜] F) (φ : X → E) : ∫ x, L (φ x) ∂μ = L (∫ x, φ x ∂μ) := by
have : CompleteSpace E ↔ CompleteSpace F :=
- completeSpace_congr (e := L.toEquiv) L.uniformEmbedding
+ completeSpace_congr (e := L.toEquiv) L.isUniformEmbedding
obtain ⟨_, _⟩|⟨_, _⟩ := iff_iff_and_or_not_and_not.mp this
· exact L.toContinuousLinearMap.integral_comp_comm' L.antilipschitz _
· simp [integral, *]
@@ -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 02f0849ff37db..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
@@ -116,14 +117,14 @@ theorem of_smul_measure (c : ℝ≥0∞) (hc_ne_top : c ≠ ∞) (hT : FinMeasAd
FinMeasAdditive μ T := by
refine of_eq_top_imp_eq_top (fun s _ hμs => ?_) hT
rw [Measure.smul_apply, smul_eq_mul, ENNReal.mul_eq_top] at hμs
- simp only [hc_ne_top, or_false_iff, Ne, false_and_iff] at hμs
+ simp only [hc_ne_top, or_false, Ne, false_and] at hμs
exact hμs.2
theorem smul_measure (c : ℝ≥0∞) (hc_ne_zero : c ≠ 0) (hT : FinMeasAdditive μ T) :
FinMeasAdditive (c • μ) T := by
refine of_eq_top_imp_eq_top (fun s _ hμs => ?_) hT
rw [Measure.smul_apply, smul_eq_mul, ENNReal.mul_eq_top]
- simp only [hc_ne_zero, true_and_iff, Ne, not_false_iff]
+ simp only [hc_ne_zero, true_and, Ne, not_false_iff]
exact Or.inl hμs
theorem smul_measure_iff (c : ℝ≥0∞) (hc_ne_zero : c ≠ 0) (hc_ne_top : c ≠ ∞) :
@@ -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])
@@ -231,8 +231,8 @@ theorem of_smul_measure (c : ℝ≥0∞) (hc_ne_top : c ≠ ∞) (hT : Dominated
DominatedFinMeasAdditive μ T (c.toReal * C) := by
have h : ∀ s, MeasurableSet s → c • μ s = ∞ → μ s = ∞ := by
intro s _ hcμs
- simp only [hc_ne_top, Algebra.id.smul_eq_mul, ENNReal.mul_eq_top, or_false_iff, Ne,
- false_and_iff] at hcμs
+ simp only [hc_ne_top, Algebra.id.smul_eq_mul, ENNReal.mul_eq_top, or_false, Ne,
+ false_and] at hcμs
exact hcμs.2
refine ⟨hT.1.of_eq_top_imp_eq_top (μ := c • μ) h, fun s hs hμs => ?_⟩
have hcμs : c • μ s ≠ ∞ := mt (h s hs) hμs.ne
@@ -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)
@@ -1502,7 +1501,7 @@ theorem setToFun_top_smul_measure (hT : DominatedFinMeasAdditive (∞ • μ) T
setToFun (∞ • μ) T hT f = 0 := by
refine setToFun_measure_zero' hT fun s _ hμs => ?_
rw [lt_top_iff_ne_top] at hμs
- simp only [true_and_iff, Measure.smul_apply, ENNReal.mul_eq_top, eq_self_iff_true,
+ simp only [true_and, Measure.smul_apply, ENNReal.mul_eq_top, eq_self_iff_true,
top_ne_zero, Ne, not_false_iff, not_or, Classical.not_not, smul_eq_mul] at hμs
simp only [hμs.right, Measure.smul_apply, mul_zero, smul_eq_mul]
@@ -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/Integral/VitaliCaratheodory.lean b/Mathlib/MeasureTheory/Integral/VitaliCaratheodory.lean
index 15a4b3437ddd3..2aa0a2e287af9 100644
--- a/Mathlib/MeasureTheory/Integral/VitaliCaratheodory.lean
+++ b/Mathlib/MeasureTheory/Integral/VitaliCaratheodory.lean
@@ -110,11 +110,11 @@ theorem SimpleFunc.exists_le_lowerSemicontinuous_lintegral_ge (f : α →ₛ ℝ
· simp only [lintegral_const, zero_mul, zero_le, ENNReal.coe_zero]
have ne_top : μ s ≠ ⊤ := by
classical
- simpa [f, hs, hc, lt_top_iff_ne_top, true_and_iff, SimpleFunc.coe_const,
+ simpa [f, hs, hc, lt_top_iff_ne_top, SimpleFunc.coe_const,
Function.const_apply, lintegral_const, ENNReal.coe_indicator, Set.univ_inter,
ENNReal.coe_ne_top, MeasurableSet.univ, ENNReal.mul_eq_top, SimpleFunc.const_zero,
- or_false_iff, lintegral_indicator, ENNReal.coe_eq_zero, Ne, not_false_iff,
- SimpleFunc.coe_zero, Set.piecewise_eq_indicator, SimpleFunc.coe_piecewise, false_and_iff,
+ lintegral_indicator, ENNReal.coe_eq_zero, Ne, not_false_iff,
+ SimpleFunc.coe_zero, Set.piecewise_eq_indicator, SimpleFunc.coe_piecewise,
restrict_apply] using h
have : μ s < μ s + ε / c := by
have : (0 : ℝ≥0∞) < ε / c := ENNReal.div_pos_iff.2 ⟨ε0, ENNReal.coe_ne_top⟩
@@ -326,12 +326,12 @@ theorem SimpleFunc.exists_upperSemicontinuous_le_lintegral_le (f : α →ₛ ℝ
Set.piecewise_eq_indicator, ENNReal.coe_zero, SimpleFunc.coe_piecewise, zero_le]
have μs_lt_top : μ s < ∞ := by
classical
- simpa only [hs, hc, lt_top_iff_ne_top, true_and_iff, SimpleFunc.coe_const, or_false_iff,
+ simpa only [hs, hc, lt_top_iff_ne_top, true_and, SimpleFunc.coe_const, or_false,
lintegral_const, ENNReal.coe_indicator, Set.univ_inter, ENNReal.coe_ne_top,
Measure.restrict_apply MeasurableSet.univ, ENNReal.mul_eq_top, SimpleFunc.const_zero,
Function.const_apply, lintegral_indicator, ENNReal.coe_eq_zero, Ne, not_false_iff,
SimpleFunc.coe_zero, Set.piecewise_eq_indicator, SimpleFunc.coe_piecewise,
- false_and_iff] using int_f
+ false_and] using int_f
have : (0 : ℝ≥0∞) < ε / c := ENNReal.div_pos_iff.2 ⟨ε0, ENNReal.coe_ne_top⟩
obtain ⟨F, Fs, F_closed, μF⟩ : ∃ (F : _), F ⊆ s ∧ IsClosed F ∧ μ s < μ F + ε / c :=
hs.exists_isClosed_lt_add μs_lt_top.ne this.ne'
diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean
index bcafad90b41d4..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
@@ -865,6 +878,42 @@ theorem measurable_update_left {a : δ} [DecidableEq δ] {x : π a} :
Measurable (update · a x) :=
measurable_update'.comp measurable_prod_mk_right
+@[measurability, fun_prop]
+theorem Set.measurable_restrict (s : Set δ) : Measurable (s.restrict (π := π)) :=
+ measurable_pi_lambda _ fun _ ↦ measurable_pi_apply _
+
+@[measurability, fun_prop]
+theorem Set.measurable_restrict₂ {s t : Set δ} (hst : s ⊆ t) :
+ Measurable (restrict₂ (π := π) hst) :=
+ measurable_pi_lambda _ fun _ ↦ measurable_pi_apply _
+
+@[measurability, fun_prop]
+theorem Finset.measurable_restrict (s : Finset δ) : Measurable (s.restrict (π := π)) :=
+ measurable_pi_lambda _ fun _ ↦ measurable_pi_apply _
+
+@[measurability, fun_prop]
+theorem Finset.measurable_restrict₂ {s t : Finset δ} (hst : s ⊆ t) :
+ Measurable (Finset.restrict₂ (π := π) hst) :=
+ measurable_pi_lambda _ fun _ ↦ measurable_pi_apply _
+
+@[measurability, fun_prop]
+theorem Set.measurable_restrict_apply (s : Set α) {f : α → γ} (hf : Measurable f) :
+ Measurable (s.restrict f) := hf.comp measurable_subtype_coe
+
+@[measurability, fun_prop]
+theorem Set.measurable_restrict₂_apply {s t : Set α} (hst : s ⊆ t)
+ {f : t → γ} (hf : Measurable f) :
+ Measurable (restrict₂ (π := fun _ ↦ γ) hst f) := hf.comp (measurable_inclusion hst)
+
+@[measurability, fun_prop]
+theorem Finset.measurable_restrict_apply (s : Finset α) {f : α → γ} (hf : Measurable f) :
+ Measurable (s.restrict f) := hf.comp measurable_subtype_coe
+
+@[measurability, fun_prop]
+theorem Finset.measurable_restrict₂_apply {s t : Finset α} (hst : s ⊆ t)
+ {f : t → γ} (hf : Measurable f) :
+ Measurable (restrict₂ (π := fun _ ↦ γ) hst f) := hf.comp (measurable_inclusion hst)
+
variable (π) in
theorem measurable_eq_mp {i i' : δ} (h : i = i') : Measurable (congr_arg π h).mp := by
cases h
@@ -1220,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/PreorderRestrict.lean b/Mathlib/MeasureTheory/MeasurableSpace/PreorderRestrict.lean
new file mode 100644
index 0000000000000..2432d3f8d2ae9
--- /dev/null
+++ b/Mathlib/MeasureTheory/MeasurableSpace/PreorderRestrict.lean
@@ -0,0 +1,40 @@
+/-
+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.Order.Restriction
+import Mathlib.MeasureTheory.MeasurableSpace.Basic
+
+/-!
+# Measurability of the restriction function for functions indexed by a preorder
+
+We prove that the map which restricts a function `f : (i : α) → X i` to elements `≤ a` is
+measurable.
+-/
+
+open MeasureTheory
+
+namespace Preorder
+
+variable {α : Type*} [Preorder α] {X : α → Type*} [∀ a, MeasurableSpace (X a)]
+
+@[measurability, fun_prop]
+theorem measurable_restrictLe (a : α) : Measurable (restrictLe (π := X) a) :=
+ Set.measurable_restrict _
+
+@[measurability, fun_prop]
+theorem measurable_restrictLe₂ {a b : α} (hab : a ≤ b) : Measurable (restrictLe₂ (π := X) hab) :=
+ Set.measurable_restrict₂ _
+
+variable [LocallyFiniteOrderBot α]
+
+@[measurability, fun_prop]
+theorem measurable_frestrictLe (a : α) : Measurable (frestrictLe (π := X) a) :=
+ Finset.measurable_restrict _
+
+@[measurability, fun_prop]
+theorem measurable_frestrictLe₂ {a b : α} (hab : a ≤ b) : Measurable (frestrictLe₂ (π := X) hab) :=
+ Finset.measurable_restrict₂ _
+
+end Preorder
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 f9ad11c6fbc66..6f771b3602413 100644
--- a/Mathlib/MeasureTheory/Measure/AEMeasurable.lean
+++ b/Mathlib/MeasureTheory/Measure/AEMeasurable.lean
@@ -197,7 +197,7 @@ theorem exists_ae_eq_range_subset (H : AEMeasurable f μ) {t : Set β} (ht : ∀
simp only [g, hx, piecewise_eq_of_not_mem, not_false_iff]
contrapose! hx
apply subset_toMeasurable
- simp only [hx, mem_compl_iff, mem_setOf_eq, false_and_iff, not_false_iff]
+ simp only [hx, mem_compl_iff, mem_setOf_eq, false_and, not_false_iff]
theorem exists_measurable_nonneg {β} [Preorder β] [Zero β] {mβ : MeasurableSpace β} {f : α → β}
(hf : AEMeasurable f μ) (f_nn : ∀ᵐ t ∂μ, 0 ≤ f t) : ∃ g, Measurable g ∧ 0 ≤ g ∧ f =ᵐ[μ] g := by
@@ -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 362cd5b634339..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
@@ -63,9 +64,8 @@ instance : Inhabited (AddContent C) :=
sUnion' := by simp }⟩
instance : DFunLike (AddContent C) (Set α) (fun _ ↦ ℝ≥0∞) where
- coe := fun m s ↦ m.toFun s
- coe_injective' := by
- intro m m' h
+ coe m s := m.toFun s
+ coe_injective' m m' _ := by
cases m
cases m'
congr
@@ -91,7 +91,7 @@ lemma addContent_union' (hs : s ∈ C) (ht : t ∈ C) (hst : s ∪ t ∈ C) (h_d
rotate_left
· simp only [coe_pair, Set.insert_subset_iff, hs, ht, Set.singleton_subset_iff, and_self_iff]
· simp only [coe_pair, Set.pairwiseDisjoint_insert, pairwiseDisjoint_singleton,
- mem_singleton_iff, Ne, id, forall_eq, true_and_iff]
+ mem_singleton_iff, Ne, id, forall_eq, true_and]
exact fun _ => h_dis
· simp only [coe_pair, sUnion_insert, sUnion_singleton]
exact hst
diff --git a/Mathlib/MeasureTheory/Measure/Complex.lean b/Mathlib/MeasureTheory/Measure/Complex.lean
index decf1c54caa15..611174a941c5f 100644
--- a/Mathlib/MeasureTheory/Measure/Complex.lean
+++ b/Mathlib/MeasureTheory/Measure/Complex.lean
@@ -4,17 +4,15 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kexing Ying
-/
import Mathlib.MeasureTheory.Measure.VectorMeasure
+import Mathlib.Analysis.Complex.Basic
/-!
# Complex measure
-This file proves some elementary results about complex measures. In particular, we prove that
+This file defines a complex measure to be a vector measure with codomain `ℂ`.
+Then we prove some elementary results about complex measures. In particular, we prove that
a complex measure is always in the form `s + it` where `s` and `t` are signed measures.
-The complex measure is defined to be vector measure over `ℂ`, this definition can be found
-in `Mathlib/MeasureTheory/Measure/VectorMeasure.lean` and is known as
-`MeasureTheory.ComplexMeasure`.
-
## Main definitions
* `MeasureTheory.ComplexMeasure.re`: obtains a signed measure `s` from a complex measure `c`
@@ -36,12 +34,16 @@ noncomputable section
open scoped MeasureTheory ENNReal NNReal
-variable {α β : Type*} {m : MeasurableSpace α}
+variable {α : Type*} {m : MeasurableSpace α}
namespace MeasureTheory
open VectorMeasure
+/-- A `ComplexMeasure` is a `ℂ`-vector measure. -/
+abbrev ComplexMeasure (α : Type*) [MeasurableSpace α] :=
+ VectorMeasure α ℂ
+
namespace ComplexMeasure
/-- The real part of a complex measure is a signed measure. -/
@@ -61,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 5306eb0281091..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
@@ -310,7 +310,7 @@ variable [S : MeasurableSpace G] [BorelSpace G]
/-- For the outer measure coming from a content, all Borel sets are measurable. -/
theorem borel_le_caratheodory : S ≤ μ.outerMeasure.caratheodory := by
- rw [@BorelSpace.measurable_eq G _ _]
+ rw [BorelSpace.measurable_eq (α := G)]
refine MeasurableSpace.generateFrom_le ?_
intro U hU
rw [μ.outerMeasure_caratheodory]
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/Basic.lean b/Mathlib/MeasureTheory/Measure/Haar/Basic.lean
index b8bf558a35d4e..c09a144500014 100644
--- a/Mathlib/MeasureTheory/Measure/Haar/Basic.lean
+++ b/Mathlib/MeasureTheory/Measure/Haar/Basic.lean
@@ -199,7 +199,7 @@ theorem index_union_le (K₁ K₂ : Compacts G) {V : Set G} (hV : (interior V).N
apply Nat.sInf_le; refine ⟨_, ?_, rfl⟩; rw [mem_setOf_eq]
apply union_subset <;> refine Subset.trans (by assumption) ?_ <;>
apply biUnion_subset_biUnion_left <;> intro g hg <;> simp only [mem_def] at hg <;>
- simp only [mem_def, Multiset.mem_union, Finset.union_val, hg, or_true_iff, true_or_iff]
+ simp only [mem_def, Multiset.mem_union, Finset.union_val, hg, or_true, true_or]
@[to_additive addIndex_union_eq]
theorem index_union_eq (K₁ K₂ : Compacts G) {V : Set G} (hV : (interior V).Nonempty)
@@ -216,7 +216,7 @@ theorem index_union_eq (K₁ K₂ : Compacts G) {V : Set G} (hV : (interior V).N
intro g hg; rcases hK hg with ⟨_, ⟨g₀, rfl⟩, _, ⟨h1g₀, rfl⟩, h2g₀⟩
simp only [mem_preimage] at h2g₀
simp only [mem_iUnion]; use g₀; constructor; swap
- · simp only [Finset.mem_filter, h1g₀, true_and_iff]; use g
+ · simp only [Finset.mem_filter, h1g₀, true_and]; use g
simp only [hg, h2g₀, mem_inter_iff, mem_preimage, and_self_iff]
exact h2g₀
refine
@@ -432,7 +432,7 @@ theorem chaar_sup_eq {K₀ : PositiveCompacts G}
mem_of_subset_of_mem _
(chaar_mem_clPrehaar K₀
⟨⟨V⁻¹, (h2V₁.inter h2V₂).preimage continuous_inv⟩, by
- simp only [V, mem_inv, inv_one, h3V₁, h3V₂, mem_inter_iff, true_and_iff]⟩)
+ simp only [V, mem_inv, inv_one, h3V₁, h3V₂, mem_inter_iff, true_and]⟩)
unfold clPrehaar; rw [IsClosed.closure_subset_iff]
· rintro _ ⟨U, ⟨h1U, h2U, h3U⟩, rfl⟩
simp only [eval, mem_preimage, sub_eq_zero, mem_singleton_iff]; rw [eq_comm]
diff --git a/Mathlib/MeasureTheory/Measure/Haar/InnerProductSpace.lean b/Mathlib/MeasureTheory/Measure/Haar/InnerProductSpace.lean
index cc3daa531971b..71eec8c794d88 100644
--- a/Mathlib/MeasureTheory/Measure/Haar/InnerProductSpace.lean
+++ b/Mathlib/MeasureTheory/Measure/Haar/InnerProductSpace.lean
@@ -16,7 +16,7 @@ measure `1` to the parallelepiped spanned by any orthonormal basis, and that it
the canonical `volume` from the `MeasureSpace` instance.
-/
-open FiniteDimensional MeasureTheory MeasureTheory.Measure Set
+open Module MeasureTheory MeasureTheory.Measure Set
variable {ι E F : Type*}
diff --git a/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean b/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean
index 29af339ad2552..dc9e9ec5eeea0 100644
--- a/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean
+++ b/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean
@@ -18,7 +18,7 @@ open scoped NNReal ENNReal Pointwise Topology
open Inv Set Function MeasureTheory.Measure Filter
-open FiniteDimensional
+open Module
namespace MeasureTheory
@@ -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. -/
@@ -122,11 +120,11 @@ alias set_integral_comp_smul_of_pos := setIntegral_comp_smul_of_pos
theorem integral_comp_mul_left (g : ℝ → F) (a : ℝ) :
(∫ x : ℝ, g (a * x)) = |a⁻¹| • ∫ y : ℝ, g y := by
- simp_rw [← smul_eq_mul, Measure.integral_comp_smul, FiniteDimensional.finrank_self, pow_one]
+ simp_rw [← smul_eq_mul, Measure.integral_comp_smul, Module.finrank_self, pow_one]
theorem integral_comp_inv_mul_left (g : ℝ → F) (a : ℝ) :
(∫ x : ℝ, g (a⁻¹ * x)) = |a| • ∫ y : ℝ, g y := by
- simp_rw [← smul_eq_mul, Measure.integral_comp_inv_smul, FiniteDimensional.finrank_self, pow_one]
+ simp_rw [← smul_eq_mul, Measure.integral_comp_inv_smul, Module.finrank_self, pow_one]
theorem integral_comp_mul_right (g : ℝ → F) (a : ℝ) :
(∫ x : ℝ, g (x * a)) = |a⁻¹| • ∫ y : ℝ, g y := by
diff --git a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean
index 5c2649473b452..7f76b5cbe8048 100644
--- a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean
+++ b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean
@@ -26,7 +26,7 @@ of the basis).
-/
-open Set TopologicalSpace MeasureTheory MeasureTheory.Measure FiniteDimensional
+open Set TopologicalSpace MeasureTheory MeasureTheory.Measure Module
open scoped Pointwise
@@ -162,7 +162,7 @@ theorem parallelepiped_single [DecidableEq ι] (a : ι → ℝ) :
· rw [sup_eq_left.mpr hai, inf_eq_right.mpr hai] at h
exact ⟨div_nonneg_of_nonpos h.2 hai, div_le_one_of_ge h.1 hai⟩
· rw [sup_eq_right.mpr hai, inf_eq_left.mpr hai] at h
- exact ⟨div_nonneg h.1 hai, div_le_one_of_le h.2 hai⟩
+ exact ⟨div_nonneg h.1 hai, div_le_one_of_le₀ h.2 hai⟩
· specialize h i
simp only [smul_eq_mul, Pi.mul_apply]
rcases eq_or_ne (a i) 0 with hai | hai
@@ -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
@@ -290,7 +288,18 @@ end Fintype
/-- A finite dimensional inner product space has a canonical measure, the Lebesgue measure giving
volume `1` to the parallelepiped spanned by any orthonormal basis. We define the measure using
some arbitrary choice of orthonormal basis. The fact that it works with any orthonormal basis
-is proved in `orthonormalBasis.volume_parallelepiped`. -/
+is proved in `orthonormalBasis.volume_parallelepiped`.
+
+This instance creates:
+
+- a potential non-defeq diamond with the natural instance for `MeasureSpace (ULift E)`,
+ which does not exist in Mathlib at the moment;
+
+- a diamond with the existing instance `MeasureTheory.Measure.instMeasureSpacePUnit`.
+
+However, we've decided not to refactor until one of these diamonds starts creating issues, see
+https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Hausdorff.20measure.20normalisation
+-/
instance (priority := 100) measureSpaceOfInnerProductSpace [NormedAddCommGroup E]
[InnerProductSpace ℝ E] [FiniteDimensional ℝ E] [MeasurableSpace E] [BorelSpace E] :
MeasureSpace E where volume := (stdOrthonormalBasis ℝ E).toBasis.addHaar
diff --git a/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean b/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean
index 4882bfa945404..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
@@ -223,7 +223,7 @@ theorem MeasureTheory.QuotientMeasureEqMeasurePreimage.haarMeasure_quotient [Loc
[IsFiniteMeasure μ] : IsHaarMeasure μ := by
obtain ⟨K⟩ := PositiveCompacts.nonempty' (α := G)
let K' : PositiveCompacts (G ⧸ Γ) :=
- K.map π continuous_coinduced_rng (QuotientGroup.isOpenMap_coe Γ)
+ K.map π QuotientGroup.continuous_mk QuotientGroup.isOpenMap_coe
haveI : IsMulLeftInvariant μ :=
MeasureTheory.QuotientMeasureEqMeasurePreimage.mulInvariantMeasure_quotient ν
rw [haarMeasure_unique μ K']
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 ed741f37cbf85..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
@@ -210,7 +210,7 @@ theorem measure_isClosed_eq_of_forall_lintegral_eq_of_isFiniteMeasure {Ω : Type
have whole := h 1
simp only [BoundedContinuousFunction.coe_one, Pi.one_apply, ENNReal.coe_one, lintegral_const,
one_mul] at whole
- simpa [← whole] using IsFiniteMeasure.measure_univ_lt_top
+ simp [← whole]
have obs_μ := HasOuterApproxClosed.tendsto_lintegral_apprSeq F_closed μ
have obs_ν := HasOuterApproxClosed.tendsto_lintegral_apprSeq F_closed ν
simp_rw [h] at obs_μ
diff --git a/Mathlib/MeasureTheory/Measure/Hausdorff.lean b/Mathlib/MeasureTheory/Measure/Hausdorff.lean
index 84bfe07b9e3fb..ce69db687e782 100644
--- a/Mathlib/MeasureTheory/Measure/Hausdorff.lean
+++ b/Mathlib/MeasureTheory/Measure/Hausdorff.lean
@@ -109,7 +109,7 @@ Hausdorff measure, measure, metric measure
open scoped NNReal ENNReal Topology
-open EMetric Set Function Filter Encodable FiniteDimensional TopologicalSpace
+open EMetric Set Function Filter Encodable Module TopologicalSpace
noncomputable section
@@ -183,7 +183,7 @@ theorem borel_le_caratheodory (hm : IsMetric μ) : borel X ≤ μ.caratheodory :
suffices μ (⋃ n, S n) ≤ ⨆ n, μ (S n) by calc
μ (s ∩ t) + μ (s \ t) = μ (s ∩ t) + μ (⋃ n, S n) := by rw [iUnion_S]
_ ≤ μ (s ∩ t) + ⨆ n, μ (S n) := by gcongr
- _ = ⨆ n, μ (s ∩ t) + μ (S n) := ENNReal.add_iSup
+ _ = ⨆ n, μ (s ∩ t) + μ (S n) := ENNReal.add_iSup ..
_ ≤ μ s := iSup_le hSs
/- It suffices to show that `∑' k, μ (S (k + 1) \ S k) ≠ ∞`. Indeed, if we have this,
then for all `N` we have `μ (⋃ n, S n) ≤ μ (S N) + ∑' k, m (S (N + k + 1) \ S (N + k))`
@@ -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/EqHaar.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean
index fb8dff12af177..9ede8fdf04384 100644
--- a/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean
+++ b/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean
@@ -100,7 +100,7 @@ theorem Basis.map_addHaar {ι E F : Type*} [Fintype ι] [NormedAddCommGroup E] [
namespace MeasureTheory
-open Measure TopologicalSpace.PositiveCompacts FiniteDimensional
+open Measure TopologicalSpace.PositiveCompacts Module
/-!
### The Lebesgue measure is a Haar measure on `ℝ` and on `ℝ^ι`.
@@ -512,8 +512,8 @@ theorem addHaar_singleton_add_smul_div_singleton_add_smul {r : ℝ} (hr : r ≠
(μ s * (μ t)⁻¹) := by
rw [ENNReal.mul_inv]
· ring
- · simp only [pow_pos (abs_pos.mpr hr), ENNReal.ofReal_eq_zero, not_le, Ne, true_or_iff]
- · simp only [ENNReal.ofReal_ne_top, true_or_iff, Ne, not_false_iff]
+ · simp only [pow_pos (abs_pos.mpr hr), ENNReal.ofReal_eq_zero, not_le, Ne, true_or]
+ · simp only [ENNReal.ofReal_ne_top, true_or, Ne, not_false_iff]
_ = μ s / μ t := by
rw [ENNReal.mul_inv_cancel, one_mul, div_eq_mul_inv]
· simp only [pow_pos (abs_pos.mpr hr), ENNReal.ofReal_eq_zero, not_le, Ne]
@@ -607,7 +607,6 @@ theorem tendsto_addHaar_inter_smul_zero_of_density_zero_aux1 (s : Set E) (x : E)
rintro r (rpos : 0 < r)
rw [← affinity_unitClosedBall rpos.le, singleton_add, ← image_vadd]
gcongr
- exact smul_set_mono t_bound
have B :
Tendsto (fun r : ℝ => μ (closedBall x r) / μ ({x} + r • u)) (𝓝[>] 0)
(𝓝 (μ (closedBall x 1) / μ ({x} + u))) := by
@@ -624,7 +623,7 @@ theorem tendsto_addHaar_inter_smul_zero_of_density_zero_aux1 (s : Set E) (x : E)
(𝓝[>] 0) (𝓝 (0 * (μ (closedBall x 1) / μ ({x} + u)))) := by
apply ENNReal.Tendsto.mul A _ B (Or.inr ENNReal.zero_ne_top)
simp only [ne_eq, not_true, singleton_add, image_add_left, measure_preimage_add, false_or,
- ENNReal.div_eq_top, h'u, false_or_iff, not_and, and_false_iff]
+ ENNReal.div_eq_top, h'u, not_and, and_false]
intro aux
exact (measure_closedBall_lt_top.ne aux).elim
-- Porting note: it used to be enough to pass `measure_closedBall_lt_top.ne` to `simp`
@@ -746,10 +745,8 @@ theorem tendsto_addHaar_inter_smul_one_of_density_one_aux (s : Set E) (hs : Meas
rw [← ENNReal.sub_mul]; swap
· simp only [uzero, ENNReal.inv_eq_top, imp_true_iff, Ne, not_false_iff]
congr 1
- apply
- ENNReal.sub_eq_of_add_eq (ne_top_of_le_ne_top utop (measure_mono inter_subset_right))
- rw [inter_comm _ u, inter_comm _ u]
- exact measure_inter_add_diff u vmeas
+ rw [inter_comm _ u, inter_comm _ u, eq_comm]
+ exact ENNReal.eq_sub_of_add_eq' utop (measure_inter_add_diff u vmeas)
have L : Tendsto (fun r => μ (sᶜ ∩ closedBall x r) / μ (closedBall x r)) (𝓝[>] 0) (𝓝 0) := by
have A : Tendsto (fun r => μ (closedBall x r) / μ (closedBall x r)) (𝓝[>] 0) (𝓝 1) := by
apply tendsto_const_nhds.congr' _
@@ -780,11 +777,10 @@ theorem tendsto_addHaar_inter_smul_one_of_density_one_aux (s : Set E) (hs : Meas
rintro r (rpos : 0 < r)
refine I ({x} + r • t) s ?_ ?_ hs
· simp only [h't, abs_of_nonneg rpos.le, pow_pos rpos, addHaar_smul, image_add_left,
- ENNReal.ofReal_eq_zero, not_le, or_false_iff, Ne, measure_preimage_add, abs_pow,
+ ENNReal.ofReal_eq_zero, not_le, or_false, Ne, measure_preimage_add, abs_pow,
singleton_add, mul_eq_zero]
· simp [h''t, ENNReal.ofReal_ne_top, addHaar_smul, image_add_left, ENNReal.mul_eq_top,
- Ne, not_false_iff, measure_preimage_add, singleton_add, and_false_iff, false_and_iff,
- or_self_iff]
+ Ne, not_false_iff, measure_preimage_add, singleton_add, or_self_iff]
/-- Consider a point `x` at which a set `s` has density one, with respect to closed balls (i.e.,
a Lebesgue density point of `s`). Then `s` has also density one at `x` with respect to any
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 a43d6a7133501..8cde3b7093566 100644
--- a/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean
+++ b/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean
@@ -40,7 +40,7 @@ Using these formulas, we compute the volume of the unit balls in several cases.
section general_case
-open MeasureTheory MeasureTheory.Measure FiniteDimensional ENNReal
+open MeasureTheory MeasureTheory.Measure Module ENNReal
theorem MeasureTheory.measure_unitBall_eq_integral_div_gamma {E : Type*} {p : ℝ}
[NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] [MeasurableSpace E]
@@ -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 : ℝ) :
@@ -160,7 +160,7 @@ end general_case
section LpSpace
-open Real Fintype ENNReal FiniteDimensional MeasureTheory MeasureTheory.Measure
+open Real Fintype ENNReal Module MeasureTheory MeasureTheory.Measure
variable (ι : Type*) [Fintype ι] {p : ℝ}
@@ -212,7 +212,7 @@ theorem MeasureTheory.volume_sum_rpow_lt [Nonempty ι] {p : ℝ} (hp : 1 ≤ p)
simp_rw [← Set.preimage_smul_inv₀ (ne_of_gt hr), Set.preimage_setOf_eq, Pi.smul_apply,
smul_eq_mul, abs_mul, mul_rpow (abs_nonneg _) (abs_nonneg _), abs_inv,
inv_rpow (abs_nonneg _), ← Finset.mul_sum, abs_eq_self.mpr (le_of_lt hr),
- inv_mul_lt_iff (rpow_pos_of_pos hr _), mul_one, ← rpow_lt_rpow_iff
+ inv_mul_lt_iff₀ (rpow_pos_of_pos hr _), mul_one, ← rpow_lt_rpow_iff
(rpow_nonneg (h₁ _) _) (le_of_lt hr) (by linarith : 0 < p), ← rpow_mul
(h₁ _), div_mul_cancel₀ _ (ne_of_gt (by linarith) : p ≠ 0), Real.rpow_one]
@@ -284,7 +284,7 @@ theorem Complex.volume_sum_rpow_lt [Nonempty ι] {p : ℝ} (hp : 1 ≤ p) (r :
convert addHaar_smul_of_nonneg volume (le_of_lt hr) {x : ι → ℂ | ∑ i, ‖x i‖ ^ p < 1} using 2
· simp_rw [← Set.preimage_smul_inv₀ (ne_of_gt hr), Set.preimage_setOf_eq, Pi.smul_apply,
norm_smul, mul_rpow (norm_nonneg _) (norm_nonneg _), Real.norm_eq_abs, abs_inv, inv_rpow
- (abs_nonneg _), ← Finset.mul_sum, abs_eq_self.mpr (le_of_lt hr), inv_mul_lt_iff
+ (abs_nonneg _), ← Finset.mul_sum, abs_eq_self.mpr (le_of_lt hr), inv_mul_lt_iff₀
(rpow_pos_of_pos hr _), mul_one, ← rpow_lt_rpow_iff (rpow_nonneg (h₁ _) _)
(le_of_lt hr) (by linarith : 0 < p), ← rpow_mul (h₁ _), div_mul_cancel₀ _
(ne_of_gt (by linarith) : p ≠ 0), Real.rpow_one]
@@ -350,7 +350,7 @@ end EuclideanSpace
section InnerProductSpace
-open MeasureTheory MeasureTheory.Measure ENNReal Real FiniteDimensional
+open MeasureTheory MeasureTheory.Measure ENNReal Real Module
variable {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℝ E] [FiniteDimensional ℝ E]
[MeasurableSpace E] [BorelSpace E] [Nontrivial E]
diff --git a/Mathlib/MeasureTheory/Measure/LevyProkhorovMetric.lean b/Mathlib/MeasureTheory/Measure/LevyProkhorovMetric.lean
index 5b7eb39f8469e..02ed4b6805a38 100644
--- a/Mathlib/MeasureTheory/Measure/LevyProkhorovMetric.lean
+++ b/Mathlib/MeasureTheory/Measure/LevyProkhorovMetric.lean
@@ -28,10 +28,6 @@ import Mathlib.MeasureTheory.Integral.BoundedContinuousFunction
probability measures on a separable space coincides with the topology of convergence in
distribution, and in particular convergence in distribution is then pseudometrizable.
-## TODO
-
-* Show that in Borel spaces, the Lévy-Prokhorov distance is a metric; not just a pseudometric.
-
## Tags
finite measure, probability measure, weak convergence, convergence in distribution, metrizability
@@ -47,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}`. -/
@@ -198,6 +194,9 @@ lemma levyProkhorovDist_triangle [OpensMeasurableSpace Ω] (μ ν κ : Measure
when they are to be equipped with the Lévy-Prokhorov distance. -/
def LevyProkhorov (α : Type*) := α
+/-- The "identity" equivalence between the type synonym `LevyProkhorov α` and `α`. -/
+def LevyProkhorov.equiv (α : Type*) : LevyProkhorov α ≃ α := Equiv.refl _
+
variable [OpensMeasurableSpace Ω]
/-- The Lévy-Prokhorov distance `levyProkhorovEDist` makes `Measure Ω` a pseudoemetric
@@ -214,25 +213,82 @@ 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]
-/-- The Lévy-Prokhorov distance `levyProkhorovDist` makes `ProbabilityMeasure Ω` a pseudoemetric
+lemma measure_le_measure_closure_of_levyProkhorovEDist_eq_zero {μ ν : Measure Ω}
+ (hLP : levyProkhorovEDist μ ν = 0) {s : Set Ω} (s_mble : MeasurableSet s)
+ (h_finite : ∃ δ > 0, ν (thickening δ s) ≠ ∞) :
+ μ s ≤ ν (closure s) := by
+ have key : Tendsto (fun ε ↦ ν (thickening ε.toReal s)) (𝓝[>] (0 : ℝ≥0∞)) (𝓝 (ν (closure s))) := by
+ have aux : Tendsto ENNReal.toReal (𝓝[>] 0) (𝓝[>] 0) := by
+ apply tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within (s := Ioi 0) ENNReal.toReal
+ · exact tendsto_nhdsWithin_of_tendsto_nhds (continuousAt_toReal zero_ne_top).tendsto
+ · filter_upwards [Ioo_mem_nhdsWithin_Ioi ⟨le_rfl, zero_lt_one⟩] with x hx
+ exact toReal_pos hx.1.ne.symm <| ne_top_of_lt hx.2
+ exact (tendsto_measure_thickening h_finite).comp aux
+ have obs := Tendsto.add key (tendsto_nhdsWithin_of_tendsto_nhds tendsto_id)
+ simp only [id_eq, add_zero] at obs
+ apply ge_of_tendsto (b := μ s) obs
+ filter_upwards [self_mem_nhdsWithin] with ε ε_pos
+ exact left_measure_le_of_levyProkhorovEDist_lt (B_mble := s_mble) (hLP ▸ ε_pos)
+
+/-- Two measures at vanishing Lévy-Prokhorov distance from each other assign the same values to all
+closed sets. -/
+lemma measure_eq_measure_of_levyProkhorovEDist_eq_zero_of_isClosed {μ ν : Measure Ω}
+ (hLP : levyProkhorovEDist μ ν = 0) {s : Set Ω} (s_closed : IsClosed s)
+ (hμs : ∃ δ > 0, μ (thickening δ s) ≠ ∞) (hνs : ∃ δ > 0, ν (thickening δ s) ≠ ∞) :
+ μ s = ν s := by
+ apply le_antisymm
+ · exact measure_le_measure_closure_of_levyProkhorovEDist_eq_zero
+ hLP s_closed.measurableSet hνs |>.trans <|
+ le_of_eq (congr_arg _ s_closed.closure_eq)
+ · exact measure_le_measure_closure_of_levyProkhorovEDist_eq_zero
+ (levyProkhorovEDist_comm μ ν ▸ hLP) s_closed.measurableSet hμs |>.trans <|
+ le_of_eq (congr_arg _ s_closed.closure_eq)
+
+/-- The Lévy-Prokhorov distance `levyProkhorovDist` makes `ProbabilityMeasure Ω` a pseudometric
space. The instance is recorded on the type synonym
-`LevyProkhorov (ProbabilityMeasure Ω) := ProbabilityMeasure Ω`. -/
+`LevyProkhorov (ProbabilityMeasure Ω) := ProbabilityMeasure Ω`.
+
+Note: For this pseudometric to give the topology of convergence in distribution, one must
+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 Ω)) :
dist μ ν = levyProkhorovDist μ.toMeasure ν.toMeasure := rfl
+/-- If `Ω` is a Borel space, then the Lévy-Prokhorov distance `levyProkhorovDist` makes
+`ProbabilityMeasure Ω` a metric space. The instance is recorded on the type synonym
+`LevyProkhorov (ProbabilityMeasure Ω) := ProbabilityMeasure Ω`.
+
+Note: For this metric to give the topology of convergence in distribution, one must
+furthermore assume that `Ω` is separable. -/
+noncomputable instance levyProkhorovDist_metricSpace_probabilityMeasure [BorelSpace Ω] :
+ MetricSpace (LevyProkhorov (ProbabilityMeasure Ω)) where
+ eq_of_dist_eq_zero := by
+ intro μ ν h
+ apply (LevyProkhorov.equiv _).injective
+ apply ProbabilityMeasure.toMeasure_injective
+ apply ext_of_generate_finite _ ?_ isPiSystem_isClosed ?_ (by simp)
+ · rw [BorelSpace.measurable_eq (α := Ω), borel_eq_generateFrom_isClosed]
+ · intro A A_closed
+ apply measure_eq_measure_of_levyProkhorovEDist_eq_zero_of_isClosed
+ · simpa only [levyProkhorovEDist_ne_top μ.toMeasure ν.toMeasure, mem_setOf_eq,
+ or_false, ne_eq, zero_ne_top, not_false_eq_true, zero_toReal]
+ using (toReal_eq_zero_iff _).mp h
+ · exact A_closed
+ · exact ⟨1, Real.zero_lt_one, measure_ne_top _ _⟩
+ · exact ⟨1, Real.zero_lt_one, measure_ne_top _ _⟩
+
/-- A simple sufficient condition for bounding `levyProkhorovEDist` between probability measures
from above. The condition involves only one of two natural bounds, the other bound is for free. -/
lemma levyProkhorovEDist_le_of_forall_le
@@ -277,21 +333,7 @@ section Levy_Prokhorov_is_finer
open BoundedContinuousFunction
-variable {ι : Type*} {Ω : Type*} [MeasurableSpace Ω]
-
-/-- Coercion from the type synonym `LevyProkhorov (ProbabilityMeasure Ω)`
-to `ProbabilityMeasure Ω`. -/
-def LevyProkhorov.toProbabilityMeasure (μ : LevyProkhorov (ProbabilityMeasure Ω)) :
- ProbabilityMeasure Ω := μ
-
-/-- Coercion to the type synonym `LevyProkhorov (ProbabilityMeasure Ω)`
-from `ProbabilityMeasure Ω`. -/
-def ProbabilityMeasure.toLevyProkhorov (μ : ProbabilityMeasure Ω) :
- LevyProkhorov (ProbabilityMeasure Ω) := μ
-
-/-- Coercion from the type synonym `LevyProkhorov (FiniteMeasure Ω)` to `FiniteMeasure Ω`. -/
-def LevyProkhorov.finiteMeasure (μ : LevyProkhorov (FiniteMeasure Ω)) :
- FiniteMeasure Ω := μ
+variable {Ω : Type*} [MeasurableSpace Ω]
variable [PseudoMetricSpace Ω] [OpensMeasurableSpace Ω]
@@ -384,13 +426,13 @@ lemma tendsto_integral_meas_thickening_le (f : Ω →ᵇ ℝ)
· exact isClosed_le continuous_const f.continuous
· exact measure_ne_top _ _
-/-- The coercion `LevyProkhorov (ProbabilityMeasure Ω) → ProbabilityMeasure Ω` is continuous. -/
-lemma LevyProkhorov.continuous_toProbabilityMeasure :
- Continuous (LevyProkhorov.toProbabilityMeasure (Ω := Ω)) := by
+/-- The identity map `LevyProkhorov (ProbabilityMeasure Ω) → ProbabilityMeasure Ω` is continuous. -/
+lemma LevyProkhorov.continuous_equiv_probabilityMeasure :
+ Continuous (LevyProkhorov.equiv (α := ProbabilityMeasure Ω)) := by
refine SeqContinuous.continuous ?_
intro μs ν hμs
- set P := ν.toProbabilityMeasure -- more palatable notation
- set Ps := fun n ↦ (μs n).toProbabilityMeasure -- more palatable notation
+ set P := LevyProkhorov.equiv _ ν -- more palatable notation
+ set Ps := fun n ↦ LevyProkhorov.equiv _ (μs n) -- more palatable notation
rw [ProbabilityMeasure.tendsto_iff_forall_integral_tendsto]
refine fun f ↦ tendsto_integral_of_forall_limsup_integral_le_integral ?_ f
intro f f_nn
@@ -433,9 +475,8 @@ lemma LevyProkhorov.continuous_toProbabilityMeasure :
· rw [ENNReal.ofReal_add (by positivity) (by positivity), ← add_zero (levyProkhorovEDist _ _)]
apply ENNReal.add_lt_add_of_le_of_lt (levyProkhorovEDist_ne_top _ _)
(le_of_eq ?_) (ofReal_pos.mpr εs_pos)
- rw [LevyProkhorov.dist_def, levyProkhorovDist,
- ofReal_toReal (levyProkhorovEDist_ne_top _ _)]
- simp only [Ps, P, LevyProkhorov.toProbabilityMeasure]
+ rw [LevyProkhorov.dist_def, levyProkhorovDist, ofReal_toReal (levyProkhorovEDist_ne_top _ _)]
+ rfl
· exact Eventually.of_forall f_nn
· simp only [IsCoboundedUnder, IsCobounded, eventually_map, eventually_atTop,
forall_exists_index]
@@ -444,9 +485,9 @@ lemma LevyProkhorov.continuous_toProbabilityMeasure :
/-- The topology of the Lévy-Prokhorov metric is at least as fine as the topology of convergence in
distribution. -/
theorem levyProkhorov_le_convergenceInDistribution :
- TopologicalSpace.coinduced (LevyProkhorov.toProbabilityMeasure (Ω := Ω)) inferInstance
+ TopologicalSpace.coinduced (LevyProkhorov.equiv (α := ProbabilityMeasure Ω)) inferInstance
≤ (inferInstance : TopologicalSpace (ProbabilityMeasure Ω)) :=
- (LevyProkhorov.continuous_toProbabilityMeasure).coinduced_le
+ (LevyProkhorov.continuous_equiv_probabilityMeasure).coinduced_le
end Levy_Prokhorov_is_finer
@@ -456,13 +497,34 @@ 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 Ω)
+ {G : Set Ω} (G_open : IsOpen G) {ε : ℝ≥0∞} (ε_pos : 0 < ε) :
+ {Q | P.toMeasure G < Q.toMeasure G + ε} ∈ 𝓝 P := by
+ by_cases easy : P.toMeasure G < ε
+ · exact Eventually.of_forall (fun _ ↦ lt_of_lt_of_le easy le_add_self)
+ by_cases ε_top : ε = ∞
+ · simp [ε_top, measure_lt_top]
+ simp only [not_lt] at easy
+ have aux : P.toMeasure G - ε < liminf (fun Q ↦ Q.toMeasure G) (𝓝 P) := by
+ apply lt_of_lt_of_le (ENNReal.sub_lt_self (measure_lt_top _ _).ne _ _)
+ <| ProbabilityMeasure.le_liminf_measure_open_of_tendsto tendsto_id G_open
+ · exact (lt_of_lt_of_le ε_pos easy).ne.symm
+ · exact ε_pos.ne.symm
+ filter_upwards [gt_mem_sets_of_limsInf_gt (α := ℝ≥0∞) isBounded_ge_of_bot
+ (show P.toMeasure G - ε < limsInf ((𝓝 P).map (fun Q ↦ Q.toMeasure G)) from aux)] with Q hQ
+ simp only [preimage_setOf_eq, mem_setOf_eq] at hQ
+ convert ENNReal.add_lt_add_right ε_top hQ
+ exact (tsub_add_cancel_of_le easy).symm
+
+variable [SeparableSpace Ω]
+
+variable (Ω) in
/-- In a separable pseudometric space, for any ε > 0 there exists a countable collection of
disjoint Borel measurable subsets of diameter at most ε that cover the whole space. -/
-lemma SeparableSpace.exists_measurable_partition_diam_le [SeparableSpace Ω]
- {ε : ℝ} (ε_pos : 0 < ε) :
+lemma SeparableSpace.exists_measurable_partition_diam_le {ε : ℝ} (ε_pos : 0 < ε) :
∃ (As : ℕ → Set Ω), (∀ n, MeasurableSet (As n)) ∧ (∀ n, Bornology.IsBounded (As n)) ∧
(∀ n, diam (As n) ≤ ε) ∧ (⋃ n, As n = univ) ∧
(Pairwise (fun (n m : ℕ) ↦ Disjoint (As n) (As m))) := by
@@ -492,29 +554,8 @@ lemma SeparableSpace.exists_measurable_partition_diam_le [SeparableSpace Ω]
simpa only [← aux] using iUnion_disjointed
· exact disjoint_disjointed Bs
-variable {Ω}
-
-lemma ProbabilityMeasure.toMeasure_add_pos_gt_mem_nhds (P : ProbabilityMeasure Ω)
- {G : Set Ω} (G_open : IsOpen G) {ε : ℝ≥0∞} (ε_pos : 0 < ε) :
- {Q | P.toMeasure G < Q.toMeasure G + ε} ∈ 𝓝 P := by
- by_cases easy : P.toMeasure G < ε
- · exact Eventually.of_forall (fun _ ↦ lt_of_lt_of_le easy le_add_self)
- by_cases ε_top : ε = ∞
- · simp [ε_top, measure_lt_top]
- simp only [not_lt] at easy
- have aux : P.toMeasure G - ε < liminf (fun Q ↦ Q.toMeasure G) (𝓝 P) := by
- apply lt_of_lt_of_le (ENNReal.sub_lt_self (measure_lt_top _ _).ne _ _)
- <| ProbabilityMeasure.le_liminf_measure_open_of_tendsto tendsto_id G_open
- · exact (lt_of_lt_of_le ε_pos easy).ne.symm
- · exact ε_pos.ne.symm
- filter_upwards [gt_mem_sets_of_limsInf_gt (α := ℝ≥0∞) isBounded_ge_of_bot
- (show P.toMeasure G - ε < limsInf ((𝓝 P).map (fun Q ↦ Q.toMeasure G)) from aux)] with Q hQ
- simp only [preimage_setOf_eq, mem_setOf_eq] at hQ
- convert ENNReal.add_lt_add_right ε_top hQ
- exact (tsub_add_cancel_of_le easy).symm
-
-lemma ProbabilityMeasure.continuous_toLevyProkhorov [SeparableSpace Ω] :
- Continuous (ProbabilityMeasure.toLevyProkhorov (Ω := Ω)) := by
+lemma LevyProkhorov.continuous_equiv_symm_probabilityMeasure :
+ Continuous (LevyProkhorov.equiv (α := ProbabilityMeasure Ω)).symm := by
-- We check continuity of `id : ProbabilityMeasure Ω → LevyProkhorov (ProbabilityMeasure Ω)` at
-- each point `P : ProbabilityMeasure Ω`.
rw [continuous_iff_continuousAt]
@@ -612,29 +653,36 @@ lemma ProbabilityMeasure.continuous_toLevyProkhorov [SeparableSpace Ω] :
/-- The topology of the Lévy-Prokhorov metric on probability measures on a separable space
coincides with the topology of convergence in distribution. -/
-theorem levyProkhorov_eq_convergenceInDistribution [SeparableSpace Ω] :
+theorem levyProkhorov_eq_convergenceInDistribution :
(inferInstance : TopologicalSpace (ProbabilityMeasure Ω))
- = TopologicalSpace.coinduced (LevyProkhorov.toProbabilityMeasure (Ω := Ω)) inferInstance :=
- le_antisymm (ProbabilityMeasure.continuous_toLevyProkhorov (Ω := Ω)).coinduced_le
+ = TopologicalSpace.coinduced (LevyProkhorov.equiv _) inferInstance :=
+ le_antisymm (LevyProkhorov.continuous_equiv_symm_probabilityMeasure (Ω := Ω)).coinduced_le
levyProkhorov_le_convergenceInDistribution
/-- The identity map is a homeomorphism from `ProbabilityMeasure Ω` with the topology of
convergence in distribution to `ProbabilityMeasure Ω` with the Lévy-Prokhorov (pseudo)metric. -/
-def homeomorph_probabilityMeasure_levyProkhorov [SeparableSpace Ω] :
+def homeomorph_probabilityMeasure_levyProkhorov :
ProbabilityMeasure Ω ≃ₜ LevyProkhorov (ProbabilityMeasure Ω) where
- toFun := ProbabilityMeasure.toLevyProkhorov (Ω := Ω)
- invFun := LevyProkhorov.toProbabilityMeasure (Ω := Ω)
+ toFun := LevyProkhorov.equiv _
+ invFun := (LevyProkhorov.equiv _).symm
left_inv := congrFun rfl
right_inv := congrFun rfl
- continuous_toFun := ProbabilityMeasure.continuous_toLevyProkhorov
- continuous_invFun := LevyProkhorov.continuous_toProbabilityMeasure
+ continuous_toFun := LevyProkhorov.continuous_equiv_symm_probabilityMeasure
+ continuous_invFun := LevyProkhorov.continuous_equiv_probabilityMeasure
/-- The topology of convergence in distribution on a separable space is pseudo-metrizable. -/
instance (X : Type*) [TopologicalSpace X] [PseudoMetrizableSpace X] [SeparableSpace X]
[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.isEmbedding.metrizableSpace
end Levy_Prokhorov_metrizes_convergence_in_distribution
diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean
index e14f83eb3ffb8..cb05efae203e2 100644
--- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean
+++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean
@@ -7,6 +7,7 @@ import Mathlib.MeasureTheory.Measure.NullMeasurable
import Mathlib.MeasureTheory.MeasurableSpace.Embedding
import Mathlib.MeasureTheory.OuterMeasure.BorelCantelli
import Mathlib.Topology.Algebra.Order.LiminfLimsup
+import Mathlib.Order.Interval.Set.Monotone
/-!
# Measure spaces
@@ -170,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]
@@ -181,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)
@@ -213,7 +214,7 @@ theorem measure_add_diff (hs : NullMeasurableSet s μ) (t : Set α) :
theorem measure_diff' (s : Set α) (hm : NullMeasurableSet t μ) (h_fin : μ t ≠ ∞) :
μ (s \ t) = μ (s ∪ t) - μ t :=
- Eq.symm <| ENNReal.sub_eq_of_add_eq h_fin <| by rw [add_comm, measure_add_diff hm, union_comm]
+ ENNReal.eq_sub_of_add_eq h_fin <| by rw [add_comm, measure_add_diff hm, union_comm]
theorem measure_diff (h : s₂ ⊆ s₁) (h₂ : NullMeasurableSet s₂ μ) (h_fin : μ s₂ ≠ ∞) :
μ (s₁ \ s₂) = μ s₁ - μ s₂ := by rw [measure_diff' _ h₂ h_fin, union_eq_self_of_subset_right h]
@@ -311,14 +312,15 @@ theorem ae_eq_of_subset_of_measure_ge (h₁ : s ⊆ t) (h₂ : μ t ≤ μ s) (h
(ht : μ t ≠ ∞) : s =ᵐ[μ] t :=
ae_eq_of_ae_subset_of_measure_ge (HasSubset.Subset.eventuallyLE h₁) h₂ hsm ht
-theorem measure_iUnion_congr_of_subset [Countable β] {s : β → Set α} {t : β → Set α}
- (hsub : ∀ b, s b ⊆ t b) (h_le : ∀ b, μ (t b) ≤ μ (s b)) : μ (⋃ b, s b) = μ (⋃ b, t b) := by
- rcases Classical.em (∃ b, μ (t b) = ∞) with (⟨b, hb⟩ | htop)
+theorem measure_iUnion_congr_of_subset {ι : Sort*} [Countable ι] {s : ι → Set α} {t : ι → Set α}
+ (hsub : ∀ i, s i ⊆ t i) (h_le : ∀ i, μ (t i) ≤ μ (s i)) : μ (⋃ i, s i) = μ (⋃ i, t i) := by
+ refine le_antisymm (by gcongr; apply hsub) ?_
+ rcases Classical.em (∃ i, μ (t i) = ∞) with (⟨i, hi⟩ | htop)
· calc
- μ (⋃ b, s b) = ∞ := top_unique (hb ▸ (h_le b).trans <| measure_mono <| subset_iUnion _ _)
- _ = μ (⋃ b, t b) := Eq.symm <| top_unique <| hb ▸ measure_mono (subset_iUnion _ _)
+ μ (⋃ i, t i) ≤ ∞ := le_top
+ _ ≤ μ (s i) := hi ▸ h_le i
+ _ ≤ μ (⋃ i, s i) := measure_mono <| subset_iUnion _ _
push_neg at htop
- refine le_antisymm (measure_mono (iUnion_mono hsub)) ?_
set M := toMeasurable μ
have H : ∀ b, (M (t b) ∩ M (⋃ b, s b) : Set α) =ᵐ[μ] M (t b) := by
refine fun b => ae_eq_of_subset_of_measure_ge inter_subset_left ?_ ?_ ?_
@@ -344,11 +346,10 @@ theorem measure_union_congr_of_subset {t₁ t₂ : Set α} (hs : s₁ ⊆ s₂)
exact measure_iUnion_congr_of_subset (Bool.forall_bool.2 ⟨ht, hs⟩) (Bool.forall_bool.2 ⟨htμ, hsμ⟩)
@[simp]
-theorem measure_iUnion_toMeasurable [Countable β] (s : β → Set α) :
- μ (⋃ b, toMeasurable μ (s b)) = μ (⋃ b, s b) :=
- Eq.symm <|
- measure_iUnion_congr_of_subset (fun _b => subset_toMeasurable _ _) fun _b =>
- (measure_toMeasurable _).le
+theorem measure_iUnion_toMeasurable {ι : Sort*} [Countable ι] (s : ι → Set α) :
+ μ (⋃ i, toMeasurable μ (s i)) = μ (⋃ i, s i) :=
+ Eq.symm <| measure_iUnion_congr_of_subset (fun _i => subset_toMeasurable _ _) fun _i ↦
+ (measure_toMeasurable _).le
theorem measure_biUnion_toMeasurable {I : Set β} (hc : I.Countable) (s : β → Set α) :
μ (⋃ b ∈ I, toMeasurable μ (s b)) = μ (⋃ b ∈ I, s b) := by
@@ -420,30 +421,28 @@ theorem nonempty_inter_of_measure_lt_add' {m : MeasurableSpace α} (μ : Measure
rw [inter_comm]
exact nonempty_inter_of_measure_lt_add μ hs h't h's h
-/-- Continuity from below: the measure of the union of a directed sequence of (not necessarily
--measurable) sets is the supremum of the measures. -/
-theorem measure_iUnion_eq_iSup [Countable ι] {s : ι → Set α} (hd : Directed (· ⊆ ·) s) :
+/-- Continuity from below:
+the measure of the union of a directed sequence of (not necessarily measurable) sets
+is the supremum of the measures. -/
+theorem _root_.Directed.measure_iUnion [Countable ι] {s : ι → Set α} (hd : Directed (· ⊆ ·) s) :
μ (⋃ i, s i) = ⨆ i, μ (s i) := by
- cases nonempty_encodable ι
-- WLOG, `ι = ℕ`
- generalize ht : Function.extend Encodable.encode s ⊥ = t
- replace hd : Directed (· ⊆ ·) t := ht ▸ hd.extend_bot Encodable.encode_injective
+ rcases Countable.exists_injective_nat ι with ⟨e, he⟩
+ generalize ht : Function.extend e s ⊥ = t
+ replace hd : Directed (· ⊆ ·) t := ht ▸ hd.extend_bot he
suffices μ (⋃ n, t n) = ⨆ n, μ (t n) by
- simp only [← ht, Function.apply_extend μ, ← iSup_eq_iUnion,
- iSup_extend_bot Encodable.encode_injective, Function.comp_def, Pi.bot_apply, bot_eq_empty,
- measure_empty] at this
- exact this.trans (iSup_extend_bot Encodable.encode_injective _)
+ simp only [← ht, Function.apply_extend μ, ← iSup_eq_iUnion, iSup_extend_bot he,
+ Function.comp_def, Pi.bot_apply, bot_eq_empty, measure_empty] at this
+ exact this.trans (iSup_extend_bot he _)
clear! ι
-- The `≥` inequality is trivial
- refine le_antisymm ?_ (iSup_le fun i => measure_mono <| subset_iUnion _ _)
+ refine le_antisymm ?_ (iSup_le fun i ↦ measure_mono <| subset_iUnion _ _)
-- Choose `T n ⊇ t n` of the same measure, put `Td n = disjointed T`
set T : ℕ → Set α := fun n => toMeasurable μ (t n)
set Td : ℕ → Set α := disjointed T
- have hm : ∀ n, MeasurableSet (Td n) :=
- MeasurableSet.disjointed fun n => measurableSet_toMeasurable _ _
+ have hm : ∀ n, MeasurableSet (Td n) := .disjointed fun n ↦ measurableSet_toMeasurable _ _
calc
- μ (⋃ n, t n) ≤ μ (⋃ n, T n) := measure_mono (iUnion_mono fun i => subset_toMeasurable _ _)
- _ = μ (⋃ n, Td n) := by rw [iUnion_disjointed]
+ μ (⋃ n, t n) = μ (⋃ n, Td n) := by rw [iUnion_disjointed, measure_iUnion_toMeasurable]
_ ≤ ∑' n, μ (Td n) := measure_iUnion_le _
_ = ⨆ I : Finset ℕ, ∑ n ∈ I, μ (Td n) := ENNReal.tsum_eq_iSup_sum
_ ≤ ⨆ n, μ (t n) := iSup_le fun I => by
@@ -456,23 +455,48 @@ theorem measure_iUnion_eq_iSup [Countable ι] {s : ι → Set α} (hd : Directed
_ ≤ μ (t N) := measure_mono (iUnion₂_subset hN)
_ ≤ ⨆ n, μ (t n) := le_iSup (μ ∘ t) N
+@[deprecated (since := "2024-09-01")] alias measure_iUnion_eq_iSup := Directed.measure_iUnion
+
+/-- Continuity from below:
+the measure of the union of a monotone family of sets is equal to the supremum of their measures.
+The theorem assumes that the `atTop` filter on the index set is countably generated,
+so it works for a family indexed by a countable type, as well as `ℝ`. -/
+theorem _root_.Monotone.measure_iUnion [Preorder ι] [IsDirected ι (· ≤ ·)]
+ [(atTop : Filter ι).IsCountablyGenerated] {s : ι → Set α} (hs : Monotone s) :
+ μ (⋃ i, s i) = ⨆ i, μ (s i) := by
+ refine le_antisymm ?_ (iSup_le fun i ↦ measure_mono <| subset_iUnion _ _)
+ cases isEmpty_or_nonempty ι with
+ | inl _ => simp
+ | inr _ =>
+ rcases exists_seq_monotone_tendsto_atTop_atTop ι with ⟨x, hxm, hx⟩
+ calc
+ μ (⋃ i, s i) ≤ μ (⋃ n, s (x n)) := by
+ refine measure_mono <| iUnion_mono' fun i ↦ ?_
+ rcases (hx.eventually_ge_atTop i).exists with ⟨n, hn⟩
+ exact ⟨n, hs hn⟩
+ _ = ⨆ n, μ (s (x n)) := (hs.comp hxm).directed_le.measure_iUnion
+ _ ≤ ⨆ i, μ (s i) := iSup_comp_le (μ ∘ s) x
+
+theorem _root_.Antitone.measure_iUnion [Preorder ι] [IsDirected ι (· ≥ ·)]
+ [(atBot : Filter ι).IsCountablyGenerated] {s : ι → Set α} (hs : Antitone s) :
+ μ (⋃ i, s i) = ⨆ i, μ (s i) :=
+ hs.dual_left.measure_iUnion
+
/-- Continuity from below: the measure of the union of a sequence of
(not necessarily measurable) sets is the supremum of the measures of the partial unions. -/
-theorem measure_iUnion_eq_iSup' {α ι : Type*} [MeasurableSpace α] {μ : Measure α}
- [Countable ι] [Preorder ι] [IsDirected ι (· ≤ ·)]
- {f : ι → Set α} : μ (⋃ i, f i) = ⨆ i, μ (Accumulate f i) := by
- have hd : Directed (· ⊆ ·) (Accumulate f) := by
- intro i j
- rcases directed_of (· ≤ ·) i j with ⟨k, rik, rjk⟩
- exact ⟨k, biUnion_subset_biUnion_left fun l rli ↦ le_trans rli rik,
- biUnion_subset_biUnion_left fun l rlj ↦ le_trans rlj rjk⟩
+theorem measure_iUnion_eq_iSup_accumulate [Preorder ι] [IsDirected ι (· ≤ ·)]
+ [(atTop : Filter ι).IsCountablyGenerated] {f : ι → Set α} :
+ μ (⋃ i, f i) = ⨆ i, μ (Accumulate f i) := by
rw [← iUnion_accumulate]
- exact measure_iUnion_eq_iSup hd
+ exact monotone_accumulate.measure_iUnion
+
+@[deprecated (since := "2024-09-01")]
+alias measure_iUnion_eq_iSup' := measure_iUnion_eq_iSup_accumulate
theorem measure_biUnion_eq_iSup {s : ι → Set α} {t : Set ι} (ht : t.Countable)
(hd : DirectedOn ((· ⊆ ·) on s) t) : μ (⋃ i ∈ t, s i) = ⨆ i ∈ t, μ (s i) := by
- haveI := ht.toEncodable
- rw [biUnion_eq_iUnion, measure_iUnion_eq_iSup hd.directed_val, ← iSup_subtype'']
+ haveI := ht.to_subtype
+ rw [biUnion_eq_iUnion, hd.directed_val.measure_iUnion, ← iSup_subtype'']
/-- Continuity from above: the measure of the intersection of a decreasing sequence of measurable
sets is the infimum of the measures. -/
@@ -483,19 +507,18 @@ theorem measure_iInter_eq_iInf [Countable ι] {s : ι → Set α} (h : ∀ i, Nu
rw [← ENNReal.sub_sub_cancel hk (iInf_le _ k), ENNReal.sub_iInf, ←
ENNReal.sub_sub_cancel hk (measure_mono (iInter_subset _ k)), ←
measure_diff (iInter_subset _ k) (.iInter h) (this _ (iInter_subset _ k)),
- diff_iInter, measure_iUnion_eq_iSup]
+ diff_iInter, Directed.measure_iUnion]
· congr 1
- refine le_antisymm (iSup_mono' fun i => ?_) (iSup_mono fun i => ?_)
- · rcases hd i k with ⟨j, hji, hjk⟩
- use j
- rw [← measure_diff hjk (h _) (this _ hjk)]
- gcongr
- · apply le_measure_diff
+ refine le_antisymm (iSup_mono' fun i => ?_) (iSup_mono fun i => le_measure_diff)
+ rcases hd i k with ⟨j, hji, hjk⟩
+ use j
+ rw [← measure_diff hjk (h _) (this _ hjk)]
+ gcongr
· exact hd.mono_comp _ fun _ _ => diff_subset_diff_right
/-- 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
@@ -506,8 +529,7 @@ theorem measure_iInter_eq_iInf' {α ι : Type*} [MeasurableSpace α] {μ : Measu
· intro h i
rcases directed_of (· ≤ ·) i i with ⟨j, rij, -⟩
exact h j i rij
- have ms : ∀ i, NullMeasurableSet (s i) μ :=
- fun i ↦ .biInter (to_countable _) fun i _ ↦ h i
+ have ms (i) : NullMeasurableSet (s i) μ := .biInter (to_countable _) fun i _ ↦ h i
have hd : Directed (· ⊇ ·) s := by
intro i j
rcases directed_of (· ≤ ·) i j with ⟨k, rik, rjk⟩
@@ -521,30 +543,46 @@ 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 [Preorder ι] [IsDirected ι (· ≤ ·)] [Countable ι]
+theorem tendsto_measure_iUnion_atTop [Preorder ι] [IsCountablyGenerated (atTop : Filter ι)]
{s : ι → Set α} (hm : Monotone s) : Tendsto (μ ∘ s) atTop (𝓝 (μ (⋃ n, s n))) := by
- rw [measure_iUnion_eq_iSup hm.directed_le]
+ 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 ι] [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' {α ι : Type*} [MeasurableSpace α] {μ : Measure α} [Countable ι]
- [Preorder ι] [IsDirected ι (· ≤ ·)] {f : ι → Set α} :
+theorem tendsto_measure_iUnion_accumulate {α ι : Type*}
+ [Preorder ι] [IsCountablyGenerated (atTop : Filter ι)]
+ {_ : MeasurableSpace α} {μ : Measure α} {f : ι → Set α} :
Tendsto (fun i ↦ μ (Accumulate f i)) atTop (𝓝 (μ (⋃ i, f i))) := by
- rw [measure_iUnion_eq_iSup']
+ 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
+@[deprecated (since := "2024-09-01")]
+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
@@ -677,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 }⟩
@@ -691,7 +729,7 @@ theorem coe_zero {_m : MeasurableSpace α} : ⇑(0 : Measure α) = 0 :=
rfl
@[simp] lemma _root_.MeasureTheory.OuterMeasure.toMeasure_zero
- [ms : MeasurableSpace α](h : ms ≤ (0 : OuterMeasure α).caratheodory) :
+ [ms : MeasurableSpace α] (h : ms ≤ (0 : OuterMeasure α).caratheodory) :
(0 : OuterMeasure α).toMeasure h = 0 := by
ext s hs
simp [hs]
@@ -707,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 =>
@@ -736,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
@@ -758,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 _ _⟩
@@ -777,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 _ _
@@ -798,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
@@ -864,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
@@ -886,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)
@@ -912,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 :=
@@ -924,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 := ⊤,
@@ -946,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 }
@@ -959,7 +996,7 @@ theorem _root_.MeasureTheory.OuterMeasure.toMeasure_top :
toOuterMeasure_toMeasure (μ := ⊤)
@[simp]
-theorem toOuterMeasure_top [MeasurableSpace α] :
+theorem toOuterMeasure_top {_ : MeasurableSpace α} :
(⊤ : Measure α).toOuterMeasure = (⊤ : OuterMeasure α) :=
rfl
@@ -991,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 -/
@@ -1193,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]
@@ -1211,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 ⊢
@@ -1256,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 _ _, ?_⟩
@@ -1267,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]
@@ -1441,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
@@ -1511,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
@@ -1664,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
@@ -1678,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
@@ -1699,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ᶜ < ∞ :=
@@ -1796,61 +1837,26 @@ 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 [SemilatticeSup α] [NoMaxOrder α]
+theorem tendsto_measure_Ico_atTop [Preorder α] [NoMaxOrder α]
[(atTop : Filter α).IsCountablyGenerated] (μ : Measure α) (a : α) :
Tendsto (fun x => μ (Ico a x)) atTop (𝓝 (μ (Ici a))) := by
- haveI : Nonempty α := ⟨a⟩
- have h_mono : Monotone fun x => μ (Ico a x) := fun i j hij => by simp only; gcongr
- convert tendsto_atTop_iSup h_mono
- obtain ⟨xs, hxs_mono, hxs_tendsto⟩ := exists_seq_monotone_tendsto_atTop_atTop α
- have h_Ici : Ici a = ⋃ n, Ico a (xs n) := by
- ext1 x
- simp only [mem_Ici, mem_iUnion, mem_Ico, exists_and_left, iff_self_and]
- intro
- obtain ⟨y, hxy⟩ := NoMaxOrder.exists_gt x
- obtain ⟨n, hn⟩ := tendsto_atTop_atTop.mp hxs_tendsto y
- exact ⟨n, hxy.trans_le (hn n le_rfl)⟩
- rw [h_Ici, measure_iUnion_eq_iSup, iSup_eq_iSup_subseq_of_monotone h_mono hxs_tendsto]
- exact Monotone.directed_le fun i j hij => Ico_subset_Ico_right (hxs_mono hij)
-
-theorem tendsto_measure_Ioc_atBot [SemilatticeInf α] [NoMinOrder α]
+ rw [← iUnion_Ico_right]
+ exact tendsto_measure_iUnion_atTop (antitone_const.Ico monotone_id)
+
+theorem tendsto_measure_Ioc_atBot [Preorder α] [NoMinOrder α]
[(atBot : Filter α).IsCountablyGenerated] (μ : Measure α) (a : α) :
Tendsto (fun x => μ (Ioc x a)) atBot (𝓝 (μ (Iic a))) := by
- haveI : Nonempty α := ⟨a⟩
- have h_mono : Antitone fun x => μ (Ioc x a) := fun i j hij => by simp only; gcongr
- convert tendsto_atBot_iSup h_mono
- obtain ⟨xs, hxs_mono, hxs_tendsto⟩ := exists_seq_antitone_tendsto_atTop_atBot α
- have h_Iic : Iic a = ⋃ n, Ioc (xs n) a := by
- ext1 x
- simp only [mem_Iic, mem_iUnion, mem_Ioc, exists_and_right, iff_and_self]
- intro
- obtain ⟨y, hxy⟩ := NoMinOrder.exists_lt x
- obtain ⟨n, hn⟩ := tendsto_atTop_atBot.mp hxs_tendsto y
- exact ⟨n, (hn n le_rfl).trans_lt hxy⟩
- rw [h_Iic, measure_iUnion_eq_iSup, iSup_eq_iSup_subseq_of_antitone h_mono hxs_tendsto]
- exact Monotone.directed_le fun i j hij => Ioc_subset_Ioc_left (hxs_mono hij)
-
-theorem tendsto_measure_Iic_atTop [SemilatticeSup α] [(atTop : Filter α).IsCountablyGenerated]
+ rw [← iUnion_Ioc_left]
+ exact tendsto_measure_iUnion_atBot (monotone_id.Ioc antitone_const)
+
+theorem tendsto_measure_Iic_atTop [Preorder α] [(atTop : Filter α).IsCountablyGenerated]
(μ : Measure α) : Tendsto (fun x => μ (Iic x)) atTop (𝓝 (μ univ)) := by
- cases isEmpty_or_nonempty α
- · have h1 : ∀ x : α, Iic x = ∅ := fun x => Subsingleton.elim _ _
- have h2 : (univ : Set α) = ∅ := Subsingleton.elim _ _
- simp_rw [h1, h2]
- exact tendsto_const_nhds
- have h_mono : Monotone fun x => μ (Iic x) := fun i j hij => by simp only; gcongr
- convert tendsto_atTop_iSup h_mono
- obtain ⟨xs, hxs_mono, hxs_tendsto⟩ := exists_seq_monotone_tendsto_atTop_atTop α
- have h_univ : (univ : Set α) = ⋃ n, Iic (xs n) := by
- ext1 x
- simp only [mem_univ, mem_iUnion, mem_Iic, true_iff_iff]
- obtain ⟨n, hn⟩ := tendsto_atTop_atTop.mp hxs_tendsto x
- exact ⟨n, hn n le_rfl⟩
- rw [h_univ, measure_iUnion_eq_iSup, iSup_eq_iSup_subseq_of_monotone h_mono hxs_tendsto]
- exact Monotone.directed_le fun i j hij => Iic_subset_Iic.mpr (hxs_mono hij)
+ rw [← iUnion_Iic]
+ exact tendsto_measure_iUnion_atTop monotone_Iic
-theorem tendsto_measure_Ici_atBot [SemilatticeInf α] [h : (atBot : Filter α).IsCountablyGenerated]
+theorem tendsto_measure_Ici_atBot [Preorder α] [(atBot : Filter α).IsCountablyGenerated]
(μ : Measure α) : Tendsto (fun x => μ (Ici x)) atBot (𝓝 (μ univ)) :=
- @tendsto_measure_Iic_atTop αᵒᵈ _ _ h μ
+ tendsto_measure_Iic_atTop (α := αᵒᵈ) μ
variable [PartialOrder α] {a b : α}
@@ -1927,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). -/
@@ -1968,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 f1d91454da789..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
@@ -122,6 +120,7 @@ theorem of_subsingleton [Subsingleton α] : NullMeasurableSet s μ :=
protected theorem congr (hs : NullMeasurableSet s μ) (h : s =ᵐ[μ] t) : NullMeasurableSet t μ :=
EventuallyMeasurableSet.congr hs h.symm
+@[measurability]
protected theorem iUnion {ι : Sort*} [Countable ι] {s : ι → Set α}
(h : ∀ i, NullMeasurableSet (s i) μ) : NullMeasurableSet (⋃ i, s i) μ :=
MeasurableSet.iUnion h
@@ -135,6 +134,7 @@ protected theorem sUnion {s : Set (Set α)} (hs : s.Countable) (h : ∀ t ∈ s,
rw [sUnion_eq_biUnion]
exact MeasurableSet.biUnion hs h
+@[measurability]
protected theorem iInter {ι : Sort*} [Countable ι] {f : ι → Set α}
(h : ∀ i, NullMeasurableSet (f i) μ) : NullMeasurableSet (⋂ i, f i) μ :=
MeasurableSet.iInter h
@@ -171,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
@@ -278,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 α μ)]
@@ -396,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/OpenPos.lean b/Mathlib/MeasureTheory/Measure/OpenPos.lean
index 611930fcce591..086d4961c2a0e 100644
--- a/Mathlib/MeasureTheory/Measure/OpenPos.lean
+++ b/Mathlib/MeasureTheory/Measure/OpenPos.lean
@@ -100,6 +100,11 @@ theorem _root_.IsClosed.measure_eq_one_iff_eq_univ [OpensMeasurableSpace X] [IsP
theorem interior_eq_empty_of_null (hs : μ s = 0) : interior s = ∅ :=
isOpen_interior.eq_empty_of_measure_zero <| measure_mono_null interior_subset hs
+/-- A property satisfied almost everywhere is satisfied on a dense subset. -/
+theorem dense_of_ae {p : X → Prop} (hp : ∀ᵐ x ∂μ, p x) : Dense {x | p x} := by
+ rw [dense_iff_closure_eq, closure_eq_compl_interior_compl, compl_univ_iff]
+ exact μ.interior_eq_empty_of_null hp
+
/-- If two functions are a.e. equal on an open set and are continuous on this set, then they are
equal on this set. -/
theorem eqOn_open_of_ae_eq {f g : X → Y} (h : f =ᵐ[μ.restrict U] g) (hU : IsOpen U)
diff --git a/Mathlib/MeasureTheory/Measure/Portmanteau.lean b/Mathlib/MeasureTheory/Measure/Portmanteau.lean
index 37d3edc5f8472..4d82e897d1771 100644
--- a/Mathlib/MeasureTheory/Measure/Portmanteau.lean
+++ b/Mathlib/MeasureTheory/Measure/Portmanteau.lean
@@ -399,13 +399,14 @@ Assuming that for all Borel sets E whose boundary ∂E carries no probability ma
candidate limit probability measure μ we have convergence of the measures μsᵢ(E) to μ(E),
then for all closed sets F we have the limsup condition limsup μsᵢ(F) ≤ μ(F). -/
lemma limsup_measure_closed_le_of_forall_tendsto_measure
- {Ω ι : Type*} {L : Filter ι} [NeBot L]
- [MeasurableSpace Ω] [PseudoEMetricSpace Ω] [OpensMeasurableSpace Ω]
+ {Ω ι : Type*} {L : Filter ι} [MeasurableSpace Ω] [PseudoEMetricSpace Ω] [OpensMeasurableSpace Ω]
{μ : Measure Ω} [IsFiniteMeasure μ] {μs : ι → Measure Ω}
(h : ∀ {E : Set Ω}, MeasurableSet E → μ (frontier E) = 0 →
Tendsto (fun i ↦ μs i E) L (𝓝 (μ E)))
(F : Set Ω) (F_closed : IsClosed F) :
L.limsup (fun i ↦ μs i F) ≤ μ F := by
+ rcases L.eq_or_neBot with rfl | _
+ · simp only [limsup_bot, bot_eq_zero', zero_le]
have ex := exists_null_frontiers_thickening μ F
let rs := Classical.choose ex
have rs_lim : Tendsto rs atTop (𝓝 0) := (Classical.choose_spec ex).1
@@ -435,7 +436,7 @@ Assuming that for all Borel sets E whose boundary ∂E carries no probability ma
candidate limit probability measure μ we have convergence of the measures μsᵢ(E) to μ(E),
then for all open sets G we have the limsup condition μ(G) ≤ liminf μsᵢ(G). -/
lemma le_liminf_measure_open_of_forall_tendsto_measure
- {Ω ι : Type*} {L : Filter ι} [NeBot L]
+ {Ω ι : Type*} {L : Filter ι}
[MeasurableSpace Ω] [PseudoEMetricSpace Ω] [OpensMeasurableSpace Ω]
{μ : Measure Ω} [IsProbabilityMeasure μ] {μs : ι → Measure Ω} [∀ i, IsProbabilityMeasure (μs i)]
(h : ∀ {E}, MeasurableSet E → μ (frontier E) = 0 → Tendsto (fun i ↦ μs i E) L (𝓝 (μ E)))
diff --git a/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean b/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean
index 62aa6c8957d30..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
@@ -504,8 +506,8 @@ lemma map_apply' (ν : ProbabilityMeasure Ω) {f : Ω → Ω'} (f_aemble : AEMea
lemma map_apply_of_aemeasurable (ν : ProbabilityMeasure Ω) {f : Ω → Ω'}
(f_aemble : AEMeasurable f ν) {A : Set Ω'} (A_mble : MeasurableSet A) :
(ν.map f_aemble) A = ν (f ⁻¹' A) := by
- have := ν.map_apply' f_aemble A_mble
- exact (ENNReal.toNNReal_eq_toNNReal_iff' (measure_ne_top _ _) (measure_ne_top _ _)).mpr this
+ exact (ENNReal.toNNReal_eq_toNNReal_iff' (measure_ne_top _ _) (measure_ne_top _ _)).mpr <|
+ ν.map_apply' f_aemble A_mble
lemma map_apply (ν : ProbabilityMeasure Ω) {f : Ω → Ω'} (f_aemble : AEMeasurable f ν)
{A : Set Ω'} (A_mble : MeasurableSet A) :
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 cb00bad6d11e4..f283ccf0b3e83 100644
--- a/Mathlib/MeasureTheory/Measure/Regular.lean
+++ b/Mathlib/MeasureTheory/Measure/Regular.lean
@@ -301,7 +301,7 @@ class WeaklyRegular (μ : Measure α) extends OuterRegular μ : Prop where
/-- A measure `μ` is inner regular if, for any measurable set `s`, then
`μ(s) = sup {μ(K) | K ⊆ s compact}`. -/
class InnerRegular (μ : Measure α) : Prop where
- protected innerRegular : InnerRegularWRT μ IsCompact (fun s ↦ MeasurableSet s)
+ protected innerRegular : InnerRegularWRT μ IsCompact MeasurableSet
/-- A measure `μ` is inner regular for finite measure sets with respect to compact sets:
for any measurable set `s` with finite measure, then `μ(s) = sup {μ(K) | K ⊆ s compact}`.
@@ -457,8 +457,7 @@ lemma of_restrict {μ : Measure α} {s : ℕ → Set α}
intro F hF r hr
have hBU : ⋃ n, F ∩ s n = F := by rw [← inter_iUnion, univ_subset_iff.mp hs, inter_univ]
have : μ F = ⨆ n, μ (F ∩ s n) := by
- rw [← measure_iUnion_eq_iSup, hBU]
- exact Monotone.directed_le fun m n h ↦ inter_subset_inter_right _ (hmono h)
+ rw [← (monotone_const.inter hmono).measure_iUnion, hBU]
rw [this] at hr
rcases lt_iSup_iff.1 hr with ⟨n, hn⟩
rw [← restrict_apply hF] at hn
@@ -509,11 +508,10 @@ lemma of_sigmaFinite [SigmaFinite μ] :
set B : ℕ → Set α := spanningSets μ
have hBU : ⋃ n, s ∩ B n = s := by rw [← inter_iUnion, iUnion_spanningSets, inter_univ]
have : μ s = ⨆ n, μ (s ∩ B n) := by
- rw [← measure_iUnion_eq_iSup, hBU]
- exact Monotone.directed_le fun m n h => inter_subset_inter_right _ (monotone_spanningSets μ h)
+ 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 α]
@@ -574,7 +572,7 @@ theorem weaklyRegular_of_finite [BorelSpace α] (μ : Measure α) [IsFiniteMeasu
refine
⟨Uᶜ, compl_subset_compl.2 hsU, Fᶜ, compl_subset_compl.2 hFs, hUo.isClosed_compl,
hFc.isOpen_compl, ?_⟩
- simp only [measure_compl_le_add_iff, *, hUo.measurableSet, hFc.measurableSet, true_and_iff]
+ simp only [measure_compl_le_add_iff, *, hUo.measurableSet, hFc.measurableSet, true_and]
-- check for disjoint unions
· intro s hsd hsm H ε ε0
have ε0' : ε / 2 ≠ 0 := (ENNReal.half_pos ε0).ne'
@@ -617,7 +615,7 @@ theorem of_pseudoMetrizableSpace {X : Type*} [TopologicalSpace X] [PseudoMetriza
let A : PseudoMetricSpace X := TopologicalSpace.pseudoMetrizableSpacePseudoMetric X
intro U hU r hr
rcases hU.exists_iUnion_isClosed with ⟨F, F_closed, -, rfl, F_mono⟩
- rw [measure_iUnion_eq_iSup F_mono.directed_le] at hr
+ rw [F_mono.measure_iUnion] at hr
rcases lt_iSup_iff.1 hr with ⟨n, hn⟩
exact ⟨F n, subset_iUnion _ _, F_closed n, hn⟩
@@ -629,8 +627,8 @@ theorem isCompact_isClosed {X : Type*} [TopologicalSpace X] [SigmaCompactSpace X
have hBc : ∀ n, IsCompact (F ∩ B n) := fun n => (isCompact_compactCovering X n).inter_left hF
have hBU : ⋃ n, F ∩ B n = F := by rw [← inter_iUnion, iUnion_compactCovering, Set.inter_univ]
have : μ F = ⨆ n, μ (F ∩ B n) := by
- rw [← measure_iUnion_eq_iSup, hBU]
- exact Monotone.directed_le fun m n h => inter_subset_inter_right _ (compactCovering_subset _ h)
+ rw [← Monotone.measure_iUnion, hBU]
+ exact monotone_const.inter monotone_accumulate
rw [this] at hr
rcases lt_iSup_iff.1 hr with ⟨n, hn⟩
exact ⟨_, inter_subset_left, hBc n, hn⟩
@@ -667,7 +665,7 @@ lemma innerRegularWRT_isClosed_isOpen [R1Space α] [OpensMeasurableSpace α] [h
theorem exists_compact_not_null [InnerRegular μ] : (∃ K, IsCompact K ∧ μ K ≠ 0) ↔ μ ≠ 0 := by
simp_rw [Ne, ← measure_univ_eq_zero, MeasurableSet.univ.measure_eq_iSup_isCompact,
- ENNReal.iSup_eq_zero, not_forall, exists_prop, subset_univ, true_and_iff]
+ ENNReal.iSup_eq_zero, not_forall, exists_prop, subset_univ, true_and]
/-- If `μ` is inner regular, then any measurable set can be approximated by a compact subset.
See also `MeasurableSet.exists_isCompact_lt_add_of_ne_top`. -/
@@ -993,7 +991,7 @@ theorem _root_.IsOpen.measure_eq_iSup_isCompact ⦃U : Set α⦄ (hU : IsOpen U)
theorem exists_compact_not_null [Regular μ] : (∃ K, IsCompact K ∧ μ K ≠ 0) ↔ μ ≠ 0 := by
simp_rw [Ne, ← measure_univ_eq_zero, isOpen_univ.measure_eq_iSup_isCompact,
- ENNReal.iSup_eq_zero, not_forall, exists_prop, subset_univ, true_and_iff]
+ ENNReal.iSup_eq_zero, not_forall, exists_prop, subset_univ, true_and]
/-- If `μ` is a regular measure, then any measurable set of finite measure can be approximated by a
compact subset. See also `MeasurableSet.exists_isCompact_lt_add` and
@@ -1051,8 +1049,8 @@ instance (priority := 100) {X : Type*}
[TopologicalSpace X] [PseudoMetrizableSpace X] [SigmaCompactSpace X] [MeasurableSpace X]
[BorelSpace X] (μ : Measure X) [SigmaFinite μ] : InnerRegular μ := by
refine ⟨(InnerRegularWRT.isCompact_isClosed μ).trans ?_⟩
- refine InnerRegularWRT.of_restrict (fun n ↦ ?_)
- (univ_subset_iff.2 (iUnion_spanningSets μ)) (monotone_spanningSets μ)
+ refine InnerRegularWRT.of_restrict (fun n ↦ ?_) (iUnion_spanningSets μ).superset
+ (monotone_spanningSets μ)
have : Fact (μ (spanningSets μ n) < ∞) := ⟨measure_spanningSets_lt_top μ n⟩
exact WeaklyRegular.innerRegular_measurable.trans InnerRegularWRT.of_sigmaFinite
diff --git a/Mathlib/MeasureTheory/Measure/Restrict.lean b/Mathlib/MeasureTheory/Measure/Restrict.lean
index 713ef07032fc3..128b3126b22c9 100644
--- a/Mathlib/MeasureTheory/Measure/Restrict.lean
+++ b/Mathlib/MeasureTheory/Measure/Restrict.lean
@@ -281,7 +281,7 @@ theorem restrict_iUnion_apply [Countable ι] {s : ι → Set α} (hd : Pairwise
theorem restrict_iUnion_apply_eq_iSup [Countable ι] {s : ι → Set α} (hd : Directed (· ⊆ ·) s)
{t : Set α} (ht : MeasurableSet t) : μ.restrict (⋃ i, s i) t = ⨆ i, μ.restrict (s i) t := by
simp only [restrict_apply ht, inter_iUnion]
- rw [measure_iUnion_eq_iSup]
+ rw [Directed.measure_iUnion]
exacts [hd.mono_comp _ fun s₁ s₂ => inter_subset_inter_right _]
/-- The restriction of the pushforward measure is the pushforward of the restriction. For a version
@@ -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
new file mode 100644
index 0000000000000..cb0e5e2a0c352
--- /dev/null
+++ b/Mathlib/MeasureTheory/Measure/SeparableMeasure.lean
@@ -0,0 +1,510 @@
+/-
+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.MeasureTheory.Function.SimpleFuncDenseLp
+import Mathlib.MeasureTheory.SetAlgebra
+
+/-!
+# Separable measure
+
+The goal of this file is to give a sufficient condition on the measure space `(X, μ)` and the
+`NormedAddCommGroup E` for the space `MeasureTheory.Lp E p μ` to have `SecondCountableTopology` when
+`1 ≤ p < ∞`. To do so we define the notion of a `MeasureTheory.MeasureDense` family and a
+separable measure (`MeasureTheory.IsSeparable`).
+We prove that if `X` is `MeasurableSpace.CountablyGenerated` and `μ` is s-finite, then `μ`
+is separable. We then prove that if `μ` is separable and `E` is second-countable,
+then `Lp E p μ` is second-countable.
+
+A family `𝒜` of subsets of `X` is said to be **measure-dense** if it contains only measurable sets
+and can approximate any measurable set with finite measure, in the sense that
+for any measurable set `s` such that `μ s ≠ ∞`, `μ (s ∆ t)` can be made
+arbitrarily small when `t ∈ 𝒜`. We show below that such a family can be chosen to contain only
+sets with finite measure.
+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.
+
+A measure `μ` is **separable** if it admits a countable and measure-dense family of sets.
+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.
+
+## Main definitions
+
+* `MeasureTheory.Measure.MeasureDense μ 𝒜`: `𝒜` is a measure-dense family if it only contains
+ measurable sets and if the following condition is satisfied: if `s` is measurable with finite
+ measure, then for any `ε > 0` there exists `t ∈ 𝒜` such that `μ (s ∆ t) < ε `.
+* `MeasureTheory.IsSeparable`: A measure is separable if there exists a countable and
+ measure-dense family.
+
+## Main statements
+
+* `MeasureTheory.instSecondCountableLp`: If `μ` is separable, `E` is second-countable and
+ `1 ≤ p < ∞` then `Lp E p μ` is second-countable. This is in particular true if `X` is countably
+ generated and `μ` is s-finite.
+
+## Implementation notes
+
+Through the whole file we consider a measurable space `X` equipped with a measure `μ`, and also
+a normed commutative group `E`. We also consider an extended non-negative real `p` such that
+`1 ≤ p < ∞`. This is registered as instances via `one_le_p : Fact (1 ≤ p)` and
+`p_ne_top : Fact (p ≠ ∞)`, so the properties are accessible via `one_le_p.elim` and `p_ne_top.elim`.
+
+Through the whole file, when we write that an extended non-negative real is finite, it is always
+written `≠ ∞` rather than `< ∞`. See `Ne.lt_top` and `ne_of_lt` to switch from one to the other.
+
+## References
+
+* [D. L. Cohn, *Measure Theory*][cohn2013measure]
+
+## Tags
+
+separable measure, measure-dense, Lp space, second-countable
+-/
+
+open MeasurableSpace Set ENNReal TopologicalSpace symmDiff Real
+
+namespace MeasureTheory
+
+variable {X E : Type*} [m : MeasurableSpace X] [NormedAddCommGroup E] {μ : Measure X}
+variable {p : ℝ≥0∞} [one_le_p : Fact (1 ≤ p)] [p_ne_top : Fact (p ≠ ∞)] {𝒜 : Set (Set X)}
+
+section MeasureDense
+
+/-! ### Definition of a measure-dense family, basic properties and sufficient conditions -/
+
+/-- A family `𝒜` of sets of a measure space is said to be measure-dense if it contains only
+measurable sets and can approximate any measurable set with finite measure, in the sense that
+for any measurable set `s` with finite measure the symmetric difference `s ∆ t` can be made
+arbitrarily small when `t ∈ 𝒜`. We show below that such a family can be chosen to contain only
+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 where
+ /-- Each set has to be measurable. -/
+ measurable : ∀ s ∈ 𝒜, MeasurableSet s
+ /-- Any measurable set can be approximated by sets in the family. -/
+ approx : ∀ s, MeasurableSet s → μ s ≠ ∞ → ∀ ε : ℝ, 0 < ε → ∃ t ∈ 𝒜, μ (s ∆ t) < ENNReal.ofReal ε
+
+theorem Measure.MeasureDense.nonempty (h𝒜 : μ.MeasureDense 𝒜) : 𝒜.Nonempty := by
+ rcases h𝒜.approx ∅ MeasurableSet.empty (by simp) 1 (by norm_num) with ⟨t, ht, -⟩
+ exact ⟨t, ht⟩
+
+theorem Measure.MeasureDense.nonempty' (h𝒜 : μ.MeasureDense 𝒜) :
+ {s | s ∈ 𝒜 ∧ μ s ≠ ∞}.Nonempty := by
+ rcases h𝒜.approx ∅ MeasurableSet.empty (by simp) 1 (by norm_num) with ⟨t, ht, hμt⟩
+ refine ⟨t, ht, ?_⟩
+ convert ne_top_of_lt hμt
+ rw [← bot_eq_empty, bot_symmDiff]
+
+/-- The set of measurable sets is measure-dense. -/
+theorem measureDense_measurableSet : μ.MeasureDense {s | MeasurableSet s} where
+ measurable _ h := h
+ approx s hs _ ε ε_pos := ⟨s, hs, by simpa⟩
+
+/-- If a family of sets `𝒜` is measure-dense in `X`, then any measurable set with finite measure
+can be approximated by sets in `𝒜` with finite measure. -/
+lemma Measure.MeasureDense.fin_meas_approx (h𝒜 : μ.MeasureDense 𝒜) {s : Set X}
+ (ms : MeasurableSet s) (hμs : μ s ≠ ∞) (ε : ℝ) (ε_pos : 0 < ε) :
+ ∃ t ∈ 𝒜, μ t ≠ ∞ ∧ μ (s ∆ t) < ENNReal.ofReal ε := by
+ rcases h𝒜.approx s ms hμs ε ε_pos with ⟨t, t_mem, ht⟩
+ exact ⟨t, t_mem, (measure_ne_top_iff_of_symmDiff <| ne_top_of_lt ht).1 hμs, ht⟩
+
+variable (p) in
+/-- If `𝒜` is a measure-dense family of sets and `c : E`, then the set of constant indicators
+with constant `c` whose underlying set is in `𝒜` is dense in the set of constant indicators
+which are in `Lp E p μ` when `1 ≤ p < ∞`. -/
+theorem Measure.MeasureDense.indicatorConstLp_subset_closure (h𝒜 : μ.MeasureDense 𝒜) (c : E) :
+ {indicatorConstLp p hs hμs c | (s : Set X) (hs : MeasurableSet s) (hμs : μ s ≠ ∞)} ⊆
+ closure {indicatorConstLp p (h𝒜.measurable s hs) hμs c |
+ (s : Set X) (hs : s ∈ 𝒜) (hμs : μ s ≠ ∞)} := by
+ obtain rfl | hc := eq_or_ne c 0
+ · refine Subset.trans ?_ subset_closure
+ rintro - ⟨s, ms, hμs, rfl⟩
+ obtain ⟨t, ht, hμt⟩ := h𝒜.nonempty'
+ refine ⟨t, ht, hμt, ?_⟩
+ simp_rw [indicatorConstLp]
+ congr
+ simp
+ · have p_pos : 0 < p := lt_of_lt_of_le (by norm_num) one_le_p.elim
+ rintro - ⟨s, ms, hμs, rfl⟩
+ refine Metric.mem_closure_iff.2 fun ε hε ↦ ?_
+ have aux : 0 < (ε / ‖c‖) ^ p.toReal := rpow_pos_of_pos (div_pos hε (norm_pos_iff.2 hc)) _
+ obtain ⟨t, ht, hμt, hμst⟩ := h𝒜.fin_meas_approx ms hμs ((ε / ‖c‖) ^ p.toReal) aux
+ refine ⟨indicatorConstLp p (h𝒜.measurable t ht) hμt c,
+ ⟨t, ht, hμt, rfl⟩, ?_⟩
+ rw [dist_indicatorConstLp_eq_norm, norm_indicatorConstLp p_pos.ne.symm p_ne_top.elim]
+ calc
+ ‖c‖ * (μ (s ∆ t)).toReal ^ (1 / p.toReal)
+ < ‖c‖ * (ENNReal.ofReal ((ε / ‖c‖) ^ p.toReal)).toReal ^ (1 / p.toReal) := by
+ rw [_root_.mul_lt_mul_left (norm_pos_iff.2 hc)]
+ refine Real.rpow_lt_rpow (by simp) ?_
+ (one_div_pos.2 <| toReal_pos p_pos.ne.symm p_ne_top.elim)
+ rwa [toReal_lt_toReal (measure_symmDiff_ne_top hμs hμt) ofReal_ne_top]
+ _ = ε := by
+ rw [toReal_ofReal (rpow_nonneg (div_nonneg hε.le (norm_nonneg _)) _),
+ one_div, Real.rpow_rpow_inv (div_nonneg hε.le (norm_nonneg _))
+ (toReal_pos p_pos.ne.symm p_ne_top.elim).ne.symm,
+ mul_div_cancel₀ _ (norm_ne_zero_iff.2 hc)]
+
+/-- If a family of sets `𝒜` is measure-dense in `X`, then it is also the case for the sets in `𝒜`
+with finite measure. -/
+theorem Measure.MeasureDense.fin_meas (h𝒜 : μ.MeasureDense 𝒜) :
+ μ.MeasureDense {s | s ∈ 𝒜 ∧ μ s ≠ ∞} where
+ measurable s h := h𝒜.measurable s h.1
+ approx s ms hμs ε ε_pos := by
+ rcases Measure.MeasureDense.fin_meas_approx h𝒜 ms hμs ε ε_pos with ⟨t, t_mem, hμt, hμst⟩
+ exact ⟨t, ⟨t_mem, hμt⟩, hμst⟩
+
+/-- If a measurable space equipped with a finite measure is generated by an algebra of sets, then
+this algebra of sets is measure-dense. -/
+theorem Measure.MeasureDense.of_generateFrom_isSetAlgebra_finite [IsFiniteMeasure μ]
+ (h𝒜 : IsSetAlgebra 𝒜) (hgen : m = MeasurableSpace.generateFrom 𝒜) : μ.MeasureDense 𝒜 where
+ measurable s hs := hgen ▸ measurableSet_generateFrom hs
+ approx s ms := by
+ -- We want to show that any measurable set can be approximated by sets in `𝒜`. To do so, it is
+ -- enough to show that such sets constitute a `σ`-algebra containing `𝒜`. This is contained in
+ -- the theorem `generateFrom_induction`.
+ have : MeasurableSet s ∧ ∀ (ε : ℝ), 0 < ε → ∃ t ∈ 𝒜, (μ (s ∆ t)).toReal < ε := by
+ apply generateFrom_induction
+ (p := fun s ↦ MeasurableSet s ∧ ∀ (ε : ℝ), 0 < ε → ∃ t ∈ 𝒜, (μ (s ∆ t)).toReal < ε)
+ (C := 𝒜) (hs := hgen ▸ ms)
+ · -- If `t ∈ 𝒜`, then `μ (t ∆ t) = 0` which is less than any `ε > 0`.
+ exact fun t t_mem ↦ ⟨hgen ▸ measurableSet_generateFrom t_mem,
+ fun ε ε_pos ↦ ⟨t, t_mem, by simpa⟩⟩
+ · -- `∅ ∈ 𝒜` and `μ (∅ ∆ ∅) = 0` which is less than any `ε > 0`.
+ exact ⟨MeasurableSet.empty, fun ε ε_pos ↦ ⟨∅, h𝒜.empty_mem, by simpa⟩⟩
+ · -- If `s` is measurable and `t ∈ 𝒜` such that `μ (s ∆ t) < ε`, then `tᶜ ∈ 𝒜` and
+ -- `μ (sᶜ ∆ tᶜ) = μ (s ∆ t) < ε` so `sᶜ` can be approximated.
+ refine fun t ⟨mt, ht⟩ ↦ ⟨mt.compl, fun ε ε_pos ↦ ?_⟩
+ rcases ht ε ε_pos with ⟨u, u_mem, hμtcu⟩
+ exact ⟨uᶜ, h𝒜.compl_mem u_mem, by rwa [compl_symmDiff_compl]⟩
+ · -- Let `(fₙ)` be a sequence of measurable sets and `ε > 0`.
+ refine fun f hf ↦ ⟨MeasurableSet.iUnion (fun n ↦ (hf n).1), fun ε ε_pos ↦ ?_⟩
+ -- We have `μ (⋃ n ≤ N, fₙ) ⟶ μ (⋃ n, fₙ)`.
+ have := tendsto_measure_iUnion_accumulate (μ := μ) (f := f)
+ rw [← tendsto_toReal_iff (fun _ ↦ measure_ne_top _ _) (measure_ne_top _ _)] at this
+ -- So there exists `N` such that `μ (⋃ n, fₙ) - μ (⋃ n ≤ N, fₙ) < ε/2`.
+ rcases Metric.tendsto_atTop.1 this (ε / 2) (by linarith [ε_pos]) with ⟨N, hN⟩
+ -- For any `n ≤ N` there exists `gₙ ∈ 𝒜` such that `μ (fₙ ∆ gₙ) < ε/(2*(N+1))`.
+ choose g g_mem hg using fun n ↦ (hf n).2 (ε / (2 * (N + 1))) (div_pos ε_pos (by linarith))
+ -- Therefore we have
+ -- `μ ((⋃ n, fₙ) ∆ (⋃ n ≤ N, gₙ))`
+ -- `≤ μ ((⋃ n, fₙ) ∆ (⋃ n ≤ N, fₙ)) + μ ((⋃ n ≤ N, fₙ) ∆ (⋃ n ≤ N, gₙ))`
+ -- `< ε/2 + ∑ n ≤ N, μ (fₙ ∆ gₙ)` (see `biSup_symmDiff_biSup_le`)
+ -- `< ε/2 + (N+1)*ε/(2*(N+1)) = ε/2`.
+ refine ⟨⋃ n ∈ Finset.range (N + 1), g n, h𝒜.biUnion_mem _ (fun i _ ↦ g_mem i), ?_⟩
+ calc
+ (μ ((⋃ n, f n) ∆ (⋃ n ∈ (Finset.range (N + 1)), g n))).toReal
+ ≤ (μ ((⋃ n, f n) \ ((⋃ n ∈ (Finset.range (N + 1)), f n)) ∪
+ ((⋃ n ∈ (Finset.range (N + 1)), f n) ∆
+ (⋃ n ∈ (Finset.range (N + 1)), g ↑n)))).toReal :=
+ toReal_mono (measure_ne_top _ _)
+ (measure_mono <| symmDiff_of_ge (iUnion_subset <|
+ fun i ↦ iUnion_subset (fun _ ↦ subset_iUnion f i)) ▸ symmDiff_triangle ..)
+ _ ≤ (μ ((⋃ n, f n) \
+ ((⋃ n ∈ (Finset.range (N + 1)), f n)))).toReal +
+ (μ ((⋃ n ∈ (Finset.range (N + 1)), f n) ∆
+ (⋃ n ∈ (Finset.range (N + 1)), g ↑n))).toReal := by
+ rw [← toReal_add (measure_ne_top _ _) (measure_ne_top _ _)]
+ exact toReal_mono (add_ne_top.2 ⟨measure_ne_top _ _, measure_ne_top _ _⟩) <|
+ measure_union_le _ _
+ _ < ε := by
+ rw [← add_halves ε]
+ apply _root_.add_lt_add
+ · rw [measure_diff (h_fin := measure_ne_top _ _),
+ toReal_sub_of_le (ha := measure_ne_top _ _)]
+ · apply lt_of_le_of_lt (sub_le_dist ..)
+ simp only [Finset.mem_range, Nat.lt_add_one_iff]
+ exact (dist_comm (α := ℝ) .. ▸ hN N (le_refl N))
+ · exact measure_mono <| iUnion_subset <|
+ fun i ↦ iUnion_subset fun _ ↦ subset_iUnion f i
+ · exact iUnion_subset <| fun i ↦ iUnion_subset (fun _ ↦ subset_iUnion f i)
+ · exact MeasurableSet.biUnion (countable_coe_iff.1 inferInstance)
+ (fun n _ ↦ (hf n).1.nullMeasurableSet)
+ · calc
+ (μ ((⋃ n ∈ (Finset.range (N + 1)), f n) ∆
+ (⋃ n ∈ (Finset.range (N + 1)), g ↑n))).toReal
+ ≤ (μ (⋃ n ∈ (Finset.range (N + 1)), f n ∆ g n)).toReal :=
+ toReal_mono (measure_ne_top _ _) (measure_mono biSup_symmDiff_biSup_le)
+ _ ≤ ∑ n in (Finset.range (N + 1)), (μ (f n ∆ g n)).toReal := by
+ rw [← toReal_sum (fun _ _ ↦ measure_ne_top _ _)]
+ exact toReal_mono (ne_of_lt <| sum_lt_top.2 fun _ _ ↦ measure_lt_top μ _)
+ (measure_biUnion_finset_le _ _)
+ _ < ∑ n in (Finset.range (N + 1)), (ε / (2 * (N + 1))) :=
+ Finset.sum_lt_sum (fun i _ ↦ le_of_lt (hg i)) ⟨0, by simp, hg 0⟩
+ _ ≤ ε / 2 := by
+ simp only [Finset.sum_const, Finset.card_range, nsmul_eq_mul,
+ Nat.cast_add, Nat.cast_one]
+ rw [div_mul_eq_div_mul_one_div, ← mul_assoc, mul_comm ((N : ℝ) + 1),
+ mul_assoc]
+ exact mul_le_of_le_one_right (by linarith [ε_pos]) <|
+ le_of_eq <| mul_one_div_cancel <| Nat.cast_add_one_ne_zero _
+ rintro - ε ε_pos
+ rcases this.2 ε ε_pos with ⟨t, t_mem, hμst⟩
+ exact ⟨t, t_mem, (lt_ofReal_iff_toReal_lt (measure_ne_top _ _)).2 hμst⟩
+
+/-- If a measure space `X` is generated by an algebra of sets which contains a monotone countable
+family of sets with finite measure spanning `X` (thus the measure is `σ`-finite), then this algebra
+of sets is measure-dense. -/
+theorem Measure.MeasureDense.of_generateFrom_isSetAlgebra_sigmaFinite (h𝒜 : IsSetAlgebra 𝒜)
+ (S : μ.FiniteSpanningSetsIn 𝒜) (hgen : m = MeasurableSpace.generateFrom 𝒜) :
+ μ.MeasureDense 𝒜 where
+ measurable s hs := hgen ▸ measurableSet_generateFrom hs
+ approx s ms hμs ε ε_pos := by
+ -- We use partial unions of (Sₙ) to get a monotone family spanning `X`.
+ let T := Accumulate S.set
+ have T_mem (n) : T n ∈ 𝒜 := by
+ simpa using h𝒜.biUnion_mem {k | k ≤ n}.toFinset (fun k _ ↦ S.set_mem k)
+ have T_finite (n) : μ (T n) < ∞ := by
+ simpa using measure_biUnion_lt_top {k | k ≤ n}.toFinset.finite_toSet
+ (fun k _ ↦ S.finite k)
+ have T_spanning : ⋃ n, T n = univ := S.spanning ▸ iUnion_accumulate
+ -- We use the fact that we already know this is true for finite measures. As `⋃ n, T n = X`,
+ -- we have that `μ ((T n) ∩ s) ⟶ μ s`.
+ have mono : Monotone (fun n ↦ (T n) ∩ s) := fun m n hmn ↦ inter_subset_inter_left s
+ (biUnion_subset_biUnion_left fun k hkm ↦ Nat.le_trans hkm hmn)
+ have := tendsto_measure_iUnion_atTop (μ := μ) mono
+ rw [← tendsto_toReal_iff] at this
+ · -- We can therefore choose `N` such that `μ s - μ ((S N) ∩ s) < ε/2`.
+ rcases Metric.tendsto_atTop.1 this (ε / 2) (by linarith [ε_pos]) with ⟨N, hN⟩
+ have : Fact (μ (T N) < ∞) := Fact.mk <| T_finite N
+ -- Then we can apply the previous result to the measure `μ ((S N) ∩ •)`.
+ -- There exists `t ∈ 𝒜` such that `μ ((S N) ∩ (s ∆ t)) < ε/2`.
+ rcases (Measure.MeasureDense.of_generateFrom_isSetAlgebra_finite
+ (μ := μ.restrict (T N)) h𝒜 hgen).approx s ms
+ (ne_of_lt (lt_of_le_of_lt (μ.restrict_apply_le _ s) hμs.lt_top))
+ (ε / 2) (by linarith [ε_pos])
+ with ⟨t, t_mem, ht⟩
+ -- We can then use `t ∩ (S N)`, because `S N ∈ 𝒜` by hypothesis.
+ -- `μ (s ∆ (t ∩ S N))`
+ -- `≤ μ (s ∆ (s ∩ S N)) + μ ((s ∩ S N) ∆ (t ∩ S N))`
+ -- `= μ s - μ (s ∩ S N) + μ (s ∆ t) ∩ S N) < ε`.
+ refine ⟨t ∩ T N, h𝒜.inter_mem t_mem (T_mem N), ?_⟩
+ calc
+ μ (s ∆ (t ∩ T N))
+ ≤ μ (s \ (s ∩ T N)) + μ ((s ∆ t) ∩ T N) := by
+ rw [← symmDiff_of_le (inter_subset_left ..), symmDiff_comm _ s,
+ inter_symmDiff_distrib_right]
+ exact measure_symmDiff_le _ _ _
+ _ < ENNReal.ofReal (ε / 2) + ENNReal.ofReal (ε / 2) := by
+ apply ENNReal.add_lt_add
+ · rw [measure_diff
+ (inter_subset_left ..)
+ (ms.inter (hgen ▸ measurableSet_generateFrom (T_mem N))).nullMeasurableSet
+ (ne_top_of_le_ne_top hμs (measure_mono (inter_subset_left ..))),
+ lt_ofReal_iff_toReal_lt (sub_ne_top hμs),
+ toReal_sub_of_le (measure_mono (inter_subset_left ..)) hμs]
+ apply lt_of_le_of_lt (sub_le_dist ..)
+ nth_rw 1 [← univ_inter s]
+ rw [inter_comm s, dist_comm, ← T_spanning, iUnion_inter _ T]
+ apply hN N (le_refl _)
+ · rwa [← μ.restrict_apply' (hgen ▸ measurableSet_generateFrom (T_mem N))]
+ _ = ENNReal.ofReal ε := by
+ rw [← ofReal_add (by linarith [ε_pos]) (by linarith [ε_pos]), add_halves]
+ · exact fun n ↦ ne_top_of_le_ne_top hμs (measure_mono (inter_subset_right ..))
+ · exact ne_top_of_le_ne_top hμs
+ (measure_mono (iUnion_subset (fun i ↦ inter_subset_right ..)))
+
+end MeasureDense
+
+section IsSeparable
+
+/-! ### Definition of a separable measure space, sufficient condition -/
+
+/-- A measure `μ` is separable if there exists a countable and measure-dense family of sets.
+
+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 where
+ exists_countable_measureDense : ∃ 𝒜, 𝒜.Countable ∧ μ.MeasureDense 𝒜
+
+/-- By definition, a separable measure admits a countable and measure-dense family of sets. -/
+theorem exists_countable_measureDense [IsSeparable μ] :
+ ∃ 𝒜, 𝒜.Countable ∧ μ.MeasureDense 𝒜 :=
+ IsSeparable.exists_countable_measureDense
+
+/-- If a measurable space is countably generated and equipped with a `σ`-finite measure, then the
+measure is separable. This is not an instance because it is used below to prove the more
+general case where `μ` is s-finite. -/
+theorem isSeparable_of_sigmaFinite [CountablyGenerated X] [SigmaFinite μ] :
+ IsSeparable μ where
+ exists_countable_measureDense := by
+ have h := countable_countableGeneratingSet (α := X)
+ have hgen := generateFrom_countableGeneratingSet (α := X)
+ let 𝒜 := (countableGeneratingSet X) ∪ {μ.toFiniteSpanningSetsIn.set n | n : ℕ}
+ have count_𝒜 : 𝒜.Countable :=
+ countable_union.2 ⟨h, countable_iff_exists_subset_range.2
+ ⟨μ.toFiniteSpanningSetsIn.set, fun _ hx ↦ hx⟩⟩
+ refine ⟨generateSetAlgebra 𝒜, countable_generateSetAlgebra count_𝒜,
+ Measure.MeasureDense.of_generateFrom_isSetAlgebra_sigmaFinite isSetAlgebra_generateSetAlgebra
+ { set := μ.toFiniteSpanningSetsIn.set
+ set_mem := fun n ↦ self_subset_generateSetAlgebra (𝒜 := 𝒜) <| Or.inr ⟨n, rfl⟩
+ finite := μ.toFiniteSpanningSetsIn.finite
+ spanning := μ.toFiniteSpanningSetsIn.spanning }
+ (le_antisymm ?_ (generateFrom_le (fun s hs ↦ ?_)))⟩
+ · rw [← hgen]
+ exact generateFrom_mono <| le_trans self_subset_generateSetAlgebra <|
+ generateSetAlgebra_mono <| subset_union_left ..
+ · induction hs with
+ | base t t_mem =>
+ rcases t_mem with t_mem | ⟨n, rfl⟩
+ · exact hgen ▸ measurableSet_generateFrom t_mem
+ · exact μ.toFiniteSpanningSetsIn.set_mem n
+ | empty => exact MeasurableSet.empty
+ | compl t _ t_mem => exact MeasurableSet.compl t_mem
+ | union t u _ _ t_mem u_mem => exact MeasurableSet.union t_mem u_mem
+
+/-- If a measurable space is countably generated and equipped with an s-finite measure, then the
+measure is separable. -/
+instance [CountablyGenerated X] [SFinite μ] : IsSeparable μ where
+ exists_countable_measureDense := by
+ have := isSeparable_of_sigmaFinite (μ := μ.restrict μ.sigmaFiniteSet)
+ rcases exists_countable_measureDense (μ := μ.restrict μ.sigmaFiniteSet) with ⟨𝒜, count_𝒜, h𝒜⟩
+ let ℬ := {s ∩ μ.sigmaFiniteSet | s ∈ 𝒜}
+ refine ⟨ℬ, count_𝒜.image (fun s ↦ s ∩ μ.sigmaFiniteSet), ?_, ?_⟩
+ · rintro - ⟨s, s_mem, rfl⟩
+ exact (h𝒜.measurable s s_mem).inter measurableSet_sigmaFiniteSet
+ · intro s ms hμs ε ε_pos
+ rcases restrict_compl_sigmaFiniteSet_eq_zero_or_top μ s with hs | hs
+ · have : (μ.restrict μ.sigmaFiniteSet) s ≠ ∞ :=
+ ne_top_of_le_ne_top hμs <| μ.restrict_le_self _
+ rcases h𝒜.approx s ms this ε ε_pos with ⟨t, t_mem, ht⟩
+ refine ⟨t ∩ μ.sigmaFiniteSet, ⟨t, t_mem, rfl⟩, ?_⟩
+ have : μ (s ∆ (t ∩ μ.sigmaFiniteSet) \ μ.sigmaFiniteSet) = 0 := by
+ rw [diff_eq_compl_inter, inter_symmDiff_distrib_left, ← ENNReal.bot_eq_zero, eq_bot_iff]
+ calc
+ μ ((μ.sigmaFiniteSetᶜ ∩ s) ∆ (μ.sigmaFiniteSetᶜ ∩ (t ∩ μ.sigmaFiniteSet)))
+ ≤ μ ((μ.sigmaFiniteSetᶜ ∩ s) ∪ (μ.sigmaFiniteSetᶜ ∩ (t ∩ μ.sigmaFiniteSet))) :=
+ measure_mono symmDiff_subset_union
+ _ ≤ μ (μ.sigmaFiniteSetᶜ ∩ s) + μ (μ.sigmaFiniteSetᶜ ∩ (t ∩ μ.sigmaFiniteSet)) :=
+ measure_union_le _ _
+ _ = 0 := by
+ rw [inter_comm, ← μ.restrict_apply ms, hs, ← inter_assoc, inter_comm,
+ ← inter_assoc, inter_compl_self, empty_inter, measure_empty, zero_add]
+ rwa [← measure_inter_add_diff _ measurableSet_sigmaFiniteSet, this, add_zero,
+ inter_symmDiff_distrib_right, inter_assoc, inter_self, ← inter_symmDiff_distrib_right,
+ ← μ.restrict_apply' measurableSet_sigmaFiniteSet]
+ · refine False.elim <| hμs ?_
+ rw [eq_top_iff, ← hs]
+ exact μ.restrict_le_self _
+
+end IsSeparable
+
+section SecondCountableLp
+
+/-! ### A sufficient condition for $L^p$ spaces to be second-countable -/
+
+/-- If the measure `μ` is separable (in particular if `X` is countably generated and `μ` is
+`s`-finite), if `E` is a second-countable `NormedAddCommGroup`, and if `1 ≤ p < +∞`,
+then the associated `Lᵖ` space is second-countable. -/
+instance Lp.SecondCountableTopology [IsSeparable μ] [TopologicalSpace.SeparableSpace E] :
+ SecondCountableTopology (Lp E p μ) := by
+ -- It is enough to show that the space is separable, i.e. admits a countable and dense susbet.
+ refine @UniformSpace.secondCountable_of_separable _ _ _ ?_
+ -- There exists a countable and measure-dense family, and we can keep only the sets with finite
+ -- measure while preserving the two properties. This family is denoted `𝒜₀`.
+ rcases exists_countable_measureDense (μ := μ) with ⟨𝒜, count_𝒜, h𝒜⟩
+ have h𝒜₀ := Measure.MeasureDense.fin_meas h𝒜
+ set 𝒜₀ := {s | s ∈ 𝒜 ∧ μ s ≠ ∞}
+ have count_𝒜₀ : 𝒜₀.Countable := count_𝒜.mono fun _ ⟨h, _⟩ ↦ h
+ -- `1 ≤ p` so `p ≠ 0`, we prove it now as it is often needed.
+ have p_ne_zero : p ≠ 0 := ne_of_gt <| lt_of_lt_of_le (by norm_num) one_le_p.elim
+ -- `E` is second-countable, therefore separable and admits a countable and dense subset `u`.
+ rcases exists_countable_dense E with ⟨u, countable_u, dense_u⟩
+ -- The countable and dense subset of `Lᵖ` we are going to build is the set of finite sums of
+ -- constant indicators with support in `𝒜₀`, and is denoted `D`. To make manipulations easier,
+ -- we define the function `key` which given an integer `n` and two families of `n` elements
+ -- in `u` and `𝒜₀` associates the corresponding sum.
+ let key (n : ℕ) (d : Fin n → u) (s : Fin n → 𝒜₀) : (Lp E p μ) :=
+ ∑ i, indicatorConstLp p (h𝒜₀.measurable (s i) (Subtype.mem (s i))) (s i).2.2 (d i : E)
+ let D := {s : Lp E p μ | ∃ n d t, s = key n d t}
+ 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 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
+ have : D ⊆ range f := by
+ rintro - ⟨n, d, s, rfl⟩
+ use ⟨n, (d, s)⟩
+ exact (countable_range f).mono this
+ · -- Let's turn to the density. Thanks to the density of simple functions in `Lᵖ`, it is enough
+ -- to show that the closure of `D` contains constant indicators which are in `Lᵖ` (i. e. the
+ -- set has finite measure), is closed by sum and closed.
+ -- This is given by `Lp.induction`.
+ refine Lp.induction p_ne_top.elim (P := fun f ↦ f ∈ closure D) ?_ ?_ isClosed_closure
+ · intro a s ms hμs
+ -- We want to approximate `a • 𝟙ₛ`.
+ apply ne_of_lt at hμs
+ rw [SeminormedAddCommGroup.mem_closure_iff]
+ intro ε ε_pos
+ have μs_pow_nonneg : 0 ≤ (μ s).toReal ^ (1 / p.toReal) :=
+ Real.rpow_nonneg ENNReal.toReal_nonneg _
+ -- To do so, we first pick `b ∈ u` such that `‖a - b‖ < ε / (3 * (1 + (μ s)^(1/p)))`.
+ have approx_a_pos : 0 < ε / (3 * (1 + (μ s).toReal ^ (1 / p.toReal))) :=
+ div_pos ε_pos (by linarith [μs_pow_nonneg])
+ have ⟨b, b_mem, hb⟩ := SeminormedAddCommGroup.mem_closure_iff.1 (dense_u a) _ approx_a_pos
+ -- Then we pick `t ∈ 𝒜₀` such that `‖b • 𝟙ₛ - b • 𝟙ₜ‖ < ε / 3`.
+ rcases SeminormedAddCommGroup.mem_closure_iff.1
+ (h𝒜₀.indicatorConstLp_subset_closure p b ⟨s, ms, hμs, rfl⟩)
+ (ε / 3) (by linarith [ε_pos]) with ⟨-, ⟨t, ht, hμt, rfl⟩, hst⟩
+ have mt := h𝒜₀.measurable t ht
+ -- We now show that `‖a • 𝟙ₛ - b • 𝟙ₜ‖ₚ < ε`, as follows:
+ -- `‖a • 𝟙ₛ - b • 𝟙ₜ‖ₚ`
+ -- `= ‖a • 𝟙ₛ - b • 𝟙ₛ + b • 𝟙ₛ - b • 𝟙ₜ‖ₚ`
+ -- `≤ ‖a - b‖ * ‖𝟙ₛ‖ₚ + ε / 3`
+ -- `= ‖a - b‖ * (μ s)^(1/p) + ε / 3`
+ -- `< ε * (μ s)^(1/p) / (3 * (1 + (μ s)^(1/p))) + ε / 3`
+ -- `≤ ε / 3 + ε / 3 < ε`.
+ refine ⟨indicatorConstLp p mt hμt b,
+ ⟨1, fun _ ↦ ⟨b, b_mem⟩, fun _ ↦ ⟨t, ht⟩, by simp [key]⟩, ?_⟩
+ rw [Lp.simpleFunc.coe_indicatorConst,
+ ← sub_add_sub_cancel _ (indicatorConstLp p ms hμs b), ← add_halves ε]
+ refine lt_of_le_of_lt (b := ε / 3 + ε / 3) (norm_add_le_of_le ?_ hst.le) (by linarith [ε_pos])
+ rw [indicatorConstLp_sub, norm_indicatorConstLp p_ne_zero p_ne_top.elim]
+ calc
+ ‖a - b‖ * (μ s).toReal ^ (1 / p.toReal)
+ ≤ (ε / (3 * (1 + (μ s).toReal ^ (1 / p.toReal)))) * (μ s).toReal ^ (1 / p.toReal) :=
+ mul_le_mul_of_nonneg_right (le_of_lt hb) μs_pow_nonneg
+ _ ≤ ε / 3 := by
+ rw [← mul_one (ε / 3), div_mul_eq_div_mul_one_div, mul_assoc, one_div_mul_eq_div]
+ exact mul_le_mul_of_nonneg_left
+ ((div_le_one (by linarith [μs_pow_nonneg])).2 (by linarith))
+ (by linarith [ε_pos])
+ · -- Now we have to show that the closure of `D` is closed by sum. Let `f` and `g` be two
+ -- functions in `Lᵖ` which are also in the closure of `D`.
+ rintro f g hf hg - f_mem g_mem
+ rw [SeminormedAddCommGroup.mem_closure_iff] at *
+ intro ε ε_pos
+ -- For `ε > 0`, there exists `bf, bg ∈ D` such that `‖f - bf‖ₚ < ε/2` and `‖g - bg‖ₚ < ε/2`.
+ rcases f_mem (ε / 2) (by linarith [ε_pos]) with ⟨bf, ⟨nf, df, sf, bf_eq⟩, hbf⟩
+ rcases g_mem (ε / 2) (by linarith [ε_pos]) with ⟨bg, ⟨ng, dg, sg, bg_eq⟩, hbg⟩
+ -- It is obvious that `D` is closed by sum, it suffices to concatenate the family of
+ -- elements of `u` and the family of elements of `𝒜₀`.
+ let d := fun i : Fin (nf + ng) ↦ if h : i < nf
+ then df (Fin.castLT i h)
+ else dg (Fin.subNat nf (Fin.cast (Nat.add_comm ..) i) (le_of_not_gt h))
+ let s := fun i : Fin (nf + ng) ↦ if h : i < nf
+ then sf (Fin.castLT i h)
+ else sg (Fin.subNat nf (Fin.cast (Nat.add_comm ..) i) (le_of_not_gt h))
+ -- So we can use `bf + bg`.
+ refine ⟨bf + bg, ⟨nf + ng, d, s, ?_⟩, ?_⟩
+ · simp [key, d, s, Fin.sum_univ_add, bf_eq, bg_eq]
+ · -- We have
+ -- `‖f + g - (bf + bg)‖ₚ`
+ -- `≤ ‖f - bf‖ₚ + ‖g - bg‖ₚ`
+ -- `< ε/2 + ε/2 = ε`.
+ calc
+ ‖Memℒp.toLp f hf + Memℒp.toLp g hg - (bf + bg)‖
+ = ‖(Memℒp.toLp f hf) - bf + ((Memℒp.toLp g hg) - bg)‖ := by congr; abel
+ _ ≤ ‖(Memℒp.toLp f hf) - bf‖ + ‖(Memℒp.toLp g hg) - bg‖ := norm_add_le ..
+ _ < ε := by linarith [hbf, hbg]
+
+end SecondCountableLp
+
+end MeasureTheory
diff --git a/Mathlib/MeasureTheory/Measure/Stieltjes.lean b/Mathlib/MeasureTheory/Measure/Stieltjes.lean
index 150f72aaf7a86..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 :=
@@ -211,7 +211,7 @@ theorem length_subadditive_Icc_Ioo {a b : ℝ} {c d : ℕ → ℝ} (ss : Icc a b
⟨s, _, hf, hs⟩
have e : ⋃ i ∈ (hf.toFinset : Set ℕ), Ioo (c i) (d i) = ⋃ i ∈ s, Ioo (c i) (d i) := by
simp only [Set.ext_iff, exists_prop, Finset.set_biUnion_coe, mem_iUnion, forall_const,
- iff_self_iff, Finite.mem_toFinset]
+ Finite.mem_toFinset]
rw [ENNReal.tsum_eq_iSup_sum]
refine le_trans ?_ (le_iSup _ hf.toFinset)
exact this hf.toFinset _ (by simpa only [e] )
@@ -312,7 +312,7 @@ theorem measurableSet_Ioi {c : ℝ} : MeasurableSet[f.outer.caratheodory] (Ioi c
sub_add_sub_cancel, le_refl,
max_eq_right]
· simp only [hbc, le_refl, Ioc_eq_empty, Ioc_inter_Ioi, min_eq_left, Ioc_diff_Ioi, f.length_empty,
- zero_add, or_true_iff, le_sup_iff, f.length_Ioc, not_lt]
+ zero_add, or_true, le_sup_iff, f.length_Ioc, not_lt]
· simp only [hac, hbc, Ioc_inter_Ioi, Ioc_diff_Ioi, f.length_Ioc, min_eq_right, _root_.sup_eq_max,
le_refl, Ioc_eq_empty, add_zero, max_eq_left, f.length_empty, not_lt]
@@ -373,7 +373,7 @@ theorem measure_singleton (a : ℝ) : f.measure {a} = ofReal (f a - leftLim f a)
simp [le_antisymm this (hx 0).2]
have L1 : Tendsto (fun n => f.measure (Ioc (u n) a)) atTop (𝓝 (f.measure {a})) := by
rw [A]
- refine tendsto_measure_iInter (fun n => measurableSet_Ioc.nullMeasurableSet)
+ refine tendsto_measure_iInter (fun n => nullMeasurableSet_Ioc)
(fun m n hmn => ?_) ?_
· exact Ioc_subset_Ioc_left (u_mono.monotone hmn)
· exact ⟨0, by simpa only [measure_Ioc] using ENNReal.ofReal_ne_top⟩
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 25c6a33aeb53c..c0205825e011a 100644
--- a/Mathlib/MeasureTheory/Measure/Typeclasses.lean
+++ b/Mathlib/MeasureTheory/Measure/Typeclasses.lean
@@ -46,13 +46,14 @@ instance Restrict.isFiniteMeasure (μ : Measure α) [hs : Fact (μ s < ∞)] :
IsFiniteMeasure (μ.restrict s) :=
⟨by simpa using hs.elim⟩
+@[simp]
theorem measure_lt_top (μ : Measure α) [IsFiniteMeasure μ] (s : Set α) : μ s < ∞ :=
(measure_mono (subset_univ s)).trans_lt IsFiniteMeasure.measure_univ_lt_top
instance isFiniteMeasureRestrict (μ : Measure α) (s : Set α) [h : IsFiniteMeasure μ] :
- IsFiniteMeasure (μ.restrict s) :=
- ⟨by simpa using measure_lt_top μ s⟩
+ IsFiniteMeasure (μ.restrict s) := ⟨by simp⟩
+@[simp, aesop (rule_sets := [finiteness]) safe apply]
theorem measure_ne_top (μ : Measure α) [IsFiniteMeasure μ] (s : Set α) : μ s ≠ ∞ :=
ne_of_lt (measure_lt_top μ s)
@@ -121,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]
@@ -145,7 +154,7 @@ theorem summable_measure_toReal [hμ : IsFiniteMeasure μ] {f : ℕ → Set α}
theorem ae_eq_univ_iff_measure_eq [IsFiniteMeasure μ] (hs : NullMeasurableSet s μ) :
s =ᵐ[μ] univ ↔ μ s = μ univ :=
⟨measure_congr, fun h ↦
- (ae_eq_of_subset_of_measure_ge (subset_univ s) h.ge hs (measure_ne_top μ univ))⟩
+ ae_eq_of_subset_of_measure_ge (subset_univ _) h.ge hs (measure_ne_top _ _)⟩
theorem ae_iff_measure_eq [IsFiniteMeasure μ] {p : α → Prop}
(hp : NullMeasurableSet { a | p a } μ) : (∀ᵐ a ∂μ, p a) ↔ μ { a | p a } = μ univ := by
@@ -276,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 `ℝ`. -/
@@ -547,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
+
+@[deprecated (since := "2024-10-11")] alias sFiniteSeq := sfiniteSeq
-instance isFiniteMeasure_sFiniteSeq [h : SFinite μ] (n : ℕ) : IsFiniteMeasure (sFiniteSeq μ n) :=
+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. -/
@@ -582,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
@@ -590,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 `ν`
@@ -599,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
@@ -630,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
@@ -645,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]
@@ -666,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 : ℕ) :
@@ -698,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
@@ -791,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 *
@@ -939,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 α) :
@@ -960,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`. -/
@@ -973,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
@@ -1053,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]
@@ -1069,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 -
@@ -1113,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]⟩⟩⟩
@@ -1139,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
@@ -1433,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 d9b3f84d8bdb6..e5e7a7d55a5d6 100644
--- a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean
+++ b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kexing Ying
-/
import Mathlib.MeasureTheory.Measure.Typeclasses
-import Mathlib.Analysis.Complex.Basic
+import Mathlib.Topology.Algebra.InfiniteSum.Module
/-!
@@ -13,7 +13,8 @@ import Mathlib.Analysis.Complex.Basic
This file defines vector valued measures, which are σ-additive functions from a set to an add monoid
`M` such that it maps the empty set and non-measurable sets to zero. In the case
that `M = ℝ`, we called the vector measure a signed measure and write `SignedMeasure α`.
-Similarly, when `M = ℂ`, we call the measure a complex measure and write `ComplexMeasure α`.
+Similarly, when `M = ℂ`, we call the measure a complex measure and write `ComplexMeasure α`
+(defined in `MeasureTheory/Measure/Complex`).
## Main definitions
@@ -63,10 +64,6 @@ structure VectorMeasure (α : Type*) [MeasurableSpace α] (M : Type*) [AddCommMo
abbrev SignedMeasure (α : Type*) [MeasurableSpace α] :=
VectorMeasure α ℝ
-/-- A `ComplexMeasure` is a `ℂ`-vector measure. -/
-abbrev ComplexMeasure (α : Type*) [MeasurableSpace α] :=
- VectorMeasure α ℂ
-
open Set MeasureTheory
namespace VectorMeasure
@@ -93,18 +90,13 @@ theorem m_iUnion (v : VectorMeasure α M) {f : ℕ → Set α} (hf₁ : ∀ i, M
(hf₂ : Pairwise (Disjoint on f)) : HasSum (fun i => v (f i)) (v (⋃ i, f i)) :=
v.m_iUnion' hf₁ hf₂
-theorem of_disjoint_iUnion_nat [T2Space M] (v : VectorMeasure α M) {f : ℕ → Set α}
- (hf₁ : ∀ i, MeasurableSet (f i)) (hf₂ : Pairwise (Disjoint on f)) :
- v (⋃ i, f i) = ∑' i, v (f i) :=
- (v.m_iUnion hf₁ hf₂).tsum_eq.symm
-
theorem coe_injective : @Function.Injective (VectorMeasure α M) (Set α → M) (⇑) := fun v w h => by
cases v
cases w
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
@@ -120,45 +112,29 @@ theorem ext_iff (v w : VectorMeasure α M) : v = w ↔ ∀ i : Set α, Measurabl
theorem ext {s t : VectorMeasure α M} (h : ∀ i : Set α, MeasurableSet i → s i = t i) : s = t :=
(ext_iff s t).2 h
-variable [T2Space M] {v : VectorMeasure α M} {f : ℕ → Set α}
+variable [Countable β] {v : VectorMeasure α M} {f : β → Set α}
-theorem hasSum_of_disjoint_iUnion [Countable β] {f : β → Set α} (hf₁ : ∀ i, MeasurableSet (f i))
- (hf₂ : Pairwise (Disjoint on f)) : HasSum (fun i => v (f i)) (v (⋃ i, f i)) := by
- cases nonempty_encodable β
- set g := fun i : ℕ => ⋃ (b : β) (_ : b ∈ Encodable.decode₂ β i), f b with hg
- have hg₁ : ∀ i, MeasurableSet (g i) :=
- fun _ => MeasurableSet.iUnion fun b => MeasurableSet.iUnion fun _ => hf₁ b
- have hg₂ : Pairwise (Disjoint on g) := Encodable.iUnion_decode₂_disjoint_on hf₂
- have := v.of_disjoint_iUnion_nat hg₁ hg₂
- rw [hg, Encodable.iUnion_decode₂] at this
- have hg₃ : (fun i : β => v (f i)) = fun i => v (g (Encodable.encode i)) := by
- ext x
- rw [hg]
- simp only
- congr
- ext y
- simp only [exists_prop, Set.mem_iUnion, Option.mem_def]
- constructor
- · intro hy
- exact ⟨x, (Encodable.decode₂_is_partial_inv _ _).2 rfl, hy⟩
- · rintro ⟨b, hb₁, hb₂⟩
- rw [Encodable.decode₂_is_partial_inv _ _] at hb₁
- rwa [← Encodable.encode_injective hb₁]
- rw [Summable.hasSum_iff, this, ← tsum_iUnion_decode₂]
- · exact v.empty
- · rw [hg₃]
- change Summable ((fun i => v (g i)) ∘ Encodable.encode)
- rw [Function.Injective.summable_iff Encodable.encode_injective]
- · exact (v.m_iUnion hg₁ hg₂).summable
- · intro x hx
- convert v.empty
- simp only [g, Set.iUnion_eq_empty, Option.mem_def, not_exists, Set.mem_range] at hx ⊢
- intro i hi
- exact False.elim ((hx i) ((Encodable.decode₂_is_partial_inv _ _).1 hi))
-
-theorem of_disjoint_iUnion [Countable β] {f : β → Set α} (hf₁ : ∀ i, MeasurableSet (f i))
- (hf₂ : Pairwise (Disjoint on f)) : v (⋃ i, f i) = ∑' i, v (f i) :=
- (hasSum_of_disjoint_iUnion hf₁ hf₂).tsum_eq.symm
+theorem hasSum_of_disjoint_iUnion (hm : ∀ i, MeasurableSet (f i)) (hd : Pairwise (Disjoint on f)) :
+ HasSum (fun i => v (f i)) (v (⋃ i, f i)) := by
+ rcases Countable.exists_injective_nat β with ⟨e, he⟩
+ rw [← hasSum_extend_zero he]
+ convert m_iUnion v (f := Function.extend e f fun _ ↦ ∅) _ _
+ · simp only [Pi.zero_def, Function.apply_extend v, Function.comp_def, empty]
+ · exact (iSup_extend_bot he _).symm
+ · simp [Function.apply_extend MeasurableSet, Function.comp_def, hm]
+ · exact hd.disjoint_extend_bot (he.factorsThrough _)
+
+variable [T2Space M]
+
+theorem of_disjoint_iUnion (hm : ∀ i, MeasurableSet (f i)) (hd : Pairwise (Disjoint on f)) :
+ v (⋃ i, f i) = ∑' i, v (f i) :=
+ (hasSum_of_disjoint_iUnion hm hd).tsum_eq.symm
+
+@[deprecated of_disjoint_iUnion (since := "2024-09-15")]
+theorem of_disjoint_iUnion_nat (v : VectorMeasure α M) {f : ℕ → Set α}
+ (hf₁ : ∀ i, MeasurableSet (f i)) (hf₂ : Pairwise (Disjoint on f)) :
+ v (⋃ i, f i) = ∑' i, v (f i) :=
+ of_disjoint_iUnion hf₁ hf₂
theorem of_union {A B : Set α} (h : Disjoint A B) (hA : MeasurableSet A) (hB : MeasurableSet B) :
v (A ∪ B) = v A + v B := by
@@ -195,12 +171,12 @@ theorem of_diff_of_diff_eq_zero {A B : Set α} (hA : MeasurableSet A) (hB : Meas
theorem of_iUnion_nonneg {M : Type*} [TopologicalSpace M] [OrderedAddCommMonoid M]
[OrderClosedTopology M] {v : VectorMeasure α M} (hf₁ : ∀ i, MeasurableSet (f i))
(hf₂ : Pairwise (Disjoint on f)) (hf₃ : ∀ i, 0 ≤ v (f i)) : 0 ≤ v (⋃ i, f i) :=
- (v.of_disjoint_iUnion_nat hf₁ hf₂).symm ▸ tsum_nonneg hf₃
+ (v.of_disjoint_iUnion hf₁ hf₂).symm ▸ tsum_nonneg hf₃
theorem of_iUnion_nonpos {M : Type*} [TopologicalSpace M] [OrderedAddCommMonoid M]
[OrderClosedTopology M] {v : VectorMeasure α M} (hf₁ : ∀ i, MeasurableSet (f i))
(hf₂ : Pairwise (Disjoint on f)) (hf₃ : ∀ i, v (f i) ≤ 0) : v (⋃ i, f i) ≤ 0 :=
- (v.of_disjoint_iUnion_nat hf₁ hf₂).symm ▸ tsum_nonpos hf₃
+ (v.of_disjoint_iUnion hf₁ hf₂).symm ▸ tsum_nonpos hf₃
theorem of_nonneg_disjoint_union_eq_zero {s : SignedMeasure α} {A B : Set α} (h : Disjoint A B)
(hA₁ : MeasurableSet A) (hB₁ : MeasurableSet B) (hA₂ : 0 ≤ s A) (hB₂ : 0 ≤ s B)
@@ -261,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⟩
@@ -292,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⟩
@@ -307,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⟩
@@ -445,7 +421,7 @@ section
/-- A vector measure over `ℝ≥0∞` is a measure. -/
def ennrealToMeasure {_ : MeasurableSpace α} (v : VectorMeasure α ℝ≥0∞) : Measure α :=
- ofMeasurable (fun s _ => v s) v.empty fun _ hf₁ hf₂ => v.of_disjoint_iUnion_nat hf₁ hf₂
+ ofMeasurable (fun s _ => v s) v.empty fun _ hf₁ hf₂ => v.of_disjoint_iUnion hf₁ hf₂
theorem ennrealToMeasure_apply {m : MeasurableSpace α} {v : VectorMeasure α ℝ≥0∞} {s : Set α}
(hs : MeasurableSet s) : ennrealToMeasure v s = v s := by
@@ -486,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
@@ -524,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) :=
@@ -585,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
@@ -718,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
@@ -815,7 +791,7 @@ theorem restrict_le_restrict_iUnion {f : ℕ → Set α} (hf₁ : ∀ n, Measura
rwa [← Set.inter_iUnion, iUnion_disjointed, Set.inter_eq_left]
have ha₄ : Pairwise (Disjoint on fun n => a ∩ disjointed f n) :=
(disjoint_disjointed _).mono fun i j => Disjoint.mono inf_le_right inf_le_right
- rw [← ha₃, v.of_disjoint_iUnion_nat _ ha₄, w.of_disjoint_iUnion_nat _ ha₄]
+ rw [← ha₃, v.of_disjoint_iUnion _ ha₄, w.of_disjoint_iUnion _ ha₄]
· refine tsum_le_tsum (fun n => (restrict_le_restrict_iff v w (hf₁ n)).1 (hf₂ n) ?_ ?_) ?_ ?_
· exact ha₁.inter (MeasurableSet.disjointed hf₁ n)
· exact Set.Subset.trans Set.inter_subset_right (disjointed_subset _ _)
@@ -904,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
@@ -1162,7 +1137,7 @@ def toMeasureOfZeroLE (s : SignedMeasure α) (i : Set α) (hi₁ : MeasurableSet
intro n m hnm
exact ((hf₂ hnm).inf_left' i).inf_right' i
simp only [toMeasureOfZeroLE', s.restrict_apply hi₁ (MeasurableSet.iUnion hf₁), Set.inter_comm,
- Set.inter_iUnion, s.of_disjoint_iUnion_nat h₁ h₂, ENNReal.some_eq_coe, id]
+ Set.inter_iUnion, s.of_disjoint_iUnion h₁ h₂, ENNReal.some_eq_coe, id]
have h : ∀ n, 0 ≤ s (i ∩ f n) := fun n =>
s.nonneg_of_zero_le_restrict (s.zero_le_restrict_subset hi₁ Set.inter_subset_left hi₂)
rw [NNReal.coe_tsum_of_nonneg h, ENNReal.coe_tsum]
diff --git a/Mathlib/MeasureTheory/Measure/WithDensity.lean b/Mathlib/MeasureTheory/Measure/WithDensity.lean
index 2822135c290aa..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) :
@@ -235,14 +235,14 @@ theorem withDensity_apply_eq_zero' {f : α → ℝ≥0∞} {s : Set α} (hf : AE
simp only [Pi.zero_apply, mem_setOf_eq, Filter.mem_mk] at A
convert A using 2
ext x
- simp only [and_comm, exists_prop, mem_inter_iff, iff_self_iff, mem_setOf_eq,
+ simp only [and_comm, exists_prop, mem_inter_iff, mem_setOf_eq,
mem_compl_iff, not_forall]
· intro hs
let t := toMeasurable μ ({ x | f x ≠ 0 } ∩ s)
have A : s ⊆ t ∪ { x | f x = 0 } := by
intro x hx
rcases eq_or_ne (f x) 0 with (fx | fx)
- · simp only [fx, mem_union, mem_setOf_eq, eq_self_iff_true, or_true_iff]
+ · simp only [fx, mem_union, mem_setOf_eq, eq_self_iff_true, or_true]
· left
apply subset_toMeasurable _ _
exact ⟨fx, hx⟩
@@ -271,7 +271,7 @@ theorem ae_withDensity_iff' {p : α → Prop} {f : α → ℝ≥0∞} (hf : AEMe
rw [ae_iff, ae_iff, withDensity_apply_eq_zero' hf, iff_iff_eq]
congr
ext x
- simp only [exists_prop, mem_inter_iff, iff_self_iff, mem_setOf_eq, not_forall]
+ simp only [exists_prop, mem_inter_iff, mem_setOf_eq, not_forall]
theorem ae_withDensity_iff {p : α → Prop} {f : α → ℝ≥0∞} (hf : Measurable f) :
(∀ᵐ x ∂μ.withDensity f, p x) ↔ ∀ᵐ x ∂μ, f x ≠ 0 → p x :=
@@ -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 a6c90472f6f46..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)) < ∞)
@@ -232,7 +232,7 @@ theorem smul_ofFunction {c : ℝ≥0∞} (hc : c ≠ ∞) : c • OuterMeasure.o
haveI : Nonempty { t : ℕ → Set α // s ⊆ ⋃ i, t i } := ⟨⟨fun _ => s, subset_iUnion (fun _ => s) 0⟩⟩
simp only [smul_apply, ofFunction_apply, ENNReal.tsum_mul_left, Pi.smul_apply, smul_eq_mul,
iInf_subtype']
- rw [ENNReal.iInf_mul_left fun h => (hc h).elim]
+ rw [ENNReal.mul_iInf fun h => (hc h).elim]
end OfFunction
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 eb36ea8a28489..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
@@ -260,8 +269,7 @@ theorem mem_generatePiSystem_iUnion_elim {α β} {g : β → Set (Set α)} (h_pi
rw [← forall_and]
constructor <;> intro h1 b <;> by_cases hbs : b ∈ T_s <;> by_cases hbt : b ∈ T_t' <;>
specialize h1 b <;>
- simp only [hbs, hbt, if_true, if_false, true_imp_iff, and_self_iff, false_imp_iff,
- and_true_iff, true_and_iff] at h1 ⊢
+ simp only [hbs, hbt, if_true, if_false, true_imp_iff, and_self_iff, false_imp_iff] at h1 ⊢
all_goals exact h1
intro b h_b
split_ifs with hbs hbt hbt
@@ -338,11 +346,10 @@ theorem piiUnionInter_singleton (π : ι → Set (Set α)) (i : ι) :
exact Or.inl (hfπ i hi)
· have ht_empty : t = ∅ := by
ext1 x
- simp only [Finset.not_mem_empty, iff_false_iff]
+ simp only [Finset.not_mem_empty, iff_false]
exact fun hx => hi (hti x hx ▸ hx)
-- Porting note: `Finset.not_mem_empty` required
- simp [ht_empty, Finset.not_mem_empty, iInter_false, iInter_univ, Set.mem_singleton univ,
- or_true_iff]
+ simp [ht_empty, Finset.not_mem_empty, iInter_false, iInter_univ, Set.mem_singleton univ]
· cases' h with hs hs
· refine ⟨{i}, ?_, fun _ => s, ⟨fun x hx => ?_, ?_⟩⟩
· rw [Finset.coe_singleton]
@@ -351,7 +358,7 @@ theorem piiUnionInter_singleton (π : ι → Set (Set α)) (i : ι) :
· simp only [Finset.mem_singleton, iInter_iInter_eq_left]
· refine ⟨∅, ?_⟩
simpa only [Finset.coe_empty, subset_singleton_iff, mem_empty_iff_false, IsEmpty.forall_iff,
- imp_true_iff, Finset.not_mem_empty, iInter_false, iInter_univ, true_and_iff,
+ imp_true_iff, Finset.not_mem_empty, iInter_false, iInter_univ, true_and,
exists_const] using hs
theorem piiUnionInter_singleton_left (s : ι → Set α) (S : Set ι) :
@@ -537,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
@@ -590,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
@@ -649,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 5da29e8340326..9df3fa00df048 100644
--- a/Mathlib/MeasureTheory/SetSemiring.lean
+++ b/Mathlib/MeasureTheory/SetSemiring.lean
@@ -72,7 +72,7 @@ lemma empty_not_mem_diffFinset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈
∅ ∉ hC.diffFinset hs ht := by
classical
simp only [diffFinset, mem_sdiff, Finset.mem_singleton, eq_self_iff_true, not_true,
- and_false_iff, not_false_iff]
+ and_false, not_false_iff]
lemma diffFinset_subset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) :
↑(hC.diffFinset hs ht) ⊆ C := by
@@ -209,7 +209,7 @@ lemma empty_not_mem_diffFinset₀ (hC : IsSetSemiring C) (hs : s ∈ C) (hI :
∅ ∉ hC.diffFinset₀ hs hI := by
classical
simp only [diffFinset₀, mem_sdiff, Finset.mem_singleton, eq_self_iff_true, not_true,
- and_false_iff, not_false_iff]
+ and_false, not_false_iff]
lemma diffFinset₀_subset (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) :
↑(hC.diffFinset₀ hs hI) ⊆ C := by
@@ -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/Algebra/Ring/Basic.lean b/Mathlib/ModelTheory/Algebra/Ring/Basic.lean
index 2a839ffd63d95..c2c75e666e4b2 100644
--- a/Mathlib/ModelTheory/Algebra/Ring/Basic.lean
+++ b/Mathlib/ModelTheory/Algebra/Ring/Basic.lean
@@ -140,7 +140,7 @@ theorem card_ring : card Language.ring = 5 := by
have : Fintype.card Language.ring.Symbols = 5 := rfl
simp [Language.card, this]
-open Language ring Structure
+open Language Structure
/-- A Type `R` is a `CompatibleRing` if it is a structure for the language of rings and this
structure is the same as the structure already given on `R` by the classes `Add`, `Mul` etc.
diff --git a/Mathlib/ModelTheory/Basic.lean b/Mathlib/ModelTheory/Basic.lean
index ed8313ca4af5b..08419dda7c6f0 100644
--- a/Mathlib/ModelTheory/Basic.lean
+++ b/Mathlib/ModelTheory/Basic.lean
@@ -89,7 +89,7 @@ protected abbrev Constants :=
/-- The type of symbols in a given language. -/
-- Porting note(#5171): this linter isn't ported yet.
-- @[nolint has_nonempty_instance]
-def Symbols :=
+abbrev Symbols :=
(Σ l, L.Functions l) ⊕ (Σ l, L.Relations l)
/-- The cardinality of a language is the cardinality of its type of symbols. -/
@@ -102,7 +102,7 @@ theorem card_eq_card_functions_add_card_relations :
L.card =
(Cardinal.sum fun l => Cardinal.lift.{v} #(L.Functions l)) +
Cardinal.sum fun l => Cardinal.lift.{u} #(L.Relations l) := by
- simp [card, Symbols]
+ simp only [card, mk_sum, mk_sigma, lift_sum]
instance isRelational_sum [L.IsRelational] [L'.IsRelational] : IsRelational (L.sum L') :=
fun _ => instIsEmptySum
@@ -111,7 +111,8 @@ instance isAlgebraic_sum [L.IsAlgebraic] [L'.IsAlgebraic] : IsAlgebraic (L.sum L
fun _ => instIsEmptySum
@[simp]
-theorem empty_card : Language.empty.card = 0 := by simp [card_eq_card_functions_add_card_relations]
+theorem empty_card : Language.empty.card = 0 := by simp only [card, mk_sum, mk_sigma, mk_eq_zero,
+ sum_const, mk_eq_aleph0, lift_id', mul_zero, add_zero]
instance isEmpty_empty : IsEmpty Language.empty.Symbols := by
simp only [Language.Symbols, isEmpty_sum, isEmpty_sigma]
@@ -132,12 +133,11 @@ theorem card_relations_sum (i : ℕ) :
Cardinal.lift.{v'} #(L.Relations i) + Cardinal.lift.{v} #(L'.Relations i) := by
simp [Language.sum]
-@[simp]
theorem card_sum :
(L.sum L').card = Cardinal.lift.{max u' v'} L.card + Cardinal.lift.{max u v} L'.card := by
- simp only [card_eq_card_functions_add_card_relations, card_functions_sum, card_relations_sum,
- sum_add_distrib', lift_add, lift_sum, lift_lift]
- simp only [add_assoc, add_comm (Cardinal.sum fun i => (#(L'.Functions i)).lift)]
+ simp only [card, mk_sum, mk_sigma, card_functions_sum, sum_add_distrib', lift_add, lift_sum,
+ lift_lift, card_relations_sum, add_assoc,
+ add_comm (Cardinal.sum fun i => (#(L'.Functions i)).lift)]
/-- Passes a `DecidableEq` instance on a type of function symbols through the `Language`
constructor. Despite the fact that this is proven by `inferInstance`, it is still needed -
@@ -247,14 +247,14 @@ theorem nonempty_of_nonempty_constants [h : Nonempty L.Constants] : Nonempty M :
/-- `HomClass L F M N` states that `F` is a type of `L`-homomorphisms. You should extend this
typeclass when you extend `FirstOrder.Language.Hom`. -/
-class HomClass (L : outParam Language) (F M N : Type*)
+class HomClass (L : outParam Language) (F : Type*) (M N : outParam Type*)
[FunLike F M N] [L.Structure M] [L.Structure N] : Prop where
map_fun : ∀ (φ : F) {n} (f : L.Functions n) (x), φ (funMap f x) = funMap f (φ ∘ x)
map_rel : ∀ (φ : F) {n} (r : L.Relations n) (x), RelMap r x → RelMap r (φ ∘ x)
/-- `StrongHomClass L F M N` states that `F` is a type of `L`-homomorphisms which preserve
relations in both directions. -/
-class StrongHomClass (L : outParam Language) (F M N : Type*)
+class StrongHomClass (L : outParam Language) (F : Type*) (M N : outParam Type*)
[FunLike F M N] [L.Structure M] [L.Structure N] : Prop where
map_fun : ∀ (φ : F) {n} (f : L.Functions n) (x), φ (funMap f x) = funMap f (φ ∘ x)
map_rel : ∀ (φ : F) {n} (r : L.Relations n) (x), RelMap r (φ ∘ x) ↔ RelMap r x
@@ -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 :=
@@ -474,7 +471,7 @@ def comp (hnp : N ↪[L] P) (hmn : M ↪[L] N) : M ↪[L] P where
-- Porting note: should be done by autoparam?
map_fun' := by intros; simp only [Function.comp_apply, map_fun]; trivial
-- Porting note: should be done by autoparam?
- map_rel' := by intros; rw [Function.comp.assoc, map_rel, map_rel]
+ map_rel' := by intros; rw [Function.comp_assoc, map_rel, map_rel]
@[simp]
theorem comp_apply (g : N ↪[L] P) (f : M ↪[L] N) (x : M) : g.comp f x = g (f x) :=
@@ -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'
@@ -551,14 +548,11 @@ def symm (f : M ≃[L] N) : N ≃[L] M :=
simp only [Equiv.toFun_as_coe]
rw [Equiv.symm_apply_eq]
refine Eq.trans ?_ (f.map_fun' f' (f.toEquiv.symm ∘ x)).symm
- rw [← Function.comp.assoc, Equiv.toFun_as_coe, Equiv.self_comp_symm, Function.id_comp]
+ rw [← Function.comp_assoc, Equiv.toFun_as_coe, Equiv.self_comp_symm, Function.id_comp]
map_rel' := fun n r {x} => by
simp only [Equiv.toFun_as_coe]
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
+ rw [← Function.comp_assoc, Equiv.toFun_as_coe, Equiv.self_comp_symm, Function.id_comp] }
@[simp]
theorem symm_symm (f : M ≃[L] N) :
@@ -648,7 +642,7 @@ def comp (hnp : N ≃[L] P) (hmn : M ≃[L] N) : M ≃[L] P :=
-- Porting note: should be done by autoparam?
map_fun' := by intros; simp only [Function.comp_apply, map_fun]; trivial
-- Porting note: should be done by autoparam?
- map_rel' := by intros; rw [Function.comp.assoc, map_rel, map_rel] }
+ map_rel' := by intros; rw [Function.comp_assoc, map_rel, map_rel] }
@[simp]
theorem comp_apply (g : N ≃[L] P) (f : M ≃[L] N) (x : M) : g.comp f x = g (f x) :=
@@ -830,8 +824,8 @@ def inducedStructureEquiv (e : M ≃ N) : @Language.Equiv L M N _ (inducedStruct
letI : L.Structure N := inducedStructure e
exact
{ e with
- map_fun' := @fun n f x => by simp [← Function.comp.assoc e.symm e x]
- map_rel' := @fun n r x => by simp [← Function.comp.assoc e.symm e x] }
+ map_fun' := @fun n f x => by simp [← Function.comp_assoc e.symm e x]
+ map_rel' := @fun n r x => by simp [← Function.comp_assoc e.symm e x] }
@[simp]
theorem toEquiv_inducedStructureEquiv (e : M ≃ N) :
diff --git a/Mathlib/ModelTheory/Complexity.lean b/Mathlib/ModelTheory/Complexity.lean
index 4cf25f2b26ea4..a44a3ddcd67f9 100644
--- a/Mathlib/ModelTheory/Complexity.lean
+++ b/Mathlib/ModelTheory/Complexity.lean
@@ -3,7 +3,7 @@ Copyright (c) 2021 Aaron Anderson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Aaron Anderson
-/
-import Mathlib.ModelTheory.Satisfiability
+import Mathlib.ModelTheory.Equivalence
/-!
# Quantifier Complexity
@@ -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
@@ -288,25 +285,25 @@ theorem IsQF.induction_on_sup_not {P : L.BoundedFormula α n → Prop} {φ : L.B
(ha : ∀ ψ : L.BoundedFormula α n, IsAtomic ψ → P ψ)
(hsup : ∀ {φ₁ φ₂}, P φ₁ → P φ₂ → P (φ₁ ⊔ φ₂)) (hnot : ∀ {φ}, P φ → P φ.not)
(hse :
- ∀ {φ₁ φ₂ : L.BoundedFormula α n}, Theory.SemanticallyEquivalent ∅ φ₁ φ₂ → (P φ₁ ↔ P φ₂)) :
+ ∀ {φ₁ φ₂ : L.BoundedFormula α n}, (φ₁ ⇔[∅] φ₂) → (P φ₁ ↔ P φ₂)) :
P φ :=
IsQF.recOn h hf @(ha) fun {φ₁ φ₂} _ _ h1 h2 =>
- (hse (φ₁.imp_semanticallyEquivalent_not_sup φ₂)).2 (hsup (hnot h1) h2)
+ (hse (φ₁.imp_iff_not_sup φ₂)).2 (hsup (hnot h1) h2)
theorem IsQF.induction_on_inf_not {P : L.BoundedFormula α n → Prop} {φ : L.BoundedFormula α n}
(h : IsQF φ) (hf : P (⊥ : L.BoundedFormula α n))
(ha : ∀ ψ : L.BoundedFormula α n, IsAtomic ψ → P ψ)
(hinf : ∀ {φ₁ φ₂}, P φ₁ → P φ₂ → P (φ₁ ⊓ φ₂)) (hnot : ∀ {φ}, P φ → P φ.not)
(hse :
- ∀ {φ₁ φ₂ : L.BoundedFormula α n}, Theory.SemanticallyEquivalent ∅ φ₁ φ₂ → (P φ₁ ↔ P φ₂)) :
+ ∀ {φ₁ φ₂ : L.BoundedFormula α n}, (φ₁ ⇔[∅] φ₂) → (P φ₁ ↔ P φ₂)) :
P φ :=
h.induction_on_sup_not hf ha
(fun {φ₁ φ₂} h1 h2 =>
- (hse (φ₁.sup_semanticallyEquivalent_not_inf_not φ₂)).2 (hnot (hinf (hnot h1) (hnot h2))))
+ (hse (φ₁.sup_iff_not_inf_not φ₂)).2 (hnot (hinf (hnot h1) (hnot h2))))
(fun {_} => hnot) fun {_ _} => hse
-theorem semanticallyEquivalent_toPrenex (φ : L.BoundedFormula α n) :
- (∅ : L.Theory).SemanticallyEquivalent φ φ.toPrenex := fun M v xs => by
+theorem iff_toPrenex (φ : L.BoundedFormula α n) :
+ φ ⇔[∅] φ.toPrenex := fun M v xs => by
rw [realize_iff, realize_toPrenex]
theorem induction_on_all_ex {P : ∀ {m}, L.BoundedFormula α m → Prop} (φ : L.BoundedFormula α n)
@@ -314,10 +311,10 @@ theorem induction_on_all_ex {P : ∀ {m}, L.BoundedFormula α m → Prop} (φ :
(hall : ∀ {m} {ψ : L.BoundedFormula α (m + 1)}, P ψ → P ψ.all)
(hex : ∀ {m} {φ : L.BoundedFormula α (m + 1)}, P φ → P φ.ex)
(hse : ∀ {m} {φ₁ φ₂ : L.BoundedFormula α m},
- Theory.SemanticallyEquivalent ∅ φ₁ φ₂ → (P φ₁ ↔ P φ₂)) :
+ (φ₁ ⇔[∅] φ₂) → (P φ₁ ↔ P φ₂)) :
P φ := by
suffices h' : ∀ {m} {φ : L.BoundedFormula α m}, φ.IsPrenex → P φ from
- (hse φ.semanticallyEquivalent_toPrenex).2 (h' φ.toPrenex_isPrenex)
+ (hse φ.iff_toPrenex).2 (h' φ.toPrenex_isPrenex)
intro m φ hφ
induction hφ with
| of_isQF hφ => exact hqf hφ
@@ -329,10 +326,10 @@ theorem induction_on_exists_not {P : ∀ {m}, L.BoundedFormula α m → Prop} (
(hnot : ∀ {m} {φ : L.BoundedFormula α m}, P φ → P φ.not)
(hex : ∀ {m} {φ : L.BoundedFormula α (m + 1)}, P φ → P φ.ex)
(hse : ∀ {m} {φ₁ φ₂ : L.BoundedFormula α m},
- Theory.SemanticallyEquivalent ∅ φ₁ φ₂ → (P φ₁ ↔ P φ₂)) :
+ (φ₁ ⇔[∅] φ₂) → (P φ₁ ↔ P φ₂)) :
P φ :=
φ.induction_on_all_ex (fun {_ _} => hqf)
- (fun {_ φ} hφ => (hse φ.all_semanticallyEquivalent_not_ex_not).2 (hnot (hex (hnot hφ))))
+ (fun {_ φ} hφ => (hse φ.all_iff_not_ex_not).2 (hnot (hex (hnot hφ))))
(fun {_ _} => hex) fun {_ _ _} => hse
/-- A universal formula is a formula defined by applying only universal quantifiers to a
diff --git a/Mathlib/ModelTheory/DirectLimit.lean b/Mathlib/ModelTheory/DirectLimit.lean
index a9c1fe39191e1..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,18 +349,18 @@ 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
change _ = funMap F (Quotient.lift _ _ ∘ Quotient.mk _ ∘ Structure.Sigma.mk f i ∘ y)
- rw [funMap_quotient_mk'_sigma_mk', ← Function.comp.assoc, Quotient.lift_comp_mk]
+ rw [funMap_quotient_mk'_sigma_mk', ← Function.comp_assoc, Quotient.lift_comp_mk]
simp only [Quotient.lift_mk, Embedding.map_fun]
rfl
map_rel' R x := by
obtain ⟨i, y, rfl⟩ := exists_quotient_mk'_sigma_mk'_eq G f x
change RelMap R (Quotient.lift _ _ ∘ Quotient.mk _ ∘ Structure.Sigma.mk f i ∘ y) ↔ _
- rw [relMap_quotient_mk'_sigma_mk' G f, ← (g i).map_rel R y, ← Function.comp.assoc,
+ rw [relMap_quotient_mk'_sigma_mk' G f, ← (g i).map_rel R y, ← Function.comp_assoc,
Quotient.lift_comp_mk]
rfl
diff --git a/Mathlib/ModelTheory/ElementaryMaps.lean b/Mathlib/ModelTheory/ElementaryMaps.lean
index ea469044e0dc8..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)
@@ -79,12 +76,12 @@ theorem map_boundedFormula (f : M ↪ₑ[L] N) {α : Type*} {n : ℕ} (φ : L.Bo
f.map_formula' ((φ.restrictFreeVar id).toFormula.relabel (Fintype.equivFin _))
(Sum.elim (v ∘ (↑)) xs ∘ (Fintype.equivFin _).symm)
simp only [Formula.realize_relabel, BoundedFormula.realize_toFormula, iff_eq_eq] at h
- rw [← Function.comp.assoc _ _ (Fintype.equivFin _).symm,
- Function.comp.assoc _ (Fintype.equivFin _).symm (Fintype.equivFin _),
- _root_.Equiv.symm_comp_self, Function.comp_id, Function.comp.assoc, Sum.elim_comp_inl,
- Function.comp.assoc _ _ Sum.inr, Sum.elim_comp_inr, ← Function.comp.assoc] at h
+ rw [← Function.comp_assoc _ _ (Fintype.equivFin _).symm,
+ Function.comp_assoc _ (Fintype.equivFin _).symm (Fintype.equivFin _),
+ _root_.Equiv.symm_comp_self, Function.comp_id, Function.comp_assoc, Sum.elim_comp_inl,
+ Function.comp_assoc _ _ Sum.inr, Sum.elim_comp_inr, ← Function.comp_assoc] at h
refine h.trans ?_
- erw [Function.comp.assoc _ _ (Fintype.equivFin _), _root_.Equiv.symm_comp_self,
+ erw [Function.comp_assoc _ _ (Fintype.equivFin _), _root_.Equiv.symm_comp_self,
Function.comp_id, Sum.elim_comp_inl, Sum.elim_comp_inr (v ∘ Subtype.val) xs,
← Set.inclusion_eq_id (s := (BoundedFormula.freeVarFinset φ : Set α)) Set.Subset.rfl,
BoundedFormula.realize_restrictFreeVar Set.Subset.rfl]
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 98775b13439f3..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
@@ -83,7 +82,7 @@ theorem listDecode_encode_list (l : List (L.Term α)) :
simp only [h, length_append, length_map, length_finRange, le_add_iff_nonneg_right,
_root_.zero_le, ↓reduceDIte, getElem_fin, cons.injEq, func.injEq, heq_eq_eq, true_and]
refine ⟨funext (fun i => ?_), ?_⟩
- · rw [List.getElem_append, List.getElem_map, List.getElem_finRange]
+ · rw [List.getElem_append_left, List.getElem_map, List.getElem_finRange]
simp only [length_map, length_finRange, i.2]
· simp only [length_map, length_finRange, drop_left']
@@ -146,7 +145,7 @@ instance [Encodable α] [Encodable (Σi, L.Functions i)] : Encodable (L.Term α)
instance [h1 : Countable α] [h2 : Countable (Σl, L.Functions l)] : Countable (L.Term α) := by
refine mk_le_aleph0_iff.1 (card_le.trans (max_le_iff.2 ?_))
- simp only [le_refl, mk_sum, add_le_aleph0, lift_le_aleph0, true_and_iff]
+ simp only [le_refl, mk_sum, add_le_aleph0, lift_le_aleph0, true_and]
exact ⟨Cardinal.mk_le_aleph0, Cardinal.mk_le_aleph0⟩
instance small [Small.{u} α] : Small.{u} (L.Term α) :=
@@ -244,7 +243,7 @@ theorem listDecode_encode_list (l : List (Σn, L.BoundedFormula α n)) :
simp only [Option.join, map_append, map_map, Option.bind_eq_some, id, exists_eq_right,
get?_eq_some, length_append, length_map, length_finRange]
refine ⟨lt_of_lt_of_le i.2 le_self_add, ?_⟩
- rw [get_eq_getElem, getElem_append, getElem_map]
+ rw [get_eq_getElem, getElem_append_left, getElem_map]
· simp only [getElem_finRange, Fin.eta, Function.comp_apply, Sum.getLeft?]
· simp only [length_map, length_finRange, is_lt]
rw [dif_pos]
diff --git a/Mathlib/ModelTheory/Equivalence.lean b/Mathlib/ModelTheory/Equivalence.lean
new file mode 100644
index 0000000000000..42f8aff5f8d70
--- /dev/null
+++ b/Mathlib/ModelTheory/Equivalence.lean
@@ -0,0 +1,262 @@
+/-
+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.ModelTheory.Satisfiability
+
+/-!
+# Equivalence of Formulas
+
+## Main Definitions
+- `FirstOrder.Language.Theory.Imp`: `φ ⟹[T] ψ` indicates that `φ` implies `ψ` in models of `T`.
+- `FirstOrder.Language.Theory.Iff`: `φ ⇔[T] ψ` indicates that `φ` and `ψ` are equivalent formulas or
+ sentences in models of `T`.
+
+## TODO
+- Define the quotient of `L.Formula α` modulo `⇔[T]` and its Boolean Algebra structure.
+
+-/
+
+universe u v w w'
+
+open Cardinal CategoryTheory
+
+open Cardinal FirstOrder
+
+namespace FirstOrder
+
+namespace Language
+
+variable {L : Language.{u, v}} {T : L.Theory} {α : Type w} {n : ℕ}
+variable {M : Type*} [Nonempty M] [L.Structure M] [M ⊨ T]
+
+namespace Theory
+
+/-- `φ ⟹[T] ψ` indicates that `φ` implies `ψ` in models of `T`. -/
+protected def Imp (T : L.Theory) (φ ψ : L.BoundedFormula α n) : Prop :=
+ T ⊨ᵇ φ.imp ψ
+
+@[inherit_doc FirstOrder.Language.Theory.Imp]
+scoped[FirstOrder] notation:51 φ:50 " ⟹[" T "] " ψ:51 => Language.Theory.Imp T φ ψ
+
+namespace Imp
+
+@[refl]
+protected theorem refl (φ : L.BoundedFormula α n) : φ ⟹[T] φ := fun _ _ _ => id
+
+instance : IsRefl (L.BoundedFormula α n) T.Imp := ⟨Imp.refl⟩
+
+@[trans]
+protected theorem trans {φ ψ θ : L.BoundedFormula α n} (h1 : φ ⟹[T] ψ) (h2 : ψ ⟹[T] θ) :
+ φ ⟹[T] θ := fun M v xs => (h2 M v xs) ∘ (h1 M v xs)
+
+instance : IsTrans (L.BoundedFormula α n) T.Imp := ⟨fun _ _ _ => Imp.trans⟩
+
+end Imp
+
+section Imp
+
+lemma bot_imp (φ : L.BoundedFormula α n) : ⊥ ⟹[T] φ := fun M v xs => by
+ simp only [BoundedFormula.realize_imp, BoundedFormula.realize_bot, false_implies]
+
+lemma imp_top (φ : L.BoundedFormula α n) : φ ⟹[T] ⊤ := fun M v xs => by
+ simp only [BoundedFormula.realize_imp, BoundedFormula.realize_top, implies_true]
+
+lemma imp_sup_left (φ ψ : L.BoundedFormula α n) : φ ⟹[T] φ ⊔ ψ := fun M v xs => by
+ simp only [BoundedFormula.realize_imp, BoundedFormula.realize_sup]
+ exact Or.inl
+
+lemma imp_sup_right (φ ψ : L.BoundedFormula α n) : ψ ⟹[T] φ ⊔ ψ := fun M v xs => by
+ simp only [BoundedFormula.realize_imp, BoundedFormula.realize_sup]
+ exact Or.inr
+
+lemma sup_imp {φ ψ θ : L.BoundedFormula α n} (h₁ : φ ⟹[T] θ) (h₂ : ψ ⟹[T] θ) :
+ φ ⊔ ψ ⟹[T] θ := fun M v xs => by
+ simp only [BoundedFormula.realize_imp, BoundedFormula.realize_sup]
+ exact fun h => h.elim (h₁ M v xs) (h₂ M v xs)
+
+lemma sup_imp_iff {φ ψ θ : L.BoundedFormula α n} :
+ (φ ⊔ ψ ⟹[T] θ) ↔ (φ ⟹[T] θ) ∧ (ψ ⟹[T] θ) :=
+ ⟨fun h => ⟨(imp_sup_left _ _).trans h, (imp_sup_right _ _).trans h⟩,
+ fun ⟨h₁, h₂⟩ => sup_imp h₁ h₂⟩
+
+lemma inf_imp_left (φ ψ : L.BoundedFormula α n) : φ ⊓ ψ ⟹[T] φ := fun M v xs => by
+ simp only [BoundedFormula.realize_imp, BoundedFormula.realize_inf]
+ exact And.left
+
+lemma inf_imp_right (φ ψ : L.BoundedFormula α n) : φ ⊓ ψ ⟹[T] ψ := fun M v xs => by
+ simp only [BoundedFormula.realize_imp, BoundedFormula.realize_inf]
+ exact And.right
+
+lemma imp_inf {φ ψ θ : L.BoundedFormula α n} (h₁ : φ ⟹[T] ψ) (h₂ : φ ⟹[T] θ) :
+ φ ⟹[T] ψ ⊓ θ := fun M v xs => by
+ simp only [BoundedFormula.realize_imp, BoundedFormula.realize_inf]
+ exact fun h => ⟨h₁ M v xs h, h₂ M v xs h⟩
+
+lemma imp_inf_iff {φ ψ θ : L.BoundedFormula α n} :
+ (φ ⟹[T] ψ ⊓ θ) ↔ (φ ⟹[T] ψ) ∧ (φ ⟹[T] θ) :=
+ ⟨fun h => ⟨h.trans (inf_imp_left _ _), h.trans (inf_imp_right _ _)⟩,
+ fun ⟨h₁, h₂⟩ => imp_inf h₁ h₂⟩
+
+end Imp
+
+/-- Two (bounded) formulas are semantically equivalent over a theory `T` when they have the same
+interpretation in every model of `T`. (This is also known as logical equivalence, which also has a
+proof-theoretic definition.) -/
+protected def Iff (T : L.Theory) (φ ψ : L.BoundedFormula α n) : Prop :=
+ T ⊨ᵇ φ.iff ψ
+
+@[inherit_doc FirstOrder.Language.Theory.Iff]
+scoped[FirstOrder]
+notation:51 φ:50 " ⇔[" T "] " ψ:51 => Language.Theory.Iff T φ ψ
+
+theorem iff_iff_imp_and_imp {φ ψ : L.BoundedFormula α n} :
+ (φ ⇔[T] ψ) ↔ (φ ⟹[T] ψ) ∧ (ψ ⟹[T] φ) := by
+ simp only [Theory.Imp, ModelsBoundedFormula, BoundedFormula.realize_imp, ← forall_and,
+ Theory.Iff, BoundedFormula.realize_iff, iff_iff_implies_and_implies]
+
+theorem imp_antisymm {φ ψ : L.BoundedFormula α n} (h₁ : φ ⟹[T] ψ) (h₂ : ψ ⟹[T] φ) :
+ φ ⇔[T] ψ :=
+ iff_iff_imp_and_imp.2 ⟨h₁, h₂⟩
+
+namespace Iff
+
+protected theorem mp {φ ψ : L.BoundedFormula α n} (h : φ ⇔[T] ψ) :
+ φ ⟹[T] ψ := (iff_iff_imp_and_imp.1 h).1
+
+protected theorem mpr {φ ψ : L.BoundedFormula α n} (h : φ ⇔[T] ψ) :
+ ψ ⟹[T] φ := (iff_iff_imp_and_imp.1 h).2
+
+@[refl]
+protected theorem refl (φ : L.BoundedFormula α n) : φ ⇔[T] φ :=
+ fun M v xs => by rw [BoundedFormula.realize_iff]
+
+instance : IsRefl (L.BoundedFormula α n) T.Iff :=
+ ⟨Iff.refl⟩
+
+@[symm]
+protected theorem symm {φ ψ : L.BoundedFormula α n}
+ (h : φ ⇔[T] ψ) : ψ ⇔[T] φ := fun M v xs => by
+ rw [BoundedFormula.realize_iff, Iff.comm, ← BoundedFormula.realize_iff]
+ exact h M v xs
+
+instance : IsSymm (L.BoundedFormula α n) T.Iff :=
+ ⟨fun _ _ => Iff.symm⟩
+
+@[trans]
+protected theorem trans {φ ψ θ : L.BoundedFormula α n}
+ (h1 : φ ⇔[T] ψ) (h2 : ψ ⇔[T] θ) :
+ φ ⇔[T] θ := fun M v xs => by
+ have h1' := h1 M v xs
+ have h2' := h2 M v xs
+ rw [BoundedFormula.realize_iff] at *
+ exact ⟨h2'.1 ∘ h1'.1, h1'.2 ∘ h2'.2⟩
+
+instance : IsTrans (L.BoundedFormula α n) T.Iff :=
+ ⟨fun _ _ _ => Iff.trans⟩
+
+theorem realize_bd_iff {φ ψ : L.BoundedFormula α n} (h : φ ⇔[T] ψ)
+ {v : α → M} {xs : Fin n → M} : φ.Realize v xs ↔ ψ.Realize v xs :=
+ BoundedFormula.realize_iff.1 (h.realize_boundedFormula M)
+
+theorem realize_iff {φ ψ : L.Formula α} {M : Type*} [Nonempty M]
+ [L.Structure M] [M ⊨ T] (h : φ ⇔[T] ψ) {v : α → M} :
+ φ.Realize v ↔ ψ.Realize v :=
+ h.realize_bd_iff
+
+theorem models_sentence_iff {φ ψ : L.Sentence} {M : Type*} [Nonempty M]
+ [L.Structure M] [M ⊨ T] (h : φ ⇔[T] ψ) :
+ M ⊨ φ ↔ M ⊨ ψ :=
+ h.realize_iff
+
+protected theorem all {φ ψ : L.BoundedFormula α (n + 1)}
+ (h : φ ⇔[T] ψ) : φ.all ⇔[T] ψ.all := by
+ simp_rw [Theory.Iff, ModelsBoundedFormula, BoundedFormula.realize_iff,
+ BoundedFormula.realize_all]
+ exact fun M v xs => forall_congr' fun a => h.realize_bd_iff
+
+protected theorem ex {φ ψ : L.BoundedFormula α (n + 1)} (h : φ ⇔[T] ψ) :
+ φ.ex ⇔[T] ψ.ex := by
+ simp_rw [Theory.Iff, ModelsBoundedFormula, BoundedFormula.realize_iff,
+ BoundedFormula.realize_ex]
+ exact fun M v xs => exists_congr fun a => h.realize_bd_iff
+
+protected theorem not {φ ψ : L.BoundedFormula α n} (h : φ ⇔[T] ψ) :
+ φ.not ⇔[T] ψ.not := by
+ simp_rw [Theory.Iff, ModelsBoundedFormula, BoundedFormula.realize_iff,
+ BoundedFormula.realize_not]
+ exact fun M v xs => not_congr h.realize_bd_iff
+
+protected theorem imp {φ ψ φ' ψ' : L.BoundedFormula α n} (h : φ ⇔[T] ψ) (h' : φ' ⇔[T] ψ') :
+ (φ.imp φ') ⇔[T] (ψ.imp ψ') := by
+ simp_rw [Theory.Iff, ModelsBoundedFormula, BoundedFormula.realize_iff,
+ BoundedFormula.realize_imp]
+ exact fun M v xs => imp_congr h.realize_bd_iff h'.realize_bd_iff
+
+end Iff
+
+/-- Semantic equivalence forms an equivalence relation on formulas. -/
+def iffSetoid (T : L.Theory) : Setoid (L.BoundedFormula α n) where
+ r := T.Iff
+ iseqv := ⟨fun _ => refl _, fun {_ _} h => h.symm, fun {_ _ _} h1 h2 => h1.trans h2⟩
+
+end Theory
+
+namespace BoundedFormula
+
+variable (φ ψ : L.BoundedFormula α n)
+
+theorem iff_not_not : φ ⇔[T] φ.not.not := fun M v xs => by
+ simp
+
+theorem imp_iff_not_sup : (φ.imp ψ) ⇔[T] (φ.not ⊔ ψ) :=
+ fun M v xs => by simp [imp_iff_not_or]
+
+theorem sup_iff_not_inf_not : (φ ⊔ ψ) ⇔[T] (φ.not ⊓ ψ.not).not :=
+ fun M v xs => by simp [imp_iff_not_or]
+
+theorem inf_iff_not_sup_not : (φ ⊓ ψ) ⇔[T] (φ.not ⊔ ψ.not).not :=
+ fun M v xs => by simp
+
+theorem all_iff_not_ex_not (φ : L.BoundedFormula α (n + 1)) :
+ φ.all ⇔[T] φ.not.ex.not := fun M v xs => by simp
+
+theorem ex_iff_not_all_not (φ : L.BoundedFormula α (n + 1)) :
+ φ.ex ⇔[T] φ.not.all.not := fun M v xs => by simp
+
+theorem iff_all_liftAt : φ ⇔[T] (φ.liftAt 1 n).all :=
+ fun M v xs => by
+ rw [realize_iff, realize_all_liftAt_one_self]
+
+lemma inf_not_iff_bot :
+ φ ⊓ ∼φ ⇔[T] ⊥ := fun M v xs => by
+ simp only [realize_iff, realize_inf, realize_not, and_not_self, realize_bot]
+
+lemma sup_not_iff_top :
+ φ ⊔ ∼φ ⇔[T] ⊤ := fun M v xs => by
+ simp only [realize_iff, realize_sup, realize_not, realize_top, iff_true, or_not]
+
+end BoundedFormula
+
+namespace Formula
+
+variable (φ ψ : L.Formula α)
+
+theorem iff_not_not : φ ⇔[T] φ.not.not :=
+ BoundedFormula.iff_not_not φ
+
+theorem imp_iff_not_sup : (φ.imp ψ) ⇔[T] (φ.not ⊔ ψ) :=
+ BoundedFormula.imp_iff_not_sup φ ψ
+
+theorem sup_iff_not_inf_not : (φ ⊔ ψ) ⇔[T] (φ.not ⊓ ψ.not).not :=
+ BoundedFormula.sup_iff_not_inf_not φ ψ
+
+theorem inf_iff_not_sup_not : (φ ⊓ ψ) ⇔[T] (φ.not ⊔ ψ.not).not :=
+ BoundedFormula.inf_iff_not_sup_not φ ψ
+
+end Formula
+
+end Language
+
+end FirstOrder
diff --git a/Mathlib/ModelTheory/Fraisse.lean b/Mathlib/ModelTheory/Fraisse.lean
index cfb2a070bf89f..49c2b90badb5d 100644
--- a/Mathlib/ModelTheory/Fraisse.lean
+++ b/Mathlib/ModelTheory/Fraisse.lean
@@ -62,7 +62,7 @@ Fraïssé limit - the countable ultrahomogeneous structure with that age.
## TODO
-- Show existence and uniqueness of Fraïssé limits
+- Show existence of Fraïssé limits
-/
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 98f073f0a6665..775c86094849c 100644
--- a/Mathlib/ModelTheory/Order.lean
+++ b/Mathlib/ModelTheory/Order.lean
@@ -3,7 +3,10 @@ Copyright (c) 2022 Aaron Anderson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Aaron Anderson
-/
+import Mathlib.Data.Rat.Denumerable
import Mathlib.ModelTheory.Complexity
+import Mathlib.ModelTheory.Fraisse
+import Mathlib.Order.CountableDenseLinearOrder
/-!
# Ordered First-Ordered Structures
@@ -35,6 +38,13 @@ This file defines ordered first-order languages and structures, as well as their
- Under `Language.order.orderedStructure` assumptions, any `OrderHomClass` has an instance of
`L.HomClass M N`, while `M ↪o N` and any `OrderIsoClass` have an instance of
`L.StrongHomClass M N`.
+- `FirstOrder.Language.isFraisseLimit_of_countable_nonempty_dlo` shows that any countable nonempty
+ model of the theory of linear orders is a Fraïssé limit of the class of finite models of the
+ theory of linear orders.
+- `FirstOrder.Language.isFraisse_finite_linear_order` shows that the class of finite models of the
+ theory of linear orders is Fraïssé.
+- `FirstOrder.Language.aleph0_categorical_dlo` shows that the theory of dense linear orders is
+ `ℵ₀`-categorical, and thus complete.
-/
@@ -70,6 +80,21 @@ lemma forall_relations {P : ∀ (n) (_ : Language.order.Relations n), Prop} :
instance instSubsingleton : Subsingleton (Language.order.Relations n) :=
⟨by rintro ⟨⟩ ⟨⟩; rfl⟩
+instance : IsEmpty (Language.order.Relations 0) := ⟨fun x => by cases x⟩
+
+instance : Unique (Σ n, Language.order.Relations n) :=
+ ⟨⟨⟨2, .le⟩⟩, fun ⟨n, R⟩ =>
+ match n, R with
+ | 2, .le => rfl⟩
+
+instance : Unique Language.order.Symbols := ⟨⟨Sum.inr default⟩, by
+ have : IsEmpty (Σ n, Language.order.Functions n) := isEmpty_sigma.2 inferInstance
+ simp only [Symbols, Sum.forall, reduceCtorEq, Sum.inr.injEq, IsEmpty.forall_iff, true_and]
+ exact Unique.eq_default⟩
+
+@[simp]
+lemma card_eq_one : Language.order.card = 1 := by simp [card]
+
end order
/-- A language is ordered if it has a symbol representing `≤`. -/
@@ -206,6 +231,8 @@ instance [Language.order.Structure M] [Language.order.OrderedStructure M] :
LHom.IsExpansionOn (orderLHom L) M where
map_onRelation := by simp [order.relation_eq_leSymb]
+instance (S : L.Substructure M) : L.OrderedStructure S := ⟨fun x => relMap_leSymb (S.subtype ∘ x)⟩
+
@[simp]
theorem Term.realize_le {t₁ t₂ : L.Term (α ⊕ (Fin n))} {v : α → M}
{xs : Fin n → M} :
@@ -228,7 +255,7 @@ theorem realize_noBotOrder_iff : M ⊨ L.noBotOrderSentence ↔ NoBotOrder M :=
intro h a
exact exists_not_ge a
-variable (L)
+variable (L M)
@[simp]
theorem realize_noTopOrder [h : NoTopOrder M] : M ⊨ L.noTopOrderSentence :=
@@ -238,6 +265,14 @@ theorem realize_noTopOrder [h : NoTopOrder M] : M ⊨ L.noTopOrderSentence :=
theorem realize_noBotOrder [h : NoBotOrder M] : M ⊨ L.noBotOrderSentence :=
realize_noBotOrder_iff.2 h
+theorem noTopOrder_of_dlo [M ⊨ L.dlo] : NoTopOrder M :=
+ realize_noTopOrder_iff.1 (L.dlo.realize_sentence_of_mem (by
+ simp only [dlo, Set.union_insert, Set.union_singleton, Set.mem_insert_iff, true_or]))
+
+theorem noBotOrder_of_dlo [M ⊨ L.dlo] : NoBotOrder M :=
+ realize_noBotOrder_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]))
+
end LE
@[simp]
@@ -275,6 +310,12 @@ theorem realize_denselyOrdered [h : DenselyOrdered M] :
M ⊨ L.denselyOrderedSentence :=
realize_denselyOrdered_iff.2 h
+variable (L) (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]))
+
end Preorder
instance model_partialOrder [PartialOrder M] [L.OrderedStructure M] :
@@ -317,10 +358,14 @@ instance : @OrderedStructure L M _ (L.leOfStructure M) _ := by
intros
rfl
-instance [h : DecidableRel (fun (a b : M) => Structure.RelMap (leSymb : L.Relations 2) ![a,b])] :
- DecidableRel (@LE.le M (L.leOfStructure M)) := by
- letI := L.leOfStructure M
- exact h
+/-- The order structure on an ordered language is decidable. -/
+-- This should not be a global instance,
+-- because it will match with any `LE` typeclass search
+@[local instance]
+def decidableLEOfStructure
+ [h : DecidableRel (fun (a b : M) => Structure.RelMap (leSymb : L.Relations 2) ![a,b])] :
+ letI := L.leOfStructure M
+ DecidableRel ((· : M) ≤ ·) := h
/-- Any model of a theory of preorders is a preorder. -/
def preorderOfModels [h : M ⊨ L.preorderTheory] : Preorder M where
@@ -405,6 +450,111 @@ lemma StrongHomClass.toOrderIsoClass
Matrix.cons_val_one, Matrix.head_cons] at h
exact h
+section Fraisse
+
+variable (M)
+
+lemma dlo_isExtensionPair
+ (M : Type w) [Language.order.Structure M] [M ⊨ Language.order.linearOrderTheory]
+ (N : Type w') [Language.order.Structure N] [N ⊨ Language.order.dlo] [Nonempty N] :
+ Language.order.IsExtensionPair M N := by
+ classical
+ rw [isExtensionPair_iff_exists_embedding_closure_singleton_sup]
+ intro S S_fg f m
+ letI := Language.order.linearOrderOfModels M
+ letI := Language.order.linearOrderOfModels N
+ have := Language.order.denselyOrdered_of_dlo N
+ have := Language.order.noBotOrder_of_dlo N
+ have := Language.order.noTopOrder_of_dlo N
+ have := NoBotOrder.to_noMinOrder N
+ have := NoTopOrder.to_noMaxOrder N
+ have hS : Set.Finite (S : Set M) := (S.fg_iff_structure_fg.1 S_fg).finite
+ obtain ⟨g, hg⟩ := Order.exists_orderEmbedding_insert hS.toFinset
+ ((OrderIso.setCongr hS.toFinset (S : Set M) hS.coe_toFinset).toOrderEmbedding.trans
+ (OrderEmbedding.ofStrictMono f (HomClass.strictMono f))) m
+ let g' :
+ ((Substructure.closure Language.order).toFun {m} ⊔ S : Language.order.Substructure M) ↪o N :=
+ ((OrderIso.setCongr _ _ (by
+ convert LowerAdjoint.closure_eq_self_of_mem_closed _
+ (Substructure.mem_closed_of_isRelational Language.order
+ ((insert m hS.toFinset : Finset M) : Set M))
+ simp only [Finset.coe_insert, Set.Finite.coe_toFinset, Substructure.closure_insert,
+ Substructure.closure_eq])).toOrderEmbedding.trans g)
+ use StrongHomClass.toEmbedding g'
+ ext ⟨x, xS⟩
+ refine ((funext_iff.1 hg) ⟨x, ?_⟩).symm
+ simp only [Set.Finite.coe_toFinset, SetLike.mem_coe, xS]
+
+instance (M : Type w) [Language.order.Structure M] [M ⊨ Language.order.dlo] [Nonempty M] :
+ Infinite M := by
+ letI := orderStructure ℚ
+ obtain ⟨f, _⟩ := embedding_from_cg cg_of_countable default (dlo_isExtensionPair ℚ M)
+ exact Infinite.of_injective f f.injective
+
+lemma dlo_age [Language.order.Structure M] [Mdlo : M ⊨ Language.order.dlo] [Nonempty M] :
+ Language.order.age M = {M : CategoryTheory.Bundled.{w'} Language.order.Structure |
+ Finite M ∧ M ⊨ Language.order.linearOrderTheory} := by
+ classical
+ rw [age]
+ ext N
+ refine ⟨fun ⟨hF, h⟩ => ⟨hF.finite, Theory.IsUniversal.models_of_embedding h.some⟩,
+ fun ⟨hF, h⟩ => ⟨FG.of_finite, ?_⟩⟩
+ letI := Language.order.linearOrderOfModels M
+ letI := Language.order.linearOrderOfModels N
+ exact ⟨StrongHomClass.toEmbedding (nonempty_orderEmbedding_of_finite_infinite N M).some⟩
+
+/-- Any countable nonempty model of the theory of dense linear orders is a Fraïssé limit of the
+class of finite models of the theory of linear orders. -/
+theorem isFraisseLimit_of_countable_nonempty_dlo (M : Type w)
+ [Language.order.Structure M] [Countable M] [Nonempty M] [M ⊨ Language.order.dlo] :
+ IsFraisseLimit {M : CategoryTheory.Bundled.{w} Language.order.Structure |
+ Finite M ∧ M ⊨ Language.order.linearOrderTheory} M :=
+ ⟨(isUltrahomogeneous_iff_IsExtensionPair cg_of_countable).2 (dlo_isExtensionPair M M), dlo_age M⟩
+
+/-- The class of finite models of the theory of linear orders is Fraïssé. -/
+theorem isFraisse_finite_linear_order :
+ IsFraisse {M : CategoryTheory.Bundled.{0} Language.order.Structure |
+ Finite M ∧ M ⊨ Language.order.linearOrderTheory} := by
+ letI : Language.order.Structure ℚ := orderStructure _
+ exact (isFraisseLimit_of_countable_nonempty_dlo ℚ).isFraisse
+
+open Cardinal
+
+/-- The theory of dense linear orders is `ℵ₀`-categorical. -/
+theorem aleph0_categorical_dlo : (ℵ₀).Categorical Language.order.dlo := fun M₁ M₂ h₁ h₂ => by
+ obtain ⟨_⟩ := denumerable_iff.2 h₁
+ obtain ⟨_⟩ := denumerable_iff.2 h₂
+ exact (isFraisseLimit_of_countable_nonempty_dlo M₁).nonempty_equiv
+ (isFraisseLimit_of_countable_nonempty_dlo M₂)
+
+/-- The theory of dense linear orders is `ℵ₀`-complete. -/
+theorem dlo_isComplete : Language.order.dlo.IsComplete :=
+ aleph0_categorical_dlo.{0}.isComplete ℵ₀ _ le_rfl (by simp [one_le_aleph0])
+ ⟨by
+ letI : Language.order.Structure ℚ := orderStructure ℚ
+ exact Theory.ModelType.of _ ℚ⟩
+ fun _ => inferInstance
+
+end Fraisse
+
end Language
end FirstOrder
+
+namespace Order
+
+open FirstOrder FirstOrder.Language
+
+/-- A model-theoretic adaptation of the proof of `Order.iso_of_countable_dense`: two countable,
+ dense, nonempty linear orders without endpoints are order isomorphic. -/
+example (α β : Type w') [LinearOrder α] [LinearOrder β]
+ [Countable α] [DenselyOrdered α] [NoMinOrder α] [NoMaxOrder α]
+ [Nonempty α] [Countable β] [DenselyOrdered β] [NoMinOrder β] [NoMaxOrder β] [Nonempty β] :
+ Nonempty (α ≃o β) := by
+ letI := orderStructure α
+ letI := orderStructure β
+ letI := StrongHomClass.toOrderIsoClass Language.order α β (α ≃[Language.order] β)
+ exact ⟨(IsFraisseLimit.nonempty_equiv (isFraisseLimit_of_countable_nonempty_dlo α)
+ (isFraisseLimit_of_countable_nonempty_dlo β)).some⟩
+
+end Order
diff --git a/Mathlib/ModelTheory/PartialEquiv.lean b/Mathlib/ModelTheory/PartialEquiv.lean
index 04111255ca71e..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
@@ -411,16 +411,41 @@ instance inhabited_FGEquiv_of_IsEmpty_Constants_and_Relations
@[simps]
def FGEquiv.symm (f : L.FGEquiv M N) : L.FGEquiv N M := ⟨f.1.symm, f.1.dom_fg_iff_cod_fg.1 f.2⟩
-lemma IsExtensionPair_iff_cod : L.IsExtensionPair M N ↔
+lemma isExtensionPair_iff_cod : L.IsExtensionPair M N ↔
∀ (f : L.FGEquiv N M) (m : M), ∃ g, m ∈ g.1.cod ∧ f ≤ g := by
refine Iff.intro ?_ ?_ <;>
· intro h f m
obtain ⟨g, h1, h2⟩ := h f.symm m
exact ⟨g.symm, h1, monotone_symm h2⟩
+/-- An alternate characterization of an extension pair is that every finitely generated partial
+isomorphism can be extended to include any particular element of the domain. -/
+theorem isExtensionPair_iff_exists_embedding_closure_singleton_sup :
+ L.IsExtensionPair M N ↔
+ ∀ (S : L.Substructure M) (_ : S.FG) (f : S ↪[L] N) (m : M),
+ ∃ g : (closure L {m} ⊔ S : L.Substructure M) ↪[L] N, f =
+ g.comp (Substructure.inclusion le_sup_right) := by
+ refine ⟨fun h S S_FG f m => ?_, fun h ⟨f, f_FG⟩ m => ?_⟩
+ · obtain ⟨⟨f', hf'⟩, mf', ff'1, ff'2⟩ := h ⟨⟨S, _, f.equivRange⟩, S_FG⟩ m
+ refine ⟨f'.toEmbedding.comp (Substructure.inclusion ?_), ?_⟩
+ · simp only [sup_le_iff, ff'1, closure_le, singleton_subset_iff, SetLike.mem_coe, mf',
+ and_self]
+ · ext ⟨x, hx⟩
+ rw [Embedding.subtype_equivRange] at ff'2
+ simp only [← ff'2, Embedding.comp_apply, Substructure.coe_inclusion, inclusion_mk,
+ Equiv.coe_toEmbedding, coeSubtype, PartialEquiv.toEmbedding_apply]
+ · obtain ⟨f', eq_f'⟩ := h f.dom f_FG f.toEmbedding m
+ refine ⟨⟨⟨closure L {m} ⊔ f.dom, f'.toHom.range, f'.equivRange⟩,
+ (fg_closure_singleton _).sup f_FG⟩,
+ subset_closure.trans (le_sup_left : (closure L) {m} ≤ _) (mem_singleton m),
+ ⟨le_sup_right, Embedding.ext (fun _ => ?_)⟩⟩
+ rw [PartialEquiv.toEmbedding] at eq_f'
+ simp only [Embedding.comp_apply, Substructure.coe_inclusion, Equiv.coe_toEmbedding, coeSubtype,
+ Embedding.equivRange_apply, eq_f']
+
namespace IsExtensionPair
-protected alias ⟨cod, _⟩ := IsExtensionPair_iff_cod
+protected alias ⟨cod, _⟩ := isExtensionPair_iff_cod
/-- The cofinal set of finite equivalences with a given element in their domain. -/
def definedAtLeft
diff --git a/Mathlib/ModelTheory/Satisfiability.lean b/Mathlib/ModelTheory/Satisfiability.lean
index 5adfbfe169f28..55fdc417813b7 100644
--- a/Mathlib/ModelTheory/Satisfiability.lean
+++ b/Mathlib/ModelTheory/Satisfiability.lean
@@ -20,8 +20,6 @@ This file deals with the satisfiability of first-order theories, as well as equi
every finite subset of `T` is satisfiable.
- `FirstOrder.Language.Theory.IsComplete`: `T.IsComplete` indicates that `T` is satisfiable and
models each sentence or its negation.
-- `FirstOrder.Language.Theory.SemanticallyEquivalent`: `T.SemanticallyEquivalent φ ψ` indicates
- that `φ` and `ψ` are equivalent formulas or sentences in models of `T`.
- `Cardinal.Categorical`: A theory is `κ`-categorical if all models of size `κ` are isomorphic.
## Main Results
@@ -281,7 +279,7 @@ variable (T)
/-- A theory models a (bounded) formula when any of its nonempty models realizes that formula on all
inputs. -/
def ModelsBoundedFormula (φ : L.BoundedFormula α n) : Prop :=
- ∀ (M : ModelType.{u, v, max u v} T) (v : α → M) (xs : Fin n → M), φ.Realize v xs
+ ∀ (M : ModelType.{u, v, max u v w} T) (v : α → M) (xs : Fin n → M), φ.Realize v xs
-- Porting note: In Lean3 it was `⊨` but ambiguous.
@[inherit_doc FirstOrder.Language.Theory.ModelsBoundedFormula]
@@ -290,7 +288,7 @@ infixl:51 " ⊨ᵇ " => ModelsBoundedFormula -- input using \|= or \vDash, but n
variable {T}
theorem models_formula_iff {φ : L.Formula α} :
- T ⊨ᵇ φ ↔ ∀ (M : ModelType.{u, v, max u v} T) (v : α → M), φ.Realize v :=
+ T ⊨ᵇ φ ↔ ∀ (M : ModelType.{u, v, max u v w} T) (v : α → M), φ.Realize v :=
forall_congr' fun _ => forall_congr' fun _ => Unique.forall_iff
theorem models_sentence_iff {φ : L.Sentence} : T ⊨ᵇ φ ↔ ∀ M : ModelType.{u, v, max u v} T, M ⊨ φ :=
@@ -327,12 +325,47 @@ theorem ModelsBoundedFormula.realize_sentence {φ : L.Sentence} (h : T ⊨ᵇ φ
exact ⟨h, inferInstance⟩
exact Model.isSatisfiable M
+theorem models_formula_iff_onTheory_models_equivSentence {φ : L.Formula α} :
+ T ⊨ᵇ φ ↔ (L.lhomWithConstants α).onTheory T ⊨ᵇ Formula.equivSentence φ := by
+ refine ⟨fun h => models_sentence_iff.2 (fun M => ?_),
+ fun h => models_formula_iff.2 (fun M v => ?_)⟩
+ · letI := (L.lhomWithConstants α).reduct M
+ have : (L.lhomWithConstants α).IsExpansionOn M := LHom.isExpansionOn_reduct _ _
+ -- why doesn't that instance just work?
+ rw [Formula.realize_equivSentence]
+ have : M ⊨ T := (LHom.onTheory_model _ _).1 M.is_model -- why isn't M.is_model inferInstance?
+ let M' := Theory.ModelType.of T M
+ exact h M' (fun a => (L.con a : M)) _
+ · letI : (constantsOn α).Structure M := constantsOn.structure v
+ have : M ⊨ (L.lhomWithConstants α).onTheory T := (LHom.onTheory_model _ _).2 inferInstance
+ exact (Formula.realize_equivSentence _ _).1 (h.realize_sentence M)
+
+theorem ModelsBoundedFormula.realize_formula {φ : L.Formula α} (h : T ⊨ᵇ φ) (M : Type*)
+ [L.Structure M] [M ⊨ T] [Nonempty M] {v : α → M} : φ.Realize v := by
+ rw [models_formula_iff_onTheory_models_equivSentence] at h
+ letI : (constantsOn α).Structure M := constantsOn.structure v
+ have : M ⊨ (L.lhomWithConstants α).onTheory T := (LHom.onTheory_model _ _).2 inferInstance
+ exact (Formula.realize_equivSentence _ _).1 (h.realize_sentence M)
+
+theorem models_toFormula_iff {φ : L.BoundedFormula α n} : T ⊨ᵇ φ.toFormula ↔ T ⊨ᵇ φ := by
+ refine ⟨fun h M v xs => ?_, ?_⟩
+ · have h' : φ.toFormula.Realize (Sum.elim v xs) := h.realize_formula M
+ simp only [BoundedFormula.realize_toFormula, Sum.elim_comp_inl, Sum.elim_comp_inr] at h'
+ exact h'
+ · simp only [models_formula_iff, BoundedFormula.realize_toFormula]
+ exact fun h M v => h M _ _
+
+theorem ModelsBoundedFormula.realize_boundedFormula
+ {φ : L.BoundedFormula α n} (h : T ⊨ᵇ φ) (M : Type*)
+ [L.Structure M] [M ⊨ T] [Nonempty M] {v : α → M} {xs : Fin n → M} : φ.Realize v xs := by
+ have h' : φ.toFormula.Realize (Sum.elim v xs) := (models_toFormula_iff.2 h).realize_formula M
+ simp only [BoundedFormula.realize_toFormula, Sum.elim_comp_inl, Sum.elim_comp_inr] at h'
+ exact h'
+
theorem models_of_models_theory {T' : L.Theory}
(h : ∀ φ : L.Sentence, φ ∈ T' → T ⊨ᵇ φ)
- {φ : L.Formula α} (hφ : T' ⊨ᵇ φ) : T ⊨ᵇ φ := by
- simp only [models_sentence_iff] at h
- intro M
- have hM : M ⊨ T' := T'.model_iff.2 (fun ψ hψ => h ψ hψ M)
+ {φ : L.Formula α} (hφ : T' ⊨ᵇ φ) : T ⊨ᵇ φ := fun M => by
+ have hM : M ⊨ T' := T'.model_iff.2 (fun ψ hψ => (h ψ hψ).realize_sentence M)
let M' : ModelType T' := ⟨M⟩
exact hφ M'
@@ -362,12 +395,12 @@ namespace IsComplete
theorem models_not_iff (h : T.IsComplete) (φ : L.Sentence) : T ⊨ᵇ φ.not ↔ ¬T ⊨ᵇ φ := by
cases' h.2 φ with hφ hφn
- · simp only [hφ, not_true, iff_false_iff]
+ · simp only [hφ, not_true, iff_false]
rw [models_sentence_iff, not_forall]
refine ⟨h.1.some, ?_⟩
simp only [Sentence.realize_not, Classical.not_not]
exact models_sentence_iff.1 hφ _
- · simp only [hφn, true_iff_iff]
+ · simp only [hφn, true_iff]
intro hφ
rw [models_sentence_iff] at *
exact hφn h.1.some (hφ _)
@@ -401,74 +434,6 @@ theorem IsMaximal.mem_of_models (h : T.IsMaximal) {φ : L.Sentence} (hφ : T ⊨
theorem IsMaximal.mem_iff_models (h : T.IsMaximal) (φ : L.Sentence) : φ ∈ T ↔ T ⊨ᵇ φ :=
⟨models_sentence_of_mem, h.mem_of_models⟩
-/-- Two (bounded) formulas are semantically equivalent over a theory `T` when they have the same
-interpretation in every model of `T`. (This is also known as logical equivalence, which also has a
-proof-theoretic definition.) -/
-def SemanticallyEquivalent (T : L.Theory) (φ ψ : L.BoundedFormula α n) : Prop :=
- T ⊨ᵇ φ.iff ψ
-
-@[refl]
-theorem SemanticallyEquivalent.refl (φ : L.BoundedFormula α n) : T.SemanticallyEquivalent φ φ :=
- fun M v xs => by rw [BoundedFormula.realize_iff]
-
-instance : IsRefl (L.BoundedFormula α n) T.SemanticallyEquivalent :=
- ⟨SemanticallyEquivalent.refl⟩
-
-@[symm]
-theorem SemanticallyEquivalent.symm {φ ψ : L.BoundedFormula α n}
- (h : T.SemanticallyEquivalent φ ψ) : T.SemanticallyEquivalent ψ φ := fun M v xs => by
- rw [BoundedFormula.realize_iff, Iff.comm, ← BoundedFormula.realize_iff]
- exact h M v xs
-
-@[trans]
-theorem SemanticallyEquivalent.trans {φ ψ θ : L.BoundedFormula α n}
- (h1 : T.SemanticallyEquivalent φ ψ) (h2 : T.SemanticallyEquivalent ψ θ) :
- T.SemanticallyEquivalent φ θ := fun M v xs => by
- have h1' := h1 M v xs
- have h2' := h2 M v xs
- rw [BoundedFormula.realize_iff] at *
- exact ⟨h2'.1 ∘ h1'.1, h1'.2 ∘ h2'.2⟩
-
-theorem SemanticallyEquivalent.realize_bd_iff {φ ψ : L.BoundedFormula α n} {M : Type max u v}
- [Nonempty M] [L.Structure M] [T.Model M] (h : T.SemanticallyEquivalent φ ψ)
- {v : α → M} {xs : Fin n → M} : φ.Realize v xs ↔ ψ.Realize v xs :=
- BoundedFormula.realize_iff.1 (h (ModelType.of T M) v xs)
-
-theorem SemanticallyEquivalent.realize_iff {φ ψ : L.Formula α} {M : Type max u v} [Nonempty M]
- [L.Structure M] (_hM : T.Model M) (h : T.SemanticallyEquivalent φ ψ) {v : α → M} :
- φ.Realize v ↔ ψ.Realize v :=
- h.realize_bd_iff
-
-/-- Semantic equivalence forms an equivalence relation on formulas. -/
-def semanticallyEquivalentSetoid (T : L.Theory) : Setoid (L.BoundedFormula α n) where
- r := SemanticallyEquivalent T
- iseqv := ⟨fun _ => refl _, fun {_ _} h => h.symm, fun {_ _ _} h1 h2 => h1.trans h2⟩
-
-protected theorem SemanticallyEquivalent.all {φ ψ : L.BoundedFormula α (n + 1)}
- (h : T.SemanticallyEquivalent φ ψ) : T.SemanticallyEquivalent φ.all ψ.all := by
- simp_rw [SemanticallyEquivalent, ModelsBoundedFormula, BoundedFormula.realize_iff,
- BoundedFormula.realize_all]
- exact fun M v xs => forall_congr' fun a => h.realize_bd_iff
-
-protected theorem SemanticallyEquivalent.ex {φ ψ : L.BoundedFormula α (n + 1)}
- (h : T.SemanticallyEquivalent φ ψ) : T.SemanticallyEquivalent φ.ex ψ.ex := by
- simp_rw [SemanticallyEquivalent, ModelsBoundedFormula, BoundedFormula.realize_iff,
- BoundedFormula.realize_ex]
- exact fun M v xs => exists_congr fun a => h.realize_bd_iff
-
-protected theorem SemanticallyEquivalent.not {φ ψ : L.BoundedFormula α n}
- (h : T.SemanticallyEquivalent φ ψ) : T.SemanticallyEquivalent φ.not ψ.not := by
- simp_rw [SemanticallyEquivalent, ModelsBoundedFormula, BoundedFormula.realize_iff,
- BoundedFormula.realize_not]
- exact fun M v xs => not_congr h.realize_bd_iff
-
-protected theorem SemanticallyEquivalent.imp {φ ψ φ' ψ' : L.BoundedFormula α n}
- (h : T.SemanticallyEquivalent φ ψ) (h' : T.SemanticallyEquivalent φ' ψ') :
- T.SemanticallyEquivalent (φ.imp φ') (ψ.imp ψ') := by
- simp_rw [SemanticallyEquivalent, ModelsBoundedFormula, BoundedFormula.realize_iff,
- BoundedFormula.realize_imp]
- exact fun M v xs => imp_congr h.realize_bd_iff h'.realize_bd_iff
-
end Theory
namespace completeTheory
@@ -490,55 +455,6 @@ theorem isComplete [Nonempty M] : (L.completeTheory M).IsComplete :=
end completeTheory
-namespace BoundedFormula
-
-variable (φ ψ : L.BoundedFormula α n)
-
-theorem semanticallyEquivalent_not_not : T.SemanticallyEquivalent φ φ.not.not := fun M v xs => by
- simp
-
-theorem imp_semanticallyEquivalent_not_sup : T.SemanticallyEquivalent (φ.imp ψ) (φ.not ⊔ ψ) :=
- fun M v xs => by simp [imp_iff_not_or]
-
-theorem sup_semanticallyEquivalent_not_inf_not :
- T.SemanticallyEquivalent (φ ⊔ ψ) (φ.not ⊓ ψ.not).not := fun M v xs => by simp [imp_iff_not_or]
-
-theorem inf_semanticallyEquivalent_not_sup_not :
- T.SemanticallyEquivalent (φ ⊓ ψ) (φ.not ⊔ ψ.not).not := fun M v xs => by
- simp
-
-theorem all_semanticallyEquivalent_not_ex_not (φ : L.BoundedFormula α (n + 1)) :
- T.SemanticallyEquivalent φ.all φ.not.ex.not := fun M v xs => by simp
-
-theorem ex_semanticallyEquivalent_not_all_not (φ : L.BoundedFormula α (n + 1)) :
- T.SemanticallyEquivalent φ.ex φ.not.all.not := fun M v xs => by simp
-
-theorem semanticallyEquivalent_all_liftAt : T.SemanticallyEquivalent φ (φ.liftAt 1 n).all :=
- fun M v xs => by
- rw [realize_iff, realize_all_liftAt_one_self]
-
-end BoundedFormula
-
-namespace Formula
-
-variable (φ ψ : L.Formula α)
-
-theorem semanticallyEquivalent_not_not : T.SemanticallyEquivalent φ φ.not.not :=
- BoundedFormula.semanticallyEquivalent_not_not φ
-
-theorem imp_semanticallyEquivalent_not_sup : T.SemanticallyEquivalent (φ.imp ψ) (φ.not ⊔ ψ) :=
- BoundedFormula.imp_semanticallyEquivalent_not_sup φ ψ
-
-theorem sup_semanticallyEquivalent_not_inf_not :
- T.SemanticallyEquivalent (φ ⊔ ψ) (φ.not ⊓ ψ.not).not :=
- BoundedFormula.sup_semanticallyEquivalent_not_inf_not φ ψ
-
-theorem inf_semanticallyEquivalent_not_sup_not :
- T.SemanticallyEquivalent (φ ⊓ ψ) (φ.not ⊔ ψ.not).not :=
- BoundedFormula.inf_semanticallyEquivalent_not_sup_not φ ψ
-
-end Formula
-
end Language
end FirstOrder
diff --git a/Mathlib/ModelTheory/Semantics.lean b/Mathlib/ModelTheory/Semantics.lean
index 64044e8cbeccd..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
@@ -353,7 +353,7 @@ theorem realize_relabel {m n : ℕ} {φ : L.BoundedFormula α n} {g : α → β
{xs : Fin (m + n) → M} :
(φ.relabel g).Realize v xs ↔
φ.Realize (Sum.elim v (xs ∘ Fin.castAdd n) ∘ g) (xs ∘ Fin.natAdd m) := by
- rw [relabel, realize_mapTermRel_add_castLe] <;> intros <;> simp
+ apply realize_mapTermRel_add_castLe <;> simp
theorem realize_liftAt {n n' m : ℕ} {φ : L.BoundedFormula α n} {v : α → M} {xs : Fin (n + n') → M}
(hmn : m + n' ≤ n + 1) :
@@ -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. -/
@@ -946,7 +939,7 @@ theorem Sentence.realize_cardGe (n) : M ⊨ Sentence.cardGe L n ↔ ↑n ≤ #M
BoundedFormula.realize_exs]
simp_rw [BoundedFormula.realize_foldr_inf]
simp only [Function.comp_apply, List.mem_map, Prod.exists, Ne, List.mem_product,
- List.mem_finRange, forall_exists_index, and_imp, List.mem_filter, true_and_iff]
+ List.mem_finRange, forall_exists_index, and_imp, List.mem_filter, true_and]
refine ⟨?_, fun xs => ⟨xs.some, ?_⟩⟩
· rintro ⟨xs, h⟩
refine ⟨⟨xs, fun i j ij => ?_⟩⟩
diff --git a/Mathlib/ModelTheory/Substructures.lean b/Mathlib/ModelTheory/Substructures.lean
index 68f04f30f9fb1..8c088e8675107 100644
--- a/Mathlib/ModelTheory/Substructures.lean
+++ b/Mathlib/ModelTheory/Substructures.lean
@@ -309,7 +309,7 @@ lemma closure_eq_of_isRelational [L.IsRelational] (s : Set M) : closure L s = s
@[simp]
lemma mem_closure_iff_of_isRelational [L.IsRelational] (s : Set M) (m : M) :
m ∈ closure L s ↔ m ∈ s := by
- rw [← SetLike.mem_coe, ((closure L).mem_closed_iff s).1 (mem_closed_of_isRelational L s)]
+ rw [← SetLike.mem_coe, closure_eq_of_isRelational]
theorem _root_.Set.Countable.substructure_closure
[Countable (Σl, L.Functions l)] (h : s.Countable) : Countable.{w + 1} (closure L s) := by
@@ -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]
@@ -739,7 +739,7 @@ theorem closure_withConstants_eq :
refine closure_eq_of_le ((A.subset_union_right).trans subset_closure) ?_
rw [← (L.lhomWithConstants A).substructureReduct.le_iff_le]
simp only [subset_closure, reduct_withConstants, closure_le, LHom.coe_substructureReduct,
- Set.union_subset_iff, and_true_iff]
+ Set.union_subset_iff, and_true]
exact subset_closure_withConstants
end Substructure
@@ -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
@@ -926,7 +926,7 @@ namespace Equiv
theorem toHom_range (f : M ≃[L] N) : f.toHom.range = ⊤ := by
ext n
- simp only [Hom.mem_range, coe_toHom, Substructure.mem_top, iff_true_iff]
+ simp only [Hom.mem_range, coe_toHom, Substructure.mem_top, iff_true]
exact ⟨f.symm n, apply_symm_apply _ _⟩
end Equiv
diff --git a/Mathlib/ModelTheory/Syntax.lean b/Mathlib/ModelTheory/Syntax.lean
index b75f1a92257f2..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
@@ -417,8 +416,8 @@ theorem castLE_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) (φ : L.BoundedFormu
| equal => simp
| rel =>
intros
- simp only [castLE, eq_self_iff_true, heq_iff_eq, true_and_iff]
- rw [← Function.comp.assoc, Term.relabel_comp_relabel]
+ simp only [castLE, eq_self_iff_true, heq_iff_eq]
+ rw [← Function.comp_assoc, Term.relabel_comp_relabel]
simp
| imp _ _ ih1 ih2 => simp [ih1, ih2]
| all _ ih3 => intros; simp only [castLE, ih3]
@@ -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]
@@ -576,8 +575,8 @@ theorem relabel_sum_inl (φ : L.BoundedFormula α n) :
| falsum => rfl
| equal => simp [Fin.natAdd_zero, castLE_of_eq, mapTermRel]
| rel => simp [Fin.natAdd_zero, castLE_of_eq, mapTermRel]; rfl
- | imp _ _ ih1 ih2 => simp [mapTermRel, ih1, ih2]
- | all _ ih3 => simp [mapTermRel, ih3, castLE]
+ | imp _ _ ih1 ih2 => simp_all [mapTermRel]
+ | all _ ih3 => simp_all [mapTermRel]
/-- Substitutes the variables in a given formula with terms. -/
def subst {n : ℕ} (φ : L.BoundedFormula α n) (f : α → L.Term β) : L.BoundedFormula β n :=
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 4c41bee0d6a33..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
@@ -148,7 +147,7 @@ theorem Admissible.one_lt_sumInv {pqr : Multiset ℕ+} : Admissible pqr → 1 <
all_goals
rw [← H, E', sumInv_pqr]
conv_rhs => simp only [OfNat.ofNat, PNat.mk_coe]
- rfl
+ norm_num
theorem lt_three {p q r : ℕ+} (hpq : p ≤ q) (hqr : q ≤ r) (H : 1 < sumInv {p, q, r}) : p < 3 := by
have h3 : (0 : ℚ) < 3 := by norm_num
@@ -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 442363c3a7429..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)
@@ -625,7 +624,7 @@ theorem mul [CommSemiring R] {f g : ArithmeticFunction R} (hf : f.IsMultiplicati
constructor
· ring
rw [Nat.mul_eq_zero] at *
- apply not_or_of_not ha hb
+ apply not_or_intro ha hb
· simp only [Set.InjOn, mem_coe, mem_divisorsAntidiagonal, Ne, mem_product, Prod.mk.inj_iff]
rintro ⟨⟨a1, a2⟩, ⟨b1, b2⟩⟩ ⟨⟨rfl, ha⟩, ⟨rfl, hb⟩⟩ ⟨⟨c1, c2⟩, ⟨d1, d2⟩⟩ hcd h
simp only [Prod.mk.inj_iff] at h
@@ -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 fbd3725afff82..be1f4f3f725a8 100644
--- a/Mathlib/NumberTheory/Bernoulli.lean
+++ b/Mathlib/NumberTheory/Bernoulli.lean
@@ -3,12 +3,8 @@ Copyright (c) 2020 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Kevin Buzzard
-/
-import Mathlib.Algebra.BigOperators.NatAntidiagonal
-import Mathlib.Algebra.GeomSum
-import Mathlib.Data.Fintype.BigOperators
import Mathlib.RingTheory.PowerSeries.Inverse
import Mathlib.RingTheory.PowerSeries.WellKnown
-import Mathlib.Tactic.FieldSimp
/-!
# Bernoulli numbers
@@ -185,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]
@@ -257,7 +253,7 @@ theorem bernoulliPowerSeries_mul_exp_sub_one : bernoulliPowerSeries A * (exp A -
simp only [bernoulliPowerSeries, coeff_mul, coeff_X, sum_antidiagonal_succ', one_div, coeff_mk,
coeff_one, coeff_exp, LinearMap.map_sub, factorial, if_pos, cast_succ, cast_one, cast_mul,
sub_zero, RingHom.map_one, add_eq_zero, if_false, _root_.inv_one, zero_add, one_ne_zero,
- mul_zero, and_false_iff, sub_self, ← RingHom.map_mul, ← map_sum]
+ mul_zero, and_false, sub_self, ← RingHom.map_mul, ← map_sum]
cases' n with n
· simp
rw [if_neg n.succ_succ_ne_one]
diff --git a/Mathlib/NumberTheory/Bertrand.lean b/Mathlib/NumberTheory/Bertrand.lean
index 772c5d12f2dff..f35408c70ebe0 100644
--- a/Mathlib/NumberTheory/Bertrand.lean
+++ b/Mathlib/NumberTheory/Bertrand.lean
@@ -165,13 +165,13 @@ theorem centralBinom_le_of_no_bertrand_prime (n : ℕ) (n_large : 2 < n)
· exact pow_factorization_choose_le (mul_pos two_pos n_pos)
have : (Finset.Icc 1 (sqrt (2 * n))).card = sqrt (2 * n) := by rw [card_Icc, Nat.add_sub_cancel]
rw [Finset.prod_const]
- refine pow_le_pow_right n2_pos ((Finset.card_le_card fun x hx => ?_).trans this.le)
+ refine pow_right_mono₀ n2_pos ((Finset.card_le_card fun x hx => ?_).trans this.le)
obtain ⟨h1, h2⟩ := Finset.mem_filter.1 hx
exact Finset.mem_Icc.mpr ⟨(Finset.mem_filter.1 h1).2.one_lt.le, h2⟩
· refine le_trans ?_ (primorial_le_4_pow (2 * n / 3))
refine (Finset.prod_le_prod' fun p hp => (?_ : f p ≤ p)).trans ?_
· obtain ⟨h1, h2⟩ := Finset.mem_filter.1 hp
- refine (pow_le_pow_right (Finset.mem_filter.1 h1).2.one_lt.le ?_).trans (pow_one p).le
+ refine (pow_right_mono₀ (Finset.mem_filter.1 h1).2.one_lt.le ?_).trans (pow_one p).le
exact Nat.factorization_choose_le_one (sqrt_lt'.mp <| not_le.1 h2)
refine Finset.prod_le_prod_of_subset_of_one_le' (Finset.filter_subset _ _) ?_
exact fun p hp _ => (Finset.mem_filter.1 hp).2.one_lt.le
diff --git a/Mathlib/NumberTheory/ClassNumber/AdmissibleAbs.lean b/Mathlib/NumberTheory/ClassNumber/AdmissibleAbs.lean
index dd9d6a2408815..694594f1a0e40 100644
--- a/Mathlib/NumberTheory/ClassNumber/AdmissibleAbs.lean
+++ b/Mathlib/NumberTheory/ClassNumber/AdmissibleAbs.lean
@@ -38,7 +38,7 @@ theorem exists_partition_int (n : ℕ) {ε : ℝ} (hε : 0 < ε) {b : ℤ} (hb :
refine ⟨fun i ↦ ⟨natAbs (floor ((A i % b : ℤ) / abs b • ε : ℝ)), ?_⟩, ?_⟩
· rw [← ofNat_lt, natAbs_of_nonneg (hfloor i), floor_lt]
apply lt_of_lt_of_le _ (Nat.le_ceil _)
- rw [Algebra.smul_def, eq_intCast, ← div_div, div_lt_div_right hε, div_lt_iff hb', one_mul,
+ rw [Algebra.smul_def, eq_intCast, ← div_div, div_lt_div_right hε, div_lt_iff₀ hb', one_mul,
cast_lt]
exact Int.emod_lt _ hb
intro i₀ i₁ hi
@@ -46,7 +46,7 @@ theorem exists_partition_int (n : ℕ) {ε : ℝ} (hε : 0 < ε) {b : ℤ} (hb :
congr_arg ((↑) : ℕ → ℤ) (Fin.mk_eq_mk.mp hi)
rw [natAbs_of_nonneg (hfloor i₀), natAbs_of_nonneg (hfloor i₁)] at hi
have hi := abs_sub_lt_one_of_floor_eq_floor hi
- rw [abs_sub_comm, ← sub_div, abs_div, abs_of_nonneg hbε.le, div_lt_iff hbε, one_mul] at hi
+ rw [abs_sub_comm, ← sub_div, abs_div, abs_of_nonneg hbε.le, div_lt_iff₀ hbε, one_mul] at hi
rwa [Int.cast_abs, Int.cast_sub]
/-- `abs : ℤ → ℤ` is an admissible absolute value. -/
diff --git a/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean b/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean
index 7b6a30b0c651c..fabb26655f44b 100644
--- a/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean
+++ b/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean
@@ -131,7 +131,7 @@ theorem exists_approx_polynomial {b : Fq[X]} (hb : b ≠ 0) {ε : ℝ} (hε : 0
cardPowDegree_nonzero _ h', cardPowDegree_nonzero _ hb, Algebra.smul_def, eq_intCast,
Int.cast_pow, Int.cast_natCast, Int.cast_pow, Int.cast_natCast,
log_mul (pow_ne_zero _ q_pos'.ne') hε.ne', ← rpow_natCast, ← rpow_natCast, log_rpow q_pos',
- log_rpow q_pos', ← lt_div_iff (log_pos one_lt_q'), add_div,
+ log_rpow q_pos', ← lt_div_iff₀ (log_pos one_lt_q'), add_div,
mul_div_cancel_right₀ _ (log_pos one_lt_q').ne']
-- And that result follows from manipulating the result from `exists_approx_polynomial_aux`
-- to turn the `-⌈-stuff⌉₊` into `+ stuff`.
@@ -160,7 +160,7 @@ theorem cardPowDegree_anti_archimedean {x y z : Fq[X]} {a : ℤ} (hxy : cardPowD
cardPowDegree_nonzero _ hyz']
have : (1 : ℤ) ≤ Fintype.card Fq := mod_cast (@Fintype.one_lt_card Fq _ _).le
simp only [Int.cast_pow, Int.cast_natCast, le_max_iff]
- refine Or.imp (pow_le_pow_right this) (pow_le_pow_right this) ?_
+ refine Or.imp (pow_le_pow_right₀ this) (pow_le_pow_right₀ this) ?_
rw [natDegree_le_iff_degree_le, natDegree_le_iff_degree_le, ← le_max_iff, ←
degree_eq_natDegree hxy', ← degree_eq_natDegree hyz']
convert degree_add_le (x - y) (y - z) using 2
diff --git a/Mathlib/NumberTheory/ClassNumber/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 891a8f3be52b6..8140cd702670f 100644
--- a/Mathlib/NumberTheory/Cyclotomic/Basic.lean
+++ b/Mathlib/NumberTheory/Cyclotomic/Basic.lean
@@ -5,7 +5,7 @@ Authors: Riccardo Brasca
-/
import Mathlib.RingTheory.Polynomial.Cyclotomic.Roots
import Mathlib.NumberTheory.NumberField.Basic
-import Mathlib.FieldTheory.Galois
+import Mathlib.FieldTheory.Galois.Basic
/-!
# Cyclotomic extensions
@@ -58,7 +58,7 @@ included in the `Cyclotomic` locale.
-/
-open Polynomial Algebra FiniteDimensional Set
+open Polynomial Algebra Module Set
universe u v w z
@@ -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 e526d1422118e..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
@@ -168,7 +169,7 @@ theorem discr_prime_pow [hcycl : IsCyclotomicExtension {p ^ k} K L] [hp : Fact (
convert_to (discr K fun i : Fin 1 ↦ (algebraMap K L) (-1) ^ ↑i) = _
· congr
ext i
- simp only [map_neg, map_one, Function.comp_apply, Fin.coe_fin_one, _root_.pow_zero]
+ simp only [map_neg, map_one, Function.comp_apply, Fin.val_eq_zero, _root_.pow_zero]
suffices (e.symm i : ℕ) = 0 by simp [this]
rw [← Nat.lt_one_iff]
convert (e.symm i).2
diff --git a/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean b/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean
index b3d2a56cf11a2..a6b2d1fc27387 100644
--- a/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean
+++ b/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean
@@ -21,7 +21,7 @@ universe u
namespace IsCyclotomicExtension.Rat
-open NumberField InfinitePlace FiniteDimensional Complex Nat Polynomial
+open NumberField InfinitePlace Module Complex Nat Polynomial
variable {n : ℕ+} (K : Type u) [Field K] [CharZero K]
@@ -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 f03c4570e3c99..0e8d24cf92d00 100644
--- a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean
+++ b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean
@@ -61,7 +61,7 @@ and only at the "final step", when we need to provide an "explicit" primitive ro
-/
-open Polynomial Algebra Finset FiniteDimensional IsCyclotomicExtension Nat PNat Set
+open Polynomial Algebra Finset Module IsCyclotomicExtension Nat PNat Set
open scoped IntermediateField
universe u v w z
@@ -113,9 +113,10 @@ variable {C}
/-- The `PowerBasis` given by a primitive root `η`. -/
@[simps!]
protected noncomputable def powerBasis : PowerBasis K L :=
- PowerBasis.map (Algebra.adjoin.powerBasis <| (integral {n} K L).isIntegral ζ) <|
- (Subalgebra.equivOfEq _ _ (IsCyclotomicExtension.adjoin_primitive_root_eq_top hζ)).trans
- Subalgebra.topEquiv
+ -- this is purely an optimization
+ letI pb := Algebra.adjoin.powerBasis <| (integral {n} K L).isIntegral ζ
+ pb.map <| (Subalgebra.equivOfEq _ _ (IsCyclotomicExtension.adjoin_primitive_root_eq_top hζ)).trans
+ Subalgebra.topEquiv
theorem powerBasis_gen_mem_adjoin_zeta_sub_one :
(hζ.powerBasis K).gen ∈ adjoin K ({ζ - 1} : Set L) := by
@@ -152,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]
@@ -182,7 +183,7 @@ least `(lcm p q).totient`. -/
theorem _root_.IsPrimitiveRoot.lcm_totient_le_finrank [FiniteDimensional K L] {p q : ℕ} {x y : L}
(hx : IsPrimitiveRoot x p) (hy : IsPrimitiveRoot y q)
(hirr : Irreducible (cyclotomic (Nat.lcm p q) K)) :
- (Nat.lcm p q).totient ≤ FiniteDimensional.finrank K L := by
+ (Nat.lcm p q).totient ≤ Module.finrank K L := by
rcases Nat.eq_zero_or_pos p with (rfl | hppos)
· simp
rcases Nat.eq_zero_or_pos q with (rfl | hqpos)
@@ -340,8 +341,8 @@ theorem sub_one_norm_eq_eval_cyclotomic [IsCyclotomicExtension {n} K L] (h : 2 <
rfl
ext
rw [← neg_sub, map_neg, map_sub, map_one, neg_eq_neg_one_mul]
- rw [prod_mul_distrib, prod_const, card_univ, AlgHom.card, IsCyclotomicExtension.finrank L hirr,
- (totient_even h).neg_one_pow, one_mul]
+ rw [prod_mul_distrib, prod_const, Finset.card_univ, AlgHom.card,
+ IsCyclotomicExtension.finrank L hirr, (totient_even h).neg_one_pow, one_mul]
have Hprod : (Finset.univ.prod fun σ : L →ₐ[K] E => 1 - σ ζ) = eval 1 (cyclotomic' n E) := by
rw [cyclotomic', eval_prod, ← @Finset.prod_attach E E, ← univ_eq_attach]
refine Fintype.prod_equiv (hζ.embeddingsEquivPrimitiveRoots E hirr) _ _ fun σ => ?_
@@ -379,7 +380,7 @@ theorem minpoly_sub_one_eq_cyclotomic_comp [Algebra K A] [IsDomain A] {ζ : A}
minpoly K (ζ - 1) = (cyclotomic n K).comp (X + 1) := by
haveI := IsCyclotomicExtension.neZero' n K A
rw [show ζ - 1 = ζ + algebraMap K A (-1) by simp [sub_eq_add_neg],
- minpoly.add_algebraMap ((integral {n} K A).isIntegral ζ),
+ minpoly.add_algebraMap ζ,
hζ.minpoly_eq_cyclotomic_of_irreducible h]
simp
@@ -392,9 +393,8 @@ theorem norm_pow_sub_one_of_prime_pow_ne_two {k s : ℕ} (hζ : IsPrimitiveRoot
[hpri : Fact (p : ℕ).Prime] [IsCyclotomicExtension {p ^ (k + 1)} K L]
(hirr : Irreducible (cyclotomic (↑(p ^ (k + 1)) : ℕ) K)) (hs : s ≤ k)
(htwo : p ^ (k - s + 1) ≠ 2) : norm K (ζ ^ (p : ℕ) ^ s - 1) = (p : K) ^ (p : ℕ) ^ s := by
--- Porting note: `by simp` was `by linarith` that now fails.
have hirr₁ : Irreducible (cyclotomic ((p : ℕ) ^ (k - s + 1)) K) :=
- cyclotomic_irreducible_pow_of_irreducible_pow hpri.1 (by simp) hirr
+ cyclotomic_irreducible_pow_of_irreducible_pow hpri.1 (by omega) hirr
rw [← PNat.pow_coe] at hirr₁
set η := ζ ^ (p : ℕ) ^ s - 1
let η₁ : K⟮η⟯ := IntermediateField.AdjoinSimple.gen K η
@@ -403,22 +403,17 @@ theorem norm_pow_sub_one_of_prime_pow_ne_two {k s : ℕ} (hζ : IsPrimitiveRoot
refine IsPrimitiveRoot.pow (p ^ (k + 1)).pos hζ ?_
rw [PNat.pow_coe, ← pow_add, add_comm s, Nat.sub_add_cancel (le_trans hs (Nat.le_succ k))]
have : IsCyclotomicExtension {p ^ (k - s + 1)} K K⟮η⟯ := by
- suffices IsCyclotomicExtension {p ^ (k - s + 1)} K K⟮η + 1⟯.toSubalgebra by
- have H : K⟮η + 1⟯.toSubalgebra = K⟮η⟯.toSubalgebra := by
- simp only [IntermediateField.adjoin_simple_toSubalgebra_of_integral
- ((integral {p ^ (k + 1)} K L).isIntegral _)]
- refine Subalgebra.ext fun x => ⟨fun hx => adjoin_le ?_ hx, fun hx => adjoin_le ?_ hx⟩
- · simp only [Set.singleton_subset_iff, SetLike.mem_coe]
- exact Subalgebra.add_mem _ (subset_adjoin (mem_singleton η)) (Subalgebra.one_mem _)
- · simp only [Set.singleton_subset_iff, SetLike.mem_coe]
- nth_rw 2 [← add_sub_cancel_right η 1]
- exact Subalgebra.sub_mem _ (subset_adjoin (mem_singleton _)) (Subalgebra.one_mem _)
--- Porting note: the previous proof was `rw [H] at this; exact this` but it now fails.
- exact IsCyclotomicExtension.equiv _ _ _ (Subalgebra.equivOfEq _ _ H)
--- Porting note: the next `refine` was `rw [H]`, abusing defeq, and it now fails.
+ have HKη : K⟮η⟯ = K⟮η + 1⟯ := by
+ refine le_antisymm ?_ ?_
+ all_goals rw [IntermediateField.adjoin_simple_le_iff]
+ · nth_rw 2 [← add_sub_cancel_right η 1]
+ exact sub_mem (IntermediateField.mem_adjoin_simple_self K (η + 1)) (one_mem _)
+ · exact add_mem (IntermediateField.mem_adjoin_simple_self K η) (one_mem _)
+ rw [HKη]
have H := IntermediateField.adjoin_simple_toSubalgebra_of_integral
- ((integral {p ^ (k + 1)} K L).isIntegral (η + 1))
- refine @IsCyclotomicExtension.equiv _ _ _ _ _ _ _ _ _ ?_ (Subalgebra.equivOfEq _ _ H).symm
+ ((integral {p ^ (k + 1)} K L).isIntegral (η + 1))
+ refine IsCyclotomicExtension.equiv _ _ _ (h := ?_) (.refl : K⟮η + 1⟯.toSubalgebra ≃ₐ[K] _)
+ rw [H]
have hη' : IsPrimitiveRoot (η + 1) ↑(p ^ (k + 1 - s)) := by simpa using hη
-- Porting note: `using 1` was not needed.
convert hη'.adjoin_isCyclotomicExtension K using 1
@@ -427,10 +422,10 @@ theorem norm_pow_sub_one_of_prime_pow_ne_two {k s : ℕ} (hζ : IsPrimitiveRoot
apply coe_submonoidClass_iff.1
convert hη using 1
rw [Nat.sub_add_comm hs, pow_coe]
--- Porting note: the following `haveI` were not needed because the locale `cyclotomic` set them
+-- Porting note: the following `have` were not needed because the locale `cyclotomic` set them
-- as instances.
- haveI := IsCyclotomicExtension.finiteDimensional {p ^ (k + 1)} K L
- haveI := IsCyclotomicExtension.isGalois (p ^ (k + 1)) K L
+ have := IsCyclotomicExtension.finiteDimensional {p ^ (k + 1)} K L
+ have := IsCyclotomicExtension.isGalois (p ^ (k + 1)) K L
rw [norm_eq_norm_adjoin K]
have H := hη.sub_one_norm_isPrimePow ?_ hirr₁ htwo
swap; · rw [PNat.pow_coe]; exact hpri.1.isPrimePow.pow (Nat.succ_ne_zero _)
@@ -439,7 +434,7 @@ theorem norm_pow_sub_one_of_prime_pow_ne_two {k s : ℕ} (hζ : IsPrimitiveRoot
congr
· rw [PNat.pow_coe, Nat.pow_minFac, hpri.1.minFac_eq]
exact Nat.succ_ne_zero _
- have := FiniteDimensional.finrank_mul_finrank K K⟮η⟯ L
+ have := Module.finrank_mul_finrank K K⟮η⟯ L
rw [IsCyclotomicExtension.finrank L hirr, IsCyclotomicExtension.finrank K⟮η⟯ hirr₁,
PNat.pow_coe, PNat.pow_coe, Nat.totient_prime_pow hpri.out (k - s).succ_pos,
Nat.totient_prime_pow hpri.out k.succ_pos, mul_comm _ ((p : ℕ) - 1), mul_assoc,
@@ -494,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,
@@ -511,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 58f251949cb62..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
@@ -293,7 +300,7 @@ theorem zeta_sub_one_prime_of_ne_two [IsCyclotomicExtension {p ^ (k + 1)} ℚ K]
Prime (hζ.toInteger - 1) := by
letI := IsCyclotomicExtension.numberField {p ^ (k + 1)} ℚ K
refine Ideal.prime_of_irreducible_absNorm_span (fun h ↦ ?_) ?_
- · apply hζ.pow_ne_one_of_pos_of_lt zero_lt_one (one_lt_pow hp.out.one_lt (by simp))
+ · apply hζ.pow_ne_one_of_pos_of_lt zero_lt_one (one_lt_pow₀ hp.out.one_lt (by simp))
rw [sub_eq_zero] at h
simpa using congrArg (algebraMap _ K) h
rw [Nat.irreducible_iff_prime, Ideal.absNorm_span_singleton, ← Nat.prime_iff,
@@ -312,7 +319,7 @@ theorem zeta_sub_one_prime_of_two_pow [IsCyclotomicExtension {(2 : ℕ+) ^ (k +
Prime (hζ.toInteger - 1) := by
letI := IsCyclotomicExtension.numberField {(2 : ℕ+) ^ (k + 1)} ℚ K
refine Ideal.prime_of_irreducible_absNorm_span (fun h ↦ ?_) ?_
- · apply hζ.pow_ne_one_of_pos_of_lt zero_lt_one (one_lt_pow (by decide) (by simp))
+ · apply hζ.pow_ne_one_of_pos_of_lt zero_lt_one (one_lt_pow₀ (by decide) (by simp))
rw [sub_eq_zero] at h
simpa using congrArg (algebraMap _ K) h
rw [Nat.irreducible_iff_prime, Ideal.absNorm_span_singleton, ← Nat.prime_iff,
@@ -453,7 +460,7 @@ theorem not_exists_int_prime_dvd_sub_of_prime_pow_ne_two
· simp only [hk, zero_add, pow_one, pow_zero, one_mul, Nat.lt_sub_iff_add_lt,
Nat.reduceAdd] at htwo ⊢
exact htwo.symm.lt_of_le hp.1.two_le
- · exact one_lt_mul_of_lt_of_le (one_lt_pow hp.1.one_lt hk)
+ · exact one_lt_mul_of_lt_of_le (one_lt_pow₀ hp.1.one_lt hk)
(have := Nat.Prime.two_le hp.out; by omega)
rw [sub_eq_iff_eq_add] at h
-- We are assuming that `ζ = n + p * x` for some integer `n` and `x : 𝓞 K`. Looking at the
@@ -498,7 +505,8 @@ theorem finite_quotient_span_sub_one [hcycl : IsCyclotomicExtension {p ^ (k + 1)
have : NumberField K := IsCyclotomicExtension.numberField {p ^ (k + 1)} ℚ K
refine Fintype.finite <| Ideal.fintypeQuotientOfFreeOfNeBot _ (fun h ↦ ?_)
simp only [Ideal.span_singleton_eq_bot, sub_eq_zero, ← Subtype.coe_inj] at h
- exact hζ.ne_one (one_lt_pow hp.1.one_lt (Nat.zero_ne_add_one k).symm) (RingOfIntegers.ext_iff.1 h)
+ exact hζ.ne_one (one_lt_pow₀ hp.1.one_lt (Nat.zero_ne_add_one k).symm)
+ (RingOfIntegers.ext_iff.1 h)
theorem finite_quotient_span_sub_one' [hcycl : IsCyclotomicExtension {p} ℚ K]
(hζ : IsPrimitiveRoot ζ ↑p) :
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 77d109b645420..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
@@ -235,7 +235,7 @@ theorem den_le_and_le_num_le_of_sub_lt_one_div_den_sq {ξ q : ℚ}
· exact le_rfl
· have hξ₀ : (0 : ℚ) < ξ.den := Nat.cast_pos.mpr ξ.pos
rw [← Rat.num_div_den ξ, div_mul_eq_mul_div, div_sub' _ _ _ hξ₀.ne', abs_div, abs_of_pos hξ₀,
- div_lt_iff hξ₀, div_mul_comm, mul_one] at h
+ div_lt_iff₀ hξ₀, div_mul_comm, mul_one] at h
refine Nat.cast_le.mp ((one_lt_div hq₀).mp <| lt_of_le_of_lt ?_ h).le
norm_cast
rw [mul_comm _ q.num]
@@ -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
@@ -422,9 +421,9 @@ private theorem aux₂ : 0 < u - ⌊ξ⌋ * v ∧ u - ⌊ξ⌋ * v < v := by
obtain ⟨hcop, _, h⟩ := h
obtain ⟨hv₀, hv₀'⟩ := aux₀ (zero_lt_two.trans_le hv)
have hv₁ : 0 < 2 * v - 1 := by linarith only [hv]
- rw [← one_div, lt_div_iff (mul_pos hv₀ hv₀'), ← abs_of_pos (mul_pos hv₀ hv₀'), ← abs_mul, sub_mul,
- ← mul_assoc, ← mul_assoc, div_mul_cancel₀ _ hv₀.ne', abs_sub_comm, abs_lt, lt_sub_iff_add_lt,
- sub_lt_iff_lt_add, mul_assoc] at h
+ rw [← one_div, lt_div_iff₀ (mul_pos hv₀ hv₀'), ← abs_of_pos (mul_pos hv₀ hv₀'), ← abs_mul,
+ sub_mul, ← mul_assoc, ← mul_assoc, div_mul_cancel₀ _ hv₀.ne', abs_sub_comm, abs_lt,
+ lt_sub_iff_add_lt, sub_lt_iff_lt_add, mul_assoc] at h
have hu₀ : 0 ≤ u - ⌊ξ⌋ * v := by
-- Porting note: this abused the definitional equality `-1 + 1 = 0`
-- refine' (mul_nonneg_iff_of_pos_right hv₁).mp ((lt_iff_add_one_le (-1 : ℤ) _).mp _)
@@ -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 8146354beb0aa..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,9 +160,13 @@ 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 [changeLevel]
+ simp
lemma factorsThrough_one_iff : FactorsThrough χ 1 ↔ χ = 1 := by
refine ⟨fun ⟨_, χ₀, hχ₀⟩ ↦ ?_,
@@ -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 78221e801b0c2..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)
@@ -82,7 +79,7 @@ theorem cons_self_properDivisors (h : n ≠ 0) :
@[simp]
theorem mem_divisors {m : ℕ} : n ∈ divisors m ↔ n ∣ m ∧ m ≠ 0 := by
rcases eq_or_ne m 0 with (rfl | hm); · simp [divisors]
- simp only [hm, Ne, not_false_iff, and_true_iff, ← filter_dvd_eq_divisors hm, mem_filter,
+ simp only [hm, Ne, not_false_iff, and_true, ← filter_dvd_eq_divisors hm, mem_filter,
mem_range, and_iff_right_iff_imp, Nat.lt_succ_iff]
exact le_of_dvd hm.bot_lt
@@ -109,7 +106,7 @@ theorem mem_divisorsAntidiagonal {x : ℕ × ℕ} :
· rw [Nat.lt_add_one_iff, Nat.lt_add_one_iff]
rw [mul_eq_zero, not_or] at h
simp only [succ_le_of_lt (Nat.pos_of_ne_zero h.1), succ_le_of_lt (Nat.pos_of_ne_zero h.2),
- true_and_iff]
+ true_and]
exact
⟨Nat.le_mul_of_pos_right _ (Nat.pos_of_ne_zero h.2),
Nat.le_mul_of_pos_left _ (Nat.pos_of_ne_zero h.1)⟩
@@ -130,7 +127,7 @@ lemma right_ne_zero_of_mem_divisorsAntidiagonal {p : ℕ × ℕ} (hp : p ∈ n.d
theorem divisor_le {m : ℕ} : n ∈ divisors m → n ≤ m := by
cases' m with m
· simp
- · simp only [mem_divisors, Nat.succ_ne_zero m, and_true_iff, Ne, not_false_iff]
+ · simp only [mem_divisors, Nat.succ_ne_zero m, and_true, Ne, not_false_iff]
exact Nat.le_of_dvd (Nat.succ_pos m)
theorem divisors_subset_of_dvd {m : ℕ} (hzero : n ≠ 0) (h : m ∣ n) : divisors m ⊆ divisors n :=
@@ -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/Basic.lean b/Mathlib/NumberTheory/FLT/Basic.lean
index 908060bf6699e..3630dbe1368d9 100644
--- a/Mathlib/NumberTheory/FLT/Basic.lean
+++ b/Mathlib/NumberTheory/FLT/Basic.lean
@@ -1,18 +1,12 @@
/-
Copyright (c) 2023 Kevin Buzzard. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kevin Buzzard, Yaël Dillies
+Authors: Kevin Buzzard, Yaël Dillies, Jineon Baek
-/
import Mathlib.Algebra.EuclideanDomain.Int
import Mathlib.Algebra.GCDMonoid.Finset
import Mathlib.Algebra.GCDMonoid.Nat
-import Mathlib.Algebra.GroupWithZero.Divisibility
-import Mathlib.Algebra.Order.Ring.Abs
-import Mathlib.Data.Rat.Defs
import Mathlib.RingTheory.PrincipalIdealDomain
-import Mathlib.Tactic.NormNum
-import Mathlib.Tactic.Positivity.Basic
-import Mathlib.Tactic.TFAE
/-!
# Statement of Fermat's Last Theorem
@@ -89,7 +83,7 @@ lemma FermatLastTheoremFor.mono (hmn : m ∣ n) (hm : FermatLastTheoremFor m) :
lemma fermatLastTheoremWith_nat_int_rat_tfae (n : ℕ) :
TFAE [FermatLastTheoremWith ℕ n, FermatLastTheoremWith ℤ n, FermatLastTheoremWith ℚ n] := by
tfae_have 1 → 2
- · rintro h a b c ha hb hc habc
+ | h, a, b, c, ha, hb, hc, habc => by
obtain hn | hn := n.even_or_odd
· refine h a.natAbs b.natAbs c.natAbs (by positivity) (by positivity) (by positivity)
(Int.natCast_inj.1 ?_)
@@ -129,7 +123,7 @@ lemma fermatLastTheoremWith_nat_int_rat_tfae (n : ℕ) :
push_cast
simp only [abs_of_pos, habc, *]
tfae_have 2 → 3
- · rintro h a b c ha hb hc habc
+ | h, a, b, c, ha, hb, hc, habc => by
rw [← Rat.num_ne_zero] at ha hb hc
refine h (a.num * b.den * c.den) (a.den * b.num * c.den) (a.den * b.den * c.num)
(by positivity) (by positivity) (by positivity) ?_
@@ -140,8 +134,7 @@ lemma fermatLastTheoremWith_nat_int_rat_tfae (n : ℕ) :
div_self (by positivity : (b.den : ℚ) ≠ 0), div_self (by positivity : (c.den : ℚ) ≠ 0),
one_mul, mul_one, Rat.num_div_den, habc]
tfae_have 3 → 1
- · rintro h a b c
- exact mod_cast h a b c
+ | h, a, b, c => mod_cast h a b c
tfae_finish
lemma fermatLastTheoremFor_iff_nat {n : ℕ} : FermatLastTheoremFor n ↔ FermatLastTheoremWith ℕ n :=
@@ -153,6 +146,67 @@ lemma fermatLastTheoremFor_iff_int {n : ℕ} : FermatLastTheoremFor n ↔ Fermat
lemma fermatLastTheoremFor_iff_rat {n : ℕ} : FermatLastTheoremFor n ↔ FermatLastTheoremWith ℚ n :=
(fermatLastTheoremWith_nat_int_rat_tfae n).out 0 2
+/--
+A relaxed variant of Fermat's Last Theorem over a given commutative semiring with a specific
+exponent, allowing nonzero solutions of units and their common multiples.
+
+1. The variant `FermatLastTheoremWith' α` is weaker than `FermatLastTheoremWith α` in general.
+ In particular, it holds trivially for `[Field α]`.
+2. This variant is equivalent to the original `FermatLastTheoremWith α` for `α = ℕ` or `ℤ`.
+ In general, they are equivalent if there is no solutions of units to the Fermat equation.
+3. For a polynomial ring `α = k[X]`, the original `FermatLastTheoremWith α` is false but the weaker
+ variant `FermatLastTheoremWith' α` is true. This polynomial variant of Fermat's Last Theorem
+ can be shown elementarily using Mason--Stothers theorem.
+-/
+def FermatLastTheoremWith' (α : Type*) [CommSemiring α] (n : ℕ) : Prop :=
+ ∀ a b c : α, a ≠ 0 → b ≠ 0 → c ≠ 0 → a ^ n + b ^ n = c ^ n →
+ ∃ d a' b' c', (a = a' * d ∧ b = b' * d ∧ c = c' * d) ∧ (IsUnit a' ∧ IsUnit b' ∧ IsUnit c')
+
+lemma FermatLastTheoremWith.fermatLastTheoremWith' {α : Type*} [CommSemiring α] {n : ℕ}
+ (h : FermatLastTheoremWith α n) : FermatLastTheoremWith' α n :=
+ fun a b c _ _ _ _ ↦ by exfalso; apply h a b c <;> assumption
+
+lemma fermatLastTheoremWith'_of_field (α : Type*) [Field α] (n : ℕ) : FermatLastTheoremWith' α n :=
+ fun a b c ha hb hc _ ↦
+ ⟨1, a, b, c,
+ ⟨(mul_one a).symm, (mul_one b).symm, (mul_one c).symm⟩,
+ ⟨ha.isUnit, hb.isUnit, hc.isUnit⟩⟩
+
+lemma FermatLastTheoremWith'.fermatLastTheoremWith {α : Type*} [CommSemiring α] [IsDomain α]
+ {n : ℕ} (h : FermatLastTheoremWith' α n)
+ (hn : ∀ a b c : α, IsUnit a → IsUnit b → IsUnit c → a ^ n + b ^ n ≠ c ^ n) :
+ FermatLastTheoremWith α n := by
+ intro a b c ha hb hc heq
+ rcases h a b c ha hb hc heq with ⟨d, a', b', c', ⟨rfl, rfl, rfl⟩, ⟨ua, ub, uc⟩⟩
+ rw [mul_pow, mul_pow, mul_pow, ← add_mul] at heq
+ exact hn _ _ _ ua ub uc <| mul_right_cancel₀ (pow_ne_zero _ (right_ne_zero_of_mul ha)) heq
+
+lemma fermatLastTheoremWith'_iff_fermatLastTheoremWith {α : Type*} [CommSemiring α] [IsDomain α]
+ {n : ℕ} (hn : ∀ a b c : α, IsUnit a → IsUnit b → IsUnit c → a ^ n + b ^ n ≠ c ^ n) :
+ FermatLastTheoremWith' α n ↔ FermatLastTheoremWith α n :=
+ Iff.intro (fun h ↦ h.fermatLastTheoremWith hn) (fun h ↦ h.fermatLastTheoremWith')
+
+lemma fermatLastTheoremWith'_nat_int_tfae (n : ℕ) :
+ TFAE [FermatLastTheoremFor n, FermatLastTheoremWith' ℕ n, FermatLastTheoremWith' ℤ n] := by
+ tfae_have 2 ↔ 1 := by
+ apply fermatLastTheoremWith'_iff_fermatLastTheoremWith
+ simp only [Nat.isUnit_iff]
+ intro _ _ _ ha hb hc
+ rw [ha, hb, hc]
+ simp only [one_pow, Nat.reduceAdd, ne_eq, OfNat.ofNat_ne_one, not_false_eq_true]
+ tfae_have 3 ↔ 1 := by
+ rw [fermatLastTheoremFor_iff_int]
+ apply fermatLastTheoremWith'_iff_fermatLastTheoremWith
+ intro a b c ha hb hc
+ by_cases hn : n = 0
+ · subst hn
+ simp only [pow_zero, Int.reduceAdd, ne_eq, OfNat.ofNat_ne_one, not_false_eq_true]
+ · rw [← isUnit_pow_iff hn, Int.isUnit_iff] at ha hb hc
+ -- case division
+ rcases ha with ha | ha <;> rcases hb with hb | hb <;> rcases hc with hc | hc <;>
+ rw [ha, hb, hc] <;> decide
+ tfae_finish
+
open Finset in
/-- To prove Fermat Last Theorem in any semiring that is a `NormalizedGCDMonoid` one can assume
that the `gcd` of `{a, b, c}` is `1`. -/
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/FactorisationProperties.lean b/Mathlib/NumberTheory/FactorisationProperties.lean
new file mode 100644
index 0000000000000..28cabcc7fd958
--- /dev/null
+++ b/Mathlib/NumberTheory/FactorisationProperties.lean
@@ -0,0 +1,198 @@
+/-
+Copyright (c) 2024 Colin Jones. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Colin Jones
+-/
+import Mathlib.Algebra.GeomSum
+import Mathlib.Algebra.IsPrimePow
+import Mathlib.NumberTheory.Divisors
+import Mathlib.Tactic.FinCases
+import Mathlib.Tactic.NormNum.Prime
+
+/-!
+# Factorisation properties of natural numbers
+
+This file defines abundant, pseudoperfect, deficient, and weird numbers and formalizes their
+relations with prime and perfect numbers.
+
+## Main Definitions
+
+* `Nat.Abundant`: a natural number `n` is _abundant_ if the sum of its proper divisors is greater
+ than `n`
+* `Nat.Pseudoperfect`: a natural number `n` is _pseudoperfect_ if the sum of a subset of its proper
+ divisors equals `n`
+* `Nat.Deficient`: a natural number `n` is _deficient_ if the sum of its proper divisors is less
+ than `n`
+* `Nat.Weird`: a natural number is _weird_ if it is abundant but not pseudoperfect
+
+## Main Results
+
+* `Nat.deficient_or_perfect_or_abundant`: A positive natural number is either deficient,
+ perfect, or abundant.
+* `Nat.Prime.deficient`: All prime natural numbers are deficient.
+* `Nat.infinite_deficient`: There are infinitely many deficient numbers.
+* `Nat.Prime.deficient_pow`: Any natural number power of a prime is deficient.
+
+## Implementation Notes
+* Zero is not included in any of the definitions and these definitions only apply to natural
+ numbers greater than zero.
+
+## References
+* [R. W. Prielipp, *PERFECT NUMBERS, ABUNDANT NUMBERS, AND DEFICIENT NUMBERS*][Prielipp1970]
+
+## Tags
+
+abundant, deficient, weird, pseudoperfect
+-/
+
+open Finset
+
+namespace Nat
+
+variable {n m p : ℕ}
+
+/-- `n : ℕ` is _abundant_ if the sum of the proper divisors of `n` is greater than `n`. -/
+def Abundant (n : ℕ) : Prop := n < ∑ i ∈ properDivisors n, i
+
+/-- `n : ℕ` is _deficient_ if the sum of the proper divisors of `n` is less than `n`. -/
+def Deficient (n : ℕ) : Prop := ∑ i ∈ properDivisors n, i < n
+
+/-- A positive natural number `n` is _pseudoperfect_ if there exists a subset of the proper
+ divisors of `n` such that the sum of that subset is equal to `n`. -/
+def Pseudoperfect (n : ℕ) : Prop :=
+ 0 < n ∧ ∃ s ⊆ properDivisors n, ∑ i ∈ s, i = n
+
+/-- `n : ℕ` is a _weird_ number if and only if it is abundant but not pseudoperfect. -/
+def Weird (n : ℕ) : Prop := Abundant n ∧ ¬ Pseudoperfect n
+
+theorem not_pseudoperfect_iff_forall :
+ ¬ Pseudoperfect n ↔ n = 0 ∨ ∀ s ⊆ properDivisors n, ∑ i ∈ s, i ≠ n := by
+ rw [Pseudoperfect, not_and_or]
+ simp only [not_lt, nonpos_iff_eq_zero, mem_powerset, not_exists, not_and, ne_eq]
+
+theorem deficient_one : Deficient 1 := zero_lt_one
+theorem deficient_two : Deficient 2 := one_lt_two
+theorem deficient_three : Deficient 3 := by norm_num [Deficient]
+
+theorem abundant_twelve : Abundant 12 := by
+ rw [Abundant, show properDivisors 12 = {1,2,3,4,6} by rfl]
+ norm_num
+
+set_option maxRecDepth 1730 in
+theorem weird_seventy : Weird 70 := by
+ rw [Weird, Abundant, not_pseudoperfect_iff_forall]
+ have h : properDivisors 70 = {1, 2, 5, 7, 10, 14, 35} := by rfl
+ constructor
+ · rw [h]
+ repeat norm_num
+ · rw [h]
+ right
+ intro s hs
+ have hs' := mem_powerset.mpr hs
+ fin_cases hs' <;> decide
+
+lemma deficient_iff_not_abundant_and_not_perfect (hn : n ≠ 0) :
+ Deficient n ↔ ¬ Abundant n ∧ ¬ Perfect n := by
+ dsimp only [Perfect, Abundant, Deficient]
+ omega
+
+lemma perfect_iff_not_abundant_and_not_deficient (hn : 0 ≠ n) :
+ Perfect n ↔ ¬ Abundant n ∧ ¬ Deficient n := by
+ dsimp only [Perfect, Abundant, Deficient]
+ omega
+
+lemma abundant_iff_not_perfect_and_not_deficient (hn : 0 ≠ n) :
+ Abundant n ↔ ¬ Perfect n ∧ ¬ Deficient n := by
+ dsimp only [Perfect, Abundant, Deficient]
+ omega
+
+/-- A positive natural number is either deficient, perfect, or abundant -/
+theorem deficient_or_perfect_or_abundant (hn : 0 ≠ n) :
+ Deficient n ∨ Abundant n ∨ Perfect n := by
+ dsimp only [Perfect, Abundant, Deficient]
+ omega
+
+theorem Perfect.pseudoperfect (h : Perfect n) : Pseudoperfect n :=
+ ⟨h.2, ⟨properDivisors n, ⟨fun ⦃_⦄ a ↦ a, h.1⟩⟩⟩
+
+theorem Prime.not_abundant (h : Prime n) : ¬ Abundant n :=
+ fun h1 ↦ (h.one_lt.trans h1).ne' (sum_properDivisors_eq_one_iff_prime.mpr h)
+
+theorem Prime.not_weird (h : Prime n) : ¬ Weird n := by
+ simp only [Nat.Weird, not_and_or]
+ left
+ exact h.not_abundant
+
+theorem Prime.not_pseudoperfect (h : Prime p) : ¬ Pseudoperfect p := by
+ simp_rw [not_pseudoperfect_iff_forall, ← mem_powerset,
+ show p.properDivisors.powerset = {∅, {1}} by rw [Prime.properDivisors h]; rfl]
+ refine Or.inr (fun s hs ↦ ?_)
+ fin_cases hs <;>
+ simp only [sum_empty, sum_singleton] <;>
+ linarith [Prime.one_lt h]
+
+theorem Prime.not_perfect (h : Prime p) : ¬ Perfect p := by
+ have h1 := Prime.not_pseudoperfect h
+ revert h1
+ exact not_imp_not.mpr (Perfect.pseudoperfect)
+
+/-- Any natural number power of a prime is deficient -/
+theorem Prime.deficient_pow (h : Prime n) : Deficient (n ^ m) := by
+ rcases Nat.eq_zero_or_pos m with (rfl | _)
+ · simpa using deficient_one
+ · have h1 : (n ^ m).properDivisors = image (n ^ ·) (range m) := by
+ apply subset_antisymm <;> intro a
+ · simp only [mem_properDivisors, mem_image, mem_range, dvd_prime_pow h]
+ rintro ⟨⟨t, ht, rfl⟩, ha'⟩
+ exact ⟨t, lt_of_le_of_ne ht (fun ht' ↦ lt_irrefl _ (ht' ▸ ha')), rfl⟩
+ · simp only [mem_image, mem_range, mem_properDivisors, forall_exists_index, and_imp]
+ intro x hx hy
+ constructor
+ · rw [← hy, dvd_prime_pow h]
+ exact ⟨x, Nat.le_of_succ_le hx, rfl⟩
+ · rw [← hy]
+ exact (Nat.pow_lt_pow_iff_right (Prime.two_le h)).mpr hx
+ have h2 : ∑ i in image (fun x => n ^ x) (range m), i = ∑ i in range m, n^i := by
+ rw [Finset.sum_image]
+ rintro x _ y _
+ apply pow_injective_of_not_isUnit h.not_unit <| Prime.ne_zero h
+ rw [Deficient, h1, h2]
+ calc
+ ∑ i ∈ range m, n ^ i
+ = (n ^ m - 1) / (n - 1) := (Nat.geomSum_eq (Prime.two_le h) _)
+ _ ≤ (n ^ m - 1) := Nat.div_le_self (n ^ m - 1) (n - 1)
+ _ < n ^ m := sub_lt (pow_pos (Prime.pos h) m) (Nat.one_pos)
+
+theorem _root_.IsPrimePow.deficient (h : IsPrimePow n) : Deficient n := by
+ obtain ⟨p, k, hp, -, rfl⟩ := h
+ exact hp.nat_prime.deficient_pow
+
+theorem Prime.deficient (h : Prime n) : Deficient n := by
+ rw [← pow_one n]
+ exact h.deficient_pow
+
+/-- There exists infinitely many deficient numbers -/
+theorem infinite_deficient : {n : ℕ | n.Deficient}.Infinite := by
+ rw [Set.infinite_iff_exists_gt]
+ intro a
+ obtain ⟨b, h1, h2⟩ := exists_infinite_primes a.succ
+ exact ⟨b, h2.deficient, h1⟩
+
+theorem infinite_even_deficient : {n : ℕ | Even n ∧ n.Deficient}.Infinite := by
+ rw [Set.infinite_iff_exists_gt]
+ intro n
+ use 2 ^ (n + 1)
+ constructor
+ · exact ⟨⟨2 ^ n, by ring⟩, prime_two.deficient_pow⟩
+ · calc
+ n ≤ 2 ^ n := Nat.le_of_lt (lt_two_pow n)
+ _ < 2 ^ (n + 1) := (Nat.pow_lt_pow_iff_right (Nat.one_lt_two)).mpr (lt_add_one n)
+
+theorem infinite_odd_deficient : {n : ℕ | Odd n ∧ n.Deficient}.Infinite := by
+ rw [Set.infinite_iff_exists_gt]
+ intro n
+ obtain ⟨p, ⟨_, h2⟩⟩ := exists_infinite_primes (max (n + 1) 3)
+ exact ⟨p, Set.mem_setOf.mpr ⟨Prime.odd_of_ne_two h2 (Ne.symm (ne_of_lt (by omega))),
+ Prime.deficient h2⟩, by omega⟩
+
+end Nat
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/FermatPsp.lean b/Mathlib/NumberTheory/FermatPsp.lean
index 87661a60098ce..113b74cc7f237 100644
--- a/Mathlib/NumberTheory/FermatPsp.lean
+++ b/Mathlib/NumberTheory/FermatPsp.lean
@@ -61,7 +61,7 @@ instance decidableProbablePrime (n b : ℕ) : Decidable (ProbablePrime n b) :=
Nat.decidable_dvd _ _
instance decidablePsp (n b : ℕ) : Decidable (FermatPsp n b) :=
- And.decidable
+ inferInstanceAs (Decidable (_ ∧ _))
/-- If `n` passes the Fermat primality test to base `b`, then `n` is coprime with `b`, assuming that
`n` and `b` are both positive.
@@ -94,7 +94,7 @@ theorem coprime_of_probablePrime {n b : ℕ} (h : ProbablePrime n b) (h₁ : 1
theorem probablePrime_iff_modEq (n : ℕ) {b : ℕ} (h : 1 ≤ b) :
ProbablePrime n b ↔ b ^ (n - 1) ≡ 1 [MOD n] := by
- have : 1 ≤ b ^ (n - 1) := one_le_pow_of_one_le h (n - 1)
+ have : 1 ≤ b ^ (n - 1) := one_le_pow₀ h
-- For exact mod_cast
rw [Nat.ModEq.comm]
constructor
@@ -135,7 +135,7 @@ private theorem b_id_helper {a b : ℕ} (ha : 2 ≤ a) (hb : 2 < b) : 2 ≤ (a ^
calc
2 * a + 1 ≤ a ^ 2 * a := by nlinarith
_ = a ^ 3 := by rw [Nat.pow_succ a 2]
- _ ≤ a ^ b := pow_le_pow_right (Nat.le_of_succ_le ha) hb
+ _ ≤ a ^ b := pow_right_mono₀ (Nat.le_of_succ_le ha) hb
private theorem AB_id_helper (b p : ℕ) (_ : 2 ≤ b) (hp : Odd p) :
(b ^ p - 1) / (b - 1) * ((b ^ p + 1) / (b + 1)) = (b ^ (2 * p) - 1) / (b ^ 2 - 1) := by
diff --git a/Mathlib/NumberTheory/FunctionField.lean b/Mathlib/NumberTheory/FunctionField.lean
index 7be9befc8a297..cd2a6cc65454d 100644
--- a/Mathlib/NumberTheory/FunctionField.lean
+++ b/Mathlib/NumberTheory/FunctionField.lean
@@ -42,9 +42,9 @@ function field, ring of integers
noncomputable section
-open scoped nonZeroDivisors Polynomial DiscreteValuation
+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]
@@ -69,9 +68,9 @@ theorem functionField_iff (Fqt : Type*) [Field Fqt] [Algebra Fq[X] Fqt]
refine IsLocalization.ext (nonZeroDivisors Fq[X]) _ _ ?_ ?_ ?_ ?_ ?_ <;> intros <;>
simp only [map_one, map_mul, AlgEquiv.commutes, ← IsScalarTower.algebraMap_apply]
constructor <;> intro h
- · let b := FiniteDimensional.finBasis (RatFunc Fq) F
+ · let b := Module.finBasis (RatFunc Fq) F
exact FiniteDimensional.of_fintype_basis (b.mapCoeffs e this)
- · let b := FiniteDimensional.finBasis Fqt F
+ · let b := Module.finBasis Fqt F
refine FiniteDimensional.of_fintype_basis (b.mapCoeffs e.symm ?_)
intro c x; convert (this (e.symm c) x).symm; simp only [e.apply_symm_apply]
diff --git a/Mathlib/NumberTheory/GaussSum.lean b/Mathlib/NumberTheory/GaussSum.lean
index 5140078baa06e..6af4f9545d5ff 100644
--- a/Mathlib/NumberTheory/GaussSum.lean
+++ b/Mathlib/NumberTheory/GaussSum.lean
@@ -97,8 +97,15 @@ lemma gaussSum_mul {R : Type u} [CommRing R] [Fintype R] {R' : Type v} [CommRing
· exact fun a _ ↦ by rw [add_sub_cancel_right, add_comm]
rw [sum_congr rfl fun x _ ↦ sum_eq x, sum_comm]
--- In the following, we need `R` to be a finite field and `R'` to be a domain.
-variable {R : Type u} [Field R] [Fintype R] {R' : Type v} [CommRing R'] [IsDomain R']
+-- In the following, we need `R` to be a finite field.
+variable {R : Type u} [Field R] [Fintype R] {R' : Type v} [CommRing R']
+
+lemma mul_gaussSum_inv_eq_gaussSum (χ : MulChar R R') (ψ : AddChar R R') :
+ χ (-1) * gaussSum χ ψ⁻¹ = gaussSum χ ψ := by
+ rw [ψ.inv_mulShift, ← Units.coe_neg_one]
+ exact gaussSum_mulShift χ ψ (-1)
+
+variable [IsDomain R'] -- From now on, `R'` needs to be a domain.
-- A helper lemma for `gaussSum_mul_gaussSum_eq_card` below
-- Is this useful enough in other contexts to be public?
@@ -130,6 +137,17 @@ theorem gaussSum_mul_gaussSum_eq_card {χ : MulChar R R'} (hχ : χ ≠ 1) {ψ :
rw [Finset.sum_ite_eq' Finset.univ (1 : R)]
simp only [Finset.mem_univ, map_one, one_mul, if_true]
+/-- If `χ` is a multiplicative character of order `n` on a finite field `F`,
+then `g(χ) * g(χ^(n-1)) = χ(-1)*#F` -/
+lemma gaussSum_mul_gaussSum_pow_orderOf_sub_one {χ : MulChar R R'} {ψ : AddChar R R'}
+ (hχ : χ ≠ 1) (hψ : ψ.IsPrimitive) :
+ gaussSum χ ψ * gaussSum (χ ^ (orderOf χ - 1)) ψ = χ (-1) * Fintype.card R := by
+ have h : χ ^ (orderOf χ - 1) = χ⁻¹ := by
+ refine (inv_eq_of_mul_eq_one_right ?_).symm
+ rw [← pow_succ', Nat.sub_one_add_one_eq_of_pos χ.orderOf_pos, pow_orderOf_eq_one]
+ rw [h, ← mul_gaussSum_inv_eq_gaussSum χ⁻¹, mul_left_comm, gaussSum_mul_gaussSum_eq_card hχ hψ,
+ MulChar.inv_apply', inv_neg_one]
+
/-- The Gauss sum of a nontrivial character on a finite field does not vanish. -/
lemma gaussSum_ne_zero_of_nontrivial (h : (Fintype.card R : R') ≠ 0) {χ : MulChar R R'}
(hχ : χ ≠ 1) {ψ : AddChar R R'} (hψ : ψ.IsPrimitive) :
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/Int.lean b/Mathlib/NumberTheory/Harmonic/Int.lean
index cf5d3e429630e..822c1dac331cb 100644
--- a/Mathlib/NumberTheory/Harmonic/Int.lean
+++ b/Mathlib/NumberTheory/Harmonic/Int.lean
@@ -43,4 +43,4 @@ theorem harmonic_not_int {n : ℕ} (h : 2 ≤ n) : ¬ (harmonic n).isInt := by
apply padicNorm.not_int_of_not_padic_int 2
rw [padicNorm.eq_zpow_of_nonzero (harmonic_pos (ne_zero_of_lt h)).ne',
padicValRat_two_harmonic, neg_neg, zpow_natCast]
- exact one_lt_pow one_lt_two (Nat.log_pos one_lt_two h).ne'
+ exact one_lt_pow₀ one_lt_two (Nat.log_pos one_lt_two h).ne'
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 6c989fdfbe4bb..2de42f2e7d95b 100644
--- a/Mathlib/NumberTheory/JacobiSum/Basic.lean
+++ b/Mathlib/NumberTheory/JacobiSum/Basic.lean
@@ -3,8 +3,9 @@ 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.NumberTheory.MulChar.Basic
-import Mathlib.Algebra.Module.BigOperators
+import Mathlib.NumberTheory.GaussSum
+import Mathlib.NumberTheory.MulChar.Lemmas
+import Mathlib.RingTheory.RootsOfUnity.Lemmas
/-!
# Jacobi Sums
@@ -27,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
@@ -59,18 +60,19 @@ end Def
### Jacobi sums over finite fields
-/
-section FiniteField
+section CommRing
-variable {F R : Type*} [Field F] [Fintype F] [DecidableEq F] [CommRing R]
+variable {F R : Type*} [CommRing F] [Nontrivial F] [Fintype F] [DecidableEq F] [CommRing R]
-/-- The Jacobi sum of two multiplicative characters on a finite field `F` can be written
-as a sum over `F \ {0,1}`. -/
+/-- The Jacobi sum of two multiplicative characters on a nontrivial finite commutative ring `F`
+can be written as a sum over `F \ {0,1}`. -/
lemma jacobiSum_eq_sum_sdiff (χ ψ : MulChar F R) :
jacobiSum χ ψ = ∑ x ∈ univ \ {0,1}, χ x * ψ (1 - x) := by
- simp only [jacobiSum, subset_univ, sum_sdiff_eq_sub, mem_singleton, zero_ne_one,
- not_false_eq_true, sum_insert, isUnit_iff_ne_zero, ne_eq, not_true_eq_false,
- MulCharClass.map_nonunit, sub_zero, map_one, mul_one, sum_singleton, sub_self, mul_zero,
- add_zero]
+ simp only [jacobiSum, subset_univ, sum_sdiff_eq_sub, sub_eq_add_neg, self_eq_add_right,
+ neg_eq_zero]
+ apply sum_eq_zero
+ simp only [mem_insert, mem_singleton, forall_eq_or_imp, χ.map_zero, neg_zero, add_zero, map_one,
+ mul_one, forall_eq, add_neg_cancel, ψ.map_zero, mul_zero, and_self]
private lemma jacobiSum_eq_aux (χ ψ : MulChar F R) :
jacobiSum χ ψ = ∑ x : F, χ x + ∑ x : F, ψ x - Fintype.card F +
@@ -86,10 +88,17 @@ private lemma jacobiSum_eq_aux (χ ψ : MulChar F R) :
congr
rw [sum_pair zero_ne_one, sub_zero, ψ.map_one, χ.map_one, sub_self, mul_zero, zero_mul, add_zero]
+end CommRing
+
+section FiniteField
+
+variable {F R : Type*} [Field F] [Fintype F] [CommRing R]
+
/-- The Jacobi sum of twice the trivial multiplicative character on a finite field `F`
equals `#F-2`. -/
theorem jacobiSum_trivial_trivial :
jacobiSum (MulChar.trivial F R) (MulChar.trivial F R) = Fintype.card F - 2 := by
+ classical
rw [jacobiSum_eq_sum_sdiff]
have : ∀ x ∈ univ \ {0, 1}, (MulChar.trivial F R) x * (MulChar.trivial F R) (1 - x) = 1 := by
intros x hx
@@ -98,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]
@@ -107,4 +116,221 @@ theorem jacobiSum_trivial_trivial :
theorem jacobiSum_one_one : jacobiSum (1 : MulChar F R) 1 = Fintype.card F - 2 :=
jacobiSum_trivial_trivial
+variable [IsDomain R] -- needed for `MulChar.sum_eq_zero_of_ne_one`
+
+/-- If `χ` is a nontrivial multiplicative character on a finite field `F`, then `J(1,χ) = -1`. -/
+theorem jacobiSum_one_nontrivial {χ : MulChar F R} (hχ : χ ≠ 1) : jacobiSum 1 χ = -1 := by
+ classical
+ have : ∑ x ∈ univ \ {0, 1}, ((1 : MulChar F R) x - 1) * (χ (1 - x) - 1) = 0 := by
+ apply Finset.sum_eq_zero
+ simp (config := { contextual := true }) only [mem_sdiff, mem_univ, mem_insert, mem_singleton,
+ not_or, ← isUnit_iff_ne_zero, true_and, MulChar.one_apply, sub_self, zero_mul, and_imp,
+ implies_true]
+ simp only [jacobiSum_eq_aux, MulChar.sum_one_eq_card_units, MulChar.sum_eq_zero_of_ne_one hχ,
+ add_zero, Fintype.card_eq_card_units_add_one (α := F), Nat.cast_add, Nat.cast_one,
+ sub_add_cancel_left, this]
+
+/-- If `χ` is a nontrivial multiplicative character on a finite field `F`,
+then `J(χ,χ⁻¹) = -χ(-1)`. -/
+theorem jacobiSum_nontrivial_inv {χ : MulChar F R} (hχ : χ ≠ 1) : jacobiSum χ χ⁻¹ = -χ (-1) := by
+ classical
+ rw [jacobiSum]
+ conv => enter [1, 2, x]; rw [MulChar.inv_apply', ← map_mul, ← div_eq_mul_inv]
+ rw [sum_eq_sum_diff_singleton_add (mem_univ (1 : F)), sub_self, div_zero, χ.map_zero, add_zero]
+ have : ∑ x ∈ univ \ {1}, χ (x / (1 - x)) = ∑ x ∈ univ \ {-1}, χ x := by
+ refine sum_bij' (fun a _ ↦ a / (1 - a)) (fun b _ ↦ b / (1 + b)) (fun x hx ↦ ?_)
+ (fun y hy ↦ ?_) (fun x hx ↦ ?_) (fun y hy ↦ ?_) (fun _ _ ↦ rfl)
+ · simp only [mem_sdiff, mem_univ, mem_singleton, true_and] at hx ⊢
+ rw [div_eq_iff <| sub_ne_zero.mpr ((ne_eq ..).symm ▸ hx).symm, mul_sub, mul_one,
+ neg_one_mul, sub_neg_eq_add, self_eq_add_left, neg_eq_zero]
+ exact one_ne_zero
+ · simp only [mem_sdiff, mem_univ, mem_singleton, true_and] at hy ⊢
+ rw [div_eq_iff fun h ↦ hy <| eq_neg_of_add_eq_zero_right h, one_mul, self_eq_add_left]
+ exact one_ne_zero
+ · simp only [mem_sdiff, mem_univ, mem_singleton, true_and] at hx
+ rw [eq_comm, ← sub_eq_zero] at hx
+ field_simp
+ · simp only [mem_sdiff, mem_univ, mem_singleton, true_and] at hy
+ rw [eq_comm, neg_eq_iff_eq_neg, ← sub_eq_zero, sub_neg_eq_add] at hy
+ field_simp
+ rw [this, ← add_eq_zero_iff_eq_neg, ← sum_eq_sum_diff_singleton_add (mem_univ (-1 : F))]
+ exact MulChar.sum_eq_zero_of_ne_one hχ
+
+/-- If `χ` and `φ` are multiplicative characters on a finite field `F` such that
+`χφ` is nontrivial, then `g(χφ) * J(χ,φ) = g(χ) * g(φ)`. -/
+theorem jacobiSum_mul_nontrivial {χ φ : MulChar F R} (h : χ * φ ≠ 1) (ψ : AddChar F R) :
+ gaussSum (χ * φ) ψ * jacobiSum χ φ = gaussSum χ ψ * gaussSum φ ψ := by
+ classical
+ rw [gaussSum_mul _ _ ψ, sum_eq_sum_diff_singleton_add (mem_univ (0 : F))]
+ conv =>
+ enter [2, 2, 2, x]
+ rw [zero_sub, neg_eq_neg_one_mul x, map_mul, mul_left_comm (χ x) (φ (-1)),
+ ← MulChar.mul_apply, ψ.map_zero_eq_one, mul_one]
+ rw [← mul_sum _ _ (φ (-1)), MulChar.sum_eq_zero_of_ne_one h, mul_zero, add_zero]
+ have sum_eq : ∀ t ∈ univ \ {0}, (∑ x : F, χ x * φ (t - x)) * ψ t =
+ (∑ y : F, χ (t * y) * φ (t - (t * y))) * ψ t := by
+ intro t ht
+ simp only [mem_sdiff, mem_univ, mem_singleton, true_and] at ht
+ exact congrArg (· * ψ t) (Equiv.sum_comp (Equiv.mulLeft₀ t ht) _).symm
+ simp_rw [← sum_mul, sum_congr rfl sum_eq, ← mul_one_sub, map_mul, mul_assoc]
+ conv => enter [2, 2, t, 1, 2, x, 2]; rw [← mul_assoc, mul_comm (χ x) (φ t)]
+ simp_rw [← mul_assoc, ← MulChar.mul_apply, mul_assoc, ← mul_sum, mul_right_comm]
+ rw [← jacobiSum, ← sum_mul, gaussSum, sum_eq_sum_diff_singleton_add (mem_univ (0 : F)),
+ (χ * φ).map_zero, zero_mul, add_zero]
+
end FiniteField
+
+section field_field
+
+variable {F F' : Type*} [Fintype F] [Field F] [Field F']
+
+/-- If `χ` and `φ` are multiplicative characters on a finite field `F` with values
+in another field `F'` and such that `χφ` is nontrivial, then `J(χ,φ) = g(χ) * g(φ) / g(χφ)`. -/
+theorem jacobiSum_eq_gaussSum_mul_gaussSum_div_gaussSum (h : (Fintype.card F : F') ≠ 0)
+ {χ φ : MulChar F F'} (hχφ : χ * φ ≠ 1) {ψ : AddChar F F'} (hψ : ψ.IsPrimitive) :
+ jacobiSum χ φ = gaussSum χ ψ * gaussSum φ ψ / gaussSum (χ * φ) ψ := by
+ rw [eq_div_iff <| gaussSum_ne_zero_of_nontrivial h hχφ hψ, mul_comm]
+ exact jacobiSum_mul_nontrivial hχφ ψ
+
+open AddChar MulChar in
+/-- If `χ` and `φ` are multiplicative characters on a finite field `F` with values in another
+field `F'` such that `χ`, `φ` and `χφ` are all nontrivial and `char F' ≠ char F`, then
+`J(χ,φ) * J(χ⁻¹,φ⁻¹) = #F` (in `F'`). -/
+lemma jacobiSum_mul_jacobiSum_inv (h : ringChar F' ≠ ringChar F) {χ φ : MulChar F F'} (hχ : χ ≠ 1)
+ (hφ : φ ≠ 1) (hχφ : χ * φ ≠ 1) :
+ jacobiSum χ φ * jacobiSum χ⁻¹ φ⁻¹ = Fintype.card F := by
+ obtain ⟨n, hp, hc⟩ := FiniteField.card F (ringChar F)
+ let ψ := FiniteField.primitiveChar F F' h -- obtain primitive additive character `ψ : F → FF'`
+ let FF' := CyclotomicField ψ.n F' -- the target field of `ψ`
+ let χ' := χ.ringHomComp (algebraMap F' FF') -- consider `χ` and `φ` as characters `F → FF'`
+ let φ' := φ.ringHomComp (algebraMap F' FF')
+ have hinj := (algebraMap F' FF').injective
+ apply hinj
+ rw [map_mul, ← jacobiSum_ringHomComp, ← jacobiSum_ringHomComp]
+ have Hχφ : χ' * φ' ≠ 1 := by
+ rw [← ringHomComp_mul]
+ exact (MulChar.ringHomComp_ne_one_iff hinj).mpr hχφ
+ have Hχφ' : χ'⁻¹ * φ'⁻¹ ≠ 1 := by
+ rwa [← mul_inv, inv_ne_one]
+ have Hχ : χ' ≠ 1 := (MulChar.ringHomComp_ne_one_iff hinj).mpr hχ
+ have Hφ : φ' ≠ 1 := (MulChar.ringHomComp_ne_one_iff hinj).mpr hφ
+ have Hcard : (Fintype.card F : FF') ≠ 0 := by
+ intro H
+ simp only [hc, Nat.cast_pow, ne_eq, PNat.ne_zero, not_false_eq_true, pow_eq_zero_iff] at H
+ exact h <| (Algebra.ringChar_eq F' FF').trans <| CharP.ringChar_of_prime_eq_zero hp H
+ have H := (gaussSum_mul_gaussSum_eq_card Hχφ ψ.prim).trans_ne Hcard
+ apply_fun (gaussSum (χ' * φ') ψ.char * gaussSum (χ' * φ')⁻¹ ψ.char⁻¹ * ·)
+ using mul_right_injective₀ H
+ simp only
+ rw [mul_mul_mul_comm, jacobiSum_mul_nontrivial Hχφ, mul_inv, ← ringHomComp_inv,
+ ← ringHomComp_inv, jacobiSum_mul_nontrivial Hχφ', map_natCast, ← mul_mul_mul_comm,
+ gaussSum_mul_gaussSum_eq_card Hχ ψ.prim, gaussSum_mul_gaussSum_eq_card Hφ ψ.prim,
+ ← mul_inv, gaussSum_mul_gaussSum_eq_card Hχφ ψ.prim]
+
+end field_field
+
+section image
+
+variable {F R : Type*} [Fintype F] [Field F] [CommRing R] [IsDomain R]
+
+/-- If `χ` and `φ` are multiplicative characters on a finite field `F` satisfying `χ^n = φ^n = 1`
+and with values in an integral domain `R`, and `μ` is a primitive `n`th root of unity in `R`,
+then the Jacobi sum `J(χ,φ)` is in `ℤ[μ] ⊆ R`. -/
+lemma jacobiSum_mem_algebraAdjoin_of_pow_eq_one {n : ℕ} (hn : n ≠ 0) {χ φ : MulChar F R}
+ (hχ : χ ^ n = 1) (hφ : φ ^ n = 1) {μ : R} (hμ : IsPrimitiveRoot μ n) :
+ jacobiSum χ φ ∈ Algebra.adjoin ℤ {μ} :=
+ Subalgebra.sum_mem _ fun _ _ ↦ Subalgebra.mul_mem _
+ (MulChar.apply_mem_algebraAdjoin_of_pow_eq_one hn hχ hμ _)
+ (MulChar.apply_mem_algebraAdjoin_of_pow_eq_one hn hφ hμ _)
+
+open Algebra in
+private
+lemma MulChar.exists_apply_sub_one_eq_mul_sub_one {n : ℕ} (hn : n ≠ 0) {χ : MulChar F R} {μ : R}
+ (hχ : χ ^ n = 1) (hμ : IsPrimitiveRoot μ n) {x : F} (hx : x ≠ 0) :
+ ∃ z ∈ Algebra.adjoin ℤ {μ}, χ x - 1 = z * (μ - 1) := by
+ obtain ⟨k, _, hk⟩ := exists_apply_eq_pow hn hχ hμ hx
+ refine hk ▸ ⟨(Finset.range k).sum (μ ^ ·), ?_, (geom_sum_mul μ k).symm⟩
+ exact Subalgebra.sum_mem _ fun m _ ↦ Subalgebra.pow_mem _ (self_mem_adjoin_singleton _ μ) _
+
+private
+lemma MulChar.exists_apply_sub_one_mul_apply_sub_one {n : ℕ} (hn : n ≠ 0) {χ ψ : MulChar F R}
+ {μ : R} (hχ : χ ^ n = 1) (hψ : ψ ^ n = 1) (hμ : IsPrimitiveRoot μ n) (x : F) :
+ ∃ z ∈ Algebra.adjoin ℤ {μ}, (χ x - 1) * (ψ (1 - x) - 1) = z * (μ - 1) ^ 2 := by
+ rcases eq_or_ne x 0 with rfl | hx₀
+ · exact ⟨0, Subalgebra.zero_mem _, by rw [sub_zero, ψ.map_one, sub_self, mul_zero, zero_mul]⟩
+ rcases eq_or_ne x 1 with rfl | hx₁
+ · exact ⟨0, Subalgebra.zero_mem _, by rw [χ.map_one, sub_self, zero_mul, zero_mul]⟩
+ obtain ⟨z₁, hz₁, Hz₁⟩ := MulChar.exists_apply_sub_one_eq_mul_sub_one hn hχ hμ hx₀
+ obtain ⟨z₂, hz₂, Hz₂⟩ :=
+ MulChar.exists_apply_sub_one_eq_mul_sub_one hn hψ hμ (sub_ne_zero_of_ne hx₁.symm)
+ rewrite [Hz₁, Hz₂, sq]
+ exact ⟨z₁ * z₂, Subalgebra.mul_mem _ hz₁ hz₂, mul_mul_mul_comm ..⟩
+
+/-- 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 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) :
+ ∃ z ∈ Algebra.adjoin ℤ {μ}, jacobiSum χ ψ = -1 + z * (μ - 1) ^ 2 := by
+ obtain ⟨q, hq⟩ := hn'
+ rw [Nat.sub_eq_iff_eq_add NeZero.one_le] at hq
+ obtain ⟨z₁, hz₁, Hz₁⟩ := hμ.self_sub_one_pow_dvd_order hn
+ by_cases hχ₀ : χ = 1 <;> by_cases hψ₀ : ψ = 1
+ · rw [hχ₀, hψ₀, jacobiSum_one_one]
+ refine ⟨q * z₁, Subalgebra.mul_mem _ (Subalgebra.natCast_mem _ q) hz₁, ?_⟩
+ rw [hq, Nat.cast_add, Nat.cast_mul, Hz₁]
+ ring
+ · refine ⟨0, Subalgebra.zero_mem _, ?_⟩
+ rw [hχ₀, jacobiSum_one_nontrivial hψ₀, zero_mul, add_zero]
+ · refine ⟨0, Subalgebra.zero_mem _, ?_⟩
+ rw [jacobiSum_comm, hψ₀, jacobiSum_one_nontrivial hχ₀, zero_mul, add_zero]
+ · classical
+ rw [jacobiSum_eq_aux, MulChar.sum_eq_zero_of_ne_one hχ₀, MulChar.sum_eq_zero_of_ne_one hψ₀, hq]
+ have H := MulChar.exists_apply_sub_one_mul_apply_sub_one (by omega) hχ hψ hμ
+ have Hcs x := (H x).choose_spec
+ refine ⟨-q * z₁ + ∑ x ∈ (univ \ {0, 1} : Finset F), (H x).choose, ?_, ?_⟩
+ · refine Subalgebra.add_mem _ (Subalgebra.mul_mem _ (Subalgebra.neg_mem _ ?_) hz₁) ?_
+ · exact Subalgebra.natCast_mem ..
+ · exact Subalgebra.sum_mem _ fun x _ ↦ (Hcs x).1
+ · conv => enter [1, 2, 2, x]; rw [(Hcs x).2]
+ rw [← Finset.sum_mul, Nat.cast_add, Nat.cast_mul, Hz₁]
+ ring
+
+end image
+
+section GaussSum
+
+variable {F R : Type*} [Fintype F] [Field F] [CommRing R] [IsDomain R]
+
+lemma gaussSum_pow_eq_prod_jacobiSum_aux (χ : MulChar F R) (ψ : AddChar F R) {n : ℕ}
+ (hn₁ : 0 < n) (hn₂ : n < orderOf χ) :
+ gaussSum χ ψ ^ n = gaussSum (χ ^ n) ψ * ∏ j ∈ Ico 1 n, jacobiSum χ (χ ^ j) := by
+ induction n, hn₁ using Nat.le_induction with
+ | base => simp only [pow_one, le_refl, Ico_eq_empty_of_le, prod_empty, mul_one]
+ | succ n hn ih =>
+ specialize ih <| lt_trans (Nat.lt_succ_self n) hn₂
+ have gauss_rw : gaussSum (χ ^ n) ψ * gaussSum χ ψ =
+ jacobiSum χ (χ ^ n) * gaussSum (χ ^ (n + 1)) ψ := by
+ have hχn : χ * (χ ^ n) ≠ 1 :=
+ pow_succ' χ n ▸ pow_ne_one_of_lt_orderOf n.add_one_ne_zero hn₂
+ rw [mul_comm, ← jacobiSum_mul_nontrivial hχn, mul_comm, ← pow_succ']
+ apply_fun (· * gaussSum χ ψ) at ih
+ rw [mul_right_comm, ← pow_succ, gauss_rw] at ih
+ rw [ih, Finset.prod_Ico_succ_top hn, mul_rotate, mul_assoc]
+
+/-- If `χ` is a multiplicative character of order `n ≥ 2` on a finite field `F`,
+then `g(χ)^n = χ(-1) * #F * J(χ,χ) * J(χ,χ²) * ... * J(χ,χⁿ⁻²)`. -/
+theorem gaussSum_pow_eq_prod_jacobiSum {χ : MulChar F R} {ψ : AddChar F R} (hχ : 2 ≤ orderOf χ)
+ (hψ : ψ.IsPrimitive) :
+ gaussSum χ ψ ^ orderOf χ =
+ χ (-1) * Fintype.card F * ∏ i ∈ Ico 1 (orderOf χ - 1), jacobiSum χ (χ ^ i) := by
+ have := gaussSum_pow_eq_prod_jacobiSum_aux χ ψ (n := orderOf χ - 1) (by omega) (by omega)
+ apply_fun (gaussSum χ ψ * ·) at this
+ rw [← pow_succ', Nat.sub_one_add_one_eq_of_pos (by omega)] at this
+ have hχ₁ : χ ≠ 1 :=
+ fun h ↦ ((orderOf_one (G := MulChar F R) ▸ h ▸ hχ).trans_lt Nat.one_lt_two).false
+ rw [this, ← mul_assoc, gaussSum_mul_gaussSum_pow_orderOf_sub_one hχ₁ hψ]
+
+end GaussSum
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 9395e10f0cc6f..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₀
@@ -397,7 +397,7 @@ theorem differentiableAt_Λ {s : ℂ} (hs : s ≠ 0 ∨ P.f₀ = 0) (hs' : s ≠
DifferentiableAt ℂ P.Λ s := by
refine ((P.differentiable_Λ₀ s).sub ?_).sub ?_
· rcases hs with hs | hs
- · simpa only [one_div] using (differentiableAt_inv' hs).smul_const P.f₀
+ · simpa only [one_div] using (differentiableAt_inv hs).smul_const P.f₀
· simpa only [hs, smul_zero] using differentiableAt_const (0 : E)
· rcases hs' with hs' | hs'
· apply DifferentiableAt.smul_const
@@ -427,10 +427,8 @@ theorem functional_equation₀ (s : ℂ) : P.Λ₀ (P.k - s) = P.ε • P.symm.
/-- Functional equation formulated for `Λ`. -/
theorem functional_equation (s : ℂ) :
P.Λ (P.k - s) = P.ε • P.symm.Λ s := by
- have := P.functional_equation₀ s
- rw [P.Λ₀_eq, P.symm_Λ₀_eq, sub_sub_cancel] at this
- rwa [smul_add, smul_add, ← mul_smul, mul_one_div, ← mul_smul, ← mul_div_assoc,
- mul_inv_cancel₀ P.hε, add_assoc, add_comm (_ • _), add_assoc, add_left_inj] at this
+ linear_combination (norm := module) P.functional_equation₀ s - P.Λ₀_eq (P.k - s)
+ + congr(P.ε • $(P.symm_Λ₀_eq s)) + congr(($(mul_inv_cancel₀ P.hε) / ((P.k:ℂ) - s)) • P.f₀)
/-- The residue of `Λ` at `s = k` is equal to `ε • g₀`. -/
theorem Λ_residue_k :
@@ -444,8 +442,7 @@ theorem Λ_residue_k :
exact continuousAt_const.div continuousAt_id (ofReal_ne_zero.mpr P.hk.ne')
· refine (tendsto_const_nhds.mono_left nhdsWithin_le_nhds).congr' ?_
refine eventually_nhdsWithin_of_forall (fun s (hs : s ≠ P.k) ↦ ?_)
- simp_rw [← mul_smul]
- congr 1
+ match_scalars
field_simp [sub_ne_zero.mpr hs.symm]
ring
@@ -457,7 +454,7 @@ theorem Λ_residue_zero :
· exact (continuous_id.smul P.differentiable_Λ₀.continuous).tendsto _
· refine (tendsto_const_nhds.mono_left nhdsWithin_le_nhds).congr' ?_
refine eventually_nhdsWithin_of_forall (fun s (hs : s ≠ 0) ↦ ?_)
- simp_rw [← mul_smul]
+ match_scalars
field_simp [sub_ne_zero.mpr hs.symm]
· rw [show 𝓝 0 = 𝓝 ((0 : ℂ) • (P.ε / (P.k - 0 : ℂ)) • P.g₀) by rw [zero_smul]]
exact (continuousAt_id.smul ((continuousAt_const.div ((continuous_sub_left _).continuousAt)
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/Deriv.lean b/Mathlib/NumberTheory/LSeries/Deriv.lean
index d9a355faf2a9f..f8f5726a088aa 100644
--- a/Mathlib/NumberTheory/LSeries/Deriv.lean
+++ b/Mathlib/NumberTheory/LSeries/Deriv.lean
@@ -20,7 +20,7 @@ import Mathlib.Analysis.Complex.HalfPlane
* We prove similar results for iterated derivatives (`LSeries.iteratedDeriv`).
* We use this to show that `LSeries f` is holomorphic on the right half-plane of
- absolute convergence (`LSeries.analyticOn`).
+ absolute convergence (`LSeries.analyticOnNhd`).
## Implementation notes
@@ -151,6 +151,10 @@ lemma LSeries_differentiableOn (f : ℕ → ℂ) :
fun _ hz ↦ (LSeries_hasDerivAt hz).differentiableAt.differentiableWithinAt
/-- The L-series of `f` is holomorphic on its open half-plane of absolute convergence. -/
+lemma LSeries_analyticOnNhd (f : ℕ → ℂ) :
+ AnalyticOnNhd ℂ (LSeries f) {s | abscissaOfAbsConv f < s.re} :=
+ (LSeries_differentiableOn f).analyticOnNhd <| isOpen_re_gt_EReal _
+
lemma LSeries_analyticOn (f : ℕ → ℂ) :
AnalyticOn ℂ (LSeries f) {s | abscissaOfAbsConv f < s.re} :=
- (LSeries_differentiableOn f).analyticOn <| isOpen_re_gt_EReal _
+ (LSeries_analyticOnNhd f).analyticOn
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 d7727a8fcffd7..a7b7dd924fbf6 100644
--- a/Mathlib/NumberTheory/LSeries/ZMod.lean
+++ b/Mathlib/NumberTheory/LSeries/ZMod.lean
@@ -6,15 +6,16 @@ Authors: David Loeffler
import Mathlib.Analysis.Fourier.ZMod
import Mathlib.Analysis.NormedSpace.Connected
-import Mathlib.LinearAlgebra.Dimension.DivisionRing
import Mathlib.NumberTheory.LSeries.RiemannZeta
-import Mathlib.Topology.Algebra.Module.Cardinality
/-!
# L-series of functions on `ZMod N`
We show that if `N` is a positive integer and `Φ : ZMod N → ℂ`, then the L-series of `Φ` has
-analytic continuation (away from a pole at `s = 1` if `∑ j, Φ j ≠ 0`).
+analytic continuation (away from a pole at `s = 1` if `∑ j, Φ j ≠ 0`) and satisfies a functional
+equation. We also define completed L-functions (given by multiplying the naive L-function by a
+Gamma-factor), and prove analytic continuation and functional equations for these too, assuming `Φ`
+is either even or odd.
The most familiar case is when `Φ` is a Dirichlet character, but the results here are valid
for general functions; for the specific case of Dirichlet characters see
@@ -23,18 +24,38 @@ for general functions; for the specific case of Dirichlet characters see
## Main definitions
* `ZMod.LFunction Φ s`: the meromorphic continuation of the function `∑ n : ℕ, Φ n * n ^ (-s)`.
+* `ZMod.completedLFunction Φ s`: the completed L-function, which for *almost* all `s` is equal to
+ `LFunction Φ s` multiplied by an Archimedean Gamma-factor.
+
+Note that `ZMod.completedLFunction Φ s` is only mathematically well-defined if `Φ` is either even
+or odd. Here we extend it to all functions `Φ` by linearity (but the functional equation only holds
+if `Φ` is either even or odd).
## Main theorems
+Results for non-completed L-functions:
+
* `ZMod.LFunction_eq_LSeries`: if `1 < re s` then the `LFunction` coincides with the naive
`LSeries`.
* `ZMod.differentiableAt_LFunction`: `ZMod.LFunction Φ` is differentiable at `s ∈ ℂ` if either
`s ≠ 1` or `∑ j, Φ j = 0`.
* `ZMod.LFunction_one_sub`: the functional equation relating `LFunction Φ (1 - s)` to
`LFunction (𝓕 Φ) s`, where `𝓕` is the Fourier transform.
+
+Results for completed L-functions:
+
+* `ZMod.LFunction_eq_completed_div_gammaFactor_even` and
+ `LFunction_eq_completed_div_gammaFactor_odd`: we have
+ `LFunction Φ s = completedLFunction Φ s / Gammaℝ s` for `Φ` even, and
+ `LFunction Φ s = completedLFunction Φ s / Gammaℝ (s + 1)` for `Φ` odd. (We formulate it this way
+ around so it is still valid at the poles of the Gamma factor.)
+* `ZMod.differentiableAt_completedLFunction`: `ZMod.completedLFunction Φ` is differentiable at
+ `s ∈ ℂ`, unless `s = 1` and `∑ j, Φ j ≠ 0`, or `s = 0` and `Φ 0 ≠ 0`.
+* `ZMod.completedLFunction_one_sub_even` and `ZMod.completedLFunction_one_sub_odd`:
+ the functional equation relating `completedLFunction Φ (1 - s)` to `completedLFunction (𝓕 Φ) s`.
-/
-open HurwitzZeta Complex ZMod Finset Classical Topology Filter
+open HurwitzZeta Complex ZMod Finset Classical Topology Filter Set
open scoped Real
@@ -70,7 +91,7 @@ lemma LFunction_eq_LSeries (Φ : ZMod N → ℂ) {s : ℂ} (hs : 1 < re s) :
LFunction Φ s = LSeries (Φ ·) s := by
rw [LFunction, LSeries, mul_sum, Nat.sumByResidueClasses (LSeriesSummable_of_one_lt_re Φ hs) N]
congr 1 with j
- have : (j.val / N : ℝ) ∈ Set.Icc 0 1 := Set.mem_Icc.mpr ⟨by positivity,
+ have : (j.val / N : ℝ) ∈ Set.Icc 0 1 := mem_Icc.mpr ⟨by positivity,
(div_le_one (Nat.cast_pos.mpr <| NeZero.pos _)).mpr <| Nat.cast_le.mpr (val_lt j).le⟩
rw [toAddCircle_apply, ← (hasSum_hurwitzZeta_of_one_lt_re this hs).tsum_eq, ← mul_assoc,
← tsum_mul_left]
@@ -97,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 _ ↦
@@ -119,6 +140,24 @@ lemma LFunction_residue_one (Φ : ZMod N → ℂ) :
exact ((continuous_neg.const_cpow (Or.inl <| NeZero.ne _)).tendsto _).mono_left
nhdsWithin_le_nhds
+local notation "𝕖" => stdAddChar
+
+/--
+The `LFunction` of the function `x ↦ e (j * x)`, where `e : ZMod N → ℂ` is the standard additive
+character, agrees with `expZeta (j / N)` on `1 < re s`. Private since it is a stepping-stone to
+the more general result `LFunction_stdAddChar_eq_expZeta` below.
+-/
+private lemma LFunction_stdAddChar_eq_expZeta_of_one_lt_re (j : ZMod N) {s : ℂ} (hs : 1 < s.re) :
+ LFunction (fun k ↦ 𝕖 (j * k)) s = expZeta (ZMod.toAddCircle j) s := by
+ rw [toAddCircle_apply, ← (hasSum_expZeta_of_one_lt_re (j.val / N) hs).tsum_eq,
+ LFunction_eq_LSeries _ hs, LSeries]
+ congr 1 with n
+ rw [LSeries.term_of_ne_zero' (ne_zero_of_one_lt_re hs), ofReal_div, ofReal_natCast,
+ ofReal_natCast, mul_assoc, div_mul_eq_mul_div, stdAddChar_apply]
+ have := ZMod.toCircle_intCast (N := N) (j.val * n)
+ conv_rhs at this => rw [Int.cast_mul, Int.cast_natCast, Int.cast_natCast, mul_div_assoc]
+ rw [← this, Int.cast_mul, Int.cast_natCast, Int.cast_natCast, natCast_zmod_val]
+
/--
The `LFunction` of the function `x ↦ e (j * x)`, where `e : ZMod N → ℂ` is the standard additive
character, is `expZeta (j / N)`.
@@ -127,8 +166,8 @@ Note this is not at all obvious from the definitions, and we prove it by analyti
from the convergence range.
-/
lemma LFunction_stdAddChar_eq_expZeta (j : ZMod N) (s : ℂ) (hjs : j ≠ 0 ∨ s ≠ 1) :
- LFunction (fun k ↦ stdAddChar (j * k)) s = expZeta (ZMod.toAddCircle j) s := by
- let U := if j = 0 then {z : ℂ | z ≠ 1} else Set.univ -- region of analyticity of both functions
+ LFunction (fun k ↦ 𝕖 (j * k)) s = expZeta (ZMod.toAddCircle j) s := by
+ let U := if j = 0 then {z : ℂ | z ≠ 1} else univ -- region of analyticity of both functions
let V := {z : ℂ | 1 < re z} -- convergence region
have hUo : IsOpen U := by
by_cases h : j = 0
@@ -136,15 +175,15 @@ lemma LFunction_stdAddChar_eq_expZeta (j : ZMod N) (s : ℂ) (hjs : j ≠ 0 ∨
· simp only [h, ↓reduceIte, isOpen_univ, U]
let f := LFunction (fun k ↦ stdAddChar (j * k))
let g := expZeta (toAddCircle j)
- have hU {u} : u ∈ U ↔ u ≠ 1 ∨ j ≠ 0 := by simp only [Set.mem_ite_univ_right, U]; tauto
+ have hU {u} : u ∈ U ↔ u ≠ 1 ∨ j ≠ 0 := by simp only [mem_ite_univ_right, U]; tauto
-- hypotheses for uniqueness of analytic continuation
- have hf : AnalyticOn ℂ f U := by
- refine DifferentiableOn.analyticOn (fun u hu ↦ ?_) hUo
+ have hf : AnalyticOnNhd ℂ f U := by
+ refine DifferentiableOn.analyticOnNhd (fun u hu ↦ ?_) hUo
refine (differentiableAt_LFunction _ _ ((hU.mp hu).imp_right fun h ↦ ?_)).differentiableWithinAt
simp only [mul_comm j, AddChar.sum_mulShift _ (isPrimitive_stdAddChar _), h,
↓reduceIte, CharP.cast_eq_zero, or_true]
- have hg : AnalyticOn ℂ g U := by
- refine DifferentiableOn.analyticOn (fun u hu ↦ ?_) hUo
+ have hg : AnalyticOnNhd ℂ g U := by
+ refine DifferentiableOn.analyticOnNhd (fun u hu ↦ ?_) hUo
refine (differentiableAt_expZeta _ _ ((hU.mp hu).imp_right fun h ↦ ?_)).differentiableWithinAt
rwa [ne_eq, toAddCircle_eq_zero]
have hUc : IsPreconnected U := by
@@ -158,43 +197,331 @@ lemma LFunction_stdAddChar_eq_expZeta (j : ZMod N) (s : ℂ) (hjs : j ≠ 0 ∨
-- apply uniqueness result
refine hf.eqOn_of_preconnected_of_eventuallyEq hg hUc hUmem ?_ hUmem'
-- now remains to prove equality on `1 < re s`
- filter_upwards [hV] with z hz
- dsimp only [f, g]
- rw [toAddCircle_apply, ← (hasSum_expZeta_of_one_lt_re (j.val / N) hz).tsum_eq,
- LFunction_eq_LSeries _ hz, LSeries]
- congr 1 with n
- rw [LSeries.term_of_ne_zero' (ne_zero_of_one_lt_re hz), ofReal_div, ofReal_natCast,
- ofReal_natCast, mul_assoc, div_mul_eq_mul_div, stdAddChar_apply]
- have := ZMod.toCircle_intCast (N := N) (j.val * n)
- conv_rhs at this => rw [Int.cast_mul, Int.cast_natCast, Int.cast_natCast, mul_div_assoc]
- rw [← this, Int.cast_mul, Int.cast_natCast, Int.cast_natCast, natCast_zmod_val]
+ filter_upwards [hV] with z using LFunction_stdAddChar_eq_expZeta_of_one_lt_re _
/-- Explicit formula for the L-function of `𝓕 Φ`, where `𝓕` is the discrete Fourier transform. -/
-lemma LFunction_dft (Φ : ZMod N → ℂ) {s : ℂ} (hs : s ≠ 1) :
+lemma LFunction_dft (Φ : ZMod N → ℂ) {s : ℂ} (hs : Φ 0 = 0 ∨ s ≠ 1) :
LFunction (𝓕 Φ) s = ∑ j : ZMod N, Φ j * expZeta (toAddCircle (-j)) s := by
- simp only [← LFunction_stdAddChar_eq_expZeta _ _ (Or.inr hs), LFunction, mul_sum]
- rw [sum_comm, dft_def]
+ have (j : ZMod N) : Φ j * LFunction (fun k ↦ 𝕖 (-j * k)) s =
+ Φ j * expZeta (toAddCircle (-j)) s := by
+ by_cases h : -j ≠ 0 ∨ s ≠ 1
+ · rw [LFunction_stdAddChar_eq_expZeta _ _ h]
+ · simp only [neg_ne_zero, not_or, not_not] at h
+ rw [h.1, show Φ 0 = 0 by tauto, zero_mul, zero_mul]
+ simp only [LFunction, ← this, mul_sum]
+ rw [dft_def, sum_comm]
simp only [sum_mul, mul_sum, Circle.smul_def, smul_eq_mul, stdAddChar_apply, ← mul_assoc]
congr 1 with j
congr 1 with k
rw [mul_assoc (Φ _), mul_comm (Φ _), neg_mul]
/-- Functional equation for `ZMod` L-functions, in terms of discrete Fourier transform. -/
-theorem LFunction_one_sub (Φ : ZMod N → ℂ) {s : ℂ} (hs : ∀ (n : ℕ), s ≠ -↑n) (hs' : s ≠ 1) :
+theorem LFunction_one_sub (Φ : ZMod N → ℂ) {s : ℂ}
+ (hs : ∀ (n : ℕ), s ≠ -n) (hs' : Φ 0 = 0 ∨ s ≠ 1) :
LFunction Φ (1 - s) = N ^ (s - 1) * (2 * π) ^ (-s) * Gamma s *
(cexp (π * I * s / 2) * LFunction (𝓕 Φ) s
+ cexp (-π * I * s / 2) * LFunction (𝓕 fun x ↦ Φ (-x)) s) := by
rw [LFunction]
- simp only [hurwitzZeta_one_sub _ hs (Or.inr hs'), mul_assoc _ _ (Gamma s)]
+ have (j : ZMod N) : Φ j * hurwitzZeta (toAddCircle j) (1 - s) = Φ j *
+ ((2 * π) ^ (-s) * Gamma s * (cexp (-π * I * s / 2) *
+ expZeta (toAddCircle j) s + cexp (π * I * s / 2) * expZeta (-toAddCircle j) s)) := by
+ rcases eq_or_ne j 0 with rfl | hj
+ · rcases hs' with hΦ | hs'
+ · simp only [hΦ, zero_mul]
+ · rw [hurwitzZeta_one_sub _ hs (Or.inr hs')]
+ · rw [hurwitzZeta_one_sub _ hs (Or.inl <| toAddCircle_eq_zero.not.mpr hj)]
+ simp only [this, mul_assoc _ _ (Gamma s)]
-- get rid of Gamma terms and power of N
generalize (2 * π) ^ (-s) * Gamma s = C
simp_rw [← mul_assoc, mul_comm _ C, mul_assoc, ← mul_sum, ← mul_assoc, mul_comm _ C, mul_assoc,
neg_sub]
congr 2
-- now gather sum terms
- rw [LFunction_dft _ hs', LFunction_dft _ hs']
+ rw [LFunction_dft _ hs', LFunction_dft _ (hs'.imp_left <| by simp only [neg_zero, imp_self])]
conv_rhs => enter [2, 2]; rw [← (Equiv.neg _).sum_comp _ _ (by simp), Equiv.neg_apply]
simp_rw [neg_neg, mul_sum, ← sum_add_distrib, ← mul_assoc, mul_comm _ (Φ _), mul_assoc,
← mul_add, map_neg, add_comm]
+section signed
+
+variable {Φ : ZMod N → ℂ}
+
+lemma LFunction_def_even (hΦ : Φ.Even) (s : ℂ) :
+ LFunction Φ s = N ^ (-s) * ∑ j : ZMod N, Φ j * hurwitzZetaEven (toAddCircle j) s := by
+ simp only [LFunction, hurwitzZeta, mul_add (Φ _), sum_add_distrib]
+ congr 1
+ simp only [add_right_eq_self, ← neg_eq_self ℂ, ← sum_neg_distrib]
+ refine Fintype.sum_equiv (.neg _) _ _ fun i ↦ ?_
+ simp only [Equiv.neg_apply, hΦ i, map_neg, hurwitzZetaOdd_neg, mul_neg]
+
+lemma LFunction_def_odd (hΦ : Φ.Odd) (s : ℂ) :
+ LFunction Φ s = N ^ (-s) * ∑ j : ZMod N, Φ j * hurwitzZetaOdd (toAddCircle j) s := by
+ simp only [LFunction, hurwitzZeta, mul_add (Φ _), sum_add_distrib]
+ congr 1
+ simp only [add_left_eq_self, ← neg_eq_self ℂ, ← sum_neg_distrib]
+ refine Fintype.sum_equiv (.neg _) _ _ fun i ↦ ?_
+ simp only [Equiv.neg_apply, hΦ i, map_neg, hurwitzZetaEven_neg, neg_mul]
+
+/-- Explicit formula for `LFunction Φ 0` when `Φ` is even. -/
+@[simp] lemma LFunction_apply_zero_of_even (hΦ : Φ.Even) :
+ LFunction Φ 0 = -Φ 0 / 2 := by
+ simp only [LFunction_def_even hΦ, neg_zero, cpow_zero, hurwitzZetaEven_apply_zero,
+ toAddCircle_eq_zero, mul_ite, mul_div, mul_neg_one, mul_zero, sum_ite_eq', Finset.mem_univ,
+ ↓reduceIte, one_mul]
+
+/-- The L-function of an even function vanishes at negative even integers. -/
+@[simp] lemma LFunction_neg_two_mul_nat_add_one (hΦ : Φ.Even) (n : ℕ) :
+ LFunction Φ (-(2 * (n + 1))) = 0 := by
+ simp only [LFunction_def_even hΦ, hurwitzZetaEven_neg_two_mul_nat_add_one, mul_zero,
+ sum_const_zero, ← neg_mul]
+
+/-- The L-function of an odd function vanishes at negative odd integers. -/
+@[simp] lemma LFunction_neg_two_mul_nat_sub_one (hΦ : Φ.Odd) (n : ℕ) :
+ LFunction Φ (-(2 * n) - 1) = 0 := by
+ simp only [LFunction_def_odd hΦ, hurwitzZetaOdd_neg_two_mul_nat_sub_one, mul_zero, ← neg_mul,
+ sum_const_zero]
+
+/--
+The completed L-function of a function `Φ : ZMod N → ℂ`.
+
+This is only mathematically meaningful if `Φ` is either even, or odd; here we extend this to all `Φ`
+by linearity.
+-/
+noncomputable def completedLFunction (Φ : ZMod N → ℂ) (s : ℂ) : ℂ :=
+ N ^ (-s) * ∑ j, Φ j * completedHurwitzZetaEven (toAddCircle j) s
+ + N ^ (-s) * ∑ j, Φ j * completedHurwitzZetaOdd (toAddCircle j) 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
+ rw [completedLFunction, this, mul_zero, add_zero]
+ refine (hΦ.mul_odd fun j ↦ ?_).sum_eq_zero
+ rw [map_neg, completedHurwitzZetaOdd_neg]
+
+lemma completedLFunction_def_odd (hΦ : Φ.Odd) (s : ℂ) :
+ completedLFunction Φ s = N ^ (-s) * ∑ j, Φ j * completedHurwitzZetaOdd (toAddCircle j) s := by
+ suffices ∑ j, Φ j * completedHurwitzZetaEven (toAddCircle j) s = 0 by
+ rw [completedLFunction, this, mul_zero, zero_add]
+ refine (hΦ.mul_even fun j ↦ ?_).sum_eq_zero
+ rw [map_neg, completedHurwitzZetaEven_neg]
+
+/--
+The completed L-function of a function `ZMod 1 → ℂ` is a scalar multiple of the completed Riemann
+zeta function.
+-/
+lemma completedLFunction_modOne_eq (Φ : ZMod 1 → ℂ) (s : ℂ) :
+ completedLFunction Φ s = Φ 1 * completedRiemannZeta s := by
+ rw [completedLFunction_def_even (show Φ.Even from fun _ ↦ congr_arg Φ (Subsingleton.elim ..)),
+ Nat.cast_one, one_cpow, one_mul, ← singleton_eq_univ 0, sum_singleton, map_zero,
+ completedHurwitzZetaEven_zero, Subsingleton.elim 0 1]
+
+/--
+The completed L-function of a function `ZMod N → ℂ`, modified by adding multiples of `N ^ (-s) / s`
+and `N ^ (-s) / (1 - s)` to make it entire.
+-/
+noncomputable def completedLFunction₀ (Φ : ZMod N → ℂ) (s : ℂ) : ℂ :=
+ N ^ (-s) * ∑ j : ZMod N, Φ j * completedHurwitzZetaEven₀ (toAddCircle j) s
+ + N ^ (-s) * ∑ j : ZMod N, Φ j * completedHurwitzZetaOdd (toAddCircle j) s
+
+/-- The function `completedLFunction₀ Φ` is differentiable. -/
+lemma differentiable_completedLFunction₀ (Φ : ZMod N → ℂ) :
+ Differentiable ℂ (completedLFunction₀ Φ) := by
+ refine .add ?_ ?_ <;>
+ refine .mul (by fun_prop) (.sum fun i _ ↦ .const_mul ?_ _)
+ exacts [differentiable_completedHurwitzZetaEven₀ _, differentiable_completedHurwitzZetaOdd _]
+
+lemma completedLFunction_eq (Φ : ZMod N → ℂ) (s : ℂ) :
+ completedLFunction Φ s =
+ completedLFunction₀ Φ s - N ^ (-s) * Φ 0 / s - N ^ (-s) * (∑ j, Φ j) / (1 - s) := by
+ simp only [completedLFunction, completedHurwitzZetaEven_eq, toAddCircle_eq_zero, div_eq_mul_inv,
+ ite_mul, one_mul, zero_mul, mul_sub, mul_ite, mul_zero, sum_sub_distrib, Fintype.sum_ite_eq',
+ ← sum_mul, completedLFunction₀, mul_assoc]
+ abel
+
+/--
+The completed L-function of a function `ZMod N → ℂ` is differentiable, with the following
+exceptions: at `s = 1` if `∑ j, Φ j ≠ 0`; and at `s = 0` if `Φ 0 ≠ 0`.
+-/
+lemma differentiableAt_completedLFunction (Φ : ZMod N → ℂ) (s : ℂ) (hs₀ : s ≠ 0 ∨ Φ 0 = 0)
+ (hs₁ : s ≠ 1 ∨ ∑ j, Φ j = 0) : DifferentiableAt ℂ (completedLFunction Φ) s := by
+ simp only [funext (completedLFunction_eq Φ), mul_div_assoc]
+ -- We know `completedLFunction₀` is differentiable everywhere, so it suffices to show that the
+ -- correction terms from `completedLFunction_eq` are differentiable at `s`.
+ refine ((differentiable_completedLFunction₀ _ _).sub ?_).sub ?_
+ · -- term with `1 / s`
+ 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 .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]
+
+/--
+Special case of `differentiableAt_completedLFunction` asserting differentiability everywhere
+under suitable hypotheses.
+-/
+lemma differentiable_completedLFunction (hΦ₂ : Φ 0 = 0) (hΦ₃ : ∑ j, Φ j = 0) :
+ Differentiable ℂ (completedLFunction Φ) :=
+ fun s ↦ differentiableAt_completedLFunction Φ s (.inr hΦ₂) (.inr hΦ₃)
+
+/--
+Relation between the completed L-function and the usual one (even case).
+We state it this way around so it holds at the poles of the gamma factor as well
+(except at `s = 0`, where it is genuinely false if `N > 1` and `Φ 0 ≠ 0`).
+-/
+lemma LFunction_eq_completed_div_gammaFactor_even (hΦ : Φ.Even) (s : ℂ) (hs : s ≠ 0 ∨ Φ 0 = 0) :
+ LFunction Φ s = completedLFunction Φ s / Gammaℝ s := by
+ simp only [completedLFunction_def_even hΦ, LFunction_def_even hΦ, mul_div_assoc, sum_div]
+ congr 2 with i
+ rcases ne_or_eq i 0 with hi | rfl
+ · rw [hurwitzZetaEven_def_of_ne_or_ne (.inl (hi ∘ toAddCircle_eq_zero.mp))]
+ · rcases hs with hs | hΦ'
+ · rw [hurwitzZetaEven_def_of_ne_or_ne (.inr hs)]
+ · simp only [hΦ', map_zero, zero_mul]
+
+/--
+Relation between the completed L-function and the usual one (odd case).
+We state it this way around so it holds at the poles of the gamma factor as well.
+-/
+lemma LFunction_eq_completed_div_gammaFactor_odd (hΦ : Φ.Odd) (s : ℂ) :
+ LFunction Φ s = completedLFunction Φ s / Gammaℝ (s + 1) := by
+ simp only [LFunction_def_odd hΦ, completedLFunction_def_odd hΦ, hurwitzZetaOdd, mul_div_assoc,
+ sum_div]
+
+/--
+First form of functional equation for completed L-functions (even case).
+
+Private because it is superseded by `completedLFunction_one_sub_even` below, which is valid for a
+much wider range of `s`.
+-/
+private lemma completedLFunction_one_sub_of_one_lt_even (hΦ : Φ.Even) {s : ℂ} (hs : 1 < re s) :
+ completedLFunction Φ (1 - s) = N ^ (s - 1) * completedLFunction (𝓕 Φ) s := by
+ have hs₀ : s ≠ 0 := ne_zero_of_one_lt_re hs
+ have hs₁ : s ≠ 1 := (lt_irrefl _ <| one_re ▸ · ▸ hs)
+ -- strip down to the key equality:
+ suffices ∑ x, Φ x * completedCosZeta (toAddCircle x) s = completedLFunction (𝓕 Φ) s by
+ simp only [completedLFunction_def_even hΦ, neg_sub, completedHurwitzZetaEven_one_sub, this]
+ -- reduce to equality with un-completed L-functions:
+ suffices ∑ x, Φ x * cosZeta (toAddCircle x) s = LFunction (𝓕 Φ) s by
+ simpa only [cosZeta, Function.update_noteq hs₀, ← mul_div_assoc, ← sum_div,
+ LFunction_eq_completed_div_gammaFactor_even (dft_even_iff.mpr hΦ) _ (.inl hs₀),
+ div_left_inj' (Gammaℝ_ne_zero_of_re_pos (zero_lt_one.trans hs))]
+ -- expand out `LFunction (𝓕 Φ)` and use parity:
+ simp only [cosZeta_eq, ← mul_div_assoc _ _ (2 : ℂ), mul_add, ← sum_div, sum_add_distrib,
+ LFunction_dft Φ (.inr hs₁), map_neg, div_eq_iff (two_ne_zero' ℂ), mul_two, add_left_inj]
+ exact Fintype.sum_equiv (.neg _) _ _ (by simp [hΦ _])
+
+/--
+First form of functional equation for completed L-functions (odd case).
+
+Private because it is superseded by `completedLFunction_one_sub_odd` below, which is valid for a
+much wider range of `s`.
+-/
+private lemma completedLFunction_one_sub_of_one_lt_odd (hΦ : Φ.Odd) {s : ℂ} (hs : 1 < re s) :
+ completedLFunction Φ (1 - s) = N ^ (s - 1) * I * completedLFunction (𝓕 Φ) s := by
+ -- strip down to the key equality:
+ suffices ∑ x, Φ x * completedSinZeta (toAddCircle x) s = I * completedLFunction (𝓕 Φ) s by
+ simp only [completedLFunction_def_odd hΦ, neg_sub, completedHurwitzZetaOdd_one_sub, this,
+ mul_assoc]
+ -- reduce to equality with un-completed L-functions:
+ suffices ∑ x, Φ x * sinZeta (toAddCircle x) s = I * LFunction (𝓕 Φ) s by
+ have hs' : 0 < re (s + 1) := by simp only [add_re, one_re]; linarith
+ simpa only [sinZeta, ← mul_div_assoc, ← sum_div, div_left_inj' (Gammaℝ_ne_zero_of_re_pos hs'),
+ LFunction_eq_completed_div_gammaFactor_odd (dft_odd_iff.mpr hΦ)]
+ -- now calculate:
+ calc ∑ x, Φ x * sinZeta (toAddCircle x) s
+ _ = (∑ x, Φ x * expZeta (toAddCircle x) s) / (2 * I)
+ - (∑ x, Φ x * expZeta (toAddCircle (-x)) s) / (2 * I) := by
+ simp only [sinZeta_eq, ← mul_div_assoc, mul_sub, sub_div, sum_sub_distrib, sum_div, map_neg]
+ _ = (∑ x, Φ (-x) * expZeta (toAddCircle (-x)) s) / (_) - (_) := by
+ congrm ?_ / _ - _
+ exact (Fintype.sum_equiv (.neg _) _ _ fun x ↦ by rfl).symm
+ _ = -I⁻¹ * LFunction (𝓕 Φ) s := by
+ simp only [hΦ _, neg_mul, sum_neg_distrib, LFunction_dft Φ (.inl hΦ.map_zero)]
+ ring
+ _ = I * LFunction (𝓕 Φ) s := by rw [inv_I, neg_neg]
+
+/--
+Functional equation for completed L-functions (even case), valid at all points of differentiability.
+-/
+theorem completedLFunction_one_sub_even (hΦ : Φ.Even) (s : ℂ)
+ (hs₀ : s ≠ 0 ∨ ∑ j, Φ j = 0) (hs₁ : s ≠ 1 ∨ Φ 0 = 0) :
+ completedLFunction Φ (1 - s) = N ^ (s - 1) * completedLFunction (𝓕 Φ) s := by
+ -- We prove this using `AnalyticOnNhd.eqOn_of_preconnected_of_eventuallyEq`, so we need to
+ -- gather up the ingredients for this big theorem.
+ -- First set up some notations:
+ let F (t) := completedLFunction Φ (1 - t)
+ let G (t) := ↑N ^ (t - 1) * completedLFunction (𝓕 Φ) t
+ -- Set on which F, G are analytic:
+ let U := {t : ℂ | (t ≠ 0 ∨ ∑ j, Φ j = 0) ∧ (t ≠ 1 ∨ Φ 0 = 0)}
+ -- Properties of U:
+ have hsU : s ∈ U := ⟨hs₀, hs₁⟩
+ have h2U : 2 ∈ U := ⟨.inl two_ne_zero, .inl (OfNat.ofNat_ne_one _)⟩
+ have hUo : IsOpen U := (isOpen_compl_singleton.union isOpen_const).inter
+ (isOpen_compl_singleton.union isOpen_const)
+ have hUp : IsPreconnected U := by
+ -- need to write `U` as the complement of an obviously countable set
+ let Uc : Set ℂ := (if ∑ j, Φ j = 0 then ∅ else {0}) ∪ (if Φ 0 = 0 then ∅ else {1})
+ have : Uc.Countable := by
+ apply Countable.union <;>
+ split_ifs <;>
+ simp only [countable_singleton, countable_empty]
+ convert (this.isConnected_compl_of_one_lt_rank ?_).isPreconnected using 1
+ · ext x
+ by_cases h : Φ 0 = 0 <;>
+ by_cases h' : ∑ j, Φ j = 0 <;>
+ simp [U, Uc, h, h', and_comm]
+ · simp only [rank_real_complex, Nat.one_lt_ofNat]
+ -- Analyticity on U:
+ have hF : AnalyticOnNhd ℂ F U := by
+ refine DifferentiableOn.analyticOnNhd
+ (fun t ht ↦ DifferentiableAt.differentiableWithinAt ?_) hUo
+ refine (differentiableAt_completedLFunction Φ _ ?_ ?_).comp t (differentiableAt_id.const_sub 1)
+ exacts [ht.2.imp_left (sub_ne_zero.mpr ∘ Ne.symm), ht.1.imp_left sub_eq_self.not.mpr]
+ have hG : AnalyticOnNhd ℂ G U := by
+ refine DifferentiableOn.analyticOnNhd
+ (fun t ht ↦ DifferentiableAt.differentiableWithinAt ?_) hUo
+ apply ((differentiableAt_id.sub_const 1).const_cpow (.inl (NeZero.ne _))).mul
+ apply differentiableAt_completedLFunction _ _ (ht.1.imp_right fun h ↦ dft_apply_zero Φ ▸ h)
+ exact ht.2.imp_right (fun h ↦ by simp only [← dft_apply_zero, dft_dft, neg_zero, h, smul_zero])
+ -- set where we know equality
+ have hV : {z | 1 < re z} ∈ 𝓝 2 := (continuous_re.isOpen_preimage _ isOpen_Ioi).mem_nhds (by simp)
+ have hFG : F =ᶠ[𝓝 2] G := eventually_of_mem hV <| fun t ht ↦ by
+ simpa only [F, G, pow_zero, mul_one] using completedLFunction_one_sub_of_one_lt_even hΦ ht
+ -- now apply the big hammer to finish
+ exact hF.eqOn_of_preconnected_of_eventuallyEq hG hUp h2U hFG hsU
+
+/-- Functional equation for completed L-functions (odd case), valid for all `s`. -/
+theorem completedLFunction_one_sub_odd (hΦ : Φ.Odd) (s : ℂ) :
+ completedLFunction Φ (1 - s) = N ^ (s - 1) * I * completedLFunction (𝓕 Φ) s := by
+ -- This is much easier than the even case since both functions are entire.
+ -- First set up some notations:
+ let F (t) := completedLFunction Φ (1 - t)
+ let G (t) := ↑N ^ (t - 1) * I * completedLFunction (𝓕 Φ) t
+ -- check F, G globally differentiable
+ have hF : Differentiable ℂ F := (differentiable_completedLFunction hΦ.map_zero
+ hΦ.sum_eq_zero).comp (differentiable_id.const_sub 1)
+ have hG : Differentiable ℂ G := by
+ apply (((differentiable_id.sub_const 1).const_cpow (.inl (NeZero.ne _))).mul_const _).mul
+ rw [← dft_odd_iff] at hΦ
+ exact differentiable_completedLFunction hΦ.map_zero hΦ.sum_eq_zero
+ -- set where we know equality
+ have : {z | 1 < re z} ∈ 𝓝 2 := (continuous_re.isOpen_preimage _ isOpen_Ioi).mem_nhds (by simp)
+ have hFG : F =ᶠ[𝓝 2] G := by filter_upwards [this] with t ht
+ using completedLFunction_one_sub_of_one_lt_odd hΦ ht
+ -- now apply the big hammer to finish
+ rw [← analyticOnNhd_univ_iff_differentiable] at hF hG
+ exact congr_fun (hF.eq_of_eventuallyEq hG hFG) s
+
+end signed
+
end ZMod
diff --git a/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean b/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean
index cd03518fe7e21..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])
@@ -205,10 +201,10 @@ theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0
simpa [hq0] using congr_arg ((↑) : ℕ → ZMod p) (le_antisymm hpq hqp)
apply_fun ZMod.val at this
rw [val_cast_of_lt hxp, val_zero] at this
- simp only [this, nonpos_iff_eq_zero, mem_Ico, one_ne_zero, false_and_iff, mem_product] at hx
+ 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 74dce799b0ee1..f408526e3fb67 100644
--- a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean
+++ b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean
@@ -161,11 +161,9 @@ theorem eq_zero_iff_not_coprime {a : ℤ} {b : ℕ} [NeZero b] : J(a | b) = 0
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,
- and_assoc, 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
@@ -214,7 +212,7 @@ theorem sq_one' {a : ℤ} {b : ℕ} (h : a.gcd b = 1) : J(a ^ 2 | b) = 1 := by r
/-- The symbol `J(a | b)` depends only on `a` mod `b`. -/
theorem mod_left (a : ℤ) (b : ℕ) : J(a | b) = J(a % b | b) :=
congr_arg List.prod <|
- List.pmap_congr _
+ List.pmap_congr_left _
(by
-- Porting note: Lean does not synthesize the instance [Fact (Nat.Prime p)] automatically
-- (it is needed for `legendreSym.mod` on line 227). Thus, we name the hypothesis
@@ -309,7 +307,7 @@ theorem value_at (a : ℤ) {R : Type*} [CommSemiring R] (χ : R →* ℤ)
conv_rhs => rw [← prod_primeFactorsList hb.pos.ne', cast_list_prod, map_list_prod χ]
rw [jacobiSym, List.map_map, ← List.pmap_eq_map Nat.Prime _ _
fun _ => prime_of_mem_primeFactorsList]
- congr 1; apply List.pmap_congr
+ congr 1; apply List.pmap_congr_left
exact fun p h pp _ => hp p pp (hb.ne_two_of_dvd_nat <| dvd_of_mem_primeFactorsList h)
/-- If `b` is odd, then `J(-1 | b)` is given by `χ₄ b`. -/
@@ -554,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 4c18eb5f5ff10..b25bd5ca4f8ea 100644
--- a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean
+++ b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean
@@ -64,7 +64,7 @@ theorem quadraticCharFun_eq_zero_iff {a : F} : quadraticCharFun F a = 0 ↔ a =
simp only [quadraticCharFun]
by_cases ha : a = 0
· simp only [ha, if_true]
- · simp only [ha, if_false, iff_false_iff]
+ · simp only [ha, if_false]
split_ifs <;> simp only [neg_eq_zero, one_ne_zero, not_false_iff]
@[simp]
@@ -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,
@@ -247,7 +246,7 @@ theorem quadraticChar_card_sqrts (hF : ringChar F ≠ 2) (a : F) :
ext1
-- Porting note(https://github.com/leanprover-community/mathlib4/issues/5026):
-- added (Set.mem_toFinset), Set.mem_setOf
- simp only [(Set.mem_toFinset), Set.mem_setOf, not_mem_empty, iff_false_iff]
+ simp only [(Set.mem_toFinset), Set.mem_setOf, not_mem_empty, iff_false]
rw [isSquare_iff_exists_sq] at h
exact fun h' ↦ h ⟨_, h'.symm⟩
@@ -284,7 +283,7 @@ theorem quadraticChar_neg_one [DecidableEq F] (hF : ringChar F ≠ 2) :
theorem FiniteField.isSquare_neg_one_iff : IsSquare (-1 : F) ↔ Fintype.card F % 4 ≠ 3 := by
classical -- suggested by the linter (instead of `[DecidableEq F]`)
by_cases hF : ringChar F = 2
- · simp only [FiniteField.isSquare_of_char_two hF, Ne, true_iff_iff]
+ · simp only [FiniteField.isSquare_of_char_two hF, Ne, true_iff]
exact fun hf ↦
one_ne_zero <|
(Nat.odd_of_mod_four_eq_three hf).symm.trans <| FiniteField.even_card_of_char_two hF
diff --git a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/GaussSum.lean b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/GaussSum.lean
index 15a271ae8ab8f..b10a0d651815b 100644
--- a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/GaussSum.lean
+++ b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/GaussSum.lean
@@ -41,7 +41,7 @@ theorem FiniteField.isSquare_two_iff :
classical
by_cases hF : ringChar F = 2
· have h := FiniteField.even_card_of_char_two hF
- simp only [FiniteField.isSquare_of_char_two hF, true_iff_iff]
+ simp only [FiniteField.isSquare_of_char_two hF, true_iff]
omega
· have h := FiniteField.odd_card_of_char_ne_two hF
rw [← quadraticChar_one_iff_isSquare (Ring.two_ne_zero hF), quadraticChar_two hF,
@@ -60,7 +60,7 @@ theorem FiniteField.isSquare_neg_two_iff :
classical
by_cases hF : ringChar F = 2
· have h := FiniteField.even_card_of_char_two hF
- simp only [FiniteField.isSquare_of_char_two hF, true_iff_iff]
+ simp only [FiniteField.isSquare_of_char_two hF, true_iff]
omega
· have h := FiniteField.odd_card_of_char_ne_two hF
rw [← quadraticChar_one_iff_isSquare (neg_ne_zero.mpr (Ring.two_ne_zero hF)),
@@ -102,7 +102,7 @@ theorem FiniteField.isSquare_odd_prime_iff (hF : ringChar F ≠ 2) {p : ℕ} [Fa
classical
by_cases hFp : ringChar F = p
· rw [show (p : F) = 0 by rw [← hFp]; exact ringChar.Nat.cast_ringChar]
- simp only [isSquare_zero, Ne, true_iff_iff, map_mul]
+ simp only [isSquare_zero, Ne, true_iff, map_mul]
obtain ⟨n, _, hc⟩ := FiniteField.card F (ringChar F)
have hchar : ringChar F = ringChar (ZMod p) := by rw [hFp]; exact (ringChar_zmod_n p).symm
conv => enter [1, 1, 2]; rw [hc, Nat.cast_pow, map_pow, hchar, map_ringChar]
diff --git a/Mathlib/NumberTheory/Liouville/Basic.lean b/Mathlib/NumberTheory/Liouville/Basic.lean
index a9e820e8d2cad..04403810047a7 100644
--- a/Mathlib/NumberTheory/Liouville/Basic.lean
+++ b/Mathlib/NumberTheory/Liouville/Basic.lean
@@ -143,7 +143,7 @@ theorem exists_pos_real_of_irrational_root {α : ℝ} (ha : Irrational α) {f :
@exists_one_le_pow_mul_dist ℤ ℕ ℝ _ _ _ (fun y => fR.eval y) α ζ |fR.derivative.eval xm| ?_ z0
(fun y hy => ?_) fun z a hq => ?_
-- 1: the denominators are positive -- essentially by definition;
- · exact fun a => one_le_pow_of_one_le ((le_add_iff_nonneg_left 1).mpr a.cast_nonneg) _
+ · exact fun a => one_le_pow₀ ((le_add_iff_nonneg_left 1).mpr a.cast_nonneg)
-- 2: the polynomial `fR` is Lipschitz at `α` -- as its derivative continuous;
· rw [mul_comm]
rw [Real.closedBall_eq_Icc] at hy
@@ -191,11 +191,11 @@ protected theorem transcendental {x : ℝ} (lx : Liouville x) : Transcendental
-- recall, this is a proof by contradiction!
refine lt_irrefl ((b : ℝ) ^ f.natDegree * |x - ↑a / ↑b|) ?_
-- clear denominators at `a1`
- rw [lt_div_iff' (pow_pos b0 _), pow_add, mul_assoc] at a1
+ rw [lt_div_iff₀' (pow_pos b0 _), pow_add, mul_assoc] at a1
-- split the inequality via `1 / A`.
refine (?_ : (b : ℝ) ^ f.natDegree * |x - a / b| < 1 / A).trans_le ?_
-- This branch of the proof uses the Liouville condition and the Archimedean property
- · refine (lt_div_iff' hA).mpr ?_
+ · refine (lt_div_iff₀' hA).mpr ?_
refine lt_of_le_of_lt ?_ a1
gcongr
refine hn.le.trans ?_
diff --git a/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean b/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean
index 2a8dad8fad8f5..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]
@@ -145,7 +145,7 @@ theorem aux_calc (n : ℕ) {m : ℝ} (hm : 2 ≤ m) :
any_goals exact pow_pos (zero_lt_two.trans_le hm) _
-- `2 ≤ m ^ n!` is a consequence of monotonicity of exponentiation at `2 ≤ m`.
exact _root_.trans (_root_.trans hm (pow_one _).symm.le)
- (pow_right_mono (one_le_two.trans hm) n.factorial_pos)
+ (pow_right_mono₀ (one_le_two.trans hm) n.factorial_pos)
_ = 1 / (m ^ n !) ^ n := congr_arg (1 / ·) (pow_mul m n ! n)
/-- An upper estimate on the remainder. This estimate works with `m ∈ ℝ` satisfying `2 ≤ m` and is
@@ -183,7 +183,7 @@ theorem liouville_liouvilleNumber {m : ℕ} (hm : 2 ≤ m) : Liouville (liouvill
intro n
-- the first `n` terms sum to `p / m ^ k!`
rcases partialSum_eq_rat (zero_lt_two.trans_le hm) n with ⟨p, hp⟩
- refine ⟨p, m ^ n !, one_lt_pow mZ1 n.factorial_ne_zero, ?_⟩
+ refine ⟨p, m ^ n !, one_lt_pow₀ mZ1 n.factorial_ne_zero, ?_⟩
push_cast
rw [Nat.cast_pow] at hp
-- separate out the sum of the first `n` terms and the rest
diff --git a/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean b/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean
index 45980956c089e..12ed3466ca3dc 100644
--- a/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean
+++ b/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean
@@ -53,7 +53,7 @@ theorem liouvilleWith_one (x : ℝ) : LiouvilleWith 1 x := by
refine ((eventually_gt_atTop 0).mono fun n hn => ?_).frequently
have hn' : (0 : ℝ) < n := by simpa
have : x < ↑(⌊x * ↑n⌋ + 1) / ↑n := by
- rw [lt_div_iff hn', Int.cast_add, Int.cast_one]
+ rw [lt_div_iff₀ hn', Int.cast_add, Int.cast_one]
exact Int.lt_floor_add_one _
refine ⟨⌊x * n⌋ + 1, this.ne, ?_⟩
rw [abs_sub_comm, abs_of_pos (sub_pos.2 this), rpow_one, sub_lt_iff_lt_add',
@@ -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
@@ -100,7 +100,7 @@ theorem frequently_lt_rpow_neg (h : LiouvilleWith p x) (hlt : q < p) :
refine (this.and_frequently hC).mono ?_
rintro n ⟨hnC, hn, m, hne, hlt⟩
replace hn : (0 : ℝ) < n := Nat.cast_pos.2 hn
- refine ⟨m, hne, hlt.trans <| (div_lt_iff <| rpow_pos_of_pos hn _).2 ?_⟩
+ refine ⟨m, hne, hlt.trans <| (div_lt_iff₀ <| rpow_pos_of_pos hn _).2 ?_⟩
rwa [mul_comm, ← rpow_add hn, ← sub_eq_add_neg]
/-- The product of a Liouville number and a nonzero rational number is again a Liouville number. -/
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 4d72a848d850a..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) ?_
@@ -53,7 +53,7 @@ theorem setOf_liouville_eq_irrational_inter_iInter_iUnion :
theorem eventually_residual_liouville : ∀ᶠ x in residual ℝ, Liouville x := by
rw [Filter.Eventually, setOf_liouville_eq_irrational_inter_iInter_iUnion]
refine eventually_residual_irrational.and ?_
- refine residual_of_dense_Gδ ?_ (Rat.denseEmbedding_coe_real.dense.mono ?_)
+ refine residual_of_dense_Gδ ?_ (Rat.isDenseEmbedding_coe_real.dense.mono ?_)
· exact .iInter fun n => IsOpen.isGδ <|
isOpen_iUnion fun a => isOpen_iUnion fun b => isOpen_iUnion fun _hb => isOpen_ball
· rintro _ ⟨r, rfl⟩
diff --git a/Mathlib/NumberTheory/LucasLehmer.lean b/Mathlib/NumberTheory/LucasLehmer.lean
index b6ad0fed7b57e..7990d0b3b0785 100644
--- a/Mathlib/NumberTheory/LucasLehmer.lean
+++ b/Mathlib/NumberTheory/LucasLehmer.lean
@@ -1,16 +1,9 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Scott Morrison, Ainsley Pahljina
+Authors: Mario Carneiro, Kim Morrison, Ainsley Pahljina
-/
-import Mathlib.Algebra.Order.Ring.Abs
-import Mathlib.Algebra.Order.Ring.Basic
-import Mathlib.Algebra.Ring.Nat
-import Mathlib.Data.ZMod.Basic
-import Mathlib.GroupTheory.OrderOfElement
import Mathlib.RingTheory.Fintype
-import Mathlib.Tactic.IntervalCases
-import Mathlib.Tactic.Zify
/-!
# The Lucas-Lehmer test for Mersenne primes.
@@ -31,7 +24,7 @@ primes using `lucas_lehmer_sufficiency`.
## History
This development began as a student project by Ainsley Pahljina,
-and was then cleaned up for mathlib by Scott Morrison.
+and was then cleaned up for mathlib by Kim Morrison.
The tactic for certified computation of Lucas-Lehmer residues was provided by Mario Carneiro.
This tactic was ported by Thomas Murrills to Lean 4, and then it was converted to a `norm_num`
extension and made to use kernel reductions by Kyle Miller.
@@ -62,7 +55,7 @@ theorem mersenne_le_mersenne {p q : ℕ} : mersenne p ≤ mersenne q ↔ p ≤ q
@[simp] lemma mersenne_odd : ∀ {p : ℕ}, Odd (mersenne p) ↔ p ≠ 0
| 0 => by simp
| p + 1 => by
- simpa using Nat.Even.sub_odd (one_le_pow_of_one_le one_le_two _)
+ simpa using Nat.Even.sub_odd (one_le_pow₀ one_le_two)
(even_two.pow_of_ne_zero p.succ_ne_zero) odd_one
@[simp] theorem mersenne_pos {p : ℕ} : 0 < mersenne p ↔ 0 < p := mersenne_lt_mersenne (p := 0)
@@ -94,7 +87,7 @@ theorem one_lt_mersenne {p : ℕ} : 1 < mersenne p ↔ 1 < p :=
@[simp]
theorem succ_mersenne (k : ℕ) : mersenne k + 1 = 2 ^ k := by
rw [mersenne, tsub_add_cancel_of_le]
- exact one_le_pow_of_one_le (by norm_num) k
+ exact one_le_pow₀ (by norm_num)
namespace LucasLehmer
@@ -456,7 +449,8 @@ theorem order_ω (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) :
have ω_pow := orderOf_dvd_iff_pow_eq_one.1 o
replace ω_pow :=
congr_arg (Units.coeHom (X (q (p' + 2))) : Units (X (q (p' + 2))) → X (q (p' + 2))) ω_pow
- simp? at ω_pow says simp only [map_pow, Units.coeHom_apply, ωUnit_coe, map_one] at ω_pow
+ simp? at ω_pow says
+ simp only [Units.coeHom_apply, Units.val_pow_eq_pow_val, ωUnit_coe, Units.val_one] at ω_pow
have h : (1 : ZMod (q (p' + 2))) = -1 :=
congr_arg Prod.fst (ω_pow.symm.trans (ω_pow_eq_neg_one p' h))
haveI : Fact (2 < (q (p' + 2) : ℕ)) := ⟨two_lt_q _⟩
@@ -512,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
@@ -536,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 : ℕ} →
@@ -560,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 ac590aca60046..47887d769b36b 100644
--- a/Mathlib/NumberTheory/LucasPrimality.lean
+++ b/Mathlib/NumberTheory/LucasPrimality.lean
@@ -3,13 +3,10 @@ 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
/-!
-# The Lucas test for primes.
+# The Lucas test for primes
This file implements the Lucas test for primes (not to be confused with the Lucas-Lehmer test for
Mersenne primes). A number `a` witnesses that `n` is prime if `a` has order `n-1` in the
@@ -18,16 +15,13 @@ and `a^d ≠ 1 (mod n)` for any divisor `d | n - 1`. This test is the basis of t
certificate.
## TODO
-
-- Bonus: Show the reverse implication i.e. if a number is prime then it has a Lucas witness.
- Use `Units.IsCyclic` from `RingTheory/IntegralDomain` to show the group is cyclic.
- Write a tactic that uses this theorem to generate Pratt primality certificates
- Integrate Pratt primality certificates into the norm_num primality verifier
## Implementation notes
Note that the proof for `lucas_primality` relies on analyzing the multiplicative group
-modulo `p`. Despite this, the theorem still holds vacuously for `p = 0` and `p = 1`: In these
+modulo `p`. Despite this, the theorem still holds vacuously for `p = 0` and `p = 1`. In these
cases, we can take `q` to be any prime and see that `hd` does not hold, since `a^((p-1)/q)` reduces
to `1`.
-/
@@ -39,23 +33,37 @@ group must itself have order `p-1`, which only happens when `p` is prime.
-/
theorem lucas_primality (p : ℕ) (a : ZMod p) (ha : a ^ (p - 1) = 1)
(hd : ∀ q : ℕ, q.Prime → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1) : p.Prime := by
- have h0 : p ≠ 0 := by
- rintro ⟨⟩
- exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
- have h1 : p ≠ 1 := by
- rintro ⟨⟩
- exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
- have hp1 : 1 < p := lt_of_le_of_ne h0.bot_lt h1.symm
- have order_of_a : orderOf a = p - 1 := by
- apply orderOf_eq_of_pow_and_pow_div_prime _ ha hd
- exact tsub_pos_of_lt hp1
- haveI : NeZero p := ⟨h0⟩
+ have h : p ≠ 0 ∧ p ≠ 1 := by
+ constructor <;> rintro rfl <;> exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
+ have hp1 : 1 < p := Nat.one_lt_iff_ne_zero_and_ne_one.2 h
+ have : NeZero p := ⟨h.1⟩
rw [Nat.prime_iff_card_units]
- -- Prove cardinality of `Units` of `ZMod p` is both `≤ p-1` and `≥ p-1`
- refine le_antisymm (Nat.card_units_zmod_lt_sub_one hp1) ?_
- have hp' : p - 2 + 1 = p - 1 := tsub_add_eq_add_tsub hp1
- let a' : (ZMod p)ˣ := Units.mkOfMulEqOne a (a ^ (p - 2)) (by rw [← pow_succ', hp', ha])
- calc
- p - 1 = orderOf a := order_of_a.symm
- _ = orderOf a' := (orderOf_injective (Units.coeHom (ZMod p)) Units.ext a')
+ apply (Nat.card_units_zmod_lt_sub_one hp1).antisymm
+ let a' : (ZMod p)ˣ := Units.mkOfMulEqOne a _ (by rwa [← pow_succ', tsub_add_eq_add_tsub hp1])
+ calc p - 1 = orderOf a := (orderOf_eq_of_pow_and_pow_div_prime (tsub_pos_of_lt hp1) ha hd).symm
+ _ = orderOf a' := orderOf_injective (Units.coeHom _) Units.ext a'
_ ≤ Fintype.card (ZMod p)ˣ := orderOf_le_card_univ
+
+/-- If `p` is prime, then there exists an `a` such that `a^(p-1) = 1 mod p`
+and `a^((p-1)/q) ≠ 1 mod p` for all prime factors `q` of `p-1`.
+The multiplicative group mod `p` is cyclic, so `a` can be any generator of the group
+(which must have order `p-1`).
+-/
+theorem reverse_lucas_primality (p : ℕ) (hP : p.Prime) :
+ ∃ a : ZMod p, a ^ (p - 1) = 1 ∧ ∀ q : ℕ, q.Prime → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1 := by
+ have : Fact p.Prime := ⟨hP⟩
+ obtain ⟨g, hg⟩ := IsCyclic.exists_generator (α := (ZMod p)ˣ)
+ have h1 : orderOf g = p - 1 := by
+ rwa [orderOf_eq_card_of_forall_mem_zpowers hg, ← Nat.prime_iff_card_units]
+ have h2 := tsub_pos_iff_lt.2 hP.one_lt
+ rw [← orderOf_injective (Units.coeHom _) Units.ext _, orderOf_eq_iff h2] at h1
+ refine ⟨g, h1.1, fun q hq hqd ↦ ?_⟩
+ replace hq := hq.one_lt
+ exact h1.2 _ (Nat.div_lt_self h2 hq) (Nat.div_pos (Nat.le_of_dvd h2 hqd) (zero_lt_one.trans hq))
+
+/-- A number `p` is prime if and only if there exists an `a` such that
+`a^(p-1) = 1 mod p` and `a^((p-1)/q) ≠ 1 mod p` for all prime factors `q` of `p-1`.
+-/
+theorem lucas_primality_iff (p : ℕ) : p.Prime ↔
+ ∃ a : ZMod p, a ^ (p - 1) = 1 ∧ ∀ q : ℕ, q.Prime → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1 :=
+ ⟨reverse_lucas_primality p, fun ⟨a, ⟨ha, hb⟩⟩ ↦ lucas_primality p a ha hb⟩
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 812b9760b6b67..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,13 +352,13 @@ 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
have : z.im < z.im / normSq (z : ℂ) := by
have imz : 0 < z.im := im_pos z
- apply (lt_div_iff z.normSq_pos).mpr
+ apply (lt_div_iff₀ z.normSq_pos).mpr
nlinarith
convert this
simp only [ModularGroup.im_smul_eq_div_normSq]
@@ -380,7 +381,7 @@ scoped[Modular] notation "𝒟ᵒ" => ModularGroup.fdo
open scoped Modular
theorem abs_two_mul_re_lt_one_of_mem_fdo (h : z ∈ 𝒟ᵒ) : |2 * z.re| < 1 := by
- rw [abs_mul, abs_two, ← lt_div_iff' (zero_lt_two' ℝ)]
+ rw [abs_mul, abs_two, ← lt_div_iff₀' (zero_lt_two' ℝ)]
exact h.2
theorem three_lt_four_mul_im_sq_of_mem_fdo (h : z ∈ 𝒟ᵒ) : 3 < 4 * z.im ^ 2 := by
@@ -465,7 +466,7 @@ theorem abs_c_le_one (hz : z ∈ 𝒟ᵒ) (hg : g • z ∈ 𝒟ᵒ) : |(↑ₘg
(by linarith) (by linarith))
hc
have h₂ : (c * z.im) ^ 4 / normSq (denom (↑g) z) ^ 2 ≤ 1 :=
- div_le_one_of_le
+ div_le_one_of_le₀
(pow_four_le_pow_two_of_pow_two_le (UpperHalfPlane.c_mul_im_sq_le_normSq_denom z g))
(sq_nonneg _)
let nsq := normSq (denom g z)
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 7c8c94626c010..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
@@ -159,14 +160,14 @@ noncomputable def ofUnitHom (f : Rˣ →* R'ˣ) : MulChar R R' where
classical
intro x y
by_cases hx : IsUnit x
- · simp only [hx, IsUnit.mul_iff, true_and_iff, dif_pos]
+ · simp only [hx, IsUnit.mul_iff, true_and, dif_pos]
by_cases hy : IsUnit y
· simp only [hy, dif_pos]
have hm : (IsUnit.mul_iff.mpr ⟨hx, hy⟩).unit = hx.unit * hy.unit := Units.eq_iff.mp rfl
rw [hm, map_mul]
norm_cast
· simp only [hy, not_false_iff, dif_neg, mul_zero]
- · simp only [hx, IsUnit.mul_iff, false_and_iff, not_false_iff, dif_neg, zero_mul]
+ · simp only [hx, IsUnit.mul_iff, false_and, not_false_iff, dif_neg, zero_mul]
map_nonunit' := by
intro a ha
simp only [ha, not_false_iff, dif_neg]
@@ -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) :
@@ -577,7 +577,7 @@ theorem sum_one_eq_card_units [DecidableEq R] :
· exact map_nonunit _ h
· congr
ext a
- simp only [Finset.mem_filter, Finset.mem_univ, true_and_iff, Finset.mem_map,
+ simp only [Finset.mem_filter, Finset.mem_univ, true_and, Finset.mem_map,
Function.Embedding.coeFn_mk, exists_true_left, IsUnit]
end sum
diff --git a/Mathlib/NumberTheory/Multiplicity.lean b/Mathlib/NumberTheory/Multiplicity.lean
index dd1a44061a628..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,11 +387,11 @@ 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_iff]
+ · simp only [add_pos_iff, Nat.succ_pos', or_true]
· exact Nat.lt_add_left _ (pow_pos y.succ_pos _)
end padicValNat
diff --git a/Mathlib/NumberTheory/NumberField/Basic.lean b/Mathlib/NumberTheory/NumberField/Basic.lean
index fa4d279501117..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}
@@ -134,22 +151,55 @@ lemma mk_eq_mk (x y : K) (hx hy) : (⟨x, hx⟩ : 𝓞 K) = ⟨y, hy⟩ ↔ x =
@[simp] lemma neg_mk (x : K) (hx) : (-⟨x, hx⟩ : 𝓞 K) = ⟨-x, neg_mem hx⟩ :=
rfl
+/-- The ring homomorphism `(𝓞 K) →+* (𝓞 L)` given by restricting a ring homomorphism
+ `f : K →+* L` to `𝓞 K`. -/
+def mapRingHom {K L F : Type*} [Field K] [Field L] [FunLike F K L]
+ [RingHomClass F K L] (f : F) : (𝓞 K) →+* (𝓞 L) where
+ toFun k := ⟨f k.val, map_isIntegral_int f k.2⟩
+ map_zero' := by ext; simp only [map_mk, map_zero]
+ map_one' := by ext; simp only [map_mk, map_one]
+ map_add' x y:= by ext; simp only [map_mk, map_add]
+ map_mul' x y := by ext; simp only [map_mk, map_mul]
+
+/-- The ring isomorphsim `(𝓞 K) ≃+* (𝓞 L)` given by restricting
+ a ring isomorphsim `e : K ≃+* L` to `𝓞 K`. -/
+def mapRingEquiv {K L E : Type*} [Field K] [Field L] [EquivLike E K L]
+ [RingEquivClass E K L] (e : E) : (𝓞 K) ≃+* (𝓞 L) :=
+ RingEquiv.ofRingHom (mapRingHom e) (mapRingHom (e : K ≃+* L).symm)
+ (RingHom.ext fun x => ext (EquivLike.right_inv e x.1))
+ (RingHom.ext fun x => ext (EquivLike.left_inv e x.1))
+
end RingOfIntegers
/-- Given an algebra between two fields, create an algebra between their two rings of integers. -/
instance inst_ringOfIntegersAlgebra [Algebra K L] : Algebra (𝓞 K) (𝓞 L) :=
- RingHom.toAlgebra
- { toFun := fun k => ⟨algebraMap K L (algebraMap _ K k), IsIntegral.algebraMap k.2⟩
- map_zero' := by ext; simp only [RingOfIntegers.map_mk, map_zero]
- map_one' := by ext; simp only [RingOfIntegers.map_mk, map_one]
- map_add' := fun x y => by ext; simp only [RingOfIntegers.map_mk, map_add]
- map_mul' := fun x y => by ext; simp only [RingOfIntegers.map_mk, map_mul] }
+ (RingOfIntegers.mapRingHom (algebraMap K L)).toAlgebra
-- diamond at `reducible_and_instances` #10906
example : Algebra.id (𝓞 K) = inst_ringOfIntegersAlgebra K K := rfl
namespace RingOfIntegers
+/-- The algebra homomorphism `(𝓞 K) →ₐ[𝓞 k] (𝓞 L)` given by restricting a algebra homomorphism
+ `f : K →ₐ[k] L` to `𝓞 K`. -/
+def mapAlgHom {k K L F : Type*} [Field k] [Field K] [Field L] [Algebra k K]
+ [Algebra k L] [FunLike F K L] [AlgHomClass F k K L] (f : F) : (𝓞 K) →ₐ[𝓞 k] (𝓞 L) where
+ toRingHom := mapRingHom f
+ commutes' x := SetCoe.ext (AlgHomClass.commutes ((f : K →ₐ[k] L).restrictScalars (𝓞 k)) x)
+
+/-- The isomorphism of algebras `(𝓞 K) ≃ₐ[𝓞 k] (𝓞 L)` given by restricting
+ an isomorphism of algebras `e : K ≃ₐ[k] L` to `𝓞 K`. -/
+def mapAlgEquiv {k K L E : Type*} [Field k] [Field K] [Field L] [Algebra k K]
+ [Algebra k L] [EquivLike E K L] [AlgEquivClass E k K L] (e : E) : (𝓞 K) ≃ₐ[𝓞 k] (𝓞 L) :=
+ AlgEquiv.ofAlgHom (mapAlgHom e) (mapAlgHom (e : K ≃ₐ[k] L).symm)
+ (AlgHom.ext fun x => ext (EquivLike.right_inv e x.1))
+ (AlgHom.ext fun x => ext (EquivLike.left_inv e x.1))
+
+instance inst_isScalarTower (k K L : Type*) [Field k] [Field K] [Field L]
+ [Algebra k K] [Algebra k L] [Algebra K L] [IsScalarTower k K L] :
+ IsScalarTower (𝓞 k) (𝓞 K) (𝓞 L) :=
+ IsScalarTower.of_algHom (mapAlgHom (IsScalarTower.toAlgHom k K L))
+
variable {K}
/-- The canonical map from `𝓞 K` to `K` is injective.
@@ -189,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 ℚ
@@ -250,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]
@@ -274,7 +369,7 @@ theorem mem_span_integralBasis {x : K} :
rw [integralBasis, Basis.localizationLocalization_span, LinearMap.mem_range,
IsScalarTower.coe_toAlgHom', RingHom.mem_range]
-theorem RingOfIntegers.rank : FiniteDimensional.finrank ℤ (𝓞 K) = FiniteDimensional.finrank ℚ K :=
+theorem RingOfIntegers.rank : Module.finrank ℤ (𝓞 K) = Module.finrank ℚ K :=
IsIntegralClosure.rank ℤ ℚ K (𝓞 K)
end NumberField
diff --git a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean
index 1c80c91f8424e..2254a38cd75ae 100644
--- a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean
+++ b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean
@@ -4,8 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Xavier Roblot
-/
import Mathlib.Algebra.Module.ZLattice.Basic
-import Mathlib.NumberTheory.NumberField.Embeddings
+import Mathlib.MeasureTheory.Measure.Haar.Unique
import Mathlib.NumberTheory.NumberField.FractionalIdeal
+import Mathlib.NumberTheory.NumberField.Units.Basic
/-!
# Canonical embedding of a number field
@@ -24,11 +25,11 @@ sending `x : K` to the vector `(φ x)` indexed by `φ : K →+* ℂ`.
image of the ring of integers by the canonical embedding and any ball centered at `0` of finite
radius is finite.
-* `NumberField.mixedEmbedding`: the ring homomorphism from `K →+* ({ w // IsReal w } → ℝ) ×
-({ w // IsComplex w } → ℂ)` that sends `x ∈ K` to `(φ_w x)_w` where `φ_w` is the embedding
-associated to the infinite place `w`. In particular, if `w` is real then `φ_w : K →+* ℝ` and, if
-`w` is complex, `φ_w` is an arbitrary choice between the two complex embeddings defining the place
-`w`.
+* `NumberField.mixedEmbedding`: the ring homomorphism from `K` to the mixed space
+`K →+* ({ w // IsReal w } → ℝ) × ({ w // IsComplex w } → ℂ)` that sends `x ∈ K` to `(φ_w x)_w`
+where `φ_w` is the embedding associated to the infinite place `w`. In particular, if `w` is real
+then `φ_w : K →+* ℝ` and, if `w` is complex, `φ_w` is an arbitrary choice between the two complex
+embeddings defining the place `w`.
## Tags
@@ -39,8 +40,6 @@ variable (K : Type*) [Field K]
namespace NumberField.canonicalEmbedding
---open NumberField
-
/-- The canonical embedding of a number field `K` of degree `n` into `ℂ^n`. -/
def _root_.NumberField.canonicalEmbedding : K →+* ((K →+* ℂ) → ℂ) := Pi.ringHom fun φ => φ
@@ -59,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]
@@ -102,7 +101,7 @@ theorem integerLattice.inter_ball_finite [NumberField K] (r : ℝ) :
· rintro ⟨x, ⟨hx1, hx2⟩, rfl⟩
exact ⟨⟨x, ⟨⟨x, hx1⟩, rfl⟩, rfl⟩, (heq x).mpr hx2⟩
-open Module Fintype FiniteDimensional
+open Module Fintype Module
/-- A `ℂ`-basis of `ℂ^n` that is also a `ℤ`-basis of the `integerLattice`. -/
noncomputable def latticeBasis [NumberField K] :
@@ -139,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) =
@@ -178,18 +177,28 @@ end NumberField.canonicalEmbedding
namespace NumberField.mixedEmbedding
-open NumberField.InfinitePlace FiniteDimensional Finset
+open NumberField.InfinitePlace Module Finset
-/-- The space `ℝ^r₁ × ℂ^r₂` with `(r₁, r₂)` the signature of `K`. -/
-local notation "E" K =>
+/-- The mixed space `ℝ^r₁ × ℂ^r₂` with `(r₁, r₂)` the signature of `K`. -/
+abbrev mixedSpace :=
({w : InfinitePlace K // IsReal w} → ℝ) × ({w : InfinitePlace K // IsComplex w} → ℂ)
-/-- The mixed embedding of a number field `K` of signature `(r₁, r₂)` into `ℝ^r₁ × ℂ^r₂`. -/
-noncomputable def _root_.NumberField.mixedEmbedding : K →+* (E K) :=
+/-- The mixed embedding of a number field `K` into the mixed space of `K`. -/
+noncomputable def _root_.NumberField.mixedEmbedding : K →+* (mixedSpace K) :=
RingHom.prod (Pi.ringHom fun w => embedding_of_isReal w.prop)
(Pi.ringHom fun w => w.val.embedding)
-instance [NumberField K] : Nontrivial (E K) := by
+@[simp]
+theorem mixedEmbedding_apply_ofIsReal (x : K) (w : {w // IsReal w}) :
+ (mixedEmbedding K x).1 w = embedding_of_isReal w.prop x := by
+ simp_rw [mixedEmbedding, RingHom.prod_apply, Pi.ringHom_apply]
+
+@[simp]
+theorem mixedEmbedding_apply_ofIsComplex (x : K) (w : {w // IsComplex w}) :
+ (mixedEmbedding K x).2 w = w.val.embedding x := by
+ simp_rw [mixedEmbedding, RingHom.prod_apply, Pi.ringHom_apply]
+
+instance [NumberField K] : Nontrivial (mixedSpace K) := by
obtain ⟨w⟩ := (inferInstance : Nonempty (InfinitePlace K))
obtain hw | hw := w.isReal_or_isComplex
· have : Nonempty {w : InfinitePlace K // IsReal w} := ⟨⟨w, hw⟩⟩
@@ -197,10 +206,10 @@ instance [NumberField K] : Nontrivial (E K) := by
· have : Nonempty {w : InfinitePlace K // IsComplex w} := ⟨⟨w, hw⟩⟩
exact nontrivial_prod_right
-protected theorem finrank [NumberField K] : finrank ℝ (E K) = finrank ℚ 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 _)]
@@ -208,11 +217,44 @@ 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
`commMap_canonical_eq_mixed`. -/
-noncomputable def commMap : ((K →+* ℂ) → ℂ) →ₗ[ℝ] (E K) where
+noncomputable def commMap : ((K →+* ℂ) → ℂ) →ₗ[ℝ] (mixedSpace K) where
toFun := fun x => ⟨fun w => (x w.val.embedding).re, fun w => x w.val.embedding⟩
map_add' := by
simp only [Pi.add_apply, Complex.add_re, Prod.mk_add_mk, Prod.mk.injEq]
@@ -236,7 +278,7 @@ theorem commMap_canonical_eq_mixed (x : K) :
exact ⟨rfl, rfl⟩
/-- This is a technical result to ensure that the image of the `ℂ`-basis of `ℂ^n` defined in
-`canonicalEmbedding.latticeBasis` is a `ℝ`-basis of `ℝ^r₁ × ℂ^r₂`,
+`canonicalEmbedding.latticeBasis` is a `ℝ`-basis of the mixed space `ℝ^r₁ × ℂ^r₂`,
see `mixedEmbedding.latticeBasis`. -/
theorem disjoint_span_commMap_ker [NumberField K] :
Disjoint (Submodule.span ℝ (Set.range (canonicalEmbedding.latticeBasis K)))
@@ -270,30 +312,29 @@ open scoped Classical
variable {K}
-/-- The norm at the infinite place `w` of an element of
-`({w // IsReal w} → ℝ) × ({ w // IsComplex w } → ℂ)`. -/
-def normAtPlace (w : InfinitePlace K) : (E K) →*₀ ℝ where
+/-- The norm at the infinite place `w` of an element of the mixed space. --/
+def normAtPlace (w : InfinitePlace K) : (mixedSpace K) →*₀ ℝ where
toFun x := if hw : IsReal w then ‖x.1 ⟨w, hw⟩‖ else ‖x.2 ⟨w, not_isReal_iff_isComplex.mp hw⟩‖
map_zero' := by simp
map_one' := by simp
map_mul' x y := by split_ifs <;> simp
-theorem normAtPlace_nonneg (w : InfinitePlace K) (x : E K) :
+theorem normAtPlace_nonneg (w : InfinitePlace K) (x : mixedSpace K) :
0 ≤ normAtPlace w x := by
rw [normAtPlace, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk]
split_ifs <;> exact norm_nonneg _
-theorem normAtPlace_neg (w : InfinitePlace K) (x : E K) :
+theorem normAtPlace_neg (w : InfinitePlace K) (x : mixedSpace K) :
normAtPlace w (- x) = normAtPlace w x := by
rw [normAtPlace, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk]
split_ifs <;> simp
-theorem normAtPlace_add_le (w : InfinitePlace K) (x y : E K) :
+theorem normAtPlace_add_le (w : InfinitePlace K) (x y : mixedSpace K) :
normAtPlace w (x + y) ≤ normAtPlace w x + normAtPlace w y := by
rw [normAtPlace, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk]
split_ifs <;> exact norm_add_le _ _
-theorem normAtPlace_smul (w : InfinitePlace K) (x : E K) (c : ℝ) :
+theorem normAtPlace_smul (w : InfinitePlace K) (x : mixedSpace K) (c : ℝ) :
normAtPlace w (c • x) = |c| * normAtPlace w x := by
rw [normAtPlace, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk]
split_ifs
@@ -301,15 +342,15 @@ theorem normAtPlace_smul (w : InfinitePlace K) (x : E K) (c : ℝ) :
· rw [Prod.smul_snd, Pi.smul_apply, norm_smul, Real.norm_eq_abs, Complex.norm_eq_abs]
theorem normAtPlace_real (w : InfinitePlace K) (c : ℝ) :
- normAtPlace w ((fun _ ↦ c, fun _ ↦ c) : (E K)) = |c| := by
- rw [show ((fun _ ↦ c, fun _ ↦ c) : (E K)) = c • 1 by ext <;> simp, normAtPlace_smul, map_one,
- mul_one]
+ normAtPlace w ((fun _ ↦ c, fun _ ↦ c) : (mixedSpace K)) = |c| := by
+ rw [show ((fun _ ↦ c, fun _ ↦ c) : (mixedSpace K)) = c • 1 by ext <;> simp, normAtPlace_smul,
+ map_one, mul_one]
-theorem normAtPlace_apply_isReal {w : InfinitePlace K} (hw : IsReal w) (x : E K) :
+theorem normAtPlace_apply_isReal {w : InfinitePlace K} (hw : IsReal w) (x : mixedSpace K) :
normAtPlace w x = ‖x.1 ⟨w, hw⟩‖ := by
rw [normAtPlace, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk, dif_pos]
-theorem normAtPlace_apply_isComplex {w : InfinitePlace K} (hw : IsComplex w) (x : E K) :
+theorem normAtPlace_apply_isComplex {w : InfinitePlace K} (hw : IsComplex w) (x : mixedSpace K) :
normAtPlace w x = ‖x.2 ⟨w, hw⟩‖ := by
rw [normAtPlace, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk,
dif_neg (not_isReal_iff_isComplex.mpr hw)]
@@ -321,7 +362,7 @@ theorem normAtPlace_apply (w : InfinitePlace K) (x : K) :
RingHom.prod_apply, Pi.ringHom_apply, norm_embedding_of_isReal, norm_embedding_eq, dite_eq_ite,
ite_id]
-theorem normAtPlace_eq_zero {x : E K} :
+theorem forall_normAtPlace_eq_zero_iff {x : mixedSpace K} :
(∀ w, normAtPlace w x = 0) ↔ x = 0 := by
refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩
· ext w
@@ -329,9 +370,16 @@ theorem normAtPlace_eq_zero {x : E K} :
· exact norm_eq_zero'.mp (normAtPlace_apply_isComplex w.prop _ ▸ h w.1)
· simp_rw [h, map_zero, implies_true]
+@[deprecated (since := "2024-09-13")] alias normAtPlace_eq_zero := forall_normAtPlace_eq_zero_iff
+
+@[simp]
+theorem exists_normAtPlace_ne_zero_iff {x : mixedSpace K} :
+ (∃ w, normAtPlace w x ≠ 0) ↔ x ≠ 0 := by
+ rw [ne_eq, ← forall_normAtPlace_eq_zero_iff, not_forall]
+
variable [NumberField K]
-theorem nnnorm_eq_sup_normAtPlace (x : E K) :
+theorem nnnorm_eq_sup_normAtPlace (x : mixedSpace K) :
‖x‖₊ = univ.sup fun w ↦ ⟨normAtPlace w x, normAtPlace_nonneg w x⟩ := by
have :
(univ : Finset (InfinitePlace K)) =
@@ -346,7 +394,7 @@ theorem nnnorm_eq_sup_normAtPlace (x : E K) :
· ext w
simp [normAtPlace_apply_isComplex w.prop]
-theorem norm_eq_sup'_normAtPlace (x : E K) :
+theorem norm_eq_sup'_normAtPlace (x : mixedSpace K) :
‖x‖ = univ.sup' univ_nonempty fun w ↦ normAtPlace w x := by
rw [← coe_nnnorm, nnnorm_eq_sup_normAtPlace, ← sup'_eq_sup univ_nonempty, ← NNReal.val_eq_coe,
← OrderHom.Subtype.val_coe, map_finset_sup', OrderHom.Subtype.val_coe]
@@ -355,43 +403,53 @@ theorem norm_eq_sup'_normAtPlace (x : E K) :
/-- The norm of `x` is `∏ w, (normAtPlace x) ^ mult w`. It is defined such that the norm of
`mixedEmbedding K a` for `a : K` is equal to the absolute value of the norm of `a` over `ℚ`,
see `norm_eq_norm`. -/
-protected def norm : (E K) →*₀ ℝ where
+protected def norm : (mixedSpace K) →*₀ ℝ where
toFun x := ∏ w, (normAtPlace w x) ^ (mult w)
map_one' := by simp only [map_one, one_pow, prod_const_one]
map_zero' := by simp [mult]
map_mul' _ _ := by simp only [map_mul, mul_pow, prod_mul_distrib]
-protected theorem norm_apply (x : E K) :
+protected theorem norm_apply (x : mixedSpace K) :
mixedEmbedding.norm x = ∏ w, (normAtPlace w x) ^ (mult w) := rfl
-protected theorem norm_nonneg (x : E K) :
+protected theorem norm_nonneg (x : mixedSpace K) :
0 ≤ mixedEmbedding.norm x := univ.prod_nonneg fun _ _ ↦ pow_nonneg (normAtPlace_nonneg _ _) _
-protected theorem norm_eq_zero_iff {x : E K} :
+protected theorem norm_eq_zero_iff {x : mixedSpace K} :
mixedEmbedding.norm x = 0 ↔ ∃ w, normAtPlace w x = 0 := by
simp_rw [mixedEmbedding.norm, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk, prod_eq_zero_iff,
mem_univ, true_and, pow_eq_zero_iff mult_ne_zero]
-protected theorem norm_ne_zero_iff {x : E K} :
+protected theorem norm_ne_zero_iff {x : mixedSpace K} :
mixedEmbedding.norm x ≠ 0 ↔ ∀ w, normAtPlace w x ≠ 0 := by
rw [← not_iff_not]
simp_rw [ne_eq, mixedEmbedding.norm_eq_zero_iff, not_not, not_forall, not_not]
-theorem norm_smul (c : ℝ) (x : E K) :
+theorem norm_eq_of_normAtPlace_eq {x y : mixedSpace K}
+ (h : ∀ w, normAtPlace w x = normAtPlace w y) :
+ mixedEmbedding.norm x = mixedEmbedding.norm y := by
+ simp_rw [mixedEmbedding.norm_apply, h]
+
+theorem norm_smul (c : ℝ) (x : mixedSpace K) :
mixedEmbedding.norm (c • x) = |c| ^ finrank ℚ K * (mixedEmbedding.norm x) := by
simp_rw [mixedEmbedding.norm_apply, normAtPlace_smul, mul_pow, prod_mul_distrib,
prod_pow_eq_pow_sum, sum_mult_eq]
theorem norm_real (c : ℝ) :
- mixedEmbedding.norm ((fun _ ↦ c, fun _ ↦ c) : (E K)) = |c| ^ finrank ℚ K := by
- rw [show ((fun _ ↦ c, fun _ ↦ c) : (E K)) = c • 1 by ext <;> simp, norm_smul, map_one, mul_one]
+ mixedEmbedding.norm ((fun _ ↦ c, fun _ ↦ c) : (mixedSpace K)) = |c| ^ finrank ℚ K := by
+ rw [show ((fun _ ↦ c, fun _ ↦ c) : (mixedSpace K)) = c • 1 by ext <;> simp, norm_smul, map_one,
+ mul_one]
@[simp]
theorem norm_eq_norm (x : K) :
mixedEmbedding.norm (mixedEmbedding K x) = |Algebra.norm ℚ x| := by
simp_rw [mixedEmbedding.norm_apply, normAtPlace_apply, prod_eq_abs_norm]
-theorem norm_eq_zero_iff' {x : E K} (hx : x ∈ Set.range (mixedEmbedding K)) :
+theorem norm_unit (u : (𝓞 K)ˣ) :
+ mixedEmbedding.norm (mixedEmbedding K u) = 1 := by
+ rw [norm_eq_norm, Units.norm, Rat.cast_one]
+
+theorem norm_eq_zero_iff' {x : mixedSpace K} (hx : x ∈ Set.range (mixedEmbedding K)) :
mixedEmbedding.norm x = 0 ↔ x = 0 := by
obtain ⟨a, rfl⟩ := hx
rw [norm_eq_norm, Rat.cast_abs, abs_eq_zero, Rat.cast_eq_zero, Algebra.norm_eq_zero_iff,
@@ -410,25 +468,27 @@ variable [NumberField K]
/-- The type indexing the basis `stdBasis`. -/
abbrev index := {w : InfinitePlace K // IsReal w} ⊕ ({w : InfinitePlace K // IsComplex w}) × (Fin 2)
-/-- The `ℝ`-basis of `({w // IsReal w} → ℝ) × ({ w // IsComplex w } → ℂ)` formed by the vector
-equal to `1` at `w` and `0` elsewhere for `IsReal w` and by the couple of vectors equal to `1`
-(resp. `I`) at `w` and `0` elsewhere for `IsComplex w`. -/
-def stdBasis : Basis (index K) ℝ (E K) :=
+/-- The `ℝ`-basis of the mixed space of `K` formed by the vector equal to `1` at `w` and `0`
+elsewhere for `IsReal w` and by the couple of vectors equal to `1` (resp. `I`) at `w` and `0`
+elsewhere for `IsComplex w`. -/
+def stdBasis : Basis (index K) ℝ (mixedSpace K) :=
Basis.prod (Pi.basisFun ℝ _)
(Basis.reindex (Pi.basis fun _ => basisOneI) (Equiv.sigmaEquivProd _ _))
variable {K}
@[simp]
-theorem stdBasis_apply_ofIsReal (x : E K) (w : {w : InfinitePlace K // IsReal w}) :
+theorem stdBasis_apply_ofIsReal (x : mixedSpace K) (w : {w : InfinitePlace K // IsReal w}) :
(stdBasis K).repr x (Sum.inl w) = x.1 w := rfl
@[simp]
-theorem stdBasis_apply_ofIsComplex_fst (x : E K) (w : {w : InfinitePlace K // IsComplex w}) :
+theorem stdBasis_apply_ofIsComplex_fst (x : mixedSpace K)
+ (w : {w : InfinitePlace K // IsComplex w}) :
(stdBasis K).repr x (Sum.inr ⟨w, 0⟩) = (x.2 w).re := rfl
@[simp]
-theorem stdBasis_apply_ofIsComplex_snd (x : E K) (w : {w : InfinitePlace K // IsComplex w}) :
+theorem stdBasis_apply_ofIsComplex_snd (x : mixedSpace K)
+ (w : {w : InfinitePlace K // IsComplex w}) :
(stdBasis K).repr x (Sum.inr ⟨w, 1⟩) = (x.2 w).im := rfl
variable (K)
@@ -465,7 +525,7 @@ def indexEquiv : (index K) ≃ (K →+* ℂ) := by
· exact ⟨Sum.inr ⟨InfinitePlace.mkComplex ⟨φ, hφ⟩, 1⟩,
by simp [(embedding_mk_eq φ).resolve_left hw]⟩
· rw [Embeddings.card, ← mixedEmbedding.finrank K,
- ← FiniteDimensional.finrank_eq_card_basis (stdBasis K)]
+ ← Module.finrank_eq_card_basis (stdBasis K)]
variable {K}
@@ -491,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,
@@ -547,9 +607,13 @@ open Module.Free
open scoped nonZeroDivisors
-/-- A `ℝ`-basis of `ℝ^r₁ × ℂ^r₂` that is also a `ℤ`-basis of the image of `𝓞 K`. -/
+/-- The image of the ring of integers of `K` in the mixed space. -/
+protected abbrev integerLattice : Submodule ℤ (mixedSpace K) :=
+ LinearMap.range ((mixedEmbedding K).comp (algebraMap (𝓞 K) K)).toIntAlgHom.toLinearMap
+
+/-- A `ℝ`-basis of the mixed space that is also a `ℤ`-basis of the image of `𝓞 K`. -/
def latticeBasis :
- Basis (ChooseBasisIndex ℤ (𝓞 K)) ℝ (E K) := by
+ Basis (ChooseBasisIndex ℤ (𝓞 K)) ℝ (mixedSpace K) := by
classical
-- We construct an `ℝ`-linear independent family from the image of
-- `canonicalEmbedding.lattice_basis` by `commMap`
@@ -560,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 _)]
@@ -571,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 : (E 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))]
@@ -582,6 +646,27 @@ theorem mem_span_latticeBasis (x : (E K)) :
RingHom.mem_range, exists_exists_eq_and]
rfl
+theorem span_latticeBasis :
+ Submodule.span ℤ (Set.range (latticeBasis K)) = mixedEmbedding.integerLattice K :=
+ Submodule.ext_iff.mpr fun _ ↦ mem_span_latticeBasis K
+
+instance : DiscreteTopology (mixedEmbedding.integerLattice K) := by
+ classical
+ rw [← span_latticeBasis]
+ infer_instance
+
+open Classical in
+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]
@@ -608,11 +693,19 @@ 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
-`ℝ^r₁ × ℂ^r₂`. This is useful, in particular, to prove that the family obtained from
-the `ℤ`-basis of `I` is actually an `ℝ`-basis of `ℝ^r₁ × ℂ^r₂`, see
+the mixed space. This is useful, in particular, to prove that the family obtained from
+the `ℤ`-basis of `I` is actually an `ℝ`-basis of the mixed space, see
`fractionalIdealLatticeBasis`. -/
theorem det_basisOfFractionalIdeal_eq_norm
(e : (ChooseBasisIndex ℤ (𝓞 K)) ≃ (ChooseBasisIndex ℤ I)) :
@@ -628,10 +721,10 @@ theorem det_basisOfFractionalIdeal_eq_norm
simp_rw [RingHom.mapMatrix_apply, Matrix.map_apply, Basis.toMatrix_apply, Function.comp_apply]
exact latticeBasis_repr_apply K _ i
-/-- A `ℝ`-basis of `ℝ^r₁ × ℂ^r₂` that is also a `ℤ`-basis of the image of the fractional
+/-- A `ℝ`-basis of the mixed space of `K` that is also a `ℤ`-basis of the image of the fractional
ideal `I`. -/
def fractionalIdealLatticeBasis :
- Basis (ChooseBasisIndex ℤ I) ℝ (E K) := by
+ Basis (ChooseBasisIndex ℤ I) ℝ (mixedSpace K) := by
let e : (ChooseBasisIndex ℤ (𝓞 K)) ≃ (ChooseBasisIndex ℤ I) := by
refine Fintype.equivOfCardEq ?_
rw [← finrank_eq_card_chooseBasisIndex, ← finrank_eq_card_chooseBasisIndex,
@@ -650,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 : (E 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) =
@@ -662,6 +755,239 @@ theorem mem_span_fractionalIdealLatticeBasis (x : (E 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 8b696820ff219..ff9af2b825008 100644
--- a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/ConvexBody.lean
+++ b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/ConvexBody.lean
@@ -10,7 +10,7 @@ import Mathlib.NumberTheory.NumberField.CanonicalEmbedding.Basic
/-!
# Convex Bodies
-The file contains the definitions of several convex bodies lying in the space `ℝ^r₁ × ℂ^r₂`
+The file contains the definitions of several convex bodies lying in the mixed space `ℝ^r₁ × ℂ^r₂`
associated to a number field of signature `K` and proves several existence theorems by applying
*Minkowski Convex Body Theorem* to those.
@@ -40,11 +40,7 @@ variable (K : Type*) [Field K]
namespace NumberField.mixedEmbedding
-open NumberField NumberField.InfinitePlace FiniteDimensional
-
-/-- The space `ℝ^r₁ × ℂ^r₂` with `(r₁, r₂)` the signature of `K`. -/
-local notation "E" K =>
- ({w : InfinitePlace K // IsReal w} → ℝ) × ({w : InfinitePlace K // IsComplex w} → ℂ)
+open NumberField NumberField.InfinitePlace Module
section convexBodyLT
@@ -54,7 +50,7 @@ variable (f : InfinitePlace K → ℝ≥0)
/-- The convex body defined by `f`: the set of points `x : E` such that `‖x w‖ < f w` for all
infinite places `w`. -/
-abbrev convexBodyLT : Set (E K) :=
+abbrev convexBodyLT : Set (mixedSpace K) :=
(Set.univ.pi (fun w : { w : InfinitePlace K // IsReal w } => ball 0 (f w))) ×ˢ
(Set.univ.pi (fun w : { w : InfinitePlace K // IsComplex w } => ball 0 (f w)))
@@ -65,7 +61,7 @@ theorem convexBodyLT_mem {x : K} :
embedding_of_isReal_apply, Subtype.forall, ← forall₂_or_left, ← not_isReal_iff_isComplex, em,
forall_true_left, norm_embedding_eq]
-theorem convexBodyLT_neg_mem (x : E K) (hx : x ∈ (convexBodyLT K f)) :
+theorem convexBodyLT_neg_mem (x : mixedSpace K) (hx : x ∈ (convexBodyLT K f)) :
-x ∈ (convexBodyLT K f) := by
simp only [Set.mem_prod, Prod.fst_neg, Set.mem_pi, Set.mem_univ, Pi.neg_apply,
mem_ball_zero_iff, norm_neg, Real.norm_eq_abs, forall_true_left, Subtype.forall,
@@ -81,25 +77,15 @@ open scoped Classical
variable [NumberField K]
-instance : IsAddHaarMeasure (volume : Measure (E K)) := prod.instIsAddHaarMeasure volume volume
-
-instance : NoAtoms (volume : Measure (E 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)
theorem one_le_convexBodyLTFactor : 1 ≤ convexBodyLTFactor K :=
- one_le_mul (one_le_pow_of_one_le one_le_two _)
- (one_le_pow_of_one_le (le_trans one_le_two Real.two_le_pi) _)
+ one_le_mul (one_le_pow₀ one_le_two) (one_le_pow₀ (one_le_two.trans Real.two_le_pi))
/-- The volume of `(ConvexBodyLt K f)` where `convexBodyLT K f` is the set of points `x`
such that `‖x w‖ < f w` for all infinite places `w`. -/
@@ -109,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)) *
@@ -160,7 +146,7 @@ variable (f : InfinitePlace K → ℝ≥0) (w₀ : {w : InfinitePlace K // IsCom
needed to ensure the element constructed is not real, see for example
`exists_primitive_element_lt_of_isComplex`.
-/
-abbrev convexBodyLT' : Set (E K) :=
+abbrev convexBodyLT' : Set (mixedSpace K) :=
(Set.univ.pi (fun w : { w : InfinitePlace K // IsReal w } ↦ ball 0 (f w))) ×ˢ
(Set.univ.pi (fun w : { w : InfinitePlace K // IsComplex w } ↦
if w = w₀ then {x | |x.re| < 1 ∧ |x.im| < (f w : ℝ) ^ 2} else ball 0 (f w)))
@@ -187,7 +173,7 @@ theorem convexBodyLT'_mem {x : K} :
rw [mem_ball_zero_iff, norm_embedding_eq]
exact h₁ w h_ne
-theorem convexBodyLT'_neg_mem (x : E K) (hx : x ∈ convexBodyLT' K f w₀) :
+theorem convexBodyLT'_neg_mem (x : mixedSpace K) (hx : x ∈ convexBodyLT' K f w₀) :
-x ∈ convexBodyLT' K f w₀ := by
simp only [Set.mem_prod, Set.mem_pi, Set.mem_univ, mem_ball, dist_zero_right, Real.norm_eq_abs,
true_implies, Subtype.forall, Prod.fst_neg, Pi.neg_apply, norm_neg, Prod.snd_neg] at hx ⊢
@@ -210,14 +196,13 @@ 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)
theorem one_le_convexBodyLT'Factor : 1 ≤ convexBodyLT'Factor K :=
- one_le_mul (one_le_pow_of_one_le one_le_two _)
- (one_le_pow_of_one_le (le_trans one_le_two Real.two_le_pi) _)
+ one_le_mul (one_le_pow₀ one_le_two) (one_le_pow₀ (one_le_two.trans Real.two_le_pi))
theorem convexBodyLT'_volume :
volume (convexBodyLT' K f w₀) = convexBodyLT'Factor K * ∏ w, (f w) ^ (mult w) := by
@@ -244,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]
@@ -277,14 +262,14 @@ open scoped Real Classical NNReal
variable [NumberField K] (B : ℝ)
variable {K}
-/-- The function that sends `x : ({w // IsReal w} → ℝ) × ({w // IsComplex w} → ℂ)` to
- `∑ w, ‖x.1 w‖ + 2 * ∑ w, ‖x.2 w‖`. It defines a norm and it used to define `convexBodySum`. -/
-noncomputable abbrev convexBodySumFun (x : E K) : ℝ := ∑ w, mult w * normAtPlace w x
+/-- The function that sends `x : mixedSpace K` to `∑ w, ‖x.1 w‖ + 2 * ∑ w, ‖x.2 w‖`. It defines a
+norm and it used to define `convexBodySum`. -/
+noncomputable abbrev convexBodySumFun (x : mixedSpace K) : ℝ := ∑ w, mult w * normAtPlace w x
-theorem convexBodySumFun_apply (x : E K) :
+theorem convexBodySumFun_apply (x : mixedSpace K) :
convexBodySumFun x = ∑ w, mult w * normAtPlace w x := rfl
-theorem convexBodySumFun_apply' (x : E K) :
+theorem convexBodySumFun_apply' (x : mixedSpace K) :
convexBodySumFun x = ∑ w, ‖x.1 w‖ + 2 * ∑ w, ‖x.2 w‖ := by
simp_rw [convexBodySumFun_apply, ← Finset.sum_add_sum_compl {w | IsReal w}.toFinset,
Set.toFinset_setOf, Finset.compl_filter, not_isReal_iff_isComplex, ← Finset.subtype_univ,
@@ -296,35 +281,35 @@ theorem convexBodySumFun_apply' (x : E K) :
rw [mult, if_neg (not_isReal_iff_isComplex.mpr w.prop), normAtPlace_apply_isComplex,
Nat.cast_ofNat]
-theorem convexBodySumFun_nonneg (x : E K) :
+theorem convexBodySumFun_nonneg (x : mixedSpace K) :
0 ≤ convexBodySumFun x :=
Finset.sum_nonneg (fun _ _ => mul_nonneg (Nat.cast_pos.mpr mult_pos).le (normAtPlace_nonneg _ _))
-theorem convexBodySumFun_neg (x : E K) :
+theorem convexBodySumFun_neg (x : mixedSpace K) :
convexBodySumFun (- x) = convexBodySumFun x := by
simp_rw [convexBodySumFun, normAtPlace_neg]
-theorem convexBodySumFun_add_le (x y : E K) :
+theorem convexBodySumFun_add_le (x y : mixedSpace K) :
convexBodySumFun (x + y) ≤ convexBodySumFun x + convexBodySumFun y := by
simp_rw [convexBodySumFun, ← Finset.sum_add_distrib, ← mul_add]
exact Finset.sum_le_sum
fun _ _ ↦ mul_le_mul_of_nonneg_left (normAtPlace_add_le _ x y) (Nat.cast_pos.mpr mult_pos).le
-theorem convexBodySumFun_smul (c : ℝ) (x : E K) :
+theorem convexBodySumFun_smul (c : ℝ) (x : mixedSpace K) :
convexBodySumFun (c • x) = |c| * convexBodySumFun x := by
simp_rw [convexBodySumFun, normAtPlace_smul, ← mul_assoc, mul_comm, Finset.mul_sum, mul_assoc]
-theorem convexBodySumFun_eq_zero_iff (x : E K) :
+theorem convexBodySumFun_eq_zero_iff (x : mixedSpace K) :
convexBodySumFun x = 0 ↔ x = 0 := by
- rw [← normAtPlace_eq_zero, convexBodySumFun, Finset.sum_eq_zero_iff_of_nonneg fun _ _ =>
- mul_nonneg (Nat.cast_pos.mpr mult_pos).le (normAtPlace_nonneg _ _)]
+ rw [← forall_normAtPlace_eq_zero_iff, convexBodySumFun, Finset.sum_eq_zero_iff_of_nonneg
+ fun _ _ ↦ mul_nonneg (Nat.cast_pos.mpr mult_pos).le (normAtPlace_nonneg _ _)]
conv =>
enter [1, w, hw]
rw [mul_left_mem_nonZeroDivisors_eq_zero_iff
(mem_nonZeroDivisors_iff_ne_zero.mpr <| Nat.cast_ne_zero.mpr mult_ne_zero)]
simp_rw [Finset.mem_univ, true_implies]
-theorem norm_le_convexBodySumFun (x : E K) : ‖x‖ ≤ convexBodySumFun x := by
+theorem norm_le_convexBodySumFun (x : mixedSpace K) : ‖x‖ ≤ convexBodySumFun x := by
rw [norm_eq_sup'_normAtPlace]
refine (Finset.sup'_le_iff _ _).mpr fun w _ ↦ ?_
rw [convexBodySumFun_apply, ← Finset.univ.add_sum_erase _ (Finset.mem_univ w)]
@@ -336,16 +321,16 @@ theorem norm_le_convexBodySumFun (x : E K) : ‖x‖ ≤ convexBodySumFun x := b
variable (K)
theorem convexBodySumFun_continuous :
- Continuous (convexBodySumFun : (E K) → ℝ) := by
+ Continuous (convexBodySumFun : mixedSpace K → ℝ) := by
refine continuous_finset_sum Finset.univ fun w ↦ ?_
obtain hw | hw := isReal_or_isComplex w
all_goals
· simp only [normAtPlace_apply_isReal, normAtPlace_apply_isComplex, hw]
fun_prop
-/-- The convex body equal to the set of points `x : E` such that
+/-- The convex body equal to the set of points `x : mixedSpace K` such that
`∑ w real, ‖x w‖ + 2 * ∑ w complex, ‖x w‖ ≤ B`. -/
-abbrev convexBodySum : Set (E K) := { x | convexBodySumFun x ≤ B }
+abbrev convexBodySum : Set (mixedSpace K) := { x | convexBodySumFun x ≤ B }
theorem convexBodySum_volume_eq_zero_of_le_zero {B} (hB : B ≤ 0) :
volume (convexBodySum K B) = 0 := by
@@ -366,7 +351,7 @@ theorem convexBodySum_mem {x : K} :
simp_rw [Set.mem_setOf_eq, convexBodySumFun, normAtPlace_apply]
rfl
-theorem convexBodySum_neg_mem {x : E K} (hx : x ∈ (convexBodySum K B)) :
+theorem convexBodySum_neg_mem {x : mixedSpace K} (hx : x ∈ (convexBodySum K B)) :
-x ∈ (convexBodySum K B) := by
rw [Set.mem_setOf, convexBodySumFun_neg]
exact hx
@@ -391,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 _)
@@ -409,7 +394,7 @@ theorem convexBodySum_volume :
convert addHaar_smul volume B (convexBodySum K 1)
· simp_rw [← Set.preimage_smul_inv₀ (ne_of_gt hB), Set.preimage_setOf_eq, convexBodySumFun,
normAtPlace_smul, abs_inv, abs_eq_self.mpr (le_of_lt hB), ← mul_assoc, mul_comm, mul_assoc,
- ← Finset.mul_sum, inv_mul_le_iff hB, mul_one]
+ ← Finset.mul_sum, inv_mul_le_iff₀ hB, mul_one]
· rw [abs_pow, ofReal_pow (abs_nonneg _), abs_eq_self.mpr (le_of_lt hB),
mixedEmbedding.finrank]
· exact this.symm
@@ -417,14 +402,14 @@ theorem convexBodySum_volume :
convexBodySumFun_neg convexBodySumFun_add_le
(fun hx => (convexBodySumFun_eq_zero_iff _).mp hx)
(fun r x => le_of_eq (convexBodySumFun_smul r x))]
- rw [measure_lt_one_eq_integral_div_gamma (g := fun x : (E K) => convexBodySumFun x)
+ rw [measure_lt_one_eq_integral_div_gamma (g := fun x : (mixedSpace K) => convexBodySumFun x)
volume ((convexBodySumFun_eq_zero_iff 0).mpr rfl) convexBodySumFun_neg convexBodySumFun_add_le
(fun hx => (convexBodySumFun_eq_zero_iff _).mp hx)
(fun r x => le_of_eq (convexBodySumFun_smul r x)) zero_lt_one]
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 : E K, exp (-convexBodySumFun x) =
- (2 : ℝ) ^ NrRealPlaces K * (π / 2) ^ NrComplexPlaces K by
+ suffices ∫ x : mixedSpace K, exp (-convexBodySumFun x) =
+ (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
@@ -435,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]
@@ -456,7 +441,7 @@ end convexBodySum
section minkowski
open scoped Classical
-open MeasureTheory MeasureTheory.Measure FiniteDimensional ZSpan Real Submodule
+open MeasureTheory MeasureTheory.Measure Module ZSpan Real Submodule
open scoped ENNReal NNReal nonZeroDivisors IntermediateField
@@ -468,7 +453,8 @@ variable [NumberField K] (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ)
`NumberField.mixedEmbedding.volume_fundamentalDomain_latticeBasis` for the computation of
`volume (fundamentalDomain (idealLatticeBasis K))`. -/
noncomputable def minkowskiBound : ℝ≥0∞ :=
- volume (fundamentalDomain (fractionalIdealLatticeBasis K I)) * (2 : ℝ≥0∞) ^ (finrank ℝ (E K))
+ volume (fundamentalDomain (fractionalIdealLatticeBasis K I)) *
+ (2 : ℝ≥0∞) ^ (finrank ℝ (mixedSpace K))
theorem volume_fundamentalDomain_fractionalIdealLatticeBasis :
volume (fundamentalDomain (fractionalIdealLatticeBasis K I)) =
@@ -503,7 +489,7 @@ the computation of this volume), then there exists a nonzero algebraic number `a
that `w a < f w` for all infinite places `w`. -/
theorem exists_ne_zero_mem_ideal_lt (h : minkowskiBound K I < volume (convexBodyLT K f)) :
∃ a ∈ (I : FractionalIdeal (𝓞 K)⁰ K), a ≠ 0 ∧ ∀ w : InfinitePlace K, w a < f w := by
- have h_fund := ZSpan.isAddFundamentalDomain (fractionalIdealLatticeBasis K I) volume
+ have h_fund := ZSpan.isAddFundamentalDomain' (fractionalIdealLatticeBasis K I) volume
have : Countable (span ℤ (Set.range (fractionalIdealLatticeBasis K I))).toAddSubgroup := by
change Countable (span ℤ (Set.range (fractionalIdealLatticeBasis K I)))
infer_instance
@@ -519,7 +505,7 @@ theorem exists_ne_zero_mem_ideal_lt' (w₀ : {w : InfinitePlace K // IsComplex w
(h : minkowskiBound K I < volume (convexBodyLT' K f w₀)) :
∃ a ∈ (I : FractionalIdeal (𝓞 K)⁰ K), a ≠ 0 ∧ (∀ w : InfinitePlace K, w ≠ w₀ → w a < f w) ∧
|(w₀.val.embedding a).re| < 1 ∧ |(w₀.val.embedding a).im| < (f w₀ : ℝ) ^ 2 := by
- have h_fund := ZSpan.isAddFundamentalDomain (fractionalIdealLatticeBasis K I) volume
+ have h_fund := ZSpan.isAddFundamentalDomain' (fractionalIdealLatticeBasis K I) volume
have : Countable (span ℤ (Set.range (fractionalIdealLatticeBasis K I))).toAddSubgroup := by
change Countable (span ℤ (Set.range (fractionalIdealLatticeBasis K I)))
infer_instance
@@ -607,7 +593,7 @@ theorem exists_ne_zero_mem_ideal_of_norm_le {B : ℝ}
-- Some inequalities that will be useful later on
have h1 : 0 < (finrank ℚ K : ℝ)⁻¹ := inv_pos.mpr (Nat.cast_pos.mpr finrank_pos)
have h2 : 0 ≤ B / (finrank ℚ K) := div_nonneg hB (Nat.cast_nonneg _)
- have h_fund := ZSpan.isAddFundamentalDomain (fractionalIdealLatticeBasis K I) volume
+ have h_fund := ZSpan.isAddFundamentalDomain' (fractionalIdealLatticeBasis K I) volume
have : Countable (span ℤ (Set.range (fractionalIdealLatticeBasis K I))).toAddSubgroup := by
change Countable (span ℤ (Set.range (fractionalIdealLatticeBasis K I)))
infer_instance
diff --git a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/FundamentalCone.lean b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/FundamentalCone.lean
new file mode 100644
index 0000000000000..419b0f6e623c0
--- /dev/null
+++ b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/FundamentalCone.lean
@@ -0,0 +1,502 @@
+/-
+Copyright (c) 2024 Xavier Roblot. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Xavier Roblot
+-/
+import Mathlib.RingTheory.Ideal.IsPrincipal
+import Mathlib.NumberTheory.NumberField.Units.DirichletTheorem
+
+/-!
+# Fundamental Cone
+
+Let `K` be a number field of signature `(r₁, r₂)`. We define an action of the units `(𝓞 K)ˣ` on
+the mixed space `ℝ^r₁ × ℂ^r₂` via the `mixedEmbedding`. The fundamental cone is a cone in the
+mixed space that is a fundamental domain for the action of `(𝓞 K)ˣ` modulo torsion.
+
+## Main definitions and results
+
+* `NumberField.mixedEmbedding.unitSMul`: the action of `(𝓞 K)ˣ` on the mixed space defined, for
+`u : (𝓞 K)ˣ`, by multiplication component by component with `mixedEmbedding K u`.
+
+* `NumberField.mixedEmbedding.fundamentalCone`: a cone in the mixed space, ie. a subset stable
+by multiplication by a nonzero real number, see `smul_mem_of_mem`, that is also a fundamental
+domain for the action of `(𝓞 K)ˣ` modulo torsion, see `exists_unit_smul_mem` and
+`torsion_unit_smul_mem_of_mem`.
+
+* `NumberField.mixedEmbedding.fundamentalCone.integralPoint`: the subset of elements of the
+fundamental cone that are images of algebraic integers of `K`.
+
+* `NumberField.mixedEmbedding.fundamentalCone.integralPointEquiv`: the equivalence between
+`fundamentalCone.integralPoint K` and the principal nonzero ideals of `𝓞 K` times the
+torsion of `K`.
+
+* `NumberField.mixedEmbedding.fundamentalCone.card_isPrincipal_norm_eq_mul_torsion`: the number of
+principal nonzero ideals in `𝓞 K` of norm `n` multiplied by the order of the torsion of `K` is
+equal to the number of `fundamentalCone.integralPoint K` of norm `n`.
+
+## Tags
+
+number field, canonical embedding, units, principal ideals
+-/
+
+variable (K : Type*) [Field K]
+
+namespace NumberField.mixedEmbedding
+
+open NumberField NumberField.InfinitePlace
+
+noncomputable section UnitSMul
+
+/-- The action of `(𝓞 K)ˣ` on the mixed space `ℝ^r₁ × ℂ^r₂` defined, for `u : (𝓞 K)ˣ`, by
+multiplication component by component with `mixedEmbedding K u`. -/
+@[simps]
+instance unitSMul : SMul (𝓞 K)ˣ (mixedSpace K) where
+ smul u x := mixedEmbedding K u * x
+
+instance : MulAction (𝓞 K)ˣ (mixedSpace K) where
+ one_smul := fun _ ↦ by simp_rw [unitSMul_smul, Units.coe_one, map_one, one_mul]
+ mul_smul := fun _ _ _ ↦ by simp_rw [unitSMul_smul, Units.coe_mul, map_mul, mul_assoc]
+
+instance : SMulZeroClass (𝓞 K)ˣ (mixedSpace K) where
+ smul_zero := fun _ ↦ by simp_rw [unitSMul_smul, mul_zero]
+
+variable {K}
+
+theorem unit_smul_eq_zero (u : (𝓞 K)ˣ) (x : mixedSpace K) :
+ u • x = 0 ↔ x = 0 := by
+ refine ⟨fun h ↦ ?_, fun h ↦ by rw [h, smul_zero]⟩
+ contrapose! h
+ obtain ⟨w, h⟩ := exists_normAtPlace_ne_zero_iff.mpr h
+ refine exists_normAtPlace_ne_zero_iff.mp ⟨w, ?_⟩
+ rw [unitSMul_smul, map_mul]
+ exact mul_ne_zero (by simp) h
+
+variable [NumberField K]
+
+theorem unit_smul_eq_iff_mul_eq {x y : 𝓞 K} {u : (𝓞 K)ˣ} :
+ u • mixedEmbedding K x = mixedEmbedding K y ↔ u * x = y := by
+ rw [unitSMul_smul, ← map_mul, Function.Injective.eq_iff, ← RingOfIntegers.coe_eq_algebraMap,
+ ← map_mul, ← RingOfIntegers.ext_iff]
+ exact mixedEmbedding_injective K
+
+theorem norm_unit_smul (u : (𝓞 K)ˣ) (x : mixedSpace K) :
+ mixedEmbedding.norm (u • x) = mixedEmbedding.norm x := by
+ rw [unitSMul_smul, map_mul, norm_unit, one_mul]
+
+end UnitSMul
+
+noncomputable section logMap
+
+open NumberField.Units NumberField.Units.dirichletUnitTheorem Module
+
+variable [NumberField K] {K}
+
+open Classical in
+/-- The map from the mixed space to `{w : InfinitePlace K // w ≠ w₀} → ℝ` (with `w₀` the fixed
+place from the proof of Dirichlet Unit Theorem) defined in such way that: 1) it factors the map
+`logEmbedding`, see `logMap_eq_logEmbedding`; 2) it is constant on the sets
+`{c • x | c ∈ ℝ, c ≠ 0}` if `norm x ≠ 0`, see `logMap_real_smul`. -/
+def logMap (x : mixedSpace K) : {w : InfinitePlace K // w ≠ w₀} → ℝ := fun w ↦
+ mult w.val * (Real.log (normAtPlace w.val x) -
+ Real.log (mixedEmbedding.norm x) * (finrank ℚ K : ℝ)⁻¹)
+
+@[simp]
+theorem logMap_apply (x : mixedSpace K) (w : {w : InfinitePlace K // w ≠ w₀}) :
+ logMap x w = mult w.val * (Real.log (normAtPlace w.val x) -
+ Real.log (mixedEmbedding.norm x) * (finrank ℚ K : ℝ)⁻¹) := rfl
+
+@[simp]
+theorem logMap_zero : logMap (0 : mixedSpace K) = 0 := by
+ ext; simp
+
+@[simp]
+theorem logMap_one : logMap (1 : mixedSpace K) = 0 := by
+ ext; simp
+
+variable {x y : mixedSpace K}
+
+theorem logMap_mul (hx : mixedEmbedding.norm x ≠ 0) (hy : mixedEmbedding.norm y ≠ 0) :
+ logMap (x * y) = logMap x + logMap y := by
+ ext w
+ simp_rw [Pi.add_apply, logMap_apply]
+ rw [map_mul, map_mul, Real.log_mul, Real.log_mul hx hy, add_mul]
+ · ring
+ · exact mixedEmbedding.norm_ne_zero_iff.mp hx w
+ · exact mixedEmbedding.norm_ne_zero_iff.mp hy w
+
+theorem logMap_apply_of_norm_one (hx : mixedEmbedding.norm x = 1)
+ (w : {w : InfinitePlace K // w ≠ w₀}) :
+ logMap x w = mult w.val * Real.log (normAtPlace w x) := by
+ rw [logMap_apply, hx, Real.log_one, zero_mul, sub_zero]
+
+@[simp]
+theorem logMap_eq_logEmbedding (u : (𝓞 K)ˣ) :
+ logMap (mixedEmbedding K u) = logEmbedding K (Additive.ofMul u) := by
+ ext; simp
+
+theorem logMap_unit_smul (u : (𝓞 K)ˣ) (hx : mixedEmbedding.norm x ≠ 0) :
+ logMap (u • x) = logEmbedding K (Additive.ofMul u) + logMap x := by
+ rw [unitSMul_smul, logMap_mul (by rw [norm_unit]; norm_num) hx, logMap_eq_logEmbedding]
+
+variable (x) in
+theorem logMap_torsion_smul {ζ : (𝓞 K)ˣ} (hζ : ζ ∈ torsion K) :
+ logMap (ζ • x) = logMap x := by
+ ext
+ simp_rw [logMap_apply, unitSMul_smul, map_mul, norm_eq_norm, Units.norm, Rat.cast_one, one_mul,
+ normAtPlace_apply, (mem_torsion K).mp hζ, one_mul]
+
+theorem logMap_real (c : ℝ) :
+ logMap (c • (1 : mixedSpace K)) = 0 := by
+ ext
+ rw [logMap_apply, normAtPlace_smul, norm_smul, map_one, map_one, mul_one, mul_one, Real.log_pow,
+ mul_comm (finrank ℚ K : ℝ) _, mul_assoc, mul_inv_cancel₀ (Nat.cast_ne_zero.mpr finrank_pos.ne'),
+ mul_one, sub_self, mul_zero, Pi.zero_apply]
+
+theorem logMap_real_smul (hx : mixedEmbedding.norm x ≠ 0) {c : ℝ} (hc : c ≠ 0) :
+ logMap (c • x) = logMap x := by
+ have : mixedEmbedding.norm (c • (1 : mixedSpace K)) ≠ 0 := by
+ rw [norm_smul, map_one, mul_one]
+ exact pow_ne_zero _ (abs_ne_zero.mpr hc)
+ rw [← smul_one_mul, logMap_mul this hx, logMap_real, zero_add]
+
+theorem logMap_eq_of_normAtPlace_eq (h : ∀ w, normAtPlace w x = normAtPlace w y) :
+ logMap x = logMap y := by
+ ext
+ simp_rw [logMap_apply, h, norm_eq_of_normAtPlace_eq h]
+
+end logMap
+
+noncomputable section
+
+open NumberField.Units NumberField.Units.dirichletUnitTheorem
+
+variable [NumberField K]
+
+open Classical in
+/-- The fundamental cone is a cone in the mixed space, ie. a subset fixed by multiplication by
+a nonzero real number, see `smul_mem_of_mem`, that is also a fundamental domain for the action
+of `(𝓞 K)ˣ` modulo torsion, see `exists_unit_smul_mem` and `torsion_smul_mem_of_mem`. -/
+def fundamentalCone : Set (mixedSpace K) :=
+ logMap⁻¹' (ZSpan.fundamentalDomain ((basisUnitLattice K).ofZLatticeBasis ℝ _)) \
+ {x | mixedEmbedding.norm x = 0}
+
+namespace fundamentalCone
+
+variable {K} {x y : mixedSpace K} {c : ℝ}
+
+theorem norm_pos_of_mem (hx : x ∈ fundamentalCone K) :
+ 0 < mixedEmbedding.norm x :=
+ lt_of_le_of_ne (mixedEmbedding.norm_nonneg _) (Ne.symm hx.2)
+
+theorem normAtPlace_pos_of_mem (hx : x ∈ fundamentalCone K) (w : InfinitePlace K) :
+ 0 < normAtPlace w x :=
+ lt_of_le_of_ne (normAtPlace_nonneg _ _)
+ (mixedEmbedding.norm_ne_zero_iff.mp (norm_pos_of_mem hx).ne' w).symm
+
+theorem mem_of_normAtPlace_eq (hx : x ∈ fundamentalCone K)
+ (hy : ∀ w, normAtPlace w y = normAtPlace w x) :
+ y ∈ fundamentalCone K := by
+ refine ⟨?_, by simpa [norm_eq_of_normAtPlace_eq hy] using hx.2⟩
+ rw [Set.mem_preimage, logMap_eq_of_normAtPlace_eq hy]
+ exact hx.1
+
+theorem smul_mem_of_mem (hx : x ∈ fundamentalCone K) (hc : c ≠ 0) :
+ c • x ∈ fundamentalCone K := by
+ refine ⟨?_, ?_⟩
+ · rw [Set.mem_preimage, logMap_real_smul hx.2 hc]
+ exact hx.1
+ · rw [Set.mem_setOf_eq, mixedEmbedding.norm_smul, mul_eq_zero, not_or]
+ exact ⟨pow_ne_zero _ (abs_ne_zero.mpr hc), hx.2⟩
+
+theorem smul_mem_iff_mem (hc : c ≠ 0) :
+ c • x ∈ fundamentalCone K ↔ x ∈ fundamentalCone K := by
+ refine ⟨fun h ↦ ?_, fun h ↦ smul_mem_of_mem h hc⟩
+ convert smul_mem_of_mem h (inv_ne_zero hc)
+ rw [eq_inv_smul_iff₀ hc]
+
+theorem exists_unit_smul_mem (hx : mixedEmbedding.norm x ≠ 0) :
+ ∃ u : (𝓞 K)ˣ, u • x ∈ fundamentalCone K := by
+ classical
+ let B := (basisUnitLattice K).ofZLatticeBasis ℝ
+ rsuffices ⟨⟨_, ⟨u, _, rfl⟩⟩, hu⟩ : ∃ e : unitLattice K, e + logMap x ∈ ZSpan.fundamentalDomain B
+ · exact ⟨u, by rwa [Set.mem_preimage, logMap_unit_smul u hx], by simp [hx]⟩
+ · obtain ⟨⟨e, h₁⟩, h₂, -⟩ := ZSpan.exist_unique_vadd_mem_fundamentalDomain B (logMap x)
+ exact ⟨⟨e, by rwa [← Basis.ofZLatticeBasis_span ℝ (unitLattice K)]⟩, h₂⟩
+
+theorem torsion_smul_mem_of_mem (hx : x ∈ fundamentalCone K) {ζ : (𝓞 K)ˣ} (hζ : ζ ∈ torsion K) :
+ ζ • x ∈ fundamentalCone K := by
+ constructor
+ · rw [Set.mem_preimage, logMap_torsion_smul _ hζ]
+ exact hx.1
+ · rw [Set.mem_setOf_eq, unitSMul_smul, map_mul, norm_unit, one_mul]
+ exact hx.2
+
+theorem unit_smul_mem_iff_mem_torsion (hx : x ∈ fundamentalCone K) (u : (𝓞 K)ˣ) :
+ u • x ∈ fundamentalCone K ↔ u ∈ torsion K := by
+ classical
+ refine ⟨fun h ↦ ?_, fun h ↦ torsion_smul_mem_of_mem hx h⟩
+ rw [← logEmbedding_eq_zero_iff]
+ let B := (basisUnitLattice K).ofZLatticeBasis ℝ
+ refine (Subtype.mk_eq_mk (h := ?_) (h' := Submodule.zero_mem _)).mp <|
+ (ZSpan.exist_unique_vadd_mem_fundamentalDomain B (logMap x)).unique ?_ ?_
+ · rw [Basis.ofZLatticeBasis_span ℝ (unitLattice K)]
+ exact ⟨u, trivial, rfl⟩
+ · rw [AddSubmonoid.mk_vadd, vadd_eq_add, ← logMap_unit_smul _ hx.2]
+ exact h.1
+ · rw [AddSubmonoid.mk_vadd, vadd_eq_add, zero_add]
+ exact hx.1
+
+variable (K) in
+/-- The set of images by `mixedEmbedding` of algebraic integers of `K` contained in the
+fundamental cone. -/
+def integralPoint : Set (mixedSpace K) :=
+ fundamentalCone K ∩ mixedEmbedding.integerLattice K
+
+theorem mem_integralPoint {a : mixedSpace K} :
+ a ∈ integralPoint K ↔ a ∈ fundamentalCone K ∧ ∃ x : 𝓞 K, mixedEmbedding K x = a := by
+ simp only [integralPoint, Set.mem_inter_iff, SetLike.mem_coe, LinearMap.mem_range,
+ AlgHom.toLinearMap_apply, RingHom.toIntAlgHom_coe, RingHom.coe_comp, Function.comp_apply]
+
+/-- If `a` is an integral point, then there is a *unique* algebraic integer in `𝓞 K` such
+that `mixedEmbedding K x = a`. -/
+theorem exists_unique_preimage_of_integralPoint {a : mixedSpace K} (ha : a ∈ integralPoint K) :
+ ∃! x : 𝓞 K, mixedEmbedding K x = a := by
+ obtain ⟨_, ⟨x, rfl⟩⟩ := mem_integralPoint.mp ha
+ refine Function.Injective.existsUnique_of_mem_range ?_ (Set.mem_range_self x)
+ exact (mixedEmbedding_injective K).comp RingOfIntegers.coe_injective
+
+theorem integralPoint_ne_zero (a : integralPoint K) : (a : mixedSpace K) ≠ 0 := by
+ by_contra!
+ exact a.prop.1.2 (this.symm ▸ mixedEmbedding.norm.map_zero')
+
+open scoped nonZeroDivisors
+
+/-- For `a : fundamentalCone K`, the unique nonzero algebraic integer `x` such that its image by
+`mixedEmbedding` is equal to `a`. Note that we state the fact that `x ≠ 0` by saying that `x` is
+a nonzero divisors since we will use later on the isomorphism
+`Ideal.associatesNonZeroDivisorsEquivIsPrincipal`, see `integralPointEquiv`. -/
+def preimageOfIntegralPoint (a : integralPoint K) : (𝓞 K)⁰ :=
+ ⟨(mem_integralPoint.mp a.prop).2.choose, mem_nonZeroDivisors_of_ne_zero (by
+ simp_rw [ne_eq, ← RingOfIntegers.coe_injective.eq_iff, ← (mixedEmbedding_injective K).eq_iff,
+ map_zero, (mem_integralPoint.mp a.prop).2.choose_spec, integralPoint_ne_zero,
+ not_false_eq_true])⟩
+
+@[simp]
+theorem mixedEmbedding_preimageOfIntegralPoint (a : integralPoint K) :
+ mixedEmbedding K (preimageOfIntegralPoint a : 𝓞 K) = (a : mixedSpace K) := by
+ rw [preimageOfIntegralPoint, (mem_integralPoint.mp a.prop).2.choose_spec]
+
+theorem preimageOfIntegralPoint_mixedEmbedding {x : (𝓞 K)⁰}
+ (hx : mixedEmbedding K (x : 𝓞 K) ∈ integralPoint K) :
+ preimageOfIntegralPoint (⟨mixedEmbedding K (x : 𝓞 K), hx⟩) = x := by
+ simp_rw [Subtype.ext_iff, RingOfIntegers.ext_iff, ← (mixedEmbedding_injective K).eq_iff,
+ mixedEmbedding_preimageOfIntegralPoint]
+
+/-- If `x : mixedSpace K` is nonzero and the image of an algebraic integer, then there exists a
+unit such that `u • x ∈ integralPoint K`. -/
+theorem exists_unitSMul_mem_integralPoint {x : mixedSpace K} (hx : x ≠ 0)
+ (hx' : x ∈ mixedEmbedding K '' (Set.range (algebraMap (𝓞 K) K))) :
+ ∃ u : (𝓞 K)ˣ, u • x ∈ integralPoint K := by
+ replace hx : mixedEmbedding.norm x ≠ 0 :=
+ (norm_eq_zero_iff' (Set.mem_range_of_mem_image (mixedEmbedding K) _ hx')).not.mpr hx
+ obtain ⟨u, hu⟩ := exists_unit_smul_mem hx
+ obtain ⟨_, ⟨x, rfl⟩, _, rfl⟩ := hx'
+ exact ⟨u, mem_integralPoint.mpr ⟨hu, u * x, by simp_rw [unitSMul_smul, ← map_mul]⟩⟩
+
+/-- The set `integralPoint K` is stable under the action of the torsion. -/
+theorem torsion_unitSMul_mem_integralPoint {x : mixedSpace K} {ζ : (𝓞 K)ˣ} (hζ : ζ ∈ torsion K)
+ (hx : x ∈ integralPoint K) : ζ • x ∈ integralPoint K := by
+ obtain ⟨a, ⟨_, rfl⟩, rfl⟩ := (mem_integralPoint.mp hx).2
+ refine mem_integralPoint.mpr ⟨torsion_smul_mem_of_mem hx.1 hζ, ⟨ζ * a, by simp⟩⟩
+
+/-- The action of `torsion K` on `integralPoint K`. -/
+@[simps]
+instance integralPoint_torsionSMul: SMul (torsion K) (integralPoint K) where
+ smul := fun ⟨ζ, hζ⟩ ⟨x, hx⟩ ↦ ⟨ζ • x, torsion_unitSMul_mem_integralPoint hζ hx⟩
+
+instance : MulAction (torsion K) (integralPoint K) where
+ one_smul := fun _ ↦ by
+ rw [Subtype.mk_eq_mk, integralPoint_torsionSMul_smul_coe, OneMemClass.coe_one, one_smul]
+ mul_smul := fun _ _ _ ↦ by
+ rw [Subtype.mk_eq_mk]
+ simp_rw [integralPoint_torsionSMul_smul_coe, Subgroup.coe_mul, mul_smul]
+
+/-- The `mixedEmbedding.norm` of `a : integralPoint K` as a natural number, see also
+`intNorm_coe`. -/
+def intNorm (a : integralPoint K) : ℕ := (Algebra.norm ℤ (preimageOfIntegralPoint a : 𝓞 K)).natAbs
+
+@[simp]
+theorem intNorm_coe (a : integralPoint K) :
+ (intNorm a : ℝ) = mixedEmbedding.norm (a : mixedSpace K) := by
+ rw [intNorm, Int.cast_natAbs, ← Rat.cast_intCast, Int.cast_abs, Algebra.coe_norm_int,
+ ← norm_eq_norm, mixedEmbedding_preimageOfIntegralPoint]
+
+/-- The norm `intNorm` lifts to a function on `integralPoint K` modulo `torsion K`. -/
+def quotIntNorm :
+ Quotient (MulAction.orbitRel (torsion K) (integralPoint K)) → ℕ :=
+ Quotient.lift (fun x ↦ intNorm x) fun a b ⟨u, hu⟩ ↦ by
+ rw [← Nat.cast_inj (R := ℝ), intNorm_coe, intNorm_coe, ← hu, integralPoint_torsionSMul_smul_coe,
+ norm_unit_smul]
+
+@[simp]
+theorem quotIntNorm_apply (a : integralPoint K) : quotIntNorm ⟦a⟧ = intNorm a := rfl
+
+variable (K) in
+/-- The map that sends an element of `a : integralPoint K` to the associates class
+of its preimage in `(𝓞 K)⁰`. By quotienting by the kernel of the map, which is equal to the
+subgroup of torsion, we get the equivalence `integralPointQuotEquivAssociates`. -/
+def integralPointToAssociates (a : integralPoint K) : Associates (𝓞 K)⁰ :=
+ ⟦preimageOfIntegralPoint a⟧
+
+@[simp]
+theorem integralPointToAssociates_apply (a : integralPoint K) :
+ integralPointToAssociates K a = ⟦preimageOfIntegralPoint a⟧ := rfl
+
+variable (K) in
+theorem integralPointToAssociates_surjective :
+ Function.Surjective (integralPointToAssociates K) := by
+ rintro ⟨x⟩
+ obtain ⟨u, hu⟩ : ∃ u : (𝓞 K)ˣ, u • mixedEmbedding K (x : 𝓞 K) ∈ integralPoint K := by
+ refine exists_unitSMul_mem_integralPoint ?_ ⟨(x : 𝓞 K), Set.mem_range_self _, rfl⟩
+ exact (map_ne_zero _).mpr <| RingOfIntegers.coe_ne_zero_iff.mpr (nonZeroDivisors.coe_ne_zero _)
+ refine ⟨⟨u • mixedEmbedding K (x : 𝓞 K), hu⟩,
+ Quotient.sound ⟨unitsNonZeroDivisorsEquiv.symm u⁻¹, ?_⟩⟩
+ simp_rw [Subtype.ext_iff, RingOfIntegers.ext_iff, ← (mixedEmbedding_injective K).eq_iff,
+ Submonoid.coe_mul, map_mul, mixedEmbedding_preimageOfIntegralPoint,
+ unitSMul_smul, ← map_mul, mul_comm, map_inv, val_inv_unitsNonZeroDivisorsEquiv_symm_apply_coe,
+ Units.mul_inv_cancel_right]
+
+theorem integralPointToAssociates_eq_iff (a b : integralPoint K) :
+ integralPointToAssociates K a = integralPointToAssociates K b ↔
+ ∃ ζ : torsion K, ζ • a = b := by
+ simp_rw [integralPointToAssociates_apply, Associates.quotient_mk_eq_mk,
+ Associates.mk_eq_mk_iff_associated, Associated, mul_comm, Subtype.ext_iff,
+ RingOfIntegers.ext_iff, ← (mixedEmbedding_injective K).eq_iff, Submonoid.coe_mul, map_mul,
+ mixedEmbedding_preimageOfIntegralPoint, integralPoint_torsionSMul_smul_coe]
+ refine ⟨fun ⟨u, h⟩ ↦ ⟨⟨unitsNonZeroDivisorsEquiv u, ?_⟩, by simpa using h⟩,
+ fun ⟨⟨u, _⟩, h⟩ ↦ ⟨unitsNonZeroDivisorsEquiv.symm u, by simpa using h⟩⟩
+ exact (unit_smul_mem_iff_mem_torsion a.prop.1 _).mp (by simpa [h] using b.prop.1)
+
+variable (K) in
+/-- The equivalence between `integralPoint K` modulo `torsion K` and `Associates (𝓞 K)⁰`. -/
+def integralPointQuotEquivAssociates :
+ Quotient (MulAction.orbitRel (torsion K) (integralPoint K)) ≃ Associates (𝓞 K)⁰ :=
+ Equiv.ofBijective
+ (Quotient.lift (integralPointToAssociates K)
+ fun _ _ h ↦ ((integralPointToAssociates_eq_iff _ _).mpr h).symm)
+ ⟨by convert Setoid.ker_lift_injective (integralPointToAssociates K)
+ all_goals
+ · ext a b
+ rw [Setoid.ker_def, eq_comm, integralPointToAssociates_eq_iff b a,
+ MulAction.orbitRel_apply, MulAction.mem_orbit_iff],
+ (Quot.surjective_lift _).mpr (integralPointToAssociates_surjective K)⟩
+
+@[simp]
+theorem integralPointQuotEquivAssociates_apply (a : integralPoint K) :
+ integralPointQuotEquivAssociates K ⟦a⟧ = ⟦preimageOfIntegralPoint a⟧ := rfl
+
+theorem integralPoint_torsionSMul_stabilizer (a : integralPoint K) :
+ MulAction.stabilizer (torsion K) a = ⊥ := by
+ refine (Subgroup.eq_bot_iff_forall _).mpr fun ζ hζ ↦ ?_
+ rwa [MulAction.mem_stabilizer_iff, Subtype.ext_iff, integralPoint_torsionSMul_smul_coe,
+ unitSMul_smul, ← mixedEmbedding_preimageOfIntegralPoint, ← map_mul,
+ (mixedEmbedding_injective K).eq_iff, ← map_mul, ← RingOfIntegers.ext_iff, mul_eq_right₀,
+ Units.val_eq_one, OneMemClass.coe_eq_one] at hζ
+ exact nonZeroDivisors.coe_ne_zero _
+
+open Submodule Ideal
+
+variable (K) in
+/-- The equivalence between `integralPoint K` and the product of the set of nonzero principal
+ideals of `K` and the torsion of `K`. -/
+def integralPointEquiv :
+ integralPoint K ≃ {I : (Ideal (𝓞 K))⁰ // IsPrincipal I.val} × torsion K :=
+ (MulAction.selfEquivSigmaOrbitsQuotientStabilizer (torsion K) (integralPoint K)).trans
+ ((Equiv.sigmaEquivProdOfEquiv (by
+ intro _
+ simp_rw [integralPoint_torsionSMul_stabilizer]
+ exact QuotientGroup.quotientBot.toEquiv)).trans
+ (Equiv.prodCongrLeft (fun _ ↦ (integralPointQuotEquivAssociates K).trans
+ (Ideal.associatesNonZeroDivisorsEquivIsPrincipal (𝓞 K)))))
+
+@[simp]
+theorem integralPointEquiv_apply_fst (a : integralPoint K) :
+ ((integralPointEquiv K a).1 : Ideal (𝓞 K)) = span {(preimageOfIntegralPoint a : 𝓞 K)} := rfl
+
+variable (K) in
+/-- For an integer `n`, The equivalence between the `integralPoint K` of norm `n` and the product
+of the set of nonzero principal ideals of `K` of norm `n` and the torsion of `K`. -/
+def integralPointEquivNorm (n : ℕ) :
+ {a : integralPoint K // intNorm a = n} ≃
+ {I : (Ideal (𝓞 K))⁰ // IsPrincipal (I : Ideal (𝓞 K)) ∧
+ absNorm (I : Ideal (𝓞 K)) = n} × (torsion K) :=
+ calc {a // intNorm a = n}
+ ≃ {I : {I : (Ideal (𝓞 K))⁰ // IsPrincipal I.1} × torsion K //
+ absNorm (I.1 : Ideal (𝓞 K)) = n} :=
+ (Equiv.subtypeEquiv (integralPointEquiv K) fun _ ↦ by simp [intNorm, absNorm_span_singleton])
+ _ ≃ {I : {I : (Ideal (𝓞 K))⁰ // IsPrincipal I.1} // absNorm (I.1 : Ideal (𝓞 K)) = n} ×
+ torsion K :=
+ Equiv.prodSubtypeFstEquivSubtypeProd (p := fun I : {I : (Ideal (𝓞 K))⁰ // IsPrincipal I.1} ↦
+ absNorm (I : Ideal (𝓞 K)) = n)
+ _ ≃ {I : (Ideal (𝓞 K))⁰ // IsPrincipal (I : Ideal (𝓞 K)) ∧
+ absNorm (I : Ideal (𝓞 K)) = n} × (torsion K) :=
+ Equiv.prodCongrLeft fun _ ↦ (Equiv.subtypeSubtypeEquivSubtypeInter
+ (fun I : (Ideal (𝓞 K))⁰ ↦ IsPrincipal I.1) (fun I ↦ absNorm I.1 = n))
+
+@[simp]
+theorem integralPointEquivNorm_apply_fst {n : ℕ} {a : integralPoint K} (ha : intNorm a = n) :
+ ((integralPointEquivNorm K n ⟨a, ha⟩).1 : Ideal (𝓞 K)) =
+ span {(preimageOfIntegralPoint a : 𝓞 K)} := by
+ simp_rw [integralPointEquivNorm, Equiv.prodSubtypeFstEquivSubtypeProd, Equiv.instTrans_trans,
+ Equiv.prodCongrLeft, Equiv.trans_apply, Equiv.subtypeEquiv_apply, Equiv.coe_fn_mk,
+ Equiv.subtypeSubtypeEquivSubtypeInter_apply_coe, integralPointEquiv_apply_fst]
+
+variable (K)
+
+/-- For `n` positive, the number of principal ideals in `𝓞 K` of norm `n` multiplied by the order
+of the torsion of `K` is equal to the number of `integralPoint K` of norm `n`. -/
+theorem card_isPrincipal_norm_eq_mul_torsion (n : ℕ) :
+ Nat.card {I : (Ideal (𝓞 K))⁰ | IsPrincipal (I : Ideal (𝓞 K)) ∧
+ absNorm (I : Ideal (𝓞 K)) = n} * torsionOrder K =
+ Nat.card {a : integralPoint K | intNorm a = n} := by
+ rw [torsionOrder, PNat.mk_coe, ← Nat.card_eq_fintype_card, ← Nat.card_prod]
+ exact Nat.card_congr (integralPointEquivNorm K n).symm
+
+/-- For `s : ℝ`, the number of principal nonzero ideals in `𝓞 K` of norm `≤ s` multiplied by the
+order of the torsion of `K` is equal to the number of `integralPoint K` of norm `≤ s`. -/
+theorem card_isPrincipal_norm_le_mul_torsion (s : ℝ) :
+ Nat.card {I : (Ideal (𝓞 K))⁰ | IsPrincipal (I : Ideal (𝓞 K)) ∧
+ absNorm (I : Ideal (𝓞 K)) ≤ s} * torsionOrder K =
+ Nat.card {a : integralPoint K | intNorm a ≤ s} := by
+ obtain hs | hs := le_or_gt 0 s
+ · simp_rw [← Nat.le_floor_iff hs]
+ rw [torsionOrder, PNat.mk_coe, ← Nat.card_eq_fintype_card, ← Nat.card_prod]
+ refine Nat.card_congr <| @Equiv.ofFiberEquiv _ (γ := Finset.Iic _) _
+ (fun I ↦ ⟨absNorm (I.1 : Ideal (𝓞 K)), Finset.mem_Iic.mpr I.1.2.2⟩)
+ (fun a ↦ ⟨intNorm a.1, Finset.mem_Iic.mpr a.2⟩) fun ⟨i, hi⟩ ↦ ?_
+ simp_rw [Subtype.mk.injEq]
+ calc
+ _ ≃ {I : {I : (Ideal (𝓞 K))⁰ // IsPrincipal I.1 ∧ absNorm I.1 ≤ _} // absNorm I.1.1 = i}
+ × torsion K := Equiv.prodSubtypeFstEquivSubtypeProd
+ _ ≃ {I : (Ideal (𝓞 K))⁰ // (IsPrincipal I.1 ∧ absNorm I.1 ≤ _) ∧ absNorm I.1 = i}
+ × torsion K :=
+ Equiv.prodCongrLeft fun _ ↦ (Equiv.subtypeSubtypeEquivSubtypeInter
+ (p := fun I : (Ideal (𝓞 K))⁰ ↦ IsPrincipal I.1 ∧ absNorm I.1 ≤ _)
+ (q := fun I ↦ absNorm I.1 = i))
+ _ ≃ {I : (Ideal (𝓞 K))⁰ // IsPrincipal I.1 ∧ absNorm I.1 = i ∧ absNorm I.1 ≤ _}
+ × torsion K :=
+ Equiv.prodCongrLeft fun _ ↦ (Equiv.subtypeEquivRight fun _ ↦ by aesop)
+ _ ≃ {I : (Ideal (𝓞 K))⁰ // IsPrincipal I.1 ∧ absNorm I.1 = i} × torsion K :=
+ Equiv.prodCongrLeft fun _ ↦ (Equiv.subtypeEquivRight fun _ ↦ by
+ rw [and_iff_left_of_imp (a := absNorm _ = _) fun h ↦ Finset.mem_Iic.mp (h ▸ hi)])
+ _ ≃ {a : integralPoint K // intNorm a = i} := (integralPointEquivNorm K i).symm
+ _ ≃ {a : {a : integralPoint K // intNorm a ≤ _} // intNorm a.1 = i} :=
+ (Equiv.subtypeSubtypeEquivSubtype fun h ↦ Finset.mem_Iic.mp (h ▸ hi)).symm
+ · simp_rw [lt_iff_not_le.mp (lt_of_lt_of_le hs (Nat.cast_nonneg _)), and_false, Set.setOf_false,
+ Nat.card_eq_fintype_card, Fintype.card_ofIsEmpty, zero_mul]
+
+end fundamentalCone
+
+end
+
+end NumberField.mixedEmbedding
diff --git a/Mathlib/NumberTheory/NumberField/ClassNumber.lean b/Mathlib/NumberTheory/NumberField/ClassNumber.lean
index c6726b41347b6..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]
@@ -41,13 +40,13 @@ variable {K}
theorem classNumber_eq_one_iff : classNumber K = 1 ↔ IsPrincipalIdealRing (𝓞 K) :=
card_classGroup_eq_one_iff
-open FiniteDimensional NumberField.InfinitePlace
+open Module NumberField.InfinitePlace
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,11 +70,11 @@ 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
- rw [← Real.sqrt_lt (by positivity) (by positivity), mul_assoc, ← inv_mul_lt_iff' (by positivity),
+ rw [← Real.sqrt_lt (by positivity) (by positivity), mul_assoc, ← inv_mul_lt_iff₀' (by positivity),
mul_inv, ← inv_pow, inv_div, inv_div, mul_assoc, Int.cast_abs] at h
rw [← classNumber_eq_one_iff, classNumber, Fintype.card_eq_one_iff]
refine ⟨1, fun C ↦ ?_⟩
diff --git a/Mathlib/NumberTheory/NumberField/Discriminant.lean b/Mathlib/NumberTheory/NumberField/Discriminant/Basic.lean
similarity index 77%
rename from Mathlib/NumberTheory/NumberField/Discriminant.lean
rename to Mathlib/NumberTheory/NumberField/Discriminant/Basic.lean
index 0800c7995ee2d..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
@@ -32,53 +30,25 @@ number field, discriminant
namespace NumberField
-open FiniteDimensional NumberField NumberField.InfinitePlace Matrix
+open Module NumberField NumberField.InfinitePlace Matrix
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
@@ -173,7 +161,7 @@ theorem abs_discr_ge (h : 1 < finrank ℚ K) :
rw [← Algebra.coe_norm_int, ← Int.cast_one, ← Int.cast_abs, Rat.cast_intCast, Int.cast_le]
exact Int.one_le_abs (Algebra.norm_ne_zero_iff.mpr h_nz)
replace h_bd := le_trans h_nm h_bd
- rw [← inv_mul_le_iff (by positivity), inv_div, mul_one, Real.le_sqrt (by positivity)
+ rw [← inv_mul_le_iff₀ (by positivity), inv_div, mul_one, Real.le_sqrt (by positivity)
(by positivity), ← Int.cast_abs, div_pow, mul_pow, ← pow_mul, ← pow_mul] at h_bd
refine le_trans ?_ h_bd
-- The sequence `a n` is a lower bound for `|discr K|`. We prove below by induction an uniform
@@ -277,7 +265,7 @@ theorem rank_le_rankOfDiscrBdd :
refine fun h ↦ discr_ne_zero K ?_
rwa [h, Nat.cast_zero, abs_nonpos_iff] at hK
have h₂ : 1 < 3 * π / 4 := by
- rw [_root_.lt_div_iff (by positivity), ← _root_.div_lt_iff' (by positivity), one_mul]
+ rw [_root_.lt_div_iff₀ (by positivity), ← _root_.div_lt_iff₀' (by positivity), one_mul]
linarith [Real.pi_gt_three]
obtain h | h := lt_or_le 1 (finrank ℚ K)
· apply le_max_of_le_right
@@ -307,8 +295,8 @@ theorem minkowskiBound_lt_boundOfDiscBdd : minkowskiBound K ↑1 < boundOfDiscBd
ENNReal.ofReal_one, one_mul, mixedEmbedding.finrank, volume_fundamentalDomain_latticeBasis,
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,
+ · exact pow_le_one₀ (by positivity) (by norm_num)
+ · 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
@@ -337,6 +325,8 @@ theorem finite_of_discr_bdd_of_isReal :
(Set.finite_Icc (-C : ℤ) C)) (fun ⟨K, hK₀⟩ ⟨hK₁, hK₂⟩ ↦ ?_)
-- We now need to prove that each field is generated by an element of the union of the rootset
simp_rw [Set.mem_iUnion]
+ -- this is purely an optimization
+ have : CharZero K := SubsemiringClass.instCharZero K
haveI : NumberField K := @NumberField.mk _ _ inferInstance hK₀
obtain ⟨w₀, hw₀⟩ := hK₁
suffices minkowskiBound K ↑1 < (convexBodyLTFactor K) * B by
@@ -358,14 +348,17 @@ 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
+ convert hx₁
+ · simp only [IntermediateField.lift_top]
+ · simp only [IntermediateField.lift_adjoin, Set.image_singleton]
have := one_le_convexBodyLTFactor K
convert lt_of_le_of_lt (mul_right_mono (coe_le_coe.mpr this))
(ENNReal.mul_lt_mul_left' (by positivity) coe_ne_top (minkowskiBound_lt_boundOfDiscBdd hK₂))
simp_rw [ENNReal.coe_one, one_mul]
+
theorem finite_of_discr_bdd_of_isComplex :
{K : { F : IntermediateField ℚ A // FiniteDimensional ℚ F} |
haveI : NumberField K := @NumberField.mk _ _ inferInstance K.prop
@@ -380,6 +373,8 @@ theorem finite_of_discr_bdd_of_isComplex :
(Set.finite_Icc (-C : ℤ) C)) (fun ⟨K, hK₀⟩ ⟨hK₁, hK₂⟩ ↦ ?_)
-- We now need to prove that each field is generated by an element of the union of the rootset
simp_rw [Set.mem_iUnion]
+ -- this is purely an optimization
+ have : CharZero K := SubsemiringClass.instCharZero K
haveI : NumberField K := @NumberField.mk _ _ inferInstance hK₀
obtain ⟨w₀, hw₀⟩ := hK₁
suffices minkowskiBound K ↑1 < (convexBodyLT'Factor K) * boundOfDiscBdd N by
@@ -402,9 +397,11 @@ 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
+ convert hx₁
+ · simp only [IntermediateField.lift_top]
+ · simp only [IntermediateField.lift_adjoin, Set.image_singleton]
have := one_le_convexBodyLT'Factor K
convert lt_of_le_of_lt (mul_right_mono (coe_le_coe.mpr this))
(ENNReal.mul_lt_mul_left' (by positivity) coe_ne_top (minkowskiBound_lt_boundOfDiscBdd hK₂))
@@ -419,6 +416,8 @@ theorem _root_.NumberField.finite_of_discr_bdd :
refine Set.Finite.subset (Set.Finite.union (finite_of_discr_bdd_of_isReal A N)
(finite_of_discr_bdd_of_isComplex A N)) ?_
rintro ⟨K, hK₀⟩ hK₁
+ -- this is purely an optimization
+ have : CharZero K := SubsemiringClass.instCharZero K
haveI : NumberField K := @NumberField.mk _ _ inferInstance hK₀
obtain ⟨w₀⟩ := (inferInstance : Nonempty (InfinitePlace K))
by_cases hw₀ : IsReal w₀
@@ -430,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 d2421c79c769e..f041f1b899502 100644
--- a/Mathlib/NumberTheory/NumberField/Embeddings.lean
+++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean
@@ -32,13 +32,13 @@ 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
section Fintype
-open FiniteDimensional
+open Module
variable (K : Type*) [Field K] [NumberField K]
variable (A : Type*) [Field A] [CharZero A]
@@ -55,7 +55,7 @@ theorem card : Fintype.card (K →+* A) = finrank ℚ K := by
instance : Nonempty (K →+* A) := by
rw [← Fintype.card_pos_iff, NumberField.Embeddings.card K A]
- exact FiniteDimensional.finrank_pos
+ exact Module.finrank_pos
end Fintype
@@ -78,7 +78,7 @@ end Roots
section Bounded
-open FiniteDimensional Polynomial Set
+open Module Polynomial Set
variable {K : Type*} [Field K] [NumberField K]
variable {A : Type*} [NormedField A] [IsAlgClosed A] [NormedAlgebra ℚ A]
@@ -259,7 +259,7 @@ open NumberField
instance {K : Type*} [Field K] : FunLike (InfinitePlace K) K ℝ where
coe w x := w.1 x
- coe_injective' := fun _ _ h => Subtype.eq (AbsoluteValue.ext fun x => congr_fun h x)
+ coe_injective' _ _ h := Subtype.eq (AbsoluteValue.ext fun x => congr_fun h x)
instance : MonoidWithZeroHomClass (InfinitePlace K) K ℝ where
map_mul w _ _ := w.1.map_mul _ _
@@ -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]
@@ -450,7 +449,7 @@ noncomputable instance NumberField.InfinitePlace.fintype [NumberField K] :
Fintype (InfinitePlace K) := Set.fintypeRange _
theorem sum_mult_eq [NumberField K] :
- ∑ w : InfinitePlace K, mult w = FiniteDimensional.finrank ℚ K := by
+ ∑ w : InfinitePlace K, mult w = Module.finrank ℚ K := by
rw [← Embeddings.card K ℂ, Fintype.card, Finset.card_eq_sum_ones, ← Finset.univ.sum_fiberwise
(fun φ => InfinitePlace.mk φ)]
exact Finset.sum_congr rfl
@@ -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]
@@ -505,7 +501,7 @@ theorem one_le_of_lt_one {w : InfinitePlace K} {a : (𝓞 K)} (ha : a ≠ 0)
rw [← InfinitePlace.prod_eq_abs_norm, ← Finset.prod_const_one]
refine Finset.prod_lt_prod_of_nonempty (fun _ _ ↦ ?_) (fun z _ ↦ ?_) Finset.univ_nonempty
· exact pow_pos (pos_iff.mpr ((Subalgebra.coe_eq_zero _).not.mpr ha)) _
- · refine pow_lt_one (apply_nonneg _ _) ?_ (by rw [mult]; split_ifs <;> norm_num)
+ · refine pow_lt_one₀ (apply_nonneg _ _) ?_ (by rw [mult]; split_ifs <;> norm_num)
by_cases hz : z = w
· rwa [hz]
· exact h hz
@@ -546,7 +542,7 @@ theorem _root_.NumberField.adjoin_eq_top_of_infinitePlace_lt {x : 𝓞 K} {w : I
end NumberField
-open Fintype FiniteDimensional
+open Fintype Module
variable (K)
@@ -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
@@ -1024,12 +1024,12 @@ lemma IsUnramifiedAtInfinitePlaces_of_odd_card_aut [IsGalois k K] [FiniteDimensi
⟨fun _ ↦ not_not.mp (Nat.not_even_iff_odd.2 h ∘ InfinitePlace.even_card_aut_of_not_isUnramified)⟩
lemma IsUnramifiedAtInfinitePlaces_of_odd_finrank [IsGalois k K]
- (h : Odd (FiniteDimensional.finrank k K)) : IsUnramifiedAtInfinitePlaces k K :=
+ (h : Odd (Module.finrank k K)) : IsUnramifiedAtInfinitePlaces k K :=
⟨fun _ ↦ not_not.mp (Nat.not_even_iff_odd.2 h ∘ InfinitePlace.even_finrank_of_not_isUnramified)⟩
variable (k K)
-open FiniteDimensional in
+open Module in
lemma IsUnramifiedAtInfinitePlaces.card_infinitePlace [NumberField k] [NumberField K]
[IsGalois k K] [IsUnramifiedAtInfinitePlaces k K] :
Fintype.card (InfinitePlace K) = Fintype.card (InfinitePlace k) * finrank k K := by
@@ -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 67fc4926a8307..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]
@@ -21,7 +22,7 @@ namespace NumberField
noncomputable section
-open Module.Free FiniteDimensional canonicalEmbedding Matrix Finset
+open Module.Free Module canonicalEmbedding Matrix Finset
/-- 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`. -/
diff --git a/Mathlib/NumberTheory/NumberField/FractionalIdeal.lean b/Mathlib/NumberTheory/NumberField/FractionalIdeal.lean
index 3d5cc80dab357..1444de4b7e903 100644
--- a/Mathlib/NumberTheory/NumberField/FractionalIdeal.lean
+++ b/Mathlib/NumberTheory/NumberField/FractionalIdeal.lean
@@ -61,7 +61,7 @@ instance (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ) :
· refine Submonoid.mul_mem _ hd (mem_nonZeroDivisors_of_ne_zero ?_)
rw [Nat.cast_ne_zero, ne_eq, Ideal.absNorm_eq_zero_iff]
exact FractionalIdeal.num_eq_zero_iff.not.mpr <| Units.ne_zero I
- · simp_rw [LinearMap.coe_restrictScalars, Submodule.coeSubtype] at h ⊢
+ · simp_rw [LinearMap.coe_restrictScalars, Submodule.coe_subtype] at h ⊢
rw [← h]
simp only [Submonoid.mk_smul, zsmul_eq_mul, Int.cast_mul, Int.cast_natCast, algebraMap_int_eq,
eq_intCast, map_intCast]
@@ -89,7 +89,7 @@ theorem mem_span_basisOfFractionalIdeal {I : (FractionalIdeal (𝓞 K)⁰ K)ˣ}
rw [basisOfFractionalIdeal, (fractionalIdealBasis K I.1).ofIsLocalizedModule_span ℚ ℤ⁰ _]
simp
-open FiniteDimensional in
+open Module in
theorem fractionalIdeal_rank (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ) :
finrank ℤ I = finrank ℤ (𝓞 K) := by
rw [finrank_eq_card_chooseBasisIndex, RingOfIntegers.rank,
diff --git a/Mathlib/NumberTheory/NumberField/House.lean b/Mathlib/NumberTheory/NumberField/House.lean
index 5d0cc0062fc60..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
@@ -27,7 +27,7 @@ namespace NumberField
noncomputable section
-open Module.Free FiniteDimensional canonicalEmbedding Matrix Finset
+open Module.Free Module canonicalEmbedding Matrix Finset
attribute [local instance] Matrix.seminormedAddCommGroup
@@ -62,7 +62,7 @@ noncomputable section
variable (K)
-open Module.Free FiniteDimensional canonicalEmbedding Matrix Finset
+open Module.Free Module canonicalEmbedding Matrix Finset
attribute [local instance] Matrix.seminormedAddCommGroup
@@ -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/Norm.lean b/Mathlib/NumberTheory/NumberField/Norm.lean
index 2b529a1d239bb..e8964a687a66b 100644
--- a/Mathlib/NumberTheory/NumberField/Norm.lean
+++ b/Mathlib/NumberTheory/NumberField/Norm.lean
@@ -22,7 +22,7 @@ rings of integers.
open scoped NumberField
-open Finset NumberField Algebra FiniteDimensional
+open Finset NumberField Algebra Module
section Rat
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 bfdf0740cfa1c..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]
@@ -84,10 +84,11 @@ variable {K}
@[simp]
theorem logEmbedding_component (x : (𝓞 K)ˣ) (w : {w : InfinitePlace K // w ≠ w₀}) :
- (logEmbedding K x) w = mult w.val * Real.log (w.val x) := rfl
+ (logEmbedding K (Additive.ofMul x)) w = mult w.val * Real.log (w.val x) := rfl
theorem sum_logEmbedding_component (x : (𝓞 K)ˣ) :
- ∑ w, logEmbedding K x w = - mult (w₀ : InfinitePlace K) * Real.log (w₀ (x : K)) := by
+ ∑ w, logEmbedding K (Additive.ofMul x) w =
+ - mult (w₀ : InfinitePlace K) * Real.log (w₀ (x : K)) := by
have h := congr_arg Real.log (prod_eq_abs_norm (x : K))
rw [Units.norm, Rat.cast_one, Real.log_one, Real.log_prod] at h
· simp_rw [Real.log_pow] at h
@@ -112,7 +113,7 @@ theorem mult_log_place_eq_zero {x : (𝓞 K)ˣ} {w : InfinitePlace K} :
variable [NumberField K]
theorem logEmbedding_eq_zero_iff {x : (𝓞 K)ˣ} :
- logEmbedding K x = 0 ↔ x ∈ torsion K := by
+ logEmbedding K (Additive.ofMul x) = 0 ↔ x ∈ torsion K := by
rw [mem_torsion]
refine ⟨fun h w => ?_, fun h => ?_⟩
· by_cases hw : w = w₀
@@ -126,13 +127,14 @@ theorem logEmbedding_eq_zero_iff {x : (𝓞 K)ˣ} :
rw [logEmbedding_component, h w.val, Real.log_one, mul_zero, Pi.zero_apply]
theorem logEmbedding_component_le {r : ℝ} {x : (𝓞 K)ˣ} (hr : 0 ≤ r) (h : ‖logEmbedding K x‖ ≤ r)
- (w : {w : InfinitePlace K // w ≠ w₀}) : |logEmbedding K x w| ≤ r := by
+ (w : {w : InfinitePlace K // w ≠ w₀}) : |logEmbedding K (Additive.ofMul x) w| ≤ r := by
lift r to NNReal using hr
simp_rw [Pi.norm_def, NNReal.coe_le_coe, Finset.sup_le_iff, ← NNReal.coe_le_coe] at h
exact h w (mem_univ _)
-theorem log_le_of_logEmbedding_le {r : ℝ} {x : (𝓞 K)ˣ} (hr : 0 ≤ r) (h : ‖logEmbedding K x‖ ≤ r)
- (w : InfinitePlace K) : |Real.log (w x)| ≤ (Fintype.card (InfinitePlace K)) * r := by
+theorem log_le_of_logEmbedding_le {r : ℝ} {x : (𝓞 K)ˣ} (hr : 0 ≤ r)
+ (h : ‖logEmbedding K (Additive.ofMul x)‖ ≤ r) (w : InfinitePlace K) :
+ |Real.log (w x)| ≤ (Fintype.card (InfinitePlace K)) * r := by
have tool : ∀ x : ℝ, 0 ≤ x → x ≤ mult w * x := fun x hx => by
nth_rw 1 [← one_mul x]
refine mul_le_mul ?_ le_rfl hx ?_
@@ -160,8 +162,8 @@ variable (K)
/-- The lattice formed by the image of the logarithmic embedding. -/
noncomputable def _root_.NumberField.Units.unitLattice :
- AddSubgroup ({w : InfinitePlace K // w ≠ w₀} → ℝ) :=
- AddSubgroup.map (logEmbedding K) ⊤
+ Submodule ℤ ({w : InfinitePlace K // w ≠ w₀} → ℝ) :=
+ Submodule.map (logEmbedding K).toIntLinearMap ⊤
theorem unitLattice_inter_ball_finite (r : ℝ) :
((unitLattice K : Set ({ w : InfinitePlace K // w ≠ w₀} → ℝ)) ∩
@@ -215,7 +217,7 @@ theorem seq_next {x : 𝓞 K} (hx : x ≠ 0) :
fun w => ⟨(w x) / 2, div_nonneg (AbsoluteValue.nonneg _ _) (by norm_num)⟩
suffices ∀ w, w ≠ w₁ → f w ≠ 0 by
obtain ⟨g, h_geqf, h_gprod⟩ := adjust_f K B this
- obtain ⟨y, h_ynz, h_yle⟩ := exists_ne_zero_mem_ringOfIntegers_lt (f := g)
+ obtain ⟨y, h_ynz, h_yle⟩ := exists_ne_zero_mem_ringOfIntegers_lt K (f := g)
(by rw [convexBodyLT_volume]; convert hB; exact congr_arg ((↑) : NNReal → ENNReal) h_gprod)
refine ⟨y, h_ynz, fun w hw => (h_geqf w hw ▸ h_yle w).trans ?_, ?_⟩
· rw [← Rat.cast_le (K := ℝ), Rat.cast_natCast]
@@ -248,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
@@ -299,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)), 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) | 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
@@ -320,13 +313,13 @@ theorem unitLattice_span_eq_top :
-- The standard basis
let B := Pi.basisFun ℝ {w : InfinitePlace K // w ≠ w₀}
-- The image by log_embedding of the family of units constructed above
- let v := fun w : { w : InfinitePlace K // w ≠ w₀ } => logEmbedding K (exists_unit K w).choose
+ let v := fun w : { w : InfinitePlace K // w ≠ w₀ } =>
+ logEmbedding K (Additive.ofMul (exists_unit K w).choose)
-- To prove the result, it is enough to prove that the family `v` is linearly independent
suffices B.det v ≠ 0 by
rw [← isUnit_iff_ne_zero, ← is_basis_iff_det] at this
rw [← this.2]
- exact Submodule.span_monotone (fun _ ⟨w, hw⟩ =>
- ⟨(exists_unit K w).choose, trivial, by rw [← hw]⟩)
+ refine Submodule.span_monotone fun _ ⟨w, hw⟩ ↦ ⟨(exists_unit K w).choose, trivial, hw⟩
rw [Basis.det_apply]
-- We use a specific lemma to prove that this determinant is nonzero
refine det_ne_zero_of_sum_col_lt_diag (fun w => ?_)
@@ -352,7 +345,7 @@ section statements
variable [NumberField K]
open scoped Classical
-open dirichletUnitTheorem FiniteDimensional
+open dirichletUnitTheorem Module
/-- The unit rank of the number field `K`, it is equal to `card (InfinitePlace K) - 1`. -/
def rank : ℕ := Fintype.card (InfinitePlace K) - 1
@@ -389,12 +382,12 @@ def logEmbeddingQuot :
(QuotientGroup.quotientMulEquivOfEq (by
ext
rw [MonoidHom.mem_ker, AddMonoidHom.toMultiplicative'_apply_apply, ofAdd_eq_one,
- ← logEmbedding_eq_zero_iff]
- rfl)).toMonoidHom
+ ← logEmbedding_eq_zero_iff])).toMonoidHom
@[simp]
theorem logEmbeddingQuot_apply (x : (𝓞 K)ˣ) :
- logEmbeddingQuot K ⟦x⟧ = logEmbedding K x := rfl
+ logEmbeddingQuot K (Additive.ofMul (QuotientGroup.mk x)) =
+ logEmbedding K (Additive.ofMul x) := rfl
theorem logEmbeddingQuot_injective :
Function.Injective (logEmbeddingQuot K) := by
@@ -420,15 +413,18 @@ set_option maxSynthPendingDepth 2 -- Note this is active for the remainder of th
`unitLattice` . -/
def logEmbeddingEquiv :
Additive ((𝓞 K)ˣ ⧸ (torsion K)) ≃ₗ[ℤ] (unitLattice K) :=
- (AddEquiv.ofBijective (AddMonoidHom.codRestrict (logEmbeddingQuot K) _
- (Quotient.ind fun x ↦ logEmbeddingQuot_apply K _ ▸ AddSubgroup.mem_map_of_mem _ trivial))
- ⟨fun _ _ ↦ by
- rw [AddMonoidHom.codRestrict_apply, AddMonoidHom.codRestrict_apply, Subtype.mk.injEq]
- apply logEmbeddingQuot_injective K, fun ⟨a, ⟨b, _, ha⟩⟩ ↦ ⟨⟦b⟧, by simp [ha]⟩⟩).toIntLinearEquiv
+ LinearEquiv.ofBijective ((logEmbeddingQuot K).codRestrict (unitLattice K)
+ (Quotient.ind fun _ ↦ logEmbeddingQuot_apply K _ ▸
+ Submodule.mem_map_of_mem trivial)).toIntLinearMap
+ ⟨fun _ _ ↦ by
+ rw [AddMonoidHom.coe_toIntLinearMap, AddMonoidHom.codRestrict_apply,
+ AddMonoidHom.codRestrict_apply, Subtype.mk.injEq]
+ apply logEmbeddingQuot_injective K, fun ⟨a, ⟨b, _, ha⟩⟩ ↦ ⟨⟦b⟧, by simpa using ha⟩⟩
@[simp]
theorem logEmbeddingEquiv_apply (x : (𝓞 K)ˣ) :
- logEmbeddingEquiv K ⟦x⟧ = logEmbedding K x := rfl
+ logEmbeddingEquiv K (Additive.ofMul (QuotientGroup.mk x)) =
+ logEmbedding K (Additive.ofMul x) := rfl
instance : Module.Free ℤ (Additive ((𝓞 K)ˣ ⧸ (torsion K))) :=
Module.Free.of_equiv (logEmbeddingEquiv K).symm
@@ -457,13 +453,17 @@ instance : Monoid.FG (𝓞 K)ˣ := by
infer_instance
theorem rank_modTorsion :
- FiniteDimensional.finrank ℤ (Additive ((𝓞 K)ˣ ⧸ (torsion K))) = rank K := by
+ Module.finrank ℤ (Additive ((𝓞 K)ˣ ⧸ (torsion K))) = rank K := by
rw [← LinearEquiv.finrank_eq (logEmbeddingEquiv K).symm, unitLattice_rank]
/-- A basis of the quotient `(𝓞 K)ˣ ⧸ (torsion K)` seen as an additive ℤ-module. -/
def basisModTorsion : Basis (Fin (rank K)) ℤ (Additive ((𝓞 K)ˣ ⧸ (torsion K))) :=
Basis.reindex (Module.Free.chooseBasis ℤ _) (Fintype.equivOfCardEq <| by
- rw [← FiniteDimensional.finrank_eq_card_chooseBasisIndex, rank_modTorsion, Fintype.card_fin])
+ rw [← Module.finrank_eq_card_chooseBasisIndex, rank_modTorsion, Fintype.card_fin])
+
+/-- The basis of the `unitLattice` obtained by mapping `basisModTorsion` via `logEmbedding`. -/
+def basisUnitLattice : Basis (Fin (rank K)) ℤ (unitLattice K) :=
+ (basisModTorsion K).map (logEmbeddingEquiv K)
/-- A fundamental system of units of `K`. The units of `fundSystem` are arbitrary lifts of the
units in `basisModTorsion`. -/
@@ -472,10 +472,12 @@ def fundSystem : Fin (rank K) → (𝓞 K)ˣ :=
fun i => Quotient.out' (Additive.toMul (basisModTorsion K i):)
theorem fundSystem_mk (i : Fin (rank K)) :
- Additive.ofMul ⟦fundSystem K i⟧ = (basisModTorsion K i) := by
- rw [fundSystem, Equiv.apply_eq_iff_eq_symm_apply, @Quotient.mk_eq_iff_out,
- Quotient.out', Quotient.out_equiv_out]
- rfl
+ Additive.ofMul (QuotientGroup.mk (fundSystem K i)) = (basisModTorsion K i) := by
+ simp_rw [fundSystem, Equiv.apply_eq_iff_eq_symm_apply, Additive.ofMul_symm_eq, Quotient.out_eq']
+
+theorem logEmbedding_fundSystem (i : Fin (rank K)) :
+ logEmbedding K (Additive.ofMul (fundSystem K i)) = basisUnitLattice K i := by
+ rw [basisUnitLattice, Basis.map_apply, ← fundSystem_mk, logEmbeddingEquiv_apply]
/-- The exponents that appear in the unique decomposition of a unit as the product of
a root of unity and powers of the units of the fundamental system `fundSystem` (see
@@ -513,5 +515,4 @@ theorem exist_unique_eq_mul_prod (x : (𝓞 K)ˣ) : ∃! ζe : torsion K × (Fin
end statements
-
end NumberField.Units
diff --git a/Mathlib/NumberTheory/NumberField/Units/Regulator.lean b/Mathlib/NumberTheory/NumberField/Units/Regulator.lean
index 63b7cd807c1f8..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]
@@ -57,11 +57,11 @@ local instance : CommGroup (𝓞 K)ˣ := inferInstance
set_option maxSynthPendingDepth 2 -- Note this is active for the remainder of the file.
theorem regulator_eq_det' (e : {w : InfinitePlace K // w ≠ w₀} ≃ Fin (rank K)) :
- regulator K = |(Matrix.of fun i ↦ (logEmbedding K) (fundSystem K (e i))).det| := by
+ regulator K = |(Matrix.of fun i ↦
+ logEmbedding K (Additive.ofMul (fundSystem K (e i)))).det| := by
simp_rw [regulator, ZLattice.covolume_eq_det _
(((basisModTorsion K).map (logEmbeddingEquiv K)).reindex e.symm), Basis.coe_reindex,
- Function.comp_def, Basis.map_apply, ← fundSystem_mk, Equiv.symm_symm]
- rfl
+ Function.comp_def, Basis.map_apply, ← fundSystem_mk, Equiv.symm_symm, logEmbeddingEquiv_apply]
/-- Let `u : Fin (rank K) → (𝓞 K)ˣ` be a family of units and let `w₁` and `w₂` be two infinite
places. Then, the two square matrices with entries `(mult w * log w (u i))_i, {w ≠ w_i}`, `i = 1,2`,
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 d32fe3c1f17a2..614c690370a02 100644
--- a/Mathlib/NumberTheory/Padics/Hensel.lean
+++ b/Mathlib/NumberTheory/Padics/Hensel.lean
@@ -131,7 +131,7 @@ private theorem T_lt_one : T < 1 := by
have h := (div_lt_one (deriv_sq_norm_pos hnorm)).2 hnorm
rw [T_def]; exact h
-private theorem T_pow {n : ℕ} (hn : n ≠ 0) : T ^ n < 1 := pow_lt_one T_nonneg (T_lt_one hnorm) hn
+private theorem T_pow {n : ℕ} (hn : n ≠ 0) : T ^ n < 1 := pow_lt_one₀ T_nonneg (T_lt_one hnorm) hn
private theorem T_pow' (n : ℕ) : T ^ 2 ^ n < 1 := T_pow hnorm (pow_ne_zero _ two_ne_zero)
@@ -156,7 +156,7 @@ private theorem calc_norm_le_one {n : ℕ} {z : ℤ_[p]} (hz : ih n z) :
gcongr
apply hz.2
_ = ‖F.derivative.eval a‖ * T ^ 2 ^ n := div_sq_cancel _ _
- _ ≤ 1 := mul_le_one (PadicInt.norm_le_one _) (T_pow_nonneg _) (le_of_lt (T_pow' hnorm _))
+ _ ≤ 1 := mul_le_one₀ (PadicInt.norm_le_one _) (T_pow_nonneg _) (le_of_lt (T_pow' hnorm _))
private theorem calc_deriv_dist {z z' z1 : ℤ_[p]} (hz' : z' = z - z1)
@@ -183,7 +183,7 @@ private def calc_eval_z' {z z' z1 : ℤ_[p]} (hz' : z' = z - z1) {n} (hz : ih n
obtain ⟨q, hq⟩ := F.binomExpansion z (-z1)
have : ‖(↑(F.derivative.eval z) * (↑(F.eval z) / ↑(F.derivative.eval z)) : ℚ_[p])‖ ≤ 1 := by
rw [padicNormE.mul]
- exact mul_le_one (PadicInt.norm_le_one _) (norm_nonneg _) h1
+ exact mul_le_one₀ (PadicInt.norm_le_one _) (norm_nonneg _) h1
have : F.derivative.eval z * -z1 = -F.eval z := by
calc
F.derivative.eval z * -z1 =
@@ -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⟩⟩
@@ -275,7 +275,7 @@ private theorem newton_seq_dist_aux (n : ℕ) :
| 0 => by simp [T_pow_nonneg, mul_nonneg]
| k + 1 =>
have : 2 ^ n ≤ 2 ^ (n + k) := by
- apply pow_le_pow_right
+ apply pow_right_mono₀
· norm_num
· apply Nat.le_add_right
calc
@@ -356,7 +356,7 @@ private theorem T_pos : T > 0 := by
private theorem newton_seq_succ_dist_weak (n : ℕ) :
‖newton_seq (n + 2) - newton_seq (n + 1)‖ < ‖F.eval a‖ / ‖F.derivative.eval a‖ :=
have : 2 ≤ 2 ^ (n + 1) := by
- have := pow_le_pow_right (by norm_num : 1 ≤ 2) (Nat.le_add_left _ _ : 1 ≤ n + 1)
+ have := pow_right_mono₀ (by norm_num : 1 ≤ 2) (Nat.le_add_left _ _ : 1 ≤ n + 1)
simpa using this
calc
‖newton_seq (n + 2) - newton_seq (n + 1)‖ ≤ ‖F.derivative.eval a‖ * T ^ 2 ^ (n + 1) :=
@@ -401,7 +401,7 @@ private theorem soln_dist_to_a : ‖soln - a‖ = ‖F.eval a‖ / ‖F.derivati
tendsto_nhds_unique (newton_seq_dist_tendsto' hnorm) (newton_seq_dist_tendsto hnorm hnsol)
private theorem soln_dist_to_a_lt_deriv : ‖soln - a‖ < ‖F.derivative.eval a‖ := by
- rw [soln_dist_to_a, div_lt_iff (deriv_norm_pos _), ← sq] <;> assumption
+ rw [soln_dist_to_a, div_lt_iff₀ (deriv_norm_pos _), ← sq] <;> assumption
private theorem soln_unique (z : ℤ_[p]) (hev : F.eval z = 0)
(hnlt : ‖z - a‖ < ‖F.derivative.eval a‖) : z = soln :=
diff --git a/Mathlib/NumberTheory/Padics/PadicIntegers.lean b/Mathlib/NumberTheory/Padics/PadicIntegers.lean
index 5e22e36d43bd8..798a8c9d36b41 100644
--- a/Mathlib/NumberTheory/Padics/PadicIntegers.lean
+++ b/Mathlib/NumberTheory/Padics/PadicIntegers.lean
@@ -78,7 +78,7 @@ def subring : Subring ℚ_[p] where
zero_mem' := by norm_num
one_mem' := by norm_num
add_mem' hx hy := (padicNormE.nonarchimedean _ _).trans <| max_le_iff.2 ⟨hx, hy⟩
- mul_mem' hx hy := (padicNormE.mul _ _).trans_le <| mul_le_one hx (norm_nonneg _) hy
+ mul_mem' hx hy := (padicNormE.mul _ _).trans_le <| mul_le_one₀ hx (norm_nonneg _) hy
neg_mem' hx := (norm_neg _).trans_le hx
@[simp]
@@ -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
@@ -494,7 +493,7 @@ theorem norm_le_pow_iff_mem_span_pow (x : ℤ_[p]) (n : ℕ) :
‖x‖ ≤ (p : ℝ) ^ (-n : ℤ) ↔ x ∈ (Ideal.span {(p : ℤ_[p]) ^ n} : Ideal ℤ_[p]) := by
by_cases hx : x = 0
· subst hx
- simp only [norm_zero, zpow_neg, zpow_natCast, inv_nonneg, iff_true_iff, Submodule.zero_mem]
+ simp only [norm_zero, zpow_neg, zpow_natCast, inv_nonneg, iff_true, Submodule.zero_mem]
exact mod_cast Nat.zero_le _
rw [norm_le_pow_iff_le_valuation x hx, mem_span_pow_iff_le_valuation x hx]
@@ -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 164a53abcb173..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,14 +248,14 @@ 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]
- simp only [padicNorm.of_int, true_and_iff]
+ simp only [padicNorm.of_int, true_and]
theorem of_nat (m : ℕ) : padicNorm p m ≤ 1 :=
padicNorm.of_int (m : ℤ)
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/ProperSpace.lean b/Mathlib/NumberTheory/Padics/ProperSpace.lean
index 623f2cd1c3b45..5aeae0f7642ee 100644
--- a/Mathlib/NumberTheory/Padics/ProperSpace.lean
+++ b/Mathlib/NumberTheory/Padics/ProperSpace.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jou Glasheen, Kevin Buzzard
-/
-import Mathlib.Analysis.Normed.Module.FiniteDimension
+import Mathlib.Analysis.Normed.Field.ProperSpace
import Mathlib.NumberTheory.Padics.RingHoms
/-!
@@ -28,6 +28,9 @@ and that `ℚ_[p]` is proper.
Gouvêa, F. Q. (2020) p-adic Numbers An Introduction. 3rd edition.
Cham, Springer International Publishing
-/
+
+assert_not_exists FiniteDimensional
+
open Metric Topology
variable (p : ℕ) [Fact (Nat.Prime p)]
@@ -55,7 +58,7 @@ namespace Padic
/-- The field of p-adic numbers `ℚ_[p]` is a proper metric space. -/
instance : ProperSpace ℚ_[p] := by
- suffices LocallyCompactSpace ℚ_[p] from .of_locallyCompactSpace ℚ_[p]
+ suffices LocallyCompactSpace ℚ_[p] from .of_nontriviallyNormedField_of_weaklyLocallyCompactSpace _
have : closedBall 0 1 ∈ 𝓝 (0 : ℚ_[p]) := closedBall_mem_nhds _ zero_lt_one
simp only [closedBall, dist_eq_norm_sub, sub_zero] at this
refine IsCompact.locallyCompactSpace_of_mem_nhds_of_addGroup ?_ this
diff --git a/Mathlib/NumberTheory/Padics/RingHoms.lean b/Mathlib/NumberTheory/Padics/RingHoms.lean
index 31ba8f2ff384a..9458144550aaf 100644
--- a/Mathlib/NumberTheory/Padics/RingHoms.lean
+++ b/Mathlib/NumberTheory/Padics/RingHoms.lean
@@ -256,7 +256,7 @@ theorem toZMod_spec : x - (ZMod.cast (toZMod x) : ℤ_[p]) ∈ maximalIdeal ℤ_
dsimp [toZMod, toZModHom]
rcases Nat.exists_eq_add_of_lt hp_prime.1.pos with ⟨p', rfl⟩
change ↑((_ : ZMod (0 + p' + 1)).val) = (_ : ℤ_[0 + p' + 1])
- simp only [ZMod.val_natCast, add_zero, add_def, Nat.cast_inj, zero_add]
+ rw [Nat.cast_inj]
apply mod_eq_of_lt
simpa only [zero_add] using zmodRepr_lt_p x
@@ -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/Pell.lean b/Mathlib/NumberTheory/Pell.lean
index 4ffe309128a95..8cdd56d82e73b 100644
--- a/Mathlib/NumberTheory/Pell.lean
+++ b/Mathlib/NumberTheory/Pell.lean
@@ -206,7 +206,7 @@ theorem y_ne_zero_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : a.y ≠ 0 :=
theorem d_pos_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : 0 < d := by
refine pos_of_mul_pos_left ?_ (sq_nonneg a.y)
rw [a.prop_y, sub_pos]
- exact one_lt_pow ha two_ne_zero
+ exact one_lt_pow₀ ha two_ne_zero
/-- If a solution has `x > 1`, then `d` is not a square. -/
theorem d_nonsquare_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : ¬IsSquare d := by
@@ -305,8 +305,8 @@ theorem exists_pos_variant (h₀ : 0 < d) (a : Solution₁ d) :
(lt_or_gt_of_ne (a.x_ne_zero h₀.le)).elim
((le_total 0 a.y).elim (fun hy hx => ⟨-a⁻¹, ?_, ?_, ?_⟩) fun hy hx => ⟨-a, ?_, ?_, ?_⟩)
((le_total 0 a.y).elim (fun hy hx => ⟨a, hx, hy, ?_⟩) fun hy hx => ⟨a⁻¹, hx, ?_, ?_⟩) <;>
- simp only [neg_neg, inv_inv, neg_inv, Set.mem_insert_iff, Set.mem_singleton_iff, true_or_iff,
- eq_self_iff_true, x_neg, x_inv, y_neg, y_inv, neg_pos, neg_nonneg, or_true_iff] <;>
+ simp only [neg_neg, inv_inv, neg_inv, Set.mem_insert_iff, Set.mem_singleton_iff, true_or,
+ eq_self_iff_true, x_neg, x_inv, y_neg, y_inv, neg_pos, neg_nonneg, or_true] <;>
assumption
end Solution₁
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 92dca84e7b65e..fa1a732eddcb9 100644
--- a/Mathlib/NumberTheory/PrimeCounting.lean
+++ b/Mathlib/NumberTheory/PrimeCounting.lean
@@ -3,8 +3,8 @@ 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.Prime.Nth
import Mathlib.Data.Nat.Totient
-import Mathlib.Data.Nat.Nth
import Mathlib.NumberTheory.SmoothNumbers
/-!
@@ -56,6 +56,10 @@ def primeCounting (n : ℕ) : ℕ :=
open scoped Nat.Prime
+@[simp]
+theorem primeCounting_sub_one (n : ℕ) : π (n - 1) = π' n := by
+ cases n <;> rfl
+
theorem monotone_primeCounting' : Monotone primeCounting' :=
count_monotone Prime
@@ -66,13 +70,51 @@ theorem monotone_primeCounting : Monotone primeCounting :=
theorem primeCounting'_nth_eq (n : ℕ) : π' (nth Prime n) = n :=
count_nth_of_infinite infinite_setOf_prime _
+/-- The `n`th prime is greater or equal to `n + 2`. -/
+theorem add_two_le_nth_prime (n : ℕ) : n + 2 ≤ nth Prime n :=
+ 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
+
+theorem surjective_primeCounting : Function.Surjective π := by
+ suffices Function.Surjective (π ∘ fun n => n - 1) from this.of_comp
+ convert surjective_primeCounting'
+ ext
+ exact primeCounting_sub_one _
+
+open Filter
+
+theorem tendsto_primeCounting' : Tendsto π' atTop atTop := by
+ apply tendsto_atTop_atTop_of_monotone' monotone_primeCounting'
+ simp [Set.range_iff_surjective.mpr surjective_primeCounting']
+
+theorem tensto_primeCounting : Tendsto π atTop atTop :=
+ (tendsto_add_atTop_iff_nat 1).mpr tendsto_primeCounting'
+
@[simp]
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`. -/
-lemma 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
@@ -80,13 +122,13 @@ lemma primesBelow_card_eq_primeCounting' (n : ℕ) : n.primesBelow.card = primeC
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
@@ -98,11 +140,4 @@ theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
rw [add_le_add_iff_left]
exact Ico_filter_coprime_le k n h0
-@[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`. -/
-lemma 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
-
end Nat
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/PythagoreanTriples.lean b/Mathlib/NumberTheory/PythagoreanTriples.lean
index b2482ab6382cc..57ca7ff109082 100644
--- a/Mathlib/NumberTheory/PythagoreanTriples.lean
+++ b/Mathlib/NumberTheory/PythagoreanTriples.lean
@@ -179,7 +179,7 @@ theorem normalize : PythagoreanTriple (x / Int.gcd x y) (y / Int.gcd x y) (z / I
have hz : z = 0 := by
simpa only [PythagoreanTriple, hx, hy, add_zero, zero_eq_mul, mul_zero,
or_self_iff] using h
- simp only [hx, hy, hz, Int.zero_div]
+ simp only [hx, hy, hz]
exact zero
rcases h.gcd_dvd with ⟨z0, rfl⟩
obtain ⟨k, x0, y0, k0, h2, rfl, rfl⟩ :
@@ -462,8 +462,7 @@ theorem isPrimitiveClassified_of_coprime_of_odd_of_pos (hc : Int.gcd x y = 1) (h
let q := (circleEquivGen hQ).symm ⟨⟨v, w⟩, hp⟩
have ht4 : v = 2 * q / (1 + q ^ 2) ∧ w = (1 - q ^ 2) / (1 + q ^ 2) := by
apply Prod.mk.inj
- have := ((circleEquivGen hQ).apply_symm_apply ⟨⟨v, w⟩, hp⟩).symm
- exact congr_arg Subtype.val this
+ exact congr_arg Subtype.val ((circleEquivGen hQ).apply_symm_apply ⟨⟨v, w⟩, hp⟩).symm
let m := (q.den : ℤ)
let n := q.num
have hm0 : m ≠ 0 := by
diff --git a/Mathlib/NumberTheory/RamificationInertia.lean b/Mathlib/NumberTheory/RamificationInertia.lean
index c059ce200afdd..cd2da449ce790 100644
--- a/Mathlib/NumberTheory/RamificationInertia.lean
+++ b/Mathlib/NumberTheory/RamificationInertia.lean
@@ -47,7 +47,7 @@ variable {R : Type u} [CommRing R]
variable {S : Type v} [CommRing S] (f : R →+* S)
variable (p : Ideal R) (P : Ideal S)
-open FiniteDimensional
+open Module
open UniqueFactorizationMonoid
@@ -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,
@@ -699,7 +736,7 @@ instance Factors.finiteDimensional_quotient [IsNoetherian R S] [p.IsMaximal]
theorem Factors.inertiaDeg_ne_zero [IsNoetherian R S] [p.IsMaximal]
(P : (factors (map (algebraMap R S) p)).toFinset) : inertiaDeg (algebraMap R S) p P ≠ 0 := by
- rw [inertiaDeg_algebraMap]; exact (FiniteDimensional.finrank_pos_iff.mpr inferInstance).ne'
+ rw [inertiaDeg_algebraMap]; exact (Module.finrank_pos_iff.mpr inferInstance).ne'
instance Factors.finiteDimensional_quotient_pow [IsNoetherian R S] [p.IsMaximal]
(P : (factors (map (algebraMap R S) p)).toFinset) :
@@ -793,4 +830,69 @@ theorem sum_ramification_inertia (K L : Type*) [Field K] [Field L] [IsDedekindDo
end FactorsMap
+section tower
+
+variable {R S T : Type*} [CommRing R] [CommRing S] [CommRing T]
+
+theorem ramificationIdx_tower [IsDedekindDomain S] [IsDedekindDomain T] {f : R →+* S} {g : S →+* T}
+ {p : Ideal R} {P : Ideal S} {Q : Ideal T} [hpm : P.IsPrime] [hqm : Q.IsPrime]
+ (hg0 : map g P ≠ ⊥) (hfg : map (g.comp f) p ≠ ⊥) (hg : map g P ≤ Q) :
+ ramificationIdx (g.comp f) p Q = ramificationIdx f p P * ramificationIdx g P Q := by
+ classical
+ have hf0 : map f p ≠ ⊥ :=
+ ne_bot_of_map_ne_bot (Eq.mp (congrArg (fun I ↦ I ≠ ⊥) (map_map f g).symm) hfg)
+ have hp0 : P ≠ ⊥ := ne_bot_of_map_ne_bot hg0
+ have hq0 : Q ≠ ⊥ := ne_bot_of_le_ne_bot hg0 hg
+ letI : P.IsMaximal := Ring.DimensionLEOne.maximalOfPrime hp0 hpm
+ rw [IsDedekindDomain.ramificationIdx_eq_normalizedFactors_count hf0 hpm hp0,
+ IsDedekindDomain.ramificationIdx_eq_normalizedFactors_count hg0 hqm hq0,
+ IsDedekindDomain.ramificationIdx_eq_normalizedFactors_count hfg hqm hq0, ← map_map]
+ rcases eq_prime_pow_mul_coprime hf0 P with ⟨I, hcp, heq⟩
+ have hcp : ⊤ = map g P ⊔ map g I := by rw [← map_sup, hcp, map_top g]
+ have hntq : ¬ ⊤ ≤ Q := fun ht ↦ IsPrime.ne_top hqm (Iff.mpr (eq_top_iff_one Q) (ht trivial))
+ nth_rw 1 [heq, map_mul, Ideal.map_pow, normalizedFactors_mul (pow_ne_zero _ hg0) <| by
+ by_contra h
+ simp only [h, Submodule.zero_eq_bot, bot_le, sup_of_le_left] at hcp
+ exact hntq (hcp.trans_le hg), Multiset.count_add, normalizedFactors_pow, Multiset.count_nsmul]
+ exact add_right_eq_self.mpr <| Decidable.byContradiction fun h ↦ hntq <| hcp.trans_le <|
+ sup_le hg <| le_of_dvd <| dvd_of_mem_normalizedFactors <| Multiset.count_ne_zero.mp h
+
+attribute [local instance] Quotient.field in
+theorem inertiaDeg_tower {f : R →+* S} {g : S →+* T} {p : Ideal R} {P : Ideal S} {I : Ideal T}
+ [p.IsMaximal] [P.IsMaximal] (hp : p = comap f P) (hP : P = comap g I) :
+ inertiaDeg (g.comp f) p I = inertiaDeg f p P * inertiaDeg g P I := by
+ have h : comap (g.comp f) I = p := by rw [hp, hP, comap_comap]
+ simp only [inertiaDeg, dif_pos hp.symm, dif_pos hP.symm, dif_pos h]
+ letI : Algebra (R ⧸ p) (S ⧸ P) := Ideal.Quotient.algebraQuotientOfLEComap (le_of_eq hp)
+ letI : Algebra (S ⧸ P) (T ⧸ I) := Ideal.Quotient.algebraQuotientOfLEComap (le_of_eq hP)
+ letI : Algebra (R ⧸ p) (T ⧸ I) := Ideal.Quotient.algebraQuotientOfLEComap (le_of_eq h.symm)
+ letI : IsScalarTower (R ⧸ p) (S ⧸ P) (T ⧸ I) := IsScalarTower.of_algebraMap_eq (by rintro ⟨⟩; rfl)
+ exact (finrank_mul_finrank (R ⧸ p) (S ⧸ P) (T ⧸ I)).symm
+
+variable [Algebra R S] [Algebra S T] [Algebra R T] [IsScalarTower R S T]
+
+/-- Let `T / S / R` be a tower of algebras, `p, P, Q` be ideals in `R, S, T` respectively,
+ and `P` and `Q` are prime. If `P = Q ∩ S`, then `e (Q | p) = e (P | p) * e (Q | P)`. -/
+theorem ramificationIdx_algebra_tower [IsDedekindDomain S] [IsDedekindDomain T]
+ {p : Ideal R} {P : Ideal S} {Q : Ideal T} [hpm : P.IsPrime] [hqm : Q.IsPrime]
+ (hg0 : map (algebraMap S T) P ≠ ⊥)
+ (hfg : map (algebraMap R T) p ≠ ⊥) (hg : map (algebraMap S T) P ≤ Q) :
+ ramificationIdx (algebraMap R T) p Q =
+ ramificationIdx (algebraMap R S) p P * ramificationIdx (algebraMap S T) P Q := by
+ classical
+ rw [IsScalarTower.algebraMap_eq R S T] at hfg ⊢
+ exact ramificationIdx_tower hg0 hfg hg
+
+/-- Let `T / S / R` be a tower of algebras, `p, P, I` be ideals in `R, S, T`, respectively,
+ and `p` and `P` are maximal. If `p = P ∩ S` and `P = Q ∩ S`,
+ then `f (Q | p) = f (P | p) * f (Q | P)`. -/
+theorem inertiaDeg_algebra_tower {p : Ideal R} {P : Ideal S} {I : Ideal T} [p.IsMaximal]
+ [P.IsMaximal] (hp : p = comap (algebraMap R S) P) (hP : P = comap (algebraMap S T) I) :
+ inertiaDeg (algebraMap R T) p I =
+ inertiaDeg (algebraMap R S) p P * inertiaDeg (algebraMap S T) P I := by
+ rw [IsScalarTower.algebraMap_eq R S T]
+ exact inertiaDeg_tower hp hP
+
+end tower
+
end Ideal
diff --git a/Mathlib/NumberTheory/Rayleigh.lean b/Mathlib/NumberTheory/Rayleigh.lean
index d7a2e5f205472..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).
-/
@@ -63,9 +63,9 @@ private theorem no_collision (hrs : r.IsConjExponent s) :
Disjoint {beattySeq r k | k} {beattySeq' s k | k} := by
rw [Set.disjoint_left]
intro j ⟨k, h₁⟩ ⟨m, h₂⟩
- rw [beattySeq, Int.floor_eq_iff, ← div_le_iff₀ hrs.pos, ← lt_div_iff hrs.pos] at h₁
+ rw [beattySeq, Int.floor_eq_iff, ← div_le_iff₀ hrs.pos, ← lt_div_iff₀ hrs.pos] at h₁
rw [beattySeq', sub_eq_iff_eq_add, Int.ceil_eq_iff, Int.cast_add, Int.cast_one,
- add_sub_cancel_right, ← div_lt_iff hrs.symm.pos, ← le_div_iff₀ hrs.symm.pos] at h₂
+ add_sub_cancel_right, ← div_lt_iff₀ hrs.symm.pos, ← le_div_iff₀ hrs.symm.pos] at h₂
have h₃ := add_lt_add_of_le_of_lt h₁.1 h₂.1
have h₄ := add_lt_add_of_lt_of_le h₁.2 h₂.2
simp_rw [div_eq_inv_mul, ← right_distrib, hrs.inv_add_inv_conj, one_mul] at h₃ h₄
@@ -91,10 +91,10 @@ private theorem hit_or_miss (h : r > 0) :
-- for both cases, the candidate is `k = ⌈(j + 1) / r⌉ - 1`
cases lt_or_ge ((⌈(j + 1) / r⌉ - 1) * r) j
· refine Or.inr ⟨⌈(j + 1) / r⌉ - 1, ?_⟩
- rw [Int.cast_sub, Int.cast_one, lt_div_iff h, sub_add_cancel]
+ rw [Int.cast_sub, Int.cast_one, lt_div_iff₀ h, sub_add_cancel]
exact ⟨‹_›, Int.le_ceil _⟩
· refine Or.inl ⟨⌈(j + 1) / r⌉ - 1, ?_⟩
- rw [beattySeq, Int.floor_eq_iff, Int.cast_sub, Int.cast_one, ← lt_div_iff h, sub_lt_iff_lt_add]
+ rw [beattySeq, Int.floor_eq_iff, Int.cast_sub, Int.cast_one, ← lt_div_iff₀ h, sub_lt_iff_lt_add]
exact ⟨‹_›, Int.ceil_lt_add_one _⟩
/-- Let `0 < r ∈ ℝ` and `j ∈ ℤ`. Then either `j ∈ B'_r` or `B'_r` jumps over `j`. -/
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/SmoothNumbers.lean b/Mathlib/NumberTheory/SmoothNumbers.lean
index 18f25f9900202..a130280fc2731 100644
--- a/Mathlib/NumberTheory/SmoothNumbers.lean
+++ b/Mathlib/NumberTheory/SmoothNumbers.lean
@@ -233,7 +233,7 @@ def equivProdNatFactoredNumbers {s : Finset ℕ} {p : ℕ} (hp : p.Prime) (hs :
refine prod_eq <|
(filter _ <| perm_primeFactorsList_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
rw [filter_append, hp.primeFactorsList_pow,
- filter_eq_nil.mpr fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2, hs],
+ filter_eq_nil_iff.mpr fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2, hs],
nil_append, filter_eq_self.mpr fun q hq ↦ by simp only [hm q hq, decide_True]]
right_inv := by
rintro ⟨m, hm₀, hm⟩
diff --git a/Mathlib/NumberTheory/Zsqrtd/Basic.lean b/Mathlib/NumberTheory/Zsqrtd/Basic.lean
index acbc027998af2..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
@@ -893,8 +893,8 @@ theorem norm_eq_zero {d : ℤ} (h_nonsquare : ∀ n : ℤ, d ≠ n * n) (a : ℤ
· push_neg at h
suffices a.re * a.re = 0 by
rw [eq_zero_of_mul_self_eq_zero this] at ha ⊢
- simpa only [true_and_iff, or_self_right, zero_re, zero_im, eq_self_iff_true, zero_eq_mul,
- mul_zero, mul_eq_zero, h.ne, false_or_iff, or_self_iff] using ha
+ simpa only [true_and, or_self_right, zero_re, zero_im, eq_self_iff_true, zero_eq_mul,
+ mul_zero, mul_eq_zero, h.ne, false_or, or_self_iff] using ha
apply _root_.le_antisymm _ (mul_self_nonneg _)
rw [ha, mul_assoc]
exact mul_nonpos_of_nonpos_of_nonneg h.le (mul_self_nonneg _)
@@ -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 67458503b39b9..fb57460b6d250 100644
--- a/Mathlib/Order/Basic.lean
+++ b/Mathlib/Order/Basic.lean
@@ -186,7 +186,7 @@ end
namespace Eq
-variable [Preorder α] {x y z : α}
+variable [Preorder α] {x y : α}
/-- If `x = y` then `y ≤ x`. Note: this lemma uses `y ≤ x` instead of `x ≥ y`, because `le` is used
almost exclusively in mathlib. -/
@@ -308,7 +308,7 @@ alias LE.le.eq_iff_not_lt := eq_iff_not_lt_of_le
protected theorem Decidable.eq_iff_le_not_lt [@DecidableRel α (· ≤ ·)] :
a = b ↔ a ≤ b ∧ ¬a < b :=
⟨fun h ↦ ⟨h.le, h ▸ lt_irrefl _⟩, fun ⟨h₁, h₂⟩ ↦
- h₁.antisymm <| Decidable.by_contradiction fun h₃ ↦ h₂ (h₁.lt_of_not_le h₃)⟩
+ h₁.antisymm <| Decidable.byContradiction fun h₃ ↦ h₂ (h₁.lt_of_not_le h₃)⟩
theorem eq_iff_le_not_lt : a = b ↔ a ≤ b ∧ ¬a < b :=
haveI := Classical.dec
@@ -463,11 +463,12 @@ theorem commutative_of_le {f : β → β → α} (comm : ∀ a b, f a b ≤ f b
/-- To prove associativity of a commutative binary operation `○`, we only to check
`(a ○ b) ○ c ≤ a ○ (b ○ c)` for all `a`, `b`, `c`. -/
-theorem associative_of_commutative_of_le {f : α → α → α} (comm : Commutative f)
- (assoc : ∀ a b c, f (f a b) c ≤ f a (f b c)) : Associative f := fun a b c ↦
- le_antisymm (assoc _ _ _) <| by
- rw [comm, comm b, comm _ c, comm a]
- exact assoc _ _ _
+theorem associative_of_commutative_of_le {f : α → α → α} (comm : Std.Commutative f)
+ (assoc : ∀ a b c, f (f a b) c ≤ f a (f b c)) : Std.Associative f where
+ assoc a b c :=
+ le_antisymm (assoc _ _ _) <| by
+ rw [comm.comm, comm.comm b, comm.comm _ c, comm.comm a]
+ exact assoc _ _ _
end PartialOrder
@@ -710,6 +711,10 @@ instance instLinearOrder (α : Type*) [LinearOrder α] : LinearOrder αᵒᵈ wh
decidableLE := (inferInstance : DecidableRel (fun a b : α ↦ b ≤ a))
decidableLT := (inferInstance : DecidableRel (fun a b : α ↦ b < a))
+/-- The opposite linear order to a given linear order -/
+def _root_.LinearOrder.swap (α : Type*) (_ : LinearOrder α) : LinearOrder α :=
+ inferInstanceAs <| LinearOrder (OrderDual α)
+
instance : ∀ [Inhabited α], Inhabited αᵒᵈ := fun [x : Inhabited α] => x
theorem Preorder.dual_dual (α : Type*) [H : Preorder α] : OrderDual.instPreorder αᵒᵈ = H :=
@@ -749,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 -/
@@ -762,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
@@ -1100,7 +1110,8 @@ instance (α β : Type*) [LE α] [LE β] : LE (α × β) :=
-- Porting note (#10754): new instance
instance instDecidableLE (α β : Type*) [LE α] [LE β] (x y : α × β)
- [Decidable (x.1 ≤ y.1)] [Decidable (x.2 ≤ y.2)] : Decidable (x ≤ y) := And.decidable
+ [Decidable (x.1 ≤ y.1)] [Decidable (x.2 ≤ y.2)] : Decidable (x ≤ y) :=
+ inferInstanceAs (Decidable (x.1 ≤ y.1 ∧ x.2 ≤ y.2))
theorem le_def [LE α] [LE β] {x y : α × β} : x ≤ y ↔ x.1 ≤ y.1 ∧ x.2 ≤ y.2 :=
Iff.rfl
@@ -1120,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 :=
@@ -1277,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 dd3aa408d0c38..1b2c1d9c34ad8 100644
--- a/Mathlib/Order/Booleanisation.lean
+++ b/Mathlib/Order/Booleanisation.lean
@@ -58,7 +58,7 @@ instance instCompl : HasCompl (Booleanisation α) where
@[simp] lemma compl_lift (a : α) : (lift a)ᶜ = comp a := rfl
@[simp] lemma compl_comp (a : α) : (comp a)ᶜ = lift a := rfl
-variable [GeneralizedBooleanAlgebra α] {x y : Booleanisation α} {a b : α}
+variable [GeneralizedBooleanAlgebra α] {a b : α}
/-- The order on `Booleanisation α` is as follows: For `a b : α`,
* `a ≤ b` iff `a ≤ b` in `α`
@@ -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 eebe3d3ddcdd1..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 -/
@@ -84,6 +85,15 @@ theorem ne_top_of_lt (h : a < b) : a ≠ ⊤ :=
alias LT.lt.ne_top := ne_top_of_lt
+theorem lt_top_of_lt (h : a < b) : a < ⊤ :=
+ lt_of_lt_of_le h le_top
+
+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 : α}
@@ -129,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
@@ -253,6 +264,11 @@ theorem ne_bot_of_gt (h : a < b) : b ≠ ⊥ :=
alias LT.lt.ne_bot := ne_bot_of_gt
+theorem bot_lt_of_lt (h : a < b) : ⊥ < b :=
+ lt_of_le_of_lt bot_le h
+
+alias LT.lt.bot_lt := bot_lt_of_lt
+
end Preorder
variable [PartialOrder α] [OrderBot α] [Preorder β] {f : α → β} {a b : α}
@@ -343,7 +359,7 @@ theorem OrderBot.ext_bot {α} {hA : PartialOrder α} (A : OrderBot α) {hB : Par
section SemilatticeSupTop
-variable [SemilatticeSup α] [OrderTop α] {a : α}
+variable [SemilatticeSup α] [OrderTop α]
-- Porting note: Not simp because simp can prove it
theorem top_sup_eq (a : α) : ⊤ ⊔ a = ⊤ :=
@@ -390,7 +406,7 @@ end SemilatticeInfTop
section SemilatticeInfBot
-variable [SemilatticeInf α] [OrderBot α] {a : α}
+variable [SemilatticeInf α] [OrderBot α]
-- Porting note: Not simp because simp can prove it
lemma bot_inf_eq (a : α) : ⊥ ⊓ a = ⊥ := inf_of_le_left bot_le
@@ -493,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
@@ -503,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 534374839904e..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₂
@@ -759,7 +714,7 @@ theorem nonempty_of_not_bddBelow [Nonempty α] (h : ¬BddBelow s) : s.Nonempty :
@[simp]
theorem bddAbove_insert [IsDirected α (· ≤ ·)] {s : Set α} {a : α} :
BddAbove (insert a s) ↔ BddAbove s := by
- simp only [insert_eq, bddAbove_union, bddAbove_singleton, true_and_iff]
+ simp only [insert_eq, bddAbove_union, bddAbove_singleton, true_and]
protected theorem BddAbove.insert [IsDirected α (· ≤ ·)] {s : Set α} (a : α) :
BddAbove s → BddAbove (insert a s) :=
@@ -769,7 +724,7 @@ protected theorem BddAbove.insert [IsDirected α (· ≤ ·)] {s : Set α} (a :
@[simp]
theorem bddBelow_insert [IsDirected α (· ≥ ·)] {s : Set α} {a : α} :
BddBelow (insert a s) ↔ BddBelow s := by
- simp only [insert_eq, bddBelow_union, bddBelow_singleton, true_and_iff]
+ simp only [insert_eq, bddBelow_union, bddBelow_singleton, true_and]
protected theorem BddBelow.insert [IsDirected α (· ≥ ·)] {s : Set α} (a : α) :
BddBelow s → BddBelow (insert a s) :=
@@ -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 5a2890bd05342..f3bc338a1d2ea 100644
--- a/Mathlib/Order/CompactlyGenerated/Basic.lean
+++ b/Mathlib/Order/CompactlyGenerated/Basic.lean
@@ -129,7 +129,7 @@ theorem isCompactElement_iff_le_of_directed_sSup_le (k : α) :
apply sSup_le_sSup
intro x hx
use {x}
- simpa only [and_true_iff, id, Finset.coe_singleton, eq_self_iff_true,
+ simpa only [and_true, id, Finset.coe_singleton, eq_self_iff_true,
Finset.sup_singleton, Set.singleton_subset_iff]
have Sne : S.Nonempty := by
suffices ⊥ ∈ S from Set.nonempty_of_mem this
@@ -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,43 +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
- · exact WellFounded.isSupFiniteCompact α
- tfae_have 2 → 3
- · exact IsSupFiniteCompact.isSupClosedCompact α
- tfae_have 3 → 1
- · exact IsSupClosedCompact.wellFounded α
- tfae_have 2 ↔ 4
- · exact isSupFiniteCompact_iff_all_elements_compact α
+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.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
@@ -296,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
@@ -317,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) :
@@ -332,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⟩⟩
@@ -398,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]
@@ -456,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 4bd82d405b971..9fd8b1100315f 100644
--- a/Mathlib/Order/Compare.lean
+++ b/Mathlib/Order/Compare.lean
@@ -31,33 +31,15 @@ def cmpLE {α} [LE α] [@DecidableRel α (· ≤ ·)] (x y : α) : Ordering :=
theorem cmpLE_swap {α} [LE α] [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (x y : α) :
(cmpLE x y).swap = cmpLE y x := by
by_cases xy : x ≤ y <;> by_cases yx : y ≤ x <;> simp [cmpLE, *, Ordering.swap]
- cases not_or_of_not xy yx (total_of _ _ _)
+ cases not_or_intro xy yx (total_of _ _ _)
theorem cmpLE_eq_cmp {α} [Preorder α] [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)]
[@DecidableRel α (· < ·)] (x y : α) : cmpLE x y = cmp x y := by
by_cases xy : x ≤ y <;> by_cases yx : y ≤ x <;> simp [cmpLE, lt_iff_le_not_le, *, cmp, cmpUsing]
- cases not_or_of_not xy yx (total_of _ _ _)
+ cases not_or_intro xy yx (total_of _ _ _)
namespace Ordering
-/-- `Compares o a b` means that `a` and `b` have the ordering relation `o` between them, assuming
-that the relation `a < b` is defined. -/
--- Porting note: we have removed `@[simp]` here in favour of separate simp lemmas,
--- otherwise this definition will unfold to a match.
-def Compares [LT α] : Ordering → α → α → Prop
- | lt, a, b => a < b
- | eq, a, b => a = b
- | gt, a, b => a > b
-
-@[simp]
-lemma compares_lt [LT α] (a b : α) : Compares lt a b = (a < b) := rfl
-
-@[simp]
-lemma compares_eq [LT α] (a b : α) : Compares eq a b = (a = b) := rfl
-
-@[simp]
-lemma compares_gt [LT α] (a b : α) : Compares gt a b = (a > b) := rfl
-
theorem compares_swap [LT α] {a b : α} {o : Ordering} : o.swap.Compares a b ↔ o.Compares b a := by
cases o
· exact Iff.rfl
@@ -70,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 :=
@@ -118,11 +100,13 @@ theorem compares_iff_of_compares_impl [LinearOrder α] [Preorder β] {a b : α}
· have hab : Compares Ordering.gt a b := hab
rwa [ho.inj (h hab)]
-theorem swap_orElse (o₁ o₂) : (orElse o₁ o₂).swap = orElse o₁.swap o₂.swap := by
- cases o₁ <;> rfl
+set_option linter.deprecated false in
+@[deprecated swap_then (since := "2024-09-13")]
+theorem swap_orElse (o₁ o₂) : (orElse o₁ o₂).swap = orElse o₁.swap o₂.swap := swap_then ..
-theorem orElse_eq_lt (o₁ o₂) : orElse o₁ o₂ = lt ↔ o₁ = lt ∨ o₁ = eq ∧ o₂ = lt := by
- cases o₁ <;> cases o₂ <;> decide
+set_option linter.deprecated false in
+@[deprecated then_eq_lt (since := "2024-09-13")]
+theorem orElse_eq_lt (o₁ o₂) : orElse o₁ o₂ = lt ↔ o₁ = lt ∨ o₁ = eq ∧ o₂ = lt := then_eq_lt ..
end Ordering
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 dd660dbea66f8..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⟩
@@ -757,6 +758,12 @@ theorem sSup_eq_iSup {s : Set α} : sSup s = ⨆ a ∈ s, a :=
theorem sInf_eq_iInf {s : Set α} : sInf s = ⨅ a ∈ s, a :=
@sSup_eq_iSup αᵒᵈ _ _
+lemma sSup_lowerBounds_eq_sInf (s : Set α) : sSup (lowerBounds s) = sInf s :=
+ (isLUB_sSup _).unique (isGLB_sInf _).isLUB
+
+lemma sInf_upperBounds_eq_csSup (s : Set α) : sInf (upperBounds s) = sSup s :=
+ (isGLB_sInf _).unique (isLUB_sSup _).isGLB
+
theorem Monotone.le_map_iSup [CompleteLattice β] {f : α → β} (hf : Monotone f) :
⨆ i, f (s i) ≤ f (iSup s) :=
iSup_le fun _ => hf <| le_iSup _ _
@@ -1066,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` -/
@@ -1221,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) :=
@@ -1320,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]
@@ -1533,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
new file mode 100644
index 0000000000000..b02e5eb918efa
--- /dev/null
+++ b/Mathlib/Order/CompleteLattice/Finset.lean
@@ -0,0 +1,247 @@
+/-
+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.Data.Finset.Option
+import Mathlib.Data.Set.Lattice
+
+/-!
+# Lattice operations on finsets
+
+This file is concerned with how big lattice or set operations behave when indexed by a finset.
+
+See also Lattice.lean, which is concerned with folding binary lattice operations over a finset.
+-/
+
+assert_not_exists OrderedCommMonoid
+assert_not_exists MonoidWithZero
+
+open Function Multiset OrderDual
+
+variable {F α β γ ι κ : Type*}
+
+section Lattice
+
+variable {ι' : Sort*} [CompleteLattice α]
+
+/-- Supremum of `s i`, `i : ι`, is equal to the supremum over `t : Finset ι` of suprema
+`⨆ i ∈ t, s i`. This version assumes `ι` is a `Type*`. See `iSup_eq_iSup_finset'` for a version
+that works for `ι : Sort*`. -/
+theorem iSup_eq_iSup_finset (s : ι → α) : ⨆ i, s i = ⨆ t : Finset ι, ⨆ i ∈ t, s i := by
+ classical
+ refine le_antisymm ?_ ?_
+ · exact iSup_le fun b => le_iSup_of_le {b} <| le_iSup_of_le b <| le_iSup_of_le (by simp) <| le_rfl
+ · exact iSup_le fun t => iSup_le fun b => iSup_le fun _ => le_iSup _ _
+
+/-- Supremum of `s i`, `i : ι`, is equal to the supremum over `t : Finset ι` of suprema
+`⨆ i ∈ t, s i`. This version works for `ι : Sort*`. See `iSup_eq_iSup_finset` for a version
+that assumes `ι : Type*` but has no `PLift`s. -/
+theorem iSup_eq_iSup_finset' (s : ι' → α) :
+ ⨆ i, s i = ⨆ t : Finset (PLift ι'), ⨆ i ∈ t, s (PLift.down i) := by
+ rw [← iSup_eq_iSup_finset, ← Equiv.plift.surjective.iSup_comp]; rfl
+
+/-- Infimum of `s i`, `i : ι`, is equal to the infimum over `t : Finset ι` of infima
+`⨅ i ∈ t, s i`. This version assumes `ι` is a `Type*`. See `iInf_eq_iInf_finset'` for a version
+that works for `ι : Sort*`. -/
+theorem iInf_eq_iInf_finset (s : ι → α) : ⨅ i, s i = ⨅ (t : Finset ι) (i ∈ t), s i :=
+ @iSup_eq_iSup_finset αᵒᵈ _ _ _
+
+/-- Infimum of `s i`, `i : ι`, is equal to the infimum over `t : Finset ι` of infima
+`⨅ i ∈ t, s i`. This version works for `ι : Sort*`. See `iInf_eq_iInf_finset` for a version
+that assumes `ι : Type*` but has no `PLift`s. -/
+theorem iInf_eq_iInf_finset' (s : ι' → α) :
+ ⨅ i, s i = ⨅ t : Finset (PLift ι'), ⨅ i ∈ t, s (PLift.down i) :=
+ @iSup_eq_iSup_finset' αᵒᵈ _ _ _
+
+end Lattice
+
+namespace Set
+
+variable {ι' : Sort*}
+
+/-- Union of an indexed family of sets `s : ι → Set α` is equal to the union of the unions
+of finite subfamilies. This version assumes `ι : Type*`. See also `iUnion_eq_iUnion_finset'` for
+a version that works for `ι : Sort*`. -/
+theorem iUnion_eq_iUnion_finset (s : ι → Set α) : ⋃ i, s i = ⋃ t : Finset ι, ⋃ i ∈ t, s i :=
+ iSup_eq_iSup_finset s
+
+/-- Union of an indexed family of sets `s : ι → Set α` is equal to the union of the unions
+of finite subfamilies. This version works for `ι : Sort*`. See also `iUnion_eq_iUnion_finset` for
+a version that assumes `ι : Type*` but avoids `PLift`s in the right hand side. -/
+theorem iUnion_eq_iUnion_finset' (s : ι' → Set α) :
+ ⋃ i, s i = ⋃ t : Finset (PLift ι'), ⋃ i ∈ t, s (PLift.down i) :=
+ iSup_eq_iSup_finset' s
+
+/-- Intersection of an indexed family of sets `s : ι → Set α` is equal to the intersection of the
+intersections of finite subfamilies. This version assumes `ι : Type*`. See also
+`iInter_eq_iInter_finset'` for a version that works for `ι : Sort*`. -/
+theorem iInter_eq_iInter_finset (s : ι → Set α) : ⋂ i, s i = ⋂ t : Finset ι, ⋂ i ∈ t, s i :=
+ iInf_eq_iInf_finset s
+
+/-- Intersection of an indexed family of sets `s : ι → Set α` is equal to the intersection of the
+intersections of finite subfamilies. This version works for `ι : Sort*`. See also
+`iInter_eq_iInter_finset` for a version that assumes `ι : Type*` but avoids `PLift`s in the right
+hand side. -/
+theorem iInter_eq_iInter_finset' (s : ι' → Set α) :
+ ⋂ i, s i = ⋂ t : Finset (PLift ι'), ⋂ i ∈ t, s (PLift.down i) :=
+ iInf_eq_iInf_finset' s
+
+end Set
+
+namespace Finset
+
+section minimal
+
+variable [DecidableEq α] {P : Finset α → Prop} {s : Finset α}
+
+theorem maximal_iff_forall_insert (hP : ∀ ⦃s t⦄, P t → s ⊆ t → P s) :
+ Maximal P s ↔ P s ∧ ∀ x ∉ s, ¬ P (insert x s) := by
+ simp only [Maximal, and_congr_right_iff]
+ exact fun _ ↦ ⟨fun h x hxs hx ↦ hxs <| h hx (subset_insert _ _) (mem_insert_self x s),
+ fun h t ht hst x hxt ↦ by_contra fun hxs ↦ h x hxs (hP ht (insert_subset hxt hst))⟩
+
+theorem minimal_iff_forall_diff_singleton (hP : ∀ ⦃s t⦄, P t → t ⊆ s → P s) :
+ Minimal P s ↔ P s ∧ ∀ x ∈ s, ¬ P (s.erase x) where
+ mp h := ⟨h.prop, fun x hxs hx ↦ by simpa using h.le_of_le hx (erase_subset _ _) hxs⟩
+ mpr h := ⟨h.1, fun t ht hts x hxs ↦ by_contra fun hxt ↦
+ h.2 x hxs <| hP ht (subset_erase.2 ⟨hts, hxt⟩)⟩
+
+end minimal
+
+/-! ### Interaction with big lattice/set operations -/
+
+section Lattice
+
+theorem iSup_coe [SupSet β] (f : α → β) (s : Finset α) : ⨆ x ∈ (↑s : Set α), f x = ⨆ x ∈ s, f x :=
+ rfl
+
+theorem iInf_coe [InfSet β] (f : α → β) (s : Finset α) : ⨅ x ∈ (↑s : Set α), f x = ⨅ x ∈ s, f x :=
+ rfl
+
+variable [CompleteLattice β]
+
+theorem iSup_singleton (a : α) (s : α → β) : ⨆ x ∈ ({a} : Finset α), s x = s a := by simp
+
+theorem iInf_singleton (a : α) (s : α → β) : ⨅ x ∈ ({a} : Finset α), s x = s a := by simp
+
+theorem iSup_option_toFinset (o : Option α) (f : α → β) : ⨆ x ∈ o.toFinset, f x = ⨆ x ∈ o, f x := by
+ simp
+
+theorem iInf_option_toFinset (o : Option α) (f : α → β) : ⨅ x ∈ o.toFinset, f x = ⨅ x ∈ o, f x :=
+ @iSup_option_toFinset _ βᵒᵈ _ _ _
+
+variable [DecidableEq α]
+
+theorem iSup_union {f : α → β} {s t : Finset α} :
+ ⨆ x ∈ s ∪ t, f x = (⨆ x ∈ s, f x) ⊔ ⨆ x ∈ t, f x := by simp [iSup_or, iSup_sup_eq]
+
+theorem iInf_union {f : α → β} {s t : Finset α} :
+ ⨅ x ∈ s ∪ t, f x = (⨅ x ∈ s, f x) ⊓ ⨅ x ∈ t, f x :=
+ @iSup_union α βᵒᵈ _ _ _ _ _
+
+theorem iSup_insert (a : α) (s : Finset α) (t : α → β) :
+ ⨆ x ∈ insert a s, t x = t a ⊔ ⨆ x ∈ s, t x := by
+ rw [insert_eq]
+ simp only [iSup_union, Finset.iSup_singleton]
+
+theorem iInf_insert (a : α) (s : Finset α) (t : α → β) :
+ ⨅ x ∈ insert a s, t x = t a ⊓ ⨅ x ∈ s, t x :=
+ @iSup_insert α βᵒᵈ _ _ _ _ _
+
+theorem iSup_finset_image {f : γ → α} {g : α → β} {s : Finset γ} :
+ ⨆ x ∈ s.image f, g x = ⨆ y ∈ s, g (f y) := by rw [← iSup_coe, coe_image, iSup_image, iSup_coe]
+
+theorem iInf_finset_image {f : γ → α} {g : α → β} {s : Finset γ} :
+ ⨅ x ∈ s.image f, g x = ⨅ y ∈ s, g (f y) := by rw [← iInf_coe, coe_image, iInf_image, iInf_coe]
+
+theorem iSup_insert_update {x : α} {t : Finset α} (f : α → β) {s : β} (hx : x ∉ t) :
+ ⨆ i ∈ insert x t, Function.update f x s i = s ⊔ ⨆ i ∈ t, f i := by
+ simp only [Finset.iSup_insert, update_same]
+ rcongr (i hi); apply update_noteq; rintro rfl; exact hx hi
+
+theorem iInf_insert_update {x : α} {t : Finset α} (f : α → β) {s : β} (hx : x ∉ t) :
+ ⨅ i ∈ insert x t, update f x s i = s ⊓ ⨅ i ∈ t, f i :=
+ @iSup_insert_update α βᵒᵈ _ _ _ _ f _ hx
+
+theorem iSup_biUnion (s : Finset γ) (t : γ → Finset α) (f : α → β) :
+ ⨆ y ∈ s.biUnion t, f y = ⨆ (x ∈ s) (y ∈ t x), f y := by simp [@iSup_comm _ α, iSup_and]
+
+theorem iInf_biUnion (s : Finset γ) (t : γ → Finset α) (f : α → β) :
+ ⨅ y ∈ s.biUnion t, f y = ⨅ (x ∈ s) (y ∈ t x), f y :=
+ @iSup_biUnion _ βᵒᵈ _ _ _ _ _ _
+
+end Lattice
+
+theorem set_biUnion_coe (s : Finset α) (t : α → Set β) : ⋃ x ∈ (↑s : Set α), t x = ⋃ x ∈ s, t x :=
+ rfl
+
+theorem set_biInter_coe (s : Finset α) (t : α → Set β) : ⋂ x ∈ (↑s : Set α), t x = ⋂ x ∈ s, t x :=
+ rfl
+
+theorem set_biUnion_singleton (a : α) (s : α → Set β) : ⋃ x ∈ ({a} : Finset α), s x = s a :=
+ iSup_singleton a s
+
+theorem set_biInter_singleton (a : α) (s : α → Set β) : ⋂ x ∈ ({a} : Finset α), s x = s a :=
+ iInf_singleton a s
+
+@[simp]
+theorem set_biUnion_preimage_singleton (f : α → β) (s : Finset β) :
+ ⋃ y ∈ s, f ⁻¹' {y} = f ⁻¹' s :=
+ Set.biUnion_preimage_singleton f s
+
+theorem set_biUnion_option_toFinset (o : Option α) (f : α → Set β) :
+ ⋃ x ∈ o.toFinset, f x = ⋃ x ∈ o, f x :=
+ iSup_option_toFinset o f
+
+theorem set_biInter_option_toFinset (o : Option α) (f : α → Set β) :
+ ⋂ x ∈ o.toFinset, f x = ⋂ x ∈ o, f x :=
+ iInf_option_toFinset o f
+
+theorem subset_set_biUnion_of_mem {s : Finset α} {f : α → Set β} {x : α} (h : x ∈ s) :
+ f x ⊆ ⋃ y ∈ s, f y :=
+ show f x ≤ ⨆ y ∈ s, f y from le_iSup_of_le x <| by simp only [h, iSup_pos, le_refl]
+
+variable [DecidableEq α]
+
+theorem set_biUnion_union (s t : Finset α) (u : α → Set β) :
+ ⋃ x ∈ s ∪ t, u x = (⋃ x ∈ s, u x) ∪ ⋃ x ∈ t, u x :=
+ iSup_union
+
+theorem set_biInter_inter (s t : Finset α) (u : α → Set β) :
+ ⋂ x ∈ s ∪ t, u x = (⋂ x ∈ s, u x) ∩ ⋂ x ∈ t, u x :=
+ iInf_union
+
+theorem set_biUnion_insert (a : α) (s : Finset α) (t : α → Set β) :
+ ⋃ x ∈ insert a s, t x = t a ∪ ⋃ x ∈ s, t x :=
+ iSup_insert a s t
+
+theorem set_biInter_insert (a : α) (s : Finset α) (t : α → Set β) :
+ ⋂ x ∈ insert a s, t x = t a ∩ ⋂ x ∈ s, t x :=
+ iInf_insert a s t
+
+theorem set_biUnion_finset_image {f : γ → α} {g : α → Set β} {s : Finset γ} :
+ ⋃ x ∈ s.image f, g x = ⋃ y ∈ s, g (f y) :=
+ iSup_finset_image
+
+theorem set_biInter_finset_image {f : γ → α} {g : α → Set β} {s : Finset γ} :
+ ⋂ x ∈ s.image f, g x = ⋂ y ∈ s, g (f y) :=
+ iInf_finset_image
+
+theorem set_biUnion_insert_update {x : α} {t : Finset α} (f : α → Set β) {s : Set β} (hx : x ∉ t) :
+ ⋃ i ∈ insert x t, @update _ _ _ f x s i = s ∪ ⋃ i ∈ t, f i :=
+ iSup_insert_update f hx
+
+theorem set_biInter_insert_update {x : α} {t : Finset α} (f : α → Set β) {s : Set β} (hx : x ∉ t) :
+ ⋂ i ∈ insert x t, @update _ _ _ f x s i = s ∩ ⋂ i ∈ t, f i :=
+ iInf_insert_update f hx
+
+theorem set_biUnion_biUnion (s : Finset γ) (t : γ → Finset α) (f : α → Set β) :
+ ⋃ y ∈ s.biUnion t, f y = ⋃ (x ∈ s) (y ∈ t x), f y :=
+ iSup_biUnion s t f
+
+theorem set_biInter_biUnion (s : Finset γ) (t : γ → Finset α) (f : α → Set β) :
+ ⋂ y ∈ s.biUnion t, f y = ⋂ (x ∈ s) (y ∈ t x), f y :=
+ iInf_biUnion s t f
+
+end Finset
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 b65457aeeec04..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
@@ -539,14 +458,20 @@ theorem csSup_le_iff (hb : BddAbove s) (hs : s.Nonempty) : sSup s ≤ a ↔ ∀
theorem le_csInf_iff (hb : BddBelow s) (hs : s.Nonempty) : a ≤ sInf s ↔ ∀ b ∈ s, a ≤ b :=
le_isGLB_iff (isGLB_csInf hs hb)
-theorem csSup_lower_bounds_eq_csInf {s : Set α} (h : BddBelow s) (hs : s.Nonempty) :
+theorem csSup_lowerBounds_eq_csInf {s : Set α} (h : BddBelow s) (hs : s.Nonempty) :
sSup (lowerBounds s) = sInf s :=
(isLUB_csSup h <| hs.mono fun _ hx _ hy => hy hx).unique (isGLB_csInf hs h).isLUB
-theorem csInf_upper_bounds_eq_csSup {s : Set α} (h : BddAbove s) (hs : s.Nonempty) :
+theorem csInf_upperBounds_eq_csSup {s : Set α} (h : BddAbove s) (hs : s.Nonempty) :
sInf (upperBounds s) = sSup s :=
(isGLB_csInf h <| hs.mono fun _ hx _ hy => hy hx).unique (isLUB_csSup hs h).isGLB
+@[deprecated (since := "2024-08-25")]
+alias csSup_lower_bounds_eq_csInf := csSup_lowerBounds_eq_csInf
+
+@[deprecated (since := "2024-08-25")]
+alias csInf_upper_bounds_eq_csSup := csInf_upperBounds_eq_csSup
+
theorem not_mem_of_lt_csInf {x : α} {s : Set α} (h : x < sInf s) (hs : BddBelow s) : x ∉ s :=
fun hx => lt_irrefl _ (h.trans_le (csInf_le hs hx))
@@ -698,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'`. -/
@@ -844,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
@@ -977,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
@@ -1059,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
@@ -1121,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
@@ -1153,73 +789,49 @@ 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 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 not_mem_of_lt_csInf' {x : α} {s : Set α} (h : x < sInf s) : x ∉ s :=
+ not_mem_of_lt_csInf h (OrderBot.bddBelow s)
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₂
-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]
+theorem csSup_le_csSup' {s t : Set α} (h₁ : BddAbove t) (h₂ : s ⊆ t) : sSup s ≤ sSup t := by
+ rcases eq_empty_or_nonempty s with rfl | h
+ · rw [csSup_empty]
+ exact bot_le
+ · exact csSup_le_csSup h₁ h h₂
end ConditionallyCompleteLinearOrderBot
@@ -1386,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`
@@ -1470,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 β]
@@ -1567,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
@@ -1599,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 α)) :=
@@ -1618,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 0e43df278296d..52b1a34e4be76 100644
--- a/Mathlib/Order/CountableDenseLinearOrder.lean
+++ b/Mathlib/Order/CountableDenseLinearOrder.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: David Wärn
-/
import Mathlib.Order.Ideal
-import Mathlib.Data.Finset.Lattice
+import Mathlib.Data.Finset.Max
/-!
# The back and forth method and countable dense linear orders
@@ -33,11 +33,13 @@ noncomputable section
namespace Order
+variable {α β : Type*} [LinearOrder α] [LinearOrder β]
+
/-- Suppose `α` is a nonempty dense linear order without endpoints, and
suppose `lo`, `hi`, are finite subsets with all of `lo` strictly
before `hi`. Then there is an element of `α` strictly between `lo`
and `hi`. -/
-theorem exists_between_finsets {α : Type*} [LinearOrder α] [DenselyOrdered α] [NoMinOrder α]
+theorem exists_between_finsets [DenselyOrdered α] [NoMinOrder α]
[NoMaxOrder α] [nonem : Nonempty α] (lo hi : Finset α) (lo_lt_hi : ∀ x ∈ lo, ∀ y ∈ hi, x < y) :
∃ m : α, (∀ x ∈ lo, x < m) ∧ ∀ y ∈ hi, m < y :=
if nlo : lo.Nonempty then
@@ -61,7 +63,40 @@ theorem exists_between_finsets {α : Type*} [LinearOrder α] [DenselyOrdered α]
nonem.elim
fun m ↦ ⟨m, fun x hx ↦ (nlo ⟨x, hx⟩).elim, fun y hy ↦ (nhi ⟨y, hy⟩).elim⟩
-variable (α β : Type*) [LinearOrder α] [LinearOrder β]
+lemma exists_orderEmbedding_insert [DenselyOrdered β] [NoMinOrder β] [NoMaxOrder β]
+ [nonem : Nonempty β] (S : Finset α) (f : S ↪o β) (a : α) :
+ ∃ (g : (insert a S : Finset α) ↪o β),
+ g ∘ (Set.inclusion ((S.subset_insert a) : ↑S ⊆ ↑(insert a S))) = f := by
+ let Slt := (S.attach.filter (fun (x : S) => x < a)).image f
+ let Sgt := (S.attach.filter (fun (x : S) => a < x)).image f
+ obtain ⟨b, hb, hb'⟩ := Order.exists_between_finsets Slt Sgt (fun x hx y hy => by
+ simp only [Finset.mem_image, Finset.mem_filter, Finset.mem_attach, true_and, Subtype.exists,
+ exists_and_left, Slt, Sgt] at hx hy
+ obtain ⟨_, hx, _, rfl⟩ := hx
+ obtain ⟨_, hy, _, rfl⟩ := hy
+ exact f.strictMono (hx.trans hy))
+ refine ⟨OrderEmbedding.ofStrictMono
+ (fun (x : (insert a S : Finset α)) => if hx : x.1 ∈ S then f ⟨x.1, hx⟩ else b) ?_, ?_⟩
+ · rintro ⟨x, hx⟩ ⟨y, hy⟩ hxy
+ if hxS : x ∈ S
+ 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_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_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_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]
+
+variable (α β)
-- Porting note: Mathport warning: expanding binder collection (p q «expr ∈ » f)
/-- The type of partial order isomorphisms between `α` and `β` defined on finite subsets.
diff --git a/Mathlib/Order/Cover.lean b/Mathlib/Order/Cover.lean
index 945aa4514d439..cf13cbab95f7f 100644
--- a/Mathlib/Order/Cover.lean
+++ b/Mathlib/Order/Cover.lean
@@ -80,7 +80,7 @@ theorem wcovBy_congr_right (hab : AntisymmRel (· ≤ ·) a b) : c ⩿ a ↔ c
/-- If `a ≤ b`, then `b` does not cover `a` iff there's an element in between. -/
theorem not_wcovBy_iff (h : a ≤ b) : ¬a ⩿ b ↔ ∃ c, a < c ∧ c < b := by
- simp_rw [WCovBy, h, true_and_iff, not_forall, exists_prop, not_not]
+ simp_rw [WCovBy, h, true_and, not_forall, exists_prop, not_not]
instance WCovBy.isRefl : IsRefl α (· ⩿ ·) :=
⟨WCovBy.refl⟩
@@ -208,7 +208,7 @@ theorem CovBy.lt (h : a ⋖ b) : a < b :=
/-- If `a < b`, then `b` does not cover `a` iff there's an element in between. -/
theorem not_covBy_iff (h : a < b) : ¬a ⋖ b ↔ ∃ c, a < c ∧ c < b := by
- simp_rw [CovBy, h, true_and_iff, not_forall, exists_prop, not_not]
+ simp_rw [CovBy, h, true_and, not_forall, exists_prop, not_not]
alias ⟨exists_lt_lt_of_not_covBy, _⟩ := not_covBy_iff
@@ -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 9a0471732ac3c..339a1a55bc927 100644
--- a/Mathlib/Order/Defs.lean
+++ b/Mathlib/Order/Defs.lean
@@ -4,9 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Batteries.Classes.Order
-import Mathlib.Init.Logic
+import Batteries.Tactic.Trans
import Mathlib.Data.Ordering.Basic
+import Mathlib.Tactic.Lemma
import Mathlib.Tactic.SplitIfs
+import Mathlib.Tactic.TypeStar
/-!
# Orders
@@ -17,8 +19,8 @@ and proves some basic lemmas about them.
/-! ### Unbundled classes -/
-universe u
-variable {α : Type u}
+/-- An empty relation does not relate any elements. -/
+@[nolint unusedArguments] def EmptyRelation {α : Sort*} := fun _ _ : α ↦ False
/-- `IsIrrefl X r` means the binary relation `r` on `X` is irreflexive (that is, `r x x` never
holds). -/
@@ -71,7 +73,7 @@ class IsPartialOrder (α : Sort*) (r : α → α → Prop) extends IsPreorder α
/-- `IsLinearOrder X r` means that the binary relation `r` on `X` is a linear order, that is,
`IsPartialOrder X r` and `IsTotal X r`. -/
-class IsLinearOrder (α : Sort u) (r : α → α → Prop) extends IsPartialOrder α r, IsTotal α r : Prop
+class IsLinearOrder (α : Sort*) (r : α → α → Prop) extends IsPartialOrder α r, IsTotal α r : Prop
/-- `IsEquiv X r` means that the binary relation `r` on `X` is an equivalence relation, that
is, `IsPreorder X r` and `IsSymm X r`. -/
@@ -83,7 +85,7 @@ class IsStrictOrder (α : Sort*) (r : α → α → Prop) extends IsIrrefl α r,
/-- `IsStrictWeakOrder X lt` means that the binary relation `lt` on `X` is a strict weak order,
that is, `IsStrictOrder X lt` and `¬lt a b ∧ ¬lt b a → ¬lt b c ∧ ¬lt c b → ¬lt a c ∧ ¬lt c a`. -/
-class IsStrictWeakOrder (α : Sort u) (lt : α → α → Prop) extends IsStrictOrder α lt : Prop where
+class IsStrictWeakOrder (α : Sort*) (lt : α → α → Prop) extends IsStrictOrder α lt : Prop where
incomp_trans : ∀ a b c, ¬lt a b ∧ ¬lt b a → ¬lt b c ∧ ¬lt c b → ¬lt a c ∧ ¬lt c a
/-- `IsTrichotomous X lt` means that the binary relation `lt` on `X` is trichotomous, that is,
@@ -106,6 +108,7 @@ section
variable {α : Sort*} {r : α → α → Prop} {a b c : α}
+/-- Local notation for an arbitrary binary relation `r`. -/
local infixl:50 " ≺ " => r
lemma irrefl [IsIrrefl α r] (a : α) : ¬a ≺ a := IsIrrefl.irrefl a
@@ -122,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
@@ -136,10 +171,81 @@ lemma total_of [IsTotal α r] (a b : α) : a ≺ b ∨ b ≺ a := IsTotal.total
@[elab_without_expected_type]
lemma trichotomous_of [IsTrichotomous α r] : ∀ a b : α, a ≺ b ∨ a = b ∨ b ≺ a := trichotomous
+section
+
+/-- `IsRefl` as a definition, suitable for use in proofs. -/
+def Reflexive := ∀ x, x ≺ x
+
+/-- `IsSymm` as a definition, suitable for use in proofs. -/
+def Symmetric := ∀ ⦃x y⦄, x ≺ y → y ≺ x
+
+/-- `IsTrans` as a definition, suitable for use in proofs. -/
+def Transitive := ∀ ⦃x y z⦄, x ≺ y → y ≺ z → x ≺ z
+
+/-- `IsIrrefl` as a definition, suitable for use in proofs. -/
+def Irreflexive := ∀ x, ¬x ≺ x
+
+/-- `IsAntisymm` as a definition, suitable for use in proofs. -/
+def AntiSymmetric := ∀ ⦃x y⦄, x ≺ y → y ≺ x → x = y
+
+/-- `IsTotal` as a definition, suitable for use in proofs. -/
+def Total := ∀ x y, x ≺ y ∨ y ≺ x
+
+@[deprecated Equivalence.refl (since := "2024-09-13")]
+theorem Equivalence.reflexive (h : Equivalence r) : Reflexive r := h.refl
+
+@[deprecated Equivalence.symm (since := "2024-09-13")]
+theorem Equivalence.symmetric (h : Equivalence r) : Symmetric r :=
+ fun _ _ ↦ h.symm
+
+@[deprecated Equivalence.trans (since := "2024-09-13")]
+theorem Equivalence.transitive (h : Equivalence r) : Transitive r :=
+ fun _ _ _ ↦ h.trans
+
+variable {β : Sort*} (r : β → β → Prop) (f : α → β)
+
+@[deprecated (since := "2024-09-13")]
+theorem InvImage.trans (h : Transitive r) : Transitive (InvImage r f) :=
+ fun (a₁ a₂ a₃ : α) (h₁ : InvImage r f a₁ a₂) (h₂ : InvImage r f a₂ a₃) ↦ h h₁ h₂
+
+@[deprecated (since := "2024-09-13")]
+theorem InvImage.irreflexive (h : Irreflexive r) : Irreflexive (InvImage r f) :=
+ fun (a : α) (h₁ : InvImage r f a a) ↦ h (f a) h₁
+
+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*}
+
section Preorder
/-!
@@ -147,7 +253,7 @@ section Preorder
-/
/-- A preorder is a reflexive, transitive relation `≤` with `a < b` defined in the obvious way. -/
-class Preorder (α : Type u) extends LE α, LT α where
+class Preorder (α : Type*) extends LE α, LT α where
le_refl : ∀ a : α, a ≤ a
le_trans : ∀ a b c : α, a ≤ b → b ≤ c → a ≤ c
lt := fun a b => a ≤ b ∧ ¬b ≤ a
@@ -235,7 +341,7 @@ section PartialOrder
-/
/-- A partial order is a reflexive, transitive, antisymmetric relation `≤`. -/
-class PartialOrder (α : Type u) extends Preorder α where
+class PartialOrder (α : Type*) extends Preorder α where
le_antisymm : ∀ a b : α, a ≤ b → b ≤ a → a = b
variable [PartialOrder α] {a b : α}
@@ -286,11 +392,11 @@ section LinearOrder
-/
/-- Default definition of `max`. -/
-def maxDefault {α : Type u} [LE α] [DecidableRel ((· ≤ ·) : α → α → Prop)] (a b : α) :=
+def maxDefault [LE α] [DecidableRel ((· ≤ ·) : α → α → Prop)] (a b : α) :=
if a ≤ b then b else a
/-- Default definition of `min`. -/
-def minDefault {α : Type u} [LE α] [DecidableRel ((· ≤ ·) : α → α → Prop)] (a b : α) :=
+def minDefault [LE α] [DecidableRel ((· ≤ ·) : α → α → Prop)] (a b : α) :=
if a ≤ b then a else b
/-- This attempts to prove that a given instance of `compare` is equal to `compareOfLessAndEq` by
@@ -309,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 u) 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. -/
@@ -395,12 +501,12 @@ namespace Nat
/-! Deprecated properties of inequality on `Nat` -/
@[deprecated (since := "2024-08-23")]
-protected def ltGeByCases {a b : Nat} {C : Sort u} (h₁ : a < b → C) (h₂ : b ≤ a → C) : C :=
+protected def ltGeByCases {a b : Nat} {C : Sort*} (h₁ : a < b → C) (h₂ : b ≤ a → C) : C :=
Decidable.byCases h₁ fun h => h₂ (Or.elim (Nat.lt_or_ge a b) (fun a => absurd a h) fun a => a)
set_option linter.deprecated false in
@[deprecated ltByCases (since := "2024-08-23")]
-protected def ltByCases {a b : Nat} {C : Sort u} (h₁ : a < b → C) (h₂ : a = b → C)
+protected def ltByCases {a b : Nat} {C : Sort*} (h₁ : a < b → C) (h₂ : a = b → C)
(h₃ : b < a → C) : C :=
Nat.ltGeByCases h₁ fun h₁ => Nat.ltGeByCases h₃ fun h => h₂ (Nat.le_antisymm h h₁)
@@ -453,13 +559,16 @@ lemma min_comm (a b : α) : min a b = min b a :=
lemma min_assoc (a b c : α) : min (min a b) c = min a (min b c) := by
apply eq_min
- · apply le_trans; apply min_le_left; apply min_le_left
- · apply le_min; apply le_trans; apply min_le_left; apply min_le_right; apply min_le_right
- · intro d h₁ h₂; apply le_min; apply le_min h₁; apply le_trans h₂; apply min_le_left
- apply le_trans h₂; apply min_le_right
+ · apply le_trans (min_le_left ..); apply min_le_left
+ · apply le_min
+ · apply le_trans (min_le_left ..); apply min_le_right
+ · apply min_le_right
+ · intro d h₁ h₂; apply le_min
+ · apply le_min h₁; apply le_trans h₂; apply min_le_left
+ · apply le_trans h₂; apply min_le_right
-lemma min_left_comm : ∀ a b c : α, min a (min b c) = min b (min a c) :=
- left_comm (@min α _) (@min_comm α _) (@min_assoc α _)
+lemma min_left_comm (a b c : α) : min a (min b c) = min b (min a c) := by
+ rw [← min_assoc, min_comm a, min_assoc]
@[simp] lemma min_self (a : α) : min a a = a := by simp [min_def]
@@ -477,13 +586,16 @@ lemma max_comm (a b : α) : max a b = max b a :=
lemma max_assoc (a b c : α) : max (max a b) c = max a (max b c) := by
apply eq_max
- · apply le_trans; apply le_max_left a b; apply le_max_left
- · apply max_le; apply le_trans; apply le_max_right a b; apply le_max_left; apply le_max_right
- · intro d h₁ h₂; apply max_le; apply max_le h₁; apply le_trans (le_max_left _ _) h₂
- apply le_trans (le_max_right _ _) h₂
+ · apply le_trans (le_max_left a b); apply le_max_left
+ · apply max_le
+ · apply le_trans (le_max_right a b); apply le_max_left
+ · apply le_max_right
+ · intro d h₁ h₂; apply max_le
+ · apply max_le h₁; apply le_trans (le_max_left _ _) h₂
+ · apply le_trans (le_max_right _ _) h₂
-lemma max_left_comm : ∀ a b c : α, max a (max b c) = max b (max a c) :=
- left_comm (@max α _) (@max_comm α _) (@max_assoc α _)
+lemma max_left_comm (a b c : α) : max a (max b c) = max b (max a c) := by
+ rw [← max_assoc, max_comm a, max_assoc]
@[simp] lemma max_self (a : α) : max a a = a := by simp [max_def]
@@ -504,7 +616,6 @@ lemma max_lt (h₁ : a < c) (h₂ : b < c) : max a b < c := by
cases le_total a b <;> simp [max_eq_left, max_eq_right, *]
section Ord
-variable {o : Ordering}
lemma compare_lt_iff_lt : compare a b = .lt ↔ a < b := by
rw [LinearOrder.compare_eq_compareOfLessAndEq, compareOfLessAndEq]
@@ -515,14 +626,14 @@ lemma compare_gt_iff_gt : compare a b = .gt ↔ a > b := by
split_ifs <;> simp only [*, lt_irrefl, not_lt_of_gt, reduceCtorEq]
case _ h₁ h₂ =>
have h : b < a := lt_trichotomy a b |>.resolve_left h₁ |>.resolve_left h₂
- exact true_iff_iff.2 h
+ rwa [true_iff]
lemma compare_eq_iff_eq : compare a b = .eq ↔ a = b := by
rw [LinearOrder.compare_eq_compareOfLessAndEq, compareOfLessAndEq]
split_ifs <;> try simp only [reduceCtorEq]
- case _ h => exact false_iff_iff.2 <| ne_iff_lt_or_gt.2 <| .inl h
- case _ _ h => exact true_iff_iff.2 h
- case _ _ h => exact false_iff_iff.2 h
+ case _ h => rw [false_iff]; exact ne_iff_lt_or_gt.2 <| .inl h
+ case _ _ h => rwa [true_iff]
+ case _ _ h => rwa [false_iff]
lemma compare_le_iff_le : compare a b ≠ .gt ↔ a ≤ b := by
cases h : compare a b <;> simp
@@ -536,13 +647,23 @@ lemma compare_ge_iff_ge : compare a b ≠ .lt ↔ a ≥ b := by
· exact le_of_eq <| (·.symm) <| compare_eq_iff_eq.1 h
· exact le_of_lt <| compare_gt_iff_gt.1 h
-lemma compare_iff (a b : α) : compare a b = o ↔ o.toRel a b := by
- cases o <;> simp only [Ordering.toRel]
+lemma compare_iff (a b : α) {o : Ordering} : compare a b = o ↔ o.Compares a b := by
+ cases o <;> simp only [Ordering.Compares]
· exact compare_lt_iff_lt
· 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
@@ -551,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 b69b6cfa1122f..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
@@ -108,7 +104,7 @@ theorem Directed.extend_bot [Preorder α] [OrderBot α] {e : ι → β} {f : ι
simp [Function.extend_apply' _ _ _ hb]
rcases hf i j with ⟨k, hi, hj⟩
use e k
- simp only [he.extend_apply, *, true_and_iff]
+ simp only [he.extend_apply, *, true_and]
/-- A set stable by infimum is `≥`-directed. -/
theorem directedOn_of_inf_mem [SemilatticeInf α] {S : Set α}
@@ -167,7 +163,7 @@ instance OrderDual.isDirected_le [LE α] [IsDirected α (· ≥ ·)] : IsDirecte
/-- A monotone function on an upwards-directed type is directed. -/
theorem directed_of_isDirected_le [LE α] [IsDirected α (· ≤ ·)] {f : α → β} {r : β → β → Prop}
(H : ∀ ⦃i j⦄, i ≤ j → r (f i) (f j)) : Directed r f :=
- directed_id.mono_comp H
+ directed_id.mono_comp _ H
theorem Monotone.directed_le [Preorder α] [IsDirected α (· ≤ ·)] [Preorder β] {f : α → β} :
Monotone f → Directed (· ≤ ·) f :=
diff --git a/Mathlib/Order/Disjoint.lean b/Mathlib/Order/Disjoint.lean
index 29678782f984f..b49a00f24c125 100644
--- a/Mathlib/Order/Disjoint.lean
+++ b/Mathlib/Order/Disjoint.lean
@@ -108,7 +108,7 @@ end PartialBoundedOrder
section SemilatticeInfBot
-variable [SemilatticeInf α] [OrderBot α] {a b c d : α}
+variable [SemilatticeInf α] [OrderBot α] {a b c : α}
theorem disjoint_iff_inf_le : Disjoint a b ↔ a ⊓ b ≤ ⊥ :=
⟨fun hd ↦ hd inf_le_left inf_le_right, fun h _ ha hb ↦ (le_inf ha hb).trans h⟩
@@ -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 : α}
@@ -267,7 +271,7 @@ end PartialBoundedOrder
section SemilatticeSupTop
-variable [SemilatticeSup α] [OrderTop α] {a b c d : α}
+variable [SemilatticeSup α] [OrderTop α] {a b c : α}
theorem codisjoint_iff_le_sup : Codisjoint a b ↔ ⊤ ≤ a ⊔ b :=
@disjoint_iff_inf_le αᵒᵈ _ _ _ _
@@ -401,7 +405,7 @@ namespace IsCompl
section BoundedPartialOrder
-variable [PartialOrder α] [BoundedOrder α] {x y z : α}
+variable [PartialOrder α] [BoundedOrder α] {x y : α}
@[symm]
protected theorem symm (h : IsCompl x y) : IsCompl y x :=
@@ -419,7 +423,7 @@ end BoundedPartialOrder
section BoundedLattice
-variable [Lattice α] [BoundedOrder α] {x y z : α}
+variable [Lattice α] [BoundedOrder α] {x y : α}
theorem of_le (h₁ : x ⊓ y ≤ ⊥) (h₂ : ⊤ ≤ x ⊔ y) : IsCompl x y :=
⟨disjoint_iff_inf_le.mpr h₁, codisjoint_iff_le_sup.mpr h₂⟩
@@ -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/Estimator.lean b/Mathlib/Order/Estimator.lean
index 6cbb66c675781..29676a5330f47 100644
--- a/Mathlib/Order/Estimator.lean
+++ b/Mathlib/Order/Estimator.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Kim Liesinger. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kim Liesinger
+Authors: Kim Morrison
-/
import Mathlib.Data.Set.Operations
import Mathlib.Order.Heyting.Basic
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 e78822c5e188c..fc058972b73f4 100644
--- a/Mathlib/Order/Filter/AtTopBot.lean
+++ b/Mathlib/Order/Filter/AtTopBot.lean
@@ -3,17 +3,12 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Jeremy Avigad, Yury Kudryashov, Patrick Massot
-/
-import Mathlib.Algebra.BigOperators.Group.Finset
-import Mathlib.Algebra.Order.Field.Defs
-import Mathlib.Algebra.Order.Group.Instances
-import Mathlib.Algebra.Order.Group.MinMax
-import Mathlib.Algebra.Order.Ring.Basic
import Mathlib.Data.Finset.Preimage
+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
-import Mathlib.Order.ConditionallyCompleteLattice.Basic
-import Mathlib.Order.Filter.Bases
-import Mathlib.Algebra.Order.Ring.Nat
/-!
# `Filter.atTop` and `Filter.atBot` filters on preorders, monoids and groups.
@@ -264,8 +259,17 @@ variable [Nonempty α]
@[instance]
lemma atTop_neBot : NeBot (atTop : Filter α) := atTop_basis.neBot_iff.2 fun _ => nonempty_Ici
+theorem atTop_neBot_iff {α : Type*} [Preorder α] :
+ (atTop : Filter α).NeBot ↔ Nonempty α ∧ IsDirected α (· ≤ ·) := by
+ refine ⟨fun h ↦ ⟨nonempty_of_neBot atTop, ⟨fun x y ↦ ?_⟩⟩, fun ⟨h₁, h₂⟩ ↦ atTop_neBot⟩
+ exact ((eventually_ge_atTop x).and (eventually_ge_atTop y)).exists
+
+theorem atBot_neBot_iff {α : Type*} [Preorder α] :
+ (atBot : Filter α).NeBot ↔ Nonempty α ∧ IsDirected α (· ≥ ·) :=
+ atTop_neBot_iff (α := αᵒᵈ)
+
@[simp] lemma mem_atTop_sets {s : Set α} : s ∈ (atTop : Filter α) ↔ ∃ a : α, ∀ b ≥ a, b ∈ s :=
- atTop_basis.mem_iff.trans <| exists_congr fun _ => true_and_iff _
+ atTop_basis.mem_iff.trans <| exists_congr fun _ => iff_of_eq (true_and _)
@[simp] lemma eventually_atTop : (∀ᶠ x in atTop, p x) ↔ ∃ a, ∀ b ≥ a, p b := mem_atTop_sets
@@ -572,618 +576,6 @@ theorem strictMono_subseq_of_id_le {u : ℕ → ℕ} (hu : ∀ n, n ≤ u n) :
theorem _root_.StrictMono.tendsto_atTop {φ : ℕ → ℕ} (h : StrictMono φ) : Tendsto φ atTop atTop :=
tendsto_atTop_mono h.id_le tendsto_id
-section OrderedAddCommMonoid
-
-variable [OrderedAddCommMonoid β] {l : Filter α} {f g : α → β}
-
-theorem tendsto_atTop_add_nonneg_left' (hf : ∀ᶠ x in l, 0 ≤ f x) (hg : Tendsto g l atTop) :
- Tendsto (fun x => f x + g x) l atTop :=
- tendsto_atTop_mono' l (hf.mono fun _ => le_add_of_nonneg_left) hg
-
-theorem tendsto_atBot_add_nonpos_left' (hf : ∀ᶠ x in l, f x ≤ 0) (hg : Tendsto g l atBot) :
- Tendsto (fun x => f x + g x) l atBot :=
- @tendsto_atTop_add_nonneg_left' _ βᵒᵈ _ _ _ _ hf hg
-
-theorem tendsto_atTop_add_nonneg_left (hf : ∀ x, 0 ≤ f x) (hg : Tendsto g l atTop) :
- Tendsto (fun x => f x + g x) l atTop :=
- tendsto_atTop_add_nonneg_left' (Eventually.of_forall hf) hg
-
-theorem tendsto_atBot_add_nonpos_left (hf : ∀ x, f x ≤ 0) (hg : Tendsto g l atBot) :
- Tendsto (fun x => f x + g x) l atBot :=
- @tendsto_atTop_add_nonneg_left _ βᵒᵈ _ _ _ _ hf hg
-
-theorem tendsto_atTop_add_nonneg_right' (hf : Tendsto f l atTop) (hg : ∀ᶠ x in l, 0 ≤ g x) :
- Tendsto (fun x => f x + g x) l atTop :=
- tendsto_atTop_mono' l (monotone_mem (fun _ => le_add_of_nonneg_right) hg) hf
-
-theorem tendsto_atBot_add_nonpos_right' (hf : Tendsto f l atBot) (hg : ∀ᶠ x in l, g x ≤ 0) :
- Tendsto (fun x => f x + g x) l atBot :=
- @tendsto_atTop_add_nonneg_right' _ βᵒᵈ _ _ _ _ hf hg
-
-theorem tendsto_atTop_add_nonneg_right (hf : Tendsto f l atTop) (hg : ∀ x, 0 ≤ g x) :
- Tendsto (fun x => f x + g x) l atTop :=
- tendsto_atTop_add_nonneg_right' hf (Eventually.of_forall hg)
-
-theorem tendsto_atBot_add_nonpos_right (hf : Tendsto f l atBot) (hg : ∀ x, g x ≤ 0) :
- Tendsto (fun x => f x + g x) l atBot :=
- @tendsto_atTop_add_nonneg_right _ βᵒᵈ _ _ _ _ hf hg
-
-theorem tendsto_atTop_add (hf : Tendsto f l atTop) (hg : Tendsto g l atTop) :
- Tendsto (fun x => f x + g x) l atTop :=
- tendsto_atTop_add_nonneg_left' (tendsto_atTop.mp hf 0) hg
-
-theorem tendsto_atBot_add (hf : Tendsto f l atBot) (hg : Tendsto g l atBot) :
- Tendsto (fun x => f x + g x) l atBot :=
- @tendsto_atTop_add _ βᵒᵈ _ _ _ _ hf hg
-
-theorem Tendsto.nsmul_atTop (hf : Tendsto f l atTop) {n : ℕ} (hn : 0 < n) :
- Tendsto (fun x => n • f x) l atTop :=
- tendsto_atTop.2 fun y =>
- (tendsto_atTop.1 hf y).mp <|
- (tendsto_atTop.1 hf 0).mono fun x h₀ hy =>
- calc
- y ≤ f x := hy
- _ = 1 • f x := (one_nsmul _).symm
- _ ≤ n • f x := nsmul_le_nsmul_left h₀ hn
-
-theorem Tendsto.nsmul_atBot (hf : Tendsto f l atBot) {n : ℕ} (hn : 0 < n) :
- Tendsto (fun x => n • f x) l atBot :=
- @Tendsto.nsmul_atTop α βᵒᵈ _ l f hf n hn
-
-end OrderedAddCommMonoid
-
-section OrderedCancelAddCommMonoid
-
-variable [OrderedCancelAddCommMonoid β] {l : Filter α} {f g : α → β}
-
-theorem tendsto_atTop_of_add_const_left (C : β) (hf : Tendsto (fun x => C + f x) l atTop) :
- Tendsto f l atTop :=
- tendsto_atTop.2 fun b => (tendsto_atTop.1 hf (C + b)).mono fun _ => le_of_add_le_add_left
-
--- Porting note: the "order dual" trick timeouts
-theorem tendsto_atBot_of_add_const_left (C : β) (hf : Tendsto (fun x => C + f x) l atBot) :
- Tendsto f l atBot :=
- tendsto_atBot.2 fun b => (tendsto_atBot.1 hf (C + b)).mono fun _ => le_of_add_le_add_left
-
-theorem tendsto_atTop_of_add_const_right (C : β) (hf : Tendsto (fun x => f x + C) l atTop) :
- Tendsto f l atTop :=
- tendsto_atTop.2 fun b => (tendsto_atTop.1 hf (b + C)).mono fun _ => le_of_add_le_add_right
-
--- Porting note: the "order dual" trick timeouts
-theorem tendsto_atBot_of_add_const_right (C : β) (hf : Tendsto (fun x => f x + C) l atBot) :
- Tendsto f l atBot :=
- tendsto_atBot.2 fun b => (tendsto_atBot.1 hf (b + C)).mono fun _ => le_of_add_le_add_right
-
-theorem tendsto_atTop_of_add_bdd_above_left' (C) (hC : ∀ᶠ x in l, f x ≤ C)
- (h : Tendsto (fun x => f x + g x) l atTop) : Tendsto g l atTop :=
- tendsto_atTop_of_add_const_left C
- (tendsto_atTop_mono' l (hC.mono fun x hx => add_le_add_right hx (g x)) h)
-
--- Porting note: the "order dual" trick timeouts
-theorem tendsto_atBot_of_add_bdd_below_left' (C) (hC : ∀ᶠ x in l, C ≤ f x)
- (h : Tendsto (fun x => f x + g x) l atBot) : Tendsto g l atBot :=
- tendsto_atBot_of_add_const_left C
- (tendsto_atBot_mono' l (hC.mono fun x hx => add_le_add_right hx (g x)) h)
-
-theorem tendsto_atTop_of_add_bdd_above_left (C) (hC : ∀ x, f x ≤ C) :
- Tendsto (fun x => f x + g x) l atTop → Tendsto g l atTop :=
- tendsto_atTop_of_add_bdd_above_left' C (univ_mem' hC)
-
--- Porting note: the "order dual" trick timeouts
-theorem tendsto_atBot_of_add_bdd_below_left (C) (hC : ∀ x, C ≤ f x) :
- Tendsto (fun x => f x + g x) l atBot → Tendsto g l atBot :=
- tendsto_atBot_of_add_bdd_below_left' C (univ_mem' hC)
-
-theorem tendsto_atTop_of_add_bdd_above_right' (C) (hC : ∀ᶠ x in l, g x ≤ C)
- (h : Tendsto (fun x => f x + g x) l atTop) : Tendsto f l atTop :=
- tendsto_atTop_of_add_const_right C
- (tendsto_atTop_mono' l (hC.mono fun x hx => add_le_add_left hx (f x)) h)
-
--- Porting note: the "order dual" trick timeouts
-theorem tendsto_atBot_of_add_bdd_below_right' (C) (hC : ∀ᶠ x in l, C ≤ g x)
- (h : Tendsto (fun x => f x + g x) l atBot) : Tendsto f l atBot :=
- tendsto_atBot_of_add_const_right C
- (tendsto_atBot_mono' l (hC.mono fun x hx => add_le_add_left hx (f x)) h)
-
-theorem tendsto_atTop_of_add_bdd_above_right (C) (hC : ∀ x, g x ≤ C) :
- Tendsto (fun x => f x + g x) l atTop → Tendsto f l atTop :=
- tendsto_atTop_of_add_bdd_above_right' C (univ_mem' hC)
-
--- Porting note: the "order dual" trick timeouts
-theorem tendsto_atBot_of_add_bdd_below_right (C) (hC : ∀ x, C ≤ g x) :
- Tendsto (fun x => f x + g x) l atBot → Tendsto f l atBot :=
- tendsto_atBot_of_add_bdd_below_right' C (univ_mem' hC)
-
-end OrderedCancelAddCommMonoid
-
-section OrderedGroup
-
-variable [OrderedAddCommGroup β] (l : Filter α) {f g : α → β}
-
-theorem tendsto_atTop_add_left_of_le' (C : β) (hf : ∀ᶠ x in l, C ≤ f x) (hg : Tendsto g l atTop) :
- Tendsto (fun x => f x + g x) l atTop :=
- @tendsto_atTop_of_add_bdd_above_left' _ _ _ l (fun x => -f x) (fun x => f x + g x) (-C) (by simpa)
- (by simpa)
-
-theorem tendsto_atBot_add_left_of_ge' (C : β) (hf : ∀ᶠ x in l, f x ≤ C) (hg : Tendsto g l atBot) :
- Tendsto (fun x => f x + g x) l atBot :=
- @tendsto_atTop_add_left_of_le' _ βᵒᵈ _ _ _ _ C hf hg
-
-theorem tendsto_atTop_add_left_of_le (C : β) (hf : ∀ x, C ≤ f x) (hg : Tendsto g l atTop) :
- Tendsto (fun x => f x + g x) l atTop :=
- tendsto_atTop_add_left_of_le' l C (univ_mem' hf) hg
-
-theorem tendsto_atBot_add_left_of_ge (C : β) (hf : ∀ x, f x ≤ C) (hg : Tendsto g l atBot) :
- Tendsto (fun x => f x + g x) l atBot :=
- @tendsto_atTop_add_left_of_le _ βᵒᵈ _ _ _ _ C hf hg
-
-theorem tendsto_atTop_add_right_of_le' (C : β) (hf : Tendsto f l atTop) (hg : ∀ᶠ x in l, C ≤ g x) :
- Tendsto (fun x => f x + g x) l atTop :=
- @tendsto_atTop_of_add_bdd_above_right' _ _ _ l (fun x => f x + g x) (fun x => -g x) (-C)
- (by simp [hg]) (by simp [hf])
-
-theorem tendsto_atBot_add_right_of_ge' (C : β) (hf : Tendsto f l atBot) (hg : ∀ᶠ x in l, g x ≤ C) :
- Tendsto (fun x => f x + g x) l atBot :=
- @tendsto_atTop_add_right_of_le' _ βᵒᵈ _ _ _ _ C hf hg
-
-theorem tendsto_atTop_add_right_of_le (C : β) (hf : Tendsto f l atTop) (hg : ∀ x, C ≤ g x) :
- Tendsto (fun x => f x + g x) l atTop :=
- tendsto_atTop_add_right_of_le' l C hf (univ_mem' hg)
-
-theorem tendsto_atBot_add_right_of_ge (C : β) (hf : Tendsto f l atBot) (hg : ∀ x, g x ≤ C) :
- Tendsto (fun x => f x + g x) l atBot :=
- @tendsto_atTop_add_right_of_le _ βᵒᵈ _ _ _ _ C hf hg
-
-theorem tendsto_atTop_add_const_left (C : β) (hf : Tendsto f l atTop) :
- Tendsto (fun x => C + f x) l atTop :=
- tendsto_atTop_add_left_of_le' l C (univ_mem' fun _ => le_refl C) hf
-
-theorem tendsto_atBot_add_const_left (C : β) (hf : Tendsto f l atBot) :
- Tendsto (fun x => C + f x) l atBot :=
- @tendsto_atTop_add_const_left _ βᵒᵈ _ _ _ C hf
-
-theorem tendsto_atTop_add_const_right (C : β) (hf : Tendsto f l atTop) :
- Tendsto (fun x => f x + C) l atTop :=
- tendsto_atTop_add_right_of_le' l C hf (univ_mem' fun _ => le_refl C)
-
-theorem tendsto_atBot_add_const_right (C : β) (hf : Tendsto f l atBot) :
- Tendsto (fun x => f x + C) l atBot :=
- @tendsto_atTop_add_const_right _ βᵒᵈ _ _ _ C hf
-
-theorem map_neg_atBot : map (Neg.neg : β → β) atBot = atTop :=
- (OrderIso.neg β).map_atBot
-
-theorem map_neg_atTop : map (Neg.neg : β → β) atTop = atBot :=
- (OrderIso.neg β).map_atTop
-
-theorem comap_neg_atBot : comap (Neg.neg : β → β) atBot = atTop :=
- (OrderIso.neg β).comap_atTop
-
-theorem comap_neg_atTop : comap (Neg.neg : β → β) atTop = atBot :=
- (OrderIso.neg β).comap_atBot
-
-theorem tendsto_neg_atTop_atBot : Tendsto (Neg.neg : β → β) atTop atBot :=
- (OrderIso.neg β).tendsto_atTop
-
-theorem tendsto_neg_atBot_atTop : Tendsto (Neg.neg : β → β) atBot atTop :=
- @tendsto_neg_atTop_atBot βᵒᵈ _
-
-variable {l}
-
-@[simp]
-theorem tendsto_neg_atTop_iff : Tendsto (fun x => -f x) l atTop ↔ Tendsto f l atBot :=
- (OrderIso.neg β).tendsto_atBot_iff
-
-@[simp]
-theorem tendsto_neg_atBot_iff : Tendsto (fun x => -f x) l atBot ↔ Tendsto f l atTop :=
- (OrderIso.neg β).tendsto_atTop_iff
-
-end OrderedGroup
-
-section OrderedSemiring
-
-variable [OrderedSemiring α] {l : Filter β} {f g : β → α}
-
-theorem Tendsto.atTop_mul_atTop (hf : Tendsto f l atTop) (hg : Tendsto g l atTop) :
- Tendsto (fun x => f x * g x) l atTop := by
- refine tendsto_atTop_mono' _ ?_ hg
- filter_upwards [hg.eventually (eventually_ge_atTop 0),
- hf.eventually (eventually_ge_atTop 1)] with _ using le_mul_of_one_le_left
-
-theorem tendsto_mul_self_atTop : Tendsto (fun x : α => x * x) atTop atTop :=
- tendsto_id.atTop_mul_atTop tendsto_id
-
-/-- The monomial function `x^n` tends to `+∞` at `+∞` for any positive natural `n`.
-A version for positive real powers exists as `tendsto_rpow_atTop`. -/
-theorem tendsto_pow_atTop {n : ℕ} (hn : n ≠ 0) : Tendsto (fun x : α => x ^ n) atTop atTop :=
- tendsto_atTop_mono' _ ((eventually_ge_atTop 1).mono fun _x hx => le_self_pow hx hn) tendsto_id
-
-end OrderedSemiring
-
-theorem zero_pow_eventuallyEq [MonoidWithZero α] :
- (fun n : ℕ => (0 : α) ^ n) =ᶠ[atTop] fun _ => 0 :=
- eventually_atTop.2 ⟨1, fun _n hn ↦ zero_pow <| Nat.one_le_iff_ne_zero.1 hn⟩
-
-section OrderedRing
-
-variable [OrderedRing α] {l : Filter β} {f g : β → α}
-
-theorem Tendsto.atTop_mul_atBot (hf : Tendsto f l atTop) (hg : Tendsto g l atBot) :
- Tendsto (fun x => f x * g x) l atBot := by
- have := hf.atTop_mul_atTop <| tendsto_neg_atBot_atTop.comp hg
- simpa only [Function.comp_def, neg_mul_eq_mul_neg, neg_neg] using
- tendsto_neg_atTop_atBot.comp this
-
-theorem Tendsto.atBot_mul_atTop (hf : Tendsto f l atBot) (hg : Tendsto g l atTop) :
- Tendsto (fun x => f x * g x) l atBot := by
- have : Tendsto (fun x => -f x * g x) l atTop :=
- (tendsto_neg_atBot_atTop.comp hf).atTop_mul_atTop hg
- simpa only [Function.comp_def, neg_mul_eq_neg_mul, neg_neg] using
- tendsto_neg_atTop_atBot.comp this
-
-theorem Tendsto.atBot_mul_atBot (hf : Tendsto f l atBot) (hg : Tendsto g l atBot) :
- Tendsto (fun x => f x * g x) l atTop := by
- have : Tendsto (fun x => -f x * -g x) l atTop :=
- (tendsto_neg_atBot_atTop.comp hf).atTop_mul_atTop (tendsto_neg_atBot_atTop.comp hg)
- simpa only [neg_mul_neg] using this
-
-end OrderedRing
-
-section LinearOrderedAddCommGroup
-
-variable [LinearOrderedAddCommGroup α]
-
-/-- $\lim_{x\to+\infty}|x|=+\infty$ -/
-theorem tendsto_abs_atTop_atTop : Tendsto (abs : α → α) atTop atTop :=
- tendsto_atTop_mono le_abs_self tendsto_id
-
-/-- $\lim_{x\to-\infty}|x|=+\infty$ -/
-theorem tendsto_abs_atBot_atTop : Tendsto (abs : α → α) atBot atTop :=
- tendsto_atTop_mono neg_le_abs tendsto_neg_atBot_atTop
-
-@[simp]
-theorem comap_abs_atTop : comap (abs : α → α) atTop = atBot ⊔ atTop := by
- refine
- le_antisymm (((atTop_basis.comap _).le_basis_iff (atBot_basis.sup atTop_basis)).2 ?_)
- (sup_le tendsto_abs_atBot_atTop.le_comap tendsto_abs_atTop_atTop.le_comap)
- rintro ⟨a, b⟩ -
- refine ⟨max (-a) b, trivial, fun x hx => ?_⟩
- rw [mem_preimage, mem_Ici, le_abs', max_le_iff, ← min_neg_neg, le_min_iff, neg_neg] at hx
- exact hx.imp And.left And.right
-
-end LinearOrderedAddCommGroup
-
-section LinearOrderedSemiring
-
-variable [LinearOrderedSemiring α] {l : Filter β} {f : β → α}
-
-theorem Tendsto.atTop_of_const_mul {c : α} (hc : 0 < c) (hf : Tendsto (fun x => c * f x) l atTop) :
- Tendsto f l atTop :=
- tendsto_atTop.2 fun b => (tendsto_atTop.1 hf (c * b)).mono
- fun _x hx => le_of_mul_le_mul_left hx hc
-
-theorem Tendsto.atTop_of_mul_const {c : α} (hc : 0 < c) (hf : Tendsto (fun x => f x * c) l atTop) :
- Tendsto f l atTop :=
- tendsto_atTop.2 fun b => (tendsto_atTop.1 hf (b * c)).mono
- fun _x hx => le_of_mul_le_mul_right hx hc
-
-@[simp]
-theorem tendsto_pow_atTop_iff {n : ℕ} : Tendsto (fun x : α => x ^ n) atTop atTop ↔ n ≠ 0 :=
- ⟨fun h hn => by simp only [hn, pow_zero, not_tendsto_const_atTop] at h, tendsto_pow_atTop⟩
-
-end LinearOrderedSemiring
-
-theorem not_tendsto_pow_atTop_atBot [LinearOrderedRing α] :
- ∀ {n : ℕ}, ¬Tendsto (fun x : α => x ^ n) atTop atBot
- | 0 => by simp [not_tendsto_const_atBot]
- | n + 1 => (tendsto_pow_atTop n.succ_ne_zero).not_tendsto disjoint_atTop_atBot
-
-section LinearOrderedSemifield
-
-variable [LinearOrderedSemifield α] {l : Filter β} {f : β → α} {r c : α} {n : ℕ}
-
-/-!
-### Multiplication by constant: iff lemmas
--/
-
-
-/-- If `r` is a positive constant, `fun x ↦ r * f x` tends to infinity along a filter
-if and only if `f` tends to infinity along the same filter. -/
-theorem tendsto_const_mul_atTop_of_pos (hr : 0 < r) :
- Tendsto (fun x => r * f x) l atTop ↔ Tendsto f l atTop :=
- ⟨fun h => h.atTop_of_const_mul hr, fun h =>
- Tendsto.atTop_of_const_mul (inv_pos.2 hr) <| by simpa only [inv_mul_cancel_left₀ hr.ne'] ⟩
-
-/-- If `r` is a positive constant, `fun x ↦ f x * r` tends to infinity along a filter
-if and only if `f` tends to infinity along the same filter. -/
-theorem tendsto_mul_const_atTop_of_pos (hr : 0 < r) :
- Tendsto (fun x => f x * r) l atTop ↔ Tendsto f l atTop := by
- simpa only [mul_comm] using tendsto_const_mul_atTop_of_pos hr
-
-/-- If `r` is a positive constant, `x ↦ f x / r` tends to infinity along a filter
-if and only if `f` tends to infinity along the same filter. -/
-lemma tendsto_div_const_atTop_of_pos (hr : 0 < r) :
- Tendsto (fun x ↦ f x / r) l atTop ↔ Tendsto f l atTop := by
- simpa only [div_eq_mul_inv] using tendsto_mul_const_atTop_of_pos (inv_pos.2 hr)
-
-/-- If `f` tends to infinity along a nontrivial filter `l`, then
-`fun x ↦ r * f x` tends to infinity if and only if `0 < r. `-/
-theorem tendsto_const_mul_atTop_iff_pos [NeBot l] (h : Tendsto f l atTop) :
- Tendsto (fun x => r * f x) l atTop ↔ 0 < r := by
- refine ⟨fun hrf => not_le.mp fun hr => ?_, fun hr => (tendsto_const_mul_atTop_of_pos hr).mpr h⟩
- rcases ((h.eventually_ge_atTop 0).and (hrf.eventually_gt_atTop 0)).exists with ⟨x, hx, hrx⟩
- exact (mul_nonpos_of_nonpos_of_nonneg hr hx).not_lt hrx
-
-/-- If `f` tends to infinity along a nontrivial filter `l`, then
-`fun x ↦ f x * r` tends to infinity if and only if `0 < r. `-/
-theorem tendsto_mul_const_atTop_iff_pos [NeBot l] (h : Tendsto f l atTop) :
- Tendsto (fun x => f x * r) l atTop ↔ 0 < r := by
- simp only [mul_comm _ r, tendsto_const_mul_atTop_iff_pos h]
-
-/-- If `f` tends to infinity along a nontrivial filter `l`, then
-`x ↦ f x * r` tends to infinity if and only if `0 < r. `-/
-lemma tendsto_div_const_atTop_iff_pos [NeBot l] (h : Tendsto f l atTop) :
- Tendsto (fun x ↦ f x / r) l atTop ↔ 0 < r := by
- simp only [div_eq_mul_inv, tendsto_mul_const_atTop_iff_pos h, inv_pos]
-
-/-- If `f` tends to infinity along a filter, then `f` multiplied by a positive
-constant (on the left) also tends to infinity. For a version working in `ℕ` or `ℤ`, use
-`Filter.Tendsto.const_mul_atTop'` instead. -/
-theorem Tendsto.const_mul_atTop (hr : 0 < r) (hf : Tendsto f l atTop) :
- Tendsto (fun x => r * f x) l atTop :=
- (tendsto_const_mul_atTop_of_pos hr).2 hf
-
-/-- If a function `f` tends to infinity along a filter, then `f` multiplied by a positive
-constant (on the right) also tends to infinity. For a version working in `ℕ` or `ℤ`, use
-`Filter.Tendsto.atTop_mul_const'` instead. -/
-theorem Tendsto.atTop_mul_const (hr : 0 < r) (hf : Tendsto f l atTop) :
- Tendsto (fun x => f x * r) l atTop :=
- (tendsto_mul_const_atTop_of_pos hr).2 hf
-
-/-- If a function `f` tends to infinity along a filter, then `f` divided by a positive
-constant also tends to infinity. -/
-theorem Tendsto.atTop_div_const (hr : 0 < r) (hf : Tendsto f l atTop) :
- Tendsto (fun x => f x / r) l atTop := by
- simpa only [div_eq_mul_inv] using hf.atTop_mul_const (inv_pos.2 hr)
-
-theorem tendsto_const_mul_pow_atTop (hn : n ≠ 0) (hc : 0 < c) :
- Tendsto (fun x => c * x ^ n) atTop atTop :=
- Tendsto.const_mul_atTop hc (tendsto_pow_atTop hn)
-
-theorem tendsto_const_mul_pow_atTop_iff :
- Tendsto (fun x => c * x ^ n) atTop atTop ↔ n ≠ 0 ∧ 0 < c := by
- refine ⟨fun h => ⟨?_, ?_⟩, fun h => tendsto_const_mul_pow_atTop h.1 h.2⟩
- · rintro rfl
- simp only [pow_zero, not_tendsto_const_atTop] at h
- · rcases ((h.eventually_gt_atTop 0).and (eventually_ge_atTop 0)).exists with ⟨k, hck, hk⟩
- exact pos_of_mul_pos_left hck (pow_nonneg hk _)
-
-lemma tendsto_zpow_atTop_atTop {n : ℤ} (hn : 0 < n) : Tendsto (fun x : α ↦ x ^ n) atTop atTop := by
- lift n to ℕ+ using hn; simp
-
-end LinearOrderedSemifield
-
-section LinearOrderedField
-
-variable [LinearOrderedField α] {l : Filter β} {f : β → α} {r : α}
-
-/-- If `r` is a positive constant, `fun x ↦ r * f x` tends to negative infinity along a filter
-if and only if `f` tends to negative infinity along the same filter. -/
-theorem tendsto_const_mul_atBot_of_pos (hr : 0 < r) :
- Tendsto (fun x => r * f x) l atBot ↔ Tendsto f l atBot := by
- simpa only [← mul_neg, ← tendsto_neg_atTop_iff] using tendsto_const_mul_atTop_of_pos hr
-
-/-- If `r` is a positive constant, `fun x ↦ f x * r` tends to negative infinity along a filter
-if and only if `f` tends to negative infinity along the same filter. -/
-theorem tendsto_mul_const_atBot_of_pos (hr : 0 < r) :
- Tendsto (fun x => f x * r) l atBot ↔ Tendsto f l atBot := by
- simpa only [mul_comm] using tendsto_const_mul_atBot_of_pos hr
-
-/-- If `r` is a positive constant, `fun x ↦ f x / r` tends to negative infinity along a filter
-if and only if `f` tends to negative infinity along the same filter. -/
-lemma tendsto_div_const_atBot_of_pos (hr : 0 < r) :
- Tendsto (fun x ↦ f x / r) l atBot ↔ Tendsto f l atBot := by
- simp [div_eq_mul_inv, tendsto_mul_const_atBot_of_pos, hr]
-
-/-- If `r` is a negative constant, `fun x ↦ r * f x` tends to infinity along a filter `l`
-if and only if `f` tends to negative infinity along `l`. -/
-theorem tendsto_const_mul_atTop_of_neg (hr : r < 0) :
- Tendsto (fun x => r * f x) l atTop ↔ Tendsto f l atBot := by
- simpa only [neg_mul, tendsto_neg_atBot_iff] using tendsto_const_mul_atBot_of_pos (neg_pos.2 hr)
-
-/-- If `r` is a negative constant, `fun x ↦ f x * r` tends to infinity along a filter `l`
-if and only if `f` tends to negative infinity along `l`. -/
-theorem tendsto_mul_const_atTop_of_neg (hr : r < 0) :
- Tendsto (fun x => f x * r) l atTop ↔ Tendsto f l atBot := by
- simpa only [mul_comm] using tendsto_const_mul_atTop_of_neg hr
-
-/-- If `r` is a negative constant, `fun x ↦ f x / r` tends to infinity along a filter `l`
-if and only if `f` tends to negative infinity along `l`. -/
-lemma tendsto_div_const_atTop_of_neg (hr : r < 0) :
- Tendsto (fun x ↦ f x / r) l atTop ↔ Tendsto f l atBot := by
- simp [div_eq_mul_inv, tendsto_mul_const_atTop_of_neg, hr]
-
-/-- If `r` is a negative constant, `fun x ↦ r * f x` tends to negative infinity along a filter `l`
-if and only if `f` tends to infinity along `l`. -/
-theorem tendsto_const_mul_atBot_of_neg (hr : r < 0) :
- Tendsto (fun x => r * f x) l atBot ↔ Tendsto f l atTop := by
- simpa only [neg_mul, tendsto_neg_atTop_iff] using tendsto_const_mul_atTop_of_pos (neg_pos.2 hr)
-
-/-- If `r` is a negative constant, `fun x ↦ f x * r` tends to negative infinity along a filter `l`
-if and only if `f` tends to infinity along `l`. -/
-theorem tendsto_mul_const_atBot_of_neg (hr : r < 0) :
- Tendsto (fun x => f x * r) l atBot ↔ Tendsto f l atTop := by
- simpa only [mul_comm] using tendsto_const_mul_atBot_of_neg hr
-
-/-- If `r` is a negative constant, `fun x ↦ f x / r` tends to negative infinity along a filter `l`
-if and only if `f` tends to infinity along `l`. -/
-lemma tendsto_div_const_atBot_of_neg (hr : r < 0) :
- Tendsto (fun x ↦ f x / r) l atBot ↔ Tendsto f l atTop := by
- simp [div_eq_mul_inv, tendsto_mul_const_atBot_of_neg, hr]
-
-/-- The function `fun x ↦ r * f x` tends to infinity along a nontrivial filter
-if and only if `r > 0` and `f` tends to infinity or `r < 0` and `f` tends to negative infinity. -/
-theorem tendsto_const_mul_atTop_iff [NeBot l] :
- Tendsto (fun x => r * f x) l atTop ↔ 0 < r ∧ Tendsto f l atTop ∨ r < 0 ∧ Tendsto f l atBot := by
- rcases lt_trichotomy r 0 with (hr | rfl | hr)
- · simp [hr, hr.not_lt, tendsto_const_mul_atTop_of_neg]
- · simp [not_tendsto_const_atTop]
- · simp [hr, hr.not_lt, tendsto_const_mul_atTop_of_pos]
-
-/-- The function `fun x ↦ f x * r` tends to infinity along a nontrivial filter
-if and only if `r > 0` and `f` tends to infinity or `r < 0` and `f` tends to negative infinity. -/
-theorem tendsto_mul_const_atTop_iff [NeBot l] :
- Tendsto (fun x => f x * r) l atTop ↔ 0 < r ∧ Tendsto f l atTop ∨ r < 0 ∧ Tendsto f l atBot := by
- simp only [mul_comm _ r, tendsto_const_mul_atTop_iff]
-
-/-- The function `fun x ↦ f x / r` tends to infinity along a nontrivial filter
-if and only if `r > 0` and `f` tends to infinity or `r < 0` and `f` tends to negative infinity. -/
-lemma tendsto_div_const_atTop_iff [NeBot l] :
- Tendsto (fun x ↦ f x / r) l atTop ↔ 0 < r ∧ Tendsto f l atTop ∨ r < 0 ∧ Tendsto f l atBot := by
- simp [div_eq_mul_inv, tendsto_mul_const_atTop_iff]
-
-/-- The function `fun x ↦ r * f x` tends to negative infinity along a nontrivial filter
-if and only if `r > 0` and `f` tends to negative infinity or `r < 0` and `f` tends to infinity. -/
-theorem tendsto_const_mul_atBot_iff [NeBot l] :
- Tendsto (fun x => r * f x) l atBot ↔ 0 < r ∧ Tendsto f l atBot ∨ r < 0 ∧ Tendsto f l atTop := by
- simp only [← tendsto_neg_atTop_iff, ← mul_neg, tendsto_const_mul_atTop_iff, neg_neg]
-
-/-- The function `fun x ↦ f x * r` tends to negative infinity along a nontrivial filter
-if and only if `r > 0` and `f` tends to negative infinity or `r < 0` and `f` tends to infinity. -/
-theorem tendsto_mul_const_atBot_iff [NeBot l] :
- Tendsto (fun x => f x * r) l atBot ↔ 0 < r ∧ Tendsto f l atBot ∨ r < 0 ∧ Tendsto f l atTop := by
- simp only [mul_comm _ r, tendsto_const_mul_atBot_iff]
-
-/-- The function `fun x ↦ f x / r` tends to negative infinity along a nontrivial filter
-if and only if `r > 0` and `f` tends to negative infinity or `r < 0` and `f` tends to infinity. -/
-lemma tendsto_div_const_atBot_iff [NeBot l] :
- Tendsto (fun x ↦ f x / r) l atBot ↔ 0 < r ∧ Tendsto f l atBot ∨ r < 0 ∧ Tendsto f l atTop := by
- simp [div_eq_mul_inv, tendsto_mul_const_atBot_iff]
-
-/-- If `f` tends to negative infinity along a nontrivial filter `l`,
-then `fun x ↦ r * f x` tends to infinity if and only if `r < 0. `-/
-theorem tendsto_const_mul_atTop_iff_neg [NeBot l] (h : Tendsto f l atBot) :
- Tendsto (fun x => r * f x) l atTop ↔ r < 0 := by
- simp [tendsto_const_mul_atTop_iff, h, h.not_tendsto disjoint_atBot_atTop]
-
-/-- If `f` tends to negative infinity along a nontrivial filter `l`,
-then `fun x ↦ f x * r` tends to infinity if and only if `r < 0. `-/
-theorem tendsto_mul_const_atTop_iff_neg [NeBot l] (h : Tendsto f l atBot) :
- Tendsto (fun x => f x * r) l atTop ↔ r < 0 := by
- simp only [mul_comm _ r, tendsto_const_mul_atTop_iff_neg h]
-
-/-- If `f` tends to negative infinity along a nontrivial filter `l`,
-then `fun x ↦ f x / r` tends to infinity if and only if `r < 0. `-/
-lemma tendsto_div_const_atTop_iff_neg [NeBot l] (h : Tendsto f l atBot) :
- Tendsto (fun x ↦ f x / r) l atTop ↔ r < 0 := by
- simp [div_eq_mul_inv, tendsto_mul_const_atTop_iff_neg h]
-
-/-- If `f` tends to negative infinity along a nontrivial filter `l`, then
-`fun x ↦ r * f x` tends to negative infinity if and only if `0 < r. `-/
-theorem tendsto_const_mul_atBot_iff_pos [NeBot l] (h : Tendsto f l atBot) :
- Tendsto (fun x => r * f x) l atBot ↔ 0 < r := by
- simp [tendsto_const_mul_atBot_iff, h, h.not_tendsto disjoint_atBot_atTop]
-
-/-- If `f` tends to negative infinity along a nontrivial filter `l`, then
-`fun x ↦ f x * r` tends to negative infinity if and only if `0 < r. `-/
-theorem tendsto_mul_const_atBot_iff_pos [NeBot l] (h : Tendsto f l atBot) :
- Tendsto (fun x => f x * r) l atBot ↔ 0 < r := by
- simp only [mul_comm _ r, tendsto_const_mul_atBot_iff_pos h]
-
-/-- If `f` tends to negative infinity along a nontrivial filter `l`, then
-`fun x ↦ f x / r` tends to negative infinity if and only if `0 < r. `-/
-lemma tendsto_div_const_atBot_iff_pos [NeBot l] (h : Tendsto f l atBot) :
- Tendsto (fun x ↦ f x / r) l atBot ↔ 0 < r := by
- simp [div_eq_mul_inv, tendsto_mul_const_atBot_iff_pos h]
-
-/-- If `f` tends to infinity along a nontrivial filter,
-`fun x ↦ r * f x` tends to negative infinity if and only if `r < 0. `-/
-theorem tendsto_const_mul_atBot_iff_neg [NeBot l] (h : Tendsto f l atTop) :
- Tendsto (fun x => r * f x) l atBot ↔ r < 0 := by
- simp [tendsto_const_mul_atBot_iff, h, h.not_tendsto disjoint_atTop_atBot]
-
-/-- If `f` tends to infinity along a nontrivial filter,
-`fun x ↦ f x * r` tends to negative infinity if and only if `r < 0. `-/
-theorem tendsto_mul_const_atBot_iff_neg [NeBot l] (h : Tendsto f l atTop) :
- Tendsto (fun x => f x * r) l atBot ↔ r < 0 := by
- simp only [mul_comm _ r, tendsto_const_mul_atBot_iff_neg h]
-
-/-- If `f` tends to infinity along a nontrivial filter,
-`fun x ↦ f x / r` tends to negative infinity if and only if `r < 0. `-/
-lemma tendsto_div_const_atBot_iff_neg [NeBot l] (h : Tendsto f l atTop) :
- Tendsto (fun x ↦ f x / r) l atBot ↔ r < 0 := by
- simp [div_eq_mul_inv, tendsto_mul_const_atBot_iff_neg h]
-
-/-- If a function `f` tends to infinity along a filter,
-then `f` multiplied by a negative constant (on the left) tends to negative infinity. -/
-theorem Tendsto.const_mul_atTop_of_neg (hr : r < 0) (hf : Tendsto f l atTop) :
- Tendsto (fun x => r * f x) l atBot :=
- (tendsto_const_mul_atBot_of_neg hr).2 hf
-
-/-- If a function `f` tends to infinity along a filter,
-then `f` multiplied by a negative constant (on the right) tends to negative infinity. -/
-theorem Tendsto.atTop_mul_const_of_neg (hr : r < 0) (hf : Tendsto f l atTop) :
- Tendsto (fun x => f x * r) l atBot :=
- (tendsto_mul_const_atBot_of_neg hr).2 hf
-
-/-- If a function `f` tends to infinity along a filter,
-then `f` divided by a negative constant tends to negative infinity. -/
-lemma Tendsto.atTop_div_const_of_neg (hr : r < 0) (hf : Tendsto f l atTop) :
- Tendsto (fun x ↦ f x / r) l atBot := (tendsto_div_const_atBot_of_neg hr).2 hf
-
-/-- If a function `f` tends to negative infinity along a filter, then `f` multiplied by
-a positive constant (on the left) also tends to negative infinity. -/
-theorem Tendsto.const_mul_atBot (hr : 0 < r) (hf : Tendsto f l atBot) :
- Tendsto (fun x => r * f x) l atBot :=
- (tendsto_const_mul_atBot_of_pos hr).2 hf
-
-/-- If a function `f` tends to negative infinity along a filter, then `f` multiplied by
-a positive constant (on the right) also tends to negative infinity. -/
-theorem Tendsto.atBot_mul_const (hr : 0 < r) (hf : Tendsto f l atBot) :
- Tendsto (fun x => f x * r) l atBot :=
- (tendsto_mul_const_atBot_of_pos hr).2 hf
-
-/-- If a function `f` tends to negative infinity along a filter, then `f` divided by
-a positive constant also tends to negative infinity. -/
-theorem Tendsto.atBot_div_const (hr : 0 < r) (hf : Tendsto f l atBot) :
- Tendsto (fun x => f x / r) l atBot := (tendsto_div_const_atBot_of_pos hr).2 hf
-
-/-- If a function `f` tends to negative infinity along a filter,
-then `f` multiplied by a negative constant (on the left) tends to positive infinity. -/
-theorem Tendsto.const_mul_atBot_of_neg (hr : r < 0) (hf : Tendsto f l atBot) :
- Tendsto (fun x => r * f x) l atTop :=
- (tendsto_const_mul_atTop_of_neg hr).2 hf
-
-/-- If a function tends to negative infinity along a filter,
-then `f` multiplied by a negative constant (on the right) tends to positive infinity. -/
-theorem Tendsto.atBot_mul_const_of_neg (hr : r < 0) (hf : Tendsto f l atBot) :
- Tendsto (fun x => f x * r) l atTop :=
- (tendsto_mul_const_atTop_of_neg hr).2 hf
-
-theorem tendsto_neg_const_mul_pow_atTop {c : α} {n : ℕ} (hn : n ≠ 0) (hc : c < 0) :
- Tendsto (fun x => c * x ^ n) atTop atBot :=
- (tendsto_pow_atTop hn).const_mul_atTop_of_neg hc
-
-theorem tendsto_const_mul_pow_atBot_iff {c : α} {n : ℕ} :
- Tendsto (fun x => c * x ^ n) atTop atBot ↔ n ≠ 0 ∧ c < 0 := by
- simp only [← tendsto_neg_atTop_iff, ← neg_mul, tendsto_const_mul_pow_atTop_iff, neg_pos]
-
-@[deprecated (since := "2024-05-06")]
-alias Tendsto.neg_const_mul_atTop := Tendsto.const_mul_atTop_of_neg
-
-@[deprecated (since := "2024-05-06")]
-alias Tendsto.atTop_mul_neg_const := Tendsto.atTop_mul_const_of_neg
-
-@[deprecated (since := "2024-05-06")]
-alias Tendsto.neg_const_mul_atBot := Tendsto.const_mul_atBot_of_neg
-
-@[deprecated (since := "2024-05-06")]
-alias Tendsto.atBot_mul_neg_const := Tendsto.atBot_mul_const_of_neg
-
-end LinearOrderedField
-
-open Filter
-
theorem tendsto_atTop_atTop_of_monotone [Preorder α] [Preorder β] {f : α → β} (hf : Monotone f)
(h : ∀ b, ∃ a, b ≤ f a) : Tendsto f atTop atTop :=
tendsto_iInf.2 fun b =>
@@ -1586,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 => add_le_add_right h k)
- (fun a b h => (le_tsub_iff_right h).symm) fun a h => by rw [tsub_add_cancel_of_le 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 => tsub_le_tsub_right h _)
- (fun a b _ => tsub_le_iff_right) fun b _ => by rw [add_tsub_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)
@@ -1605,14 +997,10 @@ 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 => b * k + (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 simp only [← Nat.lt_succ_iff, Nat.div_lt_iff_lt_mul hk, Nat.succ_eq_add_one,
- add_assoc, tsub_add_cancel_of_le (Nat.one_le_iff_ne_zero.2 hk.ne'), add_mul, one_mul])
- fun b _ =>
- calc
- b = b * k / k := by rw [Nat.mul_div_cancel b hk]
- _ ≤ (b * k + (k - 1)) / k := Nat.div_le_div_right <| Nat.le_add_right _ _
+ (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
/-- If `u` is a monotone function with linear ordered codomain and the range of `u` is not bounded
above, then `Tendsto u atTop atTop`. -/
@@ -1679,25 +1067,6 @@ theorem tendsto_atBot_of_monotone_of_subseq [Preorder ι] [Preorder α] {u : ι
Tendsto u atBot atBot :=
tendsto_atBot_of_monotone_of_filter h (tendsto_map' H)
-/-- Let `f` and `g` be two maps to the same commutative monoid. This lemma gives a sufficient
-condition for comparison of the filter `atTop.map (fun s ↦ ∏ b ∈ s, f b)` with
-`atTop.map (fun s ↦ ∏ b ∈ s, g b)`. This is useful to compare the set of limit points of
-`Π b in s, f b` as `s → atTop` with the similar set for `g`. -/
-@[to_additive "Let `f` and `g` be two maps to the same commutative additive monoid. This lemma gives
-a sufficient condition for comparison of the filter `atTop.map (fun s ↦ ∑ b ∈ s, f b)` with
-`atTop.map (fun s ↦ ∑ b ∈ s, g b)`. This is useful to compare the set of limit points of
-`∑ b ∈ s, f b` as `s → atTop` with the similar set for `g`."]
-theorem map_atTop_finset_prod_le_of_prod_eq [CommMonoid α] {f : β → α} {g : γ → α}
- (h_eq : ∀ u : Finset γ,
- ∃ v : Finset β, ∀ v', v ⊆ v' → ∃ u', u ⊆ u' ∧ ∏ x ∈ u', g x = ∏ b ∈ v', f b) :
- (atTop.map fun s : Finset β => ∏ b ∈ s, f b) ≤
- atTop.map fun s : Finset γ => ∏ x ∈ s, g x := by
- classical
- refine ((atTop_basis.map _).le_basis_iff (atTop_basis.map _)).2 fun b _ => ?_
- let ⟨v, hv⟩ := h_eq b
- refine ⟨v, trivial, ?_⟩
- simpa [image_subset_iff] using hv
-
theorem HasAntitoneBasis.eventually_subset [Preorder ι] {l : Filter α} {s : ι → Set α}
(hl : l.HasAntitoneBasis s) {t : Set α} (ht : t ∈ l) : ∀ᶠ i in atTop, s i ⊆ t :=
let ⟨i, _, hi⟩ := hl.1.mem_iff.1 ht
@@ -1838,21 +1207,6 @@ end Filter
open Filter Finset
-section
-
-variable {R : Type*} [LinearOrderedSemiring R]
-
-theorem exists_lt_mul_self (a : R) : ∃ x ≥ 0, a < x * x :=
- let ⟨x, hxa, hx0⟩ :=
- ((tendsto_mul_self_atTop.eventually (eventually_gt_atTop a)).and (eventually_ge_atTop 0)).exists
- ⟨x, hx0, hxa⟩
-
-theorem exists_le_mul_self (a : R) : ∃ x ≥ 0, a ≤ x * x :=
- let ⟨x, hx0, hxa⟩ := exists_lt_mul_self a
- ⟨x, hx0, hxa.le⟩
-
-end
-
theorem Monotone.piecewise_eventually_eq_iUnion {β : α → Type*} [Preorder ι] {s : ι → Set α}
[∀ i, DecidablePred (· ∈ s i)] [DecidablePred (· ∈ ⋃ i, s i)]
(hs : Monotone s) (f g : (a : α) → β a) (a : α) :
@@ -1873,36 +1227,44 @@ theorem Antitone.piecewise_eventually_eq_iInter {β : α → Type*} [Preorder ι
· convert congr_fun (Set.piecewise_compl (s _) g f) a
· simp only [(· ∘ ·), ← compl_iInter, Set.piecewise_compl]
-/-- Let `g : γ → β` be an injective function and `f : β → α` be a function from the codomain of `g`
-to a commutative monoid. Suppose that `f x = 1` outside of the range of `g`. Then the filters
-`atTop.map (fun s ↦ ∏ i ∈ s, f (g i))` and `atTop.map (fun s ↦ ∏ i ∈ s, f i)` coincide.
-
-The additive version of this lemma is used to prove the equality `∑' x, f (g x) = ∑' y, f y` under
-the same assumptions. -/
-@[to_additive]
-theorem Function.Injective.map_atTop_finset_prod_eq [CommMonoid α] {g : γ → β}
- (hg : Function.Injective g) {f : β → α} (hf : ∀ x, x ∉ Set.range g → f x = 1) :
- map (fun s => ∏ i ∈ s, f (g i)) atTop = map (fun s => ∏ i ∈ s, f i) atTop := by
- haveI := Classical.decEq β
- apply le_antisymm <;> refine map_atTop_finset_prod_le_of_prod_eq fun s => ?_
- · refine ⟨s.preimage g hg.injOn, fun t ht => ?_⟩
- refine ⟨t.image g ∪ s, Finset.subset_union_right, ?_⟩
- rw [← Finset.prod_image hg.injOn]
- refine (prod_subset subset_union_left ?_).symm
- simp only [Finset.mem_union, Finset.mem_image]
- refine fun y hy hyt => hf y (mt ?_ hyt)
- rintro ⟨x, rfl⟩
- exact ⟨x, ht (Finset.mem_preimage.2 <| hy.resolve_left hyt), rfl⟩
- · refine ⟨s.image g, fun t ht => ?_⟩
- simp only [← prod_preimage _ _ hg.injOn _ fun x _ => hf x]
- exact ⟨_, (image_subset_iff_subset_preimage _).1 ht, rfl⟩
-
-/-- Let `g : γ → β` be an injective function and `f : β → α` be a function from the codomain of `g`
-to an additive commutative monoid. Suppose that `f x = 0` outside of the range of `g`. Then the
-filters `atTop.map (fun s ↦ ∑ i ∈ s, f (g i))` and `atTop.map (fun s ↦ ∑ i ∈ s, f i)` coincide.
-
-This lemma is used to prove the equality `∑' x, f (g x) = ∑' y, f y` under
-the same assumptions. -/
-add_decl_doc Function.Injective.map_atTop_finset_sum_eq
-
-set_option linter.style.longFile 2000
+namespace Nat
+
+theorem eventually_pow_lt_factorial_sub (c d : ℕ) : ∀ᶠ n in atTop, c ^ n < (n - d)! := by
+ rw [eventually_atTop]
+ refine ⟨2 * (c ^ 2 + d + 1), ?_⟩
+ intro n hn
+ obtain ⟨d', rfl⟩ := Nat.exists_eq_add_of_le hn
+ obtain (rfl | c0) := c.eq_zero_or_pos
+ · simp [Nat.two_mul, ← Nat.add_assoc, Nat.add_right_comm _ 1, Nat.factorial_pos]
+ refine (Nat.le_mul_of_pos_right _ (Nat.pow_pos (n := d') c0)).trans_lt ?_
+ convert_to (c ^ 2) ^ (c ^ 2 + d' + d + 1) < (c ^ 2 + (c ^ 2 + d' + d + 1) + 1)!
+ · rw [← pow_mul, ← pow_add]
+ congr 1
+ omega
+ · congr 1
+ omega
+ refine (lt_of_lt_of_le ?_ Nat.factorial_mul_pow_le_factorial).trans_le <|
+ (factorial_le (Nat.le_succ _))
+ rw [← one_mul (_ ^ _ : ℕ)]
+ apply Nat.mul_lt_mul_of_le_of_lt
+ · exact Nat.one_le_of_lt (Nat.factorial_pos _)
+ · exact Nat.pow_lt_pow_left (Nat.lt_succ_self _) (Nat.succ_ne_zero _)
+ · exact (Nat.factorial_pos _)
+
+theorem eventually_mul_pow_lt_factorial_sub (a c d : ℕ) :
+ ∀ᶠ n in atTop, a * c ^ n < (n - d)! := by
+ filter_upwards [Nat.eventually_pow_lt_factorial_sub (a * c) d, Filter.eventually_gt_atTop 0]
+ with n hn hn0
+ rw [mul_pow] at hn
+ exact (Nat.mul_le_mul_right _ (Nat.le_self_pow hn0.ne' _)).trans_lt hn
+
+@[deprecated eventually_pow_lt_factorial_sub (since := "2024-09-25")]
+theorem exists_pow_lt_factorial (c : ℕ) : ∃ n0 > 1, ∀ n ≥ n0, c ^ n < (n - 1)! :=
+ let ⟨n0, h⟩ := (eventually_pow_lt_factorial_sub c 1).exists_forall_of_atTop
+ ⟨max n0 2, by omega, fun n hn ↦ h n (by omega)⟩
+
+@[deprecated eventually_mul_pow_lt_factorial_sub (since := "2024-09-25")]
+theorem exists_mul_pow_lt_factorial (a : ℕ) (c : ℕ) : ∃ n0, ∀ n ≥ n0, a * c ^ n < (n - 1)! :=
+ (eventually_mul_pow_lt_factorial_sub a c 1).exists_forall_of_atTop
+
+end Nat
diff --git a/Mathlib/Order/Filter/Archimedean.lean b/Mathlib/Order/Filter/AtTopBot/Archimedean.lean
similarity index 99%
rename from Mathlib/Order/Filter/Archimedean.lean
rename to Mathlib/Order/Filter/AtTopBot/Archimedean.lean
index 7b5d1fe77631c..143e3e2e610f0 100644
--- a/Mathlib/Order/Filter/Archimedean.lean
+++ b/Mathlib/Order/Filter/AtTopBot/Archimedean.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.Algebra.Order.Archimedean.Basic
-import Mathlib.Order.Filter.AtTopBot
+import Mathlib.Order.Filter.AtTopBot.Group
import Mathlib.Tactic.GCongr
/-!
diff --git a/Mathlib/Order/Filter/AtTopBot/BigOperators.lean b/Mathlib/Order/Filter/AtTopBot/BigOperators.lean
new file mode 100644
index 0000000000000..bbc99acf7d7b1
--- /dev/null
+++ b/Mathlib/Order/Filter/AtTopBot/BigOperators.lean
@@ -0,0 +1,70 @@
+/-
+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.BigOperators.Group.Finset
+import Mathlib.Order.Filter.AtTopBot
+
+/-!
+# Two lemmas about limit of `Π b ∈ s, f b` along
+
+In this file we prove two auxiliary lemmas
+about `Filter.atTop : Filter (Finset _)` and `∏ b ∈ s, f b`.
+These lemmas are useful to build the theory of absolutely convergent series.
+-/
+
+open Filter Finset
+
+variable {α β M : Type*} [CommMonoid M]
+
+/-- Let `f` and `g` be two maps to the same commutative monoid. This lemma gives a sufficient
+condition for comparison of the filter `atTop.map (fun s ↦ ∏ b ∈ s, f b)` with
+`atTop.map (fun s ↦ ∏ b ∈ s, g b)`. This is useful to compare the set of limit points of
+`Π b in s, f b` as `s → atTop` with the similar set for `g`. -/
+@[to_additive "Let `f` and `g` be two maps to the same commutative additive monoid. This lemma gives
+a sufficient condition for comparison of the filter `atTop.map (fun s ↦ ∑ b ∈ s, f b)` with
+`atTop.map (fun s ↦ ∑ b ∈ s, g b)`. This is useful to compare the set of limit points of
+`∑ b ∈ s, f b` as `s → atTop` with the similar set for `g`."]
+theorem Filter.map_atTop_finset_prod_le_of_prod_eq {f : α → M} {g : β → M}
+ (h_eq : ∀ u : Finset β,
+ ∃ v : Finset α, ∀ v', v ⊆ v' → ∃ u', u ⊆ u' ∧ ∏ x ∈ u', g x = ∏ b ∈ v', f b) :
+ (atTop.map fun s : Finset α => ∏ b ∈ s, f b) ≤
+ atTop.map fun s : Finset β => ∏ x ∈ s, g x := by
+ classical
+ refine ((atTop_basis.map _).le_basis_iff (atTop_basis.map _)).2 fun b _ => ?_
+ let ⟨v, hv⟩ := h_eq b
+ refine ⟨v, trivial, ?_⟩
+ simpa [Finset.image_subset_iff] using hv
+
+/-- Let `g : γ → β` be an injective function and `f : β → α` be a function from the codomain of `g`
+to a commutative monoid. Suppose that `f x = 1` outside of the range of `g`. Then the filters
+`atTop.map (fun s ↦ ∏ i ∈ s, f (g i))` and `atTop.map (fun s ↦ ∏ i ∈ s, f i)` coincide.
+
+The additive version of this lemma is used to prove the equality `∑' x, f (g x) = ∑' y, f y` under
+the same assumptions. -/
+@[to_additive]
+theorem Function.Injective.map_atTop_finset_prod_eq {g : α → β}
+ (hg : Function.Injective g) {f : β → M} (hf : ∀ x, x ∉ Set.range g → f x = 1) :
+ map (fun s => ∏ i ∈ s, f (g i)) atTop = map (fun s => ∏ i ∈ s, f i) atTop := by
+ haveI := Classical.decEq β
+ apply le_antisymm <;> refine map_atTop_finset_prod_le_of_prod_eq fun s => ?_
+ · refine ⟨s.preimage g hg.injOn, fun t ht => ?_⟩
+ refine ⟨t.image g ∪ s, Finset.subset_union_right, ?_⟩
+ rw [← Finset.prod_image hg.injOn]
+ refine (prod_subset subset_union_left ?_).symm
+ simp only [Finset.mem_union, Finset.mem_image]
+ refine fun y hy hyt => hf y (mt ?_ hyt)
+ rintro ⟨x, rfl⟩
+ exact ⟨x, ht (Finset.mem_preimage.2 <| hy.resolve_left hyt), rfl⟩
+ · refine ⟨s.image g, fun t ht => ?_⟩
+ simp only [← prod_preimage _ _ hg.injOn _ fun x _ => hf x]
+ exact ⟨_, (image_subset_iff_subset_preimage _).1 ht, rfl⟩
+
+/-- Let `g : γ → β` be an injective function and `f : β → α` be a function from the codomain of `g`
+to an additive commutative monoid. Suppose that `f x = 0` outside of the range of `g`. Then the
+filters `atTop.map (fun s ↦ ∑ i ∈ s, f (g i))` and `atTop.map (fun s ↦ ∑ i ∈ s, f i)` coincide.
+
+This lemma is used to prove the equality `∑' x, f (g x) = ∑' y, f y` under
+the same assumptions. -/
+add_decl_doc Function.Injective.map_atTop_finset_sum_eq
diff --git a/Mathlib/Order/Filter/AtTopBot/Field.lean b/Mathlib/Order/Filter/AtTopBot/Field.lean
new file mode 100644
index 0000000000000..519009d383724
--- /dev/null
+++ b/Mathlib/Order/Filter/AtTopBot/Field.lean
@@ -0,0 +1,320 @@
+/-
+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.Algebra.Order.Field.Defs
+import Mathlib.Order.Filter.AtTopBot.Ring
+
+/-!
+# Convergence to ±infinity in linear ordered (semi)fields
+-/
+
+namespace Filter
+
+variable {α β : Type*}
+
+section LinearOrderedSemifield
+
+variable [LinearOrderedSemifield α] {l : Filter β} {f : β → α} {r c : α} {n : ℕ}
+
+/-!
+### Multiplication by constant: iff lemmas
+-/
+
+/-- If `r` is a positive constant, `fun x ↦ r * f x` tends to infinity along a filter
+if and only if `f` tends to infinity along the same filter. -/
+theorem tendsto_const_mul_atTop_of_pos (hr : 0 < r) :
+ Tendsto (fun x => r * f x) l atTop ↔ Tendsto f l atTop :=
+ ⟨fun h => h.atTop_of_const_mul hr, fun h =>
+ Tendsto.atTop_of_const_mul (inv_pos.2 hr) <| by simpa only [inv_mul_cancel_left₀ hr.ne'] ⟩
+
+/-- If `r` is a positive constant, `fun x ↦ f x * r` tends to infinity along a filter
+if and only if `f` tends to infinity along the same filter. -/
+theorem tendsto_mul_const_atTop_of_pos (hr : 0 < r) :
+ Tendsto (fun x => f x * r) l atTop ↔ Tendsto f l atTop := by
+ simpa only [mul_comm] using tendsto_const_mul_atTop_of_pos hr
+
+/-- If `r` is a positive constant, `x ↦ f x / r` tends to infinity along a filter
+if and only if `f` tends to infinity along the same filter. -/
+lemma tendsto_div_const_atTop_of_pos (hr : 0 < r) :
+ Tendsto (fun x ↦ f x / r) l atTop ↔ Tendsto f l atTop := by
+ simpa only [div_eq_mul_inv] using tendsto_mul_const_atTop_of_pos (inv_pos.2 hr)
+
+/-- If `f` tends to infinity along a nontrivial filter `l`, then
+`fun x ↦ r * f x` tends to infinity if and only if `0 < r. `-/
+theorem tendsto_const_mul_atTop_iff_pos [NeBot l] (h : Tendsto f l atTop) :
+ Tendsto (fun x => r * f x) l atTop ↔ 0 < r := by
+ refine ⟨fun hrf => not_le.mp fun hr => ?_, fun hr => (tendsto_const_mul_atTop_of_pos hr).mpr h⟩
+ rcases ((h.eventually_ge_atTop 0).and (hrf.eventually_gt_atTop 0)).exists with ⟨x, hx, hrx⟩
+ exact (mul_nonpos_of_nonpos_of_nonneg hr hx).not_lt hrx
+
+/-- If `f` tends to infinity along a nontrivial filter `l`, then
+`fun x ↦ f x * r` tends to infinity if and only if `0 < r. `-/
+theorem tendsto_mul_const_atTop_iff_pos [NeBot l] (h : Tendsto f l atTop) :
+ Tendsto (fun x => f x * r) l atTop ↔ 0 < r := by
+ simp only [mul_comm _ r, tendsto_const_mul_atTop_iff_pos h]
+
+/-- If `f` tends to infinity along a nontrivial filter `l`, then
+`x ↦ f x * r` tends to infinity if and only if `0 < r. `-/
+lemma tendsto_div_const_atTop_iff_pos [NeBot l] (h : Tendsto f l atTop) :
+ Tendsto (fun x ↦ f x / r) l atTop ↔ 0 < r := by
+ simp only [div_eq_mul_inv, tendsto_mul_const_atTop_iff_pos h, inv_pos]
+
+/-- If `f` tends to infinity along a filter, then `f` multiplied by a positive
+constant (on the left) also tends to infinity. For a version working in `ℕ` or `ℤ`, use
+`Filter.Tendsto.const_mul_atTop'` instead. -/
+theorem Tendsto.const_mul_atTop (hr : 0 < r) (hf : Tendsto f l atTop) :
+ Tendsto (fun x => r * f x) l atTop :=
+ (tendsto_const_mul_atTop_of_pos hr).2 hf
+
+/-- If a function `f` tends to infinity along a filter, then `f` multiplied by a positive
+constant (on the right) also tends to infinity. For a version working in `ℕ` or `ℤ`, use
+`Filter.Tendsto.atTop_mul_const'` instead. -/
+theorem Tendsto.atTop_mul_const (hr : 0 < r) (hf : Tendsto f l atTop) :
+ Tendsto (fun x => f x * r) l atTop :=
+ (tendsto_mul_const_atTop_of_pos hr).2 hf
+
+/-- If a function `f` tends to infinity along a filter, then `f` divided by a positive
+constant also tends to infinity. -/
+theorem Tendsto.atTop_div_const (hr : 0 < r) (hf : Tendsto f l atTop) :
+ Tendsto (fun x => f x / r) l atTop := by
+ simpa only [div_eq_mul_inv] using hf.atTop_mul_const (inv_pos.2 hr)
+
+theorem tendsto_const_mul_pow_atTop (hn : n ≠ 0) (hc : 0 < c) :
+ Tendsto (fun x => c * x ^ n) atTop atTop :=
+ Tendsto.const_mul_atTop hc (tendsto_pow_atTop hn)
+
+theorem tendsto_const_mul_pow_atTop_iff :
+ Tendsto (fun x => c * x ^ n) atTop atTop ↔ n ≠ 0 ∧ 0 < c := by
+ refine ⟨fun h => ⟨?_, ?_⟩, fun h => tendsto_const_mul_pow_atTop h.1 h.2⟩
+ · rintro rfl
+ simp only [pow_zero, not_tendsto_const_atTop] at h
+ · rcases ((h.eventually_gt_atTop 0).and (eventually_ge_atTop 0)).exists with ⟨k, hck, hk⟩
+ exact pos_of_mul_pos_left hck (pow_nonneg hk _)
+
+lemma tendsto_zpow_atTop_atTop {n : ℤ} (hn : 0 < n) : Tendsto (fun x : α ↦ x ^ n) atTop atTop := by
+ lift n to ℕ+ using hn; simp
+
+end LinearOrderedSemifield
+
+
+section LinearOrderedField
+
+variable [LinearOrderedField α] {l : Filter β} {f : β → α} {r : α}
+
+/-- If `r` is a positive constant, `fun x ↦ r * f x` tends to negative infinity along a filter
+if and only if `f` tends to negative infinity along the same filter. -/
+theorem tendsto_const_mul_atBot_of_pos (hr : 0 < r) :
+ Tendsto (fun x => r * f x) l atBot ↔ Tendsto f l atBot := by
+ simpa only [← mul_neg, ← tendsto_neg_atTop_iff] using tendsto_const_mul_atTop_of_pos hr
+
+/-- If `r` is a positive constant, `fun x ↦ f x * r` tends to negative infinity along a filter
+if and only if `f` tends to negative infinity along the same filter. -/
+theorem tendsto_mul_const_atBot_of_pos (hr : 0 < r) :
+ Tendsto (fun x => f x * r) l atBot ↔ Tendsto f l atBot := by
+ simpa only [mul_comm] using tendsto_const_mul_atBot_of_pos hr
+
+/-- If `r` is a positive constant, `fun x ↦ f x / r` tends to negative infinity along a filter
+if and only if `f` tends to negative infinity along the same filter. -/
+lemma tendsto_div_const_atBot_of_pos (hr : 0 < r) :
+ Tendsto (fun x ↦ f x / r) l atBot ↔ Tendsto f l atBot := by
+ simp [div_eq_mul_inv, tendsto_mul_const_atBot_of_pos, hr]
+
+/-- If `r` is a negative constant, `fun x ↦ r * f x` tends to infinity along a filter `l`
+if and only if `f` tends to negative infinity along `l`. -/
+theorem tendsto_const_mul_atTop_of_neg (hr : r < 0) :
+ Tendsto (fun x => r * f x) l atTop ↔ Tendsto f l atBot := by
+ simpa only [neg_mul, tendsto_neg_atBot_iff] using tendsto_const_mul_atBot_of_pos (neg_pos.2 hr)
+
+/-- If `r` is a negative constant, `fun x ↦ f x * r` tends to infinity along a filter `l`
+if and only if `f` tends to negative infinity along `l`. -/
+theorem tendsto_mul_const_atTop_of_neg (hr : r < 0) :
+ Tendsto (fun x => f x * r) l atTop ↔ Tendsto f l atBot := by
+ simpa only [mul_comm] using tendsto_const_mul_atTop_of_neg hr
+
+/-- If `r` is a negative constant, `fun x ↦ f x / r` tends to infinity along a filter `l`
+if and only if `f` tends to negative infinity along `l`. -/
+lemma tendsto_div_const_atTop_of_neg (hr : r < 0) :
+ Tendsto (fun x ↦ f x / r) l atTop ↔ Tendsto f l atBot := by
+ simp [div_eq_mul_inv, tendsto_mul_const_atTop_of_neg, hr]
+
+/-- If `r` is a negative constant, `fun x ↦ r * f x` tends to negative infinity along a filter `l`
+if and only if `f` tends to infinity along `l`. -/
+theorem tendsto_const_mul_atBot_of_neg (hr : r < 0) :
+ Tendsto (fun x => r * f x) l atBot ↔ Tendsto f l atTop := by
+ simpa only [neg_mul, tendsto_neg_atTop_iff] using tendsto_const_mul_atTop_of_pos (neg_pos.2 hr)
+
+/-- If `r` is a negative constant, `fun x ↦ f x * r` tends to negative infinity along a filter `l`
+if and only if `f` tends to infinity along `l`. -/
+theorem tendsto_mul_const_atBot_of_neg (hr : r < 0) :
+ Tendsto (fun x => f x * r) l atBot ↔ Tendsto f l atTop := by
+ simpa only [mul_comm] using tendsto_const_mul_atBot_of_neg hr
+
+/-- If `r` is a negative constant, `fun x ↦ f x / r` tends to negative infinity along a filter `l`
+if and only if `f` tends to infinity along `l`. -/
+lemma tendsto_div_const_atBot_of_neg (hr : r < 0) :
+ Tendsto (fun x ↦ f x / r) l atBot ↔ Tendsto f l atTop := by
+ simp [div_eq_mul_inv, tendsto_mul_const_atBot_of_neg, hr]
+
+/-- The function `fun x ↦ r * f x` tends to infinity along a nontrivial filter
+if and only if `r > 0` and `f` tends to infinity or `r < 0` and `f` tends to negative infinity. -/
+theorem tendsto_const_mul_atTop_iff [NeBot l] :
+ Tendsto (fun x => r * f x) l atTop ↔ 0 < r ∧ Tendsto f l atTop ∨ r < 0 ∧ Tendsto f l atBot := by
+ rcases lt_trichotomy r 0 with (hr | rfl | hr)
+ · simp [hr, hr.not_lt, tendsto_const_mul_atTop_of_neg]
+ · simp [not_tendsto_const_atTop]
+ · simp [hr, hr.not_lt, tendsto_const_mul_atTop_of_pos]
+
+/-- The function `fun x ↦ f x * r` tends to infinity along a nontrivial filter
+if and only if `r > 0` and `f` tends to infinity or `r < 0` and `f` tends to negative infinity. -/
+theorem tendsto_mul_const_atTop_iff [NeBot l] :
+ Tendsto (fun x => f x * r) l atTop ↔ 0 < r ∧ Tendsto f l atTop ∨ r < 0 ∧ Tendsto f l atBot := by
+ simp only [mul_comm _ r, tendsto_const_mul_atTop_iff]
+
+/-- The function `fun x ↦ f x / r` tends to infinity along a nontrivial filter
+if and only if `r > 0` and `f` tends to infinity or `r < 0` and `f` tends to negative infinity. -/
+lemma tendsto_div_const_atTop_iff [NeBot l] :
+ Tendsto (fun x ↦ f x / r) l atTop ↔ 0 < r ∧ Tendsto f l atTop ∨ r < 0 ∧ Tendsto f l atBot := by
+ simp [div_eq_mul_inv, tendsto_mul_const_atTop_iff]
+
+/-- The function `fun x ↦ r * f x` tends to negative infinity along a nontrivial filter
+if and only if `r > 0` and `f` tends to negative infinity or `r < 0` and `f` tends to infinity. -/
+theorem tendsto_const_mul_atBot_iff [NeBot l] :
+ Tendsto (fun x => r * f x) l atBot ↔ 0 < r ∧ Tendsto f l atBot ∨ r < 0 ∧ Tendsto f l atTop := by
+ simp only [← tendsto_neg_atTop_iff, ← mul_neg, tendsto_const_mul_atTop_iff, neg_neg]
+
+/-- The function `fun x ↦ f x * r` tends to negative infinity along a nontrivial filter
+if and only if `r > 0` and `f` tends to negative infinity or `r < 0` and `f` tends to infinity. -/
+theorem tendsto_mul_const_atBot_iff [NeBot l] :
+ Tendsto (fun x => f x * r) l atBot ↔ 0 < r ∧ Tendsto f l atBot ∨ r < 0 ∧ Tendsto f l atTop := by
+ simp only [mul_comm _ r, tendsto_const_mul_atBot_iff]
+
+/-- The function `fun x ↦ f x / r` tends to negative infinity along a nontrivial filter
+if and only if `r > 0` and `f` tends to negative infinity or `r < 0` and `f` tends to infinity. -/
+lemma tendsto_div_const_atBot_iff [NeBot l] :
+ Tendsto (fun x ↦ f x / r) l atBot ↔ 0 < r ∧ Tendsto f l atBot ∨ r < 0 ∧ Tendsto f l atTop := by
+ simp [div_eq_mul_inv, tendsto_mul_const_atBot_iff]
+
+/-- If `f` tends to negative infinity along a nontrivial filter `l`,
+then `fun x ↦ r * f x` tends to infinity if and only if `r < 0. `-/
+theorem tendsto_const_mul_atTop_iff_neg [NeBot l] (h : Tendsto f l atBot) :
+ Tendsto (fun x => r * f x) l atTop ↔ r < 0 := by
+ simp [tendsto_const_mul_atTop_iff, h, h.not_tendsto disjoint_atBot_atTop]
+
+/-- If `f` tends to negative infinity along a nontrivial filter `l`,
+then `fun x ↦ f x * r` tends to infinity if and only if `r < 0. `-/
+theorem tendsto_mul_const_atTop_iff_neg [NeBot l] (h : Tendsto f l atBot) :
+ Tendsto (fun x => f x * r) l atTop ↔ r < 0 := by
+ simp only [mul_comm _ r, tendsto_const_mul_atTop_iff_neg h]
+
+/-- If `f` tends to negative infinity along a nontrivial filter `l`,
+then `fun x ↦ f x / r` tends to infinity if and only if `r < 0. `-/
+lemma tendsto_div_const_atTop_iff_neg [NeBot l] (h : Tendsto f l atBot) :
+ Tendsto (fun x ↦ f x / r) l atTop ↔ r < 0 := by
+ simp [div_eq_mul_inv, tendsto_mul_const_atTop_iff_neg h]
+
+/-- If `f` tends to negative infinity along a nontrivial filter `l`, then
+`fun x ↦ r * f x` tends to negative infinity if and only if `0 < r. `-/
+theorem tendsto_const_mul_atBot_iff_pos [NeBot l] (h : Tendsto f l atBot) :
+ Tendsto (fun x => r * f x) l atBot ↔ 0 < r := by
+ simp [tendsto_const_mul_atBot_iff, h, h.not_tendsto disjoint_atBot_atTop]
+
+/-- If `f` tends to negative infinity along a nontrivial filter `l`, then
+`fun x ↦ f x * r` tends to negative infinity if and only if `0 < r. `-/
+theorem tendsto_mul_const_atBot_iff_pos [NeBot l] (h : Tendsto f l atBot) :
+ Tendsto (fun x => f x * r) l atBot ↔ 0 < r := by
+ simp only [mul_comm _ r, tendsto_const_mul_atBot_iff_pos h]
+
+/-- If `f` tends to negative infinity along a nontrivial filter `l`, then
+`fun x ↦ f x / r` tends to negative infinity if and only if `0 < r. `-/
+lemma tendsto_div_const_atBot_iff_pos [NeBot l] (h : Tendsto f l atBot) :
+ Tendsto (fun x ↦ f x / r) l atBot ↔ 0 < r := by
+ simp [div_eq_mul_inv, tendsto_mul_const_atBot_iff_pos h]
+
+/-- If `f` tends to infinity along a nontrivial filter,
+`fun x ↦ r * f x` tends to negative infinity if and only if `r < 0. `-/
+theorem tendsto_const_mul_atBot_iff_neg [NeBot l] (h : Tendsto f l atTop) :
+ Tendsto (fun x => r * f x) l atBot ↔ r < 0 := by
+ simp [tendsto_const_mul_atBot_iff, h, h.not_tendsto disjoint_atTop_atBot]
+
+/-- If `f` tends to infinity along a nontrivial filter,
+`fun x ↦ f x * r` tends to negative infinity if and only if `r < 0. `-/
+theorem tendsto_mul_const_atBot_iff_neg [NeBot l] (h : Tendsto f l atTop) :
+ Tendsto (fun x => f x * r) l atBot ↔ r < 0 := by
+ simp only [mul_comm _ r, tendsto_const_mul_atBot_iff_neg h]
+
+/-- If `f` tends to infinity along a nontrivial filter,
+`fun x ↦ f x / r` tends to negative infinity if and only if `r < 0. `-/
+lemma tendsto_div_const_atBot_iff_neg [NeBot l] (h : Tendsto f l atTop) :
+ Tendsto (fun x ↦ f x / r) l atBot ↔ r < 0 := by
+ simp [div_eq_mul_inv, tendsto_mul_const_atBot_iff_neg h]
+
+/-- If a function `f` tends to infinity along a filter,
+then `f` multiplied by a negative constant (on the left) tends to negative infinity. -/
+theorem Tendsto.const_mul_atTop_of_neg (hr : r < 0) (hf : Tendsto f l atTop) :
+ Tendsto (fun x => r * f x) l atBot :=
+ (tendsto_const_mul_atBot_of_neg hr).2 hf
+
+/-- If a function `f` tends to infinity along a filter,
+then `f` multiplied by a negative constant (on the right) tends to negative infinity. -/
+theorem Tendsto.atTop_mul_const_of_neg (hr : r < 0) (hf : Tendsto f l atTop) :
+ Tendsto (fun x => f x * r) l atBot :=
+ (tendsto_mul_const_atBot_of_neg hr).2 hf
+
+/-- If a function `f` tends to infinity along a filter,
+then `f` divided by a negative constant tends to negative infinity. -/
+lemma Tendsto.atTop_div_const_of_neg (hr : r < 0) (hf : Tendsto f l atTop) :
+ Tendsto (fun x ↦ f x / r) l atBot := (tendsto_div_const_atBot_of_neg hr).2 hf
+
+/-- If a function `f` tends to negative infinity along a filter, then `f` multiplied by
+a positive constant (on the left) also tends to negative infinity. -/
+theorem Tendsto.const_mul_atBot (hr : 0 < r) (hf : Tendsto f l atBot) :
+ Tendsto (fun x => r * f x) l atBot :=
+ (tendsto_const_mul_atBot_of_pos hr).2 hf
+
+/-- If a function `f` tends to negative infinity along a filter, then `f` multiplied by
+a positive constant (on the right) also tends to negative infinity. -/
+theorem Tendsto.atBot_mul_const (hr : 0 < r) (hf : Tendsto f l atBot) :
+ Tendsto (fun x => f x * r) l atBot :=
+ (tendsto_mul_const_atBot_of_pos hr).2 hf
+
+/-- If a function `f` tends to negative infinity along a filter, then `f` divided by
+a positive constant also tends to negative infinity. -/
+theorem Tendsto.atBot_div_const (hr : 0 < r) (hf : Tendsto f l atBot) :
+ Tendsto (fun x => f x / r) l atBot := (tendsto_div_const_atBot_of_pos hr).2 hf
+
+/-- If a function `f` tends to negative infinity along a filter,
+then `f` multiplied by a negative constant (on the left) tends to positive infinity. -/
+theorem Tendsto.const_mul_atBot_of_neg (hr : r < 0) (hf : Tendsto f l atBot) :
+ Tendsto (fun x => r * f x) l atTop :=
+ (tendsto_const_mul_atTop_of_neg hr).2 hf
+
+/-- If a function tends to negative infinity along a filter,
+then `f` multiplied by a negative constant (on the right) tends to positive infinity. -/
+theorem Tendsto.atBot_mul_const_of_neg (hr : r < 0) (hf : Tendsto f l atBot) :
+ Tendsto (fun x => f x * r) l atTop :=
+ (tendsto_mul_const_atTop_of_neg hr).2 hf
+
+theorem tendsto_neg_const_mul_pow_atTop {c : α} {n : ℕ} (hn : n ≠ 0) (hc : c < 0) :
+ Tendsto (fun x => c * x ^ n) atTop atBot :=
+ (tendsto_pow_atTop hn).const_mul_atTop_of_neg hc
+
+theorem tendsto_const_mul_pow_atBot_iff {c : α} {n : ℕ} :
+ Tendsto (fun x => c * x ^ n) atTop atBot ↔ n ≠ 0 ∧ c < 0 := by
+ simp only [← tendsto_neg_atTop_iff, ← neg_mul, tendsto_const_mul_pow_atTop_iff, neg_pos]
+
+@[deprecated (since := "2024-05-06")]
+alias Tendsto.neg_const_mul_atTop := Tendsto.const_mul_atTop_of_neg
+
+@[deprecated (since := "2024-05-06")]
+alias Tendsto.atTop_mul_neg_const := Tendsto.atTop_mul_const_of_neg
+
+@[deprecated (since := "2024-05-06")]
+alias Tendsto.neg_const_mul_atBot := Tendsto.const_mul_atBot_of_neg
+
+@[deprecated (since := "2024-05-06")]
+alias Tendsto.atBot_mul_neg_const := Tendsto.atBot_mul_const_of_neg
+
+end LinearOrderedField
+end Filter
diff --git a/Mathlib/Order/Filter/AtTopBot/Floor.lean b/Mathlib/Order/Filter/AtTopBot/Floor.lean
new file mode 100644
index 0000000000000..32e3e3aad7c86
--- /dev/null
+++ b/Mathlib/Order/Filter/AtTopBot/Floor.lean
@@ -0,0 +1,28 @@
+/-
+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.Order.Floor
+import Mathlib.Order.Filter.AtTopBot
+
+/-!
+# `a * c ^ n < (n - d)!` holds true for sufficiently large `n`.
+-/
+
+open Filter
+open scoped Nat
+
+variable {K : Type*} [LinearOrderedRing K] [FloorSemiring K]
+
+theorem FloorSemiring.eventually_mul_pow_lt_factorial_sub (a c : K) (d : ℕ) :
+ ∀ᶠ n in atTop, a * c ^ n < (n - d)! := by
+ filter_upwards [Nat.eventually_mul_pow_lt_factorial_sub ⌈|a|⌉₊ ⌈|c|⌉₊ d] with n h
+ calc a * c ^ n
+ _ ≤ |a * c ^ n| := le_abs_self _
+ _ ≤ ⌈|a|⌉₊ * (⌈|c|⌉₊ : K) ^ n := ?_
+ _ = ↑(⌈|a|⌉₊ * ⌈|c|⌉₊ ^ n) := ?_
+ _ < (n - d)! := Nat.cast_lt.mpr h
+ · rw [abs_mul, abs_pow]
+ gcongr <;> try first | positivity | apply Nat.le_ceil
+ · simp_rw [Nat.cast_mul, Nat.cast_pow]
diff --git a/Mathlib/Order/Filter/AtTopBot/Group.lean b/Mathlib/Order/Filter/AtTopBot/Group.lean
new file mode 100644
index 0000000000000..4c4b84aeb895d
--- /dev/null
+++ b/Mathlib/Order/Filter/AtTopBot/Group.lean
@@ -0,0 +1,127 @@
+/-
+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.Algebra.Order.Group.Instances
+import Mathlib.Algebra.Order.Group.MinMax
+import Mathlib.Order.Filter.AtTopBot.Monoid
+
+/-!
+# Convergence to ±infinity in ordered commutative groups
+-/
+
+variable {α β : Type*}
+open Set
+
+namespace Filter
+
+section OrderedGroup
+
+variable [OrderedAddCommGroup β] (l : Filter α) {f g : α → β}
+
+theorem tendsto_atTop_add_left_of_le' (C : β) (hf : ∀ᶠ x in l, C ≤ f x) (hg : Tendsto g l atTop) :
+ Tendsto (fun x => f x + g x) l atTop :=
+ @tendsto_atTop_of_add_bdd_above_left' _ _ _ l (fun x => -f x) (fun x => f x + g x) (-C) (by simpa)
+ (by simpa)
+
+theorem tendsto_atBot_add_left_of_ge' (C : β) (hf : ∀ᶠ x in l, f x ≤ C) (hg : Tendsto g l atBot) :
+ Tendsto (fun x => f x + g x) l atBot :=
+ @tendsto_atTop_add_left_of_le' _ βᵒᵈ _ _ _ _ C hf hg
+
+theorem tendsto_atTop_add_left_of_le (C : β) (hf : ∀ x, C ≤ f x) (hg : Tendsto g l atTop) :
+ Tendsto (fun x => f x + g x) l atTop :=
+ tendsto_atTop_add_left_of_le' l C (univ_mem' hf) hg
+
+theorem tendsto_atBot_add_left_of_ge (C : β) (hf : ∀ x, f x ≤ C) (hg : Tendsto g l atBot) :
+ Tendsto (fun x => f x + g x) l atBot :=
+ @tendsto_atTop_add_left_of_le _ βᵒᵈ _ _ _ _ C hf hg
+
+theorem tendsto_atTop_add_right_of_le' (C : β) (hf : Tendsto f l atTop) (hg : ∀ᶠ x in l, C ≤ g x) :
+ Tendsto (fun x => f x + g x) l atTop :=
+ @tendsto_atTop_of_add_bdd_above_right' _ _ _ l (fun x => f x + g x) (fun x => -g x) (-C)
+ (by simp [hg]) (by simp [hf])
+
+theorem tendsto_atBot_add_right_of_ge' (C : β) (hf : Tendsto f l atBot) (hg : ∀ᶠ x in l, g x ≤ C) :
+ Tendsto (fun x => f x + g x) l atBot :=
+ @tendsto_atTop_add_right_of_le' _ βᵒᵈ _ _ _ _ C hf hg
+
+theorem tendsto_atTop_add_right_of_le (C : β) (hf : Tendsto f l atTop) (hg : ∀ x, C ≤ g x) :
+ Tendsto (fun x => f x + g x) l atTop :=
+ tendsto_atTop_add_right_of_le' l C hf (univ_mem' hg)
+
+theorem tendsto_atBot_add_right_of_ge (C : β) (hf : Tendsto f l atBot) (hg : ∀ x, g x ≤ C) :
+ Tendsto (fun x => f x + g x) l atBot :=
+ @tendsto_atTop_add_right_of_le _ βᵒᵈ _ _ _ _ C hf hg
+
+theorem tendsto_atTop_add_const_left (C : β) (hf : Tendsto f l atTop) :
+ Tendsto (fun x => C + f x) l atTop :=
+ tendsto_atTop_add_left_of_le' l C (univ_mem' fun _ => le_refl C) hf
+
+theorem tendsto_atBot_add_const_left (C : β) (hf : Tendsto f l atBot) :
+ Tendsto (fun x => C + f x) l atBot :=
+ @tendsto_atTop_add_const_left _ βᵒᵈ _ _ _ C hf
+
+theorem tendsto_atTop_add_const_right (C : β) (hf : Tendsto f l atTop) :
+ Tendsto (fun x => f x + C) l atTop :=
+ tendsto_atTop_add_right_of_le' l C hf (univ_mem' fun _ => le_refl C)
+
+theorem tendsto_atBot_add_const_right (C : β) (hf : Tendsto f l atBot) :
+ Tendsto (fun x => f x + C) l atBot :=
+ @tendsto_atTop_add_const_right _ βᵒᵈ _ _ _ C hf
+
+theorem map_neg_atBot : map (Neg.neg : β → β) atBot = atTop :=
+ (OrderIso.neg β).map_atBot
+
+theorem map_neg_atTop : map (Neg.neg : β → β) atTop = atBot :=
+ (OrderIso.neg β).map_atTop
+
+theorem comap_neg_atBot : comap (Neg.neg : β → β) atBot = atTop :=
+ (OrderIso.neg β).comap_atTop
+
+theorem comap_neg_atTop : comap (Neg.neg : β → β) atTop = atBot :=
+ (OrderIso.neg β).comap_atBot
+
+theorem tendsto_neg_atTop_atBot : Tendsto (Neg.neg : β → β) atTop atBot :=
+ (OrderIso.neg β).tendsto_atTop
+
+theorem tendsto_neg_atBot_atTop : Tendsto (Neg.neg : β → β) atBot atTop :=
+ @tendsto_neg_atTop_atBot βᵒᵈ _
+
+variable {l}
+
+@[simp]
+theorem tendsto_neg_atTop_iff : Tendsto (fun x => -f x) l atTop ↔ Tendsto f l atBot :=
+ (OrderIso.neg β).tendsto_atBot_iff
+
+@[simp]
+theorem tendsto_neg_atBot_iff : Tendsto (fun x => -f x) l atBot ↔ Tendsto f l atTop :=
+ (OrderIso.neg β).tendsto_atTop_iff
+
+end OrderedGroup
+
+section LinearOrderedAddCommGroup
+
+variable [LinearOrderedAddCommGroup α]
+
+/-- $\lim_{x\to+\infty}|x|=+\infty$ -/
+theorem tendsto_abs_atTop_atTop : Tendsto (abs : α → α) atTop atTop :=
+ tendsto_atTop_mono le_abs_self tendsto_id
+
+/-- $\lim_{x\to-\infty}|x|=+\infty$ -/
+theorem tendsto_abs_atBot_atTop : Tendsto (abs : α → α) atBot atTop :=
+ tendsto_atTop_mono neg_le_abs tendsto_neg_atBot_atTop
+
+@[simp]
+theorem comap_abs_atTop : comap (abs : α → α) atTop = atBot ⊔ atTop := by
+ refine
+ le_antisymm (((atTop_basis.comap _).le_basis_iff (atBot_basis.sup atTop_basis)).2 ?_)
+ (sup_le tendsto_abs_atBot_atTop.le_comap tendsto_abs_atTop_atTop.le_comap)
+ rintro ⟨a, b⟩ -
+ refine ⟨max (-a) b, trivial, fun x hx => ?_⟩
+ rw [mem_preimage, mem_Ici, le_abs', max_le_iff, ← min_neg_neg, le_min_iff, neg_neg] at hx
+ exact hx.imp And.left And.right
+
+end LinearOrderedAddCommGroup
+
+end Filter
diff --git a/Mathlib/Order/Filter/ModEq.lean b/Mathlib/Order/Filter/AtTopBot/ModEq.lean
similarity index 86%
rename from Mathlib/Order/Filter/ModEq.lean
rename to Mathlib/Order/Filter/AtTopBot/ModEq.lean
index 0b9c0b89ea5f7..d45c17cc0d74b 100644
--- a/Mathlib/Order/Filter/ModEq.lean
+++ b/Mathlib/Order/Filter/AtTopBot/ModEq.lean
@@ -3,9 +3,12 @@ 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.Algebra.Order.Ring.Abs
+import Mathlib.Algebra.Order.Ring.Basic
+import Mathlib.Algebra.Order.Ring.Nat
+import Mathlib.Algebra.Ring.Divisibility.Basic
+import Mathlib.Algebra.Ring.Int
import Mathlib.Data.Nat.ModEq
-import Mathlib.Order.Filter.AtTopBot
+import Mathlib.Order.Filter.AtTopBot.Monoid
/-!
# Numbers are frequently ModEq to fixed numbers
diff --git a/Mathlib/Order/Filter/AtTopBot/Monoid.lean b/Mathlib/Order/Filter/AtTopBot/Monoid.lean
new file mode 100644
index 0000000000000..0cfa275d9a426
--- /dev/null
+++ b/Mathlib/Order/Filter/AtTopBot/Monoid.lean
@@ -0,0 +1,141 @@
+/-
+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.Algebra.Order.Monoid.OrderDual
+import Mathlib.Order.Filter.AtTopBot
+
+/-!
+# Convergence to ±infinity in ordered commutative monoids
+-/
+
+variable {α β : Type*}
+
+namespace Filter
+
+section OrderedAddCommMonoid
+
+variable [OrderedAddCommMonoid β] {l : Filter α} {f g : α → β}
+
+theorem tendsto_atTop_add_nonneg_left' (hf : ∀ᶠ x in l, 0 ≤ f x) (hg : Tendsto g l atTop) :
+ Tendsto (fun x => f x + g x) l atTop :=
+ tendsto_atTop_mono' l (hf.mono fun _ => le_add_of_nonneg_left) hg
+
+theorem tendsto_atBot_add_nonpos_left' (hf : ∀ᶠ x in l, f x ≤ 0) (hg : Tendsto g l atBot) :
+ Tendsto (fun x => f x + g x) l atBot :=
+ @tendsto_atTop_add_nonneg_left' _ βᵒᵈ _ _ _ _ hf hg
+
+theorem tendsto_atTop_add_nonneg_left (hf : ∀ x, 0 ≤ f x) (hg : Tendsto g l atTop) :
+ Tendsto (fun x => f x + g x) l atTop :=
+ tendsto_atTop_add_nonneg_left' (Eventually.of_forall hf) hg
+
+theorem tendsto_atBot_add_nonpos_left (hf : ∀ x, f x ≤ 0) (hg : Tendsto g l atBot) :
+ Tendsto (fun x => f x + g x) l atBot :=
+ @tendsto_atTop_add_nonneg_left _ βᵒᵈ _ _ _ _ hf hg
+
+theorem tendsto_atTop_add_nonneg_right' (hf : Tendsto f l atTop) (hg : ∀ᶠ x in l, 0 ≤ g x) :
+ Tendsto (fun x => f x + g x) l atTop :=
+ tendsto_atTop_mono' l (monotone_mem (fun _ => le_add_of_nonneg_right) hg) hf
+
+theorem tendsto_atBot_add_nonpos_right' (hf : Tendsto f l atBot) (hg : ∀ᶠ x in l, g x ≤ 0) :
+ Tendsto (fun x => f x + g x) l atBot :=
+ @tendsto_atTop_add_nonneg_right' _ βᵒᵈ _ _ _ _ hf hg
+
+theorem tendsto_atTop_add_nonneg_right (hf : Tendsto f l atTop) (hg : ∀ x, 0 ≤ g x) :
+ Tendsto (fun x => f x + g x) l atTop :=
+ tendsto_atTop_add_nonneg_right' hf (Eventually.of_forall hg)
+
+theorem tendsto_atBot_add_nonpos_right (hf : Tendsto f l atBot) (hg : ∀ x, g x ≤ 0) :
+ Tendsto (fun x => f x + g x) l atBot :=
+ @tendsto_atTop_add_nonneg_right _ βᵒᵈ _ _ _ _ hf hg
+
+theorem tendsto_atTop_add (hf : Tendsto f l atTop) (hg : Tendsto g l atTop) :
+ Tendsto (fun x => f x + g x) l atTop :=
+ tendsto_atTop_add_nonneg_left' (tendsto_atTop.mp hf 0) hg
+
+theorem tendsto_atBot_add (hf : Tendsto f l atBot) (hg : Tendsto g l atBot) :
+ Tendsto (fun x => f x + g x) l atBot :=
+ @tendsto_atTop_add _ βᵒᵈ _ _ _ _ hf hg
+
+theorem Tendsto.nsmul_atTop (hf : Tendsto f l atTop) {n : ℕ} (hn : 0 < n) :
+ Tendsto (fun x => n • f x) l atTop :=
+ tendsto_atTop.2 fun y =>
+ (tendsto_atTop.1 hf y).mp <|
+ (tendsto_atTop.1 hf 0).mono fun x h₀ hy =>
+ calc
+ y ≤ f x := hy
+ _ = 1 • f x := (one_nsmul _).symm
+ _ ≤ n • f x := nsmul_le_nsmul_left h₀ hn
+
+theorem Tendsto.nsmul_atBot (hf : Tendsto f l atBot) {n : ℕ} (hn : 0 < n) :
+ Tendsto (fun x => n • f x) l atBot :=
+ @Tendsto.nsmul_atTop α βᵒᵈ _ l f hf n hn
+
+end OrderedAddCommMonoid
+
+section OrderedCancelAddCommMonoid
+
+variable [OrderedCancelAddCommMonoid β] {l : Filter α} {f g : α → β}
+
+theorem tendsto_atTop_of_add_const_left (C : β) (hf : Tendsto (fun x => C + f x) l atTop) :
+ Tendsto f l atTop :=
+ tendsto_atTop.2 fun b => (tendsto_atTop.1 hf (C + b)).mono fun _ => le_of_add_le_add_left
+
+-- Porting note: the "order dual" trick timeouts
+theorem tendsto_atBot_of_add_const_left (C : β) (hf : Tendsto (fun x => C + f x) l atBot) :
+ Tendsto f l atBot :=
+ tendsto_atBot.2 fun b => (tendsto_atBot.1 hf (C + b)).mono fun _ => le_of_add_le_add_left
+
+theorem tendsto_atTop_of_add_const_right (C : β) (hf : Tendsto (fun x => f x + C) l atTop) :
+ Tendsto f l atTop :=
+ tendsto_atTop.2 fun b => (tendsto_atTop.1 hf (b + C)).mono fun _ => le_of_add_le_add_right
+
+-- Porting note: the "order dual" trick timeouts
+theorem tendsto_atBot_of_add_const_right (C : β) (hf : Tendsto (fun x => f x + C) l atBot) :
+ Tendsto f l atBot :=
+ tendsto_atBot.2 fun b => (tendsto_atBot.1 hf (b + C)).mono fun _ => le_of_add_le_add_right
+
+theorem tendsto_atTop_of_add_bdd_above_left' (C) (hC : ∀ᶠ x in l, f x ≤ C)
+ (h : Tendsto (fun x => f x + g x) l atTop) : Tendsto g l atTop :=
+ tendsto_atTop_of_add_const_left C
+ (tendsto_atTop_mono' l (hC.mono fun x hx => add_le_add_right hx (g x)) h)
+
+-- Porting note: the "order dual" trick timeouts
+theorem tendsto_atBot_of_add_bdd_below_left' (C) (hC : ∀ᶠ x in l, C ≤ f x)
+ (h : Tendsto (fun x => f x + g x) l atBot) : Tendsto g l atBot :=
+ tendsto_atBot_of_add_const_left C
+ (tendsto_atBot_mono' l (hC.mono fun x hx => add_le_add_right hx (g x)) h)
+
+theorem tendsto_atTop_of_add_bdd_above_left (C) (hC : ∀ x, f x ≤ C) :
+ Tendsto (fun x => f x + g x) l atTop → Tendsto g l atTop :=
+ tendsto_atTop_of_add_bdd_above_left' C (univ_mem' hC)
+
+-- Porting note: the "order dual" trick timeouts
+theorem tendsto_atBot_of_add_bdd_below_left (C) (hC : ∀ x, C ≤ f x) :
+ Tendsto (fun x => f x + g x) l atBot → Tendsto g l atBot :=
+ tendsto_atBot_of_add_bdd_below_left' C (univ_mem' hC)
+
+theorem tendsto_atTop_of_add_bdd_above_right' (C) (hC : ∀ᶠ x in l, g x ≤ C)
+ (h : Tendsto (fun x => f x + g x) l atTop) : Tendsto f l atTop :=
+ tendsto_atTop_of_add_const_right C
+ (tendsto_atTop_mono' l (hC.mono fun x hx => add_le_add_left hx (f x)) h)
+
+-- Porting note: the "order dual" trick timeouts
+theorem tendsto_atBot_of_add_bdd_below_right' (C) (hC : ∀ᶠ x in l, C ≤ g x)
+ (h : Tendsto (fun x => f x + g x) l atBot) : Tendsto f l atBot :=
+ tendsto_atBot_of_add_const_right C
+ (tendsto_atBot_mono' l (hC.mono fun x hx => add_le_add_left hx (f x)) h)
+
+theorem tendsto_atTop_of_add_bdd_above_right (C) (hC : ∀ x, g x ≤ C) :
+ Tendsto (fun x => f x + g x) l atTop → Tendsto f l atTop :=
+ tendsto_atTop_of_add_bdd_above_right' C (univ_mem' hC)
+
+-- Porting note: the "order dual" trick timeouts
+theorem tendsto_atBot_of_add_bdd_below_right (C) (hC : ∀ x, C ≤ g x) :
+ Tendsto (fun x => f x + g x) l atBot → Tendsto f l atBot :=
+ tendsto_atBot_of_add_bdd_below_right' C (univ_mem' hC)
+
+end OrderedCancelAddCommMonoid
+
+end Filter
diff --git a/Mathlib/Order/Filter/AtTopBot/Ring.lean b/Mathlib/Order/Filter/AtTopBot/Ring.lean
new file mode 100644
index 0000000000000..74207b0e55f14
--- /dev/null
+++ b/Mathlib/Order/Filter/AtTopBot/Ring.lean
@@ -0,0 +1,104 @@
+/-
+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.Algebra.Order.Ring.Defs
+import Mathlib.Order.Filter.AtTopBot.Group
+
+/-!
+# Convergence to ±infinity in ordered rings
+-/
+
+variable {α β : Type*}
+
+namespace Filter
+
+section OrderedSemiring
+
+variable [OrderedSemiring α] {l : Filter β} {f g : β → α}
+
+theorem Tendsto.atTop_mul_atTop (hf : Tendsto f l atTop) (hg : Tendsto g l atTop) :
+ Tendsto (fun x => f x * g x) l atTop := by
+ refine tendsto_atTop_mono' _ ?_ hg
+ filter_upwards [hg.eventually (eventually_ge_atTop 0),
+ hf.eventually (eventually_ge_atTop 1)] with _ using le_mul_of_one_le_left
+
+theorem tendsto_mul_self_atTop : Tendsto (fun x : α => x * x) atTop atTop :=
+ tendsto_id.atTop_mul_atTop tendsto_id
+
+/-- The monomial function `x^n` tends to `+∞` at `+∞` for any positive natural `n`.
+A version for positive real powers exists as `tendsto_rpow_atTop`. -/
+theorem tendsto_pow_atTop {n : ℕ} (hn : n ≠ 0) : Tendsto (fun x : α => x ^ n) atTop atTop :=
+ tendsto_atTop_mono' _ ((eventually_ge_atTop 1).mono fun _x hx => le_self_pow₀ hx hn) tendsto_id
+
+end OrderedSemiring
+
+theorem zero_pow_eventuallyEq [MonoidWithZero α] :
+ (fun n : ℕ => (0 : α) ^ n) =ᶠ[atTop] fun _ => 0 :=
+ eventually_atTop.2 ⟨1, fun _n hn ↦ zero_pow <| Nat.one_le_iff_ne_zero.1 hn⟩
+
+section OrderedRing
+
+variable [OrderedRing α] {l : Filter β} {f g : β → α}
+
+theorem Tendsto.atTop_mul_atBot (hf : Tendsto f l atTop) (hg : Tendsto g l atBot) :
+ Tendsto (fun x => f x * g x) l atBot := by
+ have := hf.atTop_mul_atTop <| tendsto_neg_atBot_atTop.comp hg
+ simpa only [Function.comp_def, neg_mul_eq_mul_neg, neg_neg] using
+ tendsto_neg_atTop_atBot.comp this
+
+theorem Tendsto.atBot_mul_atTop (hf : Tendsto f l atBot) (hg : Tendsto g l atTop) :
+ Tendsto (fun x => f x * g x) l atBot := by
+ have : Tendsto (fun x => -f x * g x) l atTop :=
+ (tendsto_neg_atBot_atTop.comp hf).atTop_mul_atTop hg
+ simpa only [Function.comp_def, neg_mul_eq_neg_mul, neg_neg] using
+ tendsto_neg_atTop_atBot.comp this
+
+theorem Tendsto.atBot_mul_atBot (hf : Tendsto f l atBot) (hg : Tendsto g l atBot) :
+ Tendsto (fun x => f x * g x) l atTop := by
+ have : Tendsto (fun x => -f x * -g x) l atTop :=
+ (tendsto_neg_atBot_atTop.comp hf).atTop_mul_atTop (tendsto_neg_atBot_atTop.comp hg)
+ simpa only [neg_mul_neg] using this
+
+end OrderedRing
+
+section LinearOrderedSemiring
+
+variable [LinearOrderedSemiring α] {l : Filter β} {f : β → α}
+
+theorem Tendsto.atTop_of_const_mul {c : α} (hc : 0 < c) (hf : Tendsto (fun x => c * f x) l atTop) :
+ Tendsto f l atTop :=
+ tendsto_atTop.2 fun b => (tendsto_atTop.1 hf (c * b)).mono
+ fun _x hx => le_of_mul_le_mul_left hx hc
+
+theorem Tendsto.atTop_of_mul_const {c : α} (hc : 0 < c) (hf : Tendsto (fun x => f x * c) l atTop) :
+ Tendsto f l atTop :=
+ tendsto_atTop.2 fun b => (tendsto_atTop.1 hf (b * c)).mono
+ fun _x hx => le_of_mul_le_mul_right hx hc
+
+@[simp]
+theorem tendsto_pow_atTop_iff {n : ℕ} : Tendsto (fun x : α => x ^ n) atTop atTop ↔ n ≠ 0 :=
+ ⟨fun h hn => by simp only [hn, pow_zero, not_tendsto_const_atTop] at h, tendsto_pow_atTop⟩
+
+end LinearOrderedSemiring
+
+theorem not_tendsto_pow_atTop_atBot [LinearOrderedRing α] :
+ ∀ {n : ℕ}, ¬Tendsto (fun x : α => x ^ n) atTop atBot
+ | 0 => by simp [not_tendsto_const_atBot]
+ | n + 1 => (tendsto_pow_atTop n.succ_ne_zero).not_tendsto disjoint_atTop_atBot
+
+end Filter
+
+open Filter
+
+variable {R : Type*} [LinearOrderedSemiring R]
+
+theorem exists_lt_mul_self (a : R) : ∃ x ≥ 0, a < x * x :=
+ let ⟨x, hxa, hx0⟩ :=
+ ((tendsto_mul_self_atTop.eventually (eventually_gt_atTop a)).and (eventually_ge_atTop 0)).exists
+ ⟨x, hx0, hxa⟩
+
+theorem exists_le_mul_self (a : R) : ∃ x ≥ 0, a ≤ x * x :=
+ let ⟨x, hx0, hxa⟩ := exists_lt_mul_self a
+ ⟨x, hx0, hxa.le⟩
diff --git a/Mathlib/Order/Filter/Bases.lean b/Mathlib/Order/Filter/Bases.lean
index 4891e31ed0e66..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
@@ -117,7 +116,7 @@ def Filter.asBasis (f : Filter α) : FilterBasis α :=
⟨f.sets, ⟨univ, univ_mem⟩, fun {x y} hx hy => ⟨x ∩ y, inter_mem hx hy, subset_rfl⟩⟩
-- Porting note: was `protected` in Lean 3 but `protected` didn't work; removed
-/-- `is_basis p s` means the image of `s` bounded by `p` is a filter basis. -/
+/-- `IsBasis p s` means the image of `s` bounded by `p` is a filter basis. -/
structure Filter.IsBasis (p : ι → Prop) (s : ι → Set α) : Prop where
/-- There exists at least one `i` that satisfies `p`. -/
nonempty : ∃ i, p i
@@ -543,7 +542,7 @@ theorem hasBasis_iSup {ι : Sort*} {ι' : ι → Type*} {l : ι → Filter α} {
theorem HasBasis.sup_principal (hl : l.HasBasis p s) (t : Set α) :
(l ⊔ 𝓟 t).HasBasis p fun i => s i ∪ t :=
⟨fun u => by
- simp only [(hl.sup' (hasBasis_principal t)).mem_iff, PProd.exists, exists_prop, and_true_iff,
+ simp only [(hl.sup' (hasBasis_principal t)).mem_iff, PProd.exists, exists_prop, and_true,
Unique.exists_iff]⟩
theorem HasBasis.sup_pure (hl : l.HasBasis p s) (x : α) :
@@ -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
@@ -668,7 +663,7 @@ theorem HasBasis.eq_iInf (h : l.HasBasis (fun _ => True) s) : l = ⨅ i, 𝓟 (s
theorem hasBasis_iInf_principal {s : ι → Set α} (h : Directed (· ≥ ·) s) [Nonempty ι] :
(⨅ i, 𝓟 (s i)).HasBasis (fun _ => True) s :=
⟨fun t => by
- simpa only [true_and] using mem_iInf_of_directed (h.mono_comp monotone_principal.dual) t⟩
+ simpa only [true_and] using mem_iInf_of_directed (h.mono_comp _ monotone_principal.dual) t⟩
/-- If `s : ι → Set α` is an indexed family of sets, then finite intersections of `s i` form a basis
of `⨅ i, 𝓟 (s i)`. -/
@@ -683,7 +678,7 @@ theorem hasBasis_biInf_principal {s : β → Set α} {S : Set β} (h : DirectedO
⟨fun t => by
refine mem_biInf_of_directed ?_ ne
rw [directedOn_iff_directed, ← directed_comp] at h ⊢
- refine h.mono_comp ?_
+ refine h.mono_comp _ ?_
exact fun _ _ => principal_mono.2⟩
theorem hasBasis_biInf_principal' {ι : Type*} {p : ι → Prop} {s : ι → Set α}
@@ -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 79bc93e777efe..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,20 +318,16 @@ 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, iff_self_iff, mem_iInter]
+ simp only [← Filter.mem_sets, iSup_sets_eq, mem_iInter]
@[simp]
theorem iSup_neBot {f : ι → Filter α} : (⨆ i, f i).NeBot ↔ ∃ i, (f i).NeBot := by
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
@@ -575,7 +372,7 @@ theorem mem_iInf' {ι} {s : ι → Filter α} {U : Set α} :
exacts [hV ⟨i,_⟩, univ_mem]
· exact dif_neg hi
· simp only [iInter_dite, biInter_eq_iInter, dif_pos (Subtype.coe_prop _), Subtype.coe_eta,
- iInter_univ, inter_univ, eq_self_iff_true, true_and_iff]
+ iInter_univ, inter_univ, eq_self_iff_true, true_and]
theorem exists_iInter_of_mem_iInf {ι : Type*} {α : Type*} {f : ι → Filter α} {s}
(hs : s ∈ ⨅ i, f i) : ∃ t : ι → Set α, (∀ i, t i ∈ f i) ∧ s = ⋂ i, t i :=
@@ -595,7 +392,7 @@ theorem Iic_principal (s : Set α) : Iic (𝓟 s) = { l | s ∈ l } :=
Set.ext fun _ => le_principal_iff
theorem principal_mono {s t : Set α} : 𝓟 s ≤ 𝓟 t ↔ s ⊆ t := by
- simp only [le_principal_iff, iff_self_iff, mem_principal]
+ simp only [le_principal_iff, mem_principal]
@[gcongr] alias ⟨_, _root_.GCongr.filter_principal_mono⟩ := principal_mono
@@ -785,12 +582,13 @@ instance : DistribLattice (Filter α) :=
x.sets_of_superset hs inter_subset_right, ht₂, rfl⟩ }
/-- The dual version does not hold! `Filter α` is not a `CompleteDistribLattice`. -/
-def coframeMinimalAxioms : Coframe.MinimalAxioms (Filter α) :=
+-- See note [reducible non-instances]
+abbrev coframeMinimalAxioms : Coframe.MinimalAxioms (Filter α) :=
{ Filter.instCompleteLatticeFilter with
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⟩
@@ -949,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
@@ -1105,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
@@ -1162,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} :
@@ -1209,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
@@ -1265,17 +1047,12 @@ 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
-theorem EventuallyEq.eventually {l : Filter α} {f g : α → β} (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]
theorem EventuallyEq.rw {l : Filter α} {f g : α → β} (h : f =ᶠ[l] g) (p : α → β → Prop)
(hf : ∀ᶠ x in l, p x (f x)) : ∀ᶠ x in l, p x (g x) :=
@@ -1445,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
@@ -1619,7 +1389,7 @@ theorem set_eventuallyLE_iff_mem_inf_principal {s t : Set α} {l : Filter α} :
theorem set_eventuallyLE_iff_inf_principal_le {s t : Set α} {l : Filter α} :
s ≤ᶠ[l] t ↔ l ⊓ 𝓟 s ≤ l ⊓ 𝓟 t :=
set_eventuallyLE_iff_mem_inf_principal.trans <| by
- simp only [le_inf_iff, inf_le_left, true_and_iff, le_principal_iff]
+ simp only [le_inf_iff, inf_le_left, true_and, le_principal_iff]
theorem set_eventuallyEq_iff_inf_principal {s t : Set α} {l : Filter α} :
s =ᶠ[l] t ↔ l ⊓ 𝓟 s = l ⊓ 𝓟 t := by
@@ -1644,17 +1414,12 @@ theorem EventuallyLE.le_sup_of_le_right [SemilatticeSup β] {l : Filter α} {f g
theorem join_le {f : Filter (Filter α)} {l : Filter α} (h : ∀ᶠ m in f, m ≤ l) : join f ≤ l :=
fun _ hs => h.mono fun _ hm => hm hs
+end EventuallyEq
+
/-! ### Push-forwards, pull-backs, and the monad structure -/
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
@@ -1719,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'`
@@ -1803,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
@@ -1842,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
@@ -2450,7 +2166,7 @@ theorem mem_seq_def {f : Filter (α → β)} {g : Filter α} {s : Set β} :
theorem mem_seq_iff {f : Filter (α → β)} {g : Filter α} {s : Set β} :
s ∈ f.seq g ↔ ∃ u ∈ f, ∃ t ∈ g, Set.seq u t ⊆ s := by
- simp only [mem_seq_def, seq_subset, exists_prop, iff_self_iff]
+ simp only [mem_seq_def, seq_subset, exists_prop]
theorem mem_map_seq_iff {f : Filter α} {g : Filter β} {m : α → β → γ} {s : Set γ} :
s ∈ (f.map m).seq g ↔ ∃ t u, t ∈ g ∧ u ∈ f ∧ ∀ x ∈ u, ∀ y ∈ t, m x y ∈ s :=
@@ -2588,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, iff_self_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, iff_self_iff, 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
@@ -2859,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
@@ -2909,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 6aaac667034f4..3ec97fbbb5501 100644
--- a/Mathlib/Order/Filter/EventuallyConst.lean
+++ b/Mathlib/Order/Filter/EventuallyConst.lean
@@ -3,6 +3,7 @@ Copyright (c) 2023 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov, Floris van Doorn
-/
+import Mathlib.Algebra.Group.Indicator
import Mathlib.Order.Filter.AtTopBot
import Mathlib.Order.Filter.Subsingleton
/-!
@@ -154,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 4f014874d2d27..c36a347ed094f 100644
--- a/Mathlib/Order/Filter/FilterProduct.lean
+++ b/Mathlib/Order/Filter/FilterProduct.lean
@@ -3,8 +3,10 @@ Copyright (c) 2019 Abhimanyu Pallavi Sudhir. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Abhimanyu Pallavi Sudhir, Yury Kudryashov
-/
-import Mathlib.Order.Filter.Ultrafilter
+import Mathlib.Algebra.Order.Field.Defs
+import Mathlib.Algebra.Order.Group.Unbundled.Abs
import Mathlib.Order.Filter.Ring
+import Mathlib.Order.Filter.Ultrafilter
/-!
# Ultraproducts
@@ -37,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/IndicatorFunction.lean b/Mathlib/Order/Filter/IndicatorFunction.lean
index d7338ff33d231..2b818c2fa7218 100644
--- a/Mathlib/Order/Filter/IndicatorFunction.lean
+++ b/Mathlib/Order/Filter/IndicatorFunction.lean
@@ -3,6 +3,7 @@ Copyright (c) 2020 Zhouhang Zhou. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Zhouhang Zhou, Yury Kudryashov
-/
+import Mathlib.Algebra.Group.Indicator
import Mathlib.Order.Filter.AtTopBot
/-!
diff --git a/Mathlib/Order/Filter/Ker.lean b/Mathlib/Order/Filter/Ker.lean
index 64eecf4a76499..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 _
@@ -54,4 +51,21 @@ lemma ker_surjective : Surjective (ker : Filter α → Set α) := gi_principal_k
simp only [mem_ker, mem_comap, forall_exists_index, and_imp, @forall_swap (Set α), mem_preimage]
exact forall₂_congr fun s _ ↦ ⟨fun h ↦ h _ Subset.rfl, fun ha t ht ↦ ht ha⟩
+@[simp]
+theorem ker_iSup (f : ι → Filter α) : ker (⨆ i, f i) = ⋃ i, ker (f i) := by
+ refine subset_antisymm (fun x hx ↦ ?_) ker_mono.le_map_iSup
+ simp only [mem_iUnion, mem_ker] at hx ⊢
+ contrapose! hx
+ choose s hsf hxs using hx
+ refine ⟨⋃ i, s i, ?_, by simpa⟩
+ exact mem_iSup.2 fun i ↦ mem_of_superset (hsf i) (subset_iUnion s i)
+
+@[simp]
+theorem ker_sSup (S : Set (Filter α)) : ker (sSup S) = ⋃ f ∈ S, ker f := by
+ simp [sSup_eq_iSup]
+
+@[simp]
+theorem ker_sup (f g : Filter α) : ker (f ⊔ g) = ker f ∪ ker g := by
+ rw [← sSup_pair, ker_sSup, biUnion_pair]
+
end Filter
diff --git a/Mathlib/Order/Filter/Lift.lean b/Mathlib/Order/Filter/Lift.lean
index 9c69971f95604..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]
@@ -362,7 +353,7 @@ theorem prod_same_eq : f ×ˢ f = f.lift' fun t : Set α => t ×ˢ t :=
theorem tendsto_prod_self_iff {f : α × α → β} {x : Filter α} {y : Filter β} :
Filter.Tendsto f (x ×ˢ x) y ↔ ∀ W ∈ y, ∃ U ∈ x, ∀ x x' : α, x ∈ U → x' ∈ U → f (x, x') ∈ W := by
- simp only [tendsto_def, mem_prod_same_iff, prod_sub_preimage_iff, exists_prop, iff_self_iff]
+ simp only [tendsto_def, mem_prod_same_iff, prod_sub_preimage_iff, exists_prop]
variable {α₁ : Type*} {α₂ : Type*} {β₁ : Type*} {β₂ : Type*}
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 a6d2ad7077877..987d9fae9f218 100644
--- a/Mathlib/Order/Filter/Pointwise.lean
+++ b/Mathlib/Order/Filter/Pointwise.lean
@@ -3,6 +3,8 @@ Copyright (c) 2019 Zhouhang Zhou. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Zhouhang Zhou, Yaël Dillies
-/
+import Mathlib.Algebra.Order.Group.Defs
+import Mathlib.Algebra.Order.Group.OrderIso
import Mathlib.Data.Set.Pointwise.SMul
import Mathlib.Order.Filter.NAry
import Mathlib.Order.Filter.Ultrafilter
@@ -310,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]
@@ -549,7 +551,7 @@ theorem pow_mem_pow (hs : s ∈ f) : ∀ n : ℕ, s ^ n ∈ f ^ n
@[to_additive (attr := simp) nsmul_bot]
theorem bot_pow {n : ℕ} (hn : n ≠ 0) : (⊥ : Filter α) ^ n = ⊥ := by
- rw [← tsub_add_cancel_of_le (Nat.succ_le_of_lt <| Nat.pos_of_ne_zero hn), pow_succ', bot_mul]
+ rw [← Nat.sub_one_add_one hn, pow_succ', bot_mul]
@[to_additive]
theorem mul_top_of_one_le (hf : 1 ≤ f) : f * ⊤ = ⊤ := by
@@ -610,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
@@ -713,7 +715,7 @@ theorem isUnit_pure (a : α) : IsUnit (pure a : Filter α) :=
@[simp]
theorem isUnit_iff_singleton : IsUnit f ↔ ∃ a, f = pure a := by
- simp only [isUnit_iff, Group.isUnit, and_true_iff]
+ simp only [isUnit_iff, Group.isUnit, and_true]
@[to_additive]
theorem map_inv' : f⁻¹.map m = (f.map m)⁻¹ :=
@@ -1041,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 523512374f4c3..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,14 +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_mem_prod (hs : s ∈ f) (ht : t ∈ g) : s ×ˢ t ∈ f ×ˢ g :=
inter_mem_inf (preimage_mem_comap hs) (preimage_mem_comap ht)
@@ -66,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 =>
@@ -99,6 +95,10 @@ theorem comap_prod (f : α → β × γ) (b : Filter β) (c : Filter γ) :
comap f (b ×ˢ c) = comap (Prod.fst ∘ f) b ⊓ comap (Prod.snd ∘ f) c := by
erw [comap_inf, Filter.comap_comap, Filter.comap_comap]
+theorem comap_prodMap_prod (f : α → β) (g : γ → δ) (lb : Filter β) (ld : Filter δ) :
+ comap (Prod.map f g) (lb ×ˢ ld) = comap f lb ×ˢ comap g ld := by
+ simp [prod_eq_inf, comap_comap, Function.comp_def]
+
theorem prod_top : f ×ˢ (⊤ : Filter β) = f.comap Prod.fst := by
dsimp only [SProd.sprod]
rw [Filter.prod, comap_top, inf_top_eq]
@@ -409,7 +409,7 @@ theorem frequently_prod_and {p : α → Prop} {q : β → Prop} :
theorem tendsto_prod_iff {f : α × β → γ} {x : Filter α} {y : Filter β} {z : Filter γ} :
Tendsto f (x ×ˢ y) z ↔ ∀ W ∈ z, ∃ U ∈ x, ∃ V ∈ y, ∀ x y, x ∈ U → y ∈ V → f (x, y) ∈ W := by
- simp only [tendsto_def, mem_prod_iff, prod_sub_preimage_iff, exists_prop, iff_self_iff]
+ simp only [tendsto_def, mem_prod_iff, prod_sub_preimage_iff, exists_prop]
theorem tendsto_prod_iff' {g' : Filter γ} {s : α → β × γ} :
Tendsto s f (g ×ˢ g') ↔ Tendsto (fun n => (s n).1) f g ∧ Tendsto (fun n => (s n).2) f g' := by
@@ -429,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 3d1ae9a87f5fc..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
@@ -465,4 +465,8 @@ theorem ofComapInfPrincipal_eq_of_map (h : m '' s ∈ g) : (ofComapInfPrincipal
_ ≤ ↑g ⊓ (𝓟 <| m '' s) := inf_le_inf_right _ map_comap_le
_ = ↑g := inf_of_le_left (le_principal_iff.mpr h)
+theorem eq_of_le_pure {X : Type _} {α : Filter X} (hα : α.NeBot) {x y : X}
+ (hx : α ≤ pure x) (hy : α ≤ pure y) : x = y :=
+ Filter.pure_injective (hα.le_pure_iff.mp hx ▸ hα.le_pure_iff.mp hy)
+
end Ultrafilter
diff --git a/Mathlib/Order/Fin/Basic.lean b/Mathlib/Order/Fin/Basic.lean
index 5fac9d7e3e64c..10983f1527c03 100644
--- a/Mathlib/Order/Fin/Basic.lean
+++ b/Mathlib/Order/Fin/Basic.lean
@@ -122,6 +122,7 @@ end FromFin
/-! #### Monotonicity -/
lemma val_strictMono : StrictMono (val : Fin n → ℕ) := fun _ _ ↦ id
+lemma cast_strictMono {k l : ℕ} (h : k = l) : StrictMono (cast h) := fun {_ _} h ↦ h
lemma strictMono_succ : StrictMono (succ : Fin n → Fin (n + 1)) := fun _ _ ↦ succ_lt_succ
lemma strictMono_castLE (h : n ≤ m) : StrictMono (castLE h : Fin n → Fin m) := fun _ _ ↦ id
@@ -278,25 +279,16 @@ map. In this lemma we state that for each `i : Fin n` we have `(e i : ℕ) = (i
simpa using h _ this (e.symm _).is_lt
· rwa [← h j hj (hj.trans hi), ← lt_iff_val_lt_val, e.lt_iff_lt]
-instance orderIso_subsingleton : Subsingleton (Fin n ≃o α) :=
- ⟨fun e e' => by
- ext i
- rw [← e.symm.apply_eq_iff_eq, e.symm_apply_apply, ← e'.trans_apply, Fin.ext_iff,
- coe_orderIso_apply]⟩
-
-instance orderIso_subsingleton' : Subsingleton (α ≃o Fin n) := OrderIso.symm_injective.subsingleton
-
-instance orderIsoUnique : Unique (Fin n ≃o Fin n) := Unique.mk' _
-
/-- Two strictly monotone functions from `Fin n` are equal provided that their ranges
are equal. -/
+@[deprecated StrictMono.range_inj (since := "2024-09-17")]
lemma strictMono_unique {f g : Fin n → α} (hf : StrictMono f) (hg : StrictMono g)
(h : range f = range g) : f = g :=
- have : (hf.orderIso f).trans (OrderIso.setCongr _ _ h) = hg.orderIso g := Subsingleton.elim _ _
- congr_arg (Function.comp (Subtype.val : range g → α)) (funext <| RelIso.ext_iff.1 this)
+ (hf.range_inj hg).1 h
/-- Two order embeddings of `Fin n` are equal provided that their ranges are equal. -/
+@[deprecated OrderEmbedding.range_inj (since := "2024-09-17")]
lemma orderEmbedding_eq {f g : Fin n ↪o α} (h : range f = range g) : f = g :=
- RelEmbedding.ext <| funext_iff.1 <| strictMono_unique f.strictMono g.strictMono h
+ OrderEmbedding.range_inj.1 h
end Fin
diff --git a/Mathlib/Order/Fin/Tuple.lean b/Mathlib/Order/Fin/Tuple.lean
index 428d79cc5cd09..1f92421e88291 100644
--- a/Mathlib/Order/Fin/Tuple.lean
+++ b/Mathlib/Order/Fin/Tuple.lean
@@ -39,12 +39,12 @@ lemma insertNth_mem_Icc {i : Fin (n + 1)} {x : α i} {p : ∀ j, α (i.succAbove
lemma preimage_insertNth_Icc_of_mem {i : Fin (n + 1)} {x : α i} {q₁ q₂ : ∀ j, α j}
(hx : x ∈ Icc (q₁ i) (q₂ i)) :
i.insertNth x ⁻¹' Icc q₁ q₂ = Icc (fun j ↦ q₁ (i.succAbove j)) fun j ↦ q₂ (i.succAbove j) :=
- Set.ext fun p ↦ by simp only [mem_preimage, insertNth_mem_Icc, hx, true_and_iff]
+ Set.ext fun p ↦ by simp only [mem_preimage, insertNth_mem_Icc, hx, true_and]
lemma preimage_insertNth_Icc_of_not_mem {i : Fin (n + 1)} {x : α i} {q₁ q₂ : ∀ j, α j}
(hx : x ∉ Icc (q₁ i) (q₂ i)) : i.insertNth x ⁻¹' Icc q₁ q₂ = ∅ :=
Set.ext fun p ↦ by
- simp only [mem_preimage, insertNth_mem_Icc, hx, false_and_iff, mem_empty_iff_false]
+ simp only [mem_preimage, insertNth_mem_Icc, hx, false_and, mem_empty_iff_false]
end Fin
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/Height.lean b/Mathlib/Order/Height.lean
index 531157c49d046..22b9697c5dd05 100644
--- a/Mathlib/Order/Height.lean
+++ b/Mathlib/Order/Height.lean
@@ -100,9 +100,9 @@ theorem exists_chain_of_le_chainHeight {n : ℕ} (hn : ↑n ≤ s.chainHeight) :
theorem le_chainHeight_TFAE (n : ℕ) :
TFAE [↑n ≤ s.chainHeight, ∃ l ∈ s.subchain, length l = n, ∃ l ∈ s.subchain, n ≤ length l] := by
- tfae_have 1 → 2; · exact s.exists_chain_of_le_chainHeight
- tfae_have 2 → 3; · rintro ⟨l, hls, he⟩; exact ⟨l, hls, he.ge⟩
- tfae_have 3 → 1; · rintro ⟨l, hs, hn⟩; exact le_iSup₂_of_le l hs (WithTop.coe_le_coe.2 hn)
+ tfae_have 1 → 2 := s.exists_chain_of_le_chainHeight
+ tfae_have 2 → 3 := fun ⟨l, hls, he⟩ ↦ ⟨l, hls, he.ge⟩
+ tfae_have 3 → 1 := fun ⟨l, hs, hn⟩ ↦ le_iSup₂_of_le l hs (WithTop.coe_le_coe.2 hn)
tfae_finish
variable {s t}
@@ -169,10 +169,10 @@ theorem chainHeight_add_le_chainHeight_add (s : Set α) (t : Set β) (n m : ℕ)
theorem chainHeight_le_chainHeight_TFAE (s : Set α) (t : Set β) :
TFAE [s.chainHeight ≤ t.chainHeight, ∀ l ∈ s.subchain, ∃ l' ∈ t.subchain, length l = length l',
∀ l ∈ s.subchain, ∃ l' ∈ t.subchain, length l ≤ length l'] := by
- tfae_have 1 ↔ 3
- · convert ← chainHeight_add_le_chainHeight_add s t 0 0 <;> apply add_zero
- tfae_have 2 ↔ 3
- · refine forall₂_congr fun l hl ↦ ?_
+ tfae_have 1 ↔ 3 := by
+ convert ← chainHeight_add_le_chainHeight_add s t 0 0 <;> apply add_zero
+ tfae_have 2 ↔ 3 := by
+ refine forall₂_congr fun l _ ↦ ?_
simp_rw [← (le_chainHeight_TFAE t l.length).out 1 2, eq_comm]
tfae_finish
diff --git a/Mathlib/Order/Heyting/Basic.lean b/Mathlib/Order/Heyting/Basic.lean
index 671d477c88c61..392c6569e8911 100644
--- a/Mathlib/Order/Heyting/Basic.lean
+++ b/Mathlib/Order/Heyting/Basic.lean
@@ -124,36 +124,36 @@ theorem hnot_apply [∀ i, HNot (π i)] (a : ∀ i, π i) (i : ι) : (¬a) i =
end Pi
/-- A generalized Heyting algebra is a lattice with an additional binary operation `⇨` called
-Heyting implication such that `a ⇨` is right adjoint to `a ⊓`.
+Heyting implication such that `(a ⇨ ·)` is right adjoint to `(a ⊓ ·)`.
This generalizes `HeytingAlgebra` by not requiring a bottom element. -/
class GeneralizedHeytingAlgebra (α : Type*) extends Lattice α, OrderTop α, HImp α where
- /-- `a ⇨` is right adjoint to `a ⊓` -/
+ /-- `(a ⇨ ·)` is right adjoint to `(a ⊓ ·)` -/
le_himp_iff (a b c : α) : a ≤ b ⇨ c ↔ a ⊓ b ≤ c
/-- A generalized co-Heyting algebra is a lattice with an additional binary
-difference operation `\` such that `\ a` is right adjoint to `⊔ a`.
+difference operation `\` such that `(· \ a)` is right adjoint to `(· ⊔ a)`.
This generalizes `CoheytingAlgebra` by not requiring a top element. -/
class GeneralizedCoheytingAlgebra (α : Type*) extends Lattice α, OrderBot α, SDiff α where
- /-- `\ a` is right adjoint to `⊔ a` -/
+ /-- `(· \ a)` is right adjoint to `(· ⊔ a)` -/
sdiff_le_iff (a b c : α) : a \ b ≤ c ↔ a ≤ b ⊔ c
/-- A Heyting algebra is a bounded lattice with an additional binary operation `⇨` called Heyting
-implication such that `a ⇨` is right adjoint to `a ⊓`. -/
+implication such that `(a ⇨ ·)` is right adjoint to `(a ⊓ ·)`. -/
class HeytingAlgebra (α : Type*) extends GeneralizedHeytingAlgebra α, OrderBot α, HasCompl α where
- /-- `a ⇨` is right adjoint to `a ⊓` -/
+ /-- `aᶜ` is defined as `a ⇨ ⊥` -/
himp_bot (a : α) : a ⇨ ⊥ = aᶜ
/-- A co-Heyting algebra is a bounded lattice with an additional binary difference operation `\`
-such that `\ a` is right adjoint to `⊔ a`. -/
+such that `(· \ a)` is right adjoint to `(· ⊔ a)`. -/
class CoheytingAlgebra (α : Type*) extends GeneralizedCoheytingAlgebra α, OrderTop α, HNot α where
/-- `⊤ \ a` is `¬a` -/
top_sdiff (a : α) : ⊤ \ a = ¬a
/-- A bi-Heyting algebra is a Heyting algebra that is also a co-Heyting algebra. -/
class BiheytingAlgebra (α : Type*) extends HeytingAlgebra α, SDiff α, HNot α where
- /-- `\ a` is right adjoint to `⊔ a` -/
+ /-- `(· \ a)` is right adjoint to `(· ⊔ a)` -/
sdiff_le_iff (a b c : α) : a \ b ≤ c ↔ a ≤ b ⊔ c
/-- `⊤ \ a` is `¬a` -/
top_sdiff (a : α) : ⊤ \ a = ¬a
@@ -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 358a7b6215806..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 α β :=
@@ -190,7 +190,6 @@ theorem map_compl (a : α) : f aᶜ = (f a)ᶜ := by rw [← himp_bot, ← himp_
@[simp]
theorem map_bihimp (a b : α) : f (a ⇔ b) = f a ⇔ f b := by simp_rw [bihimp, map_inf, map_himp]
--- TODO: `map_bihimp`
end HeytingAlgebra
section CoheytingAlgebra
@@ -247,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 5f4bd78be7ae1..038a9e1b51ebd 100644
--- a/Mathlib/Order/Hom/Basic.lean
+++ b/Mathlib/Order/Hom/Basic.lean
@@ -111,7 +111,8 @@ abbrev OrderHomClass (F : Type*) (α β : outParam Type*) [LE α] [LE β] [FunLi
/-- `OrderIsoClass F α β` states that `F` is a type of order isomorphisms.
You should extend this class when you extend `OrderIso`. -/
-class OrderIsoClass (F α β : Type*) [LE α] [LE β] [EquivLike F α β] : Prop where
+class OrderIsoClass (F : Type*) (α β : outParam Type*) [LE α] [LE β] [EquivLike F α β] :
+ Prop where
/-- An order isomorphism respects `≤`. -/
map_le_map_iff (f : F) {a b : α} : f a ≤ f b ↔ a ≤ b
@@ -147,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]
@@ -751,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
@@ -914,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
@@ -928,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
@@ -940,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⟩
@@ -1052,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)]
@@ -1171,6 +1176,13 @@ theorem coe_toDualTopEquiv_eq [LE α] :
(WithBot.toDualTopEquiv : WithBot αᵒᵈ → (WithTop α)ᵒᵈ) = toDual ∘ WithBot.ofDual :=
funext fun _ => rfl
+/-- The coercion `α → WithBot α` bundled as monotone map. -/
+@[simps]
+def coeOrderHom {α : Type*} [Preorder α] : α ↪o WithBot α where
+ toFun := (↑)
+ inj' := WithBot.coe_injective
+ map_rel_iff' := WithBot.coe_le_coe
+
end WithBot
namespace WithTop
@@ -1202,6 +1214,13 @@ theorem coe_toDualBotEquiv [LE α] :
(WithTop.toDualBotEquiv : WithTop αᵒᵈ → (WithBot α)ᵒᵈ) = toDual ∘ WithTop.ofDual :=
funext fun _ => rfl
+/-- The coercion `α → WithTop α` bundled as monotone map. -/
+@[simps]
+def coeOrderHom {α : Type*} [Preorder α] : α ↪o WithTop α where
+ toFun := (↑)
+ inj' := WithTop.coe_injective
+ map_rel_iff' := WithTop.coe_le_coe
+
end WithTop
namespace OrderIso
diff --git a/Mathlib/Order/Hom/Bounded.lean b/Mathlib/Order/Hom/Bounded.lean
index 971df11a1b4ff..92fa0698730b3 100644
--- a/Mathlib/Order/Hom/Bounded.lean
+++ b/Mathlib/Order/Hom/Bounded.lean
@@ -59,14 +59,16 @@ section
/-- `TopHomClass F α β` states that `F` is a type of `⊤`-preserving morphisms.
You should extend this class when you extend `TopHom`. -/
-class TopHomClass (F α β : Type*) [Top α] [Top β] [FunLike F α β] : Prop where
+class TopHomClass (F : Type*) (α β : outParam Type*) [Top α] [Top β] [FunLike F α β] :
+ Prop where
/-- A `TopHomClass` morphism preserves the top element. -/
map_top (f : F) : f ⊤ = ⊤
/-- `BotHomClass F α β` states that `F` is a type of `⊥`-preserving morphisms.
You should extend this class when you extend `BotHom`. -/
-class BotHomClass (F α β : Type*) [Bot α] [Bot β] [FunLike F α β] : Prop where
+class BotHomClass (F : Type*) (α β : outParam Type*) [Bot α] [Bot β] [FunLike F α β] :
+ Prop where
/-- A `BotHomClass` morphism preserves the bottom element. -/
map_bot (f : F) : f ⊥ = ⊥
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 6838a14b4bba9..df6730da16330 100644
--- a/Mathlib/Order/Hom/Set.lean
+++ b/Mathlib/Order/Hom/Set.lean
@@ -5,22 +5,25 @@ Authors: Johan Commelin
-/
import Mathlib.Order.Hom.Basic
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 {F α β γ δ : Type*}
+variable {α β : Type*}
namespace OrderIso
section LE
-variable [LE α] [LE β] [LE γ]
+variable [LE α] [LE β]
theorem range_eq (e : α ≃o β) : Set.range e = Set.univ :=
e.surjective.range_eq
@@ -56,7 +59,7 @@ end LE
open Set
-variable [Preorder α] [Preorder β] [Preorder γ]
+variable [Preorder α]
/-- Order isomorphism between two equal sets. -/
def setCongr (s t : Set α) (h : s = t) :
@@ -119,6 +122,76 @@ theorem orderIsoOfSurjective_self_symm_apply (b : β) :
end StrictMono
+/-- Two order embeddings on a well-order are equal provided that their ranges are equal. -/
+lemma OrderEmbedding.range_inj [LinearOrder α] [WellFoundedLT α] [Preorder β] {f g : α ↪o β} :
+ Set.range f = Set.range g ↔ f = g := by
+ rw [f.strictMono.range_inj g.strictMono, DFunLike.coe_fn_eq]
+
+namespace OrderIso
+
+-- These results are also true whenever β is well-founded instead of α.
+-- You can use `RelEmbedding.isWellFounded` to transfer the instance over.
+
+instance subsingleton_of_wellFoundedLT [LinearOrder α] [WellFoundedLT α] [Preorder β] :
+ Subsingleton (α ≃o β) := by
+ refine ⟨fun f g ↦ ?_⟩
+ rw [OrderIso.ext_iff, ← coe_toOrderEmbedding, ← coe_toOrderEmbedding, DFunLike.coe_fn_eq,
+ ← OrderEmbedding.range_inj, coe_toOrderEmbedding, coe_toOrderEmbedding, range_eq, range_eq]
+
+instance subsingleton_of_wellFoundedLT' [LinearOrder β] [WellFoundedLT β] [Preorder α] :
+ Subsingleton (α ≃o β) := by
+ refine ⟨fun f g ↦ ?_⟩
+ change f.symm.symm = g.symm.symm
+ rw [Subsingleton.elim f.symm]
+
+instance unique_of_wellFoundedLT [LinearOrder α] [WellFoundedLT α] : Unique (α ≃o α) := Unique.mk' _
+
+instance subsingleton_of_wellFoundedGT [LinearOrder α] [WellFoundedGT α] [Preorder β] :
+ Subsingleton (α ≃o β) := by
+ refine ⟨fun f g ↦ ?_⟩
+ change f.dual.dual = g.dual.dual
+ rw [Subsingleton.elim f.dual]
+
+instance subsingleton_of_wellFoundedGT' [LinearOrder β] [WellFoundedGT β] [Preorder α] :
+ Subsingleton (α ≃o β) := by
+ refine ⟨fun f g ↦ ?_⟩
+ change f.dual.dual = g.dual.dual
+ rw [Subsingleton.elim f.dual]
+
+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
variable (α) [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 e8a30b426e0b2..0a1582e51640c 100644
--- a/Mathlib/Order/InitialSeg.lean
+++ b/Mathlib/Order/InitialSeg.lean
@@ -1,8 +1,9 @@
/-
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
@@ -20,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) :=
@@ -70,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
@@ -77,17 +103,26 @@ instance : EmbeddingLike (r ≼i s) α β where
theorem coe_coe_fn (f : r ≼i s) : ((f : r ↪r s) : α → β) = f :=
rfl
-theorem init (f : r ≼i s) {a : α} {b : β} : s b (f a) → ∃ a', f a' = b :=
- f.init' _ _
+theorem mem_range_of_rel (f : r ≼i s) {a : α} {b : β} : s b (f a) → b ∈ Set.range f :=
+ f.mem_range_of_rel' _ _
+
+@[deprecated mem_range_of_rel (since := "2024-09-21")]
+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 init_iff (f : r ≼i s) {a : α} {b : β} : s b (f a) ↔ ∃ a', f a' = b ∧ r a' a :=
+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.init h with ⟨a', rfl⟩
+ 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
/-- An order isomorphism is an initial segment -/
def ofIso (f : r ≃r s) : r ≼i s :=
@@ -123,7 +158,7 @@ instance subsingleton_of_trichotomous_of_irrefl [IsTrichotomous β s] [IsIrrefl
ext a
refine IsWellFounded.induction r a fun b IH =>
extensional_of_trichotomous_of_irrefl s fun x => ?_
- rw [f.init_iff, g.init_iff]
+ rw [f.exists_eq_iff_rel, g.exists_eq_iff_rel]
exact exists_congr fun x => and_congr_left fun hx => IH _ hx ▸ Iff.rfl⟩
instance [IsWellOrder β s] : Subsingleton (r ≼i s) :=
@@ -132,14 +167,14 @@ instance [IsWellOrder β s] : Subsingleton (r ≼i s) :=
protected theorem eq [IsWellOrder β s] (f g : r ≼i s) (a) : f a = g a := by
rw [Subsingleton.elim f g]
-theorem Antisymm.aux [IsWellOrder α r] (f : r ≼i s) (g : s ≼i r) : LeftInverse g f :=
- InitialSeg.eq (f.trans g) (InitialSeg.refl _)
+private theorem antisymm_aux [IsWellOrder α r] (f : r ≼i s) (g : s ≼i r) : LeftInverse g f :=
+ (f.trans g).eq (InitialSeg.refl _)
/-- If we have order embeddings between `α` and `β` whose images are initial segments, and `β`
is a well-order then `α` and `β` are order-isomorphic. -/
def antisymm [IsWellOrder β s] (f : r ≼i s) (g : s ≼i r) : r ≃r s :=
- haveI := f.toRelEmbedding.isWellOrder
- ⟨⟨f, g, Antisymm.aux f g, Antisymm.aux g f⟩, f.map_rel_iff'⟩
+ have := f.toRelEmbedding.isWellOrder
+ ⟨⟨f, g, antisymm_aux f g, antisymm_aux g f⟩, f.map_rel_iff'⟩
@[simp]
theorem antisymm_toFun [IsWellOrder β s] (f : r ≼i s) (g : s ≼i r) : (antisymm f g : α → β) = f :=
@@ -151,21 +186,24 @@ 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_of_not (hn a) fun hl => not_exists.2 hn (f.init 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 :=
⟨RelEmbedding.codRestrict p f H, fun a ⟨b, m⟩ h =>
- let ⟨a', e⟩ := f.init h
+ let ⟨a', e⟩ := f.mem_range_of_rel h
⟨a', by subst e; rfl⟩⟩
@[simp]
@@ -188,7 +226,7 @@ theorem leAdd_apply (r : α → α → Prop) (s : β → β → Prop) (a) : leAd
protected theorem acc (f : r ≼i s) (a : α) : Acc r a ↔ Acc s (f a) :=
⟨by
refine fun h => Acc.recOn h fun a _ ha => Acc.intro _ fun b hb => ?_
- obtain ⟨a', rfl⟩ := f.init hb
+ obtain ⟨a', rfl⟩ := f.mem_range_of_rel hb
exact ha _ (f.map_rel_iff.mp hb), f.toRelEmbedding.acc a⟩
end InitialSeg
@@ -209,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) :=
@@ -230,30 +269,48 @@ 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.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 init [IsTrans β s] (f : r ≺i s) {a : α} {b : β} (h : s b (f a)) : ∃ a', f a' = b :=
- f.down.1 <| _root_.trans h <| f.lt_top _
+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.init⟩⟩
+ ⟨fun f => ⟨f.toRelEmbedding, fun _ _ => f.mem_range_of_rel⟩⟩
theorem coe_coe_fn' [IsTrans β s] (f : r ≺i s) : ((f : r ≼i s) : α → β) = f :=
rfl
-theorem init_iff [IsTrans β s] (f : r ≺i s) {a : α} {b : β} : s b (f a) ↔ ∃ a', f a' = b ∧ r a' a :=
- @InitialSeg.init_iff α β r s f a b
+theorem exists_eq_iff_rel [IsTrans β s] (f : r ≺i s) {a : α} {b : β} :
+ s b (f a) ↔ ∃ a', f a' = b ∧ r a' a :=
+ @InitialSeg.exists_eq_iff_rel α β r s f a b
+
+@[deprecated exists_eq_iff_rel (since := "2024-09-21")]
+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)
@@ -271,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.init_iff, 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) :=
@@ -298,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) :=
@@ -326,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]
@@ -357,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
@@ -371,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⟩ :=
@@ -393,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) :
@@ -409,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 =>
@@ -431,82 +476,167 @@ theorem wellFounded_iff_principalSeg.{u} {β : Type u} {s : β → β → Prop}
/-! ### Properties of initial and principal segments -/
+namespace InitialSeg
+
/-- To an initial segment taking values in a well order, one can associate either a principal
segment (if the range is not everything, hence one can take as top the minimum of the complement
of the range) or an order isomorphism (if the range is everything). -/
-noncomputable def InitialSeg.ltOrEq [IsWellOrder β s] (f : r ≼i s) : (r ≺i s) ⊕ (r ≃r s) := by
+noncomputable def ltOrEq [IsWellOrder β s] (f : r ≼i s) : (r ≺i s) ⊕ (r ≃r s) := by
by_cases h : Surjective f
· exact Sum.inr (RelIso.ofSurjective f h)
· exact Sum.inl (f.toPrincipalSeg h)
-theorem InitialSeg.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 InitialSeg.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 InitialSeg.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
@[simp]
-theorem InitialSeg.leLT_apply [IsWellOrder β s] [IsTrans γ t] (f : r ≼i s) (g : s ≺i t) (a : α) :
+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]
-
-namespace RelEmbedding
-
-/-- Given an order embedding into a well order, collapse the order embedding by filling the
-gaps, to obtain an initial segment. Here, we construct the collapsed order embedding pointwise,
-but the proof of the fact that it is an initial segment will be given in `collapse`. -/
-noncomputable def collapseF [IsWellOrder β s] (f : r ↪r s) : ∀ a, { b // ¬s (f a) b } :=
- (RelEmbedding.wellFounded f <| IsWellFounded.wf).fix fun a IH => by
- let S := { b | ∀ a h, s (IH a h).1 b }
- have : f a ∈ S := fun a' h =>
- ((trichotomous _ _).resolve_left fun h' =>
- (IH a' h).2 <| _root_.trans (f.map_rel_iff.2 h) h').resolve_left
- fun h' => (IH a' h).2 <| h' ▸ f.map_rel_iff.2 h
- exact ⟨_, IsWellFounded.wf.not_lt_min _ ⟨_, this⟩ this⟩
-
-theorem collapseF.lt [IsWellOrder β s] (f : r ↪r s) {a : α} :
- ∀ {a'}, r a' a → s (collapseF f a').1 (collapseF f a).1 := @fun a => by
- revert a
- show (collapseF f a).1 ∈ { b | ∀ (a') (_ : r a' a), s (collapseF f a').1 b }
- unfold collapseF; rw [WellFounded.fix_eq]
+ 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
+
+/-- The function in `collapse`. -/
+private noncomputable def collapseF [IsWellOrder β s] (f : r ↪r s) : Π a, { b // ¬s (f a) b } :=
+ (RelEmbedding.isWellFounded f).fix _ fun a IH =>
+ have H : f a ∈ { b | ∀ a h, s (IH a h).1 b } :=
+ fun b h => trans_trichotomous_left (IH b h).2 (f.map_rel_iff.2 h)
+ ⟨_, IsWellFounded.wf.not_lt_min _ ⟨_, H⟩ H⟩
+
+private theorem collapseF_lt [IsWellOrder β s] (f : r ↪r s) {a : α} :
+ ∀ {a'}, r a' a → s (collapseF f a') (collapseF f a) := by
+ show _ ∈ { b | ∀ a', r a' a → s (collapseF f a') b }
+ rw [collapseF, IsWellFounded.fix_eq]
dsimp only
- apply WellFounded.min_mem _ _
+ exact WellFounded.min_mem _ _ _
-theorem collapseF.not_lt [IsWellOrder β s] (f : r ↪r s) (a : α) {b}
- (h : ∀ a' (_ : r a' a), s (collapseF f a').1 b) : ¬s b (collapseF f a).1 := by
- unfold collapseF; rw [WellFounded.fix_eq]
+private theorem collapseF_not_lt [IsWellOrder β s] (f : r ↪r s) (a : α) {b}
+ (h : ∀ a', r a' a → s (collapseF f a') b) : ¬s b (collapseF f a) := by
+ rw [collapseF, IsWellFounded.fix_eq]
dsimp only
exact WellFounded.not_lt_min _ _ _ h
-/-- Construct an initial segment from an order embedding into a well order, by collapsing it
-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 =>
- 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 }
- ⟨_, asymm h⟩ with ⟨m, hm, hm'⟩
- refine ⟨m, ((@trichotomous _ s _ _ _).resolve_left hm).resolve_right
- (collapseF.not_lt f _ fun a' h' => ?_)⟩
- by_contra hn
- exact hm' _ hn h')
- a⟩
-
-theorem collapse_apply [IsWellOrder β s] (f : r ↪r s) (a) : collapse f a = (collapseF f a).1 :=
- rfl
+/-- Construct an initial segment embedding `r ≼i s` by "filling in the gaps". That is, each
+subsequent element in `α` is mapped to the least element in `β` that hasn't been used yet.
+
+This construction is guaranteed to work as long as there exists some relation embedding `r ↪r s`. -/
+noncomputable def RelEmbedding.collapse [IsWellOrder β s] (f : r ↪r s) : r ≼i s :=
+ have H := RelEmbedding.isWellOrder f
+ ⟨RelEmbedding.ofMonotone _ fun a b => collapseF_lt f, fun a b h ↦ by
+ obtain ⟨m, hm, hm'⟩ := H.wf.has_min { a | ¬s _ b } ⟨_, asymm h⟩
+ use m
+ obtain lt | rfl | gt := trichotomous_of s b (collapseF f m)
+ · refine (collapseF_not_lt f m (fun c h ↦ ?_) lt).elim
+ by_contra hn
+ exact hm' _ hn h
+ · rfl
+ · exact (hm gt).elim⟩
+
+/-- For any two well orders, one is an initial segment of the other. -/
+noncomputable def InitialSeg.total (r s) [IsWellOrder α r] [IsWellOrder β s] :
+ (r ≼i s) ⊕ (s ≼i r) :=
+ match (leAdd r s).ltOrEq, (RelEmbedding.sumLexInr r s).collapse.ltOrEq with
+ | Sum.inl f, Sum.inr g => Sum.inl <| f.ltEquiv g.symm
+ | Sum.inr f, Sum.inl g => Sum.inr <| g.ltEquiv f.symm
+ | Sum.inr f, Sum.inr g => Sum.inl <| InitialSeg.ofIso (f.trans g.symm)
+ | Sum.inl f, Sum.inl g => Classical.choice <| by
+ obtain h | h | h := trichotomous_of (Sum.Lex r s) f.top g.top
+ · exact ⟨Sum.inl <| (f.codRestrict {x | Sum.Lex r s x g.top}
+ (fun a => _root_.trans (f.lt_top a) h) h).ltEquiv g.subrelIso⟩
+ · let f := f.subrelIso
+ rw [h] at f
+ exact ⟨Sum.inl <| InitialSeg.ofIso (f.symm.trans g.subrelIso)⟩
+ · exact ⟨Sum.inr <| (g.codRestrict {x | Sum.Lex r s x f.top}
+ (fun a => _root_.trans (g.lt_top a) h) h).ltEquiv f.subrelIso⟩
-end RelEmbedding
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 e0b90ecd39119..e8a5116a9e300 100644
--- a/Mathlib/Order/Interval/Finset/Basic.lean
+++ b/Mathlib/Order/Interval/Finset/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Yaël Dillies
+Authors: Kim Morrison, Yaël Dillies
-/
import Mathlib.Order.Cover
import Mathlib.Order.Interval.Finset.Defs
@@ -17,7 +17,7 @@ respectively, `⩿` and `⋖`, which then leads to a characterization of monoton
functions whose domain is a locally finite order. In particular, this file proves:
* `le_iff_transGen_wcovBy`: `≤` is the transitive closure of `⩿`
-* `lt_iff_transGen_covBy`: `≤` is the transitive closure of `⩿`
+* `lt_iff_transGen_covBy`: `<` is the transitive closure of `⋖`
* `monotone_iff_forall_wcovBy`: Characterization of monotone functions
* `strictMono_iff_forall_covBy`: Characterization of strictly monotone functions
@@ -51,18 +51,27 @@ section LocallyFiniteOrder
variable [LocallyFiniteOrder α]
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
theorem nonempty_Icc : (Icc a b).Nonempty ↔ a ≤ b := by
rw [← coe_nonempty, coe_Icc, Set.nonempty_Icc]
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, Aesop.nonempty_Icc_of_le⟩ := nonempty_Icc
+
+@[simp]
theorem nonempty_Ico : (Ico a b).Nonempty ↔ a < b := by
rw [← coe_nonempty, coe_Ico, Set.nonempty_Ico]
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, Aesop.nonempty_Ico_of_lt⟩ := nonempty_Ico
+
+@[simp]
theorem nonempty_Ioc : (Ioc a b).Nonempty ↔ a < b := by
rw [← coe_nonempty, coe_Ioc, Set.nonempty_Ioc]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, Aesop.nonempty_Ioc_of_lt⟩ := nonempty_Ioc
+
-- TODO: This is nonsense. A locally finite order is never densely ordered
@[simp]
theorem nonempty_Ioo [DenselyOrdered α] : (Ioo a b).Nonempty ↔ a < b := by
@@ -111,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_iff, le_rfl]
+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_iff, le_refl]
+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_iff, le_rfl]
+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_iff, le_rfl]
+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
@@ -235,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 _
@@ -260,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
@@ -331,9 +310,12 @@ variable [LocallyFiniteOrderTop α]
@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
lemma nonempty_Ici : (Ici a).Nonempty := ⟨a, mem_Ici.2 le_rfl⟩
-@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+@[simp]
lemma nonempty_Ioi : (Ioi a).Nonempty ↔ ¬ IsMax a := by simp [Finset.Nonempty]
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, Aesop.nonempty_Ioi_of_not_isMax⟩ := nonempty_Ioi
+
theorem Ici_subset_Ici : Ici a ⊆ Ici b ↔ b ≤ a := by
simpa [← coe_subset] using Set.Ici_subset_Ici
@@ -366,8 +348,13 @@ section LocallyFiniteOrderBot
variable [LocallyFiniteOrderBot α]
-@[simp] lemma nonempty_Iic : (Iic a).Nonempty := ⟨a, mem_Iic.2 le_rfl⟩
-@[simp] lemma nonempty_Iio : (Iio a).Nonempty ↔ ¬ IsMin a := by simp [Finset.Nonempty]
+@[simp, aesop safe apply (rule_sets := [finsetNonempty])]
+lemma nonempty_Iic : (Iic a).Nonempty := ⟨a, mem_Iic.2 le_rfl⟩
+@[simp]
+lemma nonempty_Iio : (Iio a).Nonempty ↔ ¬ IsMin a := by simp [Finset.Nonempty]
+
+@[aesop safe apply (rule_sets := [finsetNonempty])]
+alias ⟨_, Aesop.nonempty_Iio_of_not_isMin⟩ := nonempty_Iio
theorem Iic_subset_Iic : Iic a ⊆ Iic b ↔ a ≤ b := by
simpa [← coe_subset] using Set.Iic_subset_Iic
@@ -413,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
@@ -438,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
@@ -544,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
@@ -593,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
@@ -602,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
@@ -621,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
@@ -630,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
@@ -666,7 +639,7 @@ variable [LinearOrder α]
section LocallyFiniteOrder
-variable [LocallyFiniteOrder α] {a b : α}
+variable [LocallyFiniteOrder α]
theorem Ico_subset_Ico_iff {a₁ b₁ a₂ b₂ : α} (h : a₁ < b₁) :
Ico a₁ b₁ ⊆ Ico a₂ b₂ ↔ a₂ ≤ a₁ ∧ b₁ ≤ b₂ := by
@@ -698,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]
@@ -773,7 +746,7 @@ end LinearOrder
section Lattice
-variable [Lattice α] [LocallyFiniteOrder α] {a a₁ a₂ b b₁ b₂ c x : α}
+variable [Lattice α] [LocallyFiniteOrder α] {a a₁ a₂ b b₁ b₂ x : α}
theorem uIcc_toDual (a b : α) : [[toDual a, toDual b]] = [[a, b]].map toDual.toEmbedding :=
Icc_toDual _ _
@@ -789,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]
@@ -803,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⟩
@@ -845,7 +812,7 @@ end Lattice
section DistribLattice
-variable [DistribLattice α] [LocallyFiniteOrder α] {a a₁ a₂ b b₁ b₂ c x : α}
+variable [DistribLattice α] [LocallyFiniteOrder α] {a b c : α}
theorem eq_of_mem_uIcc_of_mem_uIcc : a ∈ [[b, c]] → b ∈ [[a, c]] → a = b := by
simp_rw [mem_uIcc]
@@ -866,7 +833,7 @@ end DistribLattice
section LinearOrder
-variable [LinearOrder α] [LocallyFiniteOrder α] {a a₁ a₂ b b₁ b₂ c x : α}
+variable [LinearOrder α] [LocallyFiniteOrder α] {a a₁ a₂ b b₁ b₂ c : α}
theorem Icc_min_max : Icc (min a b) (max a b) = [[a, b]] :=
rfl
@@ -916,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`
@@ -926,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 : α} :
@@ -959,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
@@ -973,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 133d9233ac466..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`
@@ -187,8 +164,8 @@ theorem Ico_image_const_sub_eq_Ico (hac : a ≤ c) :
theorem Ico_succ_left_eq_erase_Ico : Ico a.succ b = erase (Ico a b) a := by
ext x
- rw [Ico_succ_left, mem_erase, mem_Ico, mem_Ioo, ← and_assoc, ne_comm, @and_comm (a ≠ x),
- lt_iff_le_and_ne]
+ rw [Ico_succ_left, mem_erase, mem_Ico, mem_Ioo, ← and_assoc, ne_comm,
+ and_comm (a := a ≠ x), lt_iff_le_and_ne]
theorem mod_injOn_Ico (n a : ℕ) : Set.InjOn (· % a) (Finset.Ico n (n + a)) := by
induction' n with n ih
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 1f7aa2076a01d..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) :=
@@ -1566,16 +1537,11 @@ theorem Ioc_union_Ioc_symm : Ioc a b ∪ Ioc b a = Ioc (min a b) (max a b) := by
@[simp]
theorem Ioc_union_Ioc_union_Ioc_cycle :
Ioc a b ∪ Ioc b c ∪ Ioc c a = Ioc (min a (min b c)) (max a (max b c)) := by
- rw [Ioc_union_Ioc, Ioc_union_Ioc] <;>
- -- Porting note: mathlib3 proof finished from here as follows:
- -- (It can probably be restored after https://github.com/leanprover-community/mathlib4/pull/856)
- -- ac_rfl
- -- all_goals
- -- solve_by_elim (config := { max_depth := 5 }) [min_le_of_left_le, min_le_of_right_le,
- -- le_max_of_le_left, le_max_of_le_right, le_refl]
- simp [min_le_of_left_le, min_le_of_right_le, le_max_of_le_left, le_max_of_le_right, le_refl,
- min_assoc, max_comm]
-
+ rw [Ioc_union_Ioc, Ioc_union_Ioc]
+ · ac_rfl
+ all_goals
+ solve_by_elim (config := { maxDepth := 5 }) [min_le_of_left_le, min_le_of_right_le,
+ le_max_of_le_left, le_max_of_le_right, le_refl]
end LinearOrder
/-!
@@ -1651,4 +1617,21 @@ instance : NoMaxOrder (Set.Iio x) :=
end Dense
+/-!
+### Intervals in `Prop`
+-/
+
+namespace Set
+
+@[simp] lemma Iic_False : Iic False = {False} := by aesop
+@[simp] lemma Iic_True : Iic True = univ := by aesop
+@[simp] lemma Ici_False : Ici False = univ := by aesop
+@[simp] lemma Ici_True : Ici True = {True} := by aesop
+@[simp] lemma Iio_False : Iio False = ∅ := by aesop
+@[simp] lemma Iio_True : Iio True = {False} := by aesop (add simp [Ioi, lt_iff_le_not_le])
+@[simp] lemma Ioi_False : Ioi False = {True} := by aesop (add simp [Ioi, lt_iff_le_not_le])
+@[simp] lemma Ioi_True : Ioi True = ∅ := by aesop
+
+end Set
+
set_option linter.style.longFile 1800
diff --git a/Mathlib/Order/Interval/Set/Image.lean b/Mathlib/Order/Interval/Set/Image.lean
index 0b194b81b848d..61ca9a56a17ad 100644
--- a/Mathlib/Order/Interval/Set/Image.lean
+++ b/Mathlib/Order/Interval/Set/Image.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Kim Liesinger. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kim Liesinger, Yaël Dillies
+Authors: Kim Morrison, Yaël Dillies
-/
import Mathlib.Order.Interval.Set.Basic
import Mathlib.Data.Set.Function
diff --git a/Mathlib/Order/Interval/Set/Monotone.lean b/Mathlib/Order/Interval/Set/Monotone.lean
index 6a9f2ab8f8da3..f2f3f914fb9c1 100644
--- a/Mathlib/Order/Interval/Set/Monotone.lean
+++ b/Mathlib/Order/Interval/Set/Monotone.lean
@@ -164,29 +164,9 @@ 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]
+ (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 =>
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/SurjOn.lean b/Mathlib/Order/Interval/Set/SurjOn.lean
index fd36a0e6fb432..8ebe61b8fbd13 100644
--- a/Mathlib/Order/Interval/Set/SurjOn.lean
+++ b/Mathlib/Order/Interval/Set/SurjOn.lean
@@ -35,8 +35,8 @@ theorem surjOn_Ico_of_monotone_surjective (h_mono : Monotone f) (h_surj : Functi
· intro p hp
rcases eq_left_or_mem_Ioo_of_mem_Ico hp with (rfl | hp')
· exact mem_image_of_mem f (left_mem_Ico.mpr hab)
- · have := surjOn_Ioo_of_monotone_surjective h_mono h_surj a b hp'
- exact image_subset f Ioo_subset_Ico_self this
+ · exact image_subset f Ioo_subset_Ico_self <|
+ surjOn_Ioo_of_monotone_surjective h_mono h_surj a b hp'
· rw [Ico_eq_empty (h_mono hab).not_lt]
exact surjOn_empty f _
@@ -51,8 +51,8 @@ theorem surjOn_Icc_of_monotone_surjective (h_mono : Monotone f) (h_surj : Functi
rcases eq_endpoints_or_mem_Ioo_of_mem_Icc hp with (rfl | rfl | hp')
· exact ⟨a, left_mem_Icc.mpr hab, rfl⟩
· exact ⟨b, right_mem_Icc.mpr hab, rfl⟩
- · have := surjOn_Ioo_of_monotone_surjective h_mono h_surj a b hp'
- exact image_subset f Ioo_subset_Icc_self this
+ · exact image_subset f Ioo_subset_Icc_self <|
+ surjOn_Ioo_of_monotone_surjective h_mono h_surj a b hp'
theorem surjOn_Ioi_of_monotone_surjective (h_mono : Monotone f) (h_surj : Function.Surjective f)
(a : α) : SurjOn f (Ioi a) (Ioi (f a)) := by
diff --git a/Mathlib/Order/Interval/Set/UnorderedInterval.lean b/Mathlib/Order/Interval/Set/UnorderedInterval.lean
index a0556c3932ff6..22ca451903d02 100644
--- a/Mathlib/Order/Interval/Set/UnorderedInterval.lean
+++ b/Mathlib/Order/Interval/Set/UnorderedInterval.lean
@@ -44,7 +44,7 @@ namespace Set
section Lattice
-variable [Lattice α] [Lattice β] {a a₁ a₂ b b₁ b₂ c x : α}
+variable [Lattice α] [Lattice β] {a a₁ a₂ b b₁ b₂ x : α}
/-- `uIcc a b` is the set of elements lying between `a` and `b`, with `a` and `b` included.
Note that we define it more generally in a lattice as `Set.Icc (a ⊓ b) (a ⊔ b)`. In a product type,
@@ -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
@@ -134,7 +132,7 @@ open Interval
section DistribLattice
-variable [DistribLattice α] {a a₁ a₂ b b₁ b₂ c x : α}
+variable [DistribLattice α] {a b c : α}
lemma eq_of_mem_uIcc_of_mem_uIcc (ha : a ∈ [[b, c]]) (hb : b ∈ [[a, c]]) : a = b :=
eq_of_inf_eq_sup_eq (inf_congr_right ha.1 hb.1) <| sup_congr_right ha.2 hb.2
@@ -155,7 +153,7 @@ section LinearOrder
variable [LinearOrder α]
section Lattice
-variable [Lattice β] {f : α → β} {s : Set α} {a b : α}
+variable [Lattice β] {f : α → β} {a b : α}
lemma _root_.MonotoneOn.mapsTo_uIcc (hf : MonotoneOn f (uIcc a b)) :
MapsTo f (uIcc a b) (uIcc (f a) (f b)) := by
@@ -187,7 +185,7 @@ lemma _root_.Antitone.image_uIcc_subset (hf : Antitone f) : f '' uIcc a b ⊆ uI
end Lattice
-variable [LinearOrder β] {f : α → β} {s : Set α} {a a₁ a₂ b b₁ b₂ c d x : α}
+variable [LinearOrder β] {f : α → β} {s : Set α} {a a₁ a₂ b b₁ b₂ c : α}
theorem Icc_min_max : Icc (min a b) (max a b) = [[a, b]] :=
rfl
@@ -294,8 +292,8 @@ lemma uIoc_injective_right (a : α) : Injective fun b => Ι b a := by
rw [Set.ext_iff] at h
obtain ha | ha := le_or_lt b a
· have hb := (h b).not
- simp only [ha, left_mem_uIoc, not_lt, true_iff_iff, not_mem_uIoc, ← not_le,
- and_true_iff, not_true, false_and_iff, not_false_iff, true_iff_iff, or_false_iff] at hb
+ simp only [ha, left_mem_uIoc, not_lt, true_iff, not_mem_uIoc, ← not_le,
+ and_true, not_true, false_and, not_false_iff, or_false] at hb
refine hb.eq_of_not_lt fun hc => ?_
simpa [ha, and_iff_right hc, ← @not_le _ _ _ a, iff_not_self, -not_le] using h c
· refine
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/KrullDimension.lean b/Mathlib/Order/KrullDimension.lean
index 86ed7e2ce6e89..4631e6250c4ba 100644
--- a/Mathlib/Order/KrullDimension.lean
+++ b/Mathlib/Order/KrullDimension.lean
@@ -174,6 +174,8 @@ variable {α β : Type*}
variable [Preorder α] [Preorder β]
+lemma LTSeries.length_le_krullDim (p : LTSeries α) : p.length ≤ krullDim α := le_sSup ⟨_, rfl⟩
+
lemma krullDim_nonneg_of_nonempty [Nonempty α] : 0 ≤ krullDim α :=
le_sSup ⟨⟨0, fun _ ↦ @Nonempty.some α inferInstance, fun f ↦ f.elim0⟩, rfl⟩
@@ -214,6 +216,14 @@ lemma krullDim_eq_zero_of_unique [Unique α] : krullDim α = 0 := by
by_contra r
exact ne_of_lt (q.step ⟨0, not_le.mp r⟩) <| Subsingleton.elim _ _
+lemma krullDim_nonpos_of_subsingleton [Subsingleton α] : krullDim α ≤ 0 := by
+ by_cases hα : Nonempty α
+ · have := uniqueOfSubsingleton (Classical.choice hα)
+ exact le_of_eq krullDim_eq_zero_of_unique
+ · have := not_nonempty_iff.mp hα
+ exact le_of_lt <| lt_of_eq_of_lt krullDim_eq_bot_of_isEmpty <|
+ Batteries.compareOfLessAndEq_eq_lt.mp rfl
+
lemma krullDim_le_of_strictComono_and_surj
(f : α → β) (hf : ∀ ⦃a b⦄, f a < f b → a < b) (hf' : Function.Surjective f) :
krullDim β ≤ krullDim α :=
diff --git a/Mathlib/Order/Lattice.lean b/Mathlib/Order/Lattice.lean
index 502fe4375dfb9..8383d090d9c12 100644
--- a/Mathlib/Order/Lattice.lean
+++ b/Mathlib/Order/Lattice.lean
@@ -6,7 +6,7 @@ Authors: Johannes Hölzl
import Mathlib.Data.Bool.Basic
import Mathlib.Order.Monotone.Basic
import Mathlib.Order.ULift
-import Mathlib.Tactic.GCongr.Core
+import Mathlib.Tactic.GCongr.CoreAttrs
/-!
# (Semi-)lattices
@@ -528,7 +528,7 @@ def Lattice.mk' {α : Type*} [Sup α] [Inf α] (sup_comm : ∀ a b : α, a ⊔ b
section Lattice
-variable [Lattice α] {a b c d : α}
+variable [Lattice α] {a b c : α}
theorem inf_le_sup : a ⊓ b ≤ a ⊔ b :=
inf_le_left.trans le_sup_left
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 63af8fb864d03..a83f19741bce1 100644
--- a/Mathlib/Order/LiminfLimsup.lean
+++ b/Mathlib/Order/LiminfLimsup.lean
@@ -3,6 +3,9 @@ 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, Johannes Hölzl, Rémy Degenne
-/
+import Mathlib.Algebra.BigOperators.Group.Finset
+import Mathlib.Algebra.Order.Group.Defs
+import Mathlib.Algebra.Order.Group.Unbundled.Abs
import Mathlib.Order.Filter.Cofinite
import Mathlib.Order.Hom.CompleteLattice
@@ -123,9 +126,17 @@ lemma isBoundedUnder_iff_eventually_bddBelow :
lemma _root_.BddAbove.isBoundedUnder (hs : s ∈ f) (hu : BddAbove (u '' s)) :
f.IsBoundedUnder (· ≤ ·) u := isBoundedUnder_iff_eventually_bddAbove.2 ⟨_, hu, hs⟩
+/-- A bounded above function `u` is in particular eventually bounded above. -/
+lemma _root_.BddAbove.isBoundedUnder_of_range (hu : BddAbove (Set.range u)) :
+ f.IsBoundedUnder (· ≤ ·) u := BddAbove.isBoundedUnder (s := univ) f.univ_mem (by simpa)
+
lemma _root_.BddBelow.isBoundedUnder (hs : s ∈ f) (hu : BddBelow (u '' s)) :
f.IsBoundedUnder (· ≥ ·) u := isBoundedUnder_iff_eventually_bddBelow.2 ⟨_, hu, hs⟩
+/-- A bounded below function `u` is in particular eventually bounded below. -/
+lemma _root_.BddBelow.isBoundedUnder_of_range (hu : BddBelow (Set.range u)) :
+ f.IsBoundedUnder (· ≥ ·) u := BddBelow.isBoundedUnder (s := univ) f.univ_mem (by simpa)
+
end Preorder
theorem _root_.Monotone.isBoundedUnder_le_comp [Preorder α] [Preorder β] {l : Filter γ} {u : γ → α}
@@ -274,7 +285,7 @@ end Relation
section add_and_sum
-open Filter BigOperators Set
+open Filter Set
variable {α : Type*} {f : Filter α}
variable {R : Type*}
@@ -294,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
@@ -304,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
@@ -314,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
@@ -443,7 +450,7 @@ macro "isBoundedDefault" : tactic =>
section ConditionallyCompleteLattice
-variable [ConditionallyCompleteLattice α]
+variable [ConditionallyCompleteLattice α] {s : Set α} {u : β → α}
-- Porting note: Renamed from Limsup and Liminf to limsSup and limsInf
/-- The `limsSup` of a filter `f` is the infimum of the `a` such that, eventually for `f`,
@@ -632,12 +639,17 @@ theorem liminf_le_liminf_of_le {α β} [ConditionallyCompleteLattice β] {f g :
liminf u f ≤ liminf u g :=
limsInf_le_limsInf_of_le (map_mono h) hf hg
-theorem limsSup_principal {s : Set α} (h : BddAbove s) (hs : s.Nonempty) :
- limsSup (𝓟 s) = sSup s := by
- simp only [limsSup, eventually_principal]; exact csInf_upper_bounds_eq_csSup h hs
+lemma limsSup_principal_eq_csSup (h : BddAbove s) (hs : s.Nonempty) : limsSup (𝓟 s) = sSup s := by
+ simp only [limsSup, eventually_principal]; exact csInf_upperBounds_eq_csSup h hs
+
+lemma limsInf_principal_eq_csSup (h : BddBelow s) (hs : s.Nonempty) : limsInf (𝓟 s) = sInf s :=
+ limsSup_principal_eq_csSup (α := αᵒᵈ) h hs
-theorem limsInf_principal {s : Set α} (h : BddBelow s) (hs : s.Nonempty) : limsInf (𝓟 s) = sInf s :=
- limsSup_principal (α := αᵒᵈ) h hs
+lemma limsup_top_eq_ciSup [Nonempty β] (hu : BddAbove (range u)) : limsup u ⊤ = ⨆ i, u i := by
+ rw [limsup, map_top, limsSup_principal_eq_csSup hu (range_nonempty _), sSup_range]
+
+lemma liminf_top_eq_ciInf [Nonempty β] (hu : BddBelow (range u)) : liminf u ⊤ = ⨅ i, u i := by
+ rw [liminf, map_top, limsInf_principal_eq_csSup hu (range_nonempty _), sInf_range]
theorem limsup_congr {α : Type*} [ConditionallyCompleteLattice β] {f : Filter α} {u v : α → β}
(h : ∀ᶠ a in f, u a = v a) : limsup u f = limsup v f := by
@@ -786,7 +798,22 @@ theorem HasBasis.limsup_eq_iInf_iSup {p : ι → Prop} {s : ι → Set β} {f :
(h : f.HasBasis p s) : limsup u f = ⨅ (i) (_ : p i), ⨆ a ∈ s i, u a :=
(h.map u).limsSup_eq_iInf_sSup.trans <| by simp only [sSup_image, id]
-@[simp] lemma limsup_top (u : β → α) : limsup u ⊤ = ⨆ i, u i := by simp [limsup_eq_iInf_iSup]
+lemma limsSup_principal_eq_sSup (s : Set α) : limsSup (𝓟 s) = sSup s := by
+ simpa only [limsSup, eventually_principal] using sInf_upperBounds_eq_csSup s
+
+lemma limsInf_principal_eq_sInf (s : Set α) : limsInf (𝓟 s) = sInf s := by
+ simpa only [limsInf, eventually_principal] using sSup_lowerBounds_eq_sInf s
+
+@[simp] lemma limsup_top_eq_iSup (u : β → α) : limsup u ⊤ = ⨆ i, u i := by
+ rw [limsup, map_top, limsSup_principal_eq_sSup, sSup_range]
+
+@[simp] lemma liminf_top_eq_iInf (u : β → α) : liminf u ⊤ = ⨅ i, u i := by
+ rw [liminf, map_top, limsInf_principal_eq_sInf, sInf_range]
+
+@[deprecated (since := "2024-08-27")] alias limsSup_principal := limsSup_principal_eq_sSup
+@[deprecated (since := "2024-08-27")] alias limsInf_principal := limsInf_principal_eq_sInf
+@[deprecated (since := "2024-08-27")] alias limsup_top := limsup_top_eq_iSup
+@[deprecated (since := "2024-08-27")] alias liminf_top := liminf_top_eq_iInf
theorem blimsup_congr' {f : Filter β} {p q : β → Prop} {u : β → α}
(h : ∀ᶠ x in f, u x ≠ ⊥ → (p x ↔ q x)) : blimsup u f p = blimsup u f q := by
@@ -825,8 +852,6 @@ theorem liminf_eq_iSup_iInf_of_nat {u : ℕ → α} : liminf u atTop = ⨆ n :
theorem liminf_eq_iSup_iInf_of_nat' {u : ℕ → α} : liminf u atTop = ⨆ n : ℕ, ⨅ i : ℕ, u (i + n) :=
@limsup_eq_iInf_iSup_of_nat' αᵒᵈ _ _
-@[simp] lemma liminf_top (u : β → α) : liminf u ⊤ = ⨅ i, u i := by simp [liminf_eq_iSup_iInf]
-
theorem HasBasis.liminf_eq_iSup_iInf {p : ι → Prop} {s : ι → Set β} {f : Filter β} {u : β → α}
(h : f.HasBasis p s) : liminf u f = ⨆ (i) (_ : p i), ⨅ a ∈ s i, u a :=
HasBasis.limsup_eq_iInf_iSup (α := αᵒᵈ) h
@@ -1130,12 +1155,12 @@ theorem cofinite.bliminf_set_eq : bliminf s cofinite p = { x | { n | p n ∧ x
/-- In other words, `limsup cofinite s` is the set of elements lying inside the family `s`
infinitely often. -/
theorem cofinite.limsup_set_eq : limsup s cofinite = { x | { n | x ∈ s n }.Infinite } := by
- simp only [← cofinite.blimsup_true s, cofinite.blimsup_set_eq, true_and_iff]
+ simp only [← cofinite.blimsup_true s, cofinite.blimsup_set_eq, true_and]
/-- In other words, `liminf cofinite s` is the set of elements lying outside the family `s`
finitely often. -/
theorem cofinite.liminf_set_eq : liminf s cofinite = { x | { n | x ∉ s n }.Finite } := by
- simp only [← cofinite.bliminf_true s, cofinite.bliminf_set_eq, true_and_iff]
+ simp only [← cofinite.bliminf_true s, cofinite.bliminf_set_eq, true_and]
theorem exists_forall_mem_of_hasBasis_mem_blimsup {l : Filter β} {b : ι → Set β} {q : ι → Prop}
(hl : l.HasBasis q b) {u : β → Set α} {p : β → Prop} {x : α} (hx : x ∈ blimsup u l p) :
diff --git a/Mathlib/Order/Max.lean b/Mathlib/Order/Max.lean
index b355050f7aea9..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
@@ -356,7 +356,7 @@ end PartialOrder
section Prod
-variable [Preorder α] [Preorder β] {a a₁ a₂ : α} {b b₁ b₂ : β} {x y : α × β}
+variable [Preorder α] [Preorder β] {a : α} {b : β} {x : α × β}
theorem IsBot.prod_mk (ha : IsBot a) (hb : IsBot b) : IsBot (a, b) := fun _ => ⟨ha _, hb _⟩
diff --git a/Mathlib/Order/MinMax.lean b/Mathlib/Order/MinMax.lean
index cd79b7297eee5..d43fc960d2020 100644
--- a/Mathlib/Order/MinMax.lean
+++ b/Mathlib/Order/MinMax.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.Logic.OpClass
import Mathlib.Order.Lattice
/-!
@@ -188,14 +189,14 @@ theorem max_lt_max (h₁ : a < c) (h₂ : b < d) : max a b < max c d :=
theorem min_lt_min (h₁ : a < c) (h₂ : b < d) : min a b < min c d :=
@max_lt_max αᵒᵈ _ _ _ _ _ h₁ h₂
-theorem min_right_comm (a b c : α) : min (min a b) c = min (min a c) b :=
- right_comm min min_comm min_assoc a b c
+theorem min_right_comm (a b c : α) : min (min a b) c = min (min a c) b := by
+ rw [min_assoc, min_comm b, min_assoc]
-theorem Max.left_comm (a b c : α) : max a (max b c) = max b (max a c) :=
- _root_.left_comm max max_comm max_assoc a b c
+theorem Max.left_comm (a b c : α) : max a (max b c) = max b (max a c) := by
+ rw [← max_assoc, max_comm a, max_assoc]
-theorem Max.right_comm (a b c : α) : max (max a b) c = max (max a c) b :=
- _root_.right_comm max max_comm max_assoc a b c
+theorem Max.right_comm (a b c : α) : max (max a b) c = max (max a c) b := by
+ rw [max_assoc, max_comm b, max_assoc]
theorem MonotoneOn.map_max (hf : MonotoneOn f s) (ha : a ∈ s) (hb : b ∈ s) : f (max a b) =
max (f a) (f b) := by
@@ -234,34 +235,12 @@ theorem le_of_max_le_left {a b c : α} (h : max a b ≤ c) : a ≤ c :=
theorem le_of_max_le_right {a b c : α} (h : max a b ≤ c) : b ≤ c :=
le_trans (le_max_right _ _) h
-theorem max_commutative : Commutative (max : α → α → α) :=
- max_comm
+instance instCommutativeMax : Std.Commutative (α := α) max where comm := max_comm
+instance instAssociativeMax : Std.Associative (α := α) max where assoc := max_assoc
+instance instCommutativeMin : Std.Commutative (α := α) min where comm := min_comm
+instance instAssociativeMin : Std.Associative (α := α) min where assoc := min_assoc
-theorem max_associative : Associative (max : α → α → α) :=
- max_assoc
-
-instance : Std.Commutative (α := α) max where
- comm := max_comm
-
-instance : Std.Associative (α := α) max where
- assoc := max_assoc
-
-theorem max_left_commutative : LeftCommutative (max : α → α → α) :=
- max_left_comm
-
-theorem min_commutative : Commutative (min : α → α → α) :=
- min_comm
-
-theorem min_associative : Associative (α := α) min :=
- min_assoc
-
-instance : Std.Commutative (α := α) min where
- comm := min_comm
-
-instance : Std.Associative (α := α) min where
- assoc := min_assoc
-
-theorem min_left_commutative : LeftCommutative (min : α → α → α) :=
- min_left_comm
+theorem max_left_commutative : LeftCommutative (max : α → α → α) := ⟨max_left_comm⟩
+theorem min_left_commutative : LeftCommutative (min : α → α → α) := ⟨min_left_comm⟩
end
diff --git a/Mathlib/Order/Minimal.lean b/Mathlib/Order/Minimal.lean
index eec9b8aea31ce..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
@@ -381,7 +358,7 @@ variable [Preorder α]
theorem setOf_minimal_subset (s : Set α) : {x | Minimal (· ∈ s) x} ⊆ s :=
sep_subset ..
-theorem setOf_maximal_subset (s : Set α) : {x | Minimal (· ∈ s) x} ⊆ s :=
+theorem setOf_maximal_subset (s : Set α) : {x | Maximal (· ∈ s) x} ⊆ s :=
sep_subset ..
theorem Set.Subsingleton.maximal_mem_iff (h : s.Subsingleton) : Maximal (· ∈ s) x ↔ x ∈ s := by
@@ -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/ModularLattice.lean b/Mathlib/Order/ModularLattice.lean
index 76b1789fce3e3..7b2b7f77ae7f8 100644
--- a/Mathlib/Order/ModularLattice.lean
+++ b/Mathlib/Order/ModularLattice.lean
@@ -218,6 +218,10 @@ theorem sup_lt_sup_of_lt_of_inf_le_inf (hxy : x < y) (hinf : y ⊓ z ≤ x ⊓ z
theorem inf_lt_inf_of_lt_of_sup_le_sup (hxy : x < y) (hinf : y ⊔ z ≤ x ⊔ z) : x ⊓ z < y ⊓ z :=
sup_lt_sup_of_lt_of_inf_le_inf (α := αᵒᵈ) hxy hinf
+theorem strictMono_inf_prod_sup : StrictMono fun x ↦ (x ⊓ z, x ⊔ z) := fun _x _y hxy ↦
+ ⟨⟨inf_le_inf_right _ hxy.le, sup_le_sup_right hxy.le _⟩,
+ fun ⟨inf_le, sup_le⟩ ↦ (sup_lt_sup_of_lt_of_inf_le_inf hxy inf_le).not_le sup_le⟩
+
/-- A generalization of the theorem that if `N` is a submodule of `M` and
`N` and `M / N` are both Artinian, then `M` is Artinian. -/
theorem wellFounded_lt_exact_sequence {β γ : Type*} [PartialOrder β] [Preorder γ]
@@ -225,16 +229,9 @@ theorem wellFounded_lt_exact_sequence {β γ : Type*} [PartialOrder β] [Preorde
(f₁ : β → α) (f₂ : α → β) (g₁ : γ → α) (g₂ : α → γ) (gci : GaloisCoinsertion f₁ f₂)
(gi : GaloisInsertion g₂ g₁) (hf : ∀ a, f₁ (f₂ a) = a ⊓ K) (hg : ∀ a, g₁ (g₂ a) = a ⊔ K) :
WellFoundedLT α :=
- ⟨Subrelation.wf
- (@fun A B hAB =>
- show Prod.Lex (· < ·) (· < ·) (f₂ A, g₂ A) (f₂ B, g₂ B) by
- simp only [Prod.lex_def, lt_iff_le_not_le, ← gci.l_le_l_iff, ← gi.u_le_u_iff, hf, hg,
- le_antisymm_iff]
- simp only [gci.l_le_l_iff, gi.u_le_u_iff, ← lt_iff_le_not_le, ← le_antisymm_iff]
- rcases lt_or_eq_of_le (inf_le_inf_right K (le_of_lt hAB)) with h | h
- · exact Or.inl h
- · exact Or.inr ⟨h, sup_lt_sup_of_lt_of_inf_le_inf hAB (le_of_eq h.symm)⟩)
- (InvImage.wf _ (h₁.wf.prod_lex h₂.wf))⟩
+ StrictMono.wellFoundedLT (f := fun A ↦ (f₂ A, g₂ A)) fun A B hAB ↦ by
+ simp only [Prod.le_def, lt_iff_le_not_le, ← gci.l_le_l_iff, ← gi.u_le_u_iff, hf, hg]
+ exact strictMono_inf_prod_sup hAB
/-- A generalization of the theorem that if `N` is a submodule of `M` and
`N` and `M / N` are both Noetherian, then `M` is Noetherian. -/
@@ -261,8 +258,8 @@ def infIccOrderIsoIccSup (a b : α) : Set.Icc (a ⊓ b) a ≃o Set.Icc b (a ⊔
(by
change a ⊓ ↑x ⊔ b = ↑x
rw [inf_comm, inf_sup_assoc_of_le _ x.prop.1, inf_eq_left.2 x.prop.2])
- map_rel_iff' := @fun x y => by
- simp only [Subtype.mk_le_mk, Equiv.coe_fn_mk, and_true_iff, le_sup_right]
+ map_rel_iff' {x y} := by
+ simp only [Subtype.mk_le_mk, Equiv.coe_fn_mk, le_sup_right]
rw [← Subtype.coe_le_coe]
refine ⟨fun h => ?_, fun h => sup_le_sup_right h _⟩
rw [← sup_eq_right.2 x.prop.1, inf_sup_assoc_of_le _ x.prop.2, sup_comm, ←
diff --git a/Mathlib/Order/Monotone/Basic.lean b/Mathlib/Order/Monotone/Basic.lean
index c1a6c68abafef..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
@@ -1014,9 +1013,6 @@ theorem Antitone.ne_of_lt_of_lt_int {f : ℤ → α} (hf : Antitone f) (n : ℤ)
rintro rfl
exact (hf.reflect_lt h2).not_le (Int.le_of_lt_add_one <| hf.reflect_lt h1)
-theorem StrictMono.id_le {φ : ℕ → ℕ} (h : StrictMono φ) : ∀ n, n ≤ φ n := fun n ↦
- Nat.recOn n (Nat.zero_le _) fun n hn ↦ Nat.succ_le_of_lt (hn.trans_lt <| h <| Nat.lt_succ_self n)
-
end Preorder
theorem Subtype.mono_coe [Preorder α] (t : Set α) : Monotone ((↑) : Subtype t → α) :=
@@ -1028,7 +1024,7 @@ theorem Subtype.strictMono_coe [Preorder α] (t : Set α) :
section Preorder
-variable [Preorder α] [Preorder β] [Preorder γ] [Preorder δ] {f : α → γ} {g : β → δ} {a b : α}
+variable [Preorder α] [Preorder β] [Preorder γ] [Preorder δ] {f : α → γ} {g : β → δ}
theorem monotone_fst : Monotone (@Prod.fst α β) := fun _ _ ↦ And.left
@@ -1077,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/Nat.lean b/Mathlib/Order/Nat.lean
index 9ecce65c098b4..fb4ba2eb92da7 100644
--- a/Mathlib/Order/Nat.lean
+++ b/Mathlib/Order/Nat.lean
@@ -23,6 +23,9 @@ instance instOrderBot : OrderBot ℕ where
bot := 0
bot_le := zero_le
+instance instNoMaxOrder : NoMaxOrder ℕ where
+ exists_gt n := ⟨n + 1, n.lt_succ_self⟩
+
/-! ### Miscellaneous lemmas -/
-- We want to use this lemma earlier than the lemma simp can prove it with
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 cfb8d50271716..e40824d604869 100644
--- a/Mathlib/Order/PartialSups.lean
+++ b/Mathlib/Order/PartialSups.lean
@@ -1,12 +1,12 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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 abdda3c97c4c7..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⟩
@@ -257,6 +254,15 @@ theorem parts_top_subsingleton (a : α) [Decidable (a = ⊥)] :
((⊤ : Finpartition a).parts : Set α).Subsingleton :=
Set.subsingleton_of_subset_singleton fun _ hb ↦ mem_singleton.1 <| parts_top_subset _ hb
+-- TODO: this instance takes double-exponential time to generate all partitions, find a faster way
+instance [DecidableEq α] {s : Finset α} : Fintype (Finpartition s) where
+ elems := s.powerset.powerset.image
+ fun ps ↦ if h : ps.sup id = s ∧ ⊥ ∉ ps ∧ ps.SupIndep id then ⟨ps, h.2.2, h.1, h.2.1⟩ else ⊤
+ complete P := by
+ refine mem_image.mpr ⟨P.parts, ?_, ?_⟩
+ · rw [mem_powerset]; intro p hp; rw [mem_powerset]; exact P.le hp
+ · simp only [P.supIndep, P.sup_parts, P.not_bot_mem]; rfl
+
end Order
end Lattice
@@ -329,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
@@ -380,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]
@@ -405,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
@@ -419,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]
@@ -497,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
@@ -523,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
@@ -537,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
@@ -555,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,
@@ -572,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
@@ -596,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
@@ -605,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
@@ -620,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]
@@ -630,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]
@@ -639,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)
@@ -653,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 dcfbcc1773326..cf73ab1542940 100644
--- a/Mathlib/Order/RelClasses.lean
+++ b/Mathlib/Order/RelClasses.lean
@@ -89,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 }
@@ -132,15 +128,13 @@ theorem eq_empty_relation (r) [IsIrrefl α r] [Subsingleton α] : r = EmptyRelat
instance : IsIrrefl α EmptyRelation :=
⟨fun _ => id⟩
-theorem trans_trichotomous_left [IsTrans α r] [IsTrichotomous α r] {a b c : α} :
- ¬r b a → r b c → r a c := by
- intro h₁ h₂
+theorem trans_trichotomous_left [IsTrans α r] [IsTrichotomous α r] {a b c : α}
+ (h₁ : ¬r b a) (h₂ : r b c) : r a c := by
rcases trichotomous_of r a b with (h₃ | rfl | h₃)
exacts [_root_.trans h₃ h₂, h₂, absurd h₃ h₁]
-theorem trans_trichotomous_right [IsTrans α r] [IsTrichotomous α r] {a b c : α} :
- r a b → ¬r c b → r a c := by
- intro h₁ h₂
+theorem trans_trichotomous_right [IsTrans α r] [IsTrichotomous α r] {a b c : α}
+ (h₁ : r a b) (h₂ : ¬r c b) : r a c := by
rcases trichotomous_of r b c with (h₃ | rfl | h₃)
exacts [_root_.trans h₁ h₃, h₁, absurd h₃ h₂]
@@ -158,7 +152,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₂
@@ -170,7 +164,7 @@ abbrev partialOrderOfSO (r) [IsStrictOrder α r] : PartialOrder α where
| _, _, Or.inl rfl => rfl
| _, Or.inr h₁, Or.inr h₂ => (asymm h₁ h₂).elim
lt_iff_le_not_le x y :=
- ⟨fun h => ⟨Or.inr h, not_or_of_not (fun e => by rw [e] at h; exact irrefl _ h) (asymm h)⟩,
+ ⟨fun h => ⟨Or.inr h, not_or_intro (fun e => by rw [e] at h; exact irrefl _ h) (asymm h)⟩,
fun ⟨h₁, h₂⟩ => h₁.resolve_left fun e => h₂ <| e ▸ Or.inl rfl⟩
/-- Construct a linear order from an `IsStrictTotalOrder` relation.
@@ -184,7 +178,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,
@@ -776,9 +770,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
@@ -799,9 +790,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 bfbc41e545f91..ae6e5fc6d18b7 100644
--- a/Mathlib/Order/RelIso/Basic.lean
+++ b/Mathlib/Order/RelIso/Basic.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.Algebra.Classes
import Mathlib.Data.FunLike.Basic
import Mathlib.Logic.Embedding.Basic
import Mathlib.Order.RelClasses
@@ -59,7 +58,7 @@ satisfy `r a b → s (f a) (f b)`.
The relations `r` and `s` are `outParam`s since figuring them out from a goal is a higher-order
matching problem that Lean usually can't do unaided.
-/
-class RelHomClass (F : Type*) {α β : Type*} (r : outParam <| α → α → Prop)
+class RelHomClass (F : Type*) {α β : outParam Type*} (r : outParam <| α → α → Prop)
(s : outParam <| β → β → Prop) [FunLike F α β] : Prop where
/-- A `RelHomClass` sends related elements to related elements -/
map_rel : ∀ (f : F) {a b}, r a b → s (f a) (f b)
@@ -202,7 +201,7 @@ instance : Coe (r ↪r s) (r →r s) :=
-- TODO: define and instantiate a `RelEmbeddingClass` when `EmbeddingLike` is defined
instance : FunLike (r ↪r s) α β where
- coe := fun x => x.toFun
+ coe x := x.toFun
coe_injective' f g h := by
rcases f with ⟨⟨⟩⟩
rcases g with ⟨⟨⟩⟩
@@ -350,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 => ?_
@@ -372,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
@@ -390,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
@@ -537,7 +536,7 @@ instance : CoeOut (r ≃r s) (r ↪r s) :=
-- TODO: define and instantiate a `RelIsoClass` when `EquivLike` is defined
instance : FunLike (r ≃r s) α β where
- coe := fun x => x
+ coe x := x
coe_injective' := Equiv.coe_fn_injective.comp toEquiv_injective
-- TODO: define and instantiate a `RelIsoClass` when `EquivLike` is defined
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 fc2073f2ab1b0..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 `α`
@@ -758,7 +758,7 @@ lemma apply_add_index_le_apply_add_index_nat (p : LTSeries ℕ) (i j : Fin (p.le
have ⟨j, hj⟩ := j
simp only [Fin.mk_le_mk] at hij
simp only at *
- induction j, hij using Nat.le_induction with
+ induction j, hij using Nat.le_induction with
| base => simp
| succ j _hij ih =>
specialize ih (Nat.lt_of_succ_lt hj)
diff --git a/Mathlib/Order/Restriction.lean b/Mathlib/Order/Restriction.lean
new file mode 100644
index 0000000000000..53d992f41e60b
--- /dev/null
+++ b/Mathlib/Order/Restriction.lean
@@ -0,0 +1,84 @@
+/-
+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.Order.Interval.Set.Basic
+import Mathlib.Order.Interval.Finset.Basic
+
+/-!
+# Restriction of a function indexed by a preorder
+
+Given a preorder `α` and dependent function `f : (i : α) → π i` and `a : α`, one might want
+to consider the restriction of `f` to elements `≤ a`.
+This is defined in this file as `Preorder.restrictLe a f`.
+Similarly, if we have `a b : α`, `hab : a ≤ b` and `f : (i : ↑(Set.Iic b)) → π ↑i`,
+one might want to restrict it to elements `≤ a`.
+This is defined in this file as `Preorder.restrictLe₂ hab f`.
+
+We also provide versions where the intervals are seen as finite sets, see `Preorder.frestrictLe`
+and `Preorder.frestrictLe₂`.
+
+## Main definitions
+* `Preorder.restrictLe a f`: Restricts the function `f` to the variables indexed by elements `≤ a`.
+-/
+
+namespace Preorder
+
+variable {α : Type*} [Preorder α] {π : α → Type*}
+
+section Set
+
+open Set
+
+/-- Restrict domain of a function `f` indexed by `α` to elements `≤ a`. -/
+def restrictLe (a : α) := (Iic a).restrict (π := π)
+
+@[simp]
+lemma restrictLe_apply (a : α) (f : (a : α) → π a) (i : Iic a) : restrictLe a f i = f i := rfl
+
+/-- If a function `f` indexed by `α` is restricted to elements `≤ π`, and `a ≤ b`,
+this is the restriction to elements `≤ a`. -/
+def restrictLe₂ {a b : α} (hab : a ≤ b) := Set.restrict₂ (π := π) (Iic_subset_Iic.2 hab)
+
+@[simp]
+lemma restrictLe₂_apply {a b : α} (hab : a ≤ b) (f : (i : Iic b) → π i) (i : Iic a) :
+ restrictLe₂ hab f i = f ⟨i.1, Iic_subset_Iic.2 hab i.2⟩ := rfl
+
+theorem restrictLe₂_comp_restrictLe {a b : α} (hab : a ≤ b) :
+ (restrictLe₂ (π := π) hab) ∘ (restrictLe b) = restrictLe a := rfl
+
+theorem restrictLe₂_comp_restrictLe₂ {a b c : α} (hab : a ≤ b) (hbc : b ≤ c) :
+ (restrictLe₂ (π := π) hab) ∘ (restrictLe₂ hbc) = restrictLe₂ (hab.trans hbc) := rfl
+
+end Set
+
+section Finset
+
+variable [LocallyFiniteOrderBot α]
+
+open Finset
+
+/-- Restrict domain of a function `f` indexed by `α` to elements `≤ α`, seen as a finite set. -/
+def frestrictLe (a : α) := (Iic a).restrict (π := π)
+
+@[simp]
+lemma frestrictLe_apply (a : α) (f : (a : α) → π a) (i : Iic a) : frestrictLe a f i = f i := rfl
+
+/-- If a function `f` indexed by `α` is restricted to elements `≤ b`, and `a ≤ b`,
+this is the restriction to elements `≤ b`. Intervals are seen as finite sets. -/
+def frestrictLe₂ {a b : α} (hab : a ≤ b) := Finset.restrict₂ (π := π) (Iic_subset_Iic.2 hab)
+
+@[simp]
+lemma frestrictLe₂_apply {a b : α} (hab : a ≤ b) (f : (i : Iic b) → π i) (i : Iic a) :
+ frestrictLe₂ hab f i = f ⟨i.1, Iic_subset_Iic.2 hab i.2⟩ := rfl
+
+theorem frestrictLe₂_comp_frestrictLe {a b : α} (hab : a ≤ b) :
+ (frestrictLe₂ (π := π) hab) ∘ (frestrictLe b) = frestrictLe a := rfl
+
+theorem frestrictLe₂_comp_frestrictLe₂ {a b c : α} (hab : a ≤ b) (hbc : b ≤ c) :
+ (frestrictLe₂ (π := π) hab) ∘ (frestrictLe₂ hbc) = frestrictLe₂ (hab.trans hbc) := rfl
+
+end Finset
+
+end Preorder
diff --git a/Mathlib/Order/ScottContinuity.lean b/Mathlib/Order/ScottContinuity.lean
index 00f7de8d741c2..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`.
@@ -71,7 +71,7 @@ lemma ScottContinuousOn.prodMk (hD : ∀ a b : α, a ≤ b → {a, b} ∈ D)
rw [IsLUB, IsLeast, upperBounds]
constructor
· simp only [mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, mem_setOf_eq,
- Prod.mk_le_mk]
+ Prod.mk_le_mk]
intro b hb
exact ⟨hf.monotone D hD (hda.1 hb), hg.monotone D hD (hda.1 hb)⟩
· intro ⟨p₁, p₂⟩ hp
@@ -101,7 +101,7 @@ lemma ScottContinuous.scottContinuousOn {D : Set (Set α)} :
ScottContinuous f → ScottContinuousOn D f := fun h _ _ d₂ d₃ _ hda => h d₂ d₃ hda
protected theorem ScottContinuous.monotone (h : ScottContinuous f) : Monotone f :=
- h.scottContinuousOn.monotone univ (fun _ _ _ ↦ trivial)
+ h.scottContinuousOn.monotone univ (fun _ _ _ ↦ mem_univ _)
@[simp] lemma ScottContinuous.id : ScottContinuous (id : α → α) := by simp [ScottContinuous]
@@ -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 a0c95c0506eb5..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 α]
@@ -138,8 +200,8 @@ end LinearOrder
section bdd_range
variable [Preorder α] [Nonempty α] [Preorder β] {f : α → β}
-lemma StrictMono.not_bddAbove_range [NoMaxOrder α] [SuccOrder β] [IsSuccArchimedean β]
- (hf : StrictMono f) : ¬ BddAbove (Set.range f) := by
+lemma StrictMono.not_bddAbove_range_of_isSuccArchimedean [NoMaxOrder α] [SuccOrder β]
+ [IsSuccArchimedean β] (hf : StrictMono f) : ¬ BddAbove (Set.range f) := by
rintro ⟨m, hm⟩
have hm' : ∀ a, f a ≤ m := fun a ↦ hm <| Set.mem_range_self _
obtain ⟨a₀⟩ := ‹Nonempty α›
@@ -152,14 +214,29 @@ lemma StrictMono.not_bddAbove_range [NoMaxOrder α] [SuccOrder β] [IsSuccArchim
rintro b _ ⟨a, hba⟩
exact (h a).imp (fun a' ↦ (succ_le_of_lt hba).trans_lt)
-lemma StrictMono.not_bddBelow_range [NoMinOrder α] [PredOrder β] [IsPredArchimedean β]
- (hf : StrictMono f) : ¬ BddBelow (Set.range f) := hf.dual.not_bddAbove_range
+@[deprecated StrictMono.not_bddAbove_range_of_isSuccArchimedean (since := "2024-09-21")]
+alias StrictMono.not_bddAbove_range := StrictMono.not_bddAbove_range_of_isSuccArchimedean
+
+lemma StrictMono.not_bddBelow_range_of_isPredArchimedean [NoMinOrder α] [PredOrder β]
+ [IsPredArchimedean β] (hf : StrictMono f) : ¬ BddBelow (Set.range f) :=
+ hf.dual.not_bddAbove_range_of_isSuccArchimedean
+
+@[deprecated StrictMono.not_bddBelow_range_of_isPredArchimedean (since := "2024-09-21")]
+alias StrictMono.not_bddBelow_range := StrictMono.not_bddBelow_range_of_isPredArchimedean
+
+lemma StrictAnti.not_bddBelow_range_of_isSuccArchimedean [NoMinOrder α] [SuccOrder β]
+ [IsSuccArchimedean β] (hf : StrictAnti f) : ¬ BddAbove (Set.range f) :=
+ hf.dual_right.not_bddBelow_range_of_isPredArchimedean
-lemma StrictAnti.not_bddAbove_range [NoMinOrder α] [SuccOrder β] [IsSuccArchimedean β]
- (hf : StrictAnti f) : ¬ BddAbove (Set.range f) := hf.dual_right.not_bddBelow_range
+@[deprecated StrictAnti.not_bddBelow_range_of_isSuccArchimedean (since := "2024-09-21")]
+alias StrictAnti.not_bddAbove_range := StrictAnti.not_bddBelow_range_of_isSuccArchimedean
-lemma StrictAnti.not_bddBelow_range [NoMaxOrder α] [PredOrder β] [IsPredArchimedean β]
- (hf : StrictAnti f) : ¬ BddBelow (Set.range f) := hf.dual_right.not_bddAbove_range
+lemma StrictAnti.not_bddBelow_range_of_isPredArchimedean [NoMaxOrder α] [PredOrder β]
+ [IsPredArchimedean β] (hf : StrictAnti f) : ¬ BddBelow (Set.range f) :=
+ hf.dual_right.not_bddAbove_range_of_isSuccArchimedean
+
+@[deprecated StrictAnti.not_bddBelow_range_of_isPredArchimedean (since := "2024-09-21")]
+alias StrictAnti.not_bddBelow_range := StrictAnti.not_bddBelow_range_of_isPredArchimedean
end bdd_range
@@ -218,3 +295,218 @@ lemma SuccOrder.forall_ne_bot_iff
rw [← Nat.succ_pred_eq_of_pos hj]
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]
+
+/-- `IsSuccArchimedean` transfers across equivalences between `SuccOrder`s. -/
+protected lemma IsSuccArchimedean.of_orderIso [SuccOrder X] [IsSuccArchimedean X] [SuccOrder Y]
+ (f : X ≃o Y) : IsSuccArchimedean Y where
+ exists_succ_iterate_of_le {a b} h := by
+ refine (exists_succ_iterate_of_le ((map_inv_le_map_inv_iff f).mpr h)).imp ?_
+ intro n
+ rw [← f.apply_eq_iff_eq, EquivLike.apply_inv_apply]
+ rintro rfl
+ clear h
+ induction n generalizing a with
+ | zero => simp
+ | succ n IH => simp only [Function.iterate_succ', Function.comp_apply, IH, f.map_succ]
+
+/-- `IsPredArchimedean` transfers across equivalences between `PredOrder`s. -/
+protected lemma IsPredArchimedean.of_orderIso [PredOrder X] [IsPredArchimedean X] [PredOrder Y]
+ (f : X ≃o Y) : IsPredArchimedean Y where
+ exists_pred_iterate_of_le {a b} h := by
+ refine (exists_pred_iterate_of_le ((map_inv_le_map_inv_iff f).mpr h)).imp ?_
+ intro n
+ rw [← f.apply_eq_iff_eq, EquivLike.apply_inv_apply]
+ rintro rfl
+ clear h
+ induction n generalizing b with
+ | zero => simp
+ | 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 c73818b764697..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 α] :
@@ -223,15 +223,13 @@ lemma le_succ_of_wcovBy (h : a ⩿ b) : b ≤ succ a := by
alias _root_.WCovBy.le_succ := le_succ_of_wcovBy
-theorem le_succ_iterate (k : ℕ) (x : α) : x ≤ succ^[k] x := by
- conv_lhs => rw [(by simp only [Function.iterate_id, id] : x = id^[k] x)]
- exact Monotone.le_iterate_of_le succ_mono le_succ k x
+theorem le_succ_iterate (k : ℕ) (x : α) : x ≤ succ^[k] x :=
+ id_le_iterate_of_id_le le_succ _ _
theorem isMax_iterate_succ_of_eq_of_lt {n m : ℕ} (h_eq : succ^[n] a = succ^[m] a)
(h_lt : n < m) : IsMax (succ^[n] a) := by
refine max_of_succ_le (le_trans ?_ h_eq.symm.le)
- have : succ (succ^[n] a) = succ^[n + 1] a := by rw [Function.iterate_succ', comp]
- rw [this]
+ rw [← iterate_succ_apply' succ]
have h_le : n + 1 ≤ m := Nat.succ_le_of_lt h_lt
exact Monotone.monotone_iterate_of_le_map succ_mono (le_succ a) h_le
@@ -427,6 +425,11 @@ theorem le_succ_iff_eq_or_le : a ≤ succ b ↔ a = succ b ∨ a ≤ b := by
theorem lt_succ_iff_eq_or_lt_of_not_isMax (hb : ¬IsMax b) : a < succ b ↔ a = b ∨ a < b :=
(lt_succ_iff_of_not_isMax hb).trans le_iff_eq_or_lt
+theorem not_isMin_succ [Nontrivial α] (a : α) : ¬ IsMin (succ a) := by
+ obtain ha | ha := (le_succ a).eq_or_lt
+ · exact (ha ▸ succ_eq_iff_isMax.1 ha.symm).not_isMin
+ · exact not_isMin_of_lt ha
+
theorem Iic_succ (a : α) : Iic (succ a) = insert (succ a) (Iic a) :=
ext fun _ => le_succ_iff_eq_or_le
@@ -802,6 +805,9 @@ theorem pred_le_iff_eq_or_le : pred a ≤ b ↔ b = pred a ∨ a ≤ b := by
theorem pred_lt_iff_eq_or_lt_of_not_isMin (ha : ¬IsMin a) : pred a < b ↔ a = b ∨ a < b :=
(pred_lt_iff_of_not_isMin ha).trans le_iff_eq_or_lt
+theorem not_isMax_pred [Nontrivial α] (a : α) : ¬ IsMax (pred a) :=
+ not_isMin_succ (α := αᵒᵈ) a
+
theorem Ici_pred (a : α) : Ici (pred a) = insert (pred a) (Ici a) :=
ext fun _ => pred_le_iff_eq_or_le
@@ -921,7 +927,7 @@ lemma gc_pred_succ : GaloisConnection (pred : α → α) succ := fun _ _ ↦ pre
end Preorder
-variable [PartialOrder α] [SuccOrder α] [PredOrder α] {a b : α}
+variable [PartialOrder α] [SuccOrder α] [PredOrder α] {a : α}
@[simp]
theorem succ_pred_of_not_isMin (h : ¬IsMin a) : succ (pred a) = a :=
@@ -1202,3 +1208,107 @@ instance [hα : Nonempty α] : IsEmpty (SuccOrder (WithBot α)) :=
end Succ
end WithBot
+
+section OrderIso
+
+variable {X Y : Type*} [Preorder X] [Preorder Y]
+
+-- See note [reducible non instances]
+/-- `SuccOrder` transfers across equivalences between orders. -/
+protected abbrev SuccOrder.ofOrderIso [SuccOrder X] (f : X ≃o Y) : SuccOrder Y where
+ succ y := f (succ (f.symm y))
+ le_succ y := by rw [← map_inv_le_iff f]; exact le_succ (f.symm y)
+ max_of_succ_le h := by
+ rw [← f.symm.isMax_apply]
+ refine max_of_succ_le ?_
+ simp [f.le_symm_apply, h]
+ succ_le_of_lt h := by rw [← le_map_inv_iff]; exact succ_le_of_lt (by simp [h])
+
+-- See note [reducible non instances]
+/-- `PredOrder` transfers across equivalences between orders. -/
+protected abbrev PredOrder.ofOrderIso [PredOrder X] (f : X ≃o Y) :
+ PredOrder Y where
+ pred y := f (pred (f.symm y))
+ pred_le y := by rw [← le_map_inv_iff f]; exact pred_le (f.symm y)
+ min_of_le_pred h := by
+ rw [← f.symm.isMin_apply]
+ refine min_of_le_pred ?_
+ simp [f.symm_apply_le, h]
+ 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/Limit.lean b/Mathlib/Order/SuccPred/Limit.lean
index b9d91e1646c68..45933dc60feb8 100644
--- a/Mathlib/Order/SuccPred/Limit.lean
+++ b/Mathlib/Order/SuccPred/Limit.lean
@@ -13,17 +13,18 @@ We define the predicate `Order.IsSuccPrelimit` for "successor pre-limits", value
any others. They are so named since they can't be the successors of anything smaller. We define
`Order.IsPredPrelimit` analogously, and prove basic results.
-## TODO
+For some applications, it is desirable to exclude minimal elements from being successor limits, or
+maximal elements from being predecessor limits. As such, we also provide `Order.IsSuccLimit` and
+`Order.IsPredLimit`, which exclude these cases.
-For some applications, it's desirable to exclude the case where an element is minimal. A future PR
-will introduce `IsSuccLimit` for this usage.
+## TODO
The plan is to eventually replace `Ordinal.IsLimit` and `Cardinal.IsLimit` with the common
predicate `Order.IsSuccLimit`.
-/
-variable {α : Type*}
+variable {α : Type*} {a b : α}
namespace Order
@@ -41,14 +42,10 @@ variable [LT α]
It's so named because in a successor order, a successor pre-limit can't be the successor of anything
smaller.
-For some applications, it's desirable to exclude the case where an element is minimal. A future PR
-will introduce `IsSuccLimit` for this usage. -/
+Use `IsSuccLimit` if you want to exclude the case of a minimal element. -/
def IsSuccPrelimit (a : α) : Prop :=
∀ b, ¬b ⋖ a
-@[deprecated IsSuccPrelimit (since := "2024-09-05")]
-alias IsSuccLimit := IsSuccPrelimit
-
theorem not_isSuccPrelimit_iff_exists_covBy (a : α) : ¬IsSuccPrelimit a ↔ ∃ b, b ⋖ a := by
simp [IsSuccPrelimit]
@@ -65,7 +62,36 @@ end LT
section Preorder
-variable [Preorder α] {a : α}
+variable [Preorder α]
+
+/-- A successor limit is a value that isn't minimal and doesn't cover any other.
+
+It's so named because in a successor order, a successor limit can't be the successor of anything
+smaller.
+
+This previously allowed the element to be minimal. This usage is now covered by `IsSuccPrelimit`. -/
+def IsSuccLimit (a : α) : Prop :=
+ ¬ IsMin a ∧ IsSuccPrelimit a
+
+protected theorem IsSuccLimit.not_isMin (h : IsSuccLimit a) : ¬ IsMin a := h.1
+protected theorem IsSuccLimit.isSuccPrelimit (h : IsSuccLimit a) : IsSuccPrelimit a := h.2
+
+theorem IsSuccPrelimit.isSuccLimit_of_not_isMin (h : IsSuccPrelimit a) (ha : ¬ IsMin a) :
+ IsSuccLimit a :=
+ ⟨ha, h⟩
+
+theorem IsSuccPrelimit.isSuccLimit [NoMinOrder α] (h : IsSuccPrelimit a) : IsSuccLimit a :=
+ h.isSuccLimit_of_not_isMin (not_isMin a)
+
+theorem isSuccPrelimit_iff_isSuccLimit_of_not_isMin (h : ¬ IsMin a) :
+ IsSuccPrelimit a ↔ IsSuccLimit a :=
+ ⟨fun ha ↦ ha.isSuccLimit_of_not_isMin h, IsSuccLimit.isSuccPrelimit⟩
+
+theorem isSuccPrelimit_iff_isSuccLimit [NoMinOrder α] : IsSuccPrelimit a ↔ IsSuccLimit a :=
+ isSuccPrelimit_iff_isSuccLimit_of_not_isMin (not_isMin a)
+
+protected theorem _root_.IsMin.not_isSuccLimit (h : IsMin a) : ¬ IsSuccLimit a :=
+ fun ha ↦ ha.not_isMin h
protected theorem _root_.IsMin.isSuccPrelimit : IsMin a → IsSuccPrelimit a := fun h _ hab =>
not_isMin_of_lt hab.lt h
@@ -74,26 +100,35 @@ protected theorem _root_.IsMin.isSuccPrelimit : IsMin a → IsSuccPrelimit a :=
alias _root_.IsMin.isSuccLimit := _root_.IsMin.isSuccPrelimit
theorem isSuccPrelimit_bot [OrderBot α] : IsSuccPrelimit (⊥ : α) :=
- IsMin.isSuccPrelimit isMin_bot
+ isMin_bot.isSuccPrelimit
+
+theorem not_isSuccLimit_bot [OrderBot α] : ¬ IsSuccLimit (⊥ : α) :=
+ isMin_bot.not_isSuccLimit
+
+theorem IsSuccLimit.ne_bot [OrderBot α] (h : IsSuccLimit a) : a ≠ ⊥ := by
+ rintro rfl
+ exact not_isSuccLimit_bot h
@[deprecated isSuccPrelimit_bot (since := "2024-09-05")]
alias isSuccLimit_bot := isSuccPrelimit_bot
+theorem not_isSuccLimit_iff : ¬ IsSuccLimit a ↔ IsMin a ∨ ¬ IsSuccPrelimit a := by
+ rw [IsSuccLimit, not_and_or, not_not]
+
variable [SuccOrder α]
protected theorem IsSuccPrelimit.isMax (h : IsSuccPrelimit (succ a)) : IsMax a := by
by_contra H
exact h a (covBy_succ_of_not_isMax H)
-@[deprecated IsSuccPrelimit.isMax (since := "2024-09-05")]
-alias IsSuccLimit.isMax := IsSuccPrelimit.isMax
+protected theorem IsSuccLimit.isMax (h : IsSuccLimit (succ a)) : IsMax a :=
+ h.isSuccPrelimit.isMax
-theorem not_isSuccPrelimit_succ_of_not_isMax (ha : ¬IsMax a) : ¬IsSuccPrelimit (succ a) := by
- contrapose! ha
- exact ha.isMax
+theorem not_isSuccPrelimit_succ_of_not_isMax (ha : ¬ IsMax a) : ¬ IsSuccPrelimit (succ a) :=
+ mt IsSuccPrelimit.isMax ha
-@[deprecated not_isSuccPrelimit_succ_of_not_isMax (since := "2024-09-05")]
-alias not_isSuccLimit_succ_of_not_isMax := not_isSuccPrelimit_succ_of_not_isMax
+theorem not_isSuccLimit_succ_of_not_isMax (ha : ¬ IsMax a) : ¬ IsSuccLimit (succ a) :=
+ mt IsSuccLimit.isMax ha
section NoMaxOrder
@@ -103,22 +138,22 @@ theorem IsSuccPrelimit.succ_ne (h : IsSuccPrelimit a) (b : α) : succ b ≠ a :=
rintro rfl
exact not_isMax _ h.isMax
-@[deprecated IsSuccPrelimit.succ_ne (since := "2024-09-05")]
-alias IsSuccLimit.succ_ne := IsSuccPrelimit.succ_ne
+theorem IsSuccLimit.succ_ne (h : IsSuccLimit a) (b : α) : succ b ≠ a :=
+ h.isSuccPrelimit.succ_ne b
@[simp]
theorem not_isSuccPrelimit_succ (a : α) : ¬IsSuccPrelimit (succ a) := fun h => h.succ_ne _ rfl
-@[deprecated not_isSuccPrelimit_succ (since := "2024-09-05")]
-alias not_isSuccLimit_succ := not_isSuccPrelimit_succ
+@[simp]
+theorem not_isSuccLimit_succ (a : α) : ¬IsSuccLimit (succ a) := fun h => h.succ_ne _ rfl
end NoMaxOrder
section IsSuccArchimedean
-variable [IsSuccArchimedean α]
+variable [IsSuccArchimedean α] [NoMaxOrder α]
-theorem IsSuccPrelimit.isMin_of_noMax [NoMaxOrder α] (h : IsSuccPrelimit a) : IsMin a := by
+theorem IsSuccPrelimit.isMin_of_noMax (h : IsSuccPrelimit a) : IsMin a := by
intro b hb
rcases hb.exists_succ_iterate with ⟨_ | n, rfl⟩
· exact le_rfl
@@ -129,16 +164,17 @@ theorem IsSuccPrelimit.isMin_of_noMax [NoMaxOrder α] (h : IsSuccPrelimit a) : I
alias IsSuccLimit.isMin_of_noMax := IsSuccPrelimit.isMin_of_noMax
@[simp]
-theorem isSuccPrelimit_iff_of_noMax [NoMaxOrder α] : IsSuccPrelimit a ↔ IsMin a :=
+theorem isSuccPrelimit_iff_of_noMax : IsSuccPrelimit a ↔ IsMin a :=
⟨IsSuccPrelimit.isMin_of_noMax, IsMin.isSuccPrelimit⟩
@[deprecated isSuccPrelimit_iff_of_noMax (since := "2024-09-05")]
alias isSuccLimit_iff_of_noMax := isSuccPrelimit_iff_of_noMax
-theorem not_isSuccPrelimit_of_noMax [NoMinOrder α] [NoMaxOrder α] : ¬IsSuccPrelimit a := by simp
+@[simp]
+theorem not_isSuccLimit_of_noMax : ¬ IsSuccLimit a :=
+ fun h ↦ h.not_isMin h.isSuccPrelimit.isMin_of_noMax
-@[deprecated not_isSuccPrelimit_of_noMax (since := "2024-09-05")]
-alias not_isSuccLimit_of_noMax := not_isSuccPrelimit_of_noMax
+theorem not_isSuccPrelimit_of_noMax [NoMinOrder α] : ¬ IsSuccPrelimit a := by simp
end IsSuccArchimedean
@@ -146,7 +182,12 @@ end Preorder
section PartialOrder
-variable [PartialOrder α] [SuccOrder α] {a b : α} {C : α → Sort*}
+variable [PartialOrder α]
+
+theorem isSuccLimit_iff [OrderBot α] : IsSuccLimit a ↔ a ≠ ⊥ ∧ IsSuccPrelimit a := by
+ rw [IsSuccLimit, isMin_iff_eq_bot]
+
+variable [SuccOrder α]
theorem isSuccPrelimit_of_succ_ne (h : ∀ b, succ b ≠ a) : IsSuccPrelimit a := fun b hba =>
h b (CovBy.succ_eq hba)
@@ -154,25 +195,23 @@ theorem isSuccPrelimit_of_succ_ne (h : ∀ b, succ b ≠ a) : IsSuccPrelimit a :
@[deprecated isSuccPrelimit_of_succ_ne (since := "2024-09-05")]
alias isSuccLimit_of_succ_ne := isSuccPrelimit_of_succ_ne
-theorem not_isSuccPrelimit_iff : ¬IsSuccPrelimit a ↔ ∃ b, ¬IsMax b ∧ succ b = a := by
+theorem not_isSuccPrelimit_iff : ¬ IsSuccPrelimit a ↔ ∃ b, ¬ IsMax b ∧ succ b = a := by
rw [not_isSuccPrelimit_iff_exists_covBy]
refine exists_congr fun b => ⟨fun hba => ⟨hba.lt.not_isMax, (CovBy.succ_eq hba)⟩, ?_⟩
rintro ⟨h, rfl⟩
exact covBy_succ_of_not_isMax h
-@[deprecated not_isSuccPrelimit_iff (since := "2024-09-05")]
-alias not_isSuccLimit_iff := not_isSuccPrelimit_iff
-
/-- See `not_isSuccPrelimit_iff` for a version that states that `a` is a successor of a value other
than itself. -/
-theorem mem_range_succ_of_not_isSuccPrelimit (h : ¬IsSuccPrelimit a) : a ∈ range (@succ α _ _) := by
- cases' not_isSuccPrelimit_iff.1 h with b hb
+theorem mem_range_succ_of_not_isSuccPrelimit (h : ¬ IsSuccPrelimit a) :
+ a ∈ range (succ : α → α) := by
+ obtain ⟨b, hb⟩ := not_isSuccPrelimit_iff.1 h
exact ⟨b, hb.2⟩
@[deprecated mem_range_succ_of_not_isSuccPrelimit (since := "2024-09-05")]
alias mem_range_succ_of_not_isSuccLimit := mem_range_succ_of_not_isSuccPrelimit
-theorem mem_range_succ_or_isSuccPrelimit (a) : a ∈ range (@succ α _ _) ∨ IsSuccPrelimit a :=
+theorem mem_range_succ_or_isSuccPrelimit (a) : a ∈ range (succ : α → α) ∨ IsSuccPrelimit a :=
or_iff_not_imp_right.2 <| mem_range_succ_of_not_isSuccPrelimit
@[deprecated mem_range_succ_or_isSuccPrelimit (since := "2024-09-05")]
@@ -192,14 +231,14 @@ theorem IsSuccPrelimit.succ_lt (hb : IsSuccPrelimit b) (ha : a < b) : succ a < b
subst hab
exact (h hb.isMax).elim
-@[deprecated IsSuccPrelimit.succ_lt (since := "2024-09-05")]
-alias IsSuccLimit.succ_lt := IsSuccPrelimit.succ_lt
+theorem IsSuccLimit.succ_lt (hb : IsSuccLimit b) (ha : a < b) : succ a < b :=
+ hb.isSuccPrelimit.succ_lt ha
theorem IsSuccPrelimit.succ_lt_iff (hb : IsSuccPrelimit b) : succ a < b ↔ a < b :=
⟨fun h => (le_succ a).trans_lt h, hb.succ_lt⟩
-@[deprecated IsSuccPrelimit.succ_lt_iff (since := "2024-09-05")]
-alias IsSuccLimit.succ_lt_iff := IsSuccPrelimit.succ_lt_iff
+theorem IsSuccLimit.succ_lt_iff (hb : IsSuccLimit b) : succ a < b ↔ a < b :=
+ hb.isSuccPrelimit.succ_lt_iff
theorem isSuccPrelimit_iff_succ_lt : IsSuccPrelimit b ↔ ∀ a < b, succ a < b :=
⟨fun hb _ => hb.succ_lt, isSuccPrelimit_of_succ_lt⟩
@@ -217,9 +256,8 @@ theorem isSuccPrelimit_iff_succ_ne : IsSuccPrelimit a ↔ ∀ b, succ b ≠ a :=
@[deprecated isSuccPrelimit_iff_succ_ne (since := "2024-09-05")]
alias isSuccLimit_iff_succ_ne := isSuccPrelimit_iff_succ_ne
-theorem not_isSuccPrelimit_iff' : ¬IsSuccPrelimit a ↔ a ∈ range (@succ α _ _) := by
- simp_rw [isSuccPrelimit_iff_succ_ne, not_forall, not_ne_iff]
- rfl
+theorem not_isSuccPrelimit_iff' : ¬ IsSuccPrelimit a ↔ a ∈ range (succ : α → α) := by
+ simp_rw [isSuccPrelimit_iff_succ_ne, not_forall, not_ne_iff, mem_range]
@[deprecated not_isSuccPrelimit_iff' (since := "2024-09-05")]
alias not_isSuccLimit_iff' := not_isSuccPrelimit_iff'
@@ -237,44 +275,51 @@ protected theorem IsSuccPrelimit.isMin (h : IsSuccPrelimit a) : IsMin a := fun b
rw [this] at hc ⊢
exact H hc
-@[deprecated IsSuccPrelimit.isMin (since := "2024-09-05")]
-alias IsSuccLimit.isMin := IsSuccPrelimit.isMin
-
@[simp]
theorem isSuccPrelimit_iff : IsSuccPrelimit a ↔ IsMin a :=
⟨IsSuccPrelimit.isMin, IsMin.isSuccPrelimit⟩
-@[deprecated isSuccPrelimit_iff (since := "2024-09-05")]
-alias isSuccLimit_iff := isSuccPrelimit_iff
-
-theorem not_isSuccPrelimit [NoMinOrder α] : ¬IsSuccPrelimit a := by simp
+@[simp]
+theorem not_isSuccLimit : ¬ IsSuccLimit a :=
+ fun h ↦ h.not_isMin <| h.isSuccPrelimit.isMin
-@[deprecated not_isSuccPrelimit (since := "2024-09-05")]
-alias not_isSuccLimit := not_isSuccPrelimit
+theorem not_isSuccPrelimit [NoMinOrder α] : ¬ IsSuccPrelimit a := by simp
end IsSuccArchimedean
end PartialOrder
+section LinearOrder
+
+variable [LinearOrder α]
+
+theorem IsSuccPrelimit.le_iff_forall_le (h : IsSuccPrelimit a) : a ≤ b ↔ ∀ c < a, c ≤ b := by
+ use fun ha c hc ↦ hc.le.trans ha
+ intro H
+ by_contra! ha
+ exact h b ⟨ha, fun c hb hc ↦ (H c hc).not_lt hb⟩
+
+theorem IsSuccPrelimit.lt_iff_exists_lt (h : IsSuccPrelimit b) : a < b ↔ ∃ c < b, a < c := by
+ rw [← not_iff_not]
+ simp [h.le_iff_forall_le]
+
+end LinearOrder
+
/-! ### Predecessor limits -/
section LT
-variable [LT α] {a : α}
+variable [LT α]
-/-- A successor pre-limit is a value that isn't covered by any other.
+/-- A predecessor pre-limit is a value that isn't covered by any other.
-It's so named because in a predecessor order, a predecessor limit can't be the predecessor of
-anything greater.
+It's so named because in a predecessor order, a predecessor pre-limit can't be the predecessor of
+anything smaller.
-For some applications, it's desirable to exclude the case where an element is maximal. A future PR
-will introduce `IsPredLimit` for this usage. -/
+Use `IsPredLimit` to exclude the case of a maximal element. -/
def IsPredPrelimit (a : α) : Prop :=
- ∀ b, ¬a ⋖ b
-
-@[deprecated IsPredPrelimit (since := "2024-09-05")]
-alias IsPredLimit := IsPredPrelimit
+ ∀ b, ¬ a ⋖ b
theorem not_isPredPrelimit_iff_exists_covBy (a : α) : ¬IsPredPrelimit a ↔ ∃ b, a ⋖ b := by
simp [IsPredPrelimit]
@@ -291,16 +336,10 @@ alias isPredLimit_of_dense := isPredPrelimit_of_dense
theorem isSuccPrelimit_toDual_iff : IsSuccPrelimit (toDual a) ↔ IsPredPrelimit a := by
simp [IsSuccPrelimit, IsPredPrelimit]
-@[deprecated isSuccPrelimit_toDual_iff (since := "2024-09-05")]
-alias isSuccLimit_toDual_iff := isSuccPrelimit_toDual_iff
-
@[simp]
theorem isPredPrelimit_toDual_iff : IsPredPrelimit (toDual a) ↔ IsSuccPrelimit a := by
simp [IsSuccPrelimit, IsPredPrelimit]
-@[deprecated isPredPrelimit_toDual_iff (since := "2024-09-05")]
-alias isPredLimit_toDual_iff := isPredPrelimit_toDual_iff
-
alias ⟨_, IsPredPrelimit.dual⟩ := isSuccPrelimit_toDual_iff
alias ⟨_, IsSuccPrelimit.dual⟩ := isPredPrelimit_toDual_iff
@[deprecated IsPredPrelimit.dual (since := "2024-09-05")]
@@ -312,7 +351,47 @@ end LT
section Preorder
-variable [Preorder α] {a : α}
+variable [Preorder α]
+
+/-- A predecessor limit is a value that isn't maximal and doesn't cover any other.
+
+It's so named because in a predecessor order, a predecessor limit can't be the predecessor of
+anything larger.
+
+This previously allowed the element to be maximal. This usage is now covered by `IsPredPreLimit`. -/
+def IsPredLimit (a : α) : Prop :=
+ ¬ IsMax a ∧ IsPredPrelimit a
+
+protected theorem IsPredLimit.not_isMax (h : IsPredLimit a) : ¬ IsMax a := h.1
+protected theorem IsPredLimit.isPredPrelimit (h : IsPredLimit a) : IsPredPrelimit a := h.2
+
+@[simp]
+theorem isSuccLimit_toDual_iff : IsSuccLimit (toDual a) ↔ IsPredLimit a := by
+ simp [IsSuccLimit, IsPredLimit]
+
+@[simp]
+theorem isPredLimit_toDual_iff : IsPredLimit (toDual a) ↔ IsSuccLimit a := by
+ simp [IsSuccLimit, IsPredLimit]
+
+alias ⟨_, IsPredLimit.dual⟩ := isSuccLimit_toDual_iff
+alias ⟨_, IsSuccLimit.dual⟩ := isPredLimit_toDual_iff
+
+theorem IsPredPrelimit.isPredLimit_of_not_isMax (h : IsPredPrelimit a) (ha : ¬ IsMax a) :
+ IsPredLimit a :=
+ ⟨ha, h⟩
+
+theorem IsPredPrelimit.isPredLimit [NoMaxOrder α] (h : IsPredPrelimit a) : IsPredLimit a :=
+ h.isPredLimit_of_not_isMax (not_isMax a)
+
+theorem isPredPrelimit_iff_isPredLimit_of_not_isMax (h : ¬ IsMax a) :
+ IsPredPrelimit a ↔ IsPredLimit a :=
+ ⟨fun ha ↦ ha.isPredLimit_of_not_isMax h, IsPredLimit.isPredPrelimit⟩
+
+theorem isPredPrelimit_iff_isPredLimit [NoMaxOrder α] : IsPredPrelimit a ↔ IsPredLimit a :=
+ isPredPrelimit_iff_isPredLimit_of_not_isMax (not_isMax a)
+
+protected theorem _root_.IsMax.not_isPredLimit (h : IsMax a) : ¬ IsPredLimit a :=
+ fun ha ↦ ha.not_isMax h
protected theorem _root_.IsMax.isPredPrelimit : IsMax a → IsPredPrelimit a := fun h _ hab =>
not_isMax_of_lt hab.lt h
@@ -321,67 +400,77 @@ protected theorem _root_.IsMax.isPredPrelimit : IsMax a → IsPredPrelimit a :=
alias _root_.IsMax.isPredLimit := _root_.IsMax.isPredPrelimit
theorem isPredPrelimit_top [OrderTop α] : IsPredPrelimit (⊤ : α) :=
- IsMax.isPredPrelimit isMax_top
+ isMax_top.isPredPrelimit
@[deprecated isPredPrelimit_top (since := "2024-09-05")]
alias isPredLimit_top := isPredPrelimit_top
+theorem not_isPredLimit_top [OrderTop α] : ¬ IsPredLimit (⊤ : α) :=
+ isMax_top.not_isPredLimit
+
+theorem IsPredLimit.ne_top [OrderTop α] (h : IsPredLimit a) : a ≠ ⊤ :=
+ h.dual.ne_bot
+
+theorem not_isPredLimit_iff : ¬ IsPredLimit a ↔ IsMax a ∨ ¬ IsPredPrelimit a := by
+ rw [IsPredLimit, not_and_or, not_not]
+
+theorem not_isPredLimit_of_not_isPredPrelimit (h : ¬ IsPredPrelimit a) : ¬ IsPredLimit a :=
+ not_isPredLimit_iff.2 (Or.inr h)
+
variable [PredOrder α]
-protected theorem IsPredPrelimit.isMin (h : IsPredPrelimit (pred a)) : IsMin a := by
- by_contra H
- exact h a (pred_covBy_of_not_isMin H)
+protected theorem IsPredPrelimit.isMin (h : IsPredPrelimit (pred a)) : IsMin a :=
+ h.dual.isMax
-@[deprecated IsPredPrelimit.isMin (since := "2024-09-05")]
-alias IsPredLimit.isMin := IsPredPrelimit.isMin
+protected theorem IsPredLimit.isMin (h : IsPredLimit (pred a)) : IsMin a :=
+ h.dual.isMax
-theorem not_isPredPrelimit_pred_of_not_isMin (ha : ¬IsMin a) : ¬IsPredPrelimit (pred a) := by
- contrapose! ha
- exact ha.isMin
+theorem not_isPredPrelimit_pred_of_not_isMin (ha : ¬ IsMin a) : ¬ IsPredPrelimit (pred a) :=
+ mt IsPredPrelimit.isMin ha
-@[deprecated not_isPredPrelimit_pred_of_not_isMin (since := "2024-09-05")]
-alias not_isPredLimit_pred_of_not_isMin := not_isPredPrelimit_pred_of_not_isMin
+theorem not_isPredLimit_pred_of_not_isMin (ha : ¬ IsMin a) : ¬ IsPredLimit (pred a) :=
+ mt IsPredLimit.isMin ha
section NoMinOrder
variable [NoMinOrder α]
-theorem IsPredPrelimit.pred_ne (h : IsPredPrelimit a) (b : α) : pred b ≠ a := by
- rintro rfl
- exact not_isMin _ h.isMin
+theorem IsPredPrelimit.pred_ne (h : IsPredPrelimit a) (b : α) : pred b ≠ a :=
+ h.dual.succ_ne b
-@[deprecated IsPredPrelimit.pred_ne (since := "2024-09-05")]
-alias IsPredLimit.pred_ne := IsPredPrelimit.pred_ne
+theorem IsPredLimit.pred_ne (h : IsPredLimit a) (b : α) : pred b ≠ a :=
+ h.isPredPrelimit.pred_ne b
@[simp]
-theorem not_isPredPrelimit_pred (a : α) : ¬IsPredPrelimit (pred a) := fun h => h.pred_ne _ rfl
+theorem not_isPredPrelimit_pred (a : α) : ¬ IsPredPrelimit (pred a) := fun h => h.pred_ne _ rfl
-@[deprecated not_isPredPrelimit_pred (since := "2024-09-05")]
-alias not_isPredLimit_pred := not_isPredPrelimit_pred
+@[simp]
+theorem not_isPredLimit_pred (a : α) : ¬ IsPredLimit (pred a) := fun h => h.pred_ne _ rfl
end NoMinOrder
section IsPredArchimedean
-variable [IsPredArchimedean α]
+variable [IsPredArchimedean α] [NoMinOrder α]
-protected theorem IsPredPrelimit.isMax_of_noMin [NoMinOrder α] (h : IsPredPrelimit a) : IsMax a :=
+theorem IsPredPrelimit.isMax_of_noMin (h : IsPredPrelimit a) : IsMax a :=
h.dual.isMin_of_noMax
@[deprecated IsPredPrelimit.isMax_of_noMin (since := "2024-09-05")]
alias IsPredLimit.isMax_of_noMin := IsPredPrelimit.isMax_of_noMin
@[simp]
-theorem isPredPrelimit_iff_of_noMin [NoMinOrder α] : IsPredPrelimit a ↔ IsMax a :=
- isSuccPrelimit_toDual_iff.symm.trans isSuccPrelimit_iff_of_noMax
+theorem isPredPrelimit_iff_of_noMin : IsPredPrelimit a ↔ IsMax a :=
+ ⟨IsPredPrelimit.isMax_of_noMin, IsMax.isPredPrelimit⟩
@[deprecated isPredPrelimit_iff_of_noMin (since := "2024-09-05")]
alias isPredLimit_iff_of_noMin := isPredPrelimit_iff_of_noMin
-theorem not_isPredPrelimit_of_noMin [NoMinOrder α] [NoMaxOrder α] : ¬IsPredPrelimit a := by simp
+theorem not_isPredPrelimit_of_noMin [NoMaxOrder α] : ¬ IsPredPrelimit a := by simp
-@[deprecated not_isPredPrelimit_of_noMin (since := "2024-09-05")]
-alias not_isPredLimit_of_noMin := not_isPredPrelimit_of_noMin
+@[simp]
+theorem not_isPredLimit_of_noMin : ¬ IsPredLimit a :=
+ fun h ↦ h.not_isMax h.isPredPrelimit.isMax_of_noMin
end IsPredArchimedean
@@ -389,7 +478,12 @@ end Preorder
section PartialOrder
-variable [PartialOrder α] [PredOrder α] {a b : α} {C : α → Sort*}
+variable [PartialOrder α]
+
+theorem isPredLimit_iff [OrderTop α] : IsPredLimit a ↔ a ≠ ⊤ ∧ IsPredPrelimit a := by
+ rw [IsPredLimit, isMax_iff_eq_top]
+
+variable [PredOrder α]
theorem isPredPrelimit_of_pred_ne (h : ∀ b, pred b ≠ a) : IsPredPrelimit a := fun b hba =>
h b (CovBy.pred_eq hba)
@@ -397,48 +491,46 @@ theorem isPredPrelimit_of_pred_ne (h : ∀ b, pred b ≠ a) : IsPredPrelimit a :
@[deprecated isPredPrelimit_of_pred_ne (since := "2024-09-05")]
alias isPredLimit_of_pred_ne := isPredPrelimit_of_pred_ne
-theorem not_isPredPrelimit_iff : ¬IsPredPrelimit a ↔ ∃ b, ¬IsMin b ∧ pred b = a := by
+theorem not_isPredPrelimit_iff : ¬ IsPredPrelimit a ↔ ∃ b, ¬ IsMin b ∧ pred b = a := by
rw [← isSuccPrelimit_toDual_iff]
exact not_isSuccPrelimit_iff
-@[deprecated not_isPredPrelimit_iff (since := "2024-09-05")]
-alias not_isPredLimit_iff := not_isPredPrelimit_iff
-
/-- See `not_isPredPrelimit_iff` for a version that states that `a` is a successor of a value other
than itself. -/
-theorem mem_range_pred_of_not_isPredPrelimit (h : ¬IsPredPrelimit a) : a ∈ range (@pred α _ _) := by
- cases' not_isPredPrelimit_iff.1 h with b hb
+theorem mem_range_pred_of_not_isPredPrelimit (h : ¬ IsPredPrelimit a) :
+ a ∈ range (pred : α → α) := by
+ obtain ⟨b, hb⟩ := not_isPredPrelimit_iff.1 h
exact ⟨b, hb.2⟩
@[deprecated mem_range_pred_of_not_isPredPrelimit (since := "2024-09-05")]
alias mem_range_pred_of_not_isPredLimit := mem_range_pred_of_not_isPredPrelimit
-theorem mem_range_pred_or_isPredPrelimit (a) : a ∈ range (@pred α _ _) ∨ IsPredPrelimit a :=
+theorem mem_range_pred_or_isPredPrelimit (a) : a ∈ range (pred : α → α) ∨ IsPredPrelimit a :=
or_iff_not_imp_right.2 <| mem_range_pred_of_not_isPredPrelimit
@[deprecated mem_range_pred_or_isPredPrelimit (since := "2024-09-05")]
alias mem_range_pred_or_isPredLimit := mem_range_pred_or_isPredPrelimit
-theorem isPredPrelimit_of_pred_lt (H : ∀ a > b, pred a < b) : IsPredPrelimit b := fun a hab =>
- (H a hab.lt).ne (CovBy.pred_eq hab)
+theorem isPredPrelimit_of_pred_lt (H : ∀ b > a, a < pred b) : IsPredPrelimit a := fun a hab =>
+ (H a hab.lt).ne (CovBy.pred_eq hab).symm
@[deprecated isPredPrelimit_of_pred_lt (since := "2024-09-05")]
alias isPredLimit_of_pred_lt := isPredPrelimit_of_pred_lt
-theorem IsPredPrelimit.lt_pred (h : IsPredPrelimit a) : a < b → a < pred b :=
- h.dual.succ_lt
+theorem IsPredPrelimit.lt_pred (ha : IsPredPrelimit a) (hb : a < b) : a < pred b :=
+ ha.dual.succ_lt hb
-@[deprecated IsPredPrelimit.lt_pred (since := "2024-09-05")]
-alias IsPredLimit.lt_pred := IsPredPrelimit.lt_pred
+theorem IsPredLimit.lt_pred (ha : IsPredLimit a) (hb : a < b) : a < pred b :=
+ ha.isPredPrelimit.lt_pred hb
-theorem IsPredPrelimit.lt_pred_iff (h : IsPredPrelimit a) : a < pred b ↔ a < b :=
- h.dual.succ_lt_iff
+theorem IsPredPrelimit.lt_pred_iff (ha : IsPredPrelimit a) : a < pred b ↔ a < b :=
+ ha.dual.succ_lt_iff
-@[deprecated IsPredPrelimit.lt_pred_iff (since := "2024-09-05")]
-alias IsPredLimit.lt_pred_iff := IsPredPrelimit.lt_pred_iff
+theorem IsPredLimit.lt_pred_iff (ha : IsPredLimit a) : a < pred b ↔ a < b :=
+ ha.dual.succ_lt_iff
-theorem isPredPrelimit_iff_lt_pred : IsPredPrelimit a ↔ ∀ ⦃b⦄, a < b → a < pred b :=
- isSuccPrelimit_toDual_iff.symm.trans isSuccPrelimit_iff_succ_lt
+theorem isPredPrelimit_iff_lt_pred : IsPredPrelimit a ↔ ∀ b > a, a < pred b :=
+ ⟨fun hb _ => hb.lt_pred, isPredPrelimit_of_pred_lt⟩
@[deprecated isPredPrelimit_iff_lt_pred (since := "2024-09-05")]
alias isPredLimit_iff_lt_pred := isPredPrelimit_iff_lt_pred
@@ -447,6 +539,12 @@ section NoMinOrder
variable [NoMinOrder α]
+theorem isPredPrelimit_iff_pred_ne : IsPredPrelimit a ↔ ∀ b, pred b ≠ a :=
+ ⟨IsPredPrelimit.pred_ne, isPredPrelimit_of_pred_ne⟩
+
+theorem not_isPredPrelimit_iff' : ¬ IsPredPrelimit a ↔ a ∈ range (pred : α → α) := by
+ simp_rw [isPredPrelimit_iff_pred_ne, not_forall, not_ne_iff, mem_range]
+
end NoMinOrder
section IsPredArchimedean
@@ -461,80 +559,88 @@ alias IsPredLimit.isMax := IsPredPrelimit.isMax
@[simp]
theorem isPredPrelimit_iff : IsPredPrelimit a ↔ IsMax a :=
- isSuccPrelimit_toDual_iff.symm.trans isSuccPrelimit_iff
+ ⟨IsPredPrelimit.isMax, IsMax.isPredPrelimit⟩
-@[deprecated isPredPrelimit_iff (since := "2024-09-05")]
-alias isPredLimit_iff := isPredPrelimit_iff
-
-theorem not_isPredPrelimit [NoMaxOrder α] : ¬IsPredPrelimit a := by simp
+@[simp]
+theorem not_isPredLimit : ¬ IsPredLimit a :=
+ fun h ↦ h.not_isMax <| h.isPredPrelimit.isMax
-@[deprecated not_isPredPrelimit (since := "2024-09-05")]
-alias not_isPredLimit := not_isPredPrelimit
+theorem not_isPredPrelimit [NoMaxOrder α] : ¬ IsPredPrelimit a := by simp
end IsPredArchimedean
end PartialOrder
+section LinearOrder
+
+variable [LinearOrder α]
+
+theorem IsPredPrelimit.le_iff_forall_le (h : IsPredPrelimit a) : b ≤ a ↔ ∀ ⦃c⦄, a < c → b ≤ c :=
+ h.dual.le_iff_forall_le
+
+theorem IsPredPrelimit.lt_iff_exists_lt (h : IsPredPrelimit b) : b < a ↔ ∃ c, b < c ∧ c < a :=
+ h.dual.lt_iff_exists_lt
+
+end LinearOrder
+
+end Order
+
/-! ### Induction principles -/
-variable {C : α → Sort*} {b : α}
+variable {C : α → Sort*}
+
+namespace Order
section isSuccPrelimitRecOn
section PartialOrder
variable [PartialOrder α] [SuccOrder α]
+ (hs : ∀ a, ¬ IsMax a → C (succ a)) (hl : ∀ a, IsSuccPrelimit a → C a)
-/-- A value can be built by building it on successors and successor limits. -/
+variable (b) in
+open Classical in
+/-- A value can be built by building it on successors and successor pre-limits. -/
@[elab_as_elim]
-noncomputable def isSuccPrelimitRecOn (b : α) (hs : ∀ a, ¬ IsMax a → C (succ a))
- (hl : ∀ a, IsSuccPrelimit a → C a) : C b := by
- by_cases hb : IsSuccPrelimit b
- · exact hl b hb
- · have H := Classical.choose_spec (not_isSuccPrelimit_iff.1 hb)
- rw [← H.2]
- exact hs _ H.1
-
-@[deprecated isSuccPrelimitRecOn (since := "2024-09-05")]
-alias isSuccLimitRecOn := isSuccPrelimitRecOn
-
-theorem isSuccPrelimitRecOn_limit (hs : ∀ a, ¬ IsMax a → C (succ a))
- (hl : ∀ a, IsSuccPrelimit a → C a) (hb : IsSuccPrelimit b) :
+noncomputable def isSuccPrelimitRecOn : C b :=
+ if hb : IsSuccPrelimit b then hl b hb else
+ haveI H := Classical.choose_spec (not_isSuccPrelimit_iff.1 hb)
+ cast (congr_arg C H.2) (hs _ H.1)
+
+theorem isSuccPrelimitRecOn_of_isSuccPrelimit (hb : IsSuccPrelimit b) :
isSuccPrelimitRecOn b hs hl = hl b hb :=
dif_pos hb
-@[deprecated isSuccPrelimitRecOn_limit (since := "2024-09-05")]
-alias isSuccLimitRecOn_limit := isSuccPrelimitRecOn_limit
+@[deprecated isSuccPrelimitRecOn_of_isSuccPrelimit (since := "2024-09-05")]
+alias isSuccLimitRecOn_limit := isSuccPrelimitRecOn_of_isSuccPrelimit
+@[deprecated isSuccPrelimitRecOn_of_isSuccPrelimit (since := "2024-09-14")]
+alias isSuccPrelimitRecOn_limit := isSuccPrelimitRecOn_of_isSuccPrelimit
end PartialOrder
section LinearOrder
variable [LinearOrder α] [SuccOrder α]
+ (hs : ∀ a, ¬ IsMax a → C (succ a)) (hl : ∀ a, IsSuccPrelimit a → C a)
-theorem isSuccPrelimitRecOn_succ' (hs : ∀ a, ¬ IsMax a → C (succ a))
- (hl : ∀ a, IsSuccPrelimit a → C a) (hb : ¬ IsMax b) :
+theorem isSuccPrelimitRecOn_succ_of_not_isMax (hb : ¬ IsMax b) :
isSuccPrelimitRecOn (succ b) hs hl = hs b hb := by
have hb' := not_isSuccPrelimit_succ_of_not_isMax hb
have H := Classical.choose_spec (not_isSuccPrelimit_iff.1 hb')
- rw [isSuccPrelimitRecOn]
- simp only [cast_eq_iff_heq, hb', not_false_iff, eq_mpr_eq_cast, dif_neg]
- congr 1 <;> first |
- exact (succ_eq_succ_iff_of_not_isMax H.left hb).mp H.right |
- exact proof_irrel_heq H.left hb
+ rw [isSuccPrelimitRecOn, dif_neg hb', cast_eq_iff_heq]
+ congr
+ exacts [(succ_eq_succ_iff_of_not_isMax H.1 hb).1 H.2, proof_irrel_heq _ _]
-@[deprecated isSuccPrelimitRecOn_succ' (since := "2024-09-05")]
-alias isSuccLimitRecOn_succ' := isSuccPrelimitRecOn_succ'
+@[deprecated isSuccPrelimitRecOn_succ_of_not_isMax (since := "2024-09-05")]
+alias isSuccLimitRecOn_succ' := isSuccPrelimitRecOn_succ_of_not_isMax
+@[deprecated isSuccPrelimitRecOn_succ_of_not_isMax (since := "2024-09-14")]
+alias isSuccPrelimitRecOn_succ' := isSuccPrelimitRecOn_succ_of_not_isMax
@[simp]
-theorem isSuccPrelimitRecOn_succ [NoMaxOrder α] (hs : ∀ a, ¬ IsMax a → C (succ a))
- (hl : ∀ a, IsSuccPrelimit a → C a) (b : α) :
- @isSuccPrelimitRecOn α C _ _ (succ b) hs hl = hs b (not_isMax b) :=
- isSuccPrelimitRecOn_succ' _ _ _
-
-@[deprecated isSuccPrelimitRecOn_succ (since := "2024-09-05")]
-alias isSuccLimitRecOn_succ := isSuccPrelimitRecOn_succ
+theorem isSuccPrelimitRecOn_succ [NoMaxOrder α] (b : α) :
+ isSuccPrelimitRecOn (succ b) hs hl = hs b (not_isMax b) :=
+ isSuccPrelimitRecOn_succ_of_not_isMax _ _ _
end LinearOrder
@@ -545,23 +651,22 @@ section isPredPrelimitRecOn
section PartialOrder
variable [PartialOrder α] [PredOrder α]
+ (hs : ∀ a, ¬ IsMin a → C (pred a)) (hl : ∀ a, IsPredPrelimit a → C a)
-/-- A value can be built by building it on predecessors and predecessor limits. -/
+variable (b) in
+/-- A value can be built by building it on predecessors and predecessor pre-limits. -/
@[elab_as_elim]
-noncomputable def isPredPrelimitRecOn (b : α) (hs : ∀ a, ¬ IsMin a → C (pred a))
- (hl : ∀ a, IsPredPrelimit a → C a) : C b :=
- @isSuccPrelimitRecOn αᵒᵈ _ _ _ _ hs fun _ ha => hl _ ha.dual
-
-@[deprecated isPredPrelimitRecOn (since := "2024-09-05")]
-alias isPredLimitRecOn := isPredPrelimitRecOn
+noncomputable def isPredPrelimitRecOn : C b :=
+ isSuccPrelimitRecOn (α := αᵒᵈ) b hs (fun a ha ↦ hl a ha.dual)
-theorem isPredPrelimitRecOn_limit (hs : ∀ a, ¬ IsMin a → C (pred a))
- (hl : ∀ a, IsPredPrelimit a → C a) (hb : IsPredPrelimit b) :
+theorem isPredPrelimitRecOn_of_isPredPrelimit (hb : IsPredPrelimit b) :
isPredPrelimitRecOn b hs hl = hl b hb :=
- isSuccPrelimitRecOn_limit _ _ hb.dual
+ isSuccPrelimitRecOn_of_isSuccPrelimit _ _ hb.dual
-@[deprecated isPredPrelimitRecOn_limit (since := "2024-09-05")]
-alias isPredLimitRecOn_limit := isPredPrelimitRecOn_limit
+@[deprecated isPredPrelimitRecOn_of_isPredPrelimit (since := "2024-09-05")]
+alias isPredLimitRecOn_limit := isPredPrelimitRecOn_of_isPredPrelimit
+@[deprecated isPredPrelimitRecOn_of_isPredPrelimit (since := "2024-09-14")]
+alias isPredPrelimitRecOn_limit := isPredPrelimitRecOn_of_isPredPrelimit
end PartialOrder
@@ -570,31 +675,114 @@ section LinearOrder
variable [LinearOrder α] [PredOrder α]
(hs : ∀ a, ¬ IsMin a → C (pred a)) (hl : ∀ a, IsPredPrelimit a → C a)
-theorem isPredPrelimitRecOn_pred' {b : α} (hb : ¬ IsMin b) :
- @isPredPrelimitRecOn α C _ _ (pred b) hs hl = hs b hb :=
- isSuccPrelimitRecOn_succ' _ _ _
+theorem isPredPrelimitRecOn_pred_of_not_isMin (hb : ¬ IsMin b) :
+ isPredPrelimitRecOn (pred b) hs hl = hs b hb :=
+ isSuccPrelimitRecOn_succ_of_not_isMax (α := αᵒᵈ) _ _ _
-@[deprecated isPredPrelimitRecOn_pred' (since := "2024-09-05")]
-alias isPredLimitRecOn_pred' := isPredPrelimitRecOn_pred'
+@[deprecated isPredPrelimitRecOn_pred_of_not_isMin (since := "2024-09-05")]
+alias isPredLimitRecOn_pred' := isPredPrelimitRecOn_pred_of_not_isMin
+@[deprecated isPredPrelimitRecOn_pred_of_not_isMin (since := "2024-09-14")]
+alias isPredPrelimitRecOn_pred' := isPredPrelimitRecOn_pred_of_not_isMin
@[simp]
theorem isPredPrelimitRecOn_pred [NoMinOrder α] (b : α) :
- @isPredPrelimitRecOn α C _ _ (pred b) hs hl = hs b (not_isMin b) :=
- isSuccPrelimitRecOn_succ _ _ _
-
-@[deprecated isPredPrelimitRecOn_pred (since := "2024-09-05")]
-alias isPredLimitRecOn_pred := isPredPrelimitRecOn_pred
+ isPredPrelimitRecOn (pred b) hs hl = hs b (not_isMin b) :=
+ isPredPrelimitRecOn_pred_of_not_isMin _ _ _
end LinearOrder
end isPredPrelimitRecOn
+section isSuccLimitRecOn
+
+section PartialOrder
+
+variable [PartialOrder α] [SuccOrder α]
+ (hm : ∀ a, IsMin a → C a) (hs : ∀ a, ¬ IsMax a → C (succ a)) (hl : ∀ a, IsSuccLimit a → C a)
+
+variable (b) in
+open Classical in
+/-- A value can be built by building it on minimal elements, successors, and successor limits. -/
+@[elab_as_elim]
+noncomputable def isSuccLimitRecOn : C b :=
+ isSuccPrelimitRecOn b hs fun a ha ↦
+ if h : IsMin a then hm a h else hl a (ha.isSuccLimit_of_not_isMin h)
+
+@[simp]
+theorem isSuccLimitRecOn_of_isSuccLimit (hb : IsSuccLimit b) :
+ isSuccLimitRecOn b hm hs hl = hl b hb := by
+ rw [isSuccLimitRecOn, isSuccPrelimitRecOn_of_isSuccPrelimit _ _ hb.isSuccPrelimit,
+ dif_neg hb.not_isMin]
+
+end PartialOrder
+
+section LinearOrder
+
+variable [LinearOrder α] [SuccOrder α]
+ (hm : ∀ a, IsMin a → C a) (hs : ∀ a, ¬ IsMax a → C (succ a)) (hl : ∀ a, IsSuccLimit a → C a)
+
+theorem isSuccLimitRecOn_succ_of_not_isMax (hb : ¬ IsMax b) :
+ isSuccLimitRecOn (succ b) hm hs hl = hs b hb := by
+ rw [isSuccLimitRecOn, isSuccPrelimitRecOn_succ_of_not_isMax]
+
+@[simp]
+theorem isSuccLimitRecOn_succ [NoMaxOrder α] (b : α) :
+ isSuccLimitRecOn (succ b) hm hs hl = hs b (not_isMax b) :=
+ isSuccLimitRecOn_succ_of_not_isMax hm hs hl _
+
+theorem isSuccLimitRecOn_of_isMin (hb : IsMin b) : isSuccLimitRecOn b hm hs hl = hm b hb := by
+ rw [isSuccLimitRecOn, isSuccPrelimitRecOn_of_isSuccPrelimit _ _ hb.isSuccPrelimit, dif_pos hb]
+
+end LinearOrder
+
+end isSuccLimitRecOn
+
+section isPredLimitRecOn
+
+section PartialOrder
+
+variable [PartialOrder α] [PredOrder α]
+ (hm : ∀ a, IsMax a → C a) (hs : ∀ a, ¬ IsMin a → C (pred a)) (hl : ∀ a, IsPredLimit a → C a)
+
+variable (b) in
+/-- A value can be built by building it on maximal elements, predecessors,
+and predecessor limits. -/
+@[elab_as_elim]
+noncomputable def isPredLimitRecOn : C b :=
+ isSuccLimitRecOn (α := αᵒᵈ) b hm hs (fun a ha => hl a ha.dual)
+
+@[simp]
+theorem isPredLimitRecOn_of_isPredLimit (hb : IsPredLimit b) :
+ isPredLimitRecOn b hm hs hl = hl b hb :=
+ isSuccLimitRecOn_of_isSuccLimit (α := αᵒᵈ) hm hs _ hb.dual
+
+end PartialOrder
+
+section LinearOrder
+
+variable [LinearOrder α] [PredOrder α]
+ (hm : ∀ a, IsMax a → C a) (hs : ∀ a, ¬ IsMin a → C (pred a)) (hl : ∀ a, IsPredLimit a → C a)
+
+theorem isPredLimitRecOn_pred_of_not_isMin (hb : ¬ IsMin b) :
+ isPredLimitRecOn (pred b) hm hs hl = hs b hb :=
+ isSuccLimitRecOn_succ_of_not_isMax (α := αᵒᵈ) hm hs _ hb
+
+@[simp]
+theorem isPredLimitRecOn_pred [NoMinOrder α] :
+ isPredLimitRecOn (pred b) hm hs hl = hs b (not_isMin b) :=
+ isSuccLimitRecOn_succ (α := αᵒᵈ) hm hs _ b
+
+theorem isPredLimitRecOn_of_isMax (hb : IsMax b) : isPredLimitRecOn b hm hs hl = hm b hb :=
+ isSuccLimitRecOn_of_isMin (α := αᵒᵈ) hm hs _ hb
+
+end LinearOrder
+
+end isPredLimitRecOn
+
end Order
open Order
-variable {C : α → Sort*} {b : α}
-
namespace SuccOrder
section prelimitRecOn
@@ -602,29 +790,27 @@ section prelimitRecOn
section PartialOrder
variable [PartialOrder α] [SuccOrder α] [WellFoundedLT α]
+ (hs : ∀ a, ¬ IsMax a → C a → C (Order.succ a)) (hl : ∀ a, IsSuccPrelimit a → (∀ b < a, C b) → C a)
-open scoped Classical in
+variable (b) in
+open Classical in
/-- Recursion principle on a well-founded partial `SuccOrder`. -/
-@[elab_as_elim] noncomputable def prelimitRecOn (b : α)
- (hs : ∀ a, ¬ IsMax a → C a → C (Order.succ a))
- (hl : ∀ a, IsSuccPrelimit a → (∀ b < a, C b) → C a) : C b :=
+@[elab_as_elim] noncomputable def prelimitRecOn : C b :=
wellFounded_lt.fix
(fun a IH ↦ if h : IsSuccPrelimit a then hl a h IH else
- let x := Classical.indefiniteDescription _ (not_isSuccPrelimit_iff.mp h)
- x.2.2 ▸ hs x x.2.1 (IH x <| x.2.2.subst <| lt_succ_of_not_isMax x.2.1))
+ haveI H := Classical.choose_spec (not_isSuccPrelimit_iff.1 h)
+ cast (congr_arg C H.2) (hs _ H.1 <| IH _ <| H.2.subst <| lt_succ_of_not_isMax H.1))
b
-@[deprecated prelimitRecOn (since := "2024-09-05")]
-alias limitRecOn := prelimitRecOn
-
@[simp]
-theorem prelimitRecOn_limit (hs : ∀ a, ¬ IsMax a → C a → C (Order.succ a))
- (hl : ∀ a, IsSuccPrelimit a → (∀ b < a, C b) → C a) (hb : IsSuccPrelimit b) :
- prelimitRecOn b hs hl = hl b hb fun x _ ↦ prelimitRecOn x hs hl := by
+theorem prelimitRecOn_of_isSuccPrelimit (hb : IsSuccPrelimit b) :
+ prelimitRecOn b hs hl = hl b hb fun x _ ↦ SuccOrder.prelimitRecOn x hs hl := by
rw [prelimitRecOn, WellFounded.fix_eq, dif_pos hb]; rfl
-@[deprecated prelimitRecOn_limit (since := "2024-09-05")]
-alias limitRecOn_limit := prelimitRecOn_limit
+@[deprecated prelimitRecOn_of_isSuccPrelimit (since := "2024-09-05")]
+alias limitRecOn_limit := prelimitRecOn_of_isSuccPrelimit
+@[deprecated prelimitRecOn_of_isSuccPrelimit (since := "2024-09-14")]
+alias prelimitRecOn_limit := prelimitRecOn_of_isSuccPrelimit
end PartialOrder
@@ -633,23 +819,73 @@ section LinearOrder
variable [LinearOrder α] [SuccOrder α] [WellFoundedLT α]
(hs : ∀ a, ¬ IsMax a → C a → C (Order.succ a)) (hl : ∀ a, IsSuccPrelimit a → (∀ b < a, C b) → C a)
-@[simp]
-theorem prelimitRecOn_succ (hb : ¬ IsMax b) :
+theorem prelimitRecOn_succ_of_not_isMax (hb : ¬ IsMax b) :
prelimitRecOn (Order.succ b) hs hl = hs b hb (prelimitRecOn b hs hl) := by
have h := not_isSuccPrelimit_succ_of_not_isMax hb
+ have H := Classical.choose_spec (not_isSuccPrelimit_iff.1 h)
rw [prelimitRecOn, WellFounded.fix_eq, dif_neg h]
- have {b c hb hc} {x : ∀ a, C a} (h : b = c) :
- congr_arg Order.succ h ▸ hs b hb (x b) = hs c hc (x c) := by subst h; rfl
- let x := Classical.indefiniteDescription _ (not_isSuccPrelimit_iff.mp h)
- exact this ((succ_eq_succ_iff_of_not_isMax x.2.1 hb).mp x.2.2)
+ have {a c : α} {ha hc} {x : ∀ a, C a} (h : a = c) :
+ cast (congr_arg (C ∘ succ) h) (hs a ha (x a)) = hs c hc (x c) := by subst h; rfl
+ exact this <| (succ_eq_succ_iff_of_not_isMax H.1 hb).1 H.2
-@[deprecated prelimitRecOn_succ (since := "2024-09-05")]
-alias limitRecOn_succ := prelimitRecOn_succ
+@[deprecated prelimitRecOn_succ_of_not_isMax (since := "2024-09-05")]
+alias limitRecOn_succ' := prelimitRecOn_succ_of_not_isMax
+@[deprecated prelimitRecOn_succ_of_not_isMax (since := "2024-09-14")]
+alias prelimitRecOn_succ' := prelimitRecOn_succ_of_not_isMax
+
+@[simp]
+theorem prelimitRecOn_succ [NoMaxOrder α] (b : α) :
+ prelimitRecOn (Order.succ b) hs hl = hs b (not_isMax b) (prelimitRecOn b hs hl) :=
+ prelimitRecOn_succ_of_not_isMax _ _ _
end LinearOrder
end prelimitRecOn
+section limitRecOn
+
+section PartialOrder
+
+variable [PartialOrder α] [SuccOrder α] [WellFoundedLT α] (hm : ∀ a, IsMin a → C a)
+ (hs : ∀ a, ¬ IsMax a → C a → C (Order.succ a)) (hl : ∀ a, IsSuccLimit a → (∀ b < a, C b) → C a)
+
+variable (b) in
+open Classical in
+/-- Recursion principle on a well-founded partial `SuccOrder`, separating out the case of a
+minimal element. -/
+@[elab_as_elim] noncomputable def limitRecOn : C b :=
+ prelimitRecOn b hs fun a ha IH ↦
+ if h : IsMin a then hm a h else hl a (ha.isSuccLimit_of_not_isMin h) IH
+
+@[simp]
+theorem limitRecOn_isMin (hb : IsMin b) : limitRecOn b hm hs hl = hm b hb := by
+ rw [limitRecOn, prelimitRecOn_of_isSuccPrelimit _ _ hb.isSuccPrelimit, dif_pos hb]
+
+@[simp]
+theorem limitRecOn_of_isSuccLimit (hb : IsSuccLimit b) :
+ limitRecOn b hm hs hl = hl b hb fun x _ ↦ limitRecOn x hm hs hl := by
+ rw [limitRecOn, prelimitRecOn_of_isSuccPrelimit _ _ hb.isSuccPrelimit, dif_neg hb.not_isMin]; rfl
+
+end PartialOrder
+
+section LinearOrder
+
+variable [LinearOrder α] [SuccOrder α] [WellFoundedLT α] (hm : ∀ a, IsMin a → C a)
+ (hs : ∀ a, ¬ IsMax a → C a → C (Order.succ a)) (hl : ∀ a, IsSuccLimit a → (∀ b < a, C b) → C a)
+
+theorem limitRecOn_succ_of_not_isMax (hb : ¬ IsMax b) :
+ limitRecOn (Order.succ b) hm hs hl = hs b hb (limitRecOn b hm hs hl) := by
+ rw [limitRecOn, prelimitRecOn_succ_of_not_isMax]; rfl
+
+@[simp]
+theorem limitRecOn_succ [NoMaxOrder α] (b : α) :
+ limitRecOn (Order.succ b) hm hs hl = hs b (not_isMax b) (limitRecOn b hm hs hl) :=
+ limitRecOn_succ_of_not_isMax hm hs hl _
+
+end LinearOrder
+
+end limitRecOn
+
end SuccOrder
namespace PredOrder
@@ -659,24 +895,22 @@ section prelimitRecOn
section PartialOrder
variable [PartialOrder α] [PredOrder α] [WellFoundedGT α]
+ (hp : ∀ a, ¬ IsMin a → C a → C (Order.pred a)) (hl : ∀ a, IsPredPrelimit a → (∀ b > a, C b) → C a)
+variable (b) in
/-- Recursion principle on a well-founded partial `PredOrder`. -/
-@[elab_as_elim] noncomputable def prelimitRecOn (b : α)
- (hp : ∀ a, ¬ IsMin a → C a → C (Order.pred a))
- (hl : ∀ a, IsPredPrelimit a → (∀ b > a, C b) → C a) : C b :=
- SuccOrder.prelimitRecOn (α := αᵒᵈ) b hp fun a ha => hl a ha.dual
-
-@[deprecated prelimitRecOn (since := "2024-09-05")]
-alias limitRecOn := prelimitRecOn
+@[elab_as_elim] noncomputable def prelimitRecOn : C b :=
+ SuccOrder.prelimitRecOn (α := αᵒᵈ) b hp (fun a ha => hl a ha.dual)
@[simp]
-theorem prelimitRecOn_limit (hp : ∀ a, ¬ IsMin a → C a → C (Order.pred a))
- (hl : ∀ a, IsPredPrelimit a → (∀ b > a, C b) → C a) (hb : IsPredPrelimit b) :
+theorem prelimitRecOn_of_isPredPrelimit (hb : IsPredPrelimit b) :
prelimitRecOn b hp hl = hl b hb fun x _ ↦ prelimitRecOn x hp hl :=
- SuccOrder.prelimitRecOn_limit _ _ hb.dual
+ SuccOrder.prelimitRecOn_of_isSuccPrelimit _ _ hb.dual
-@[deprecated prelimitRecOn_limit (since := "2024-09-05")]
-alias limitRecOn_limit := prelimitRecOn_limit
+@[deprecated prelimitRecOn_of_isPredPrelimit (since := "2024-09-05")]
+alias limitRecOn_limit := prelimitRecOn_of_isPredPrelimit
+@[deprecated prelimitRecOn_of_isPredPrelimit (since := "2024-09-14")]
+alias prelimitRecOn_limit := prelimitRecOn_of_isPredPrelimit
end PartialOrder
@@ -685,16 +919,65 @@ section LinearOrder
variable [LinearOrder α] [PredOrder α] [WellFoundedGT α]
(hp : ∀ a, ¬ IsMin a → C a → C (Order.pred a)) (hl : ∀ a, IsPredPrelimit a → (∀ b > a, C b) → C a)
-@[simp]
-theorem prelimitRecOn_pred (hb : ¬ IsMin b) :
+theorem prelimitRecOn_pred_of_not_isMin (hb : ¬ IsMin b) :
prelimitRecOn (Order.pred b) hp hl = hp b hb (prelimitRecOn b hp hl) :=
- SuccOrder.prelimitRecOn_succ (α := αᵒᵈ) _ _ hb
+ SuccOrder.prelimitRecOn_succ_of_not_isMax _ _ _
-@[deprecated prelimitRecOn_pred (since := "2024-09-05")]
-alias limitRecOn_pred := prelimitRecOn_pred
+@[deprecated prelimitRecOn_pred_of_not_isMin (since := "2024-09-05")]
+alias limitRecOn_pred' := prelimitRecOn_pred_of_not_isMin
+@[deprecated prelimitRecOn_pred_of_not_isMin (since := "2024-09-14")]
+alias prelimitRecOn_pred' := prelimitRecOn_pred_of_not_isMin
+
+@[simp]
+theorem prelimitRecOn_pred [NoMinOrder α] (b : α) :
+ prelimitRecOn (Order.pred b) hp hl = hp b (not_isMin b) (prelimitRecOn b hp hl) :=
+ prelimitRecOn_pred_of_not_isMin _ _ _
end LinearOrder
end prelimitRecOn
+section limitRecOn
+
+section PartialOrder
+
+variable [PartialOrder α] [PredOrder α] [WellFoundedGT α] (hm : ∀ a, IsMax a → C a)
+ (hs : ∀ a, ¬ IsMin a → C a → C (Order.pred a)) (hl : ∀ a, IsPredLimit a → (∀ b > a, C b) → C a)
+
+variable (b) in
+open Classical in
+/-- Recursion principle on a well-founded partial `PredOrder`, separating out the case of a
+maximal element. -/
+@[elab_as_elim] noncomputable def limitRecOn : C b :=
+ SuccOrder.limitRecOn (α := αᵒᵈ) b hm hs (fun a ha => hl a ha.dual)
+
+@[simp]
+theorem limitRecOn_isMax (hb : IsMax b) : limitRecOn b hm hs hl = hm b hb :=
+ SuccOrder.limitRecOn_isMin (α := αᵒᵈ) hm hs _ hb
+
+@[simp]
+theorem limitRecOn_of_isPredLimit (hb : IsPredLimit b) :
+ limitRecOn b hm hs hl = hl b hb fun x _ ↦ limitRecOn x hm hs hl :=
+ SuccOrder.limitRecOn_of_isSuccLimit (α := αᵒᵈ) hm hs _ hb.dual
+
+end PartialOrder
+
+section LinearOrder
+
+variable [LinearOrder α] [PredOrder α] [WellFoundedGT α] (hm : ∀ a, IsMax a → C a)
+ (hs : ∀ a, ¬ IsMin a → C a → C (Order.pred a)) (hl : ∀ a, IsPredLimit a → (∀ b > a, C b) → C a)
+
+theorem limitRecOn_pred_of_not_isMin (hb : ¬ IsMin b) :
+ limitRecOn (Order.pred b) hm hs hl = hs b hb (limitRecOn b hm hs hl) :=
+ SuccOrder.limitRecOn_succ_of_not_isMax (α := αᵒᵈ) hm hs _ hb
+
+@[simp]
+theorem limitRecOn_pred [NoMinOrder α] (b : α) :
+ limitRecOn (Order.pred b) hm hs hl = hs b (not_isMin b) (limitRecOn b hm hs hl) :=
+ SuccOrder.limitRecOn_succ (α := αᵒᵈ) hm hs _ b
+
+end LinearOrder
+
+end limitRecOn
+
end PredOrder
diff --git a/Mathlib/Order/SuccPred/LinearLocallyFinite.lean b/Mathlib/Order/SuccPred/LinearLocallyFinite.lean
index 2a11b704d5899..e758ae8c0f2f4 100644
--- a/Mathlib/Order/SuccPred/LinearLocallyFinite.lean
+++ b/Mathlib/Order/SuccPred/LinearLocallyFinite.lean
@@ -68,13 +68,14 @@ instance (priority := 100) isPredArchimedean_of_isSuccArchimedean [IsSuccArchime
⟨Nat.find h_exists, Nat.find_spec h_exists, fun m hmn ↦ Nat.find_min h_exists hmn⟩
refine ⟨n, ?_⟩
rw [← hn_eq]
- induction' n with n
- · simp only [Function.iterate_zero, id]
- · rw [pred_succ_iterate_of_not_isMax]
+ cases n with
+ | zero => simp only [Function.iterate_zero, id]
+ | succ n =>
+ rw [pred_succ_iterate_of_not_isMax]
rw [Nat.succ_sub_succ_eq_sub, tsub_zero]
suffices succ^[n] i < succ^[n.succ] i from not_isMax_of_lt this
refine lt_of_le_of_ne ?_ ?_
- · rw [Function.iterate_succ']
+ · rw [Function.iterate_succ_apply']
exact le_succ _
· rw [hn_eq]
exact hn_lt_ne _ (Nat.lt_succ_self n)
@@ -84,9 +85,9 @@ instance isSuccArchimedean_of_isPredArchimedean [IsPredArchimedean ι] : IsSuccA
/-- In a linear `SuccOrder` that's also a `PredOrder`, `IsSuccArchimedean` and `IsPredArchimedean`
are equivalent. -/
-theorem isSuccArchimedean_iff_isPredArchimedean : IsSuccArchimedean ι ↔ IsPredArchimedean ι :=
- ⟨fun _ => isPredArchimedean_of_isSuccArchimedean,
- fun _ => isSuccArchimedean_of_isPredArchimedean⟩
+theorem isSuccArchimedean_iff_isPredArchimedean : IsSuccArchimedean ι ↔ IsPredArchimedean ι where
+ mp _ := isPredArchimedean_of_isSuccArchimedean
+ mpr _ := isSuccArchimedean_of_isPredArchimedean
end LinearOrder
@@ -193,12 +194,13 @@ variable [SuccOrder ι] [IsSuccArchimedean ι] [PredOrder ι] {i0 i : ι}
the range of `toZ`. -/
def toZ (i0 i : ι) : ℤ :=
dite (i0 ≤ i) (fun hi ↦ Nat.find (exists_succ_iterate_of_le hi)) fun hi ↦
- -Nat.find (exists_pred_iterate_of_le (not_le.mp hi).le)
+ -Nat.find (exists_pred_iterate_of_le (α := ι) (not_le.mp hi).le)
theorem toZ_of_ge (hi : i0 ≤ i) : toZ i0 i = Nat.find (exists_succ_iterate_of_le hi) :=
dif_pos hi
-theorem toZ_of_lt (hi : i < i0) : toZ i0 i = -Nat.find (exists_pred_iterate_of_le hi.le) :=
+theorem toZ_of_lt (hi : i < i0) :
+ toZ i0 i = -Nat.find (exists_pred_iterate_of_le (α := ι) hi.le) :=
dif_neg (not_le.mpr hi)
@[simp]
@@ -309,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 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 b973420ec6a20..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
@@ -131,7 +154,7 @@ theorem supIndep_pair [DecidableEq ι] {i j : ι} (hij : i ≠ j) :
have : ({i, k} : Finset ι).erase k = {i} := by
ext
rw [mem_erase, mem_insert, mem_singleton, mem_singleton, and_or_left, Ne,
- not_and_self_iff, or_false_iff, and_iff_right_of_imp]
+ not_and_self_iff, or_false, and_iff_right_of_imp]
rintro rfl
exact hij
rw [this, Finset.sup_singleton]⟩
@@ -174,7 +197,7 @@ theorem supIndep_attach : (s.attach.SupIndep fun a => f a) ↔ s.SupIndep f := b
convert h (filter_subset (fun (i : { x // x ∈ s }) => (i : ι) ∈ t) _) (mem_attach _ ⟨i, ‹_›⟩)
fun hi => hit <| by simpa using hi using 1
refine eq_of_forall_ge_iff ?_
- simp only [Finset.sup_le_iff, mem_filter, mem_attach, true_and_iff, Function.comp_apply,
+ simp only [Finset.sup_le_iff, mem_filter, mem_attach, true_and, Function.comp_apply,
Subtype.forall, Subtype.coe_mk]
exact fun a => forall_congr' fun j => ⟨fun h _ => h, fun h hj => h (ht hj) hj⟩
diff --git a/Mathlib/Order/SymmDiff.lean b/Mathlib/Order/SymmDiff.lean
index 8805a9c3184ad..439253b07c5a3 100644
--- a/Mathlib/Order/SymmDiff.lean
+++ b/Mathlib/Order/SymmDiff.lean
@@ -82,14 +82,14 @@ theorem symmDiff_eq_Xor' (p q : Prop) : p ∆ q = Xor' p q :=
@[simp]
theorem bihimp_iff_iff {p q : Prop} : p ⇔ q ↔ (p ↔ q) :=
- (iff_iff_implies_and_implies _ _).symm.trans Iff.comm
+ iff_iff_implies_and_implies.symm.trans Iff.comm
@[simp]
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 cacf754c0c287..1c5e905b8da09 100644
--- a/Mathlib/Order/WellFounded.lean
+++ b/Mathlib/Order/WellFounded.lean
@@ -3,7 +3,8 @@ 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
-/
-import Mathlib.Data.Set.Basic
+import Mathlib.Data.Set.Function
+import Mathlib.Order.Bounds.Defs
/-!
# Well-founded relations
@@ -119,47 +120,86 @@ protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] {
exact hy
rintro (hy | rfl); (· exact _root_.trans hy (wo.wf.lt_succ h)); exact wo.wf.lt_succ h
+end WellFounded
+
section LinearOrder
-variable [LinearOrder β] [PartialOrder γ]
+variable [LinearOrder β] [Preorder γ]
-theorem min_le (h : WellFounded ((· < ·) : β → β → Prop)) {x : β} {s : Set β} (hx : x ∈ s)
- (hne : s.Nonempty := ⟨x, hx⟩) : h.min s hne ≤ x :=
+theorem WellFounded.min_le (h : WellFounded ((· < ·) : β → β → Prop))
+ {x : β} {s : Set β} (hx : x ∈ s) (hne : s.Nonempty := ⟨x, hx⟩) : h.min s hne ≤ x :=
not_lt.1 <| h.not_lt_min _ _ hx
-private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
- (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
- f b ≤ g b := by
- obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
- rw [hfg]
- exact Set.mem_range_self b
- rcases lt_or_le c b with hcb | hbc
- · rw [H c hcb] at hc
- rw [hg.injective hc] at hcb
- exact hcb.false.elim
- · rw [← hc]
- exact hf.monotone hbc
-
-theorem eq_strictMono_iff_eq_range (h : WellFounded ((· < ·) : β → β → Prop))
+theorem Set.range_injOn_strictMono [WellFoundedLT β] :
+ Set.InjOn Set.range { f : β → γ | StrictMono f } := by
+ intro f hf g hg hfg
+ ext a
+ apply WellFoundedLT.induction a
+ intro a IH
+ obtain ⟨b, hb⟩ := hfg ▸ mem_range_self a
+ obtain h | rfl | h := lt_trichotomy b a
+ · rw [← IH b h] at hb
+ cases (hf.injective hb).not_lt h
+ · rw [hb]
+ · obtain ⟨c, hc⟩ := hfg.symm ▸ mem_range_self a
+ have := hg h
+ rw [hb, ← hc, hf.lt_iff_lt] at this
+ rw [IH c this] at hc
+ cases (hg.injective hc).not_lt this
+
+theorem Set.range_injOn_strictAnti [WellFoundedGT β] :
+ Set.InjOn Set.range { f : β → γ | StrictAnti f } :=
+ fun _ hf _ hg ↦ Set.range_injOn_strictMono (β := βᵒᵈ) hf.dual hg.dual
+
+theorem StrictMono.range_inj [WellFoundedLT β] {f g : β → γ}
+ (hf : StrictMono f) (hg : StrictMono g) : Set.range f = Set.range g ↔ f = g :=
+ Set.range_injOn_strictMono.eq_iff hf hg
+
+theorem StrictAnti.range_inj [WellFoundedGT β] {f g : β → γ}
+ (hf : StrictAnti f) (hg : StrictAnti g) : Set.range f = Set.range g ↔ f = g :=
+ Set.range_injOn_strictAnti.eq_iff hf hg
+
+@[deprecated StrictMono.range_inj (since := "2024-09-11")]
+theorem WellFounded.eq_strictMono_iff_eq_range (h : WellFounded ((· < ·) : β → β → Prop))
{f g : β → γ} (hf : StrictMono f) (hg : StrictMono g) :
Set.range f = Set.range g ↔ f = g :=
- ⟨fun hfg => by
- funext a
- apply h.induction a
- exact fun b H =>
- le_antisymm (eq_strictMono_iff_eq_range_aux hf hg hfg H)
- (eq_strictMono_iff_eq_range_aux hg hf hfg.symm fun a hab => (H a hab).symm),
- congr_arg _⟩
-
-theorem self_le_of_strictMono (h : WellFounded ((· < ·) : β → β → Prop))
+ @StrictMono.range_inj β γ _ _ ⟨h⟩ f g hf hg
+
+/-- A strictly monotone function `f` on a well-order satisfies `x ≤ f x` for all `x`. -/
+theorem StrictMono.id_le [WellFoundedLT β] {f : β → β} (hf : StrictMono f) : id ≤ f := by
+ rw [Pi.le_def]
+ by_contra! H
+ obtain ⟨m, hm, hm'⟩ := wellFounded_lt.has_min _ H
+ exact hm' _ (hf hm) hm
+
+theorem StrictMono.le_apply [WellFoundedLT β] {f : β → β} (hf : StrictMono f) {x} : x ≤ f x :=
+ hf.id_le x
+
+/-- A strictly monotone function `f` on a cowell-order satisfies `f x ≤ x` for all `x`. -/
+theorem StrictMono.le_id [WellFoundedGT β] {f : β → β} (hf : StrictMono f) : f ≤ id :=
+ StrictMono.id_le (β := βᵒᵈ) hf.dual
+
+theorem StrictMono.apply_le [WellFoundedGT β] {f : β → β} (hf : StrictMono f) {x} : f x ≤ x :=
+ StrictMono.le_apply (β := βᵒᵈ) hf.dual
+
+@[deprecated StrictMono.le_apply (since := "2024-09-11")]
+theorem WellFounded.self_le_of_strictMono (h : WellFounded ((· < ·) : β → β → Prop))
{f : β → β} (hf : StrictMono f) : ∀ n, n ≤ f n := by
by_contra! h₁
have h₂ := h.min_mem _ h₁
exact h.not_lt_min _ h₁ (hf h₂) h₂
-end LinearOrder
+theorem StrictMono.not_bddAbove_range_of_wellFoundedLT {f : β → β} [WellFoundedLT β] [NoMaxOrder β]
+ (hf : StrictMono f) : ¬ BddAbove (Set.range f) := by
+ rintro ⟨a, ha⟩
+ obtain ⟨b, hb⟩ := exists_gt a
+ exact ((hf.le_apply.trans_lt (hf hb)).trans_le <| ha (Set.mem_range_self _)).false
-end WellFounded
+theorem StrictMono.not_bddBelow_range_of_wellFoundedGT {f : β → β} [WellFoundedGT β] [NoMinOrder β]
+ (hf : StrictMono f) : ¬ BddBelow (Set.range f) :=
+ hf.dual.not_bddAbove_range_of_wellFoundedLT
+
+end LinearOrder
namespace Function
diff --git a/Mathlib/Order/WellFoundedSet.lean b/Mathlib/Order/WellFoundedSet.lean
index 5e939f8f9b787..e6c840cc1936d 100644
--- a/Mathlib/Order/WellFoundedSet.lean
+++ b/Mathlib/Order/WellFoundedSet.lean
@@ -134,16 +134,15 @@ theorem acc_iff_wellFoundedOn {α} {r : α → α → Prop} {a : α} :
TFAE [Acc r a,
WellFoundedOn { b | ReflTransGen r b a } r,
WellFoundedOn { b | TransGen r b a } r] := by
- tfae_have 1 → 2
- · refine fun h => ⟨fun b => InvImage.accessible _ ?_⟩
+ tfae_have 1 → 2 := by
+ refine fun h => ⟨fun b => InvImage.accessible _ ?_⟩
rw [← acc_transGen_iff] at h ⊢
obtain h' | h' := reflTransGen_iff_eq_or_transGen.1 b.2
· rwa [h'] at h
· exact h.inv h'
- tfae_have 2 → 3
- · exact fun h => h.subset fun _ => TransGen.to_reflTransGen
- tfae_have 3 → 1
- · refine fun h => Acc.intro _ (fun b hb => (h.apply ⟨b, .single hb⟩).of_fibration Subtype.val ?_)
+ tfae_have 2 → 3 := fun h => h.subset fun _ => TransGen.to_reflTransGen
+ tfae_have 3 → 1 := by
+ refine fun h => Acc.intro _ (fun b hb => (h.apply ⟨b, .single hb⟩).of_fibration Subtype.val ?_)
exact fun ⟨c, hc⟩ d h => ⟨⟨d, .head h hc⟩, h, rfl⟩
tfae_finish
@@ -167,10 +166,10 @@ theorem wellFoundedOn_iff_no_descending_seq :
· rintro ⟨⟨f, hf⟩⟩
have H : ∀ n, f n ∈ s := fun n => (hf.2 n.lt_succ_self).2.2
refine ⟨⟨f, ?_⟩, H⟩
- simpa only [H, and_true_iff] using @hf
+ simpa only [H, and_true] using @hf
· rintro ⟨⟨f, hf⟩, hfs : ∀ n, f n ∈ s⟩
refine ⟨⟨f, ?_⟩⟩
- simpa only [hfs, and_true_iff] using @hf
+ simpa only [hfs, and_true] using @hf
theorem WellFoundedOn.union (hs : s.WellFoundedOn r) (ht : t.WellFoundedOn r) :
(s ∪ t).WellFoundedOn r := by
@@ -310,7 +309,7 @@ theorem Subsingleton.partiallyWellOrderedOn (hs : s.Subsingleton) : PartiallyWel
theorem partiallyWellOrderedOn_insert :
PartiallyWellOrderedOn (insert a s) r ↔ PartiallyWellOrderedOn s r := by
simp only [← singleton_union, partiallyWellOrderedOn_union,
- partiallyWellOrderedOn_singleton, true_and_iff]
+ partiallyWellOrderedOn_singleton, true_and]
protected theorem PartiallyWellOrderedOn.insert (h : PartiallyWellOrderedOn s r) (a : α) :
PartiallyWellOrderedOn (insert a s) r :=
@@ -431,7 +430,7 @@ protected theorem Subsingleton.isPWO (hs : s.Subsingleton) : IsPWO s := hs.finit
@[simp]
theorem isPWO_insert {a} : IsPWO (insert a s) ↔ IsPWO s := by
- simp only [← singleton_union, isPWO_union, isPWO_singleton, true_and_iff]
+ simp only [← singleton_union, isPWO_union, isPWO_singleton, true_and]
protected theorem IsPWO.insert (h : IsPWO s) (a : α) : IsPWO (insert a s) :=
isPWO_insert.2 h
@@ -444,7 +443,7 @@ protected theorem Subsingleton.isWF (hs : s.Subsingleton) : IsWF s := hs.isPWO.i
@[simp]
theorem isWF_insert {a} : IsWF (insert a s) ↔ IsWF s := by
- simp only [← singleton_union, isWF_union, isWF_singleton, true_and_iff]
+ simp only [← singleton_union, isWF_union, isWF_singleton, true_and]
protected theorem IsWF.insert (h : IsWF s) (a : α) : IsWF (insert a s) :=
isWF_insert.2 h
@@ -468,7 +467,7 @@ protected theorem Subsingleton.wellFoundedOn (hs : s.Subsingleton) : s.WellFound
@[simp]
theorem wellFoundedOn_insert : WellFoundedOn (insert a s) r ↔ WellFoundedOn s r := by
- simp only [← singleton_union, wellFoundedOn_union, wellFoundedOn_singleton, true_and_iff]
+ simp only [← singleton_union, wellFoundedOn_union, wellFoundedOn_singleton, true_and]
protected theorem WellFoundedOn.insert (h : WellFoundedOn s r) (a : α) :
WellFoundedOn (insert a s) r :=
@@ -839,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 81a092fceb2e0..b78132bdc9a95 100644
--- a/Mathlib/Order/WithBot.lean
+++ b/Mathlib/Order/WithBot.lean
@@ -3,7 +3,6 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl
-/
-import Mathlib.Init.Algebra.Classes
import Mathlib.Logic.Nontrivial.Basic
import Mathlib.Order.BoundedOrder
import Mathlib.Order.TypeTags
@@ -294,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⟩
@@ -435,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, ⟨_⟩, _⟩
@@ -470,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)
@@ -934,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 :=
@@ -964,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 :=
@@ -1089,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/ConditionalExpectation.lean b/Mathlib/Probability/ConditionalExpectation.lean
index 66719c1935974..18a5ab72ec167 100644
--- a/Mathlib/Probability/ConditionalExpectation.lean
+++ b/Mathlib/Probability/ConditionalExpectation.lean
@@ -58,11 +58,11 @@ theorem condexp_indep_eq (hle₁ : m₁ ≤ m) (hle₂ : m₂ ≤ m) [SigmaFinit
· have heq₁ : (fun f : lpMeas E ℝ m₁ 1 μ => ∫ x, (f : Ω → E) x ∂μ) =
(fun f : Lp E 1 μ => ∫ x, f x ∂μ) ∘ Submodule.subtypeL _ := by
refine funext fun f => integral_congr_ae ?_
- simp_rw [Submodule.coe_subtypeL', Submodule.coeSubtype]; norm_cast
+ simp_rw [Submodule.coe_subtypeL', Submodule.coe_subtype]; norm_cast
have heq₂ : (fun f : lpMeas E ℝ m₁ 1 μ => ∫ x in s, (f : Ω → E) x ∂μ) =
(fun f : Lp E 1 μ => ∫ x in s, f x ∂μ) ∘ Submodule.subtypeL _ := by
refine funext fun f => integral_congr_ae (ae_restrict_of_ae ?_)
- simp_rw [Submodule.coe_subtypeL', Submodule.coeSubtype]
+ simp_rw [Submodule.coe_subtypeL', Submodule.coe_subtype]
exact Eventually.of_forall fun _ => (by trivial)
refine isClosed_eq (Continuous.const_smul ?_ _) ?_
· rw [heq₁]
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/Gamma.lean b/Mathlib/Probability/Distributions/Gamma.lean
index 0548d04bfd3c0..562c9b3c3b6f9 100644
--- a/Mathlib/Probability/Distributions/Gamma.lean
+++ b/Mathlib/Probability/Distributions/Gamma.lean
@@ -30,8 +30,8 @@ open MeasureTheory Real Set Filter Topology
lemma lintegral_Iic_eq_lintegral_Iio_add_Icc {y z : ℝ} (f : ℝ → ℝ≥0∞) (hzy : z ≤ y) :
∫⁻ x in Iic y, f x = (∫⁻ x in Iio z, f x) + ∫⁻ x in Icc z y, f x := by
rw [← Iio_union_Icc_eq_Iic hzy, lintegral_union measurableSet_Icc]
- rw [Set.disjoint_iff]
- rintro x ⟨h1 : x < _, h2, _⟩
+ simp_rw [Set.disjoint_iff_forall_ne, mem_Iio, mem_Icc]
+ intros
linarith
namespace ProbabilityTheory
@@ -49,8 +49,9 @@ def gammaPDF (a r x : ℝ) : ℝ≥0∞ :=
ENNReal.ofReal (gammaPDFReal a r x)
lemma gammaPDF_eq (a r x : ℝ) :
- gammaPDF a r x = ENNReal.ofReal (if 0 ≤ x then
- r ^ a / (Gamma a) * x ^ (a-1) * exp (-(r * x)) else 0) := rfl
+ gammaPDF a r x =
+ ENNReal.ofReal (if 0 ≤ x then r ^ a / (Gamma a) * x ^ (a-1) * exp (-(r * x)) else 0) :=
+ rfl
lemma gammaPDF_of_neg {a r x : ℝ} (hx : x < 0) : gammaPDF a r x = 0 := by
simp only [gammaPDF_eq, if_neg (not_le.mpr hx), ENNReal.ofReal_zero]
diff --git a/Mathlib/Probability/Distributions/Pareto.lean b/Mathlib/Probability/Distributions/Pareto.lean
new file mode 100644
index 0000000000000..abc5e6e63621a
--- /dev/null
+++ b/Mathlib/Probability/Distributions/Pareto.lean
@@ -0,0 +1,147 @@
+/-
+Copyright (c) 2024 Alvan Caleb Arulandu. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Alvan Caleb Arulandu
+-/
+import Mathlib.Probability.Notation
+import Mathlib.Probability.CDF
+import Mathlib.Analysis.SpecialFunctions.ImproperIntegrals
+
+/-! # Pareto distributions over ℝ
+
+Define the Pareto measure over the reals.
+
+## Main definitions
+* `paretoPDFReal`: the function `t r x ↦ r * t ^ r * x ^ -(r + 1)`
+ for `t ≤ x` or `0` else, which is the probability density function of a Pareto distribution with
+ scale `t` and shape `r` (when `ht : 0 < t` and `hr : 0 < r`).
+* `paretoPDF`: `ℝ≥0∞`-valued pdf,
+ `paretoPDF t r = ENNReal.ofReal (paretoPDFReal t r)`.
+* `paretoMeasure`: a Pareto measure on `ℝ`, parametrized by its scale `t` and shape `r`.
+* `paretoCDFReal`: the CDF given by the definition of CDF in `ProbabilityTheory.CDF` applied to the
+ Pareto measure.
+-/
+
+open scoped ENNReal NNReal
+
+open MeasureTheory Real Set Filter Topology
+
+namespace ProbabilityTheory
+variable {t r x : ℝ}
+
+section ParetoPDF
+
+/-- The pdf of the Pareto distribution depending on its scale `t` and rate `r`. -/
+noncomputable def paretoPDFReal (t r x : ℝ) : ℝ :=
+ if t ≤ x then r * t ^ r * x ^ (-(r + 1)) else 0
+
+/-- The pdf of the Pareto distribution, as a function valued in `ℝ≥0∞`. -/
+noncomputable def paretoPDF (t r x : ℝ) : ℝ≥0∞ :=
+ ENNReal.ofReal (paretoPDFReal t r x)
+
+lemma paretoPDF_eq (t r x : ℝ) :
+ paretoPDF t r x = ENNReal.ofReal (if t ≤ x then r * t ^ r * x ^ (-(r + 1)) else 0) := rfl
+
+lemma paretoPDF_of_lt (hx : x < t) : paretoPDF t r x = 0 := by
+ simp only [paretoPDF_eq, if_neg (not_le.mpr hx), ENNReal.ofReal_zero]
+
+lemma paretoPDF_of_le (hx : t ≤ x) :
+ paretoPDF t r x = ENNReal.ofReal (r * t ^ r * x ^ (-(r + 1))) := by
+ simp only [paretoPDF_eq, if_pos hx]
+
+/-- The Lebesgue integral of the Pareto pdf over reals `≤ t` equals `0`. -/
+lemma lintegral_paretoPDF_of_le (hx : x ≤ t) :
+ ∫⁻ y in Iio x, paretoPDF t r y = 0 := by
+ rw [setLIntegral_congr_fun (g := fun _ ↦ 0) measurableSet_Iio]
+ · rw [lintegral_zero, ← ENNReal.ofReal_zero]
+ · simp only [paretoPDF_eq, ge_iff_le, ENNReal.ofReal_eq_zero]
+ filter_upwards with a (_ : a < _)
+ rw [if_neg (by linarith)]
+
+/-- The Pareto pdf is measurable. -/
+@[measurability, fun_prop]
+lemma measurable_paretoPDFReal (t r : ℝ) : Measurable (paretoPDFReal t r) :=
+ Measurable.ite measurableSet_Ici ((measurable_id.pow_const _).const_mul _) measurable_const
+
+/-- The Pareto pdf is strongly measurable. -/
+@[measurability]
+lemma stronglyMeasurable_paretoPDFReal (t r : ℝ) :
+ StronglyMeasurable (paretoPDFReal t r) :=
+ (measurable_paretoPDFReal t r).stronglyMeasurable
+
+/-- The Pareto pdf is positive for all reals `>= t`. -/
+lemma paretoPDFReal_pos (ht : 0 < t) (hr : 0 < r) (hx : t ≤ x) :
+ 0 < paretoPDFReal t r x := by
+ rw [paretoPDFReal, if_pos hx]
+ have _ : 0 < x := by linarith
+ positivity
+
+/-- The Pareto pdf is nonnegative. -/
+lemma paretoPDFReal_nonneg (ht : 0 ≤ t) (hr : 0 ≤ r) (x : ℝ) :
+ 0 ≤ paretoPDFReal t r x := by
+ unfold paretoPDFReal
+ split_ifs with h
+ · cases le_iff_eq_or_lt.1 ht with
+ | inl ht0 =>
+ rw [← ht0] at h
+ positivity
+ | inr htp =>
+ have := lt_of_lt_of_le htp h
+ positivity
+ · positivity
+
+open Measure
+
+/-- The pdf of the Pareto distribution integrates to `1`. -/
+@[simp]
+lemma lintegral_paretoPDF_eq_one (ht : 0 < t) (hr : 0 < r) :
+ ∫⁻ x, paretoPDF t r x = 1 := by
+ have leftSide : ∫⁻ x in Iio t, paretoPDF t r x = 0 := lintegral_paretoPDF_of_le (le_refl t)
+ have rightSide : ∫⁻ x in Ici t, paretoPDF t r x =
+ ∫⁻ x in Ici t, ENNReal.ofReal (r * t ^ r * x ^ (-(r + 1))) :=
+ setLIntegral_congr_fun measurableSet_Ici (ae_of_all _ (fun _ ↦ paretoPDF_of_le))
+ rw [← ENNReal.toReal_eq_one_iff, ← lintegral_add_compl _ measurableSet_Ici, compl_Ici,
+ leftSide, rightSide, add_zero, ← integral_eq_lintegral_of_nonneg_ae]
+ · rw [integral_Ici_eq_integral_Ioi, integral_mul_left, integral_Ioi_rpow_of_lt _ ht]
+ · field_simp [hr]
+ rw [mul_assoc, ← rpow_add ht]
+ simp
+ linarith
+ · rw [EventuallyLE, ae_restrict_iff' measurableSet_Ici]
+ refine ae_of_all _ fun x (hx : t ≤ x) ↦ ?_
+ have := lt_of_lt_of_le ht hx
+ positivity
+ · apply (measurable_paretoPDFReal t r).aestronglyMeasurable.congr
+ refine (ae_restrict_iff' measurableSet_Ici).mpr <| ae_of_all _ fun x (hx : t ≤ x) ↦ ?_
+ simp_rw [paretoPDFReal, eq_true_intro hx, ite_true]
+
+end ParetoPDF
+
+open MeasureTheory
+
+/-- Measure defined by the Pareto distribution. -/
+noncomputable def paretoMeasure (t r : ℝ) : Measure ℝ :=
+ volume.withDensity (paretoPDF t r)
+
+lemma isProbabilityMeasure_paretoMeasure (ht : 0 < t) (hr : 0 < r) :
+ IsProbabilityMeasure (paretoMeasure t r) where
+ measure_univ := by simp [paretoMeasure, lintegral_paretoPDF_eq_one ht hr]
+
+section ParetoCDF
+
+/-- CDF of the Pareto distribution equals the integral of the PDF. -/
+lemma paretoCDFReal_eq_integral (ht : 0 < t) (hr : 0 < r) (x : ℝ) :
+ cdf (paretoMeasure t r) x = ∫ x in Iic x, paretoPDFReal t r x := by
+ have : IsProbabilityMeasure (paretoMeasure t r) := isProbabilityMeasure_paretoMeasure ht hr
+ rw [cdf_eq_toReal, paretoMeasure, withDensity_apply _ measurableSet_Iic]
+ refine (integral_eq_lintegral_of_nonneg_ae ?_ ?_).symm
+ · exact ae_of_all _ fun _ ↦ by simp only [Pi.zero_apply, paretoPDFReal_nonneg ht.le hr.le]
+ · exact (measurable_paretoPDFReal t r).aestronglyMeasurable.restrict
+
+lemma paretoCDFReal_eq_lintegral (ht : 0 < t) (hr : 0 < r) (x : ℝ) :
+ cdf (paretoMeasure t r) x = ENNReal.toReal (∫⁻ x in Iic x, paretoPDF t r x) := by
+ have : IsProbabilityMeasure (paretoMeasure t r) := isProbabilityMeasure_paretoMeasure ht hr
+ rw [cdf_eq_toReal, paretoMeasure, withDensity_apply _ measurableSet_Iic]
+
+end ParetoCDF
+end ProbabilityTheory
diff --git a/Mathlib/Probability/Distributions/Uniform.lean b/Mathlib/Probability/Distributions/Uniform.lean
index 67f4746b80fcf..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
@@ -346,7 +346,7 @@ theorem mem_support_ofMultiset_iff (a : α) : a ∈ (ofMultiset s hs).support
theorem ofMultiset_apply_of_not_mem {a : α} (ha : a ∉ s) : ofMultiset s hs a = 0 := by
simpa only [ofMultiset_apply, ENNReal.div_eq_zero_iff, Nat.cast_eq_zero, Multiset.count_eq_zero,
- ENNReal.natCast_ne_top, or_false_iff] using ha
+ ENNReal.natCast_ne_top, or_false] using ha
section Measure
diff --git a/Mathlib/Probability/Independence/Basic.lean b/Mathlib/Probability/Independence/Basic.lean
index cd225daccfa3e..cfa5d0c19e7b7 100644
--- a/Mathlib/Probability/Independence/Basic.lean
+++ b/Mathlib/Probability/Independence/Basic.lean
@@ -64,6 +64,8 @@ when defining `μ` in the example above, the measurable space used is the last o
Part A, Chapter 4.
-/
+assert_not_exists MeasureTheory.Integrable
+
open MeasureTheory MeasurableSpace Set
open scoped MeasureTheory ENNReal
@@ -561,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 μ ↔
@@ -715,44 +722,3 @@ theorem iIndepSet.iIndepFun_indicator [Zero β] [One β] {m : MeasurableSpace β
end IndepFun
end ProbabilityTheory
-
-namespace MeasureTheory
-
-open Filter ProbabilityTheory
-open scoped NNReal Topology
-
-/-- If a nonzero function belongs to `ℒ^p` and is independent of another function, then
-the space is a probability space. -/
-lemma Memℒp.isProbabilityMeasure_of_indepFun
- {Ω : Type*} [MeasurableSpace Ω] {μ : Measure Ω}
- {E : Type*} [NormedAddCommGroup E] [MeasurableSpace E] [BorelSpace E]
- {F : Type*} [MeasurableSpace F]
- (f : Ω → E) (g : Ω → F) {p : ℝ≥0∞} (hp : p ≠ 0) (hp' : p ≠ ∞)
- (hℒp : Memℒp f p μ) (h'f : ¬(∀ᵐ ω ∂μ, f ω = 0)) (hindep : IndepFun f g μ) :
- IsProbabilityMeasure μ := by
- obtain ⟨c, c_pos, hc⟩ : ∃ (c : ℝ≥0), 0 < c ∧ 0 < μ {ω | c ≤ ‖f ω‖₊} := by
- contrapose! h'f
- have A (c : ℝ≥0) (hc : 0 < c) : ∀ᵐ ω ∂μ, ‖f ω‖₊ < c := by simpa [ae_iff] using h'f c hc
- obtain ⟨u, -, u_pos, u_lim⟩ : ∃ u, StrictAnti u ∧ (∀ (n : ℕ), 0 < u n)
- ∧ Tendsto u atTop (𝓝 0) := exists_seq_strictAnti_tendsto (0 : ℝ≥0)
- filter_upwards [ae_all_iff.2 (fun n ↦ A (u n) (u_pos n))] with ω hω
- simpa using ge_of_tendsto' u_lim (fun i ↦ (hω i).le)
- have h'c : μ {ω | c ≤ ‖f ω‖₊} < ∞ := hℒp.meas_ge_lt_top hp hp' c_pos.ne'
- have := hindep.measure_inter_preimage_eq_mul {x | c ≤ ‖x‖₊} Set.univ
- (isClosed_le continuous_const continuous_nnnorm).measurableSet MeasurableSet.univ
- simp only [Set.preimage_setOf_eq, Set.preimage_univ, Set.inter_univ] at this
- exact ⟨(ENNReal.mul_eq_left hc.ne' h'c.ne).1 this.symm⟩
-
-/-- If a nonzero function is integrable and is independent of another function, then
-the space is a probability space. -/
-lemma Integrable.isProbabilityMeasure_of_indepFun
- {Ω : Type*} [MeasurableSpace Ω] {μ : Measure Ω}
- {E : Type*} [NormedAddCommGroup E] [MeasurableSpace E] [BorelSpace E]
- {F : Type*} [MeasurableSpace F]
- (f : Ω → E) (g : Ω → F)
- (hf : Integrable f μ) (h'f : ¬(∀ᵐ ω ∂μ, f ω = 0)) (hindep : IndepFun f g μ) :
- IsProbabilityMeasure μ :=
- Memℒp.isProbabilityMeasure_of_indepFun f g one_ne_zero ENNReal.one_ne_top
- (memℒp_one_iff_integrable.mpr hf) h'f hindep
-
-end MeasureTheory
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/Integrable.lean b/Mathlib/Probability/Independence/Integrable.lean
new file mode 100644
index 0000000000000..c33b372d816a2
--- /dev/null
+++ b/Mathlib/Probability/Independence/Integrable.lean
@@ -0,0 +1,54 @@
+/-
+Copyright (c) 2024 Sébastien Gouëzel. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Sébastien Gouëzel
+-/
+import Mathlib.MeasureTheory.Function.L1Space
+import Mathlib.Probability.Independence.Basic
+
+/-!
+# Independence of functions implies that the measure is a probability measure
+
+If a nonzero function belongs to `ℒ^p` (in particular if it is integrable) and is independent
+of another function, then the space is a probability space.
+
+-/
+
+open Filter ProbabilityTheory
+
+open scoped ENNReal NNReal Topology
+
+namespace MeasureTheory
+
+variable {Ω E F: Type*} [MeasurableSpace Ω] {μ : Measure Ω}
+ [NormedAddCommGroup E] [MeasurableSpace E] [BorelSpace E]
+ [MeasurableSpace F]
+
+/-- If a nonzero function belongs to `ℒ^p` and is independent of another function, then
+the space is a probability space. -/
+lemma Memℒp.isProbabilityMeasure_of_indepFun
+ (f : Ω → E) (g : Ω → F) {p : ℝ≥0∞} (hp : p ≠ 0) (hp' : p ≠ ∞)
+ (hℒp : Memℒp f p μ) (h'f : ¬ (∀ᵐ ω ∂μ, f ω = 0)) (hindep : IndepFun f g μ) :
+ IsProbabilityMeasure μ := by
+ obtain ⟨c, c_pos, hc⟩ : ∃ (c : ℝ≥0), 0 < c ∧ 0 < μ {ω | c ≤ ‖f ω‖₊} := by
+ contrapose! h'f
+ have A (c : ℝ≥0) (hc : 0 < c) : ∀ᵐ ω ∂μ, ‖f ω‖₊ < c := by simpa [ae_iff] using h'f c hc
+ obtain ⟨u, -, u_pos, u_lim⟩ : ∃ u, StrictAnti u ∧ (∀ (n : ℕ), 0 < u n)
+ ∧ Tendsto u atTop (𝓝 0) := exists_seq_strictAnti_tendsto (0 : ℝ≥0)
+ filter_upwards [ae_all_iff.2 (fun n ↦ A (u n) (u_pos n))] with ω hω
+ simpa using ge_of_tendsto' u_lim (fun i ↦ (hω i).le)
+ have h'c : μ {ω | c ≤ ‖f ω‖₊} < ∞ := hℒp.meas_ge_lt_top hp hp' c_pos.ne'
+ have := hindep.measure_inter_preimage_eq_mul {x | c ≤ ‖x‖₊} Set.univ
+ (isClosed_le continuous_const continuous_nnnorm).measurableSet MeasurableSet.univ
+ simp only [Set.preimage_setOf_eq, Set.preimage_univ, Set.inter_univ] at this
+ exact ⟨(ENNReal.mul_eq_left hc.ne' h'c.ne).1 this.symm⟩
+
+/-- If a nonzero function is integrable and is independent of another function, then
+the space is a probability space. -/
+lemma Integrable.isProbabilityMeasure_of_indepFun (f : Ω → E) (g : Ω → F)
+ (hf : Integrable f μ) (h'f : ¬ (∀ᵐ ω ∂μ, f ω = 0)) (hindep : IndepFun f g μ) :
+ IsProbabilityMeasure μ :=
+ Memℒp.isProbabilityMeasure_of_indepFun f g one_ne_zero ENNReal.one_ne_top
+ (memℒp_one_iff_integrable.mpr hf) h'f hindep
+
+end MeasureTheory
diff --git a/Mathlib/Probability/Independence/Kernel.lean b/Mathlib/Probability/Independence/Kernel.lean
index ed4fbcb838ea5..cf48a19edc339 100644
--- a/Mathlib/Probability/Independence/Kernel.lean
+++ b/Mathlib/Probability/Independence/Kernel.lean
@@ -5,6 +5,7 @@ Authors: Rémy Degenne
-/
import Mathlib.MeasureTheory.Constructions.Pi
import Mathlib.Probability.Kernel.Basic
+import Mathlib.Tactic.Peel
/-!
# Independence with respect to a kernel and a measure
@@ -826,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) :
@@ -906,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 2c9a8b8c7a5cb..b4ac72bc2f810 100644
--- a/Mathlib/Probability/Kernel/Basic.lean
+++ b/Mathlib/Probability/Kernel/Basic.lean
@@ -3,387 +3,44 @@ Copyright (c) 2022 Rémy Degenne. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Rémy Degenne
-/
-import Mathlib.MeasureTheory.Integral.Bochner
-import Mathlib.MeasureTheory.Measure.GiryMonad
+import Mathlib.Probability.Kernel.Defs
/-!
-# Markov Kernels
+# Basic kernels
-A kernel from a measurable space `α` to another measurable space `β` is a measurable map
-`α → MeasureTheory.Measure β`, where the measurable space instance on `measure β` is the one defined
-in `MeasureTheory.Measure.instMeasurableSpace`. That is, a kernel `κ` verifies that for all
-measurable sets `s` of `β`, `a ↦ κ a s` is measurable.
+This file contains basic results about kernels in general and definitions of some particular
+kernels.
## Main definitions
-Classes of kernels:
-* `ProbabilityTheory.Kernel α β`: kernels from `α` to `β`.
-* `ProbabilityTheory.IsMarkovKernel κ`: a kernel from `α` to `β` is said to be a Markov kernel
- if for all `a : α`, `k a` is a probability measure.
-* `ProbabilityTheory.IsZeroOrMarkovKernel κ`: a kernel from `α` to `β` which is zero or
- a Markov kernel.
-* `ProbabilityTheory.IsFiniteKernel κ`: a kernel from `α` to `β` is said to be finite if there
- exists `C : ℝ≥0∞` such that `C < ∞` and for all `a : α`, `κ a univ ≤ C`. This implies in
- particular that all measures in the image of `κ` are finite, but is stronger since it requires a
- uniform bound. This stronger condition is necessary to ensure that the composition of two finite
- kernels is finite.
-* `ProbabilityTheory.IsSFiniteKernel κ`: a kernel is called s-finite if it is a countable
- sum of finite kernels.
-
-Particular kernels:
* `ProbabilityTheory.Kernel.deterministic (f : α → β) (hf : Measurable f)`:
kernel `a ↦ Measure.dirac (f a)`.
* `ProbabilityTheory.Kernel.const α (μβ : measure β)`: constant kernel `a ↦ μβ`.
* `ProbabilityTheory.Kernel.restrict κ (hs : MeasurableSet s)`: kernel for which the image of
`a : α` is `(κ a).restrict s`.
Integral: `∫⁻ b, f b ∂(κ.restrict hs a) = ∫⁻ b in s, f b ∂(κ a)`
+* `ProbabilityTheory.Kernel.comapRight`: Kernel with value `(κ a).comap f`,
+ for a measurable embedding `f`. That is, for a measurable set `t : Set β`,
+ `ProbabilityTheory.Kernel.comapRight κ hf a t = κ a (f '' t)`
+* `ProbabilityTheory.Kernel.piecewise (hs : MeasurableSet s) κ η`: the kernel equal to `κ`
+ on the measurable set `s` and to `η` on its complement.
## Main statements
-* `ProbabilityTheory.Kernel.ext_fun`: if `∫⁻ b, f b ∂(κ a) = ∫⁻ b, f b ∂(η a)` for all measurable
- functions `f` and all `a`, then the two kernels `κ` and `η` are equal.
-
-/
+assert_not_exists MeasureTheory.integral
open MeasureTheory
-open scoped MeasureTheory ENNReal NNReal
+open scoped ENNReal
namespace ProbabilityTheory
-/-- A kernel from a measurable space `α` to another measurable space `β` is a measurable function
-`κ : α → Measure β`. The measurable space structure on `MeasureTheory.Measure β` is given by
-`MeasureTheory.Measure.instMeasurableSpace`. A map `κ : α → MeasureTheory.Measure β` is measurable
-iff `∀ s : Set β, MeasurableSet s → Measurable (fun a ↦ κ a s)`. -/
-structure Kernel (α β : Type*) [MeasurableSpace α] [MeasurableSpace β] where
- /-- The underlying function of a kernel.
-
- Do not use this function directly. Instead use the coercion coming from the `DFunLike`
- instance. -/
- toFun : α → Measure β
- /-- A kernel is a measurable map.
-
- Do not use this lemma directly. Use `Kernel.measurable` instead. -/
- measurable' : Measurable toFun
-
-@[deprecated (since := "2024-07-22")] alias kernel := Kernel
-
-/-- Notation for `Kernel` with respect to a non-standard σ-algebra in the domain. -/
-scoped notation "Kernel[" mα "]" α:arg β:arg => @Kernel α β mα _
-
-/-- Notation for `Kernel` with respect to a non-standard σ-algebra in the domain and codomain. -/
-scoped notation "Kernel[" mα ", " mβ "]" α:arg β:arg => @Kernel α β mα mβ
-
-variable {α β ι : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β}
-
-namespace Kernel
-
-instance instFunLike : FunLike (Kernel α β) α (Measure β) where
- coe := toFun
- coe_injective' f g h := by cases f; cases g; congr
-
-lemma measurable (κ : Kernel α β) : Measurable κ := κ.measurable'
-@[simp, norm_cast] lemma coe_mk (f : α → Measure β) (hf) : mk f hf = f := rfl
-
-initialize_simps_projections Kernel (toFun → apply)
-
-instance instZero : Zero (Kernel α β) where zero := ⟨0, measurable_zero⟩
-noncomputable instance instAdd : Add (Kernel α β) where add κ η := ⟨κ + η, κ.2.add η.2⟩
-noncomputable instance instSMulNat : SMul ℕ (Kernel α β) where
- smul n κ := ⟨n • κ, (measurable_const (a := n)).smul κ.2⟩
-
-@[simp, norm_cast] lemma coe_zero : ⇑(0 : Kernel α β) = 0 := rfl
-@[simp, norm_cast] lemma coe_add (κ η : Kernel α β) : ⇑(κ + η) = κ + η := rfl
-@[simp, norm_cast] lemma coe_nsmul (n : ℕ) (κ : Kernel α β) : ⇑(n • κ) = n • κ := rfl
-
-@[simp] lemma zero_apply (a : α) : (0 : Kernel α β) a = 0 := rfl
-@[simp] lemma add_apply (κ η : Kernel α β) (a : α) : (κ + η) a = κ a + η a := rfl
-@[simp] lemma nsmul_apply (n : ℕ) (κ : Kernel α β) (a : α) : (n • κ) a = n • κ a := rfl
-
-noncomputable instance instAddCommMonoid : AddCommMonoid (Kernel α β) :=
- DFunLike.coe_injective.addCommMonoid _ coe_zero coe_add (by intros; rfl)
-
-instance instPartialOrder : PartialOrder (Kernel α β) := .lift _ DFunLike.coe_injective
-
-instance instCovariantAddLE {α β : Type*} [MeasurableSpace α] [MeasurableSpace β] :
- CovariantClass (Kernel α β) (Kernel α β) (· + ·) (· ≤ ·) :=
- ⟨fun _ _ _ hμ a ↦ add_le_add_left (hμ a) _⟩
-
-noncomputable
-instance instOrderBot {α β : Type*} [MeasurableSpace α] [MeasurableSpace β] :
- OrderBot (Kernel α β) where
- bot := 0
- bot_le κ a := by simp only [coe_zero, Pi.zero_apply, Measure.zero_le]
-
-/-- Coercion to a function as an additive monoid homomorphism. -/
-def coeAddHom (α β : Type*) [MeasurableSpace α] [MeasurableSpace β] :
- Kernel α β →+ α → Measure β where
- toFun := (⇑)
- map_zero' := coe_zero
- map_add' := coe_add
-
-@[simp]
-theorem coe_finset_sum (I : Finset ι) (κ : ι → Kernel α β) : ⇑(∑ i ∈ I, κ i) = ∑ i ∈ I, ⇑(κ i) :=
- map_sum (coeAddHom α β) _ _
-
-theorem finset_sum_apply (I : Finset ι) (κ : ι → Kernel α β) (a : α) :
- (∑ i ∈ I, κ i) a = ∑ i ∈ I, κ i a := by rw [coe_finset_sum, Finset.sum_apply]
-
-theorem finset_sum_apply' (I : Finset ι) (κ : ι → Kernel α β) (a : α) (s : Set β) :
- (∑ i ∈ I, κ i) a s = ∑ i ∈ I, κ i a s := by rw [finset_sum_apply, Measure.finset_sum_apply]
-
-end Kernel
-
-/-- A kernel is a Markov kernel if every measure in its image is a probability measure. -/
-class IsMarkovKernel (κ : Kernel α β) : Prop where
- isProbabilityMeasure : ∀ a, IsProbabilityMeasure (κ a)
-
-/-- A class for kernels which are zero or a Markov kernel. -/
-class IsZeroOrMarkovKernel (κ : Kernel α β) : Prop where
- eq_zero_or_isMarkovKernel' : κ = 0 ∨ IsMarkovKernel κ
-
-/-- A kernel is finite if every measure in its image is finite, with a uniform bound. -/
-class IsFiniteKernel (κ : Kernel α β) : Prop where
- exists_univ_le : ∃ C : ℝ≥0∞, C < ∞ ∧ ∀ a, κ a Set.univ ≤ C
-
-theorem eq_zero_or_isMarkovKernel
- (κ : Kernel α β) [h : IsZeroOrMarkovKernel κ] :
- κ = 0 ∨ IsMarkovKernel κ :=
- h.eq_zero_or_isMarkovKernel'
-
-/-- A constant `C : ℝ≥0∞` such that `C < ∞` (`ProbabilityTheory.IsFiniteKernel.bound_lt_top κ`) and
-for all `a : α` and `s : Set β`, `κ a s ≤ C` (`ProbabilityTheory.Kernel.measure_le_bound κ a s`).
-
-Porting note (#11215): TODO: does it make sense to
--- make `ProbabilityTheory.IsFiniteKernel.bound` the least possible bound?
--- Should it be an `NNReal` number? -/
-noncomputable def IsFiniteKernel.bound (κ : Kernel α β) [h : IsFiniteKernel κ] : ℝ≥0∞ :=
- h.exists_univ_le.choose
-
-theorem IsFiniteKernel.bound_lt_top (κ : Kernel α β) [h : IsFiniteKernel κ] :
- IsFiniteKernel.bound κ < ∞ :=
- h.exists_univ_le.choose_spec.1
-
-theorem IsFiniteKernel.bound_ne_top (κ : Kernel α β) [IsFiniteKernel κ] :
- IsFiniteKernel.bound κ ≠ ∞ :=
- (IsFiniteKernel.bound_lt_top κ).ne
-
-theorem Kernel.measure_le_bound (κ : Kernel α β) [h : IsFiniteKernel κ] (a : α) (s : Set β) :
- κ 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 β} :
- IsFiniteKernel (0 : Kernel α β) :=
- ⟨⟨0, ENNReal.coe_lt_top, fun _ => by
- simp only [Kernel.zero_apply, Measure.coe_zero, Pi.zero_apply, le_zero_iff]⟩⟩
-
-instance IsFiniteKernel.add (κ η : Kernel α β) [IsFiniteKernel κ] [IsFiniteKernel η] :
- IsFiniteKernel (κ + η) := by
- refine ⟨⟨IsFiniteKernel.bound κ + IsFiniteKernel.bound η,
- ENNReal.add_lt_top.mpr ⟨IsFiniteKernel.bound_lt_top κ, IsFiniteKernel.bound_lt_top η⟩,
- fun a => ?_⟩⟩
- exact add_le_add (Kernel.measure_le_bound _ _ _) (Kernel.measure_le_bound _ _ _)
-
-lemma isFiniteKernel_of_le {κ ν : Kernel α β} [hν : IsFiniteKernel ν] (hκν : κ ≤ ν) :
- IsFiniteKernel κ := by
- refine ⟨hν.bound, hν.bound_lt_top, fun a ↦ (hκν _ _).trans (Kernel.measure_le_bound ν a Set.univ)⟩
-
-variable {κ : Kernel α β}
-
-instance IsMarkovKernel.is_probability_measure' [IsMarkovKernel κ] (a : α) :
- IsProbabilityMeasure (κ a) :=
- IsMarkovKernel.isProbabilityMeasure a
-
-instance : IsZeroOrMarkovKernel (0 : Kernel α β) := ⟨Or.inl rfl⟩
-
-instance (priority := 100) IsMarkovKernel.IsZeroOrMarkovKernel [h : IsMarkovKernel κ] :
- IsZeroOrMarkovKernel κ := ⟨Or.inr h⟩
-
-instance (priority := 100) IsZeroOrMarkovKernel.isZeroOrProbabilityMeasure
- [IsZeroOrMarkovKernel κ] (a : α) : IsZeroOrProbabilityMeasure (κ a) := by
- rcases eq_zero_or_isMarkovKernel κ with rfl | h'
- · simp only [Kernel.zero_apply]
- infer_instance
- · infer_instance
-
-instance IsFiniteKernel.isFiniteMeasure [IsFiniteKernel κ] (a : α) : IsFiniteMeasure (κ a) :=
- ⟨(Kernel.measure_le_bound κ a Set.univ).trans_lt (IsFiniteKernel.bound_lt_top κ)⟩
-
-instance (priority := 100) IsZeroOrMarkovKernel.isFiniteKernel [h : IsZeroOrMarkovKernel κ] :
- IsFiniteKernel κ := by
- rcases eq_zero_or_isMarkovKernel κ with rfl | _h'
- · infer_instance
- · exact ⟨⟨1, ENNReal.one_lt_top, fun _ => prob_le_one⟩⟩
+variable {α β ι : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {κ : Kernel α β}
namespace Kernel
-@[ext]
-theorem ext {η : Kernel α β} (h : ∀ a, κ a = η a) : κ = η := DFunLike.ext _ _ h
-
-theorem ext_iff' {η : Kernel α β} :
- κ = η ↔ ∀ a s, MeasurableSet s → κ a s = η a s := by
- simp_rw [Kernel.ext_iff, Measure.ext_iff]
-
-theorem ext_fun {η : Kernel α β} (h : ∀ a f, Measurable f → ∫⁻ b, f b ∂κ a = ∫⁻ b, f b ∂η a) :
- κ = η := by
- ext a s hs
- specialize h a (s.indicator fun _ => 1) (Measurable.indicator measurable_const hs)
- simp_rw [lintegral_indicator_const hs, one_mul] at h
- rw [h]
-
-theorem ext_fun_iff {η : Kernel α β} :
- κ = η ↔ ∀ a f, Measurable f → ∫⁻ b, f b ∂κ a = ∫⁻ b, f b ∂η a :=
- ⟨fun h a f _ => by rw [h], ext_fun⟩
-
-protected theorem measurable_coe (κ : Kernel α β) {s : Set β} (hs : MeasurableSet s) :
- Measurable fun a => κ a s :=
- (Measure.measurable_coe hs).comp κ.measurable
-
-lemma apply_congr_of_mem_measurableAtom (κ : Kernel α β) {y' y : α} (hy' : y' ∈ measurableAtom y) :
- κ y' = κ y := by
- ext s hs
- exact mem_of_mem_measurableAtom hy' (κ.measurable_coe hs (measurableSet_singleton (κ y s))) rfl
-
-lemma IsFiniteKernel.integrable (μ : Measure α) [IsFiniteMeasure μ]
- (κ : Kernel α β) [IsFiniteKernel κ] {s : Set β} (hs : MeasurableSet s) :
- Integrable (fun x => (κ x s).toReal) μ := by
- refine Integrable.mono' (integrable_const (IsFiniteKernel.bound κ).toReal)
- ((κ.measurable_coe hs).ennreal_toReal.aestronglyMeasurable)
- (ae_of_all μ fun x => ?_)
- rw [Real.norm_eq_abs, abs_of_nonneg ENNReal.toReal_nonneg,
- ENNReal.toReal_le_toReal (measure_ne_top _ _) (IsFiniteKernel.bound_ne_top _)]
- exact Kernel.measure_le_bound _ _ _
-
-lemma IsMarkovKernel.integrable (μ : Measure α) [IsFiniteMeasure μ]
- (κ : Kernel α β) [IsMarkovKernel κ] {s : Set β} (hs : MeasurableSet s) :
- Integrable (fun x => (κ x s).toReal) μ :=
- IsFiniteKernel.integrable μ κ hs
-
-lemma integral_congr_ae₂ {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {f g : α → β → E}
- {μ : Measure α} (h : ∀ᵐ a ∂μ, f a =ᵐ[κ a] g a) :
- ∫ a, ∫ b, f a b ∂(κ a) ∂μ = ∫ a, ∫ b, g a b ∂(κ a) ∂μ := by
- apply integral_congr_ae
- filter_upwards [h] with _ ha
- apply integral_congr_ae
- filter_upwards [ha] with _ hb using hb
-
-section Sum
-
-/-- Sum of an indexed family of kernels. -/
-protected noncomputable def sum [Countable ι] (κ : ι → Kernel α β) : Kernel α β where
- toFun a := Measure.sum fun n => κ n a
- measurable' := by
- refine Measure.measurable_of_measurable_coe _ fun s hs => ?_
- simp_rw [Measure.sum_apply _ hs]
- exact Measurable.ennreal_tsum fun n => Kernel.measurable_coe (κ n) hs
-
-theorem sum_apply [Countable ι] (κ : ι → Kernel α β) (a : α) :
- Kernel.sum κ a = Measure.sum fun n => κ n a :=
- rfl
-
-theorem sum_apply' [Countable ι] (κ : ι → Kernel α β) (a : α) {s : Set β} (hs : MeasurableSet s) :
- Kernel.sum κ a s = ∑' n, κ n a s := by rw [sum_apply κ a, Measure.sum_apply _ hs]
-
-@[simp]
-theorem sum_zero [Countable ι] : (Kernel.sum fun _ : ι => (0 : Kernel α β)) = 0 := by
- ext a s hs
- rw [sum_apply' _ a hs]
- simp only [zero_apply, Measure.coe_zero, Pi.zero_apply, tsum_zero]
-
-theorem sum_comm [Countable ι] (κ : ι → ι → Kernel α β) :
- (Kernel.sum fun n => Kernel.sum (κ n)) = Kernel.sum fun m => Kernel.sum fun n => κ n m := by
- ext a s; simp_rw [sum_apply]; rw [Measure.sum_comm]
-
-@[simp]
-theorem sum_fintype [Fintype ι] (κ : ι → Kernel α β) : Kernel.sum κ = ∑ i, κ i := by
- ext a s hs
- simp only [sum_apply' κ a hs, finset_sum_apply' _ κ a s, tsum_fintype]
-
-theorem sum_add [Countable ι] (κ η : ι → Kernel α β) :
- (Kernel.sum fun n => κ n + η n) = Kernel.sum κ + Kernel.sum η := by
- ext a s hs
- simp only [coe_add, Pi.add_apply, sum_apply, Measure.sum_apply _ hs, Pi.add_apply,
- Measure.coe_add, tsum_add ENNReal.summable ENNReal.summable]
-
-end Sum
-
-section SFinite
-
-/-- A kernel is s-finite if it can be written as the sum of countably many finite kernels. -/
-class _root_.ProbabilityTheory.IsSFiniteKernel (κ : Kernel α β) : Prop where
- tsum_finite : ∃ κs : ℕ → Kernel α β, (∀ n, IsFiniteKernel (κs n)) ∧ κ = Kernel.sum κs
-
-instance (priority := 100) IsFiniteKernel.isSFiniteKernel [h : IsFiniteKernel κ] :
- IsSFiniteKernel κ :=
- ⟨⟨fun n => if n = 0 then κ else 0, fun n => by
- simp only; split_ifs
- · exact h
- · infer_instance, by
- ext a s hs
- rw [Kernel.sum_apply' _ _ hs]
- have : (fun i => ((ite (i = 0) κ 0) a) s) = fun i => ite (i = 0) (κ a s) 0 := by
- ext1 i; split_ifs <;> rfl
- rw [this, tsum_ite_eq]⟩⟩
-
-/-- A sequence of finite kernels such that `κ = ProbabilityTheory.Kernel.sum (seq κ)`. See
-`ProbabilityTheory.Kernel.isFiniteKernel_seq` and `ProbabilityTheory.Kernel.kernel_sum_seq`. -/
-noncomputable def seq (κ : Kernel α β) [h : IsSFiniteKernel κ] : ℕ → Kernel α β :=
- h.tsum_finite.choose
-
-theorem kernel_sum_seq (κ : Kernel α β) [h : IsSFiniteKernel κ] : Kernel.sum (seq κ) = κ :=
- h.tsum_finite.choose_spec.2.symm
-
-theorem measure_sum_seq (κ : Kernel α β) [h : IsSFiniteKernel κ] (a : α) :
- (Measure.sum fun n => seq κ n a) = κ a := by rw [← Kernel.sum_apply, kernel_sum_seq κ]
-
-instance isFiniteKernel_seq (κ : Kernel α β) [h : IsSFiniteKernel κ] (n : ℕ) :
- IsFiniteKernel (Kernel.seq κ n) :=
- h.tsum_finite.choose_spec.1 n
-
-instance _root_.ProbabilityTheory.IsSFiniteKernel.sFinite [IsSFiniteKernel κ] (a : α) :
- SFinite (κ a) :=
- ⟨⟨fun n ↦ seq κ n a, inferInstance, (measure_sum_seq κ a).symm⟩⟩
-
-instance IsSFiniteKernel.add (κ η : Kernel α β) [IsSFiniteKernel κ] [IsSFiniteKernel η] :
- IsSFiniteKernel (κ + η) := by
- refine ⟨⟨fun n => seq κ n + seq η n, fun n => inferInstance, ?_⟩⟩
- rw [sum_add, kernel_sum_seq κ, kernel_sum_seq η]
-
-theorem IsSFiniteKernel.finset_sum {κs : ι → Kernel α β} (I : Finset ι)
- (h : ∀ i ∈ I, IsSFiniteKernel (κs i)) : IsSFiniteKernel (∑ i ∈ I, κs i) := by
- classical
- induction' I using Finset.induction with i I hi_nmem_I h_ind h
- · rw [Finset.sum_empty]; infer_instance
- · rw [Finset.sum_insert hi_nmem_I]
- haveI : IsSFiniteKernel (κs i) := h i (Finset.mem_insert_self _ _)
- have : IsSFiniteKernel (∑ x ∈ I, κs x) :=
- h_ind fun i hiI => h i (Finset.mem_insert_of_mem hiI)
- exact IsSFiniteKernel.add _ _
-
-theorem isSFiniteKernel_sum_of_denumerable [Denumerable ι] {κs : ι → Kernel α β}
- (hκs : ∀ n, IsSFiniteKernel (κs n)) : IsSFiniteKernel (Kernel.sum κs) := by
- let e : ℕ ≃ ι × ℕ := (Denumerable.eqv (ι × ℕ)).symm
- refine ⟨⟨fun n => seq (κs (e n).1) (e n).2, inferInstance, ?_⟩⟩
- have hκ_eq : Kernel.sum κs = Kernel.sum fun n => Kernel.sum (seq (κs n)) := by
- simp_rw [kernel_sum_seq]
- ext a s hs
- rw [hκ_eq]
- simp_rw [Kernel.sum_apply' _ _ hs]
- change (∑' i, ∑' m, seq (κs i) m a s) = ∑' n, (fun im : ι × ℕ => seq (κs im.fst) im.snd a s) (e n)
- rw [e.tsum_eq (fun im : ι × ℕ => seq (κs im.fst) im.snd a s),
- tsum_prod' ENNReal.summable fun _ => ENNReal.summable]
-
-theorem isSFiniteKernel_sum [Countable ι] {κs : ι → Kernel α β}
- (hκs : ∀ n, IsSFiniteKernel (κs n)) : IsSFiniteKernel (Kernel.sum κs) := by
- cases fintypeOrInfinite ι
- · rw [sum_fintype]
- exact IsSFiniteKernel.finset_sum Finset.univ fun i _ => hκs i
- cases nonempty_denumerable ι
- exact isSFiniteKernel_sum_of_denumerable hκs
-
-end SFinite
-
section Deterministic
/-- Kernel which to `a` associates the dirac measure at `f a`. This is a Markov kernel. -/
@@ -434,36 +91,6 @@ theorem setLIntegral_deterministic {f : β → ℝ≥0∞} {g : α → β} {a :
@[deprecated (since := "2024-06-29")]
alias set_lintegral_deterministic := setLIntegral_deterministic
-theorem integral_deterministic' {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- [CompleteSpace E] {f : β → E} {g : α → β} {a : α} (hg : Measurable g)
- (hf : StronglyMeasurable f) : ∫ x, f x ∂deterministic g hg a = f (g a) := by
- rw [deterministic_apply, integral_dirac' _ _ hf]
-
-@[simp]
-theorem integral_deterministic {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- [CompleteSpace E] {f : β → E} {g : α → β} {a : α} (hg : Measurable g)
- [MeasurableSingletonClass β] : ∫ x, f x ∂deterministic g hg a = f (g a) := by
- rw [deterministic_apply, integral_dirac _ (g a)]
-
-theorem setIntegral_deterministic' {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- [CompleteSpace E] {f : β → E} {g : α → β} {a : α} (hg : Measurable g)
- (hf : StronglyMeasurable f) {s : Set β} (hs : MeasurableSet s) [Decidable (g a ∈ s)] :
- ∫ x in s, f x ∂deterministic g hg a = if g a ∈ s then f (g a) else 0 := by
- rw [deterministic_apply, setIntegral_dirac' hf _ hs]
-
-@[deprecated (since := "2024-04-17")]
-alias set_integral_deterministic' := setIntegral_deterministic'
-
-@[simp]
-theorem setIntegral_deterministic {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- [CompleteSpace E] {f : β → E} {g : α → β} {a : α} (hg : Measurable g)
- [MeasurableSingletonClass β] (s : Set β) [Decidable (g a ∈ s)] :
- ∫ x in s, f x ∂deterministic g hg a = if g a ∈ s then f (g a) else 0 := by
- rw [deterministic_apply, setIntegral_dirac f _ s]
-
-@[deprecated (since := "2024-04-17")]
-alias set_integral_deterministic := setIntegral_deterministic
-
end Deterministic
section Const
@@ -497,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 α μβ) :=
@@ -525,19 +152,6 @@ theorem setLIntegral_const {f : β → ℝ≥0∞} {μ : Measure β} {a : α} {s
@[deprecated (since := "2024-06-29")]
alias set_lintegral_const := setLIntegral_const
-@[simp]
-theorem integral_const {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- {f : β → E} {μ : Measure β} {a : α} : ∫ x, f x ∂const α μ a = ∫ x, f x ∂μ := by
- rw [const_apply]
-
-@[simp]
-theorem setIntegral_const {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- {f : β → E} {μ : Measure β} {a : α} {s : Set β} :
- ∫ x in s, f x ∂const α μ a = ∫ x in s, f x ∂μ := by rw [const_apply]
-
-@[deprecated (since := "2024-04-17")]
-alias set_integral_const := setIntegral_const
-
end Const
/-- In a countable space with measurable singletons, every function `α → MeasureTheory.Measure β`
@@ -584,14 +198,6 @@ theorem setLIntegral_restrict (κ : Kernel α β) (hs : MeasurableSet s) (a : α
@[deprecated (since := "2024-06-29")]
alias set_lintegral_restrict := setLIntegral_restrict
-@[simp]
-theorem setIntegral_restrict {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- {f : β → E} {a : α} (hs : MeasurableSet s) (t : Set β) :
- ∫ x in t, f x ∂κ.restrict hs a = ∫ x in t ∩ s, f x ∂κ a := by
- rw [restrict_apply, Measure.restrict_restrict' hs]
-
-@[deprecated (since := "2024-04-17")]
-alias set_integral_restrict := setIntegral_restrict
instance IsFiniteKernel.restrict (κ : Kernel α β) [IsFiniteKernel κ] (hs : MeasurableSet s) :
IsFiniteKernel (κ.restrict hs) := by
@@ -716,20 +322,6 @@ theorem setLIntegral_piecewise (a : α) (g : β → ℝ≥0∞) (t : Set β) :
@[deprecated (since := "2024-06-29")]
alias set_lintegral_piecewise := setLIntegral_piecewise
-theorem integral_piecewise {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- (a : α) (g : β → E) :
- ∫ b, g b ∂piecewise hs κ η a = if a ∈ s then ∫ b, g b ∂κ a else ∫ b, g b ∂η a := by
- simp_rw [piecewise_apply]; split_ifs <;> rfl
-
-theorem setIntegral_piecewise {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
- (a : α) (g : β → E) (t : Set β) :
- ∫ b in t, g b ∂piecewise hs κ η a =
- if a ∈ s then ∫ b in t, g b ∂κ a else ∫ b in t, g b ∂η a := by
- simp_rw [piecewise_apply]; split_ifs <;> rfl
-
-@[deprecated (since := "2024-04-17")]
-alias set_integral_piecewise := setIntegral_piecewise
-
end Piecewise
lemma exists_ae_eq_isMarkovKernel {μ : Measure α}
diff --git a/Mathlib/Probability/Kernel/Composition.lean b/Mathlib/Probability/Kernel/Composition.lean
index 97547030b3738..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
@@ -113,7 +113,7 @@ theorem compProdFun_iUnion (κ : Kernel α β) (η : Kernel (α × β) γ) [IsSF
Set.mem_empty_iff_false] using hf_disj hij hbci hbcj
· exact fun i ↦ measurable_prod_mk_left (hf_meas i)
rw [h_tsum, lintegral_tsum]
- · rfl
+ · simp [compProdFun]
· intro i
have hm : MeasurableSet {p : (α × β) × γ | (p.1.2, p.2) ∈ f i} :=
measurable_fst.snd.prod_mk measurable_snd (hf_meas i)
@@ -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,19 +229,51 @@ 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]
@[simp]
-lemma compProd_zero_right (κ : Kernel α β) (γ : Type*) [MeasurableSpace γ] :
+lemma compProd_zero_right (κ : Kernel α β) (γ : Type*) {mγ : MeasurableSpace γ} :
κ ⊗ₖ (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 :
@@ -320,11 +352,10 @@ theorem compProd_restrict {s : Set β} {t : Set γ} (hs : MeasurableSet s) (ht :
classical
rw [Set.indicator_apply]
split_ifs with h
- · simp only [h, true_and_iff]
- rfl
- · simp only [h, false_and_iff, and_false_iff, Set.setOf_false, measure_empty]
+ · 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
@@ -384,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
@@ -486,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
@@ -498,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
@@ -531,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
@@ -546,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]
@@ -567,7 +595,7 @@ section MapComap
/-! ### map, comap -/
-variable {γ δ : Type*} [MeasurableSpace γ] {mδ : MeasurableSpace δ} {f : β → γ} {g : γ → α}
+variable {γ δ : Type*} {mγ : MeasurableSpace γ} {mδ : MeasurableSpace δ} {f : β → γ} {g : γ → α}
/-- The pushforward of a kernel along a measurable function. This is an implementation detail,
use `map κ f` instead. -/
@@ -581,7 +609,7 @@ open Classical in
If the function is not measurable, we use zero instead. This choice of junk
value ensures that typeclass inference can infer that the `map` of a kernel
satisfying `IsZeroOrMarkovKernel` again satisfies this property. -/
-noncomputable def map (κ : Kernel α β) (f : β → γ) : Kernel α γ :=
+noncomputable def map [MeasurableSpace γ] (κ : Kernel α β) (f : β → γ) : Kernel α γ :=
if hf : Measurable f then mapOfMeasurable κ f hf else 0
theorem map_of_not_measurable (κ : Kernel α β) {f : β → γ} (hf : ¬(Measurable f)) :
@@ -593,8 +621,7 @@ theorem map_of_not_measurable (κ : Kernel α β) {f : β → γ} (hf : ¬(Measu
simp [map, hf]
theorem map_apply (κ : Kernel α β) (hf : Measurable f) (a : α) : map κ f a = (κ a).map f := by
- simp only [map, hf, ↓reduceDIte, mapOfMeasurable]
- rfl
+ simp only [map, hf, ↓reduceDIte, mapOfMeasurable, coe_mk]
theorem map_apply' (κ : Kernel α β) (hf : Measurable f) (a : α) {s : Set γ} (hs : MeasurableSet s) :
map κ f a s = κ a (f ⁻¹' s) := by rw [map_apply _ hf, Measure.map_apply hf hs]
@@ -665,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
@@ -729,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 :=
@@ -804,7 +834,7 @@ lemma map_prodMkLeft (γ : Type*) [MeasurableSpace γ] (κ : Kernel α β) (f :
rfl
· simp [map_of_not_measurable _ hf]
-lemma map_prodMkRight (κ : Kernel α β) (γ : Type*) [MeasurableSpace γ] (f : β → δ) :
+lemma map_prodMkRight (κ : Kernel α β) (γ : Type*) {mγ : MeasurableSpace γ} (f : β → δ) :
map (prodMkRight γ κ) f = prodMkRight γ (map κ f) := by
by_cases hf : Measurable f
· simp only [map, hf, ↓reduceDIte]
@@ -834,10 +864,10 @@ instance IsFiniteKernel.swapLeft (κ : Kernel (α × β) γ) [IsFiniteKernel κ]
instance IsSFiniteKernel.swapLeft (κ : Kernel (α × β) γ) [IsSFiniteKernel κ] :
IsSFiniteKernel (swapLeft κ) := by rw [Kernel.swapLeft]; infer_instance
-@[simp] lemma swapLeft_prodMkLeft (κ : Kernel α β) (γ : Type*) [MeasurableSpace γ] :
+@[simp] lemma swapLeft_prodMkLeft (κ : Kernel α β) (γ : Type*) {_ : MeasurableSpace γ} :
swapLeft (prodMkLeft γ κ) = prodMkRight γ κ := rfl
-@[simp] lemma swapLeft_prodMkRight (κ : Kernel α β) (γ : Type*) [MeasurableSpace γ] :
+@[simp] lemma swapLeft_prodMkRight (κ : Kernel α β) (γ : Type*) {_ : MeasurableSpace γ} :
swapLeft (prodMkRight γ κ) = prodMkLeft γ κ := rfl
/-- Define a `Kernel α (γ × β)` from a `Kernel α (β × γ)` by taking the map of `Prod.swap`.
@@ -916,8 +946,8 @@ lemma fst_map_prod (κ : Kernel α β) {f : β → γ} {g : β → δ} (hg : Mea
fst (map κ (fun x ↦ (f x, g x))) = map κ f := by
by_cases hf : Measurable f
· ext x s hs
- rw [fst_apply' _ _ hs, map_apply' _ (hf.prod hg), map_apply' _ hf _ hs]
- · rfl
+ rw [fst_apply' _ _ hs, map_apply' _ (hf.prod hg) _, map_apply' _ hf _ hs]
+ · simp only [Set.preimage, Set.mem_setOf]
· exact measurable_fst hs
· have : ¬ Measurable (fun x ↦ (f x, g x)) := by
contrapose! hf; exact hf.fst
@@ -993,7 +1023,7 @@ lemma snd_map_prod (κ : Kernel α β) {f : β → γ} {g : β → δ} (hf : Mea
by_cases hg : Measurable g
· ext x s hs
rw [snd_apply' _ _ hs, map_apply' _ (hf.prod hg), map_apply' _ hg _ hs]
- · rfl
+ · simp only [Set.preimage, Set.mem_setOf]
· exact measurable_snd hs
· have : ¬ Measurable (fun x ↦ (f x, g x)) := by
contrapose! hg; exact hg.snd
@@ -1031,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
@@ -1048,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
@@ -1087,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
@@ -1098,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 α (β × γ) :=
@@ -1116,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 : α) :
@@ -1160,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
new file mode 100644
index 0000000000000..df3b0dacc3a32
--- /dev/null
+++ b/Mathlib/Probability/Kernel/Defs.lean
@@ -0,0 +1,354 @@
+/-
+Copyright (c) 2022 Rémy Degenne. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Rémy Degenne
+-/
+import Mathlib.MeasureTheory.Measure.GiryMonad
+
+/-!
+# Markov Kernels
+
+A kernel from a measurable space `α` to another measurable space `β` is a measurable map
+`α → MeasureTheory.Measure β`, where the measurable space instance on `measure β` is the one defined
+in `MeasureTheory.Measure.instMeasurableSpace`. That is, a kernel `κ` verifies that for all
+measurable sets `s` of `β`, `a ↦ κ a s` is measurable.
+
+## Main definitions
+
+Classes of kernels:
+* `ProbabilityTheory.Kernel α β`: kernels from `α` to `β`.
+* `ProbabilityTheory.IsMarkovKernel κ`: a kernel from `α` to `β` is said to be a Markov kernel
+ if for all `a : α`, `k a` is a probability measure.
+* `ProbabilityTheory.IsZeroOrMarkovKernel κ`: a kernel from `α` to `β` which is zero or
+ a Markov kernel.
+* `ProbabilityTheory.IsFiniteKernel κ`: a kernel from `α` to `β` is said to be finite if there
+ exists `C : ℝ≥0∞` such that `C < ∞` and for all `a : α`, `κ a univ ≤ C`. This implies in
+ particular that all measures in the image of `κ` are finite, but is stronger since it requires a
+ uniform bound. This stronger condition is necessary to ensure that the composition of two finite
+ kernels is finite.
+* `ProbabilityTheory.IsSFiniteKernel κ`: a kernel is called s-finite if it is a countable
+ sum of finite kernels.
+
+## Main statements
+
+* `ProbabilityTheory.Kernel.ext_fun`: if `∫⁻ b, f b ∂(κ a) = ∫⁻ b, f b ∂(η a)` for all measurable
+ functions `f` and all `a`, then the two kernels `κ` and `η` are equal.
+
+-/
+
+assert_not_exists MeasureTheory.integral
+
+open MeasureTheory
+
+open scoped ENNReal
+
+namespace ProbabilityTheory
+
+/-- A kernel from a measurable space `α` to another measurable space `β` is a measurable function
+`κ : α → Measure β`. The measurable space structure on `MeasureTheory.Measure β` is given by
+`MeasureTheory.Measure.instMeasurableSpace`. A map `κ : α → MeasureTheory.Measure β` is measurable
+iff `∀ s : Set β, MeasurableSet s → Measurable (fun a ↦ κ a s)`. -/
+structure Kernel (α β : Type*) [MeasurableSpace α] [MeasurableSpace β] where
+ /-- The underlying function of a kernel.
+
+ Do not use this function directly. Instead use the coercion coming from the `DFunLike`
+ instance. -/
+ toFun : α → Measure β
+ /-- A kernel is a measurable map.
+
+ Do not use this lemma directly. Use `Kernel.measurable` instead. -/
+ measurable' : Measurable toFun
+
+@[deprecated (since := "2024-07-22")] alias kernel := Kernel
+
+/-- Notation for `Kernel` with respect to a non-standard σ-algebra in the domain. -/
+scoped notation "Kernel[" mα "]" α:arg β:arg => @Kernel α β mα _
+
+/-- Notation for `Kernel` with respect to a non-standard σ-algebra in the domain and codomain. -/
+scoped notation "Kernel[" mα ", " mβ "]" α:arg β:arg => @Kernel α β mα mβ
+
+variable {α β ι : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β}
+
+namespace Kernel
+
+instance instFunLike : FunLike (Kernel α β) α (Measure β) where
+ coe := toFun
+ coe_injective' f g h := by cases f; cases g; congr
+
+lemma measurable (κ : Kernel α β) : Measurable κ := κ.measurable'
+@[simp, norm_cast] lemma coe_mk (f : α → Measure β) (hf) : mk f hf = f := rfl
+
+initialize_simps_projections Kernel (toFun → apply)
+
+instance instZero : Zero (Kernel α β) where zero := ⟨0, measurable_zero⟩
+noncomputable instance instAdd : Add (Kernel α β) where add κ η := ⟨κ + η, κ.2.add η.2⟩
+noncomputable instance instSMulNat : SMul ℕ (Kernel α β) where
+ smul n κ := ⟨n • κ, (measurable_const (a := n)).smul κ.2⟩
+
+@[simp, norm_cast] lemma coe_zero : ⇑(0 : Kernel α β) = 0 := rfl
+@[simp, norm_cast] lemma coe_add (κ η : Kernel α β) : ⇑(κ + η) = κ + η := rfl
+@[simp, norm_cast] lemma coe_nsmul (n : ℕ) (κ : Kernel α β) : ⇑(n • κ) = n • κ := rfl
+
+@[simp] lemma zero_apply (a : α) : (0 : Kernel α β) a = 0 := rfl
+@[simp] lemma add_apply (κ η : Kernel α β) (a : α) : (κ + η) a = κ a + η a := rfl
+@[simp] lemma nsmul_apply (n : ℕ) (κ : Kernel α β) (a : α) : (n • κ) a = n • κ a := rfl
+
+noncomputable instance instAddCommMonoid : AddCommMonoid (Kernel α β) :=
+ DFunLike.coe_injective.addCommMonoid _ coe_zero coe_add (by intros; rfl)
+
+instance instPartialOrder : PartialOrder (Kernel α β) := .lift _ DFunLike.coe_injective
+
+instance instCovariantAddLE {α β : Type*} [MeasurableSpace α] [MeasurableSpace β] :
+ CovariantClass (Kernel α β) (Kernel α β) (· + ·) (· ≤ ·) :=
+ ⟨fun _ _ _ hμ a ↦ add_le_add_left (hμ a) _⟩
+
+noncomputable
+instance instOrderBot {α β : Type*} [MeasurableSpace α] [MeasurableSpace β] :
+ OrderBot (Kernel α β) where
+ bot := 0
+ bot_le κ a := by simp only [coe_zero, Pi.zero_apply, Measure.zero_le]
+
+/-- Coercion to a function as an additive monoid homomorphism. -/
+def coeAddHom (α β : Type*) [MeasurableSpace α] [MeasurableSpace β] :
+ Kernel α β →+ α → Measure β where
+ toFun := (⇑)
+ map_zero' := coe_zero
+ map_add' := coe_add
+
+@[simp]
+theorem coe_finset_sum (I : Finset ι) (κ : ι → Kernel α β) : ⇑(∑ i ∈ I, κ i) = ∑ i ∈ I, ⇑(κ i) :=
+ map_sum (coeAddHom α β) _ _
+
+theorem finset_sum_apply (I : Finset ι) (κ : ι → Kernel α β) (a : α) :
+ (∑ i ∈ I, κ i) a = ∑ i ∈ I, κ i a := by rw [coe_finset_sum, Finset.sum_apply]
+
+theorem finset_sum_apply' (I : Finset ι) (κ : ι → Kernel α β) (a : α) (s : Set β) :
+ (∑ i ∈ I, κ i) a s = ∑ i ∈ I, κ i a s := by rw [finset_sum_apply, Measure.finset_sum_apply]
+
+end Kernel
+
+/-- A kernel is a Markov kernel if every measure in its image is a probability measure. -/
+class IsMarkovKernel (κ : Kernel α β) : Prop where
+ isProbabilityMeasure : ∀ a, IsProbabilityMeasure (κ a)
+
+/-- A class for kernels which are zero or a Markov kernel. -/
+class IsZeroOrMarkovKernel (κ : Kernel α β) : Prop where
+ eq_zero_or_isMarkovKernel' : κ = 0 ∨ IsMarkovKernel κ
+
+/-- A kernel is finite if every measure in its image is finite, with a uniform bound. -/
+class IsFiniteKernel (κ : Kernel α β) : Prop where
+ exists_univ_le : ∃ C : ℝ≥0∞, C < ∞ ∧ ∀ a, κ a Set.univ ≤ C
+
+theorem eq_zero_or_isMarkovKernel
+ (κ : Kernel α β) [h : IsZeroOrMarkovKernel κ] :
+ κ = 0 ∨ IsMarkovKernel κ :=
+ h.eq_zero_or_isMarkovKernel'
+
+/-- A constant `C : ℝ≥0∞` such that `C < ∞` (`ProbabilityTheory.IsFiniteKernel.bound_lt_top κ`) and
+for all `a : α` and `s : Set β`, `κ a s ≤ C` (`ProbabilityTheory.Kernel.measure_le_bound κ a s`).
+
+Porting note (#11215): TODO: does it make sense to
+-- make `ProbabilityTheory.IsFiniteKernel.bound` the least possible bound?
+-- Should it be an `NNReal` number? -/
+noncomputable def IsFiniteKernel.bound (κ : Kernel α β) [h : IsFiniteKernel κ] : ℝ≥0∞ :=
+ h.exists_univ_le.choose
+
+theorem IsFiniteKernel.bound_lt_top (κ : Kernel α β) [h : IsFiniteKernel κ] :
+ IsFiniteKernel.bound κ < ∞ :=
+ h.exists_univ_le.choose_spec.1
+
+theorem IsFiniteKernel.bound_ne_top (κ : Kernel α β) [IsFiniteKernel κ] :
+ IsFiniteKernel.bound κ ≠ ∞ :=
+ (IsFiniteKernel.bound_lt_top κ).ne
+
+theorem Kernel.measure_le_bound (κ : Kernel α β) [h : IsFiniteKernel κ] (a : α) (s : Set β) :
+ κ a s ≤ IsFiniteKernel.bound κ :=
+ (measure_mono (Set.subset_univ s)).trans (h.exists_univ_le.choose_spec.2 a)
+
+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]⟩⟩
+
+instance IsFiniteKernel.add (κ η : Kernel α β) [IsFiniteKernel κ] [IsFiniteKernel η] :
+ IsFiniteKernel (κ + η) := by
+ refine ⟨⟨IsFiniteKernel.bound κ + IsFiniteKernel.bound η,
+ ENNReal.add_lt_top.mpr ⟨IsFiniteKernel.bound_lt_top κ, IsFiniteKernel.bound_lt_top η⟩,
+ fun a => ?_⟩⟩
+ exact add_le_add (Kernel.measure_le_bound _ _ _) (Kernel.measure_le_bound _ _ _)
+
+lemma isFiniteKernel_of_le {κ ν : Kernel α β} [hν : IsFiniteKernel ν] (hκν : κ ≤ ν) :
+ IsFiniteKernel κ := by
+ refine ⟨hν.bound, hν.bound_lt_top, fun a ↦ (hκν _ _).trans (Kernel.measure_le_bound ν a Set.univ)⟩
+
+variable {κ η : Kernel α β}
+
+instance IsMarkovKernel.is_probability_measure' [IsMarkovKernel κ] (a : α) :
+ IsProbabilityMeasure (κ a) :=
+ IsMarkovKernel.isProbabilityMeasure a
+
+instance : IsZeroOrMarkovKernel (0 : Kernel α β) := ⟨Or.inl rfl⟩
+
+instance (priority := 100) IsMarkovKernel.IsZeroOrMarkovKernel [h : IsMarkovKernel κ] :
+ IsZeroOrMarkovKernel κ := ⟨Or.inr h⟩
+
+instance (priority := 100) IsZeroOrMarkovKernel.isZeroOrProbabilityMeasure
+ [IsZeroOrMarkovKernel κ] (a : α) : IsZeroOrProbabilityMeasure (κ a) := by
+ rcases eq_zero_or_isMarkovKernel κ with rfl | h'
+ · simp only [Kernel.zero_apply]
+ infer_instance
+ · infer_instance
+
+instance IsFiniteKernel.isFiniteMeasure [IsFiniteKernel κ] (a : α) : IsFiniteMeasure (κ a) :=
+ ⟨(Kernel.measure_le_bound κ a Set.univ).trans_lt (IsFiniteKernel.bound_lt_top κ)⟩
+
+instance (priority := 100) IsZeroOrMarkovKernel.isFiniteKernel [h : IsZeroOrMarkovKernel κ] :
+ IsFiniteKernel κ := by
+ rcases eq_zero_or_isMarkovKernel κ with rfl | _h'
+ · infer_instance
+ · exact ⟨⟨1, ENNReal.one_lt_top, fun _ => prob_le_one⟩⟩
+
+namespace Kernel
+
+@[ext]
+theorem ext (h : ∀ a, κ a = η a) : κ = η := DFunLike.ext _ _ h
+
+theorem ext_iff' : κ = η ↔ ∀ a s, MeasurableSet s → κ a s = η a s := by
+ simp_rw [Kernel.ext_iff, Measure.ext_iff]
+
+theorem ext_fun (h : ∀ a f, Measurable f → ∫⁻ b, f b ∂κ a = ∫⁻ b, f b ∂η a) :
+ κ = η := by
+ ext a s hs
+ specialize h a (s.indicator fun _ => 1) (Measurable.indicator measurable_const hs)
+ simp_rw [lintegral_indicator_const hs, one_mul] at h
+ rw [h]
+
+theorem ext_fun_iff : κ = η ↔ ∀ a f, Measurable f → ∫⁻ b, f b ∂κ a = ∫⁻ b, f b ∂η a :=
+ ⟨fun h a f _ => by rw [h], ext_fun⟩
+
+protected theorem measurable_coe (κ : Kernel α β) {s : Set β} (hs : MeasurableSet s) :
+ Measurable fun a => κ a s :=
+ (Measure.measurable_coe hs).comp κ.measurable
+
+lemma apply_congr_of_mem_measurableAtom (κ : Kernel α β) {y' y : α} (hy' : y' ∈ measurableAtom y) :
+ κ y' = κ y := by
+ ext s hs
+ exact mem_of_mem_measurableAtom hy' (κ.measurable_coe hs (measurableSet_singleton (κ y s))) rfl
+
+section Sum
+
+/-- Sum of an indexed family of kernels. -/
+protected noncomputable def sum [Countable ι] (κ : ι → Kernel α β) : Kernel α β where
+ toFun a := Measure.sum fun n => κ n a
+ measurable' := by
+ refine Measure.measurable_of_measurable_coe _ fun s hs => ?_
+ simp_rw [Measure.sum_apply _ hs]
+ exact Measurable.ennreal_tsum fun n => Kernel.measurable_coe (κ n) hs
+
+theorem sum_apply [Countable ι] (κ : ι → Kernel α β) (a : α) :
+ Kernel.sum κ a = Measure.sum fun n => κ n a :=
+ rfl
+
+theorem sum_apply' [Countable ι] (κ : ι → Kernel α β) (a : α) {s : Set β} (hs : MeasurableSet s) :
+ Kernel.sum κ a s = ∑' n, κ n a s := by rw [sum_apply κ a, Measure.sum_apply _ hs]
+
+@[simp]
+theorem sum_zero [Countable ι] : (Kernel.sum fun _ : ι => (0 : Kernel α β)) = 0 := by
+ ext a s hs
+ rw [sum_apply' _ a hs]
+ simp only [zero_apply, Measure.coe_zero, Pi.zero_apply, tsum_zero]
+
+theorem sum_comm [Countable ι] (κ : ι → ι → Kernel α β) :
+ (Kernel.sum fun n => Kernel.sum (κ n)) = Kernel.sum fun m => Kernel.sum fun n => κ n m := by
+ ext a s; simp_rw [sum_apply]; rw [Measure.sum_comm]
+
+@[simp]
+theorem sum_fintype [Fintype ι] (κ : ι → Kernel α β) : Kernel.sum κ = ∑ i, κ i := by
+ ext a s hs
+ simp only [sum_apply' κ a hs, finset_sum_apply' _ κ a s, tsum_fintype]
+
+theorem sum_add [Countable ι] (κ η : ι → Kernel α β) :
+ (Kernel.sum fun n => κ n + η n) = Kernel.sum κ + Kernel.sum η := by
+ ext a s hs
+ simp only [coe_add, Pi.add_apply, sum_apply, Measure.sum_apply _ hs, Pi.add_apply,
+ Measure.coe_add, tsum_add ENNReal.summable ENNReal.summable]
+
+end Sum
+
+section SFinite
+
+/-- A kernel is s-finite if it can be written as the sum of countably many finite kernels. -/
+class _root_.ProbabilityTheory.IsSFiniteKernel (κ : Kernel α β) : Prop where
+ tsum_finite : ∃ κs : ℕ → Kernel α β, (∀ n, IsFiniteKernel (κs n)) ∧ κ = Kernel.sum κs
+
+instance (priority := 100) IsFiniteKernel.isSFiniteKernel [h : IsFiniteKernel κ] :
+ IsSFiniteKernel κ :=
+ ⟨⟨fun n => if n = 0 then κ else 0, fun n => by
+ simp only; split_ifs
+ · exact h
+ · infer_instance, by
+ ext a s hs
+ rw [Kernel.sum_apply' _ _ hs]
+ have : (fun i => ((ite (i = 0) κ 0) a) s) = fun i => ite (i = 0) (κ a s) 0 := by
+ ext1 i; split_ifs <;> rfl
+ rw [this, tsum_ite_eq]⟩⟩
+
+/-- A sequence of finite kernels such that `κ = ProbabilityTheory.Kernel.sum (seq κ)`. See
+`ProbabilityTheory.Kernel.isFiniteKernel_seq` and `ProbabilityTheory.Kernel.kernel_sum_seq`. -/
+noncomputable def seq (κ : Kernel α β) [h : IsSFiniteKernel κ] : ℕ → Kernel α β :=
+ h.tsum_finite.choose
+
+theorem kernel_sum_seq (κ : Kernel α β) [h : IsSFiniteKernel κ] : Kernel.sum (seq κ) = κ :=
+ h.tsum_finite.choose_spec.2.symm
+
+theorem measure_sum_seq (κ : Kernel α β) [h : IsSFiniteKernel κ] (a : α) :
+ (Measure.sum fun n => seq κ n a) = κ a := by rw [← Kernel.sum_apply, kernel_sum_seq κ]
+
+instance isFiniteKernel_seq (κ : Kernel α β) [h : IsSFiniteKernel κ] (n : ℕ) :
+ IsFiniteKernel (Kernel.seq κ n) :=
+ h.tsum_finite.choose_spec.1 n
+
+instance _root_.ProbabilityTheory.IsSFiniteKernel.sFinite [IsSFiniteKernel κ] (a : α) :
+ SFinite (κ a) :=
+ ⟨⟨fun n ↦ seq κ n a, inferInstance, (measure_sum_seq κ a).symm⟩⟩
+
+instance IsSFiniteKernel.add (κ η : Kernel α β) [IsSFiniteKernel κ] [IsSFiniteKernel η] :
+ IsSFiniteKernel (κ + η) := by
+ refine ⟨⟨fun n => seq κ n + seq η n, fun n => inferInstance, ?_⟩⟩
+ rw [sum_add, kernel_sum_seq κ, kernel_sum_seq η]
+
+theorem IsSFiniteKernel.finset_sum {κs : ι → Kernel α β} (I : Finset ι)
+ (h : ∀ i ∈ I, IsSFiniteKernel (κs i)) : IsSFiniteKernel (∑ i ∈ I, κs i) := by
+ classical
+ induction' I using Finset.induction with i I hi_nmem_I h_ind h
+ · rw [Finset.sum_empty]; infer_instance
+ · rw [Finset.sum_insert hi_nmem_I]
+ haveI : IsSFiniteKernel (κs i) := h i (Finset.mem_insert_self _ _)
+ have : IsSFiniteKernel (∑ x ∈ I, κs x) :=
+ h_ind fun i hiI => h i (Finset.mem_insert_of_mem hiI)
+ exact IsSFiniteKernel.add _ _
+
+theorem isSFiniteKernel_sum_of_denumerable [Denumerable ι] {κs : ι → Kernel α β}
+ (hκs : ∀ n, IsSFiniteKernel (κs n)) : IsSFiniteKernel (Kernel.sum κs) := by
+ let e : ℕ ≃ ι × ℕ := (Denumerable.eqv (ι × ℕ)).symm
+ refine ⟨⟨fun n => seq (κs (e n).1) (e n).2, inferInstance, ?_⟩⟩
+ have hκ_eq : Kernel.sum κs = Kernel.sum fun n => Kernel.sum (seq (κs n)) := by
+ simp_rw [kernel_sum_seq]
+ ext a s hs
+ rw [hκ_eq]
+ simp_rw [Kernel.sum_apply' _ _ hs]
+ change (∑' i, ∑' m, seq (κs i) m a s) = ∑' n, (fun im : ι × ℕ => seq (κs im.fst) im.snd a s) (e n)
+ rw [e.tsum_eq (fun im : ι × ℕ => seq (κs im.fst) im.snd a s),
+ tsum_prod' ENNReal.summable fun _ => ENNReal.summable]
+
+theorem isSFiniteKernel_sum [Countable ι] {κs : ι → Kernel α β}
+ (hκs : ∀ n, IsSFiniteKernel (κs n)) : IsSFiniteKernel (Kernel.sum κs) := by
+ cases fintypeOrInfinite ι
+ · rw [sum_fintype]
+ exact IsSFiniteKernel.finset_sum Finset.univ fun i _ => hκs i
+ cases nonempty_denumerable ι
+ exact isSFiniteKernel_sum_of_denumerable hκs
+
+end SFinite
+end Kernel
+end ProbabilityTheory
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 18005da5094fd..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)
@@ -147,7 +148,7 @@ lemma setLIntegral_stieltjesOfMeasurableRat [IsFiniteKernel κ] (hf : IsRatCondK
· exact mod_cast ha.le
· refine le_of_forall_lt_rat_imp_le fun q hq ↦ h q ?_
exact mod_cast hq
- · exact fun _ ↦ measurableSet_Iic.nullMeasurableSet
+ · exact fun _ ↦ nullMeasurableSet_Iic
· refine Monotone.directed_ge fun r r' hrr' ↦ Iic_subset_Iic.mpr ?_
exact mod_cast hrr'
· obtain ⟨q, hq⟩ := exists_rat_gt x
@@ -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)
@@ -550,7 +551,7 @@ lemma setLIntegral_toKernel_univ [IsFiniteKernel κ] (hf : IsCondKernelCDF f κ
refine Monotone.directed_le fun i j hij ↦ ?_
refine prod_subset_prod_iff.mpr (Or.inl ⟨subset_rfl, Iic_subset_Iic.mpr ?_⟩)
exact mod_cast hij
- simp_rw [measure_iUnion_eq_iSup h_dir, measure_iUnion_eq_iSup h_dir_prod]
+ simp_rw [h_dir.measure_iUnion, h_dir_prod.measure_iUnion]
rw [lintegral_iSup_directed]
· simp_rw [setLIntegral_toKernel_Iic hf _ _ hs]
· refine fun q ↦ Measurable.aemeasurable ?_
@@ -621,7 +622,7 @@ lemma lintegral_toKernel_mem [IsFiniteKernel κ] (hf : IsCondKernelCDF f κ ν)
simp only [mem_setOf_eq] at ht₁ ht₂
have h_prod_eq_snd : ∀ a ∈ t₁, {x : ℝ | (a, x) ∈ t₁ ×ˢ t₂} = t₂ := by
intro a ha
- simp only [ha, prod_mk_mem_set_prod_eq, true_and_iff, setOf_mem_eq]
+ simp only [ha, prod_mk_mem_set_prod_eq, true_and, setOf_mem_eq]
rw [← lintegral_add_compl _ ht₁]
have h_eq1 : ∫⁻ x in t₁, hf.toKernel f (a, x) {y : ℝ | (x, y) ∈ t₁ ×ˢ t₂} ∂(ν a)
= ∫⁻ x in t₁, hf.toKernel f (a, x) t₂ ∂(ν a) := by
@@ -635,7 +636,7 @@ lemma lintegral_toKernel_mem [IsFiniteKernel κ] (hf : IsCondKernelCDF f κ ν)
simp only [lintegral_const, zero_mul]
intro a hat₁
rw [mem_compl_iff] at hat₁
- simp only [hat₁, prod_mk_mem_set_prod_eq, false_and_iff, setOf_false, measure_empty]
+ simp only [hat₁, prod_mk_mem_set_prod_eq, false_and, setOf_false, measure_empty]
rw [h_eq1, h_eq2, add_zero]
exact setLIntegral_toKernel_prod hf a ht₁ ht₂
· intro t ht ht_eq
@@ -667,7 +668,7 @@ lemma lintegral_toKernel_mem [IsFiniteKernel κ] (hf : IsCondKernelCDF f κ ν)
have h_disj := hf_disj hij
rw [Function.onFun, disjoint_iff_inter_eq_empty] at h_disj ⊢
ext1 x
- simp only [mem_inter_iff, mem_setOf_eq, mem_empty_iff_false, iff_false_iff]
+ simp only [mem_inter_iff, mem_setOf_eq, mem_empty_iff_false, iff_false]
intro h_mem_both
suffices (a, x) ∈ ∅ by rwa [mem_empty_iff_false] at this
rwa [← h_disj, mem_inter_iff]
@@ -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 4b5aac1603122..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 α :=
@@ -78,10 +78,8 @@ theorem tendsto_IicSnd_atTop {s : Set α} (hs : MeasurableSet s) :
Tendsto (fun r : ℚ ↦ ρ.IicSnd r s) atTop (𝓝 (ρ.fst s)) := by
simp_rw [ρ.IicSnd_apply _ hs, fst_apply hs, ← prod_univ]
rw [← Real.iUnion_Iic_rat, prod_iUnion]
- refine tendsto_measure_iUnion fun r q hr_le_q x ↦ ?_
- simp only [mem_prod, mem_Iic, and_imp]
- refine fun hxs hxr ↦ ⟨hxs, hxr.trans ?_⟩
- exact mod_cast hr_le_q
+ apply tendsto_measure_iUnion_atTop
+ exact monotone_const.set_prod Rat.cast_mono.Iic
theorem tendsto_IicSnd_atBot [IsFiniteMeasure ρ] {s : Set α} (hs : MeasurableSet s) :
Tendsto (fun r : ℚ ↦ ρ.IicSnd r s) atBot (𝓝 0) := by
@@ -114,7 +112,7 @@ open MeasureTheory
namespace ProbabilityTheory
-variable {α β ι : Type*} {mα : MeasurableSpace α}
+variable {α : Type*} {mα : MeasurableSpace α}
attribute [local instance] MeasureTheory.Measure.IsFiniteMeasure.IicSnd
@@ -194,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 77a32c6fbfe53..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) :
@@ -656,11 +656,8 @@ lemma tendsto_integral_density_of_monotone (hκν : fst κ ≤ ν) [IsFiniteKern
· simp only [mem_Iio]
exact ENNReal.lt_add_right (measure_ne_top _ _) one_ne_zero
refine h_cont.tendsto.comp ?_
- have h := tendsto_measure_iUnion (s := fun m ↦ univ ×ˢ seq m) (μ := κ a) ?_
- swap; · intro n m hnm x; simp only [mem_prod, mem_univ, true_and]; exact fun h ↦ hseq hnm h
- convert h
- rw [← prod_iUnion, hseq_iUnion]
- simp only [univ_prod_univ, measure_univ]
+ convert tendsto_measure_iUnion_atTop (monotone_const.set_prod hseq)
+ rw [← prod_iUnion, hseq_iUnion, univ_prod_univ]
lemma tendsto_integral_density_of_antitone (hκν : fst κ ≤ ν) [IsFiniteKernel ν] (a : α)
(seq : ℕ → Set β) (hseq : Antitone seq) (hseq_iInter : ⋂ i, seq i = ∅)
@@ -776,13 +773,7 @@ lemma tendsto_densityProcess_fst_atTop_univ_of_monotone (κ : Kernel α (γ ×
simp only [mem_prod, mem_setOf_eq, and_imp]
exact fun h _ ↦ h
refine ENNReal.Tendsto.div_const ?_ ?_
- · have h := tendsto_measure_iUnion (μ := κ a)
- (s := fun m ↦ countablePartitionSet n x ×ˢ seq m) ?_
- swap
- · intro m m' hmm'
- simp only [le_eq_subset, prod_subset_prod_iff, subset_rfl, true_and]
- exact Or.inl <| hseq hmm'
- convert h
+ · convert tendsto_measure_iUnion_atTop (monotone_const.set_prod hseq)
rw [← prod_iUnion, hseq_iUnion]
· exact Or.inr h0
diff --git a/Mathlib/Probability/Kernel/Disintegration/Integral.lean b/Mathlib/Probability/Kernel/Disintegration/Integral.lean
index f712bc83a22b8..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
@@ -146,12 +146,12 @@ end ProbabilityTheory
namespace MeasureTheory.Measure
-variable {α β Ω : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β}
+variable {β Ω : Type*} {mβ : MeasurableSpace β}
[MeasurableSpace Ω] [StandardBorelSpace Ω] [Nonempty Ω]
section Lintegral
-variable [CountableOrCountablyGenerated α β] {ρ : Measure (β × Ω)} [IsFiniteMeasure ρ]
+variable {ρ : Measure (β × Ω)} [IsFiniteMeasure ρ]
{f : β × Ω → ℝ≥0∞}
lemma lintegral_condKernel_mem {s : Set (β × Ω)} (hs : MeasurableSet s) :
@@ -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
new file mode 100644
index 0000000000000..e97ef25407719
--- /dev/null
+++ b/Mathlib/Probability/Kernel/Integral.lean
@@ -0,0 +1,130 @@
+/-
+Copyright (c) 2022 Rémy Degenne. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Rémy Degenne
+-/
+import Mathlib.MeasureTheory.Integral.Bochner
+import Mathlib.Probability.Kernel.Basic
+
+/-!
+# Bochner integrals of kernels
+
+-/
+
+open MeasureTheory
+
+namespace ProbabilityTheory
+
+variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {κ : Kernel α β}
+ {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {f : β → E} {a : α}
+
+namespace Kernel
+
+lemma IsFiniteKernel.integrable (μ : Measure α) [IsFiniteMeasure μ]
+ (κ : Kernel α β) [IsFiniteKernel κ] {s : Set β} (hs : MeasurableSet s) :
+ Integrable (fun x ↦ (κ x s).toReal) μ := by
+ refine Integrable.mono' (integrable_const (IsFiniteKernel.bound κ).toReal)
+ ((κ.measurable_coe hs).ennreal_toReal.aestronglyMeasurable)
+ (ae_of_all μ fun x ↦ ?_)
+ rw [Real.norm_eq_abs, abs_of_nonneg ENNReal.toReal_nonneg,
+ ENNReal.toReal_le_toReal (measure_ne_top _ _) (IsFiniteKernel.bound_ne_top _)]
+ exact Kernel.measure_le_bound _ _ _
+
+lemma IsMarkovKernel.integrable (μ : Measure α) [IsFiniteMeasure μ]
+ (κ : Kernel α β) [IsMarkovKernel κ] {s : Set β} (hs : MeasurableSet s) :
+ Integrable (fun x => (κ x s).toReal) μ :=
+ IsFiniteKernel.integrable μ κ hs
+
+lemma integral_congr_ae₂ {f g : α → β → E} {μ : Measure α} (h : ∀ᵐ a ∂μ, f a =ᵐ[κ a] g a) :
+ ∫ a, ∫ b, f a b ∂(κ a) ∂μ = ∫ a, ∫ b, g a b ∂(κ a) ∂μ := by
+ apply integral_congr_ae
+ filter_upwards [h] with _ ha
+ apply integral_congr_ae
+ filter_upwards [ha] with _ hb using hb
+
+section Deterministic
+
+variable [CompleteSpace E] {g : α → β}
+
+theorem integral_deterministic' (hg : Measurable g) (hf : StronglyMeasurable f) :
+ ∫ x, f x ∂deterministic g hg a = f (g a) := by
+ rw [deterministic_apply, integral_dirac' _ _ hf]
+
+@[simp]
+theorem integral_deterministic [MeasurableSingletonClass β] (hg : Measurable g) :
+ ∫ x, f x ∂deterministic g hg a = f (g a) := by
+ rw [deterministic_apply, integral_dirac _ (g a)]
+
+theorem setIntegral_deterministic' (hg : Measurable g)
+ (hf : StronglyMeasurable f) {s : Set β} (hs : MeasurableSet s) [Decidable (g a ∈ s)] :
+ ∫ x in s, f x ∂deterministic g hg a = if g a ∈ s then f (g a) else 0 := by
+ rw [deterministic_apply, setIntegral_dirac' hf _ hs]
+
+@[deprecated (since := "2024-04-17")]
+alias set_integral_deterministic' := setIntegral_deterministic'
+
+@[simp]
+theorem setIntegral_deterministic [MeasurableSingletonClass β] (hg : Measurable g)
+ (s : Set β) [Decidable (g a ∈ s)] :
+ ∫ x in s, f x ∂deterministic g hg a = if g a ∈ s then f (g a) else 0 := by
+ rw [deterministic_apply, setIntegral_dirac f _ s]
+
+@[deprecated (since := "2024-04-17")]
+alias set_integral_deterministic := setIntegral_deterministic
+
+end Deterministic
+
+section Const
+
+@[simp]
+theorem integral_const {μ : Measure β} : ∫ x, f x ∂const α μ a = ∫ x, f x ∂μ := by
+ rw [const_apply]
+
+@[simp]
+theorem setIntegral_const {μ : Measure β} {s : Set β} :
+ ∫ x in s, f x ∂const α μ a = ∫ x in s, f x ∂μ := by rw [const_apply]
+
+@[deprecated (since := "2024-04-17")]
+alias set_integral_const := setIntegral_const
+
+end Const
+
+section Restrict
+
+variable {s : Set β}
+
+@[simp]
+theorem integral_restrict (hs : MeasurableSet s) :
+ ∫ x, f x ∂κ.restrict hs a = ∫ x in s, f x ∂κ a := by
+ rw [restrict_apply]
+
+@[simp]
+theorem setIntegral_restrict (hs : MeasurableSet s) (t : Set β) :
+ ∫ x in t, f x ∂κ.restrict hs a = ∫ x in t ∩ s, f x ∂κ a := by
+ rw [restrict_apply, Measure.restrict_restrict' hs]
+
+@[deprecated (since := "2024-04-17")]
+alias set_integral_restrict := setIntegral_restrict
+
+end Restrict
+
+section Piecewise
+
+variable {η : Kernel α β} {s : Set α} {hs : MeasurableSet s} [DecidablePred (· ∈ s)]
+
+theorem integral_piecewise (a : α) (g : β → E) :
+ ∫ b, g b ∂piecewise hs κ η a = if a ∈ s then ∫ b, g b ∂κ a else ∫ b, g b ∂η a := by
+ simp_rw [piecewise_apply]; split_ifs <;> rfl
+
+theorem setIntegral_piecewise (a : α) (g : β → E) (t : Set β) :
+ ∫ b in t, g b ∂piecewise hs κ η a =
+ if a ∈ s then ∫ b in t, g b ∂κ a else ∫ b in t, g b ∂η a := by
+ simp_rw [piecewise_apply]; split_ifs <;> rfl
+
+@[deprecated (since := "2024-04-17")]
+alias set_integral_piecewise := setIntegral_piecewise
+
+end Piecewise
+
+end Kernel
+end ProbabilityTheory
diff --git a/Mathlib/Probability/Kernel/IntegralCompProd.lean b/Mathlib/Probability/Kernel/IntegralCompProd.lean
index a6cb2cd870a84..e88e7a0f5f916 100644
--- a/Mathlib/Probability/Kernel/IntegralCompProd.lean
+++ b/Mathlib/Probability/Kernel/IntegralCompProd.lean
@@ -116,7 +116,7 @@ theorem integrable_compProd_iff ⦃f : β × γ → E⦄ (hf : AEStronglyMeasura
(∀ᵐ x ∂κ a, Integrable (fun y => f (x, y)) (η (a, x))) ∧
Integrable (fun x => ∫ y, ‖f (x, y)‖ ∂η (a, x)) (κ a) := by
simp only [Integrable, hasFiniteIntegral_compProd_iff' hf, hf.norm.integral_kernel_compProd,
- hf, hf.compProd_mk_left, eventually_and, true_and_iff]
+ hf, hf.compProd_mk_left, eventually_and, true_and]
theorem _root_.MeasureTheory.Integrable.compProd_mk_left_ae ⦃f : β × γ → E⦄
(hf : Integrable f ((κ ⊗ₖ η) a)) : ∀ᵐ x ∂κ a, Integrable (fun y => f (x, y)) (η (a, x)) :=
@@ -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 312093ef4376d..63c99fb77ebfa 100644
--- a/Mathlib/Probability/Kernel/MeasurableIntegral.lean
+++ b/Mathlib/Probability/Kernel/MeasurableIntegral.lean
@@ -3,9 +3,8 @@ Copyright (c) 2023 Rémy Degenne. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Rémy Degenne
-/
-import Mathlib.Probability.Kernel.Basic
-import Mathlib.MeasureTheory.Constructions.Prod.Basic
import Mathlib.MeasureTheory.Integral.DominatedConvergence
+import Mathlib.Probability.Kernel.Basic
/-!
# Measurability of the integral against a kernel
@@ -64,7 +63,7 @@ theorem measurable_kernel_prod_mk_left_of_finite {t : Set (α × β)} (ht : Meas
have h_eq_sdiff : ∀ a, Prod.mk a ⁻¹' t'ᶜ = Set.univ \ Prod.mk a ⁻¹' t' := by
intro a
ext1 b
- simp only [mem_compl_iff, mem_preimage, mem_diff, mem_univ, true_and_iff]
+ simp only [mem_compl_iff, mem_preimage, mem_diff, mem_univ, true_and]
simp_rw [h_eq_sdiff]
have :
(fun a => κ a (Set.univ \ Prod.mk a ⁻¹' t')) = fun a =>
@@ -153,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
@@ -167,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]
@@ -232,11 +231,11 @@ 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
- simp_rw [Integrable, hf.of_uncurry_left.aestronglyMeasurable, true_and_iff]
+ simp_rw [Integrable, hf.of_uncurry_left.aestronglyMeasurable, true_and]
exact measurableSet_lt (Measurable.lintegral_kernel_prod_right hf.ennnorm) measurable_const
end ProbabilityTheory
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 831ab2d4dae51..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
@@ -173,8 +173,8 @@ theorem Submartingale.upcrossings_ae_lt_top' [IsFiniteMeasure μ] (hf : Submarti
exact norm_nonneg _
· simp only [Ne, ENNReal.coe_ne_top, not_false_iff]
· simp only [hab, Ne, ENNReal.ofReal_eq_zero, sub_nonpos, not_le]
- · simp only [hab, Ne, ENNReal.ofReal_eq_zero, sub_nonpos, not_le, true_or_iff]
- · simp only [Ne, ENNReal.ofReal_ne_top, not_false_iff, true_or_iff]
+ · simp only [hab, Ne, ENNReal.ofReal_eq_zero, sub_nonpos, not_le, true_or]
+ · simp only [Ne, ENNReal.ofReal_ne_top, not_false_iff, true_or]
theorem Submartingale.upcrossings_ae_lt_top [IsFiniteMeasure μ] (hf : Submartingale f ℱ μ)
(hbdd : ∀ n, eLpNorm (f n) 1 μ ≤ R) : ∀ᵐ ω ∂μ, ∀ a b : ℚ, a < b → upcrossings a b f ω < ∞ := by
@@ -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 3132d43cb03f9..90b9489aaa39c 100644
--- a/Mathlib/Probability/Martingale/OptionalSampling.lean
+++ b/Mathlib/Probability/Martingale/OptionalSampling.lean
@@ -66,7 +66,7 @@ theorem condexp_stopping_time_ae_eq_restrict_eq_const_of_le_const (h : Martingal
rw [Set.inter_comm _ t, IsStoppingTime.measurableSet_inter_eq_iff]
· suffices {x : Ω | τ x = i} = ∅ by simp [this]; norm_cast
ext1 x
- simp only [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false_iff]
+ simp only [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false]
rintro rfl
exact hin (hτ_le x)
@@ -88,7 +88,7 @@ theorem stoppedValue_ae_eq_condexp_of_le_const_of_countable_range (h : Martingal
stoppedValue f τ =ᵐ[μ] μ[f n|hτ.measurableSpace] := by
have : Set.univ = ⋃ i ∈ Set.range τ, {x | τ x = i} := by
ext1 x
- simp only [Set.mem_univ, Set.mem_range, true_and_iff, Set.iUnion_exists, Set.iUnion_iUnion_eq',
+ simp only [Set.mem_univ, Set.mem_range, Set.iUnion_exists, Set.iUnion_iUnion_eq',
Set.mem_iUnion, Set.mem_setOf_eq, exists_apply_eq_apply']
nth_rw 1 [← @Measure.restrict_univ Ω _ μ]
rw [this, ae_eq_restrict_biUnion_iff _ h_countable_range]
@@ -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 0d3e293008a55..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)] =
@@ -449,7 +449,7 @@ theorem crossing_eq_crossing_of_lowerCrossingTime_lt {M : ℕ} (hNM : N ≤ M)
lt_of_le_of_lt upperCrossingTime_le_lowerCrossingTime h
induction' n with k ih
· simp only [upperCrossingTime_zero, bot_eq_zero', eq_self_iff_true,
- lowerCrossingTime_zero, true_and_iff, eq_comm]
+ lowerCrossingTime_zero, true_and, eq_comm]
refine hitting_eq_hitting_of_exists hNM ?_
rw [lowerCrossingTime, hitting_lt_iff] at h
· obtain ⟨j, hj₁, hj₂⟩ := h
@@ -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 9f39ce4a332a9..1433dc8119e43 100644
--- a/Mathlib/Probability/Moments.lean
+++ b/Mathlib/Probability/Moments.lean
@@ -166,7 +166,7 @@ theorem mgf_pos' (hμ : μ ≠ 0) (h_int_X : Integrable (fun ω => exp (t * X ω
rw [this, setIntegral_pos_iff_support_of_nonneg_ae _ _]
· have h_eq_univ : (Function.support fun x : Ω => exp (t * X x)) = Set.univ := by
ext1 x
- simp only [Function.mem_support, Set.mem_univ, iff_true_iff]
+ simp only [Function.mem_support, Set.mem_univ, iff_true]
exact (exp_pos _).ne'
rw [h_eq_univ, Set.inter_univ _]
refine Ne.bot_lt ?_
@@ -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 ec56f812e2f47..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 => ?_⟩
@@ -176,7 +176,8 @@ theorem toOuterMeasure_apply_eq_one_iff : p.toOuterMeasure s = 1 ↔ p.support
(fun x => Set.indicator_apply_le fun _ => le_rfl) hsa
· suffices ∀ (x) (_ : x ∉ s), p x = 0 from
_root_.trans (tsum_congr
- fun a => (Set.indicator_apply s p a).trans (ite_eq_left_iff.2 <| symm ∘ this a)) p.tsum_coe
+ fun a => (Set.indicator_apply s p a).trans
+ (ite_eq_left_iff.2 <| symm ∘ this a)) p.tsum_coe
exact fun a ha => (p.apply_eq_zero_iff a).2 <| Set.not_mem_subset h ha
@[simp]
@@ -209,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
@@ -332,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/Integrals.lean b/Mathlib/Probability/ProbabilityMassFunction/Integrals.lean
index 0803f711af0ab..befbc17ee812f 100644
--- a/Mathlib/Probability/ProbabilityMassFunction/Integrals.lean
+++ b/Mathlib/Probability/ProbabilityMassFunction/Integrals.lean
@@ -42,7 +42,7 @@ theorem integral_eq_tsum (p : PMF α) (f : α → E) (hf : Integrable f p.toMeas
theorem integral_eq_sum [Fintype α] (p : PMF α) (f : α → E) :
∫ a, f a ∂(p.toMeasure) = ∑ a, (p a).toReal • f a := by
- rw [integral_fintype _ (.of_finite _ f)]
+ rw [integral_fintype _ .of_finite]
congr with x; congr 2
exact PMF.toMeasure_apply_singleton p x (MeasurableSet.singleton _)
diff --git a/Mathlib/Probability/ProbabilityMassFunction/Monad.lean b/Mathlib/Probability/ProbabilityMassFunction/Monad.lean
index d137f3c66d02f..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
@@ -67,9 +66,11 @@ theorem toOuterMeasure_pure_apply : (pure a).toOuterMeasure s = if a ∈ s then
refine (toOuterMeasure_apply (pure a) s).trans ?_
split_ifs with ha
· refine (tsum_congr fun b => ?_).trans (tsum_ite_eq a 1)
- exact ite_eq_left_iff.2 fun hb => symm (ite_eq_right_iff.2 fun h => (hb <| h.symm ▸ ha).elim)
+ exact ite_eq_left_iff.2 fun hb =>
+ symm (ite_eq_right_iff.2 fun h => (hb <| h.symm ▸ ha).elim)
· refine (tsum_congr fun b => ?_).trans tsum_zero
- exact ite_eq_right_iff.2 fun hb => ite_eq_right_iff.2 fun h => (ha <| h ▸ hb).elim
+ exact ite_eq_right_iff.2 fun hb =>
+ ite_eq_right_iff.2 fun h => (ha <| h ▸ hb).elim
variable [MeasurableSpace α]
@@ -154,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 28eb2728601cf..4cf0ce22da61f 100644
--- a/Mathlib/Probability/Process/HittingTime.lean
+++ b/Mathlib/Probability/Process/HittingTime.lean
@@ -164,7 +164,7 @@ theorem hitting_le_iff_of_lt [IsWellOrder ι (· < ·)] {m : ι} (i : ι) (hi :
· rw [hitting_le_iff_of_exists h_exists]
· simp_rw [hitting, if_neg h_exists]
push_neg at h_exists
- simp only [not_le.mpr hi, Set.mem_Icc, false_iff_iff, not_exists, not_and, and_imp]
+ simp only [not_le.mpr hi, Set.mem_Icc, false_iff, not_exists, not_and, and_imp]
exact fun k hkn hki => h_exists k ⟨hkn, hki.trans hi.le⟩
theorem hitting_lt_iff [IsWellOrder ι (· < ·)] {m : ι} (i : ι) (hi : i ≤ m) :
@@ -251,7 +251,7 @@ theorem isStoppingTime_hitting_isStoppingTime [ConditionallyCompleteLinearOrder
have h₂ : ⋃ i > n, {x | τ x = i} ∩ {x | hitting u s i N x ≤ n} = ∅ := by
ext x
simp only [gt_iff_lt, Set.mem_iUnion, Set.mem_inter_iff, Set.mem_setOf_eq, exists_prop,
- Set.mem_empty_iff_false, iff_false_iff, not_exists, not_and, not_le]
+ Set.mem_empty_iff_false, iff_false, not_exists, not_and, not_le]
rintro m hm rfl
exact lt_of_lt_of_le hm (le_hitting (hτbdd _) _)
rw [h₁, h₂, Set.union_empty]
@@ -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,14 +276,14 @@ 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
cases' lt_or_le i n with hi hi
· rw [hitting_le_iff_of_lt _ hi]
simp
- · simp only [(hitting_le ω).trans hi, true_iff_iff]
+ · simp only [(hitting_le ω).trans hi, true_iff]
obtain ⟨j, hj₁, hj₂⟩ := hx
exact ⟨j, hj₁.trans hi, hj₂⟩
diff --git a/Mathlib/Probability/Process/Stopping.lean b/Mathlib/Probability/Process/Stopping.lean
index 9d48460885ec5..40bf2069437c8 100644
--- a/Mathlib/Probability/Process/Stopping.lean
+++ b/Mathlib/Probability/Process/Stopping.lean
@@ -69,7 +69,7 @@ theorem IsStoppingTime.measurableSet_lt_of_pred [PredOrder ι] (hτ : IsStopping
by_cases hi_min : IsMin i
· suffices {ω : Ω | τ ω < i} = ∅ by rw [this]; exact @MeasurableSet.empty _ (f i)
ext1 ω
- simp only [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false_iff]
+ simp only [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false]
rw [isMin_iff_forall_not_lt] at hi_min
exact hi_min (τ ω)
have : {ω : Ω | τ ω < i} = τ ⁻¹' Set.Iic (pred i) := by ext; simp [Iic_pred_of_not_isMin hi_min]
@@ -152,7 +152,7 @@ theorem IsStoppingTime.measurableSet_lt_of_isLUB (hτ : IsStoppingTime f τ) (i
by_cases hi_min : IsMin i
· suffices {ω | τ ω < i} = ∅ by rw [this]; exact @MeasurableSet.empty _ (f i)
ext1 ω
- simp only [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false_iff]
+ simp only [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false]
exact isMin_iff_forall_not_lt.mp hi_min (τ ω)
obtain ⟨seq, -, -, h_tendsto, h_bound⟩ :
∃ seq : ℕ → ι, Monotone seq ∧ (∀ j, seq j ≤ i) ∧ Tendsto seq atTop (𝓝 i) ∧ ∀ j, seq j < i :=
@@ -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]
@@ -261,7 +261,7 @@ theorem add_const_nat {f : Filtration ℕ m} {τ : Ω → ℕ} (hτ : IsStopping
· rw [not_le] at hij
convert @MeasurableSet.empty _ (f.1 j)
ext ω
- simp only [Set.mem_empty_iff_false, iff_false_iff, Set.mem_setOf]
+ simp only [Set.mem_empty_iff_false, iff_false, Set.mem_setOf]
omega
-- generalize to certain countable type?
@@ -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 :=
@@ -567,18 +566,17 @@ theorem measurableSet_inter_le [TopologicalSpace ι] [SecondCountableTopology ι
s ∩ {ω | τ ω ≤ i} ∩ {ω | min (τ ω) (π ω) ≤ i} ∩
{ω | min (τ ω) i ≤ min (min (τ ω) (π ω)) i} := by
ext1 ω
- simp only [min_le_iff, Set.mem_inter_iff, Set.mem_setOf_eq, le_min_iff, le_refl, true_and_iff,
- and_true_iff, true_or_iff, or_true_iff]
+ simp only [min_le_iff, Set.mem_inter_iff, Set.mem_setOf_eq, le_min_iff, le_refl, true_and,
+ true_or]
by_cases hτi : τ ω ≤ i
- · simp only [hτi, true_or_iff, and_true_iff, and_congr_right_iff]
+ · simp only [hτi, true_or, and_true, and_congr_right_iff]
intro
constructor <;> intro h
· exact Or.inl h
· cases' h with h h
· exact h
· exact hτi.trans h
- simp only [hτi, false_or_iff, and_false_iff, false_and_iff, iff_false_iff, not_and, not_le,
- and_imp]
+ simp only [hτi, false_or, and_false, false_and, iff_false, not_and, not_le, and_imp]
refine fun _ hτ_le_π => lt_of_lt_of_le ?_ hτ_le_π
rw [← not_le]
exact hτi
@@ -617,10 +615,10 @@ theorem measurableSet_le_stopping_time [TopologicalSpace ι] [SecondCountableTop
intro j
have : {ω | τ ω ≤ π ω} ∩ {ω | τ ω ≤ j} = {ω | min (τ ω) j ≤ min (π ω) j} ∩ {ω | τ ω ≤ j} := by
ext1 ω
- simp only [Set.mem_inter_iff, Set.mem_setOf_eq, min_le_iff, le_min_iff, le_refl, and_true_iff,
+ simp only [Set.mem_inter_iff, Set.mem_setOf_eq, min_le_iff, le_min_iff, le_refl,
and_congr_left_iff]
intro h
- simp only [h, or_self_iff, and_true_iff]
+ simp only [h, or_self_iff, and_true]
rw [Iff.comm, or_iff_left_iff_imp]
exact h.trans
rw [this]
@@ -806,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
@@ -957,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 ec1e988d50e44..4158b48564a82 100644
--- a/Mathlib/Probability/StrongLaw.lean
+++ b/Mathlib/Probability/StrongLaw.lean
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel
-/
import Mathlib.Probability.IdentDistrib
+import Mathlib.Probability.Independence.Integrable
import Mathlib.MeasureTheory.Integral.DominatedConvergence
import Mathlib.Analysis.SpecificLimits.FloorPow
import Mathlib.Analysis.PSeries
@@ -107,11 +108,11 @@ theorem truncation_eq_of_nonneg {f : α → ℝ} {A : ℝ} (h : ∀ x, 0 ≤ f x
truncation f A = indicator (Set.Ioc 0 A) id ∘ f := by
ext x
rcases (h x).lt_or_eq with (hx | hx)
- · simp only [truncation, indicator, hx, Set.mem_Ioc, id, Function.comp_apply, true_and_iff]
+ · simp only [truncation, indicator, hx, Set.mem_Ioc, id, Function.comp_apply]
by_cases h'x : f x ≤ A
· have : -A < f x := by linarith [h x]
- simp only [this, true_and_iff]
- · simp only [h'x, and_false_iff]
+ simp only [this, true_and]
+ · simp only [h'x, and_false]
· simp only [truncation, indicator, hx, id, Function.comp_apply, ite_self]
theorem truncation_nonneg {f : α → ℝ} (A : ℝ) {x : α} (h : 0 ≤ f x) : 0 ≤ truncation f A x :=
@@ -298,7 +299,7 @@ theorem tsum_prob_mem_Ioi_lt_top {X : Ω → ℝ} (hint : Integrable X) (hnonneg
· simp (config := {contextual := true}) only [Set.mem_Ioc, Set.mem_Ioi,
Set.iUnion_subset_iff, Set.setOf_subset_setOf, imp_true_iff]
rw [this]
- apply tendsto_measure_iUnion
+ apply tendsto_measure_iUnion_atTop
intro m n hmn x hx
exact ⟨hx.1, hx.2.trans (Nat.cast_le.2 hmn)⟩
apply le_of_tendsto_of_tendsto A tendsto_const_nhds
@@ -395,7 +396,7 @@ theorem strong_law_aux1 {c : ℝ} (c_one : 1 < c) {ε : ℝ} (εpos : 0 < ε) :
set Y := fun n : ℕ => truncation (X n) n
set S := fun n => ∑ i ∈ range n, Y i with hS
let u : ℕ → ℕ := fun n => ⌊c ^ n⌋₊
- have u_mono : Monotone u := fun i j hij => Nat.floor_mono (pow_le_pow_right c_one.le hij)
+ have u_mono : Monotone u := fun i j hij => Nat.floor_mono (pow_right_mono₀ c_one.le hij)
have I1 : ∀ K, ∑ j ∈ range K, ((j : ℝ) ^ 2)⁻¹ * Var[Y j] ≤ 2 * 𝔼[X 0] := by
intro K
calc
@@ -419,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,
@@ -456,7 +456,7 @@ theorem strong_law_aux1 {c : ℝ} (c_one : 1 < c) {ε : ℝ} (εpos : 0 < ε) :
refine zero_lt_one.trans_le ?_
apply Nat.le_floor
rw [Nat.cast_one]
- apply one_le_pow_of_one_le c_one.le
+ apply one_le_pow₀ c_one.le
_ = ENNReal.ofReal (∑ i ∈ range N, Var[S (u i)] / (u i * ε) ^ 2) := by
rw [ENNReal.ofReal_sum_of_nonneg fun i _ => ?_]
exact div_nonneg (variance_nonneg _ _) (sq_nonneg _)
@@ -546,7 +546,7 @@ theorem strong_law_aux5 :
· have : -(n : ℝ) < X n ω := by
apply lt_of_lt_of_le _ (hnonneg n ω)
simpa only [Right.neg_neg_iff, Nat.cast_pos] using npos
- simp only [this, true_and_iff, not_le] at h
+ simp only [this, true_and, not_le] at h
exact (hn h).elim
filter_upwards [B] with ω hω
convert isLittleO_sum_range_of_tendsto_zero hω using 1
@@ -562,7 +562,7 @@ theorem strong_law_aux6 {c : ℝ} (c_one : 1 < c) :
have H : ∀ n : ℕ, (0 : ℝ) < ⌊c ^ n⌋₊ := by
intro n
refine zero_lt_one.trans_le ?_
- simp only [Nat.one_le_cast, Nat.one_le_floor_iff, one_le_pow_of_one_le c_one.le n]
+ simp only [Nat.one_le_cast, Nat.one_le_floor_iff, one_le_pow₀ c_one.le]
filter_upwards [strong_law_aux4 X hint hindep hident hnonneg c_one,
strong_law_aux5 X hint hident hnonneg] with ω hω h'ω
rw [← tendsto_sub_nhds_zero_iff, ← Asymptotics.isLittleO_one_iff ℝ]
@@ -602,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
@@ -614,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.
@@ -629,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]
@@ -649,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
@@ -698,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
@@ -716,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) :=
@@ -744,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,
@@ -782,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
@@ -822,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 d2036c459f53a..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]
@@ -228,16 +229,16 @@ theorem evariance_def' [@IsProbabilityMeasure Ω _ ℙ] {X : Ω → ℝ} (hX : A
rw [Memℒp, not_and] at hℒ
specialize hℒ hX
simp only [eLpNorm_eq_lintegral_rpow_nnnorm two_ne_zero ENNReal.two_ne_top, not_lt, top_le_iff,
- ENNReal.toReal_ofNat, one_div, ENNReal.rpow_eq_top_iff, inv_lt_zero, inv_pos, and_true_iff,
+ ENNReal.toReal_ofNat, one_div, ENNReal.rpow_eq_top_iff, inv_lt_zero, inv_pos, and_true,
or_iff_not_imp_left, not_and_or, zero_lt_two] at hℒ
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
- · simp only [Real.coe_toNNReal', max_le_iff, abs_nonneg, and_true_iff]
+ 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 f52d5604cf170..2f15639455bdf 100644
--- a/Mathlib/RepresentationTheory/Action/Basic.lean
+++ b/Mathlib/RepresentationTheory/Action/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.Grp.Basic
import Mathlib.CategoryTheory.SingleObj
@@ -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
@@ -125,6 +124,16 @@ theorem comp_hom {M N K : Action V G} (f : M ⟶ N) (g : N ⟶ K) :
(f ≫ g : Hom M K).hom = f.hom ≫ g.hom :=
rfl
+@[simp]
+theorem hom_inv_hom {M N : Action V G} (f : M ≅ N) :
+ f.hom.hom ≫ f.inv.hom = 𝟙 M.V := by
+ rw [← comp_hom, Iso.hom_inv_id, id_hom]
+
+@[simp]
+theorem inv_hom_hom {M N : Action V G} (f : M ≅ N) :
+ f.inv.hom ≫ f.hom.hom = 𝟙 N.V := by
+ rw [← comp_hom, Iso.inv_hom_id, id_hom]
+
/-- Construct an isomorphism of `G` actions/representations
from an isomorphism of the underlying objects,
where the forward direction commutes with the group action. -/
@@ -145,6 +154,12 @@ instance isIso_hom_mk {M N : Action V G} (f : M.V ⟶ N.V) [IsIso f] (w) :
@IsIso _ _ M N (Hom.mk f w) :=
(mkIso (asIso f) w).isIso_hom
+instance {M N : Action V G} (f : M ≅ N) : IsIso f.hom.hom where
+ out := ⟨f.inv.hom, by simp⟩
+
+instance {M N : Action V G} (f : M ≅ N) : IsIso f.inv.hom where
+ out := ⟨f.hom.hom, by simp⟩
+
namespace FunctorCategoryEquivalence
/-- Auxiliary definition for `functorCategoryEquivalence`. -/
@@ -180,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
@@ -268,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 1ae786bb201e9..16750cee24335 100644
--- a/Mathlib/RepresentationTheory/Action/Concrete.lean
+++ b/Mathlib/RepresentationTheory/Action/Concrete.lean
@@ -1,10 +1,12 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Group.Action.Pi
import Mathlib.CategoryTheory.FintypeCat
+import Mathlib.GroupTheory.GroupAction.Quotient
+import Mathlib.GroupTheory.QuotientGroup.Defs
import Mathlib.RepresentationTheory.Action.Basic
/-!
@@ -36,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
@@ -44,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
@@ -68,6 +70,12 @@ def diagonalOneIsoLeftRegular (G : Type u) [Monoid G] : diagonal G 1 ≅ leftReg
namespace FintypeCat
+/-- If `X` is a type with `[Fintype X]` and `G` acts on `X`, then `G` also acts on
+`FintypeCat.of X`. -/
+instance (G : Type*) (X : Type*) [Monoid G] [MulAction G X] [Fintype X] :
+ MulAction G (FintypeCat.of X) :=
+ inferInstanceAs <| MulAction G X
+
/-- Bundles a finite type `H` with a multiplicative action of `G` as an `Action`. -/
def ofMulAction (G : Type u) (H : FintypeCat.{u}) [Monoid G] [MulAction G H] :
Action FintypeCat (MonCat.of G) where
@@ -79,6 +87,82 @@ theorem ofMulAction_apply {G : Type u} {H : FintypeCat.{u}} [Monoid G] [MulActio
(g : G) (x : H) : (FintypeCat.ofMulAction G H).ρ g x = (g • x : H) :=
rfl
+section
+
+/-- Shorthand notation for the quotient of `G` by `H` as a finite `G`-set. -/
+notation:10 G:10 " ⧸ₐ " H:10 => Action.FintypeCat.ofMulAction G (FintypeCat.of <| G ⧸ H)
+
+variable {G : Type*} [Group G] (H N : Subgroup G) [Fintype (G ⧸ N)]
+
+/-- If `N` is a normal subgroup of `G`, then this is the group homomorphism
+sending an element `g` of `G` to the `G`-endomorphism of `G ⧸ₐ N` given by
+multiplication with `g⁻¹` on the right. -/
+def toEndHom [N.Normal] : G →* End (G ⧸ₐ N) where
+ toFun v := {
+ hom := Quotient.lift (fun σ ↦ ⟦σ * v⁻¹⟧) <| fun a b h ↦ Quotient.sound <| by
+ apply (QuotientGroup.leftRel_apply).mpr
+ simp only [mul_inv_rev, inv_inv]
+ convert_to v * (a⁻¹ * b) * v⁻¹ ∈ N
+ · group
+ · exact Subgroup.Normal.conj_mem ‹_› _ (QuotientGroup.leftRel_apply.mp h) _
+ comm := fun (g : G) ↦ by
+ ext (x : G ⧸ N)
+ induction' x using Quotient.inductionOn with x
+ simp only [FintypeCat.comp_apply, Action.FintypeCat.ofMulAction_apply, Quotient.lift_mk]
+ show Quotient.lift (fun σ ↦ ⟦σ * v⁻¹⟧) _ (⟦g • x⟧) = _
+ simp only [smul_eq_mul, Quotient.lift_mk, mul_assoc]
+ rfl
+ }
+ map_one' := by
+ apply Action.hom_ext
+ ext (x : G ⧸ N)
+ induction' x using Quotient.inductionOn with x
+ simp
+ map_mul' σ τ := by
+ apply Action.hom_ext
+ ext (x : G ⧸ N)
+ induction' x using Quotient.inductionOn with x
+ show ⟦x * (σ * τ)⁻¹⟧ = ⟦x * τ⁻¹ * σ⁻¹⟧
+ rw [mul_inv_rev, mul_assoc]
+
+@[simp]
+lemma toEndHom_apply [N.Normal] (g h : G) : (toEndHom N g).hom ⟦h⟧ = ⟦h * g⁻¹⟧ := rfl
+
+variable {N} in
+lemma toEndHom_trivial_of_mem [N.Normal] {n : G} (hn : n ∈ N) : toEndHom N n = 𝟙 (G ⧸ₐ N) := by
+ apply Action.hom_ext
+ ext (x : G ⧸ N)
+ induction' x using Quotient.inductionOn with μ
+ exact Quotient.sound ((QuotientGroup.leftRel_apply).mpr <| by simpa)
+
+/-- If `H` and `N` are subgroups of a group `G` with `N` normal, there is a canonical
+group homomorphism `H ⧸ N ⊓ H` to the `G`-endomorphisms of `G ⧸ N`. -/
+def quotientToEndHom [N.Normal] : H ⧸ Subgroup.subgroupOf N H →* End (G ⧸ₐ N) :=
+ QuotientGroup.lift (Subgroup.subgroupOf N H) ((toEndHom N).comp H.subtype) <| fun _ uinU' ↦
+ toEndHom_trivial_of_mem uinU'
+
+@[simp]
+lemma quotientToEndHom_mk [N.Normal] (x : H) (g : G) :
+ (quotientToEndHom H N ⟦x⟧).hom ⟦g⟧ = ⟦g * x⁻¹⟧ :=
+ rfl
+
+/-- 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 _ _ hab ↦ Quotient.sound <|
+ (QuotientGroup.leftRel_apply).mpr (h <| (QuotientGroup.leftRel_apply).mp hab)
+ comm g := by
+ ext (x : G ⧸ N)
+ induction' x using Quotient.inductionOn with μ
+ rfl
+
+@[simp]
+lemma quotientToQuotientOfLE_hom_mk [Fintype (G ⧸ H)] (h : N ≤ H) (x : G) :
+ (quotientToQuotientOfLE H N h).hom ⟦x⟧ = ⟦x⟧ :=
+ rfl
+
+end
+
end FintypeCat
section ToMulAction
diff --git a/Mathlib/RepresentationTheory/Action/Limits.lean b/Mathlib/RepresentationTheory/Action/Limits.lean
index 60d9a97e9d74f..3978ae5ce16ce 100644
--- a/Mathlib/RepresentationTheory/Action/Limits.lean
+++ b/Mathlib/RepresentationTheory/Action/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Abelian.FunctorCategory
import Mathlib.CategoryTheory.Abelian.Transfer
diff --git a/Mathlib/RepresentationTheory/Action/Monoidal.lean b/Mathlib/RepresentationTheory/Action/Monoidal.lean
index 022783ffbf8d2..3eecdddcbe909 100644
--- a/Mathlib/RepresentationTheory/Action/Monoidal.lean
+++ b/Mathlib/RepresentationTheory/Action/Monoidal.lean
@@ -1,17 +1,15 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
-import Mathlib.RepresentationTheory.Action.Limits
-import Mathlib.RepresentationTheory.Action.Concrete
-import Mathlib.CategoryTheory.Monoidal.FunctorCategory
-import Mathlib.CategoryTheory.Monoidal.Transport
-import Mathlib.CategoryTheory.Monoidal.Rigid.OfEquivalence
-import Mathlib.CategoryTheory.Monoidal.Rigid.FunctorCategory
import Mathlib.CategoryTheory.Monoidal.Linear
-import Mathlib.CategoryTheory.Monoidal.Braided.Basic
+import Mathlib.CategoryTheory.Monoidal.Rigid.FunctorCategory
+import Mathlib.CategoryTheory.Monoidal.Rigid.OfEquivalence
+import Mathlib.CategoryTheory.Monoidal.Transport
import Mathlib.CategoryTheory.Monoidal.Types.Basic
+import Mathlib.RepresentationTheory.Action.Concrete
+import Mathlib.RepresentationTheory.Action.Limits
/-!
# Induced monoidal structure on `Action V G`
@@ -35,77 +33,36 @@ open MonoidalCategory
variable [MonoidalCategory V]
+@[simps! tensorUnit_V tensorObj_V tensorHom_hom whiskerLeft_hom whiskerRight_hom
+ associator_hom_hom associator_inv_hom leftUnitor_hom_hom leftUnitor_inv_hom
+ rightUnitor_hom_hom rightUnitor_inv_hom]
instance instMonoidalCategory : MonoidalCategory (Action V G) :=
Monoidal.transport (Action.functorCategoryEquivalence _ _).symm
+/- Adding this solves `simpNF` linter report at `tensorUnit_ρ` -/
@[simp]
-theorem tensorUnit_v : (𝟙_ (Action V G)).V = 𝟙_ V :=
- rfl
-
--- Porting note: removed @[simp] as the simpNF linter complains
-theorem tensorUnit_rho {g : G} : (𝟙_ (Action V G)).ρ g = 𝟙 (𝟙_ V) :=
+theorem tensorUnit_ρ' {g : G} :
+ @DFunLike.coe (G →* MonCat.of (End (𝟙_ V))) _ _ _ (𝟙_ (Action V G)).ρ g = 𝟙 (𝟙_ V) := by
rfl
@[simp]
-theorem tensor_v {X Y : Action V G} : (X ⊗ Y).V = X.V ⊗ Y.V :=
- rfl
-
--- Porting note: removed @[simp] as the simpNF linter complains
-theorem tensor_rho {X Y : Action V G} {g : G} : (X ⊗ Y).ρ g = X.ρ g ⊗ Y.ρ g :=
+theorem tensorUnit_ρ {g : G} : (𝟙_ (Action V G)).ρ g = 𝟙 (𝟙_ V) :=
rfl
+/- Adding this solves `simpNF` linter report at `tensor_ρ` -/
@[simp]
-theorem tensor_hom {W X Y Z : Action V G} (f : W ⟶ X) (g : Y ⟶ Z) : (f ⊗ g).hom = f.hom ⊗ g.hom :=
+theorem tensor_ρ' {X Y : Action V G} {g : G} :
+ @DFunLike.coe (G →* MonCat.of (End (X.V ⊗ Y.V))) _ _ _ (X ⊗ Y).ρ g = X.ρ g ⊗ Y.ρ g :=
rfl
@[simp]
-theorem whiskerLeft_hom (X : Action V G) {Y Z : Action V G} (f : Y ⟶ Z) :
- (X ◁ f).hom = X.V ◁ f.hom :=
+theorem tensor_ρ {X Y : Action V G} {g : G} : (X ⊗ Y).ρ g = X.ρ g ⊗ Y.ρ g :=
rfl
-@[simp]
-theorem whiskerRight_hom {X Y : Action V G} (f : X ⟶ Y) (Z : Action V G) :
- (f ▷ Z).hom = f.hom ▷ Z.V :=
- rfl
-
--- Porting note: removed @[simp] as the simpNF linter complains
-theorem associator_hom_hom {X Y Z : Action V G} :
- Hom.hom (α_ X Y Z).hom = (α_ X.V Y.V Z.V).hom := by
- dsimp
- simp
-
--- Porting note: removed @[simp] as the simpNF linter complains
-theorem associator_inv_hom {X Y Z : Action V G} :
- Hom.hom (α_ X Y Z).inv = (α_ X.V Y.V Z.V).inv := by
- dsimp
- simp
-
--- Porting note: removed @[simp] as the simpNF linter complains
-theorem leftUnitor_hom_hom {X : Action V G} : Hom.hom (λ_ X).hom = (λ_ X.V).hom := by
- dsimp
- simp
-
--- Porting note: removed @[simp] as the simpNF linter complains
-theorem leftUnitor_inv_hom {X : Action V G} : Hom.hom (λ_ X).inv = (λ_ X.V).inv := by
- dsimp
- simp
-
--- Porting note: removed @[simp] as the simpNF linter complains
-theorem rightUnitor_hom_hom {X : Action V G} : Hom.hom (ρ_ X).hom = (ρ_ X.V).hom := by
- dsimp
- simp
-
--- Porting note: removed @[simp] as the simpNF linter complains
-theorem rightUnitor_inv_hom {X : Action V G} : Hom.hom (ρ_ X).inv = (ρ_ X.V).inv := by
- dsimp
- simp
-
/-- Given an object `X` isomorphic to the tensor unit of `V`, `X` equipped with the trivial action
is isomorphic to the tensor unit of `Action V G`. -/
def tensorUnitIso {X : V} (f : 𝟙_ V ≅ X) : 𝟙_ (Action V G) ≅ Action.mk X 1 :=
- Action.mkIso f fun _ => by
- simp only [MonoidHom.one_apply, End.one_def, Category.id_comp f.hom, tensorUnit_rho,
- MonCat.oneHom_apply, MonCat.one_of, Category.comp_id]
+ Action.mkIso f
variable (V G)
@@ -114,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
@@ -284,11 +241,11 @@ noncomputable def leftRegularTensorIso (G : Type u) [Group G] (X : Action (Type
comm := fun (g : G) => by
funext ⟨(x₁ : G), (x₂ : X.V)⟩
refine Prod.ext rfl ?_
- erw [tensor_rho, tensor_rho]
+ rw [tensor_ρ, tensor_ρ]
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 6f61040dc4ac8..ec67d8f8cb669 100644
--- a/Mathlib/RepresentationTheory/Basic.lean
+++ b/Mathlib/RepresentationTheory/Basic.lean
@@ -3,12 +3,7 @@ Copyright (c) 2022 Antoine Labelle. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Antoine Labelle
-/
-import Mathlib.Algebra.Group.Equiv.TypeTags
-import Mathlib.Algebra.Module.Defs
-import Mathlib.Algebra.MonoidAlgebra.Basic
-import Mathlib.LinearAlgebra.Dual
import Mathlib.LinearAlgebra.Contraction
-import Mathlib.RingTheory.TensorProduct.Basic
/-!
# Monoid representations
@@ -18,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
@@ -31,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.
-/
@@ -454,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 a0566328c0f4a..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
@@ -32,7 +32,7 @@ noncomputable section
universe u
-open CategoryTheory LinearMap CategoryTheory.MonoidalCategory Representation FiniteDimensional
+open CategoryTheory LinearMap CategoryTheory.MonoidalCategory Representation Module
variable {k : Type u} [Field k]
@@ -51,21 +51,14 @@ theorem char_mul_comm (V : FDRep k G) (g : G) (h : G) :
V.character (h * g) = V.character (g * h) := by simp only [trace_mul_comm, character, map_mul]
@[simp]
-theorem char_one (V : FDRep k G) : V.character 1 = FiniteDimensional.finrank k V := by
+theorem char_one (V : FDRep k G) : V.character 1 = Module.finrank k V := by
simp only [character, map_one, trace_one]
/-- The character is multiplicative under the tensor product. -/
+@[simp]
theorem char_tensor (V W : FDRep k G) : (V ⊗ W).character = V.character * W.character := by
ext g; convert trace_tensorProduct' (V.ρ g) (W.ρ g)
--- Porting note: adding variant of `char_tensor` to make the simp-set confluent
-@[simp]
-theorem char_tensor' (V W : FDRep k G) :
- character (Action.FunctorCategoryEquivalence.inverse.obj
- (Action.FunctorCategoryEquivalence.functor.obj V ⊗
- Action.FunctorCategoryEquivalence.functor.obj W)) = V.character * W.character := by
- simp [← char_tensor]
-
/-- The character of isomorphic representations is the same. -/
theorem char_iso {V W : FDRep k G} (i : V ≅ W) : V.character = W.character := by
ext g
@@ -96,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/FDRep.lean b/Mathlib/RepresentationTheory/FDRep.lean
index b45a965988b28..1f3f8535f0114 100644
--- a/Mathlib/RepresentationTheory/FDRep.lean
+++ b/Mathlib/RepresentationTheory/FDRep.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.FGModuleCat.Limits
import Mathlib.CategoryTheory.Monoidal.Rigid.Braided
@@ -114,7 +114,7 @@ example : MonoidalPreadditive (FDRep k G) := by infer_instance
example : MonoidalLinear k (FDRep k G) := by infer_instance
-open FiniteDimensional
+open Module
open scoped Classical
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 fbe67ec9e3438..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
@@ -146,7 +145,7 @@ theorem dZero_comp_eq : dZero A ∘ₗ (zeroCochainsLequiv A) =
oneCochainsLequiv A ∘ₗ (inhomogeneousCochains A).d 0 1 := by
ext x y
show A.ρ y (x default) - x default = _ + ({0} : Finset _).sum _
- simp_rw [Fin.coe_fin_one, zero_add, pow_one, neg_smul, one_smul,
+ simp_rw [Fin.val_eq_zero, zero_add, pow_one, neg_smul, one_smul,
Finset.sum_singleton, sub_eq_add_neg]
rcongr i <;> exact Fin.elim0 i
@@ -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 c225b3a938bec..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
@@ -136,7 +136,7 @@ theorem actionDiagonalSucc_inv_apply {G : Type u} [Group G] {n : ℕ} (g : G) (f
dsimp only [actionDiagonalSucc]
simp only [Iso.trans_inv, comp_hom, hn, diagonalSucc_inv_hom, types_comp_apply, tensorIso_inv,
Iso.refl_inv, Action.tensorHom, id_hom, tensor_apply, types_id_apply,
- leftRegularTensorIso_inv_hom, tensor_rho, leftRegular_ρ_apply, Pi.smul_apply, smul_eq_mul]
+ leftRegularTensorIso_inv_hom, tensor_ρ, leftRegular_ρ_apply, Pi.smul_apply, smul_eq_mul]
refine' Fin.cases _ _ x
· simp only [Fin.cons_zero, Fin.partialProd_zero, mul_one]
· intro i
@@ -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 f35efe285d18d..a3351fef477c7 100644
--- a/Mathlib/RepresentationTheory/Maschke.lean
+++ b/Mathlib/RepresentationTheory/Maschke.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.MonoidAlgebra.Basic
import Mathlib.LinearAlgebra.Basis.VectorSpace
@@ -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 8cf8b61925ff3..e6d2b8e5cd51e 100644
--- a/Mathlib/RepresentationTheory/Rep.lean
+++ b/Mathlib/RepresentationTheory/Rep.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.ModuleCat.Adjunctions
import Mathlib.Algebra.Category.ModuleCat.Limits
@@ -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 }
@@ -361,7 +357,7 @@ def homEquiv (A B C : Rep k G) : (A ⊗ B ⟶ C) ≃ (B ⟶ (Rep.ihom A).obj C)
comm := fun g => TensorProduct.ext' fun x y => by
/- Porting note: rest of broken proof was
dsimp only [MonoidalCategory.tensorLeft_obj, ModuleCat.comp_def, LinearMap.comp_apply,
- tensor_rho, ModuleCat.MonoidalCategory.hom_apply, TensorProduct.map_tmul]
+ tensor_ρ, ModuleCat.MonoidalCategory.hom_apply, TensorProduct.map_tmul]
simp only [TensorProduct.uncurry_apply f.hom.flip, LinearMap.flip_apply, Action_ρ_eq_ρ,
hom_comm_apply f g y, Rep.ihom_obj_ρ_apply, LinearMap.comp_apply, ρ_inv_self_apply] -/
change TensorProduct.uncurry k _ _ _ f.hom.flip (A.ρ g x ⊗ₜ[k] B.ρ g y) =
@@ -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}
@@ -404,7 +400,7 @@ theorem ihom_obj_ρ_def (A B : Rep k G) : ((ihom A).obj B).ρ = ((Rep.ihom A).ob
@[simp]
theorem homEquiv_def (A B C : Rep k G) : (ihom.adjunction A).homEquiv B C = Rep.homEquiv A B C :=
- rfl
+ congrFun (congrFun (Adjunction.mkOfHomEquiv_homEquiv _) _) _
@[simp]
theorem ihom_ev_app_hom (A B : Rep k G) :
@@ -445,7 +441,9 @@ theorem MonoidalClosed.linearHomEquivComm_hom (f : A ⊗ B ⟶ C) :
rfl
theorem MonoidalClosed.linearHomEquiv_symm_hom (f : B ⟶ A ⟶[Rep k G] C) :
- ((MonoidalClosed.linearHomEquiv A B C).symm f).hom = TensorProduct.uncurry k A B C f.hom.flip :=
+ ((MonoidalClosed.linearHomEquiv A B C).symm f).hom =
+ TensorProduct.uncurry k A B C f.hom.flip := by
+ simp [linearHomEquiv]
rfl
theorem MonoidalClosed.linearHomEquivComm_symm_hom (f : A ⟶ B ⟶[Rep k G] C) :
@@ -567,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 7532a1f66cbdf..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
@@ -353,11 +352,11 @@ noncomputable instance instField [Fact (Irreducible f)] : Field (AdjoinRoot f) w
ratCast_def q := by
rw [← map_natCast (of f), ← map_intCast (of f), ← map_div₀, ← Rat.cast_def]; rfl
nnqsmul_def q x :=
- AdjoinRoot.induction_on (C := fun y ↦ q • y = (of f) q * y) x fun p ↦ by
+ AdjoinRoot.induction_on f (C := fun y ↦ q • y = (of f) q * y) x fun p ↦ by
simp only [smul_mk, of, RingHom.comp_apply, ← (mk f).map_mul, Polynomial.nnqsmul_eq_C_mul]
qsmul_def q x :=
-- Porting note: I gave the explicit motive and changed `rw` to `simp`.
- AdjoinRoot.induction_on (C := fun y ↦ q • y = (of f) q * y) x fun p ↦ by
+ AdjoinRoot.induction_on f (C := fun y ↦ q • y = (of f) q * y) x fun p ↦ by
simp only [smul_mk, of, RingHom.comp_apply, ← (mk f).map_mul, Polynomial.qsmul_eq_C_mul]
theorem coe_injective (h : degree f ≠ 0) : Function.Injective ((↑) : K → AdjoinRoot f) :=
@@ -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 0326b17fa9001..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 ?_
@@ -79,16 +137,24 @@ theorem Subalgebra.isAlgebraic_iff (S : Subalgebra R A) :
/-- An algebra is algebraic if and only if it is algebraic as a subalgebra. -/
theorem Algebra.isAlgebraic_iff : Algebra.IsAlgebraic R A ↔ (⊤ : Subalgebra R A).IsAlgebraic := by
delta Subalgebra.IsAlgebraic
- simp only [Algebra.isAlgebraic_def, Algebra.mem_top, forall_prop_of_true, iff_self_iff]
+ simp only [Algebra.isAlgebraic_def, Algebra.mem_top, forall_prop_of_true]
theorem isAlgebraic_iff_not_injective {x : A} :
IsAlgebraic R x ↔ ¬Function.Injective (Polynomial.aeval x : R[X] →ₐ[R] A) := by
simp only [IsAlgebraic, injective_iff_map_eq_zero, not_forall, and_comm, exists_prop]
+/-- 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 b0e1db85e19c4..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
@@ -82,11 +81,25 @@ theorem algebraicIndependent_iff_injective_aeval :
@[simp]
theorem algebraicIndependent_empty_type_iff [IsEmpty ι] :
AlgebraicIndependent R x ↔ Injective (algebraMap R A) := by
- have : aeval x = (Algebra.ofId R A).comp (@isEmptyAlgEquiv R ι _ _).toAlgHom := by
- ext i
- exact IsEmpty.elim' ‹IsEmpty ι› i
- rw [AlgebraicIndependent, this, ← Injective.of_comp_iff' _ (@isEmptyAlgEquiv R ι _ _).bijective]
- rfl
+ 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
@@ -144,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) :
@@ -369,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)) =
@@ -413,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. -/
@@ -436,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 60965f6c689e4..6942b8afeb66c 100644
--- a/Mathlib/RingTheory/Artinian.lean
+++ b/Mathlib/RingTheory/Artinian.lean
@@ -91,22 +91,39 @@ theorem isArtinian_of_surjective (f : M →ₗ[R] P) (hf : Function.Surjective f
show A.comap f < B.comap f from Submodule.comap_strictMono_of_surjective hf hAB)
(InvImage.wf (Submodule.comap f) IsWellFounded.wf)⟩
+instance isArtinian_of_quotient_of_artinian
+ (N : Submodule R M) [IsArtinian R M] : IsArtinian R (M ⧸ N) :=
+ isArtinian_of_surjective M (Submodule.mkQ N) (Submodule.Quotient.mk_surjective N)
+
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)
- (hf : Function.Injective f) (hg : Function.Surjective g)
(h : LinearMap.range f = LinearMap.ker g) : IsArtinian R N :=
- wellFounded_lt_exact_sequence (LinearMap.range f) (Submodule.map f)
- (Submodule.comap f) (Submodule.comap g) (Submodule.map g) (Submodule.gciMapComap hf)
- (Submodule.giMapComap hg)
- (by simp [Submodule.map_comap_eq, inf_comm]) (by simp [Submodule.comap_map_eq, h])
+ wellFounded_lt_exact_sequence (LinearMap.range f) (Submodule.map (f.ker.liftQ f le_rfl))
+ (Submodule.comap (f.ker.liftQ f le_rfl))
+ (Submodule.comap g.rangeRestrict) (Submodule.map g.rangeRestrict)
+ (Submodule.gciMapComap <| LinearMap.ker_eq_bot.mp <| Submodule.ker_liftQ_eq_bot _ _ _ le_rfl)
+ (Submodule.giMapComap g.surjective_rangeRestrict)
+ (by simp [Submodule.map_comap_eq, inf_comm, Submodule.range_liftQ])
+ (by simp [Submodule.comap_map_eq, h])
+
+theorem isArtinian_iff_submodule_quotient (S : Submodule R P) :
+ IsArtinian R P ↔ IsArtinian R S ∧ IsArtinian R (P ⧸ S) := by
+ refine ⟨fun h ↦ ⟨inferInstance, inferInstance⟩, fun ⟨_, _⟩ ↦ ?_⟩
+ apply isArtinian_of_range_eq_ker S.subtype S.mkQ
+ rw [Submodule.ker_mkQ, Submodule.range_subtype]
instance isArtinian_prod [IsArtinian R M] [IsArtinian R P] : IsArtinian R (M × P) :=
- isArtinian_of_range_eq_ker (LinearMap.inl R M P) (LinearMap.snd R M P) LinearMap.inl_injective
- LinearMap.snd_surjective (LinearMap.range_inl R M P)
+ isArtinian_of_range_eq_ker (LinearMap.inl R M P) (LinearMap.snd R M P) (LinearMap.range_inl R M P)
instance (priority := 100) isArtinian_of_finite [Finite M] : IsArtinian R M :=
⟨Finite.wellFounded_of_trans_of_irrefl _⟩
@@ -114,31 +131,38 @@ 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)],
- ∀ [∀ i, Module R (M i)], ∀ [∀ i, IsArtinian R (M i)], IsArtinian R (∀ i, M i) := by
+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 _ _ _ ι
- · intro α β e hα M _ _ _ _
- have := @hα
- exact isArtinian_of_linearEquiv (LinearEquiv.piCongrLeft R M e)
- · intro M _ _ _ _
- infer_instance
- · intro α _ ih M _ _ _ _
- have := @ih
- exact isArtinian_of_linearEquiv (LinearEquiv.piOptionEquivProd R).symm
+ · exact fun e h ↦ isArtinian_of_linearEquiv (LinearEquiv.piCongrLeft R _ e)
+ · infer_instance
+ · exact fun ih ↦ isArtinian_of_linearEquiv (LinearEquiv.piOptionEquivProd R).symm
/-- 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
@@ -336,10 +360,6 @@ theorem Ring.isArtinian_of_zero_eq_one {R} [Ring R] (h01 : (0 : R) = 1) : IsArti
theorem isArtinian_of_submodule_of_artinian (R M) [Ring R] [AddCommGroup M] [Module R M]
(N : Submodule R M) (_ : IsArtinian R M) : IsArtinian R N := inferInstance
-instance isArtinian_of_quotient_of_artinian (R) [Ring R] (M) [AddCommGroup M] [Module R M]
- (N : Submodule R M) [IsArtinian R M] : IsArtinian R (M ⧸ N) :=
- isArtinian_of_surjective M (Submodule.mkQ N) (Submodule.Quotient.mk_surjective N)
-
/-- If `M / S / R` is a scalar tower, and `M / R` is Artinian, then `M / S` is also Artinian. -/
theorem isArtinian_of_tower (R) {S M} [CommRing R] [Ring S] [AddCommGroup M] [Algebra R S]
[Module S M] [Module R M] [IsScalarTower R S M] (h : IsArtinian R M) : IsArtinian S M :=
@@ -520,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 4ef7731887a6d..6bc38c5db39ce 100644
--- a/Mathlib/RingTheory/Bezout.lean
+++ b/Mathlib/RingTheory/Bezout.lean
@@ -51,13 +51,13 @@ theorem TFAE [IsBezout R] [IsDomain R] :
[IsNoetherianRing R, IsPrincipalIdealRing R, UniqueFactorizationMonoid R, WfDvdMonoid R] := by
classical
tfae_have 1 → 2
- · intro H; exact ⟨fun I => isPrincipal_of_FG _ (IsNoetherian.noetherian _)⟩
+ | _ => inferInstance
tfae_have 2 → 3
- · intro; infer_instance
+ | _ => inferInstance
tfae_have 3 → 4
- · intro; infer_instance
+ | _ => inferInstance
tfae_have 4 → 1
- · rintro ⟨h⟩
+ | ⟨h⟩ => by
rw [isNoetherianRing_iff, isNoetherian_iff_fg_wellFounded]
refine ⟨RelEmbedding.wellFounded ?_ h⟩
have : ∀ I : { J : Ideal R // J.FG }, ∃ x : R, (I : Ideal R) = Ideal.span {x} :=
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 ed816bb3683ea..c188aa8e7b497 100644
--- a/Mathlib/RingTheory/ChainOfDivisors.lean
+++ b/Mathlib/RingTheory/ChainOfDivisors.lean
@@ -160,7 +160,7 @@ theorem element_of_chain_eq_pow_second_of_chain {q r : Associates M} {n : ℕ} (
rw [Finset.card_image_iff]
refine Set.injOn_of_injective (fun m m' h => Fin.ext ?_)
refine
- pow_injective_of_not_unit (element_of_chain_not_isUnit_of_index_ne_zero (by simp) h₁) ?_ h
+ pow_injective_of_not_isUnit (element_of_chain_not_isUnit_of_index_ne_zero (by simp) h₁) ?_ h
exact Irreducible.ne_zero (second_of_chain_is_irreducible hn h₁ (@h₂) hq)
suffices H' : ∀ r ∈ Finset.univ.image fun m : Fin (i + 1) => c 1 ^ (m : ℕ), r ≤ q by
simp only [← Nat.succ_le_iff, Nat.succ_eq_add_one, ← this]
@@ -302,37 +302,33 @@ 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
-variable [Unique Mˣ] [Unique Nˣ]
+variable [Subsingleton Mˣ] [Subsingleton Nˣ]
/-- The order isomorphism between the factors of `mk m` and the factors of `mk n` induced by a
bijection between the factors of `m` and the factors of `n` that preserves `∣`. -/
@@ -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 03811b4c741c4..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
@@ -62,6 +62,9 @@ def Coalgebra.Repr.arbitrary (R : Type u) {A : Type v}
index := TensorProduct.exists_finset (R := R) (CoalgebraStruct.comul a) |>.choose
eq := TensorProduct.exists_finset (R := R) (CoalgebraStruct.comul a) |>.choose_spec.symm
+@[inherit_doc Coalgebra.Repr.arbitrary]
+scoped[Coalgebra] notation "ℛ" => Coalgebra.Repr.arbitrary
+
namespace Coalgebra
export CoalgebraStruct (comul counit)
end Coalgebra
@@ -115,6 +118,44 @@ lemma sum_tmul_counit_eq {a : A} (repr : Coalgebra.Repr R a) :
∑ i ∈ repr.index, (repr.left i) ⊗ₜ counit (R := R) (repr.right i) = a ⊗ₜ[R] 1 := by
simpa [← repr.eq, map_sum] using congr($(lTensor_counit_comp_comul (R := R) (A := A)) a)
+@[simp]
+lemma sum_tmul_tmul_eq {a : A} (repr : Repr R a)
+ (a₁ : (i : repr.ι) → Repr R (repr.left i)) (a₂ : (i : repr.ι) → Repr R (repr.right i)) :
+ ∑ i in repr.index, ∑ j in (a₁ i).index,
+ (a₁ i).left j ⊗ₜ[R] (a₁ i).right j ⊗ₜ[R] repr.right i
+ = ∑ i in repr.index, ∑ j in (a₂ i).index,
+ repr.left i ⊗ₜ[R] (a₂ i).left j ⊗ₜ[R] (a₂ i).right j := by
+ simpa [(a₂ _).eq, ← (a₁ _).eq, ← TensorProduct.tmul_sum,
+ TensorProduct.sum_tmul, ← repr.eq] using congr($(coassoc (R := R)) a)
+
+@[simp]
+theorem sum_counit_tmul_map_eq {B : Type*} [AddCommMonoid B] [Module R B]
+ {F : Type*} [FunLike F A B] [LinearMapClass F R A B] (f : F) (a : A) {repr : Repr R a} :
+ ∑ i in repr.index, counit (R := R) (repr.left i) ⊗ₜ f (repr.right i) = 1 ⊗ₜ[R] f a := by
+ have := sum_counit_tmul_eq repr
+ apply_fun LinearMap.lTensor R (f : A →ₗ[R] B) at this
+ simp_all only [map_sum, LinearMap.lTensor_tmul, LinearMap.coe_coe]
+
+@[simp]
+theorem sum_map_tmul_counit_eq {B : Type*} [AddCommMonoid B] [Module R B]
+ {F : Type*} [FunLike F A B] [LinearMapClass F R A B] (f : F) (a : A) {repr : Repr R a} :
+ ∑ i in repr.index, f (repr.left i) ⊗ₜ counit (R := R) (repr.right i) = f a ⊗ₜ[R] 1 := by
+ have := sum_tmul_counit_eq repr
+ apply_fun LinearMap.rTensor R (f : A →ₗ[R] B) at this
+ simp_all only [map_sum, LinearMap.rTensor_tmul, LinearMap.coe_coe]
+
+@[simp]
+theorem sum_map_tmul_tmul_eq {B : Type*} [AddCommMonoid B] [Module R B]
+ {F : Type*} [FunLike F A B] [LinearMapClass F R A B] (f g h : F) (a : A) {repr : Repr R a}
+ {a₁ : (i : repr.ι) → Repr R (repr.left i)} {a₂ : (i : repr.ι) → Repr R (repr.right i)} :
+ ∑ i in repr.index, ∑ j in (a₂ i).index,
+ f (repr.left i) ⊗ₜ (g ((a₂ i).left j) ⊗ₜ h ((a₂ i).right j)) =
+ ∑ i in repr.index, ∑ j in (a₁ i).index,
+ f ((a₁ i).left j) ⊗ₜ[R] (g ((a₁ i).right j) ⊗ₜ[R] h (repr.right i)) := by
+ have := sum_tmul_tmul_eq repr a₁ a₂
+ apply_fun TensorProduct.map (f : A →ₗ[R] B)
+ (TensorProduct.map (g : A →ₗ[R] B) (h : A →ₗ[R] B)) at this
+ simp_all only [map_sum, TensorProduct.map_tmul, LinearMap.coe_coe]
end Coalgebra
@@ -218,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]
@@ -284,8 +387,7 @@ open Coalgebra
variable {R A B : Type*} [CommSemiring R] [AddCommMonoid A] [AddCommMonoid B]
[Module R A] [Module R B] [CoalgebraStruct R A] [CoalgebraStruct R B]
-/-- The coalgebra instance will be defined in #11975, in
-`Mathlib.RingTheory.Coalgebra.TensorProduct`. -/
+/-- See `Mathlib.RingTheory.Coalgebra.TensorProduct` for the `Coalgebra` instance. -/
@[simps] instance instCoalgebraStruct :
CoalgebraStruct R (A ⊗[R] B) where
comul := TensorProduct.tensorTensorTensorComm R A A B B ∘ₗ TensorProduct.map comul comul
diff --git a/Mathlib/RingTheory/Coalgebra/Equiv.lean b/Mathlib/RingTheory/Coalgebra/Equiv.lean
index f1e8563bdc49c..843220c0bfa2f 100644
--- a/Mathlib/RingTheory/Coalgebra/Equiv.lean
+++ b/Mathlib/RingTheory/Coalgebra/Equiv.lean
@@ -200,10 +200,23 @@ def symm (e : A ≃ₗc[R] B) : B ≃ₗc[R] A :=
theorem symm_toLinearEquiv (e : A ≃ₗc[R] B) :
e.symm = (e : A ≃ₗ[R] B).symm := rfl
+theorem coe_symm_toLinearEquiv (e : A ≃ₗc[R] B) :
+ ⇑(e : A ≃ₗ[R] B).symm = e.symm := rfl
+
@[simp]
theorem symm_toCoalgHom (e : A ≃ₗc[R] B) :
((e.symm : B →ₗc[R] A) : B →ₗ[R] A) = (e : A ≃ₗ[R] B).symm := rfl
+@[simp]
+theorem symm_apply_apply (e : A ≃ₗc[R] B) (x) :
+ e.symm (e x) = x :=
+ LinearEquiv.symm_apply_apply (e : A ≃ₗ[R] B) x
+
+@[simp]
+theorem apply_symm_apply (e : A ≃ₗc[R] B) (x) :
+ e (e.symm x) = x :=
+ LinearEquiv.apply_symm_apply (e : A ≃ₗ[R] B) x
+
/-- See Note [custom simps projection] -/
def Simps.symm_apply {R : Type*} [CommSemiring R]
{A : Type*} {B : Type*} [AddCommMonoid A] [AddCommMonoid B] [Module R A] [Module R B]
@@ -240,4 +253,35 @@ theorem coe_toEquiv_trans : (e₁₂ : A ≃ B).trans e₂₃ = (e₁₂.trans e
rfl
end
+variable [CommSemiring R] [AddCommMonoid A] [Module R A] [Coalgebra R A]
+ [AddCommMonoid B] [Module R B] [CoalgebraStruct R B]
+
+/-- Let `A` be an `R`-coalgebra and let `B` be an `R`-module with a `CoalgebraStruct`.
+A linear equivalence `A ≃ₗ[R] B` that respects the `CoalgebraStruct`s defines an `R`-coalgebra
+structure on `B`. -/
+@[reducible] def toCoalgebra (f : A ≃ₗc[R] B) :
+ Coalgebra R B where
+ coassoc := by
+ simp only [← ((f : A ≃ₗ[R] B).comp_toLinearMap_symm_eq _ _).2 f.map_comp_comul,
+ ← LinearMap.comp_assoc]
+ congr 1
+ ext x
+ simpa only [toCoalgHom_eq_coe, CoalgHom.toLinearMap_eq_coe, LinearMap.coe_comp,
+ LinearEquiv.coe_coe, Function.comp_apply, ← (ℛ R _).eq, map_sum, TensorProduct.map_tmul,
+ LinearMap.coe_coe, CoalgHom.coe_coe, LinearMap.rTensor_tmul, coe_symm_toLinearEquiv,
+ symm_apply_apply, LinearMap.lTensor_comp_map, TensorProduct.sum_tmul,
+ TensorProduct.assoc_tmul, TensorProduct.tmul_sum] using (sum_map_tmul_tmul_eq f f f x).symm
+ rTensor_counit_comp_comul := by
+ simp_rw [(f.toLinearEquiv.eq_comp_toLinearMap_symm _ _).2 f.counit_comp,
+ ← (f.toLinearEquiv.comp_toLinearMap_symm_eq _ _).2 f.map_comp_comul, ← LinearMap.comp_assoc,
+ f.toLinearEquiv.comp_toLinearMap_symm_eq]
+ ext x
+ simp [← (ℛ R _).eq, coe_symm_toLinearEquiv]
+ lTensor_counit_comp_comul := by
+ simp_rw [(f.toLinearEquiv.eq_comp_toLinearMap_symm _ _).2 f.counit_comp,
+ ← (f.toLinearEquiv.comp_toLinearMap_symm_eq _ _).2 f.map_comp_comul, ← LinearMap.comp_assoc,
+ f.toLinearEquiv.comp_toLinearMap_symm_eq]
+ ext x
+ simp [← (ℛ R _).eq, coe_symm_toLinearEquiv]
+
end CoalgEquiv
diff --git a/Mathlib/RingTheory/Coalgebra/Hom.lean b/Mathlib/RingTheory/Coalgebra/Hom.lean
index b10428555036d..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 :=
@@ -308,16 +308,4 @@ def Repr.induced {a : A} (repr : Repr R a)
eq := (congr($((CoalgHomClass.map_comp_comul φ).symm) a).trans <|
by rw [LinearMap.comp_apply, ← repr.eq, map_sum]; rfl).symm
-@[simp]
-lemma sum_tmul_counit_apply_eq
- {F : Type*} [FunLike F A B] [CoalgHomClass F R A B] (φ : F) {a : A} (repr : Repr R a) :
- ∑ i ∈ repr.index, counit (R := R) (repr.left i) ⊗ₜ φ (repr.right i) = 1 ⊗ₜ[R] φ a := by
- simp [← sum_counit_tmul_eq (repr.induced φ)]
-
-@[simp]
-lemma sum_tmul_apply_counit_eq
- {F : Type*} [FunLike F A B] [CoalgHomClass F R A B] (φ : F) {a : A} (repr : Repr R a) :
- ∑ i ∈ repr.index, φ (repr.left i) ⊗ₜ counit (R := R) (repr.right i) = φ a ⊗ₜ[R] 1 := by
- simp [← sum_tmul_counit_eq (repr.induced φ)]
-
end Coalgebra
diff --git a/Mathlib/RingTheory/Coalgebra/TensorProduct.lean b/Mathlib/RingTheory/Coalgebra/TensorProduct.lean
new file mode 100644
index 0000000000000..5226e76ef5d0e
--- /dev/null
+++ b/Mathlib/RingTheory/Coalgebra/TensorProduct.lean
@@ -0,0 +1,201 @@
+/-
+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.Algebra.Category.CoalgebraCat.ComonEquivalence
+
+/-!
+# Tensor products of coalgebras
+
+Given two `R`-coalgebras `M, N`, we can define a natural comultiplication map
+`Δ : M ⊗[R] N → (M ⊗[R] N) ⊗[R] (M ⊗[R] N)` and counit map `ε : M ⊗[R] N → R` induced by
+the comultiplication and counit maps of `M` and `N`. These `Δ, ε` are declared as linear maps
+in `TensorProduct.instCoalgebraStruct` in `Mathlib.RingTheory.Coalgebra.Basic`.
+
+In this file we show that `Δ, ε` satisfy the axioms of a coalgebra, and also define other data
+in the monoidal structure on `R`-coalgebras, like the tensor product of two coalgebra morphisms
+as a coalgebra morphism.
+
+## Implementation notes
+
+We keep the linear maps underlying `Δ, ε` and other definitions in this file syntactically equal
+to the corresponding definitions for tensor products of modules in the hope that this makes
+life easier. However, to fill in prop fields, we use the API in
+`Mathlib.Algebra.Category.CoalgebraCat.ComonEquivalence`. That file defines the monoidal category
+structure on coalgebras induced by an equivalence with comonoid objects in the category of modules,
+`CoalgebraCat.instMonoidalCategoryAux`, but we do not declare this as an instance - we just use it
+to prove things. Then, we use the definitions in this file to make a monoidal category instance on
+`CoalgebraCat R` in `Mathlib.Algebra.Category.CoalgebraCat.Monoidal` that has simpler data.
+
+However, this approach forces our coalgebras to be in the same universe as the base ring `R`,
+since it relies on the monoidal category structure on `ModuleCat R`, which is currently
+universe monomorphic. Any contribution that achieves universe polymorphism would be welcome. For
+instance, the tensor product of coalgebras 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 CategoryTheory
+open scoped TensorProduct
+
+section
+
+variable {R M N P Q : Type u} [CommRing R]
+ [AddCommGroup M] [AddCommGroup N] [Module R M] [Module R N] [Coalgebra R M] [Coalgebra R N]
+
+open MonoidalCategory in
+noncomputable instance TensorProduct.instCoalgebra : Coalgebra R (M ⊗[R] N) :=
+ let I := Monoidal.transport ((CoalgebraCat.comonEquivalence R).symm)
+ CoalgEquiv.toCoalgebra
+ (A := (CoalgebraCat.of R M ⊗ CoalgebraCat.of R N : CoalgebraCat R))
+ { LinearEquiv.refl R _ with
+ counit_comp := rfl
+ map_comp_comul := by
+ rw [CoalgebraCat.ofComonObjCoalgebraStruct_comul]
+ simp [-Mon_.monMonoidalStruct_tensorObj_X,
+ ModuleCat.MonoidalCategory.instMonoidalCategoryStruct_tensorHom,
+ ModuleCat.comp_def, ModuleCat.of, ModuleCat.asHom,
+ ModuleCat.MonoidalCategory.tensor_μ_eq_tensorTensorTensorComm] }
+
+end
+
+namespace Coalgebra
+namespace TensorProduct
+
+open CoalgebraCat.MonoidalCategoryAux MonoidalCategory
+
+variable {R M N P Q : Type u} [CommRing R]
+ [AddCommGroup M] [AddCommGroup N] [AddCommGroup P] [AddCommGroup Q] [Module R M] [Module R N]
+ [Module R P] [Module R Q] [Coalgebra R M] [Coalgebra R N] [Coalgebra R P] [Coalgebra R Q]
+
+attribute [local instance] CoalgebraCat.instMonoidalCategoryAux in
+section
+
+/-- The tensor product of two coalgebra morphisms as a coalgebra morphism. -/
+noncomputable def map (f : M →ₗc[R] N) (g : P →ₗc[R] Q) :
+ M ⊗[R] P →ₗc[R] N ⊗[R] Q where
+ toLinearMap := _root_.TensorProduct.map f.toLinearMap g.toLinearMap
+ counit_comp := by
+ simp_rw [← tensorHom_toLinearMap]
+ apply (CoalgebraCat.ofHom f ⊗ CoalgebraCat.ofHom g).1.counit_comp
+ map_comp_comul := by
+ simp_rw [← tensorHom_toLinearMap, ← comul_tensorObj]
+ apply (CoalgebraCat.ofHom f ⊗ CoalgebraCat.ofHom g).1.map_comp_comul
+
+@[simp]
+theorem map_tmul (f : M →ₗc[R] N) (g : P →ₗc[R] Q) (x : M) (y : P) :
+ map f g (x ⊗ₜ y) = f x ⊗ₜ g y :=
+ rfl
+
+@[simp]
+theorem map_toLinearMap (f : M →ₗc[R] N) (g : P →ₗc[R] Q) :
+ map f g = _root_.TensorProduct.map (f : M →ₗ[R] N) (g : P →ₗ[R] Q) := rfl
+
+variable (R M N P)
+
+/-- The associator for tensor products of R-coalgebras, as a coalgebra equivalence. -/
+protected noncomputable def assoc :
+ (M ⊗[R] N) ⊗[R] P ≃ₗc[R] M ⊗[R] (N ⊗[R] P) :=
+ { _root_.TensorProduct.assoc R M N P with
+ counit_comp := by
+ simp_rw [← associator_hom_toLinearMap, ← counit_tensorObj_tensorObj_right,
+ ← counit_tensorObj_tensorObj_left]
+ apply CoalgHom.counit_comp (α_ (CoalgebraCat.of R M) (CoalgebraCat.of R N)
+ (CoalgebraCat.of R P)).hom.1
+ map_comp_comul := by
+ simp_rw [← associator_hom_toLinearMap, ← comul_tensorObj_tensorObj_left,
+ ← comul_tensorObj_tensorObj_right]
+ exact CoalgHom.map_comp_comul (α_ (CoalgebraCat.of R M)
+ (CoalgebraCat.of R N) (CoalgebraCat.of R P)).hom.1 }
+
+variable {R M N P}
+
+@[simp]
+theorem assoc_tmul (x : M) (y : N) (z : P) :
+ Coalgebra.TensorProduct.assoc R M N P ((x ⊗ₜ y) ⊗ₜ z) = x ⊗ₜ (y ⊗ₜ z) :=
+ rfl
+
+@[simp]
+theorem assoc_symm_tmul (x : M) (y : N) (z : P) :
+ (Coalgebra.TensorProduct.assoc R M N P).symm (x ⊗ₜ (y ⊗ₜ z)) = (x ⊗ₜ y) ⊗ₜ z :=
+ rfl
+
+@[simp]
+theorem assoc_toLinearEquiv :
+ Coalgebra.TensorProduct.assoc R M N P = _root_.TensorProduct.assoc R M N P := rfl
+
+variable (R M)
+
+/-- The base ring is a left identity for the tensor product of coalgebras, up to
+coalgebra equivalence. -/
+protected noncomputable def lid : R ⊗[R] M ≃ₗc[R] M :=
+ { _root_.TensorProduct.lid R M with
+ counit_comp := by
+ simp only [← leftUnitor_hom_toLinearMap]
+ apply CoalgHom.counit_comp (λ_ (CoalgebraCat.of R M)).hom.1
+ map_comp_comul := by
+ simp_rw [← leftUnitor_hom_toLinearMap, ← comul_tensorObj]
+ apply CoalgHom.map_comp_comul (λ_ (CoalgebraCat.of R M)).hom.1 }
+
+variable {R M}
+
+@[simp]
+theorem lid_toLinearEquiv :
+ (Coalgebra.TensorProduct.lid R M) = _root_.TensorProduct.lid R M := rfl
+
+@[simp]
+theorem lid_tmul (r : R) (a : M) : Coalgebra.TensorProduct.lid R M (r ⊗ₜ a) = r • a := rfl
+
+@[simp]
+theorem lid_symm_apply (a : M) : (Coalgebra.TensorProduct.lid R M).symm a = 1 ⊗ₜ a := rfl
+
+variable (R M)
+
+/-- The base ring is a right identity for the tensor product of coalgebras, up to
+coalgebra equivalence. -/
+protected noncomputable def rid : M ⊗[R] R ≃ₗc[R] M :=
+ { _root_.TensorProduct.rid R M with
+ counit_comp := by
+ simp only [← rightUnitor_hom_toLinearMap]
+ apply CoalgHom.counit_comp (ρ_ (CoalgebraCat.of R M)).hom.1
+ map_comp_comul := by
+ simp_rw [← rightUnitor_hom_toLinearMap, ← comul_tensorObj]
+ apply CoalgHom.map_comp_comul (ρ_ (CoalgebraCat.of R M)).hom.1 }
+
+variable {R M}
+
+@[simp]
+theorem rid_toLinearEquiv :
+ (Coalgebra.TensorProduct.rid R M) = _root_.TensorProduct.rid R M := rfl
+
+@[simp]
+theorem rid_tmul (r : R) (a : M) : Coalgebra.TensorProduct.rid R M (a ⊗ₜ r) = r • a := rfl
+
+@[simp]
+theorem rid_symm_apply (a : M) : (Coalgebra.TensorProduct.rid R M).symm a = a ⊗ₜ 1 := rfl
+
+end
+
+end TensorProduct
+end Coalgebra
+namespace CoalgHom
+
+variable {R M N P : Type u} [CommRing R]
+ [AddCommGroup M] [AddCommGroup N] [AddCommGroup P] [Module R M] [Module R N]
+ [Module R P] [Coalgebra R M] [Coalgebra R N] [Coalgebra R P]
+
+variable (M)
+
+/-- `lTensor M f : M ⊗ N →ₗc M ⊗ P` is the natural coalgebra morphism induced by `f : N →ₗc P`. -/
+noncomputable abbrev lTensor (f : N →ₗc[R] P) : M ⊗[R] N →ₗc[R] M ⊗[R] P :=
+ Coalgebra.TensorProduct.map (CoalgHom.id R M) f
+
+/-- `rTensor M f : N ⊗ M →ₗc P ⊗ M` is the natural coalgebra morphism induced by `f : N →ₗc P`. -/
+noncomputable abbrev rTensor (f : N →ₗc[R] P) : N ⊗[R] M →ₗc[R] P ⊗[R] M :=
+ Coalgebra.TensorProduct.map f (CoalgHom.id R M)
+
+end CoalgHom
diff --git a/Mathlib/RingTheory/Congruence/Basic.lean b/Mathlib/RingTheory/Congruence/Basic.lean
index 1a9c8ef824451..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,197 +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)
-
--- Porting note: upgrade to `FunLike`
-/-- A coercion from a congruence relation to its underlying binary relation. -/
-instance : FunLike (RingCon R) R (R → Prop) :=
- { coe := fun c => c.r,
- coe_injective' := fun 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
-
-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)
@@ -231,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 _ _ _
@@ -394,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
@@ -409,7 +86,6 @@ end Quotient
The API in this section is copied from `Mathlib/GroupTheory/Congruence.lean`
-/
-
section Lattice
variable [Add R] [Mul R]
@@ -437,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/Coprime/Ideal.lean b/Mathlib/RingTheory/Coprime/Ideal.lean
index 3a76aa94c02e4..3f7176c9ae4c7 100644
--- a/Mathlib/RingTheory/Coprime/Ideal.lean
+++ b/Mathlib/RingTheory/Coprime/Ideal.lean
@@ -32,10 +32,10 @@ theorem iSup_iInf_eq_top_iff_pairwise {t : Finset ι} (h : t.Nonempty) (I : ι
haveI : DecidableEq ι := Classical.decEq ι
rw [eq_top_iff_one, Submodule.mem_iSup_finset_iff_exists_sum]
refine h.cons_induction ?_ ?_ <;> clear t h
- · simp only [Finset.sum_singleton, Finset.coe_singleton, Set.pairwise_singleton, iff_true_iff]
+ · simp only [Finset.sum_singleton, Finset.coe_singleton, Set.pairwise_singleton, iff_true]
refine fun a => ⟨fun i => if h : i = a then ⟨1, ?_⟩ else 0, ?_⟩
· simp [h]
- · simp only [dif_pos, dif_ctx_congr, Submodule.coe_mk, eq_self_iff_true]
+ · simp only [dif_pos, Submodule.coe_mk, eq_self_iff_true]
intro a t hat h ih
rw [Finset.coe_cons,
Set.pairwise_insert_of_symmetric fun i j (h : I i ⊔ I j = ⊤) ↦ (sup_comm _ _).trans h]
diff --git a/Mathlib/RingTheory/DedekindDomain/AdicValuation.lean b/Mathlib/RingTheory/DedekindDomain/AdicValuation.lean
index a9006150a5a66..4163653269e60 100644
--- a/Mathlib/RingTheory/DedekindDomain/AdicValuation.lean
+++ b/Mathlib/RingTheory/DedekindDomain/AdicValuation.lean
@@ -58,7 +58,7 @@ dedekind domain, dedekind ring, adic valuation
noncomputable section
-open scoped Classical DiscreteValuation
+open scoped Classical Multiplicative
open Multiplicative IsDedekindDomain
diff --git a/Mathlib/RingTheory/DedekindDomain/Basic.lean b/Mathlib/RingTheory/DedekindDomain/Basic.lean
index 29a6df2a644da..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
@@ -122,7 +122,6 @@ use `isDedekindDomain_iff` to prove `IsDedekindDomain` for a given `fraction_map
This is the default implementation, but there are equivalent definitions,
`IsDedekindDomainDvr` and `IsDedekindDomainInv`.
-TODO: Prove that these are actually equivalent definitions.
-/
class IsDedekindDomain
extends IsDomain A, IsDedekindRing A : Prop
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 04b1f0a1bc959..c7086a988650b 100644
--- a/Mathlib/RingTheory/DedekindDomain/Dvr.lean
+++ b/Mathlib/RingTheory/DedekindDomain/Dvr.lean
@@ -1,18 +1,16 @@
/-
Copyright (c) 2020 Kenji Nakagawa. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kenji Nakagawa, Anne Baanen, Filippo A. E. Nuccio
+Authors: Kenji Nakagawa, Anne Baanen, Filippo A. E. Nuccio, Yongle Hu
-/
-import Mathlib.RingTheory.Localization.LocalizationLocalization
-import Mathlib.RingTheory.Localization.Submodule
import Mathlib.RingTheory.DiscreteValuationRing.TFAE
+import Mathlib.RingTheory.LocalProperties.IntegrallyClosed
/-!
# Dedekind domains
This file defines an equivalent notion of a Dedekind domain (or Dedekind ring),
-namely a Noetherian integral domain where the localization at all nonzero prime ideals is a DVR
-(TODO: and shows that implies the main definition).
+namely a Noetherian integral domain where the localization at all nonzero prime ideals is a DVR.
## Main definitions
@@ -45,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
@@ -53,10 +51,8 @@ open scoped nonZeroDivisors Polynomial
localization at every nonzero prime is a discrete valuation ring.
This is equivalent to `IsDedekindDomain`.
-TODO: prove the equivalence.
-/
-structure IsDedekindDomainDvr : Prop where
- isNoetherianRing : IsNoetherianRing A
+class IsDedekindDomainDvr extends IsNoetherian A A : Prop where
is_dvr_at_nonzero_prime : ∀ P ≠ (⊥ : Ideal A), ∀ _ : P.IsPrime,
DiscreteValuationRing (Localization.AtPrime P)
@@ -94,7 +90,7 @@ theorem IsLocalization.isDedekindDomain [IsDedekindDomain A] {M : Submonoid A} (
IsFractionRing.isFractionRing_of_isDomain_of_isLocalization M _ _
refine (isDedekindDomain_iff _ (FractionRing A)).mpr ⟨?_, ?_, ?_, ?_⟩
· infer_instance
- · exact IsLocalization.isNoetherianRing M _ (by infer_instance)
+ · exact IsLocalization.isNoetherianRing M _ inferInstance
· exact Ring.DimensionLEOne.localization Aₘ hM
· intro x hx
obtain ⟨⟨y, y_mem⟩, hy⟩ := hx.exists_multiple_integral_of_isLocalization M _
@@ -109,8 +105,12 @@ theorem IsLocalization.AtPrime.isDedekindDomain [IsDedekindDomain A] (P : Ideal
IsDedekindDomain Aₘ :=
IsLocalization.isDedekindDomain A P.primeCompl_le_nonZeroDivisors Aₘ
+instance Localization.AtPrime.isDedekindDomain [IsDedekindDomain A] (P : Ideal A) [P.IsPrime] :
+ IsDedekindDomain (Localization.AtPrime P) :=
+ IsLocalization.AtPrime.isDedekindDomain A P _
+
theorem IsLocalization.AtPrime.not_isField {P : Ideal A} (hP : P ≠ ⊥) [pP : P.IsPrime] (Aₘ : Type*)
- [CommRing Aₘ] [Algebra A Aₘ] [IsLocalization.AtPrime Aₘ P] : ¬IsField Aₘ := by
+ [CommRing Aₘ] [Algebra A Aₘ] [IsLocalization.AtPrime Aₘ P] : ¬ IsField Aₘ := by
intro h
letI := h.toField
obtain ⟨x, x_mem, x_ne⟩ := P.ne_bot_iff.mp hP
@@ -139,7 +139,36 @@ theorem IsLocalization.AtPrime.discreteValuationRing_of_dedekind_domain [IsDedek
/-- Dedekind domains, in the sense of Noetherian integrally closed domains of Krull dimension ≤ 1,
are also Dedekind domains in the sense of Noetherian domains where the localization at every
nonzero prime ideal is a DVR. -/
-theorem IsDedekindDomain.isDedekindDomainDvr [IsDedekindDomain A] : IsDedekindDomainDvr A :=
- { isNoetherianRing := IsDedekindRing.toIsNoetherian
- is_dvr_at_nonzero_prime := fun _ hP _ =>
- IsLocalization.AtPrime.discreteValuationRing_of_dedekind_domain A hP _ }
+instance IsDedekindDomain.isDedekindDomainDvr [IsDedekindDomain A] : IsDedekindDomainDvr A where
+ is_dvr_at_nonzero_prime := fun _ hP _ =>
+ IsLocalization.AtPrime.discreteValuationRing_of_dedekind_domain A hP _
+
+instance IsDedekindDomainDvr.ring_dimensionLEOne [h : IsDedekindDomainDvr A] :
+ Ring.DimensionLEOne A where
+ maximalOfPrime := by
+ intro p hp hpp
+ rcases p.exists_le_maximal (Ideal.IsPrime.ne_top hpp) with ⟨q, hq, hpq⟩
+ let f := (IsLocalization.orderIsoOfPrime q.primeCompl (Localization.AtPrime q)).symm
+ let P := f ⟨p, hpp, hpq.disjoint_compl_left⟩
+ let Q := f ⟨q, hq.isPrime, Set.disjoint_left.mpr fun _ a => a⟩
+ have hinj : Function.Injective (algebraMap A (Localization.AtPrime q)) :=
+ IsLocalization.injective (Localization.AtPrime q) q.primeCompl_le_nonZeroDivisors
+ have hp1 : P.1 ≠ ⊥ := fun x => hp ((p.map_eq_bot_iff_of_injective hinj).mp x)
+ have hq1 : Q.1 ≠ ⊥ :=
+ fun x => (ne_bot_of_le_ne_bot hp hpq) ((q.map_eq_bot_iff_of_injective hinj).mp x)
+ rcases (DiscreteValuationRing.iff_pid_with_one_nonzero_prime (Localization.AtPrime q)).mp
+ (h.is_dvr_at_nonzero_prime q (ne_bot_of_le_ne_bot hp hpq) hq.isPrime) with ⟨_, huq⟩
+ rw [show p = q from Subtype.val_inj.mpr <| f.injective <|
+ Subtype.val_inj.mp (huq.unique ⟨hp1, P.2⟩ ⟨hq1, Q.2⟩)]
+ exact hq
+
+instance IsDedekindDomainDvr.isIntegrallyClosed [h : IsDedekindDomainDvr A] :
+ IsIntegrallyClosed A :=
+ IsIntegrallyClosed.of_localization_maximal <| fun p hp0 hpm =>
+ let ⟨_, _⟩ := (DiscreteValuationRing.iff_pid_with_one_nonzero_prime (Localization.AtPrime p)).mp
+ (h.is_dvr_at_nonzero_prime p hp0 hpm.isPrime)
+ inferInstance
+
+/-- If an integral domain is Noetherian, and the localization at every nonzero prime is
+a discrete valuation ring, then it is a Dedekind domain. -/
+instance IsDedekindDomainDvr.isDedekindDomain [IsDedekindDomainDvr A] : IsDedekindDomain A where
diff --git a/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean b/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean
index 8591f904f4b2b..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
@@ -215,7 +215,7 @@ theorem zero : (0 : K_hat R K).IsFiniteAdele := by
rw [IsFiniteAdele, Filter.eventually_cofinite]
have h_empty :
{v : HeightOneSpectrum R | ¬(0 : v.adicCompletion K) ∈ v.adicCompletionIntegers K} = ∅ := by
- ext v; rw [mem_empty_iff_false, iff_false_iff]; intro hv
+ ext v; rw [mem_empty_iff_false, iff_false]; intro hv
rw [mem_setOf] at hv; apply hv; rw [mem_adicCompletionIntegers]
have h_zero : (Valued.v (0 : v.adicCompletion K) : WithZero (Multiplicative ℤ)) = 0 :=
Valued.v.map_zero'
@@ -259,13 +259,13 @@ theorem one : (1 : K_hat R K).IsFiniteAdele := by
rw [IsFiniteAdele, Filter.eventually_cofinite]
have h_empty :
{v : HeightOneSpectrum R | ¬(1 : v.adicCompletion K) ∈ v.adicCompletionIntegers K} = ∅ := by
- ext v; rw [mem_empty_iff_false, iff_false_iff]; intro hv
+ ext v; rw [mem_empty_iff_false, iff_false]; intro hv
rw [mem_setOf] at hv; apply hv; rw [mem_adicCompletionIntegers]
exact le_of_eq Valued.v.map_one'
-- Porting note: was `exact`, but `OfNat` got in the way.
convert finite_empty
-open scoped DiscreteValuation
+open scoped Multiplicative
theorem algebraMap' (k : K) : (_root_.algebraMap K (K_hat R K) k).IsFiniteAdele := by
rw [IsFiniteAdele, Filter.eventually_cofinite]
@@ -337,7 +337,7 @@ instance : IsScalarTower R K (FiniteAdeleRing R K) :=
IsScalarTower.of_algebraMap_eq' rfl
instance : Coe (FiniteAdeleRing R K) (K_hat R K) where
- coe := fun x ↦ x.1
+ coe x := x.1
@[ext]
lemma ext {a₁ a₂ : FiniteAdeleRing R K} (h : (a₁ : K_hat R K) = a₂) : a₁ = a₂ :=
@@ -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
@@ -371,7 +371,7 @@ lemma exists_finiteIntegralAdele_iff (a : FiniteAdeleRing R K) : (∃ c : R_hat
section Topology
open nonZeroDivisors
-open scoped DiscreteValuation
+open scoped Multiplicative
variable {R K} in
lemma mul_nonZeroDivisor_mem_finiteIntegralAdeles (a : FiniteAdeleRing R K) :
@@ -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 67e3680bfcb02..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.
@@ -630,7 +630,7 @@ instance Ideal.uniqueFactorizationMonoid : UniqueFactorizationMonoid (Ideal A) :
rintro ⟨⟨x, x_mem, x_not_mem⟩, ⟨y, y_mem, y_not_mem⟩⟩
exact
⟨x * y, Ideal.mul_mem_mul x_mem y_mem,
- mt this.isPrime.mem_or_mem (not_or_of_not x_not_mem y_not_mem)⟩⟩, Prime.irreducible⟩ }
+ mt this.isPrime.mem_or_mem (not_or_intro x_not_mem y_not_mem)⟩⟩, Prime.irreducible⟩ }
instance Ideal.normalizationMonoid : NormalizationMonoid (Ideal A) :=
normalizationMonoidOfUniqueUnits
@@ -720,7 +720,7 @@ theorem Ideal.eq_prime_pow_of_succ_lt_of_le {P I : Ideal A} [P_prime : P.IsPrime
theorem Ideal.pow_succ_lt_pow {P : Ideal A} [P_prime : P.IsPrime] (hP : P ≠ ⊥) (i : ℕ) :
P ^ (i + 1) < P ^ i :=
lt_of_le_of_ne (Ideal.pow_le_pow_right (Nat.le_succ _))
- (mt (pow_eq_pow_iff hP (mt Ideal.isUnit_iff.mp P_prime.ne_top)).mp i.succ_ne_self)
+ (mt (pow_inj_of_not_isUnit (mt Ideal.isUnit_iff.mp P_prime.ne_top) hP).mp i.succ_ne_self)
theorem Associates.le_singleton_iff (x : A) (n : ℕ) (I : Ideal A) :
Associates.mk I ^ n ≤ Associates.mk (Ideal.span {x}) ↔ x ∈ I ^ n := by
@@ -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
@@ -892,29 +892,43 @@ theorem sup_eq_prod_inf_factors [DecidableEq (Ideal T)] (hI : I ≠ ⊥) (hJ : J
· exact ne_bot_of_le_ne_bot hI le_sup_left
· exact this
-theorem irreducible_pow_sup [DecidableEq (Ideal T)](hI : I ≠ ⊥) (hJ : Irreducible J) (n : ℕ) :
+theorem irreducible_pow_sup [DecidableEq (Ideal T)] (hI : I ≠ ⊥) (hJ : Irreducible J) (n : ℕ) :
J ^ n ⊔ I = J ^ min ((normalizedFactors I).count J) n := by
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] :
+ ∃ Q : Ideal T, P ⊔ Q = ⊤ ∧ I = P ^ (Multiset.count P (normalizedFactors I)) * Q := by
+ use (filter (¬ P = ·) (normalizedFactors I)).prod
+ constructor
+ · refine P.sup_multiset_prod_eq_top (fun p hpi ↦ ?_)
+ have hp : Prime p := prime_of_normalized_factor p (filter_subset _ (normalizedFactors I) hpi)
+ exact hpm.coprime_of_ne ((isPrime_of_prime hp).isMaximal hp.ne_zero) (of_mem_filter hpi)
+ · nth_rw 1 [← prod_normalizedFactors_eq_self hI, ← filter_add_not (P = ·) (normalizedFactors I)]
+ rw [prod_add, pow_count]
end IsDedekindDomain
@@ -1108,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'
@@ -1180,26 +1191,6 @@ theorem Ideal.le_mul_of_no_prime_factors {I J K : Ideal R}
(UniqueFactorizationMonoid.dvd_of_dvd_mul_right_of_no_prime_factors (b := K) hJ0 ?_ hJ)
exact fun hPJ hPK => mt Ideal.isPrime_of_prime (coprime _ hPJ hPK)
-theorem Ideal.le_of_pow_le_prime {I P : Ideal R} [hP : P.IsPrime] {n : ℕ} (h : I ^ n ≤ P) :
- I ≤ P := by
- by_cases hP0 : P = ⊥
- · simp only [hP0, le_bot_iff] at h ⊢
- exact pow_eq_zero h
- rw [← Ideal.dvd_iff_le] at h ⊢
- exact ((Ideal.prime_iff_isPrime hP0).mpr hP).dvd_of_dvd_pow h
-
-theorem Ideal.pow_le_prime_iff {I P : Ideal R} [_hP : P.IsPrime] {n : ℕ} (hn : n ≠ 0) :
- I ^ n ≤ P ↔ I ≤ P :=
- ⟨Ideal.le_of_pow_le_prime, fun h => _root_.trans (Ideal.pow_le_self hn) h⟩
-
-theorem Ideal.prod_le_prime {ι : Type*} {s : Finset ι} {f : ι → Ideal R} {P : Ideal R}
- [hP : P.IsPrime] : ∏ i ∈ s, f i ≤ P ↔ ∃ i ∈ s, f i ≤ P := by
- by_cases hP0 : P = ⊥
- · simp only [hP0, le_bot_iff]
- rw [← Ideal.zero_eq_bot, Finset.prod_eq_zero_iff]
- simp only [← Ideal.dvd_iff_le]
- exact ((Ideal.prime_iff_isPrime hP0).mpr hP).dvd_finset_prod_iff _
-
/-- The intersection of distinct prime powers in a Dedekind domain is the product of these
prime powers. -/
theorem IsDedekindDomain.inf_prime_pow_eq_prod {ι : Type*} (s : Finset ι) (f : ι → Ideal R)
@@ -1217,15 +1208,13 @@ theorem IsDedekindDomain.inf_prime_pow_eq_prod {ι : Type*} (s : Finset ι) (f :
rw [Finset.inf_insert, Finset.prod_insert ha, ih]
refine le_antisymm (Ideal.le_mul_of_no_prime_factors ?_ inf_le_left inf_le_right) Ideal.mul_le_inf
intro P hPa hPs hPp
- obtain ⟨b, hb, hPb⟩ := Ideal.prod_le_prime.mp hPs
+ obtain ⟨b, hb, hPb⟩ := hPp.prod_le.mp hPs
haveI := Ideal.isPrime_of_prime (prime a (Finset.mem_insert_self a s))
haveI := Ideal.isPrime_of_prime (prime b (Finset.mem_insert_of_mem hb))
refine coprime a (Finset.mem_insert_self a s) b (Finset.mem_insert_of_mem hb) ?_ ?_
· exact (ne_of_mem_of_not_mem hb ha).symm
- · refine ((Ring.DimensionLeOne.prime_le_prime_iff_eq ?_).mp
- (Ideal.le_of_pow_le_prime hPa)).trans
- ((Ring.DimensionLeOne.prime_le_prime_iff_eq ?_).mp
- (Ideal.le_of_pow_le_prime hPb)).symm
+ · refine ((Ring.DimensionLeOne.prime_le_prime_iff_eq ?_).mp (hPp.le_of_pow_le hPa)).trans
+ ((Ring.DimensionLeOne.prime_le_prime_iff_eq ?_).mp (hPp.le_of_pow_le hPb)).symm
· exact (prime a (Finset.mem_insert_self a s)).ne_zero
· exact (prime b (Finset.mem_insert_of_mem hb)).ne_zero
@@ -1240,17 +1229,13 @@ noncomputable def IsDedekindDomain.quotientEquivPiOfProdEq {ι : Type*} [Fintype
simp only [← prod_eq, Finset.inf_eq_iInf, Finset.mem_univ, ciInf_pos,
← IsDedekindDomain.inf_prime_pow_eq_prod _ _ _ (fun i _ => prime i)
(coprime.set_pairwise _)])).trans <|
- Ideal.quotientInfRingEquivPiQuotient _ fun i j hij => Ideal.coprime_of_no_prime_ge (by
+ Ideal.quotientInfRingEquivPiQuotient _ fun i j hij => Ideal.coprime_of_no_prime_ge <| by
intro P hPi hPj hPp
haveI := Ideal.isPrime_of_prime (prime i)
haveI := Ideal.isPrime_of_prime (prime j)
- refine coprime hij ?_
- refine ((Ring.DimensionLeOne.prime_le_prime_iff_eq ?_).mp
- (Ideal.le_of_pow_le_prime hPi)).trans
- ((Ring.DimensionLeOne.prime_le_prime_iff_eq ?_).mp
- (Ideal.le_of_pow_le_prime hPj)).symm
- · exact (prime i).ne_zero
- · exact (prime j).ne_zero)
+ exact coprime hij <| ((Ring.DimensionLeOne.prime_le_prime_iff_eq (prime i).ne_zero).mp
+ (hPp.le_of_pow_le hPi)).trans <| Eq.symm <|
+ (Ring.DimensionLeOne.prime_le_prime_iff_eq (prime j).ne_zero).mp (hPp.le_of_pow_le hPj)
open scoped Classical
@@ -1260,14 +1245,14 @@ 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 :=
(factors I).toFinset.prod_coe_sort fun P => P ^ (factors I).count P
_ = ((factors I).map fun P => P).prod := (Finset.prod_multiset_map_count (factors I) id).symm
_ = (factors I).prod := by rw [Multiset.map_id']
- _ = I := (@associated_iff_eq (Ideal R) _ Ideal.uniqueUnits _ _).mp (factors_prod hI)
+ _ = I := associated_iff_eq.mp (factors_prod hI)
)
@[simp]
@@ -1356,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]
@@ -1404,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)]
@@ -1437,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]
@@ -1449,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 8f37a34bfe33b..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 ι]
@@ -156,7 +156,7 @@ theorem FiniteDimensional.exists_is_basis_integral :
· intro x; simp only [mul_inv_cancel_left₀ hy']
· rintro ⟨x', hx'⟩
simp only [Algebra.smul_def, Finset.mem_image, exists_prop, Finset.mem_univ,
- true_and_iff] at his'
+ true_and] at his'
simp only [Basis.map_apply, LinearEquiv.coe_mk]
exact his' _ ⟨_, rfl⟩
@@ -198,13 +198,13 @@ theorem IsIntegralClosure.module_free [NoZeroSMulDivisors A L] [IsPrincipalIdeal
and `L` has no zero smul divisors by `A`, the `A`-rank of the integral closure `C` of `A` in `L`
is equal to the `K`-rank of `L`. -/
theorem IsIntegralClosure.rank [IsPrincipalIdealRing A] [NoZeroSMulDivisors A L] :
- FiniteDimensional.finrank A C = FiniteDimensional.finrank K L := by
+ Module.finrank A C = Module.finrank K L := by
haveI : Module.Free A C := IsIntegralClosure.module_free A K L C
haveI : IsNoetherian A C := IsIntegralClosure.isNoetherian A K L C
haveI : IsLocalization (Algebra.algebraMapSubmonoid C A⁰) L :=
IsIntegralClosure.isLocalization A K L C
let b := Basis.localizationLocalization K A⁰ L (Module.Free.chooseBasis A C)
- rw [FiniteDimensional.finrank_eq_card_chooseBasisIndex, FiniteDimensional.finrank_eq_card_basis b]
+ rw [Module.finrank_eq_card_chooseBasisIndex, Module.finrank_eq_card_basis b]
variable {A K}
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 43994f9070494..964dfa3fb3639 100644
--- a/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean
+++ b/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean
@@ -67,7 +67,7 @@ namespace IsDedekindDomain
noncomputable section
-open scoped DiscreteValuation nonZeroDivisors
+open scoped Multiplicative nonZeroDivisors
universe u v
@@ -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
new file mode 100644
index 0000000000000..ec1b10e49cb27
--- /dev/null
+++ b/Mathlib/RingTheory/Derivation/MapCoeffs.lean
@@ -0,0 +1,101 @@
+/-
+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.RingTheory.Derivation.Basic
+import Mathlib.Algebra.Polynomial.Module.Basic
+
+/-!
+# Coefficient-wise derivation on polynomials
+
+In this file we define applying a derivation on the coefficients of a polynomial,
+show this forms a derivation, and prove `apply_eval_eq`, which shows that for a derivation `D`,
+`D(p(x)) = (D.mapCoeffs p)(x) + D(x) * p'(x)`. `apply_aeval_eq` and `apply_aeval_eq'`
+are generalizations of that for algebras.
+-/
+
+noncomputable section
+
+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)
+
+/--
+The `R`-derivation from `A[X]` to `M[X]` which applies the derivative to each
+of the coefficients.
+-/
+def mapCoeffs : Derivation R A[X] (PolynomialModule A M) where
+ __ := (PolynomialModule.map A d.toLinearMap).comp
+ PolynomialModule.equivPolynomial.symm.toLinearMap
+ map_one_eq_zero' := show (Finsupp.single 0 1).mapRange (d : A → M) d.map_zero = 0 by simp
+ leibniz' p q := by
+ dsimp
+ induction p using Polynomial.induction_on' with
+ | h_add => simp only [add_mul, map_add, add_smul, smul_add, add_add_add_comm, *]
+ | h_monomial n a =>
+ induction q using Polynomial.induction_on' with
+ | h_add => simp only [mul_add, map_add, add_smul, smul_add, add_add_add_comm, *]
+ | h_monomial m b =>
+ refine Finsupp.ext fun i ↦ ?_
+ dsimp [PolynomialModule.equivPolynomial, PolynomialModule.map]
+ simp only [toFinsupp_mul, toFinsupp_monomial, AddMonoidAlgebra.single_mul_single]
+ show d _ = _ + _
+ erw [Finsupp.mapRange.linearMap_apply, Finsupp.mapRange.linearMap_apply]
+ rw [Finsupp.mapRange_single, Finsupp.mapRange_single]
+ erw [PolynomialModule.monomial_smul_single, PolynomialModule.monomial_smul_single]
+ simp only [AddMonoidAlgebra.single_apply, apply_ite d, leibniz, map_zero, coeFn_coe,
+ PolynomialModule.single_apply, ite_add_zero, add_comm m n]
+
+@[simp]
+lemma mapCoeffs_apply (p : A[X]) (i) :
+ d.mapCoeffs p i = d (coeff p i) := rfl
+
+@[simp]
+lemma mapCoeffs_monomial (n : ℕ) (x : A) :
+ d.mapCoeffs (monomial n x) = .single A n (d x) := Finsupp.ext fun _ ↦ by
+ simp [coeff_monomial, apply_ite d, PolynomialModule.single_apply]
+
+@[simp]
+lemma mapCoeffs_X :
+ d.mapCoeffs (X : A[X]) = 0 := by simp [← monomial_one_one_eq_X]
+
+@[simp]
+lemma mapCoeffs_C (x : A) :
+ d.mapCoeffs (C x) = .single A 0 (d x) := by simp [← monomial_zero_left]
+
+variable {B M' : Type*} [CommRing B] [Algebra R B] [Algebra A B]
+ [AddCommGroup M'] [Module B M'] [Module R M'] [Module A M']
+
+theorem apply_aeval_eq' (d' : Derivation R B M') (f : M →ₗ[A] M')
+ (h : ∀ a, f (d a) = d' (algebraMap A B a)) (x : B) (p : A[X]) :
+ d' (aeval x p) = PolynomialModule.eval x (PolynomialModule.map B f (d.mapCoeffs p)) +
+ aeval x (derivative p) • d' x := by
+ induction p using Polynomial.induction_on' with
+ | h_add => simp_all only [eval_add, map_add, add_smul]; abel
+ | h_monomial =>
+ simp only [aeval_monomial, leibniz, leibniz_pow, mapCoeffs_monomial,
+ PolynomialModule.map_single, PolynomialModule.eval_single, derivative_monomial, map_mul,
+ _root_.map_natCast, h]
+ rw [add_comm, ← smul_smul, ← smul_smul, Nat.cast_smul_eq_nsmul]
+
+
+theorem apply_aeval_eq [IsScalarTower R A B] [IsScalarTower A B M'] (d : Derivation R B M')
+ (x : B) (p : A[X]) :
+ d (aeval x p) = PolynomialModule.eval x ((d.compAlgebraMap A).mapCoeffs p) +
+ aeval x (derivative p) • d x := by
+ convert apply_aeval_eq' (d.compAlgebraMap A) d LinearMap.id _ x p
+ · apply Finsupp.ext
+ intro x
+ rfl
+ · intro a
+ rfl
+
+theorem apply_eval_eq (x : A) (p : A[X]) :
+ d (eval x p) = PolynomialModule.eval x (d.mapCoeffs p) + eval x (derivative p) • d x :=
+ apply_aeval_eq d x p
+
+end Derivation
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 d461a65055d40..8257492736d5b 100644
--- a/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean
+++ b/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean
@@ -193,7 +193,7 @@ theorem toUniqueFactorizationMonoid (hR : HasUnitMulPowIrreducibleFactorization
intro a b h
by_cases ha : a = 0
· rw [ha]
- simp only [true_or_iff, dvd_zero]
+ simp only [true_or, dvd_zero]
obtain ⟨m, u, rfl⟩ := spec.2 ha
rw [mul_assoc, mul_left_comm, Units.dvd_mul_left] at h
rw [Units.dvd_mul_right]
@@ -222,8 +222,7 @@ theorem of_ufd_of_unique_irreducible [UniqueFactorizationMonoid R] (h₁ : ∃ p
congr 1
symm
rw [Multiset.eq_replicate]
- simp only [true_and_iff, and_imp, Multiset.card_map, eq_self_iff_true, Multiset.mem_map,
- exists_imp]
+ simp only [true_and, and_imp, Multiset.card_map, eq_self_iff_true, Multiset.mem_map, exists_imp]
rintro _ q hq rfl
rw [Associates.mk_eq_mk_iff_associated]
apply h₂ (hfx.1 _ hq) hp
@@ -311,8 +310,7 @@ theorem associated_pow_irreducible {x : R} (hx : x ≠ 0) {ϖ : R} (hirr : Irred
rw [← H, ← Associates.prod_mk, Associates.mk_pow, ← Multiset.prod_replicate]
congr 1
rw [Multiset.eq_replicate]
- simp only [true_and_iff, and_imp, Multiset.card_map, eq_self_iff_true, Multiset.mem_map,
- exists_imp]
+ simp only [true_and, and_imp, Multiset.card_map, eq_self_iff_true, Multiset.mem_map, exists_imp]
rintro _ _ _ rfl
rw [Associates.mk_eq_mk_iff_associated]
refine associated_of_irreducible _ ?_ hirr
@@ -367,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
@@ -400,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 _ _
@@ -420,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
@@ -433,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 _ _
@@ -449,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 fcd304e64d732..763ee85bc69d5 100644
--- a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean
+++ b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean
@@ -25,11 +25,11 @@ 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 DiscreteValuation
+open scoped Multiplicative
-open LocalRing FiniteDimensional
+open LocalRing Module
theorem exists_maximalIdeal_pow_eq_of_principal [IsNoetherianRing R] [LocalRing R] [IsDomain R]
(h' : (maximalIdeal R).IsPrincipal) (I : Ideal R) (hI : I ≠ ⊥) :
@@ -166,23 +166,17 @@ theorem tfae_of_isNoetherianRing_of_localRing_of_isDomain
(maximalIdeal R).IsPrincipal,
finrank (ResidueField R) (CotangentSpace R) ≤ 1,
∀ (I) (_ : I ≠ ⊥), ∃ n : ℕ, I = maximalIdeal R ^ n] := by
- tfae_have 1 → 2
- · exact fun _ ↦ inferInstance
- tfae_have 2 → 1
- · exact fun _ ↦ ((IsBezout.TFAE (R := R)).out 0 1).mp ‹_›
+ tfae_have 1 → 2 := fun _ ↦ inferInstance
+ tfae_have 2 → 1 := fun _ ↦ ((IsBezout.TFAE (R := R)).out 0 1).mp ‹_›
tfae_have 1 → 4
- · intro H
- exact ⟨inferInstance, fun P hP hP' ↦ eq_maximalIdeal (hP'.isMaximal hP)⟩
- tfae_have 4 → 3
- · exact fun ⟨h₁, h₂⟩ ↦ { h₁ with maximalOfPrime := (h₂ _ · · ▸ maximalIdeal.isMaximal R) }
- tfae_have 3 → 5
- · exact fun h ↦ maximalIdeal_isPrincipal_of_isDedekindDomain R
- tfae_have 6 ↔ 5
- · exact finrank_cotangentSpace_le_one_iff
- tfae_have 5 → 7
- · exact exists_maximalIdeal_pow_eq_of_principal R
- tfae_have 7 → 2
- · rw [ValuationRing.iff_ideal_total]
+ | H => ⟨inferInstance, fun P hP hP' ↦ eq_maximalIdeal (hP'.isMaximal hP)⟩
+ tfae_have 4 → 3 :=
+ fun ⟨h₁, h₂⟩ ↦ { h₁ with maximalOfPrime := (h₂ _ · · ▸ maximalIdeal.isMaximal R) }
+ tfae_have 3 → 5 := fun h ↦ maximalIdeal_isPrincipal_of_isDedekindDomain R
+ tfae_have 6 ↔ 5 := finrank_cotangentSpace_le_one_iff
+ tfae_have 5 → 7 := exists_maximalIdeal_pow_eq_of_principal R
+ tfae_have 7 → 2 := by
+ rw [ValuationRing.iff_ideal_total]
intro H
constructor
intro I J
diff --git a/Mathlib/RingTheory/Discriminant.lean b/Mathlib/RingTheory/Discriminant.lean
index f6285f4b7aa27..f3faffa03b668 100644
--- a/Mathlib/RingTheory/Discriminant.lean
+++ b/Mathlib/RingTheory/Discriminant.lean
@@ -50,7 +50,7 @@ universe u v w z
open scoped Matrix
-open Matrix FiniteDimensional Fintype Polynomial Finset IntermediateField
+open Matrix Module Fintype Polynomial Finset IntermediateField
namespace Algebra
@@ -190,7 +190,7 @@ theorem discr_powerBasis_eq_prod'' [Algebra.IsSeparable K L] (e : Fin pb.dim ≃
have h₂ : 2 ∣ pb.dim * (pb.dim - 1) := pb.dim.even_mul_pred_self.two_dvd
have hne : ((2 : ℕ) : ℚ) ≠ 0 := by simp
have hle : 1 ≤ pb.dim := by
- rw [← hn, Nat.one_le_iff_ne_zero, ← zero_lt_iff, FiniteDimensional.finrank_pos_iff]
+ rw [← hn, Nat.one_le_iff_ne_zero, ← zero_lt_iff, Module.finrank_pos_iff]
infer_instance
rw [hn, Nat.cast_div h₂ hne, Nat.cast_mul, Nat.cast_sub hle]
field_simp
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 0a5d43bc3a05a..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
@@ -11,7 +11,7 @@ import Mathlib.RingTheory.Unramified.Basic
# Etale morphisms
-An `R`-algebra `A` is formally étale if for every `R`-algebra,
+An `R`-algebra `A` is formally étale if for every `R`-algebra `B`,
every square-zero ideal `I : Ideal B` and `f : A →ₐ[R] B ⧸ I`, there exists
exactly one lift `A →ₐ[R] B`.
It is étale if it is formally étale and of finite presentation.
@@ -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 a2955e2776f05..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
@@ -69,8 +69,7 @@ theorem of_finiteType [IsNoetherianRing R] : FiniteType R A ↔ FinitePresentati
-- Porting note: rewrote code to help typeclass inference
rw [isNoetherianRing_iff] at hnoet
letI : Module (MvPolynomial (Fin n) R) (MvPolynomial (Fin n) R) := Semiring.toModule
- have := hnoet.noetherian (RingHom.ker f.toRingHom)
- convert this
+ convert hnoet.noetherian (RingHom.ker f.toRingHom)
/-- If `e : A ≃ₐ[R] B` and `A` is finitely presented, then so is `B`. -/
theorem equiv [FinitePresentation R A] (e : A ≃ₐ[R] B) : FinitePresentation R B := by
@@ -262,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]
@@ -276,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]
@@ -341,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
@@ -352,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]
@@ -395,6 +394,7 @@ variable {A B C : Type*} [CommRing A] [CommRing B] [CommRing C]
/-- A ring morphism `A →+* B` is of `RingHom.FinitePresentation` if `B` is finitely presented as
`A`-algebra. -/
+@[algebraize]
def FinitePresentation (f : A →+* B) : Prop :=
@Algebra.FinitePresentation A B _ _ f.toAlgebra
@@ -415,11 +415,9 @@ theorem id : FinitePresentation (RingHom.id A) :=
variable {A}
theorem comp_surjective {f : A →+* B} {g : B →+* C} (hf : f.FinitePresentation) (hg : Surjective g)
- (hker : g.ker.FG) : (g.comp f).FinitePresentation :=
- letI := f.toAlgebra
- letI := (g.comp f).toAlgebra
- letI : Algebra.FinitePresentation A B := hf
- Algebra.FinitePresentation.of_surjective
+ (hker : g.ker.FG) : (g.comp f).FinitePresentation := by
+ algebraize [f, g.comp f]
+ exact Algebra.FinitePresentation.of_surjective
(f :=
{ g with
toFun := g
@@ -435,28 +433,16 @@ theorem of_finiteType [IsNoetherianRing A] {f : A →+* B} : f.FiniteType ↔ f.
@Algebra.FinitePresentation.of_finiteType A B _ _ f.toAlgebra _
theorem comp {g : B →+* C} {f : A →+* B} (hg : g.FinitePresentation) (hf : f.FinitePresentation) :
- (g.comp f).FinitePresentation :=
+ (g.comp f).FinitePresentation := by
-- Porting note: specify `Algebra` instances to get `SMul`
- letI ins1 := RingHom.toAlgebra f
- letI ins2 := RingHom.toAlgebra g
- letI ins3 := RingHom.toAlgebra (g.comp f)
- letI ins4 : IsScalarTower A B C :=
- { smul_assoc := fun a b c => by simp [Algebra.smul_def, mul_assoc]; rfl }
- letI : Algebra.FinitePresentation A B := hf
- letI : Algebra.FinitePresentation B C := hg
- Algebra.FinitePresentation.trans A B C
+ algebraize [f, g, g.comp f]
+ exact Algebra.FinitePresentation.trans A B C
theorem of_comp_finiteType (f : A →+* B) {g : B →+* C} (hg : (g.comp f).FinitePresentation)
- (hf : f.FiniteType) : g.FinitePresentation :=
+ (hf : f.FiniteType) : g.FinitePresentation := by
-- Porting note: need to specify some instances
- letI ins1 := RingHom.toAlgebra f
- letI ins2 := RingHom.toAlgebra g
- letI ins3 := RingHom.toAlgebra (g.comp f)
- letI ins4 : IsScalarTower A B C :=
- { smul_assoc := fun a b c => by simp [Algebra.smul_def, mul_assoc]; rfl }
- letI : Algebra.FinitePresentation A C := hg
- letI : Algebra.FiniteType A B := hf
- Algebra.FinitePresentation.of_restrict_scalars_finitePresentation A B C
+ algebraize [f, g, g.comp f]
+ exact Algebra.FinitePresentation.of_restrict_scalars_finitePresentation A B C
end FinitePresentation
diff --git a/Mathlib/RingTheory/FiniteType.lean b/Mathlib/RingTheory/FiniteType.lean
index b0366a10493a5..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
@@ -45,7 +47,7 @@ section Algebra
-- see Note [lower instance priority]
instance (priority := 100) finiteType {R : Type*} (A : Type*) [CommSemiring R] [Semiring A]
- [Algebra R A] [hRA : Finite R A] : Algebra.FiniteType R A :=
+ [Algebra R A] [hRA : Module.Finite R A] : Algebra.FiniteType R A :=
⟨Subalgebra.fg_of_submodule_fg hRA.1⟩
end 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 :
@@ -207,6 +213,7 @@ namespace RingHom
variable {A B C : Type*} [CommRing A] [CommRing B] [CommRing C]
/-- A ring morphism `A →+* B` is of `FiniteType` if `B` is finitely generated as `A`-algebra. -/
+@[algebraize]
def FiniteType (f : A →+* B) : Prop :=
@Algebra.FiniteType A B _ _ f.toAlgebra
@@ -228,8 +235,7 @@ variable {A}
theorem comp_surjective {f : A →+* B} {g : B →+* C} (hf : f.FiniteType) (hg : Surjective g) :
(g.comp f).FiniteType := by
- let _ : Algebra A B := f.toAlgebra
- let _ : Algebra A C := (g.comp f).toAlgebra
+ algebraize_only [f, g.comp f]
exact Algebra.FiniteType.of_surjective hf
{ g with
toFun := g
@@ -242,15 +248,8 @@ theorem of_surjective (f : A →+* B) (hf : Surjective f) : f.FiniteType := by
theorem comp {g : B →+* C} {f : A →+* B} (hg : g.FiniteType) (hf : f.FiniteType) :
(g.comp f).FiniteType := by
- let _ : Algebra A B := f.toAlgebra
- let _ : Algebra A C := (g.comp f).toAlgebra
- let _ : Algebra B C := g.toAlgebra
- exact @Algebra.FiniteType.trans A B C _ _ _ f.toAlgebra (g.comp f).toAlgebra g.toAlgebra
- ⟨by
- intro a b c
- simp [Algebra.smul_def, RingHom.map_mul, mul_assoc]
- rfl⟩
- hf hg
+ algebraize_only [f, g, g.comp f]
+ exact Algebra.FiniteType.trans hf hg
theorem of_finite {f : A →+* B} (hf : f.Finite) : f.FiniteType :=
@Module.Finite.finiteType _ _ _ _ f.toAlgebra hf
@@ -259,11 +258,7 @@ alias _root_.RingHom.Finite.to_finiteType := of_finite
theorem of_comp_finiteType {f : A →+* B} {g : B →+* C} (h : (g.comp f).FiniteType) :
g.FiniteType := by
- let _ := f.toAlgebra
- let _ := g.toAlgebra
- let _ := (g.comp f).toAlgebra
- let _ : IsScalarTower A B C := RestrictScalars.isScalarTower A B C
- let _ : Algebra.FiniteType A C := h
+ algebraize [f, g, g.comp f]
exact Algebra.FiniteType.of_restrictScalars_finiteType A B C
end FiniteType
@@ -414,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,
@@ -439,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,
@@ -582,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]⟩
@@ -606,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]⟩
@@ -693,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
@@ -712,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
@@ -725,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
@@ -746,7 +741,7 @@ This is similar to `IsNoetherian.injective_of_surjective_endomorphism` but only
commutative case, but does not use a Noetherian hypothesis. -/
@[deprecated OrzechProperty.injective_of_surjective_endomorphism (since := "2024-05-30")]
theorem Module.Finite.injective_of_surjective_endomorphism {R : Type*} [CommRing R] {M : Type*}
- [AddCommGroup M] [Module R M] [Finite R M] (f : M →ₗ[R] M)
+ [AddCommGroup M] [Module R M] [Module.Finite R M] (f : M →ₗ[R] M)
(f_surj : Function.Surjective f) : Function.Injective f :=
OrzechProperty.injective_of_surjective_endomorphism f f_surj
diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean
index 42e2948fd00cc..74a7408d863d7 100644
--- a/Mathlib/RingTheory/Finiteness.lean
+++ b/Mathlib/RingTheory/Finiteness.lean
@@ -5,12 +5,13 @@ 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
/-!
# Finiteness conditions in commutative algebra
@@ -193,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]
@@ -312,11 +313,13 @@ theorem fg_induction (R M : Type*) [Semiring R] [AddCommMonoid M] [Module R M]
(h₂ : ∀ M₁ M₂, P M₁ → P M₂ → P (M₁ ⊔ M₂)) (N : Submodule R M) (hN : N.FG) : P N := by
classical
obtain ⟨s, rfl⟩ := hN
- induction s using Finset.induction
- · rw [Finset.coe_empty, Submodule.span_empty, ← Submodule.span_zero_singleton]
- apply h₁
- · rw [Finset.coe_insert, Submodule.span_insert]
- apply h₂ <;> apply_assumption
+ induction s using Finset.induction with
+ | empty =>
+ rw [Finset.coe_empty, Submodule.span_empty, ← Submodule.span_zero_singleton]
+ exact h₁ _
+ | insert _ ih =>
+ rw [Finset.coe_insert, Submodule.span_insert]
+ exact h₂ _ _ (h₁ _) ih
/-- The kernel of the composition of two linear maps is finitely generated if both kernels are and
the first morphism is surjective. -/
@@ -378,9 +381,7 @@ theorem fg_iff_compact (s : Submodule R M) : s.FG ↔ CompleteLattice.IsCompactE
suffices u.sup id ≤ s from le_antisymm husup this
rw [sSup', Finset.sup_id_eq_sSup]
exact sSup_le_sSup huspan
- -- Porting note: had to split this out of the `obtain`
- have := Finset.subset_image_iff.mp huspan
- obtain ⟨t, ⟨-, rfl⟩⟩ := this
+ obtain ⟨t, -, rfl⟩ := Finset.subset_set_image_iff.mp huspan
rw [Finset.sup_image, Function.id_comp, Finset.sup_eq_iSup, supr_rw, ←
span_eq_iSup_of_singleton_spans, eq_comm] at ssup
exact ⟨t, ssup⟩
@@ -492,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
@@ -499,7 +528,7 @@ section ModuleAndAlgebra
variable (R A B M N : Type*)
/-- A module over a semiring is `Finite` if it is finitely generated as a module. -/
-class Module.Finite [Semiring R] [AddCommMonoid M] [Module R M] : Prop where
+protected class Module.Finite [Semiring R] [AddCommMonoid M] [Module R M] : Prop where
out : (⊤ : Submodule R M).FG
attribute [inherit_doc Module.Finite] Module.Finite.out
@@ -509,7 +538,7 @@ namespace Module
variable [Semiring R] [AddCommMonoid M] [Module R M] [AddCommMonoid N] [Module R N]
theorem finite_def {R M} [Semiring R] [AddCommMonoid M] [Module R M] :
- Finite R M ↔ (⊤ : Submodule R M).FG :=
+ Module.Finite R M ↔ (⊤ : Submodule R M).FG :=
⟨fun h => h.1, fun h => ⟨h⟩⟩
namespace Finite
@@ -527,46 +556,63 @@ theorem iff_addGroup_fg {G : Type*} [AddCommGroup G] : Module.Finite ℤ G ↔ A
variable {R M N}
/-- See also `Module.Finite.exists_fin'`. -/
-theorem exists_fin [Finite R M] : ∃ (n : ℕ) (s : Fin n → M), Submodule.span R (range s) = ⊤ :=
+lemma exists_fin [Module.Finite R M] : ∃ (n : ℕ) (s : Fin n → M), Submodule.span R (range s) = ⊤ :=
Submodule.fg_iff_exists_fin_generating_family.mp out
variable (R M) in
-lemma exists_fin' [Finite R M] : ∃ (n : ℕ) (f : (Fin n → R) →ₗ[R] M), Surjective f := by
+lemma exists_fin' [Module.Finite R M] : ∃ (n : ℕ) (f : (Fin n → R) →ₗ[R] M), Surjective f := by
have ⟨n, s, hs⟩ := exists_fin (R := R) (M := M)
refine ⟨n, Basis.constr (Pi.basisFun R _) ℕ s, ?_⟩
rw [← LinearMap.range_eq_top, Basis.constr_range, hs]
-theorem of_surjective [hM : Finite R M] (f : M →ₗ[R] N) (hf : Surjective f) : Finite R N :=
+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
rw [← LinearMap.range_eq_top.2 hf, ← Submodule.map_top]
exact hM.1.map f⟩
instance quotient (R) {A M} [Semiring R] [AddCommGroup M] [Ring A] [Module A M] [Module R M]
- [SMul R A] [IsScalarTower R A M] [Finite R M]
- (N : Submodule A M) : Finite R (M ⧸ N) :=
+ [SMul R A] [IsScalarTower R A M] [Module.Finite R M]
+ (N : Submodule A M) : Module.Finite R (M ⧸ N) :=
Module.Finite.of_surjective (N.mkQ.restrictScalars R) N.mkQ_surjective
/-- The range of a linear map from a finite module is finite. -/
-instance range {F : Type*} [FunLike F M N] [SemilinearMapClass F (RingHom.id R) M N] [Finite R M]
- (f : F) : Finite R (LinearMap.range f) :=
+instance range {F : Type*} [FunLike F M N] [SemilinearMapClass F (RingHom.id R) M N]
+ [Module.Finite R M] (f : F) : Module.Finite R (LinearMap.range f) :=
of_surjective (SemilinearMapClass.semilinearMap f).rangeRestrict
fun ⟨_, y, hy⟩ => ⟨y, Subtype.ext hy⟩
/-- Pushforwards of finite submodules are finite. -/
-instance map (p : Submodule R M) [Finite R p] (f : M →ₗ[R] N) : Finite R (p.map f) :=
+instance map (p : Submodule R M) [Module.Finite R p] (f : M →ₗ[R] N) : Module.Finite R (p.map f) :=
of_surjective (f.restrict fun _ => Submodule.mem_map_of_mem) fun ⟨_, _, hy, hy'⟩ =>
⟨⟨_, hy⟩, Subtype.ext hy'⟩
variable (R)
-instance self : Finite R R :=
+instance self : Module.Finite R R :=
⟨⟨{1}, by simpa only [Finset.coe_singleton] using Ideal.span_singleton_one⟩⟩
variable (M)
theorem of_restrictScalars_finite (R A M : Type*) [CommSemiring R] [Semiring A] [AddCommMonoid M]
- [Module R M] [Module A M] [Algebra R A] [IsScalarTower R A M] [hM : Finite R M] :
- Finite A M := by
+ [Module R M] [Module A M] [Algebra R A] [IsScalarTower R A M] [hM : Module.Finite R M] :
+ Module.Finite A M := by
rw [finite_def, Submodule.fg_def] at hM ⊢
obtain ⟨S, hSfin, hSgen⟩ := hM
refine ⟨S, hSfin, eq_top_iff.2 ?_⟩
@@ -576,24 +622,24 @@ theorem of_restrictScalars_finite (R A M : Type*) [CommSemiring R] [Semiring A]
variable {R M}
-instance prod [hM : Finite R M] [hN : Finite R N] : Finite R (M × N) :=
+instance prod [hM : Module.Finite R M] [hN : Module.Finite R N] : Module.Finite R (M × N) :=
⟨by
rw [← Submodule.prod_top]
exact hM.1.prod hN.1⟩
instance pi {ι : Type*} {M : ι → Type*} [_root_.Finite ι] [∀ i, AddCommMonoid (M i)]
- [∀ i, Module R (M i)] [h : ∀ i, Finite R (M i)] : Finite R (∀ i, M i) :=
+ [∀ i, Module R (M i)] [h : ∀ i, Module.Finite R (M i)] : Module.Finite R (∀ i, M i) :=
⟨by
rw [← Submodule.pi_top]
exact Submodule.fg_pi fun i => (h i).1⟩
-theorem equiv [Finite R M] (e : M ≃ₗ[R] N) : Finite R N :=
+theorem equiv [Module.Finite R M] (e : M ≃ₗ[R] N) : Module.Finite R N :=
of_surjective (e : M →ₗ[R] N) e.surjective
-theorem equiv_iff (e : M ≃ₗ[R] N) : Finite R M ↔ Finite R N :=
+theorem equiv_iff (e : M ≃ₗ[R] N) : Module.Finite R M ↔ Module.Finite R N :=
⟨fun _ ↦ equiv e, fun _ ↦ equiv e.symm⟩
-instance ulift [Finite R M] : Finite R (ULift M) := equiv ULift.moduleEquiv.symm
+instance ulift [Module.Finite R M] : Module.Finite R (ULift M) := equiv ULift.moduleEquiv.symm
theorem iff_fg {N : Submodule R M} : Module.Finite R N ↔ N.FG := Module.finite_def.trans (fg_top _)
@@ -601,7 +647,7 @@ variable (R M)
instance bot : Module.Finite R (⊥ : Submodule R M) := iff_fg.mpr fg_bot
-instance top [Finite R M] : Module.Finite R (⊤ : Submodule R M) := iff_fg.mpr out
+instance top [Module.Finite R M] : Module.Finite R (⊤ : Submodule R M) := iff_fg.mpr out
variable {M}
@@ -618,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} :
@@ -628,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
@@ -640,7 +692,7 @@ section Algebra
theorem trans {R : Type*} (A M : Type*) [Semiring R] [Semiring A] [Module R A]
[AddCommMonoid M] [Module R M] [Module A M] [IsScalarTower R A M] :
- ∀ [Finite R A] [Finite A M], Finite R M
+ ∀ [Module.Finite R A] [Module.Finite A M], Module.Finite R M
| ⟨⟨s, hs⟩⟩, ⟨⟨t, ht⟩⟩ =>
⟨Submodule.fg_def.2
⟨Set.image2 (· • ·) (↑s : Set A) (↑t : Set M),
@@ -700,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} [Ring 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›
@@ -758,6 +810,7 @@ namespace RingHom
variable {A B C : Type*} [CommRing A] [CommRing B] [CommRing C]
/-- A ring morphism `A →+* B` is `Finite` if `B` is finitely generated as `A`-module. -/
+@[algebraize Module.Finite]
def Finite (f : A →+* B) : Prop :=
letI : Algebra A B := f.toAlgebra
Module.Finite A B
@@ -776,20 +829,11 @@ theorem of_surjective (f : A →+* B) (hf : Surjective f) : f.Finite :=
Module.Finite.of_surjective (Algebra.linearMap A B) hf
theorem comp {g : B →+* C} {f : A →+* B} (hg : g.Finite) (hf : f.Finite) : (g.comp f).Finite := by
- letI := f.toAlgebra
- letI := g.toAlgebra
- letI := (g.comp f).toAlgebra
- letI : IsScalarTower A B C := RestrictScalars.isScalarTower A B C
- letI : Module.Finite A B := hf
- letI : Module.Finite B C := hg
+ algebraize [f, g, g.comp f]
exact Module.Finite.trans B C
theorem of_comp_finite {f : A →+* B} {g : B →+* C} (h : (g.comp f).Finite) : g.Finite := by
- letI := f.toAlgebra
- letI := g.toAlgebra
- letI := (g.comp f).toAlgebra
- letI : IsScalarTower A B C := RestrictScalars.isScalarTower A B C
- letI : Module.Finite A C := h
+ algebraize [f, g, g.comp f]
exact Module.Finite.of_restrictScalars_finite A B C
end Finite
diff --git a/Mathlib/RingTheory/Fintype.lean b/Mathlib/RingTheory/Fintype.lean
index ea2719912c171..9ee3bc2a315f2 100644
--- a/Mathlib/RingTheory/Fintype.lean
+++ b/Mathlib/RingTheory/Fintype.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Data.Fintype.Units
import Mathlib.Data.ZMod.Basic
diff --git a/Mathlib/RingTheory/Flat/Algebra.lean b/Mathlib/RingTheory/Flat/Algebra.lean
index 0aa4d1079abf0..53bc49e2510e5 100644
--- a/Mathlib/RingTheory/Flat/Algebra.lean
+++ b/Mathlib/RingTheory/Flat/Algebra.lean
@@ -60,6 +60,7 @@ theorem isBaseChange [Algebra R S] (R' : Type w) (S' : Type t) [CommRing R'] [Co
end Algebra.Flat
/-- A ring homomorphism `f : R →+* S` is flat if `S` is flat as an `R` algebra. -/
+@[algebraize RingHom.Flat.out]
class RingHom.Flat {R : Type u} {S : Type v} [CommRing R] [CommRing S] (f : R →+* S) : Prop where
out : f.toAlgebra.Flat := by infer_instance
@@ -75,11 +76,8 @@ variable {R : Type u} {S : Type v} {T : Type w} [CommRing R] [CommRing S] [CommR
/-- Composition of flat ring homomorphisms is flat. -/
instance comp [RingHom.Flat f] [RingHom.Flat g] : RingHom.Flat (g.comp f) where
- out :=
- letI : Algebra R S := f.toAlgebra
- letI : Algebra S T := g.toAlgebra
- letI : Algebra R T := (g.comp f).toAlgebra
- letI : IsScalarTower R S T := IsScalarTower.of_algebraMap_eq (congrFun rfl)
- Algebra.Flat.comp R S T
+ out := by
+ algebraize_only [f, g, g.comp f]
+ exact Algebra.Flat.comp R S T
end RingHom.Flat
diff --git a/Mathlib/RingTheory/Flat/Basic.lean b/Mathlib/RingTheory/Flat/Basic.lean
index 7592d42a7c793..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
@@ -172,7 +189,7 @@ instance directSum (ι : Type v) (M : ι → Type w) [(i : ι) → AddCommGroup
apply TensorProduct.ext'
intro a m
simp only [ρ, ψ, φ, η, η₁, coe_comp, LinearEquiv.coe_coe, Function.comp_apply,
- directSumRight_symm_lof_tmul, rTensor_tmul, Submodule.coeSubtype, lid_tmul, map_smul]
+ directSumRight_symm_lof_tmul, rTensor_tmul, Submodule.coe_subtype, lid_tmul, map_smul]
rw [DirectSum.component.of, DirectSum.component.of]
by_cases h₂ : j = i
· subst j; simp
@@ -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/EquationalCriterion.lean b/Mathlib/RingTheory/Flat/EquationalCriterion.lean
index bef434517f9b0..763d9dc2c83db 100644
--- a/Mathlib/RingTheory/Flat/EquationalCriterion.lean
+++ b/Mathlib/RingTheory/Flat/EquationalCriterion.lean
@@ -120,19 +120,17 @@ theorem tfae_equational_criterion : List.TFAE [
∀ {ι : Type u} [Fintype ι] {f : ι →₀ R} {x : (ι →₀ R) →ₗ[R] M}, x f = 0 →
∃ (κ : Type u) (_ : Fintype κ) (a : (ι →₀ R) →ₗ[R] (κ →₀ R)) (y : (κ →₀ R) →ₗ[R] M),
x = y ∘ₗ a ∧ a f = 0,
- ∀ {N : Type u} [AddCommGroup N] [Module R N] [Free R N] [Finite R N] {f : N} {x : N →ₗ[R] M},
- x f = 0 →
+ ∀ {N : Type u} [AddCommGroup N] [Module R N] [Free R N] [Module.Finite R N] {f : N}
+ {x : N →ₗ[R] M}, x f = 0 →
∃ (κ : Type u) (_ : Fintype κ) (a : N →ₗ[R] (κ →₀ R)) (y : (κ →₀ R) →ₗ[R] M),
x = y ∘ₗ a ∧ a f = 0] := by
classical
- tfae_have 1 ↔ 2
- · exact iff_rTensor_injective' R M
- tfae_have 3 ↔ 2
- · exact forall_vanishesTrivially_iff_forall_rTensor_injective R
- tfae_have 3 ↔ 4
- · simp [(TensorProduct.lid R M).injective.eq_iff.symm, isTrivialRelation_iff_vanishesTrivially]
+ tfae_have 1 ↔ 2 := iff_rTensor_injective' R M
+ tfae_have 3 ↔ 2 := forall_vanishesTrivially_iff_forall_rTensor_injective R
+ tfae_have 3 ↔ 4 := by
+ simp [(TensorProduct.lid R M).injective.eq_iff.symm, isTrivialRelation_iff_vanishesTrivially]
tfae_have 4 → 5
- · intro h₄ ι hι f x hfx
+ | h₄, ι, hι, f, x, hfx => by
let f' : ι → R := f
let x' : ι → M := fun i ↦ x (single i 1)
have := calc
@@ -154,7 +152,7 @@ theorem tfae_equational_criterion : List.TFAE [
simp only [linearCombination_apply, zero_smul, implies_true, sum_fintype, finset_sum_apply]
exact ha' j
tfae_have 5 → 4
- · intro h₅ ι hi f x hfx
+ | h₅, ι, hi, f, x, hfx => by
let f' : ι →₀ R := equivFunOnFinite.symm f
let x' : (ι →₀ R) →ₗ[R] M := Finsupp.linearCombination R x
have : x' f' = 0 := by simpa [x', f', linearCombination_apply, sum_fintype] using hfx
@@ -167,7 +165,7 @@ theorem tfae_equational_criterion : List.TFAE [
← (fun _ ↦ equivFunOnFinite_symm_apply_toFun _ _ : ∀ x, f' x = f x), univ_sum_single]
simpa using DFunLike.congr_fun ha' j
tfae_have 5 → 6
- · intro h₅ N _ _ _ _ f x hfx
+ | h₅, N, _, _, _, _, f, x, hfx => by
have ϕ := Module.Free.repr R N
have : (x ∘ₗ ϕ.symm) (ϕ f) = 0 := by simpa
obtain ⟨κ, hκ, a', y, ha'y, ha'⟩ := h₅ this
@@ -175,8 +173,7 @@ theorem tfae_equational_criterion : List.TFAE [
· simpa [LinearMap.comp_assoc] using congrArg (fun g ↦ (g ∘ₗ ϕ : N →ₗ[R] M)) ha'y
· simpa using ha'
tfae_have 6 → 5
- · intro h₆ _ _ _ _ hfx
- exact h₆ hfx
+ | h₆, _, _, _, _, hfx => h₆ hfx
tfae_finish
/-- **Equational criterion for flatness** [Stacks 00HK](https://stacks.math.columbia.edu/tag/00HK).
@@ -246,8 +243,8 @@ Let $M$ be a flat module over a commutative ring $R$. Let $N$ be a finite free m
let $f \in N$, and let $x \colon N \to M$ be a homomorphism such that $x(f) = 0$. Then there exist a
finite index type $\kappa$ and module homomorphisms $a \colon N \to R^{\kappa}$ and
$y \colon R^{\kappa} \to M$ such that $x = y \circ a$ and $a(f) = 0$. -/
-theorem exists_factorization_of_apply_eq_zero_of_free [Flat R M] {N : Type u}
- [AddCommGroup N] [Module R N] [Free R N] [Finite R N] {f : N} {x : N →ₗ[R] M} (h : x f = 0) :
+theorem exists_factorization_of_apply_eq_zero_of_free [Flat R M] {N : Type u} [AddCommGroup N]
+ [Module R N] [Free R N] [Module.Finite R N] {f : N} {x : N →ₗ[R] M} (h : x f = 0) :
∃ (κ : Type u) (_ : Fintype κ) (a : N →ₗ[R] (κ →₀ R)) (y : (κ →₀ R) →ₗ[R] M),
x = y ∘ₗ a ∧ a f = 0 := by
exact ((tfae_equational_criterion R M).out 0 5 rfl rfl).mp ‹Flat R M› h
@@ -257,8 +254,8 @@ free, and let $f \colon K \to N$ and $x \colon N \to M$ be homomorphisms such th
$x \circ f = 0$. Then there exist a finite index type $\kappa$ and module homomorphisms
$a \colon N \to R^{\kappa}$ and $y \colon R^{\kappa} \to M$ such that $x = y \circ a$ and
$a \circ f = 0$. -/
-theorem exists_factorization_of_comp_eq_zero_of_free [Flat R M] {K N : Type u}
- [AddCommGroup K] [Module R K] [Finite R K] [AddCommGroup N] [Module R N] [Free R N] [Finite R N]
+theorem exists_factorization_of_comp_eq_zero_of_free [Flat R M] {K N : Type u} [AddCommGroup K]
+ [Module R K] [Module.Finite R K] [AddCommGroup N] [Module R N] [Free R N] [Module.Finite R N]
{f : K →ₗ[R] N} {x : N →ₗ[R] M} (h : x ∘ₗ f = 0) :
∃ (κ : Type u) (_ : Fintype κ) (a : N →ₗ[R] (κ →₀ R)) (y : (κ →₀ R) →ₗ[R] M),
x = y ∘ₗ a ∧ a ∘ₗ f = 0 := by
@@ -286,7 +283,7 @@ theorem exists_factorization_of_isFinitelyPresented [Flat R M] {P : Type u} [Add
∃ (κ : Type u) (_ : Fintype κ) (h₂ : P →ₗ[R] (κ →₀ R)) (h₃ : (κ →₀ R) →ₗ[R] M),
h₁ = h₃ ∘ₗ h₂ := by
obtain ⟨L, _, _, K, ϕ, _, _, hK⟩ := FinitePresentation.equiv_quotient R P
- haveI : Finite R ↥K := Module.Finite.iff_fg.mpr hK
+ haveI : Module.Finite R ↥K := Module.Finite.iff_fg.mpr hK
have : (h₁ ∘ₗ ϕ.symm ∘ₗ K.mkQ) ∘ₗ K.subtype = 0 := by
simp_rw [comp_assoc, (LinearMap.exact_subtype_mkQ K).linearMap_comp_eq_zero, comp_zero]
obtain ⟨κ, hκ, a, y, hay, ha⟩ := exists_factorization_of_comp_eq_zero_of_free this
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/Generators.lean b/Mathlib/RingTheory/Generators.lean
index 8cd1cdb774bff..3ded91b21c690 100644
--- a/Mathlib/RingTheory/Generators.lean
+++ b/Mathlib/RingTheory/Generators.lean
@@ -106,6 +106,18 @@ def ofSurjective {vars} (val : vars → S) (h : Function.Surjective (aeval (R :=
σ' x := (h x).choose
aeval_val_σ' x := (h x).choose_spec
+/-- If `algebraMap R S` is surjective, the empty type generates `S`. -/
+noncomputable def ofSurjectiveAlgebraMap (h : Function.Surjective (algebraMap R S)) :
+ Generators.{w} R S :=
+ ofSurjective PEmpty.elim <| fun s ↦ by
+ use C (h s).choose
+ simp [(h s).choose_spec]
+
+/-- The canonical generators for `R` as an `R`-algebra. -/
+noncomputable def id : Generators.{w} R R := ofSurjectiveAlgebraMap <| by
+ rw [id.map_eq_id]
+ exact RingHomSurjective.is_surjective
+
/-- Construct `Generators` from an assignment `I → S` such that `R[X] → S` is surjective. -/
noncomputable
def ofAlgHom {I} (f : MvPolynomial I R →ₐ[R] S) (h : Function.Surjective f) :
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 148770477311f..7719c9ebf8a30 100644
--- a/Mathlib/RingTheory/HahnSeries/Multiplication.lean
+++ b/Mathlib/RingTheory/HahnSeries/Multiplication.lean
@@ -6,6 +6,7 @@ Authors: Aaron Anderson, Scott Carnahan
import Mathlib.Algebra.Algebra.Subalgebra.Basic
import Mathlib.Data.Finset.MulAntidiagonal
import Mathlib.Data.Finset.SMulAntidiagonal
+import Mathlib.GroupTheory.GroupAction.Ring
import Mathlib.RingTheory.HahnSeries.Addition
/-!
@@ -36,7 +37,7 @@ open Finset Function Pointwise
noncomputable section
-variable {Γ Γ' R V : Type*}
+variable {Γ Γ' R S V : Type*}
namespace HahnSeries
@@ -73,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
@@ -228,10 +235,10 @@ theorem add_smul [AddCommMonoid R] [SMulWithZero R V] {x y : HahnSeries Γ R}
ext a
have hwf := x.isPWO_support.union y.isPWO_support
rw [smul_coeff_left hwf, HahnSeries.add_coeff', of_symm_add]
- simp_all only [Pi.add_apply, HahnSeries.add_coeff']
- rw [smul_coeff_left hwf Set.subset_union_right,
- smul_coeff_left hwf Set.subset_union_left]
- · simp only [HahnSeries.add_coeff, h, sum_add_distrib]
+ · simp_all only [Pi.add_apply, HahnSeries.add_coeff']
+ rw [smul_coeff_left hwf Set.subset_union_right,
+ smul_coeff_left hwf Set.subset_union_left]
+ simp only [HahnSeries.add_coeff, h, sum_add_distrib]
· intro b
simp_all only [Set.isPWO_union, HahnSeries.isPWO_support, and_self, HahnSeries.mem_support,
HahnSeries.add_coeff, ne_eq, Set.mem_union, Set.mem_setOf_eq, mem_support]
@@ -252,7 +259,7 @@ theorem single_smul_coeff_add [MulZeroClass R] [SMulWithZero R V] {r : R} {x : H
rw [sum_congr _ fun _ _ => rfl, sum_empty]
ext ⟨a1, a2⟩
simp only [not_mem_empty, not_and, Set.mem_singleton_iff, Classical.not_not,
- mem_vaddAntidiagonal, Set.mem_setOf_eq, iff_false_iff]
+ mem_vaddAntidiagonal, Set.mem_setOf_eq, iff_false]
rintro rfl h2 h1
rw [IsCancelVAdd.left_cancel a1 a2 a h1] at h2
exact h2 hx
@@ -347,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 =
@@ -386,7 +406,7 @@ theorem mul_single_coeff_add [NonUnitalNonAssocSemiring R] {r : R} {x : HahnSeri
rw [sum_congr _ fun _ _ => rfl, sum_empty]
ext ⟨a1, a2⟩
simp only [not_mem_empty, not_and, Set.mem_singleton_iff, Classical.not_not,
- mem_addAntidiagonal, Set.mem_setOf_eq, iff_false_iff]
+ mem_addAntidiagonal, Set.mem_setOf_eq, iff_false]
rintro h2 rfl h1
rw [← add_right_cancel h1] at hx
exact h2 hx
@@ -534,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
@@ -633,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
@@ -753,9 +776,9 @@ instance [Nontrivial Γ] [Nontrivial R] : Nontrivial (Subalgebra R (HahnSeries
rw [Ne, SetLike.ext_iff, not_forall]
obtain ⟨a, ha⟩ := exists_ne (0 : Γ)
refine ⟨single a 1, ?_⟩
- simp only [Algebra.mem_bot, not_exists, Set.mem_range, iff_true_iff, Algebra.mem_top]
+ 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 1441d746ae5c7..7a70d9e119bf8 100644
--- a/Mathlib/RingTheory/HahnSeries/PowerSeries.lean
+++ b/Mathlib/RingTheory/HahnSeries/PowerSeries.lean
@@ -5,6 +5,7 @@ Authors: Aaron Anderson
-/
import Mathlib.RingTheory.HahnSeries.Multiplication
import Mathlib.RingTheory.PowerSeries.Basic
+import Mathlib.RingTheory.MvPowerSeries.NoZeroDivisors
import Mathlib.Data.Finsupp.PWO
/-!
@@ -18,6 +19,11 @@ we get the more familiar semiring of formal power series with coefficients in `R
* `toPowerSeries` the isomorphism from `HahnSeries ℕ R` to `PowerSeries R`.
* `ofPowerSeries` the inverse, casting a `PowerSeries R` to a `HahnSeries ℕ R`.
+## Instances
+ * For `Finite σ`, the instance `NoZeroDivisors (HahnSeries (σ →₀ ℕ) R)`,
+ deduced from the case of `MvPowerSeries`
+ The case of `HahnSeries ℕ R` is taken care of by `instNoZeroDivisors`.
+
## TODO
* Build an API for the variable `X` (defined to be `single 1 1 : HahnSeries Γ R`) in analogy to
`X : R[X]` and `X : PowerSeries R`
@@ -31,7 +37,7 @@ open Finset Function Pointwise Polynomial
noncomputable section
-variable {Γ : Type*} {R : Type*}
+variable {Γ R : Type*}
namespace HahnSeries
@@ -107,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]
@@ -120,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]
@@ -166,6 +172,12 @@ def toMvPowerSeries {σ : Type*} [Finite σ] : HahnSeries (σ →₀ ℕ) R ≃+
variable {σ : Type*} [Finite σ]
+-- TODO : generalize to all (?) rings of Hahn Series
+/-- If R has no zero divisors and `σ` is finite,
+then `HahnSeries (σ →₀ ℕ) R` has no zero divisors -/
+instance [NoZeroDivisors R] : NoZeroDivisors (HahnSeries (σ →₀ ℕ) R) :=
+ toMvPowerSeries.toMulEquiv.noZeroDivisors (A := HahnSeries (σ →₀ ℕ) R) (MvPowerSeries σ R)
+
theorem coeff_toMvPowerSeries {f : HahnSeries (σ →₀ ℕ) R} {n : σ →₀ ℕ} :
MvPowerSeries.coeff R n (toMvPowerSeries f) = f.coeff n :=
rfl
diff --git a/Mathlib/RingTheory/HahnSeries/Summable.lean b/Mathlib/RingTheory/HahnSeries/Summable.lean
index 517632b481a87..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
@@ -418,8 +547,8 @@ def powers (x : HahnSeries Γ R) (hx : 0 < x.orderTop) : SummableFamily Γ R ℕ
· exact Set.mem_union_right _ (Set.mem_singleton 0)
· obtain ⟨i, hi, j, hj, rfl⟩ := support_mul_subset_add_support hn
refine Set.mem_union_left _ ⟨n, Set.mem_iUnion.2 ⟨⟨j, i⟩, Set.mem_iUnion.2 ⟨?_, hi⟩⟩, rfl⟩
- simp only [and_true_iff, Set.mem_iUnion, mem_addAntidiagonal, mem_coe, eq_self_iff_true,
- Ne, mem_support, Set.mem_setOf_eq]
+ simp only [Set.mem_iUnion, mem_addAntidiagonal, mem_coe, eq_self_iff_true, Ne, mem_support,
+ Set.mem_setOf_eq]
exact ⟨hj, ⟨n, hi⟩, add_comm j i⟩
variable {x : HahnSeries Γ R} (hx : 0 < x.orderTop)
@@ -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 18e8607dbc93a..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`.
@@ -121,10 +124,9 @@ theorem HenselianLocalRing.TFAE (R : Type u) [CommRing R] [LocalRing R] :
∀ (φ : R →+* K), Surjective φ → ∀ f : R[X], f.Monic → ∀ a₀ : K,
f.eval₂ φ a₀ = 0 → f.derivative.eval₂ φ a₀ ≠ 0 → ∃ a : R, f.IsRoot a ∧ φ a = a₀] := by
tfae_have 3 → 2
- · intro H
- exact H (residue R) Ideal.Quotient.mk_surjective
+ | H => H (residue R) Ideal.Quotient.mk_surjective
tfae_have 2 → 1
- · intro H
+ | H => by
constructor
intro f hf a₀ h₁ h₂
specialize H f hf (residue R a₀)
@@ -136,10 +138,10 @@ theorem HenselianLocalRing.TFAE (R : Type u) [CommRing R] [LocalRing R] :
rw [← Ideal.Quotient.eq_zero_iff_mem]
rwa [← sub_eq_zero, ← RingHom.map_sub] at ha₂
tfae_have 1 → 3
- · intro hR K _K φ hφ f hf a₀ h₁ h₂
+ | hR, K, _K, φ, hφ, f, hf, a₀, h₁, h₂ => by
obtain ⟨a₀, rfl⟩ := hφ a₀
have H := HenselianLocalRing.is_henselian f hf a₀
- simp only [← ker_eq_maximalIdeal φ hφ, eval₂_at_apply, RingHom.mem_ker φ] at H h₁ h₂
+ simp only [← ker_eq_maximalIdeal φ hφ, eval₂_at_apply, RingHom.mem_ker] at H h₁ h₂
obtain ⟨a, ha₁, ha₂⟩ := H h₁ (by
contrapose! h₂
rwa [← mem_nonunits_iff, ← LocalRing.mem_maximalIdeal, ← LocalRing.ker_eq_maximalIdeal φ hφ,
@@ -194,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
@@ -230,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 e37e8ce6c85bf..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
/-!
@@ -104,7 +104,7 @@ theorem LinearEquiv.AssociatedPrimes.eq (l : M ≃ₗ[R] M') :
(associatedPrimes.subset_of_injective l.symm l.symm.injective)
theorem associatedPrimes.eq_empty_of_subsingleton [Subsingleton M] : associatedPrimes R M = ∅ := by
- ext; simp only [Set.mem_empty_iff_false, iff_false_iff]
+ ext; simp only [Set.mem_empty_iff_false, iff_false]
apply not_isAssociatedPrime_of_subsingleton
variable (R M)
@@ -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 b54b293c33f77..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,357 +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 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 {S : Type*} [CommSemiring S] {x y : S} {I : Ideal S} :
- x ∈ Ideal.span {y} ⊔ I ↔ ∃ a : S, ∃ 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)
@@ -395,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
@@ -424,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 mem_span_singleton_self (x : α) : x ∈ span ({x} : Set α) :=
- mem_span_singleton.mpr dvd_rfl
-
-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}
-
-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
@@ -520,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
@@ -586,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`. -/
@@ -678,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
@@ -802,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/Cotangent.lean b/Mathlib/RingTheory/Ideal/Cotangent.lean
index 948ea0ff4843f..9ce01fea0e26b 100644
--- a/Mathlib/RingTheory/Ideal/Cotangent.lean
+++ b/Mathlib/RingTheory/Ideal/Cotangent.lean
@@ -251,7 +251,7 @@ lemma CotangentSpace.span_image_eq_top_iff [IsNoetherianRing R] {s : Set (maxima
· simp only [Ideal.toCotangent_apply, Submodule.restrictScalars_top, Submodule.map_span]
· exact Ideal.Quotient.mk_surjective
-open FiniteDimensional
+open Module
lemma finrank_cotangentSpace_eq_zero_iff [IsNoetherianRing R] :
finrank (ResidueField R) (CotangentSpace R) = 0 ↔ IsField R := by
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 8b0482cf861a6..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 :=
@@ -125,11 +130,21 @@ theorem comap_comap {T : Type*} [Semiring T] {I : Ideal T} (f : R →+* S) (g :
(I.comap g).comap f = I.comap (g.comp f) :=
rfl
+lemma comap_comapₐ {R A B C : Type*} [CommSemiring R] [Semiring A] [Algebra R A] [Semiring B]
+ [Algebra R B] [Semiring C] [Algebra R C] {I : Ideal C} (f : A →ₐ[R] B) (g : B →ₐ[R] C) :
+ (I.comap g).comap f = I.comap (g.comp f) :=
+ I.comap_comap f.toRingHom g.toRingHom
+
theorem map_map {T : Type*} [Semiring T] {I : Ideal R} (f : R →+* S) (g : S →+* T) :
(I.map f).map g = I.map (g.comp f) :=
((gc_map_comap f).compose (gc_map_comap g)).l_unique (gc_map_comap (g.comp f)) fun _ =>
comap_comap _ _
+lemma map_mapₐ {R A B C : Type*} [CommSemiring R] [Semiring A] [Algebra R A] [Semiring B]
+ [Algebra R B] [Semiring C] [Algebra R C] {I : Ideal A} (f : A →ₐ[R] B) (g : B →ₐ[R] C) :
+ (I.map f).map g = I.map (g.comp f) :=
+ I.map_map f.toRingHom g.toRingHom
+
theorem map_span (f : F) (s : Set R) : map f (span s) = span (f '' s) := by
refine (Submodule.span_eq_of_le _ ?_ ?_).symm
· rintro _ ⟨x, hx, rfl⟩; exact mem_map_of_mem f (subset_span hx)
@@ -163,6 +178,9 @@ theorem comap_eq_top_iff {I : Ideal S} : I.comap f = ⊤ ↔ I = ⊤ :=
theorem map_bot : (⊥ : Ideal R).map f = ⊥ :=
(gc_map_comap f).l_bot
+theorem ne_bot_of_map_ne_bot (hI : map f I ≠ ⊥) : I ≠ ⊥ :=
+ fun h => hI (Eq.mpr (congrArg (fun I ↦ map f I = ⊥) h) map_bot)
+
variable (f I J K L)
@[simp]
@@ -196,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}
@@ -281,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 _ _⟩
@@ -317,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]
@@ -325,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
@@ -408,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 =>
@@ -433,6 +464,10 @@ theorem comap_le_iff_le_map (hf : Function.Bijective f) {I : Ideal R} {K : Ideal
⟨fun h => le_map_of_comap_le_of_surjective f hf.right h, fun h =>
(relIsoOfBijective f hf).right_inv I ▸ comap_mono h⟩
+lemma comap_map_of_bijective (hf : Function.Bijective f) {I : Ideal R} :
+ (I.map f).comap f = I :=
+ le_antisymm ((comap_le_iff_le_map f hf).mpr fun _ ↦ id) le_comap_map
+
theorem map.isMaximal (hf : Function.Bijective f) {I : Ideal R} (H : IsMaximal I) :
IsMaximal (map f I) := by
refine
@@ -442,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) :
@@ -466,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)))
@@ -529,8 +569,9 @@ variable (f : F) (g : G)
def ker : Ideal R :=
Ideal.comap f ⊥
+variable {f} in
/-- An element is in the kernel if and only if it maps to zero. -/
-theorem mem_ker {r} : r ∈ ker f ↔ f r = 0 := by rw [ker, Ideal.mem_comap, Submodule.mem_bot]
+@[simp] theorem mem_ker {r} : r ∈ ker f ↔ f r = 0 := by rw [ker, Ideal.mem_comap, Submodule.mem_bot]
theorem ker_eq : (ker f : Set R) = Set.preimage f {0} :=
rfl
@@ -552,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 :=
@@ -609,16 +650,122 @@ theorem ker_isMaximal_of_surjective {R K F : Type*} [Ring R] [Field K]
(hf : Function.Surjective f) : (ker f).IsMaximal := by
refine
Ideal.isMaximal_iff.mpr
- ⟨fun h1 => one_ne_zero' K <| map_one f ▸ (mem_ker f).mp h1, fun J x hJ hxf hxJ => ?_⟩
+ ⟨fun h1 => one_ne_zero' K <| map_one f ▸ mem_ker.mp h1, fun J x hJ hxf hxJ => ?_⟩
obtain ⟨y, hy⟩ := hf (f x)⁻¹
have H : 1 = y * x - (y * x - 1) := (sub_sub_cancel _ _).symm
rw [H]
refine J.sub_mem (J.mul_mem_left _ hxJ) (hJ ?_)
rw [mem_ker]
- simp only [hy, map_sub, map_one, map_mul, inv_mul_cancel₀ (mt (mem_ker f).mpr hxf), sub_self]
+ simp only [hy, map_sub, map_one, map_mul, inv_mul_cancel₀ (mt mem_ker.mpr hxf :), sub_self]
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*}
@@ -631,12 +778,13 @@ theorem map_eq_bot_iff_le_ker {I : Ideal R} (f : F) : I.map f = ⊥ ↔ I ≤ Ri
rw [RingHom.ker, eq_bot_iff, map_le_iff_le_comap]
theorem ker_le_comap {K : Ideal S} (f : F) : RingHom.ker f ≤ comap f K := fun _ hx =>
- mem_comap.2 (((RingHom.mem_ker f).1 hx).symm ▸ K.zero_mem)
+ 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
@@ -645,6 +793,10 @@ section Ring
variable [Ring R] [Ring S] [FunLike F R S] [rc : RingHomClass F R S]
+lemma comap_map_of_surjective' (f : F) (hf : Function.Surjective f) (I : Ideal R) :
+ (I.map f).comap f = I ⊔ RingHom.ker f :=
+ comap_map_of_surjective f hf I
+
theorem map_sInf {A : Set (Ideal R)} {f : F} (hf : Function.Surjective f) :
(∀ J ∈ A, RingHom.ker f ≤ J) → map f (sInf A) = sInf (map f '' A) := by
refine fun h => le_antisymm (le_sInf ?_) ?_
@@ -726,15 +878,15 @@ def liftOfRightInverseAux (hf : Function.RightInverse f_inv f) (g : A →+* C)
{ AddMonoidHom.liftOfRightInverse f.toAddMonoidHom f_inv hf ⟨g.toAddMonoidHom, hg⟩ with
toFun := fun b => g (f_inv b)
map_one' := by
- rw [← map_one g, ← sub_eq_zero, ← map_sub g, ← mem_ker g]
+ rw [← map_one g, ← sub_eq_zero, ← map_sub g, ← mem_ker]
apply hg
- rw [mem_ker f, map_sub f, sub_eq_zero, map_one f]
+ rw [mem_ker, map_sub f, sub_eq_zero, map_one f]
exact hf 1
map_mul' := by
intro x y
- rw [← map_mul g, ← sub_eq_zero, ← map_sub g, ← mem_ker g]
+ rw [← map_mul g, ← sub_eq_zero, ← map_sub g, ← mem_ker]
apply hg
- rw [mem_ker f, map_sub f, sub_eq_zero, map_mul f]
+ rw [mem_ker, map_sub f, sub_eq_zero, map_mul f]
simp only [hf _] }
@[simp]
@@ -764,7 +916,7 @@ See `RingHom.eq_liftOfRightInverse` for the uniqueness lemma.
def liftOfRightInverse (hf : Function.RightInverse f_inv f) :
{ g : A →+* C // RingHom.ker f ≤ RingHom.ker g } ≃ (B →+* C) where
toFun g := f.liftOfRightInverseAux f_inv hf g.1 g.2
- invFun φ := ⟨φ.comp f, fun x hx => (mem_ker _).mpr <| by simp [(mem_ker _).mp hx]⟩
+ invFun φ := ⟨φ.comp f, fun x hx => mem_ker.mpr <| by simp [mem_ker.mp hx]⟩
left_inv g := by
ext
simp only [comp_apply, liftOfRightInverseAux_comp_apply, Subtype.coe_mk]
@@ -807,6 +959,10 @@ lemma coe_ker : RingHom.ker f = RingHom.ker (f : A →+* B) := rfl
lemma coe_ideal_map (I : Ideal A) :
Ideal.map f I = Ideal.map (f : A →+* B) I := rfl
+lemma comap_ker {C : Type*} [Semiring C] [Algebra R C] (f : B →ₐ[R] C) (g : A →ₐ[R] B) :
+ (RingHom.ker f).comap g = RingHom.ker (f.comp g) :=
+ RingHom.comap_ker f.toRingHom g.toRingHom
+
end AlgHom
namespace Algebra
@@ -820,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 b30d0820ffb94..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
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 839647966fb3a..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,9 +522,14 @@ 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 = ⊤) :
+ I ⊔ Multiset.prod s = ⊤ :=
+ Multiset.prod_induction (I ⊔ · = ⊤) s (fun _ _ hp hq ↦ (sup_mul_eq_of_coprime_left hp).trans hq)
+ (by simp only [one_eq_top, ge_iff_le, top_le_iff, le_top, sup_of_le_right]) h
+
theorem sup_iInf_eq_top {s : Finset ι} {J : ι → Ideal R} (h : ∀ i, i ∈ s → I ⊔ J i = ⊤) :
(I ⊔ ⨅ i ∈ s, J i) = ⊤ :=
eq_top_iff.mpr <|
@@ -633,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]
@@ -684,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]⟩
@@ -878,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 _ _)
@@ -898,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 =>
@@ -975,10 +925,37 @@ theorem IsPrime.multiset_prod_mem_iff_exists_mem {I : Ideal R} (hI : I.IsPrime)
s.prod ∈ I ↔ ∃ p ∈ s, p ∈ I := by
simpa [span_singleton_le_iff_mem] using (hI.multiset_prod_map_le (span {·}))
+theorem IsPrime.pow_le_iff {I P : Ideal R} [hP : P.IsPrime] {n : ℕ} (hn : n ≠ 0) :
+ I ^ n ≤ P ↔ I ≤ P := by
+ have h : (Multiset.replicate n I).prod ≤ P ↔ _ := hP.multiset_prod_le
+ simp_rw [Multiset.prod_replicate, Multiset.mem_replicate, ne_eq, hn, not_false_eq_true,
+ true_and, exists_eq_left] at h
+ exact h
+
+@[deprecated (since := "2024-10-06")] alias pow_le_prime_iff := IsPrime.pow_le_iff
+
+theorem IsPrime.le_of_pow_le {I P : Ideal R} [hP : P.IsPrime] {n : ℕ} (h : I ^ n ≤ P) :
+ I ≤ P := by
+ by_cases hn : n = 0
+ · rw [hn, pow_zero, one_eq_top] at h
+ exact fun ⦃_⦄ _ ↦ h Submodule.mem_top
+ · exact (pow_le_iff hn).mp h
+
+@[deprecated (since := "2024-10-06")] alias le_of_pow_le_prime := IsPrime.le_of_pow_le
+
theorem IsPrime.prod_le {s : Finset ι} {f : ι → Ideal R} {P : Ideal R} (hp : IsPrime P) :
s.prod f ≤ P ↔ ∃ i ∈ s, f i ≤ P :=
hp.multiset_prod_map_le f
+@[deprecated (since := "2024-10-06")] alias prod_le_prime := IsPrime.prod_le
+
+/-- The product of a finite number of elements in the commutative semiring `R` lies in the
+ prime ideal `p` if and only if at least one of those elements is in `p`. -/
+theorem IsPrime.prod_mem_iff {s : Finset ι} {x : ι → R} {p : Ideal R} [hp : p.IsPrime] :
+ ∏ i in s, x i ∈ p ↔ ∃ i ∈ s, x i ∈ p := by
+ simp_rw [← span_singleton_le_iff_mem, ← prod_span_singleton]
+ exact hp.prod_le
+
theorem IsPrime.prod_mem_iff_exists_mem {I : Ideal R} (hI : I.IsPrime) (s : Finset R) :
s.prod (fun x ↦ x) ∈ I ↔ ∃ p ∈ s, p ∈ I := by
rw [Finset.prod_eq_multiset_prod, Multiset.map_id']
@@ -1017,7 +994,7 @@ theorem subset_union_prime' {R : Type u} [CommRing R] {s : Finset ι} {f : ι
rw [Finset.card_eq_zero] at hn
subst hn
rw [Finset.coe_empty, Set.biUnion_empty, Set.union_empty, subset_union] at h
- simpa only [exists_prop, Finset.not_mem_empty, false_and_iff, exists_false, or_false_iff]
+ simpa only [exists_prop, Finset.not_mem_empty, false_and, exists_false, or_false]
classical
replace hn : ∃ (i : ι) (t : Finset ι), i ∉ t ∧ insert i t = s ∧ t.card = n :=
Finset.card_eq_succ.1 hn
@@ -1038,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 => ?_))
@@ -1047,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
@@ -1059,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 7abf1424f8ab5..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
@@ -36,7 +37,7 @@ This is an isomorphism if `f` has a right inverse (`quotientKerEquivOfRightInver
is surjective (`quotientKerEquivOfSurjective`).
-/
def kerLift : R ⧸ ker f →+* S :=
- Ideal.Quotient.lift _ f fun _ => f.mem_ker.mp
+ Ideal.Quotient.lift _ f fun _ => mem_ker.mp
@[simp]
theorem kerLift_mk (r : R) : kerLift f (Ideal.Quotient.mk (ker f) r) = f r :=
@@ -49,7 +50,7 @@ theorem lift_injective_of_ker_le_ideal (I : Ideal R) {f : R →+* S} (H : ∀ a
obtain ⟨v, rfl⟩ := Ideal.Quotient.mk_surjective u
rw [Ideal.Quotient.lift_mk] at hu
rw [Ideal.Quotient.eq_zero_iff_mem]
- exact hI ((RingHom.mem_ker f).mpr hu)
+ exact hI (RingHom.mem_ker.mpr hu)
/-- The induced map from the quotient by the kernel is injective. -/
theorem kerLift_injective : Function.Injective (kerLift f) :=
@@ -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 ccb893e5a0cc6..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))
@@ -148,9 +155,23 @@ variable (f : R →+* S)
theorem RingHom.IsIntegralElem.neg {x : S} (hx : f.IsIntegralElem x) : f.IsIntegralElem (-x) :=
hx.of_mem_closure f hx (Subring.neg_mem _ (Subring.subset_closure (Or.inl rfl)))
+theorem RingHom.IsIntegralElem.of_neg {x : S} (h : f.IsIntegralElem (-x)) : f.IsIntegralElem x :=
+ neg_neg x ▸ h.neg
+
+@[simp]
+theorem RingHom.IsIntegralElem.neg_iff {x : S} : f.IsIntegralElem (-x) ↔ f.IsIntegralElem x :=
+ ⟨fun h => h.of_neg, fun h => h.neg⟩
+
theorem IsIntegral.neg {x : B} (hx : IsIntegral R x) : IsIntegral R (-x) :=
.of_mem_of_fg _ hx.fg_adjoin_singleton _ (Subalgebra.neg_mem _ <| Algebra.subset_adjoin rfl)
+theorem IsIntegral.of_neg {x : B} (hx : IsIntegral R (-x)) : IsIntegral R x :=
+ neg_neg x ▸ hx.neg
+
+@[simp]
+theorem IsIntegral.neg_iff {x : B} : IsIntegral R (-x) ↔ IsIntegral R x :=
+ ⟨IsIntegral.of_neg, IsIntegral.neg⟩
+
theorem RingHom.IsIntegralElem.sub {x y : S} (hx : f.IsIntegralElem x) (hy : f.IsIntegralElem y) :
f.IsIntegralElem (x - y) := by
simpa only [sub_eq_add_neg] using hx.add f (hy.neg f)
@@ -185,3 +206,7 @@ def integralClosure : Subalgebra R A where
algebraMap_mem' _ := isIntegral_algebraMap
end
+
+theorem mem_integralClosure_iff (R A : Type*) [CommRing R] [CommRing A] [Algebra R A] {a : A} :
+ a ∈ integralClosure R A ↔ IsIntegral R a :=
+ Iff.rfl
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/IntegralRestrict.lean b/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean
index f0f556d8c02f6..5253fd9dff111 100644
--- a/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean
+++ b/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean
@@ -3,11 +3,11 @@ Copyright (c) 2023 Andrew Yang, Patrick Lutz. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andrew Yang
-/
-import Mathlib.RingTheory.IntegralClosure.IntegrallyClosed
-import Mathlib.RingTheory.LocalProperties
-import Mathlib.RingTheory.Localization.NormTrace
-import Mathlib.RingTheory.Localization.LocalizationLocalization
import Mathlib.RingTheory.DedekindDomain.IntegralClosure
+import Mathlib.RingTheory.RingHom.Finite
+import Mathlib.RingTheory.Localization.LocalizationLocalization
+import Mathlib.RingTheory.Localization.NormTrace
+
/-!
# Restriction of various maps between fields to integrally closed subrings.
diff --git a/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean b/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean
index aa5706c755a4c..e4a5c700b65ef 100644
--- a/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean
+++ b/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.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.IntegralClosure.Algebra.Basic
import Mathlib.RingTheory.Localization.Integral
+import Mathlib.RingTheory.Localization.LocalizationLocalization
/-!
# Integrally closed rings
@@ -275,3 +275,31 @@ theorem isIntegrallyClosedOfFiniteExtension [IsDomain R] [FiniteDimensional K L]
(integralClosure_eq_bot_iff L).mp integralClosure_idem
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`,
+ and it is not desirable to involve more content from other files. -/
+instance Field.instIsIntegrallyClosed (K : Type*) [Field K] : IsIntegrallyClosed K :=
+ (isIntegrallyClosed_iff K).mpr fun {x} _ ↦ ⟨x, rfl⟩
diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean
index ef2c7b2672431..ab277015154a5 100644
--- a/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean
+++ b/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean
@@ -131,6 +131,26 @@ theorem IsIntegral.tower_top [Algebra A B] [IsScalarTower R A B] {x : B}
let ⟨p, hp, hpx⟩ := hx
⟨p.map <| algebraMap R A, hp.map _, by rw [← aeval_def, aeval_map_algebraMap, aeval_def, hpx]⟩
+/- If `R` and `T` are isomorphic commutative rings and `S` is an `R`-algebra and a `T`-algebra in
+ a compatible way, then an element `a ∈ S` is integral over `R` if and only if it is integral
+ over `T`.-/
+theorem RingEquiv.isIntegral_iff {R S T : Type*} [CommRing R] [CommRing S] [CommRing T]
+ [Algebra R S] [Algebra T S] (φ : R ≃+* T)
+ (h : (algebraMap T S).comp φ.toRingHom = algebraMap R S) (a : S) :
+ IsIntegral R a ↔ IsIntegral T a := by
+ constructor <;> intro ha
+ · letI : Algebra R T := φ.toRingHom.toAlgebra
+ letI : IsScalarTower R T S :=
+ ⟨fun r t s ↦ by simp only [Algebra.smul_def, map_mul, ← h, mul_assoc]; rfl⟩
+ exact IsIntegral.tower_top ha
+ · have h' : (algebraMap T S) = (algebraMap R S).comp φ.symm.toRingHom := by
+ simp only [← h, RingHom.comp_assoc, RingEquiv.toRingHom_eq_coe, RingEquiv.comp_symm,
+ RingHomCompTriple.comp_eq]
+ letI : Algebra T R := φ.symm.toRingHom.toAlgebra
+ letI : IsScalarTower T R S :=
+ ⟨fun r t s ↦ by simp only [Algebra.smul_def, map_mul, h', mul_assoc]; rfl⟩
+ exact IsIntegral.tower_top ha
+
theorem map_isIntegral_int {B C F : Type*} [Ring B] [Ring C] {b : B}
[FunLike F B C] [RingHomClass F B C] (f : F)
(hb : IsIntegral ℤ b) : IsIntegral ℤ (f b) :=
diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegral/Defs.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegral/Defs.lean
index 891b51eb8aa16..a145ced7ef9ab 100644
--- a/Mathlib/RingTheory/IntegralClosure/IsIntegral/Defs.lean
+++ b/Mathlib/RingTheory/IntegralClosure/IsIntegral/Defs.lean
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kenny Lau
-/
import Mathlib.Algebra.Polynomial.Eval
+import Mathlib.Tactic.Algebraize
/-!
# Integral closure of a subring.
@@ -35,6 +36,7 @@ def RingHom.IsIntegralElem (f : R →+* A) (x : A) :=
/-- A ring homomorphism `f : R →+* A` is said to be integral
if every element `A` is integral with respect to the map `f` -/
+@[algebraize Algebra.IsIntegral.mk]
def RingHom.IsIntegral (f : R →+* A) :=
∀ x : A, f.IsIntegralElem x
diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean
index 0a9301168ce1c..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]
@@ -395,14 +465,14 @@ variable [Algebra R A] [Algebra R A'] [IsScalarTower R A B] [IsScalarTower R A'
/-- Integral closures are all isomorphic to each other. -/
noncomputable def equiv : A ≃ₐ[R] A' :=
AlgEquiv.ofAlgHom
- (lift _ B (isIntegral := isIntegral_algebra R B))
- (lift _ B (isIntegral := isIntegral_algebra R B))
+ (lift R A' B (isIntegral := isIntegral_algebra R B))
+ (lift R A B (isIntegral := isIntegral_algebra R B))
(by ext x; apply algebraMap_injective A' R B; simp)
(by ext x; apply algebraMap_injective A R B; simp)
@[simp]
theorem algebraMap_equiv (x : A) : algebraMap A' B (equiv R A B A' x) = algebraMap A B x :=
- algebraMap_lift A' B (isIntegral := isIntegral_algebra R B) x
+ algebraMap_lift R A' B (isIntegral := isIntegral_algebra R B) x
end Equiv
@@ -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 544f816a2f202..b292e8b1c1ffc 100644
--- a/Mathlib/RingTheory/IntegralDomain.lean
+++ b/Mathlib/RingTheory/IntegralDomain.lean
@@ -54,7 +54,7 @@ def Fintype.groupWithZeroOfCancel (M : Type*) [CancelMonoidWithZero M] [Decidabl
inv_zero := by simp [Inv.inv, dif_pos rfl] }
theorem exists_eq_pow_of_mul_eq_pow_of_coprime {R : Type*} [CommSemiring R] [IsDomain R]
- [GCDMonoid R] [Unique Rˣ] {a b c : R} {n : ℕ} (cp : IsCoprime a b) (h : a * b = c ^ n) :
+ [GCDMonoid R] [Subsingleton Rˣ] {a b c : R} {n : ℕ} (cp : IsCoprime a b) (h : a * b = c ^ n) :
∃ d : R, a = d ^ n := by
refine exists_eq_pow_of_mul_eq_pow (isUnit_of_dvd_one ?_) h
obtain ⟨x, y, hxy⟩ := cp
@@ -65,7 +65,7 @@ theorem exists_eq_pow_of_mul_eq_pow_of_coprime {R : Type*} [CommSemiring R] [IsD
nonrec
theorem Finset.exists_eq_pow_of_mul_eq_pow_of_coprime {ι R : Type*} [CommSemiring R] [IsDomain R]
- [GCDMonoid R] [Unique Rˣ] {n : ℕ} {c : R} {s : Finset ι} {f : ι → R}
+ [GCDMonoid R] [Subsingleton Rˣ] {n : ℕ} {c : R} {s : Finset ι} {f : ι → R}
(h : ∀ i ∈ s, ∀ j ∈ s, i ≠ j → IsCoprime (f i) (f j))
(hprod : ∏ i ∈ s, f i = c ^ n) : ∀ i ∈ s, ∃ d : R, f i = d ^ n := by
classical
@@ -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 03e036aa35719..32da2faaaf6e3 100644
--- a/Mathlib/RingTheory/IsAdjoinRoot.lean
+++ b/Mathlib/RingTheory/IsAdjoinRoot.lean
@@ -121,10 +121,10 @@ theorem subsingleton (h : IsAdjoinRoot S f) [Subsingleton R] : Subsingleton S :=
theorem algebraMap_apply (h : IsAdjoinRoot S f) (x : R) :
algebraMap R S x = h.map (Polynomial.C x) := by rw [h.algebraMap_eq, RingHom.comp_apply]
-@[simp]
theorem mem_ker_map (h : IsAdjoinRoot S f) {p} : p ∈ RingHom.ker h.map ↔ f ∣ p := by
rw [h.ker_map, Ideal.mem_span_singleton]
+@[simp]
theorem map_eq_zero_iff (h : IsAdjoinRoot S f) {p} : h.map p = 0 ↔ f ∣ p := by
rw [← h.mem_ker_map, RingHom.mem_ker]
@@ -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/IsTensorProduct.lean b/Mathlib/RingTheory/IsTensorProduct.lean
index 942b0ab45ddf4..b02662937d43f 100644
--- a/Mathlib/RingTheory/IsTensorProduct.lean
+++ b/Mathlib/RingTheory/IsTensorProduct.lean
@@ -318,11 +318,40 @@ theorem IsBaseChange.comp {f : M →ₗ[R] N} (hf : IsBaseChange S f) {g : N →
ext
rfl
+/-- If `N` is the base change of `M` to `S` and `O` the base change of `M` to `T`, then
+`O` is the base change of `N` to `T`. -/
+lemma IsBaseChange.of_comp {f : M →ₗ[R] N} (hf : IsBaseChange S f) {h : N →ₗ[S] O}
+ (hc : IsBaseChange T ((h : N →ₗ[R] O) ∘ₗ f)) :
+ IsBaseChange T h := by
+ apply IsBaseChange.of_lift_unique
+ intro Q _ _ _ _ r
+ letI : Module R Q := inferInstanceAs (Module R (RestrictScalars R S Q))
+ haveI : IsScalarTower R S Q := IsScalarTower.of_algebraMap_smul fun r ↦ congrFun rfl
+ haveI : IsScalarTower R T Q := IsScalarTower.of_algebraMap_smul fun r x ↦ by
+ simp [IsScalarTower.algebraMap_apply R S T]
+ let r' : M →ₗ[R] Q := r ∘ₗ f
+ let q : O →ₗ[T] Q := hc.lift r'
+ refine ⟨q, ?_, ?_⟩
+ · apply hf.algHom_ext'
+ simp [LinearMap.comp_assoc, hc.lift_comp]
+ · intro q' hq'
+ apply hc.algHom_ext'
+ apply_fun LinearMap.restrictScalars R at hq'
+ rw [← LinearMap.comp_assoc]
+ rw [show q'.restrictScalars R ∘ₗ h.restrictScalars R = _ from hq', hc.lift_comp]
+
+/-- If `N` is the base change `M` to `S`, then `O` is the base change of `M` to `T` if and
+only if `O` is the base change of `N` to `T`. -/
+lemma IsBaseChange.comp_iff {f : M →ₗ[R] N} (hf : IsBaseChange S f) {h : N →ₗ[S] O} :
+ IsBaseChange T ((h : N →ₗ[R] O) ∘ₗ f) ↔ IsBaseChange T h :=
+ ⟨fun hc ↦ IsBaseChange.of_comp hf hc, fun hh ↦ IsBaseChange.comp hf hh⟩
+
variable {R' S' : Type*} [CommSemiring R'] [CommSemiring S']
variable [Algebra R R'] [Algebra S S'] [Algebra R' S'] [Algebra R S']
variable [IsScalarTower R R' S'] [IsScalarTower R S S']
open IsScalarTower (toAlgHom)
+open IsScalarTower (algebraMap_apply)
variable (R S R' S')
@@ -424,7 +453,7 @@ noncomputable def Algebra.pushoutDesc [H : Algebra.IsPushout R S R' S'] {A : Typ
rw [mul_add, map_add, map_add, mul_add, e₁, e₂]
@[simp]
-theorem Algebra.pushoutDesc_left [H : Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
+theorem Algebra.pushoutDesc_left [Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
[Algebra R A] (f : S →ₐ[R] A) (g : R' →ₐ[R] A) (H) (x : S) :
Algebra.pushoutDesc S' f g H (algebraMap S S' x) = f x := by
letI := Module.compHom A f.toRingHom
@@ -442,7 +471,7 @@ theorem Algebra.lift_algHom_comp_left [Algebra.IsPushout R S R' S'] {A : Type*}
AlgHom.ext fun x => (Algebra.pushoutDesc_left S' f g H x : _)
@[simp]
-theorem Algebra.pushoutDesc_right [H : Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
+theorem Algebra.pushoutDesc_right [Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
[Algebra R A] (f : S →ₐ[R] A) (g : R' →ₐ[R] A) (H) (x : R') :
Algebra.pushoutDesc S' f g H (algebraMap R' S' x) = g x :=
letI := Module.compHom A f.toRingHom
@@ -471,4 +500,33 @@ theorem Algebra.IsPushout.algHom_ext [H : Algebra.IsPushout R S R' S'] {A : Type
· intro s₁ s₂ e₁ e₂
rw [map_add, map_add, e₁, e₂]
+/--
+Let the following be a commutative diagram of rings
+```
+ R → S → T
+ ↓ ↓ ↓
+ R' → S' → T'
+```
+where the left-hand square is a pushout. Then the following are equivalent:
+- the big rectangle is a pushout.
+- the right-hand square is a pushout.
+
+Note that this is essentially the isomorphism `T ⊗[S] (S ⊗[R] R') ≃ₐ[T] T ⊗[R] R'`.
+-/
+lemma Algebra.IsPushout.comp_iff {T' : Type*} [CommRing T'] [Algebra R T']
+ [Algebra S' T'] [Algebra S T'] [Algebra T T'] [Algebra R' T']
+ [IsScalarTower R T T'] [IsScalarTower S T T'] [IsScalarTower S S' T']
+ [IsScalarTower R R' T'] [IsScalarTower R S' T'] [IsScalarTower R' S' T']
+ [Algebra.IsPushout R S R' S'] :
+ Algebra.IsPushout R T R' T' ↔ Algebra.IsPushout S T S' T' := by
+ let f : R' →ₗ[R] S' := (IsScalarTower.toAlgHom R R' S').toLinearMap
+ haveI : IsScalarTower R S T' := IsScalarTower.of_algebraMap_eq <| fun x ↦ by
+ rw [algebraMap_apply R S' T', algebraMap_apply R S S', ← algebraMap_apply S S' T']
+ have heq : (toAlgHom S S' T').toLinearMap.restrictScalars R ∘ₗ f =
+ (toAlgHom R R' T').toLinearMap := by
+ ext x
+ simp [f, ← IsScalarTower.algebraMap_apply]
+ rw [isPushout_iff, isPushout_iff, ← heq, IsBaseChange.comp_iff]
+ exact Algebra.IsPushout.out
+
end IsBaseChange
diff --git a/Mathlib/RingTheory/Jacobson.lean b/Mathlib/RingTheory/Jacobson.lean
index f9ca45cdd5b0b..aaa724fa39606 100644
--- a/Mathlib/RingTheory/Jacobson.lean
+++ b/Mathlib/RingTheory/Jacobson.lean
@@ -127,7 +127,7 @@ theorem isJacobson_of_isIntegral [Algebra R S] [Algebra.IsIntegral R S] (hR : Is
((isJacobson_iff_prime_eq.1 hR) (comap (algebraMap R S) P) (comap_isPrime _ _)),
comap_jacobson]
refine sInf_le_sInf fun J hJ => ?_
- simp only [true_and_iff, Set.mem_image, bot_le, Set.mem_setOf_eq]
+ simp only [true_and, Set.mem_image, bot_le, Set.mem_setOf_eq]
have : J.IsMaximal := by simpa using hJ
exact exists_ideal_over_maximal_of_isIntegral J
(comap_bot_le_of_injective _ algebraMap_quotient_injective)
@@ -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 c51eef801b35e..0597e9532b91d 100644
--- a/Mathlib/RingTheory/JacobsonIdeal.lean
+++ b/Mathlib/RingTheory/JacobsonIdeal.lean
@@ -1,11 +1,12 @@
/-
Copyright (c) 2020 Devon Tuma. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kenny Lau, Devon Tuma
+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
/-!
# Jacobson radical
@@ -13,20 +14,24 @@ import Mathlib.RingTheory.Polynomial.Quotient
The Jacobson radical of a ring `R` is defined to be the intersection of all maximal ideals of `R`.
This is similar to how the nilradical is equal to the intersection of all prime ideals of `R`.
-We can extend the idea of the nilradical to ideals of `R`,
-by letting the radical of an ideal `I` be the intersection of prime ideals containing `I`.
+We can extend the idea of the nilradical of `R` to ideals of `R`,
+by letting the nilradical of an ideal `I` be the intersection of prime ideals containing `I`.
Under this extension, the original nilradical is the radical of the zero ideal `⊥`.
Here we define the Jacobson radical of an ideal `I` in a similar way,
as the intersection of maximal ideals containing `I`.
## Main definitions
-Let `R` be a commutative ring, and `I` be an ideal of `R`
+Let `R` be a ring, and `I` be a left ideal of `R`
-* `Ideal.jacobson I` is the jacobson radical, i.e. the infimum of all maximal ideals containing I.
+* `Ideal.jacobson I` is the Jacobson radical, i.e. the infimum of all maximal ideals containing `I`.
* `Ideal.IsLocal I` is the proposition that the jacobson radical of `I` is itself a maximal ideal
+Furthermore when `I` is a two-sided ideal of `R`
+
+* `TwoSidedIdeal.jacobson I` is the Jacobson radical as a two-sided ideal
+
## Main statements
* `mem_jacobson_iff` gives a characterization of members of the jacobson of I
@@ -111,11 +116,17 @@ theorem mem_jacobson_iff {x : R} : x ∈ jacobson I ↔ ∀ y, ∃ z, z * y * x
sub_add_cancel]
exact M.mul_mem_left _ hi) <| him hz⟩
-theorem exists_mul_sub_mem_of_sub_one_mem_jacobson {I : Ideal R} (r : R) (h : r - 1 ∈ jacobson I) :
- ∃ s, s * r - 1 ∈ I := by
+theorem exists_mul_add_sub_mem_of_mem_jacobson {I : Ideal R} (r : R) (h : r ∈ jacobson I) :
+ ∃ s, s * (r + 1) - 1 ∈ I := by
cases' mem_jacobson_iff.1 h 1 with s hs
use s
- simpa [mul_sub] using hs
+ rw [mul_add, mul_one]
+ simpa using hs
+
+theorem exists_mul_sub_mem_of_sub_one_mem_jacobson {I : Ideal R} (r : R) (h : r - 1 ∈ jacobson I) :
+ ∃ s, s * r - 1 ∈ I := by
+ convert exists_mul_add_sub_mem_of_mem_jacobson _ h
+ simp
/-- An ideal equals its Jacobson radical iff it is the intersection of a set of maximal ideals.
Allowing the set to include ⊤ is equivalent, and is included only to simplify some proofs. -/
@@ -214,6 +225,44 @@ theorem jacobson_mono {I J : Ideal R} : I ≤ J → I.jacobson ≤ J.jacobson :=
erw [mem_sInf] at hx ⊢
exact fun K ⟨hK, hK_max⟩ => hx ⟨Trans.trans h hK, hK_max⟩
+/-- The Jacobson radical of a two-sided ideal is two-sided.
+
+It is preferable to use `TwoSidedIdeal.jacobson` instead of this lemma. -/
+theorem jacobson_mul_mem_right {I : Ideal R}
+ (mul_mem_right : ∀ {x y}, x ∈ I → x * y ∈ I) :
+ ∀ {x y}, x ∈ I.jacobson → x * y ∈ I.jacobson := by
+ -- Proof generalized from
+ -- https://ysharifi.wordpress.com/2022/08/16/the-jacobson-radical-definition-and-basic-results/
+ intro x r xJ
+ apply mem_sInf.mpr
+ intro 𝔪 𝔪_mem
+ by_cases r𝔪 : r ∈ 𝔪
+ · apply 𝔪.smul_mem _ r𝔪
+ -- 𝔪₀ := { a : R | a*r ∈ 𝔪 }
+ let 𝔪₀ : Ideal R := Submodule.comap (DistribMulAction.toLinearMap R (S := Rᵐᵒᵖ) R (.op r)) 𝔪
+ suffices x ∈ 𝔪₀ by simpa [𝔪₀] using this
+ have I𝔪₀ : I ≤ 𝔪₀ := fun i iI =>
+ 𝔪_mem.left (mul_mem_right iI)
+ have 𝔪₀_maximal : IsMaximal 𝔪₀ := by
+ refine isMaximal_iff.mpr ⟨
+ fun h => r𝔪 (by simpa [𝔪₀] using h),
+ fun J b 𝔪₀J b𝔪₀ bJ => ?_⟩
+ let K : Ideal R := Ideal.span {b*r} ⊔ 𝔪
+ have ⟨s, y, y𝔪, sbyr⟩ :=
+ mem_span_singleton_sup.mp <|
+ mul_mem_left _ r <|
+ (isMaximal_iff.mp 𝔪_mem.right).right K (b*r)
+ le_sup_right b𝔪₀
+ (mem_sup_left <| mem_span_singleton_self _)
+ have : 1 - s*b ∈ 𝔪₀ := by
+ rw [mul_one, add_comm, ← eq_sub_iff_add_eq] at sbyr
+ rw [sbyr, ← mul_assoc] at y𝔪
+ simp [𝔪₀, sub_mul, y𝔪]
+ have : 1 - s*b + s*b ∈ J := by
+ apply add_mem (𝔪₀J this) (J.mul_mem_left _ bJ)
+ simpa using this
+ exact mem_sInf.mp xJ ⟨I𝔪₀, 𝔪₀_maximal⟩
+
end Ring
section CommRing
@@ -363,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
@@ -375,3 +425,16 @@ theorem isPrimary_of_isMaximal_radical [CommRing R] {I : Ideal R} (hi : IsMaxima
(this ▸ id)⟩
end Ideal
+
+namespace TwoSidedIdeal
+
+variable {R : Type u} [Ring R]
+
+/-- The Jacobson radical of `I` is the infimum of all maximal (left) ideals containing `I`. -/
+def jacobson (I : TwoSidedIdeal R) : TwoSidedIdeal R :=
+ (asIdeal I).jacobson.toTwoSided (Ideal.jacobson_mul_mem_right <| I.mul_mem_right _ _)
+
+lemma asIdeal_jacobson (I : TwoSidedIdeal R) : asIdeal I.jacobson = (asIdeal I).jacobson := by
+ ext; simp [jacobson]
+
+end TwoSidedIdeal
diff --git a/Mathlib/RingTheory/Kaehler/Basic.lean b/Mathlib/RingTheory/Kaehler/Basic.lean
index 4c0d923b7ddfc..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 :
@@ -808,10 +808,10 @@ def KaehlerDifferential.kerToTensor :
map_add' x y := by simp only [Submodule.coe_add, map_add, TensorProduct.tmul_add]
map_smul' r x := by simp only [SetLike.val_smul, smul_eq_mul, Derivation.leibniz,
TensorProduct.tmul_add, TensorProduct.tmul_smul, TensorProduct.smul_tmul', ←
- algebraMap_eq_smul_one, (RingHom.mem_ker _).mp x.prop, TensorProduct.zero_tmul, add_zero,
+ 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] :=
@@ -820,7 +820,7 @@ def KaehlerDifferential.kerCotangentToTensor :
rintro x hx y -
simp only [Submodule.mem_comap, LinearMap.lsmul_apply, LinearMap.mem_ker, map_smul,
kerToTensor_apply, TensorProduct.smul_tmul', ← algebraMap_eq_smul_one,
- (RingHom.mem_ker _).mp hx, TensorProduct.zero_tmul]))
+ RingHom.mem_ker.mp hx, TensorProduct.zero_tmul]))
@[simp]
lemma KaehlerDifferential.kerCotangentToTensor_toCotangent (x) :
@@ -837,7 +837,7 @@ theorem KaehlerDifferential.range_kerCotangentToTensor
constructor
· rintro ⟨x, rfl⟩
obtain ⟨x, rfl⟩ := Ideal.toCotangent_surjective _ x
- simp [kerCotangentToTensor_toCotangent, (RingHom.mem_ker _).mp x.2]
+ simp [kerCotangentToTensor_toCotangent, RingHom.mem_ker.mp x.2]
· intro hx
obtain ⟨x, rfl⟩ := LinearMap.rTensor_surjective (Ω[A⁄R]) (g := Algebra.linearMap A B) h x
obtain ⟨x, rfl⟩ := (TensorProduct.lid _ _).symm.surjective x
@@ -870,7 +870,7 @@ theorem KaehlerDifferential.range_kerCotangentToTensor
simp only [smul_sub, TensorProduct.tmul_sub, Finset.sum_sub_distrib, ← TensorProduct.tmul_sum,
← Finset.sum_smul, Finset.sum_attach, sub_eq_self,
Finset.sum_attach (f := fun i ↦ x i • KaehlerDifferential.D R A i)]
- rw [← TensorProduct.smul_tmul, ← Algebra.algebraMap_eq_smul_one, (RingHom.mem_ker _).mp this,
+ rw [← TensorProduct.smul_tmul, ← Algebra.algebraMap_eq_smul_one, RingHom.mem_ker.mp this,
TensorProduct.zero_tmul]
theorem KaehlerDifferential.exact_kerCotangentToTensor_mapBaseChange
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/KrullDimension/Basic.lean b/Mathlib/RingTheory/KrullDimension/Basic.lean
new file mode 100644
index 0000000000000..cca9f211a88e5
--- /dev/null
+++ b/Mathlib/RingTheory/KrullDimension/Basic.lean
@@ -0,0 +1,64 @@
+/-
+Copyright (c) 2024 Jujian Zhang. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Fangming Li, Jujian Zhang
+-/
+import Mathlib.Algebra.MvPolynomial.CommRing
+import Mathlib.Algebra.Polynomial.Basic
+import Mathlib.RingTheory.PrimeSpectrum
+import Mathlib.Order.KrullDimension
+
+/-!
+# Krull dimensions of (commutative) rings
+
+Given a commutative ring, its ring theoretic Krull dimension is the order theoretic Krull dimension
+of its prime spectrum. Unfolding this definition, it is the length of the longest sequence(s) of
+prime ideals ordered by strict inclusion.
+-/
+
+open Order
+
+/--
+The ring theoretic Krull dimension is the Krull dimension of its spectrum ordered by inclusion.
+-/
+noncomputable def ringKrullDim (R : Type*) [CommRing R] : WithBot (WithTop ℕ) :=
+ krullDim (PrimeSpectrum R)
+
+variable {R S : Type*} [CommRing R] [CommRing S]
+
+@[nontriviality]
+lemma ringKrullDim_eq_bot_of_subsingleton [Subsingleton R] :
+ ringKrullDim R = ⊥ :=
+ krullDim_eq_bot_of_isEmpty
+
+lemma ringKrullDim_nonneg_of_nontrivial [Nontrivial R] :
+ 0 ≤ ringKrullDim R :=
+ krullDim_nonneg_of_nonempty
+
+/-- If `f : R →+* S` is surjective, then `ringKrullDim S ≤ ringKrullDim R`. -/
+theorem ringKrullDim_le_of_surjective (f : R →+* S) (hf : Function.Surjective f) :
+ ringKrullDim S ≤ ringKrullDim R :=
+ krullDim_le_of_strictMono (fun I ↦ ⟨Ideal.comap f I.asIdeal, inferInstance⟩)
+ (Monotone.strictMono_of_injective (fun _ _ hab ↦ Ideal.comap_mono hab)
+ (fun _ _ h => PrimeSpectrum.ext_iff.mpr <| Ideal.comap_injective_of_surjective f hf <| by
+ simpa using h))
+
+/-- If `I` is an ideal of `R`, then `ringKrullDim (R ⧸ I) ≤ ringKrullDim R`. -/
+theorem ringKrullDim_quotient_le (I : Ideal R) :
+ ringKrullDim (R ⧸ I) ≤ ringKrullDim R :=
+ ringKrullDim_le_of_surjective _ Ideal.Quotient.mk_surjective
+
+/-- If `R` and `S` are isomorphic, then `ringKrullDim R = ringKrullDim S`. -/
+theorem ringKrullDim_eq_of_ringEquiv (e : R ≃+* S) :
+ ringKrullDim R = ringKrullDim S :=
+ le_antisymm (ringKrullDim_le_of_surjective e.symm e.symm.surjective)
+ (ringKrullDim_le_of_surjective e e.surjective)
+
+alias RingEquiv.ringKrullDim := ringKrullDim_eq_of_ringEquiv
+
+proof_wanted Polynomial.ringKrullDim_le :
+ ringKrullDim (Polynomial R) ≤ 2 * (ringKrullDim R) + 1
+
+proof_wanted MvPolynomial.fin_ringKrullDim_eq_add_of_isNoetherianRing
+ [IsNoetherianRing R] (n : ℕ) :
+ ringKrullDim (MvPolynomial (Fin n) R) = ringKrullDim R + n
diff --git a/Mathlib/RingTheory/KrullDimension/Field.lean b/Mathlib/RingTheory/KrullDimension/Field.lean
new file mode 100644
index 0000000000000..bc8ebdf09a387
--- /dev/null
+++ b/Mathlib/RingTheory/KrullDimension/Field.lean
@@ -0,0 +1,22 @@
+/-
+Copyright (c) 2024 Jujian Zhang. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Fangming Li, Jujian Zhang
+-/
+import Mathlib.RingTheory.KrullDimension.Basic
+
+/-!
+# The Krull dimension of a field
+
+This file proves that the Krull dimension of a field is zero.
+-/
+
+open Order
+
+@[simp]
+theorem ringKrullDim_eq_zero_of_field (F : Type*) [Field F] : ringKrullDim F = 0 :=
+ krullDim_eq_zero_of_unique
+
+theorem ringKrullDim_eq_zero_of_isField {F : Type*} [CommRing F] (hF : IsField F) :
+ ringKrullDim F = 0 :=
+ @krullDim_eq_zero_of_unique _ _ <| @PrimeSpectrum.instUnique _ hF.toField
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 bd1f3b8b077e1..14f5ca19d8a36 100644
--- a/Mathlib/RingTheory/LaurentSeries.lean
+++ b/Mathlib/RingTheory/LaurentSeries.lean
@@ -4,53 +4,68 @@ 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`.
* Embedding of rational functions into Laurent series, provided as a coercion, utilizing
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 `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
-`intValuation_le_iff_coeff_lt_eq_zero`.
+`LaurentSeries.intValuation_le_iff_coeff_lt_eq_zero`.
* The valuation of a Laurent series is the order of the first non-zero coefficient, see
-`valuation_le_iff_coeff_lt_eq_zero`.
+`LaurentSeries.valuation_le_iff_coeff_lt_eq_zero`.
* Every Laurent series of valuation less than `(1 : ℤₘ₀)` comes from a power series, see
-`val_le_one_iff_eq_coe`.
+`LaurentSeries.val_le_one_iff_eq_coe`.
+* The uniform space of `LaurentSeries` over a field is complete, formalized in the instance
+`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
@@ -58,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]))
@@ -76,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]
@@ -128,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
@@ -145,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, ?_, ?_⟩, ?_⟩
@@ -187,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
@@ -198,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,
@@ -235,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:
@@ -297,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]
@@ -345,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]
@@ -377,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⟩
@@ -396,13 +473,12 @@ instance : IsScalarTower F[X] (RatFunc F) (LaurentSeries F) :=
end RatFunc
section AdicValuation
-open scoped DiscreteValuation
+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
@@ -448,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
@@ -464,20 +541,21 @@ end RatFunc
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]
@@ -490,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⟩
@@ -510,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
@@ -538,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
@@ -580,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)
@@ -609,3 +687,169 @@ theorem val_le_one_iff_eq_coe (f : LaurentSeries K) : Valued.v f ≤ (1 : ℤₘ
end LaurentSeries
end AdicValuation
+namespace LaurentSeries
+section Complete
+
+open Filter
+
+open scoped Multiplicative
+
+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 : 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 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
+`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 K⸨X⸩} (hℱ : Cauchy ℱ) : ℤ → K :=
+ let _ : UniformSpace K := ⊥
+ fun d ↦ UniformSpace.DiscreteUnif.cauchyConst rfl <| hℱ.map (uniformContinuous_coeff 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
+
+/- For every Cauchy filter of Laurent series, there is a `N` such that the `n`-th coefficient
+vanishes for all `n ≤ N` and almost all series in the filter. This is an auxiliary lemma used
+to construct the limit of the Cauchy filter as a Laurent series, ensuring that the support of the
+limit is `PWO`.
+The result is true also for more general Hahn Series indexed over a partially ordered group `Γ`
+beyond the special case `Γ = ℤ`, that corresponds to Laurent Series: nevertheless the proof below
+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 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 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 : 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 ↦ ?_⟩
+ rw [hf, sub_zero] at hg
+ exact (valuation_le_iff_coeff_lt_eq_zero K).mp hg
+ · refine ⟨min (f.2.isWF.min (HahnSeries.support_nonempty_iff.mpr hf)) 0 - 1, fun _ hg n hn ↦ ?_⟩
+ rw [eq_coeff_of_valuation_sub_lt K hg (d := 0)]
+ · exact Function.nmem_support.mp fun h ↦
+ f.2.isWF.not_lt_min (HahnSeries.support_nonempty_iff.mpr hf) h
+ <| lt_trans hn <| Int.sub_one_lt_iff.mpr <| min_le_left _ _
+ exact lt_of_lt_of_le hn <| le_of_lt (Int.sub_one_lt_of_le <| min_le_right _ _)
+ use N
+ apply mem_of_superset (inter_mem hS hT)
+ intro g hg
+ have h_prod : (f, g) ∈ entourage := Set.prod_mono (Set.inter_subset_left (t := T))
+ (Set.inter_subset_right (s := S)) |>.trans H <| Set.mem_prod.mpr ⟨hf, hg⟩
+ exact hN g (le_of_lt h_prod)
+
+/- The support of `Cauchy.coeff` has a lower bound. -/
+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ℱ
+ refine ⟨N, fun n hn ↦ Ultrafilter.eq_of_le_pure (hℱ.map (uniformContinuous_coeff n)).1
+ ((principal_singleton _).symm ▸ coeff_tendsto _ _) ?_⟩
+ simp only [pure_zero, nonpos_iff]
+ apply Filter.mem_of_superset hN (fun _ ha ↦ ha _ hn)
+
+/- The support of `Cauchy.coeff` is bounded below -/
+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 `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 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 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 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 K⸨X⸩ := fun d ↦ {f | coeff hℱ d = f.coeff d}
+ have intersec₁ :
+ (⋂ 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 `ℱ`.
+ let ℓ := (exists_lb_coeff_ne hℱ).choose
+ let N := max ℓ D
+ have intersec₂ : ⋂ n ∈ Set.Iio D, φ n ⊇ (⋂ n ∈ Set.Iio ℓ, φ n) ∩ (⋂ n ∈ Set.Icc ℓ N, φ n) := by
+ simp only [Set.mem_Iio, Set.mem_Icc, Set.subset_iInter_iff]
+ intro i hi x hx
+ simp only [Set.mem_inter_iff, Set.mem_iInter, and_imp] at hx
+ by_cases H : i < ℓ
+ exacts [hx.1 _ H, hx.2 _ (le_of_not_lt H) <| le_of_lt <| lt_max_of_lt_right hi]
+ suffices (⋂ n ∈ Set.Iio ℓ, φ n) ∩ (⋂ n ∈ Set.Icc ℓ N, φ n) ∈ ℱ by
+ exact ℱ.sets_of_superset this <| intersec₂.trans intersec₁
+ /- To show that the intersection we have in sight is in `ℱ`, we use that it contains a double
+ intersection (an infinite and a finite one): by general properties of filters, we are reduced
+ to show that both terms are in `ℱ`, which is easy in light of their definition. -/
+ · simp only [Set.mem_Iio, Set.mem_Ico, inter_mem_iff]
+ constructor
+ · have := (exists_lb_coeff_ne hℱ).choose_spec
+ rw [Filter.eventually_iff] at this
+ convert this
+ ext
+ simp only [Set.mem_iInter, Set.mem_setOf_eq]; rfl
+ · rw [biInter_mem (Set.finite_Icc ℓ N)]
+ intro _ _
+ apply coeff_tendsto hℱ
+ simp only [principal_singleton, mem_pure]; rfl
+
+
+open scoped Topology
+
+/- The main result showing that the Cauchy filter tends to the `Cauchy.limit`-/
+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 : 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
+ rw [← WithZero.coe_unzero γ.ne_zero, WithZero.coe_lt_coe, hD₀, neg_neg, ofAdd_sub,
+ ofAdd_toAdd, div_lt_comm, div_self', ← ofAdd_zero, Multiplicative.ofAdd_lt]
+ exact zero_lt_one
+ apply coeff_eventually_equal (D := D) hℱ |>.mono
+ intro _ hf
+ apply lt_of_le_of_lt (valuation_le_iff_coeff_lt_eq_zero K |>.mpr _) hD
+ intro n hn
+ 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 K⸨X⸩ :=
+ ⟨fun hℱ ↦ ⟨Cauchy.limit hℱ, fun _ hS ↦ Cauchy.eventually_mem_nhds hℱ hS⟩⟩
+
+end Complete
+
+end LaurentSeries
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/LittleWedderburn.lean b/Mathlib/RingTheory/LittleWedderburn.lean
index 24f9b1cce5f40..42f44f6d9f529 100644
--- a/Mathlib/RingTheory/LittleWedderburn.lean
+++ b/Mathlib/RingTheory/LittleWedderburn.lean
@@ -48,7 +48,7 @@ private def InductionHyp : Prop :=
namespace InductionHyp
-open FiniteDimensional Polynomial
+open Module Polynomial
variable {D}
diff --git a/Mathlib/RingTheory/LocalProperties.lean b/Mathlib/RingTheory/LocalProperties.lean
deleted file mode 100644
index 47a42f14e2524..0000000000000
--- a/Mathlib/RingTheory/LocalProperties.lean
+++ /dev/null
@@ -1,665 +0,0 @@
-/-
-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.RingTheory.FiniteType
-import Mathlib.RingTheory.Localization.AtPrime
-import Mathlib.RingTheory.Localization.Away.Basic
-import Mathlib.RingTheory.Localization.Integer
-import Mathlib.RingTheory.Localization.Submodule
-import Mathlib.RingTheory.Nilpotent.Lemmas
-import Mathlib.RingTheory.RingHomProperties
-import Mathlib.Data.Set.Subsingleton
-
-/-!
-# Local properties of commutative rings
-
-In this file, we provide the proofs of various local properties.
-
-## Naming Conventions
-
-* `localization_P` : `P` holds for `S⁻¹R` if `P` holds for `R`.
-* `P_of_localization_maximal` : `P` holds for `R` if `P` holds for `Rₘ` for all maximal `m`.
-* `P_of_localization_prime` : `P` holds for `R` if `P` holds for `Rₘ` for all prime `m`.
-* `P_ofLocalizationSpan` : `P` holds for `R` if given a spanning set `{fᵢ}`, `P` holds for all
- `R_{fᵢ}`.
-
-## Main results
-
-The following properties are covered:
-
-* The triviality of an ideal or an element:
- `ideal_eq_bot_of_localization`, `eq_zero_of_localization`
-* `IsReduced` : `localization_isReduced`, `isReduced_of_localization_maximal`.
-* `RingHom.finite`: `localization_finite`, `finite_ofLocalizationSpan`
-* `RingHom.finiteType`: `localization_finiteType`, `finiteType_ofLocalizationSpan`
-
--/
-
-open scoped Pointwise Classical
-
-universe u
-
-variable {R S : Type u} [CommRing R] [CommRing S] (M : Submonoid R)
-variable (N : Submonoid S) (R' S' : Type u) [CommRing R'] [CommRing S'] (f : R →+* S)
-variable [Algebra R R'] [Algebra S S']
-
-section Properties
-
-section CommRing
-
-variable (P : ∀ (R : Type u) [CommRing R], Prop)
-
-/-- A property `P` of comm rings is said to be preserved by localization
- if `P` holds for `M⁻¹R` whenever `P` holds for `R`. -/
-def LocalizationPreserves : Prop :=
- ∀ {R : Type u} [hR : CommRing R] (M : Submonoid R) (S : Type u) [hS : CommRing S] [Algebra R S]
- [IsLocalization M S], @P R hR → @P S hS
-
-/-- A property `P` of comm rings satisfies `OfLocalizationMaximal`
- if `P` holds for `R` whenever `P` holds for `Rₘ` for all maximal ideal `m`. -/
-def OfLocalizationMaximal : Prop :=
- ∀ (R : Type u) [CommRing R],
- (∀ (J : Ideal R) (_ : J.IsMaximal), P (Localization.AtPrime J)) → P R
-
-end CommRing
-
-section RingHom
-
-variable (P : ∀ {R S : Type u} [CommRing R] [CommRing S] (_ : R →+* S), Prop)
-
-/-- A property `P` of ring homs is said to be preserved by localization
- if `P` holds for `M⁻¹R →+* M⁻¹S` whenever `P` holds for `R →+* S`. -/
-def RingHom.LocalizationPreserves :=
- ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (M : Submonoid R) (R' S' : Type u)
- [CommRing R'] [CommRing S'] [Algebra R R'] [Algebra S S'] [IsLocalization M R']
- [IsLocalization (M.map f) S'],
- P f → P (IsLocalization.map S' f (Submonoid.le_comap_map M) : R' →+* S')
-
-/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationFiniteSpan`
-if `P` holds for `R →+* S` whenever there exists a finite set `{ r }` that spans `R` such that
-`P` holds for `Rᵣ →+* Sᵣ`.
-
-Note that this is equivalent to `RingHom.OfLocalizationSpan` via
-`RingHom.ofLocalizationSpan_iff_finite`, but this is easier to prove. -/
-def RingHom.OfLocalizationFiniteSpan :=
- ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (s : Finset R)
- (_ : Ideal.span (s : Set R) = ⊤) (_ : ∀ r : s, P (Localization.awayMap f r)), P f
-
-/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationFiniteSpan`
-if `P` holds for `R →+* S` whenever there exists a set `{ r }` that spans `R` such that
-`P` holds for `Rᵣ →+* Sᵣ`.
-
-Note that this is equivalent to `RingHom.OfLocalizationFiniteSpan` via
-`RingHom.ofLocalizationSpan_iff_finite`, but this has less restrictions when applying. -/
-def RingHom.OfLocalizationSpan :=
- ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (s : Set R) (_ : Ideal.span s = ⊤)
- (_ : ∀ r : s, P (Localization.awayMap f r)), P f
-
-/-- A property `P` of ring homs satisfies `RingHom.HoldsForLocalizationAway`
- if `P` holds for each localization map `R →+* Rᵣ`. -/
-def RingHom.HoldsForLocalizationAway : Prop :=
- ∀ ⦃R : Type u⦄ (S : Type u) [CommRing R] [CommRing S] [Algebra R S] (r : R)
- [IsLocalization.Away r S], P (algebraMap R S)
-
-/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationFiniteSpanTarget`
-if `P` holds for `R →+* S` whenever there exists a finite set `{ r }` that spans `S` such that
-`P` holds for `R →+* Sᵣ`.
-
-Note that this is equivalent to `RingHom.OfLocalizationSpanTarget` via
-`RingHom.ofLocalizationSpanTarget_iff_finite`, but this is easier to prove. -/
-def RingHom.OfLocalizationFiniteSpanTarget : Prop :=
- ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (s : Finset S)
- (_ : Ideal.span (s : Set S) = ⊤)
- (_ : ∀ r : s, P ((algebraMap S (Localization.Away (r : S))).comp f)), P f
-
-/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationSpanTarget`
-if `P` holds for `R →+* S` whenever there exists a set `{ r }` that spans `S` such that
-`P` holds for `R →+* Sᵣ`.
-
-Note that this is equivalent to `RingHom.OfLocalizationFiniteSpanTarget` via
-`RingHom.ofLocalizationSpanTarget_iff_finite`, but this has less restrictions when applying. -/
-def RingHom.OfLocalizationSpanTarget : Prop :=
- ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (s : Set S) (_ : Ideal.span s = ⊤)
- (_ : ∀ r : s, P ((algebraMap S (Localization.Away (r : S))).comp f)), P f
-
-/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationPrime`
-if `P` holds for `R` whenever `P` holds for `Rₘ` for all prime ideals `p`. -/
-def RingHom.OfLocalizationPrime : Prop :=
- ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S),
- (∀ (J : Ideal S) (_ : J.IsPrime), P (Localization.localRingHom _ J f rfl)) → P f
-
-/-- A property of ring homs is local if it is preserved by localizations and compositions, and for
-each `{ r }` that spans `S`, we have `P (R →+* S) ↔ ∀ r, P (R →+* Sᵣ)`. -/
-structure RingHom.PropertyIsLocal : Prop where
- LocalizationPreserves : RingHom.LocalizationPreserves @P
- OfLocalizationSpanTarget : RingHom.OfLocalizationSpanTarget @P
- StableUnderComposition : RingHom.StableUnderComposition @P
- HoldsForLocalizationAway : RingHom.HoldsForLocalizationAway @P
-
-theorem RingHom.ofLocalizationSpan_iff_finite :
- RingHom.OfLocalizationSpan @P ↔ RingHom.OfLocalizationFiniteSpan @P := by
- delta RingHom.OfLocalizationSpan RingHom.OfLocalizationFiniteSpan
- apply forall₅_congr
- -- TODO: Using `refine` here breaks `resetI`.
- intros
- constructor
- · intro h s; exact h s
- · intro h s hs hs'
- obtain ⟨s', h₁, h₂⟩ := (Ideal.span_eq_top_iff_finite s).mp hs
- exact h s' h₂ fun x => hs' ⟨_, h₁ x.prop⟩
-
-theorem RingHom.ofLocalizationSpanTarget_iff_finite :
- RingHom.OfLocalizationSpanTarget @P ↔ RingHom.OfLocalizationFiniteSpanTarget @P := by
- delta RingHom.OfLocalizationSpanTarget RingHom.OfLocalizationFiniteSpanTarget
- apply forall₅_congr
- -- TODO: Using `refine` here breaks `resetI`.
- intros
- constructor
- · intro h s; exact h s
- · intro h s hs hs'
- obtain ⟨s', h₁, h₂⟩ := (Ideal.span_eq_top_iff_finite s).mp hs
- exact h s' h₂ fun x => hs' ⟨_, h₁ x.prop⟩
-
-theorem RingHom.HoldsForLocalizationAway.of_bijective
- (H : RingHom.HoldsForLocalizationAway P) (hf : Function.Bijective f) :
- P f := by
- letI := f.toAlgebra
- have := IsLocalization.at_units (.powers (1 : R)) (by simp)
- have := IsLocalization.isLocalization_of_algEquiv (.powers (1 : R))
- (AlgEquiv.ofBijective (Algebra.ofId R S) hf)
- exact H _ 1
-
-variable {P f R' S'}
-
-theorem RingHom.PropertyIsLocal.respectsIso (hP : RingHom.PropertyIsLocal @P) :
- RingHom.RespectsIso @P := by
- apply hP.StableUnderComposition.respectsIso
- introv
- letI := e.toRingHom.toAlgebra
- -- Porting note: was `apply_with hP.holds_for_localization_away { instances := ff }`
- have : IsLocalization.Away (1 : R) S := by
- apply IsLocalization.away_of_isUnit_of_bijective _ isUnit_one e.bijective
- exact RingHom.PropertyIsLocal.HoldsForLocalizationAway hP S (1 : R)
-
--- Almost all arguments are implicit since this is not intended to use mid-proof.
-theorem RingHom.LocalizationPreserves.away (H : RingHom.LocalizationPreserves @P) (r : R)
- [IsLocalization.Away r R'] [IsLocalization.Away (f r) S'] (hf : P f) :
- P (IsLocalization.Away.map R' S' f r) := by
- have : IsLocalization ((Submonoid.powers r).map f) S' := by rw [Submonoid.map_powers]; assumption
- exact H f (Submonoid.powers r) R' S' hf
-
-theorem RingHom.PropertyIsLocal.ofLocalizationSpan (hP : RingHom.PropertyIsLocal @P) :
- RingHom.OfLocalizationSpan @P := by
- introv R hs hs'
- apply_fun Ideal.map f at hs
- rw [Ideal.map_span, Ideal.map_top] at hs
- apply hP.OfLocalizationSpanTarget _ _ hs
- rintro ⟨_, r, hr, rfl⟩
- convert hP.StableUnderComposition
- _ _ (hP.HoldsForLocalizationAway (Localization.Away r) r) (hs' ⟨r, hr⟩) using 1
- exact (IsLocalization.map_comp _).symm
-
-lemma RingHom.OfLocalizationSpanTarget.ofIsLocalization
- (hP : RingHom.OfLocalizationSpanTarget P) (hP' : RingHom.RespectsIso P)
- {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) (s : Set S) (hs : Ideal.span s = ⊤)
- (hT : ∀ r : s, ∃ (T : Type u) (_ : CommRing T) (_ : Algebra S T)
- (_ : IsLocalization.Away (r : S) T), P ((algebraMap S T).comp f)) : P f := by
- apply hP _ s hs
- intros r
- obtain ⟨T, _, _, _, hT⟩ := hT r
- convert hP'.1 _
- (Localization.algEquiv (R := S) (Submonoid.powers (r : S)) T).symm.toRingEquiv hT
- rw [← RingHom.comp_assoc, RingEquiv.toRingHom_eq_coe, AlgEquiv.toRingEquiv_eq_coe,
- AlgEquiv.toRingEquiv_toRingHom, Localization.coe_algEquiv_symm, IsLocalization.map_comp,
- RingHom.comp_id]
-
-end RingHom
-
-end Properties
-
-section Ideal
-
-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),
- Ideal.map (algebraMap R (Localization.AtPrime P)) I ≤
- Ideal.map (algebraMap R (Localization.AtPrime P)) J) :
- I ≤ J := by
- intro x hx
- suffices J.colon (Ideal.span {x}) = ⊤ by
- simpa using Submodule.mem_colon.mp
- (show (1 : R) ∈ J.colon (Ideal.span {x}) from this.symm ▸ Submodule.mem_top) x
- (Ideal.mem_span_singleton_self x)
- refine Not.imp_symm (J.colon (Ideal.span {x})).exists_le_maximal ?_
- push_neg
- intro P hP le
- obtain ⟨⟨⟨a, ha⟩, ⟨s, hs⟩⟩, eq⟩ :=
- (IsLocalization.mem_map_algebraMap_iff P.primeCompl _).mp (h P hP (Ideal.mem_map_of_mem _ hx))
- rw [← _root_.map_mul, ← sub_eq_zero, ← map_sub] at eq
- obtain ⟨⟨m, hm⟩, eq⟩ := (IsLocalization.map_eq_zero_iff P.primeCompl _ _).mp eq
- refine hs ((hP.isPrime.mem_or_mem (le (Ideal.mem_colon_singleton.mpr ?_))).resolve_right hm)
- simp only [Subtype.coe_mk, mul_sub, sub_eq_zero, mul_comm x s, mul_left_comm] at eq
- simpa only [mul_assoc, eq] using J.mul_mem_left m ha
-
-/-- Let `I J : Ideal R`. If the localization of `I` at each maximal ideal `P` is equal to
-the localization of `J` at `P`, then `I = J`. -/
-theorem Ideal.eq_of_localization_maximal {I J : Ideal R}
- (h : ∀ (P : Ideal R) (_ : P.IsMaximal),
- Ideal.map (algebraMap R (Localization.AtPrime P)) I =
- Ideal.map (algebraMap R (Localization.AtPrime P)) J) :
- I = J :=
- le_antisymm (Ideal.le_of_localization_maximal fun P hP => (h P hP).le)
- (Ideal.le_of_localization_maximal fun P hP => (h P hP).ge)
-
-/-- 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),
- Ideal.map (algebraMap R (Localization.AtPrime J)) I = ⊥) :
- I = ⊥ :=
- Ideal.eq_of_localization_maximal fun P hP => by simpa using h P hP
-
--- TODO: This proof should work for all modules, once we have enough material on submodules of
--- 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),
- IsLocalization.coeSubmodule (Localization.AtPrime J) I = ⊥) :
- I = ⊥ :=
- ideal_eq_bot_of_localization' _ fun P hP =>
- (Ideal.map_eq_bot_iff_le_ker _).mpr fun x hx => by
- rw [RingHom.mem_ker, ← Submodule.mem_bot R, ← h P hP, IsLocalization.mem_coeSubmodule]
- 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) :
- r = 0 := by
- rw [← Ideal.span_singleton_eq_bot]
- apply ideal_eq_bot_of_localization
- intro J hJ
- delta IsLocalization.coeSubmodule
- erw [Submodule.map_span, Submodule.span_eq_bot]
- rintro _ ⟨_, h', rfl⟩
- cases Set.mem_singleton_iff.mpr h'
- exact h J hJ
-
-end Ideal
-
-section Reduced
-
-theorem localization_isReduced : LocalizationPreserves fun R hR => IsReduced R := by
- introv R _ _
- constructor
- rintro x ⟨_ | n, e⟩
- · simpa using congr_arg (· * x) e
- obtain ⟨⟨y, m⟩, hx⟩ := IsLocalization.surj M x
- dsimp only at hx
- let hx' := congr_arg (· ^ n.succ) hx
- simp only [mul_pow, e, zero_mul, ← RingHom.map_pow] at hx'
- rw [← (algebraMap R S).map_zero] at hx'
- obtain ⟨m', hm'⟩ := (IsLocalization.eq_iff_exists M S).mp hx'
- apply_fun (· * (m' : R) ^ n) at hm'
- simp only [mul_assoc, zero_mul, mul_zero] at hm'
- rw [← mul_left_comm, ← pow_succ', ← mul_pow] at hm'
- replace hm' := IsNilpotent.eq_zero ⟨_, hm'.symm⟩
- rw [← (IsLocalization.map_units S m).mul_left_inj, hx, zero_mul,
- IsLocalization.map_eq_zero_iff M]
- exact ⟨m', by rw [← hm', mul_comm]⟩
-
-instance [IsReduced R] : IsReduced (Localization M) :=
- localization_isReduced M _ inferInstance
-
-theorem isReduced_ofLocalizationMaximal : OfLocalizationMaximal fun R hR => IsReduced R := by
- introv R h
- constructor
- intro x hx
- apply eq_zero_of_localization
- intro J hJ
- specialize h J hJ
- exact (hx.map <| algebraMap R <| Localization.AtPrime J).eq_zero
-
-end Reduced
-
-section Surjective
-
-theorem localizationPreserves_surjective :
- RingHom.LocalizationPreserves fun {R S} _ _ f => Function.Surjective f := by
- introv R H x
- obtain ⟨x, ⟨_, s, hs, rfl⟩, rfl⟩ := IsLocalization.mk'_surjective (M.map f) x
- obtain ⟨y, rfl⟩ := H x
- use IsLocalization.mk' R' y ⟨s, hs⟩
- rw [IsLocalization.map_mk']
-
-theorem surjective_ofLocalizationSpan :
- RingHom.OfLocalizationSpan fun {R S} _ _ f => Function.Surjective f := by
- introv R e H
- rw [← Set.range_iff_surjective, Set.eq_univ_iff_forall]
- letI := f.toAlgebra
- intro x
- apply Submodule.mem_of_span_eq_top_of_smul_pow_mem
- (LinearMap.range (Algebra.linearMap R S)) s e
- intro r
- obtain ⟨a, e'⟩ := H r (algebraMap _ _ x)
- obtain ⟨b, ⟨_, n, rfl⟩, rfl⟩ := IsLocalization.mk'_surjective (Submonoid.powers (r : R)) a
- erw [IsLocalization.map_mk'] at e'
- rw [eq_comm, IsLocalization.eq_mk'_iff_mul_eq, Subtype.coe_mk, Subtype.coe_mk, ← map_mul] at e'
- obtain ⟨⟨_, n', rfl⟩, e''⟩ := (IsLocalization.eq_iff_exists (Submonoid.powers (f r)) _).mp e'
- dsimp only at e''
- rw [mul_comm x, ← mul_assoc, ← map_pow, ← map_mul, ← map_mul, ← pow_add] at e''
- exact ⟨n' + n, _, e''.symm⟩
-
-/-- A surjective ring homomorphism `R →+* S` induces a surjective homomorphism `R_{f⁻¹(P)} →+* S_P`
-for every prime ideal `P` of `S`. -/
-theorem surjective_localRingHom_of_surjective (h : Function.Surjective f) (P : Ideal S)
- [P.IsPrime] : Function.Surjective (Localization.localRingHom (P.comap f) P f rfl) :=
- have : IsLocalization (Submonoid.map f (Ideal.comap f P).primeCompl) (Localization.AtPrime P) :=
- (Submonoid.map_comap_eq_of_surjective h P.primeCompl).symm ▸ Localization.isLocalization
- localizationPreserves_surjective _ _ _ _ h
-
-lemma surjective_respectsIso : RingHom.RespectsIso (fun f ↦ Function.Surjective f) := by
- apply RingHom.StableUnderComposition.respectsIso
- · intro R S T _ _ _ f g hf hg
- simp only [RingHom.coe_comp]
- exact Function.Surjective.comp hg hf
- · intro R S _ _ e
- exact EquivLike.surjective e
-
-end Surjective
-
-section Finite
-
-lemma Module.Finite_of_isLocalization (R S Rₚ Sₚ) [CommSemiring R] [CommRing S] [CommRing Rₚ]
- [CommRing Sₚ] [Algebra R S] [Algebra R Rₚ] [Algebra R Sₚ] [Algebra S Sₚ] [Algebra Rₚ Sₚ]
- [IsScalarTower R S Sₚ] [IsScalarTower R Rₚ Sₚ] (M : Submonoid R) [IsLocalization M Rₚ]
- [IsLocalization (Algebra.algebraMapSubmonoid S M) Sₚ] [hRS : Module.Finite R S] :
- Module.Finite Rₚ Sₚ := by
- classical
- have : algebraMap Rₚ Sₚ = IsLocalization.map (T := Algebra.algebraMapSubmonoid S M) Sₚ
- (algebraMap R S) (Submonoid.le_comap_map M) := by
- apply IsLocalization.ringHom_ext M
- simp only [IsLocalization.map_comp, ← IsScalarTower.algebraMap_eq]
- -- We claim that if `S` is generated by `T` as an `R`-module,
- -- then `S'` is generated by `T` as an `R'`-module.
- obtain ⟨T, hT⟩ := hRS
- use T.image (algebraMap S Sₚ)
- rw [eq_top_iff]
- rintro x -
- -- By the hypotheses, for each `x : S'`, we have `x = y / (f r)` for some `y : S` and `r : M`.
- -- Since `S` is generated by `T`, the image of `y` should fall in the span of the image of `T`.
- obtain ⟨y, ⟨_, ⟨r, hr, rfl⟩⟩, rfl⟩ :=
- IsLocalization.mk'_surjective (Algebra.algebraMapSubmonoid S M) x
- rw [IsLocalization.mk'_eq_mul_mk'_one, mul_comm, Finset.coe_image]
- have hy : y ∈ Submodule.span R ↑T := by rw [hT]; trivial
- replace hy : algebraMap S Sₚ y ∈ Submodule.map (IsScalarTower.toAlgHom R S Sₚ).toLinearMap
- (Submodule.span R (T : Set S)) := Submodule.mem_map_of_mem
--- -- Note: #8386 had to specify the value of `f` below
- (f := (IsScalarTower.toAlgHom R S Sₚ).toLinearMap) hy
- rw [Submodule.map_span (IsScalarTower.toAlgHom R S Sₚ).toLinearMap T] at hy
- have H : Submodule.span R (algebraMap S Sₚ '' T) ≤
- (Submodule.span Rₚ (algebraMap S Sₚ '' T)).restrictScalars R := by
- rw [Submodule.span_le]; exact Submodule.subset_span
- -- Now, since `y ∈ span T`, and `(f r)⁻¹ ∈ R'`, `x / (f r)` is in `span T` as well.
- convert (Submodule.span Rₚ (algebraMap S Sₚ '' T)).smul_mem
- (IsLocalization.mk' Rₚ (1 : R) ⟨r, hr⟩) (H hy) using 1
- rw [Algebra.smul_def, this, IsLocalization.map_mk', map_one]
-
-/-- If `S` is a finite `R`-algebra, then `S' = M⁻¹S` is a finite `R' = M⁻¹R`-algebra. -/
-theorem localization_finite : RingHom.LocalizationPreserves @RingHom.Finite := by
- introv R hf
- letI := f.toAlgebra
- letI := ((algebraMap S S').comp f).toAlgebra
- let f' : R' →+* S' := IsLocalization.map S' f (Submonoid.le_comap_map M)
- letI := f'.toAlgebra
- have : IsScalarTower R R' S' := IsScalarTower.of_algebraMap_eq'
- (IsLocalization.map_comp M.le_comap_map).symm
- have : IsScalarTower R S S' := IsScalarTower.of_algebraMap_eq' rfl
- have : IsLocalization (Algebra.algebraMapSubmonoid S M) S' := by
- rwa [Algebra.algebraMapSubmonoid, RingHom.algebraMap_toAlgebra]
- have : Module.Finite R S := hf
- apply Module.Finite_of_isLocalization R S R' S' M
-
-theorem localization_away_map_finite (r : R) [IsLocalization.Away r R']
- [IsLocalization.Away (f r) S'] (hf : f.Finite) : (IsLocalization.Away.map R' S' f r).Finite :=
- localization_finite.away r hf
-
-/-- Let `S` be an `R`-algebra, `M` a submonoid of `R`, and `S' = M⁻¹S`.
-If the image of some `x : S` falls in the span of some finite `s ⊆ S'` over `R`,
-then there exists some `m : M` such that `m • x` falls in the
-span of `IsLocalization.finsetIntegerMultiple _ s` over `R`.
--/
-theorem IsLocalization.smul_mem_finsetIntegerMultiple_span [Algebra R S] [Algebra R S']
- [IsScalarTower R S S'] [IsLocalization (M.map (algebraMap R S)) S'] (x : S) (s : Finset S')
- (hx : algebraMap S S' x ∈ Submodule.span R (s : Set S')) :
- ∃ m : M, m • x ∈
- Submodule.span R
- (IsLocalization.finsetIntegerMultiple (M.map (algebraMap R S)) s : Set S) := by
- let g : S →ₐ[R] S' :=
- AlgHom.mk' (algebraMap S S') fun c x => by simp [Algebra.algebraMap_eq_smul_one]
- -- We first obtain the `y' ∈ M` such that `s' = y' • s` is falls in the image of `S` in `S'`.
- let y := IsLocalization.commonDenomOfFinset (M.map (algebraMap R S)) s
- have hx₁ : (y : S) • (s : Set S') = g '' _ :=
- (IsLocalization.finsetIntegerMultiple_image _ s).symm
- obtain ⟨y', hy', e : algebraMap R S y' = y⟩ := y.prop
- have : algebraMap R S y' • (s : Set S') = y' • (s : Set S') := by
- simp_rw [Algebra.algebraMap_eq_smul_one, smul_assoc, one_smul]
- rw [← e, this] at hx₁
- replace hx₁ := congr_arg (Submodule.span R) hx₁
- rw [Submodule.span_smul] at hx₁
- replace hx : _ ∈ y' • Submodule.span R (s : Set S') := Set.smul_mem_smul_set hx
- rw [hx₁] at hx
- erw [← _root_.map_smul g, ← Submodule.map_span (g : S →ₗ[R] S')] at hx
- -- Since `x` falls in the span of `s` in `S'`, `y' • x : S` falls in the span of `s'` in `S'`.
- -- That is, there exists some `x' : S` in the span of `s'` in `S` and `x' = y' • x` in `S'`.
- -- Thus `a • (y' • x) = a • x' ∈ span s'` in `S` for some `a ∈ M`.
- obtain ⟨x', hx', hx'' : algebraMap _ _ _ = _⟩ := hx
- obtain ⟨⟨_, a, ha₁, rfl⟩, ha₂⟩ :=
- (IsLocalization.eq_iff_exists (M.map (algebraMap R S)) S').mp hx''
- use (⟨a, ha₁⟩ : M) * (⟨y', hy'⟩ : M)
- convert (Submodule.span R
- (IsLocalization.finsetIntegerMultiple (Submonoid.map (algebraMap R S) M) s : Set S)).smul_mem
- a hx' using 1
- convert ha₂.symm using 1
- · rw [Subtype.coe_mk, Submonoid.smul_def, Submonoid.coe_mul, ← smul_smul]
- exact Algebra.smul_def _ _
- · exact Algebra.smul_def _ _
-
-/-- If `M` is an `R' = S⁻¹R` module, and `x ∈ span R' s`,
-then `t • x ∈ span R s` for some `t : S`. -/
-theorem multiple_mem_span_of_mem_localization_span
- {N : Type*} [AddCommMonoid N] [Module R N] [Module R' N]
- [IsScalarTower R R' N] [IsLocalization M R'] (s : Set N) (x : N)
- (hx : x ∈ Submodule.span R' s) : ∃ (t : M), t • x ∈ Submodule.span R s := by
- classical
- obtain ⟨s', hss', hs'⟩ := Submodule.mem_span_finite_of_mem_span hx
- rsuffices ⟨t, ht⟩ : ∃ t : M, t • x ∈ Submodule.span R (s' : Set N)
- · exact ⟨t, Submodule.span_mono hss' ht⟩
- clear hx hss' s
- induction s' using Finset.induction_on generalizing x
- · use 1; simpa using hs'
- rename_i a s _ hs
- simp only [Finset.coe_insert, Finset.image_insert, Finset.coe_image, Subtype.coe_mk,
- Submodule.mem_span_insert] at hs' ⊢
- rcases hs' with ⟨y, z, hz, rfl⟩
- rcases IsLocalization.surj M y with ⟨⟨y', s'⟩, e⟩
- apply congrArg (fun x ↦ x • a) at e
- simp only [algebraMap_smul] at e
- rcases hs _ hz with ⟨t, ht⟩
- refine ⟨t * s', t * y', _, (Submodule.span R (s : Set N)).smul_mem s' ht, ?_⟩
- rw [smul_add, ← smul_smul, mul_comm, ← smul_smul, ← smul_smul, ← e, mul_comm, ← Algebra.smul_def]
- simp
- rfl
-
-/-- If `S` is an `R' = M⁻¹R` algebra, and `x ∈ adjoin R' s`,
-then `t • x ∈ adjoin R s` for some `t : M`. -/
-theorem multiple_mem_adjoin_of_mem_localization_adjoin [Algebra R' S] [Algebra R S]
- [IsScalarTower R R' S] [IsLocalization M R'] (s : Set S) (x : S)
- (hx : x ∈ Algebra.adjoin R' s) : ∃ t : M, t • x ∈ Algebra.adjoin R s := by
- change ∃ t : M, t • x ∈ Subalgebra.toSubmodule (Algebra.adjoin R s)
- change x ∈ Subalgebra.toSubmodule (Algebra.adjoin R' s) at hx
- simp_rw [Algebra.adjoin_eq_span] at hx ⊢
- exact multiple_mem_span_of_mem_localization_span M R' _ _ hx
-
-theorem finite_ofLocalizationSpan : RingHom.OfLocalizationSpan @RingHom.Finite := by
- rw [RingHom.ofLocalizationSpan_iff_finite]
- introv R hs H
- -- We first setup the instances
- letI := f.toAlgebra
- letI := fun r : s => (Localization.awayMap f r).toAlgebra
- have : ∀ r : s,
- IsLocalization ((Submonoid.powers (r : R)).map (algebraMap R S)) (Localization.Away (f r)) :=
- by intro r; rw [Submonoid.map_powers]; exact Localization.isLocalization
- haveI : ∀ r : s, IsScalarTower R (Localization.Away (r : R)) (Localization.Away (f r)) :=
- fun r => IsScalarTower.of_algebraMap_eq'
- (IsLocalization.map_comp (Submonoid.powers (r : R)).le_comap_map).symm
- -- By the hypothesis, we may find a finite generating set for each `Sᵣ`. This set can then be
- -- lifted into `R` by multiplying a sufficiently large power of `r`. I claim that the union of
- -- these generates `S`.
- constructor
- replace H := fun r => (H r).1
- choose s₁ s₂ using H
- let sf := fun x : s => IsLocalization.finsetIntegerMultiple (Submonoid.powers (f x)) (s₁ x)
- use s.attach.biUnion sf
- rw [Submodule.span_attach_biUnion, eq_top_iff]
- -- It suffices to show that `r ^ n • x ∈ span T` for each `r : s`, since `{ r ^ n }` spans `R`.
- -- This then follows from the fact that each `x : R` is a linear combination of the generating set
- -- of `Sᵣ`. By multiplying a sufficiently large power of `r`, we can cancel out the `r`s in the
- -- denominators of both the generating set and the coefficients.
- rintro x -
- apply Submodule.mem_of_span_eq_top_of_smul_pow_mem _ (s : Set R) hs _ _
- intro r
- obtain ⟨⟨_, n₁, rfl⟩, hn₁⟩ :=
- multiple_mem_span_of_mem_localization_span (Submonoid.powers (r : R))
- (Localization.Away (r : R)) (s₁ r : Set (Localization.Away (f r))) (algebraMap S _ x)
- (by rw [s₂ r]; trivial)
- dsimp only at hn₁
- rw [Submonoid.smul_def, Algebra.smul_def, IsScalarTower.algebraMap_apply R S, ← map_mul] at hn₁
- obtain ⟨⟨_, n₂, rfl⟩, hn₂⟩ :=
- IsLocalization.smul_mem_finsetIntegerMultiple_span (Submonoid.powers (r : R))
- (Localization.Away (f r)) _ (s₁ r) hn₁
- rw [Submonoid.smul_def, ← Algebra.smul_def, smul_smul, ← pow_add] at hn₂
- simp_rw [Submonoid.map_powers] at hn₂
- use n₂ + n₁
- exact le_iSup (fun x : s => Submodule.span R (sf x : Set S)) r hn₂
-
-end Finite
-
-section FiniteType
-
-theorem localization_finiteType : RingHom.LocalizationPreserves @RingHom.FiniteType := by
- introv R hf
- -- mirrors the proof of `localization_map_finite`
- letI := f.toAlgebra
- letI := ((algebraMap S S').comp f).toAlgebra
- let f' : R' →+* S' := IsLocalization.map S' f (Submonoid.le_comap_map M)
- letI := f'.toAlgebra
- haveI : IsScalarTower R R' S' :=
- IsScalarTower.of_algebraMap_eq' (IsLocalization.map_comp M.le_comap_map).symm
- let fₐ : S →ₐ[R] S' := AlgHom.mk' (algebraMap S S') fun c x => RingHom.map_mul _ _ _
- obtain ⟨T, hT⟩ := id hf
- use T.image (algebraMap S S')
- rw [eq_top_iff]
- rintro x -
- obtain ⟨y, ⟨_, ⟨r, hr, rfl⟩⟩, rfl⟩ := IsLocalization.mk'_surjective (M.map f) x
- rw [IsLocalization.mk'_eq_mul_mk'_one, mul_comm, Finset.coe_image]
- have hy : y ∈ Algebra.adjoin R (T : Set S) := by rw [hT]; trivial
- replace hy : algebraMap S S' y ∈ (Algebra.adjoin R (T : Set S)).map fₐ :=
- Subalgebra.mem_map.mpr ⟨_, hy, rfl⟩
- rw [fₐ.map_adjoin T] at hy
- have H : Algebra.adjoin R (algebraMap S S' '' T) ≤
- (Algebra.adjoin R' (algebraMap S S' '' T)).restrictScalars R := by
- rw [Algebra.adjoin_le_iff]; exact Algebra.subset_adjoin
- convert (Algebra.adjoin R' (algebraMap S S' '' T)).smul_mem (H hy)
- (IsLocalization.mk' R' (1 : R) ⟨r, hr⟩) using 1
- rw [Algebra.smul_def]
- erw [IsLocalization.map_mk' M.le_comap_map]
- rw [map_one]
-
-theorem localization_away_map_finiteType (r : R) [IsLocalization.Away r R']
- [IsLocalization.Away (f r) S'] (hf : f.FiniteType) :
- (IsLocalization.Away.map R' S' f r).FiniteType :=
- localization_finiteType.away r hf
-
-variable {S'}
-
-/-- Let `S` be an `R`-algebra, `M` a submonoid of `S`, `S' = M⁻¹S`.
-Suppose the image of some `x : S` falls in the adjoin of some finite `s ⊆ S'` over `R`,
-and `A` is an `R`-subalgebra of `S` containing both `M` and the numerators of `s`.
-Then, there exists some `m : M` such that `m • x` falls in `A`.
--/
-theorem IsLocalization.exists_smul_mem_of_mem_adjoin [Algebra R S] [Algebra R S']
- [IsScalarTower R S S'] (M : Submonoid S) [IsLocalization M S'] (x : S) (s : Finset S')
- (A : Subalgebra R S) (hA₁ : (IsLocalization.finsetIntegerMultiple M s : Set S) ⊆ A)
- (hA₂ : M ≤ A.toSubmonoid) (hx : algebraMap S S' x ∈ Algebra.adjoin R (s : Set S')) :
- ∃ m : M, m • x ∈ A := by
- let g : S →ₐ[R] S' := IsScalarTower.toAlgHom R S S'
- let y := IsLocalization.commonDenomOfFinset M s
- have hx₁ : (y : S) • (s : Set S') = g '' _ :=
- (IsLocalization.finsetIntegerMultiple_image _ s).symm
- obtain ⟨n, hn⟩ :=
- Algebra.pow_smul_mem_of_smul_subset_of_mem_adjoin (y : S) (s : Set S') (A.map g)
- (by rw [hx₁]; exact Set.image_subset _ hA₁) hx (Set.mem_image_of_mem _ (hA₂ y.2))
- obtain ⟨x', hx', hx''⟩ := hn n (le_of_eq rfl)
- rw [Algebra.smul_def, ← _root_.map_mul] at hx''
- obtain ⟨a, ha₂⟩ := (IsLocalization.eq_iff_exists M S').mp hx''
- use a * y ^ n
- convert A.mul_mem hx' (hA₂ a.prop) using 1
- rw [Submonoid.smul_def, smul_eq_mul, Submonoid.coe_mul, SubmonoidClass.coe_pow, mul_assoc, ← ha₂,
- mul_comm]
-
-/-- Let `S` be an `R`-algebra, `M` a submonoid of `R`, and `S' = M⁻¹S`.
-If the image of some `x : S` falls in the adjoin of some finite `s ⊆ S'` over `R`,
-then there exists some `m : M` such that `m • x` falls in the
-adjoin of `IsLocalization.finsetIntegerMultiple _ s` over `R`.
--/
-theorem IsLocalization.lift_mem_adjoin_finsetIntegerMultiple [Algebra R S] [Algebra R S']
- [IsScalarTower R S S'] [IsLocalization (M.map (algebraMap R S)) S'] (x : S) (s : Finset S')
- (hx : algebraMap S S' x ∈ Algebra.adjoin R (s : Set S')) :
- ∃ m : M, m • x ∈
- Algebra.adjoin R
- (IsLocalization.finsetIntegerMultiple (M.map (algebraMap R S)) s : Set S) := by
- obtain ⟨⟨_, a, ha, rfl⟩, e⟩ :=
- IsLocalization.exists_smul_mem_of_mem_adjoin (M.map (algebraMap R S)) x s (Algebra.adjoin R _)
- Algebra.subset_adjoin (by rintro _ ⟨a, _, rfl⟩; exact Subalgebra.algebraMap_mem _ a) hx
- refine ⟨⟨a, ha⟩, ?_⟩
- simpa only [Submonoid.smul_def, algebraMap_smul] using e
-
-theorem finiteType_ofLocalizationSpan : RingHom.OfLocalizationSpan @RingHom.FiniteType := by
- rw [RingHom.ofLocalizationSpan_iff_finite]
- introv R hs H
- -- mirrors the proof of `finite_ofLocalizationSpan`
- letI := f.toAlgebra
- letI := fun r : s => (Localization.awayMap f r).toAlgebra
- have : ∀ r : s,
- IsLocalization ((Submonoid.powers (r : R)).map (algebraMap R S)) (Localization.Away (f r)) :=
- by intro r; rw [Submonoid.map_powers]; exact Localization.isLocalization
- haveI : ∀ r : s, IsScalarTower R (Localization.Away (r : R)) (Localization.Away (f r)) :=
- fun r => IsScalarTower.of_algebraMap_eq'
- (IsLocalization.map_comp (Submonoid.powers (r : R)).le_comap_map).symm
- constructor
- replace H := fun r => (H r).1
- choose s₁ s₂ using H
- let sf := fun x : s => IsLocalization.finsetIntegerMultiple (Submonoid.powers (f x)) (s₁ x)
- use s.attach.biUnion sf
- convert (Algebra.adjoin_attach_biUnion (R := R) sf).trans _
- rw [eq_top_iff]
- rintro x -
- apply (⨆ x : s, Algebra.adjoin R (sf x : Set S)).toSubmodule.mem_of_span_eq_top_of_smul_pow_mem
- _ hs _ _
- intro r
- obtain ⟨⟨_, n₁, rfl⟩, hn₁⟩ :=
- multiple_mem_adjoin_of_mem_localization_adjoin (Submonoid.powers (r : R))
- (Localization.Away (r : R)) (s₁ r : Set (Localization.Away (f r)))
- (algebraMap S (Localization.Away (f r)) x) (by rw [s₂ r]; trivial)
- rw [Submonoid.smul_def, Algebra.smul_def, IsScalarTower.algebraMap_apply R S, ← map_mul] at hn₁
- obtain ⟨⟨_, n₂, rfl⟩, hn₂⟩ :=
- IsLocalization.lift_mem_adjoin_finsetIntegerMultiple (Submonoid.powers (r : R)) _ (s₁ r) hn₁
- rw [Submonoid.smul_def, ← Algebra.smul_def, smul_smul, ← pow_add] at hn₂
- simp_rw [Submonoid.map_powers] at hn₂
- use n₂ + n₁
- exact le_iSup (fun x : s => Algebra.adjoin R (sf x : Set S)) r hn₂
-
-end FiniteType
diff --git a/Mathlib/RingTheory/LocalProperties/Basic.lean b/Mathlib/RingTheory/LocalProperties/Basic.lean
new file mode 100644
index 0000000000000..1bc5294a8e5f1
--- /dev/null
+++ b/Mathlib/RingTheory/LocalProperties/Basic.lean
@@ -0,0 +1,374 @@
+/-
+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.RingTheory.Localization.AtPrime
+import Mathlib.RingTheory.Localization.BaseChange
+import Mathlib.RingTheory.Localization.Submodule
+import Mathlib.RingTheory.RingHomProperties
+
+/-!
+# Local properties of commutative rings
+
+In this file, we define local properties in general.
+
+## Naming Conventions
+
+* `localization_P` : `P` holds for `S⁻¹R` if `P` holds for `R`.
+* `P_of_localization_maximal` : `P` holds for `R` if `P` holds for `Rₘ` for all maximal `m`.
+* `P_of_localization_prime` : `P` holds for `R` if `P` holds for `Rₘ` for all prime `m`.
+* `P_ofLocalizationSpan` : `P` holds for `R` if given a spanning set `{fᵢ}`, `P` holds for all
+ `R_{fᵢ}`.
+
+## Main definitions
+
+* `LocalizationPreserves` : A property `P` of comm rings is said to be preserved by localization
+ if `P` holds for `M⁻¹R` whenever `P` holds for `R`.
+* `OfLocalizationMaximal` : A property `P` of comm rings satisfies `OfLocalizationMaximal`
+ if `P` holds for `R` whenever `P` holds for `Rₘ` for all maximal ideal `m`.
+* `RingHom.LocalizationPreserves` : A property `P` of ring homs is said to be preserved by
+ localization if `P` holds for `M⁻¹R →+* M⁻¹S` whenever `P` holds for `R →+* S`.
+* `RingHom.OfLocalizationSpan` : A property `P` of ring homs satisfies
+ `RingHom.OfLocalizationSpan` if `P` holds for `R →+* S` whenever there exists a
+ set `{ r }` that spans `R` such that `P` holds for `Rᵣ →+* Sᵣ`.
+
+## Main results
+
+* The triviality of an ideal or an element:
+ `ideal_eq_bot_of_localization`, `eq_zero_of_localization`
+
+-/
+
+open scoped Pointwise Classical
+
+universe u
+
+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
+
+section CommRing
+
+variable (P : ∀ (R : Type u) [CommRing R], Prop)
+
+/-- A property `P` of comm rings is said to be preserved by localization
+ if `P` holds for `M⁻¹R` whenever `P` holds for `R`. -/
+def LocalizationPreserves : Prop :=
+ ∀ {R : Type u} [hR : CommRing R] (M : Submonoid R) (S : Type u) [hS : CommRing S] [Algebra R S]
+ [IsLocalization M S], @P R hR → @P S hS
+
+/-- A property `P` of comm rings satisfies `OfLocalizationMaximal`
+ if `P` holds for `R` whenever `P` holds for `Rₘ` for all maximal ideal `m`. -/
+def OfLocalizationMaximal : Prop :=
+ ∀ (R : Type u) [CommRing R],
+ (∀ (J : Ideal R) (_ : J.IsMaximal), P (Localization.AtPrime J)) → P R
+
+end CommRing
+
+section RingHom
+
+variable (P : ∀ {R S : Type u} [CommRing R] [CommRing S] (_ : R →+* S), Prop)
+
+/-- A property `P` of ring homs is said to contain identities if `P` holds
+for the identity homomorphism of every ring. -/
+def RingHom.ContainsIdentities := ∀ (R : Type u) [CommRing R], P (RingHom.id R)
+
+/-- A property `P` of ring homs is said to be preserved by localization
+ if `P` holds for `M⁻¹R →+* M⁻¹S` whenever `P` holds for `R →+* S`. -/
+def RingHom.LocalizationPreserves :=
+ ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (M : Submonoid R) (R' S' : Type u)
+ [CommRing R'] [CommRing S'] [Algebra R R'] [Algebra S S'] [IsLocalization M R']
+ [IsLocalization (M.map f) S'],
+ P f → P (IsLocalization.map S' f (Submonoid.le_comap_map M) : R' →+* S')
+
+/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationFiniteSpan`
+if `P` holds for `R →+* S` whenever there exists a finite set `{ r }` that spans `R` such that
+`P` holds for `Rᵣ →+* Sᵣ`.
+
+Note that this is equivalent to `RingHom.OfLocalizationSpan` via
+`RingHom.ofLocalizationSpan_iff_finite`, but this is easier to prove. -/
+def RingHom.OfLocalizationFiniteSpan :=
+ ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (s : Finset R)
+ (_ : Ideal.span (s : Set R) = ⊤) (_ : ∀ r : s, P (Localization.awayMap f r)), P f
+
+/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationFiniteSpan`
+if `P` holds for `R →+* S` whenever there exists a set `{ r }` that spans `R` such that
+`P` holds for `Rᵣ →+* Sᵣ`.
+
+Note that this is equivalent to `RingHom.OfLocalizationFiniteSpan` via
+`RingHom.ofLocalizationSpan_iff_finite`, but this has less restrictions when applying. -/
+def RingHom.OfLocalizationSpan :=
+ ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (s : Set R) (_ : Ideal.span s = ⊤)
+ (_ : ∀ r : s, P (Localization.awayMap f r)), P f
+
+/-- A property `P` of ring homs satisfies `RingHom.HoldsForLocalizationAway`
+ if `P` holds for each localization map `R →+* Rᵣ`. -/
+def RingHom.HoldsForLocalizationAway : Prop :=
+ ∀ ⦃R : Type u⦄ (S : Type u) [CommRing R] [CommRing S] [Algebra R S] (r : R)
+ [IsLocalization.Away r S], P (algebraMap R S)
+
+/-- A property `P` of ring homs satisfies `RingHom.StableUnderCompositionWithLocalizationAway`
+if whenever `P` holds for `f` it also holds for the composition with
+localization maps on the left and on the right. -/
+def RingHom.StableUnderCompositionWithLocalizationAway : Prop :=
+ (∀ ⦃R S : Type u⦄ (T : Type u) [CommRing R] [CommRing S] [CommRing T] [Algebra S T] (s : S)
+ [IsLocalization.Away s T] (f : R →+* S), P f → P ((algebraMap S T).comp f)) ∧
+ ∀ ⦃R : Type u⦄ (S : Type u) ⦃T : Type u⦄ [CommRing R] [CommRing S] [CommRing T] [Algebra R S]
+ (r : R) [IsLocalization.Away r S] (f : S →+* T), P f → P (f.comp (algebraMap R S))
+
+/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationFiniteSpanTarget`
+if `P` holds for `R →+* S` whenever there exists a finite set `{ r }` that spans `S` such that
+`P` holds for `R →+* Sᵣ`.
+
+Note that this is equivalent to `RingHom.OfLocalizationSpanTarget` via
+`RingHom.ofLocalizationSpanTarget_iff_finite`, but this is easier to prove. -/
+def RingHom.OfLocalizationFiniteSpanTarget : Prop :=
+ ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (s : Finset S)
+ (_ : Ideal.span (s : Set S) = ⊤)
+ (_ : ∀ r : s, P ((algebraMap S (Localization.Away (r : S))).comp f)), P f
+
+/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationSpanTarget`
+if `P` holds for `R →+* S` whenever there exists a set `{ r }` that spans `S` such that
+`P` holds for `R →+* Sᵣ`.
+
+Note that this is equivalent to `RingHom.OfLocalizationFiniteSpanTarget` via
+`RingHom.ofLocalizationSpanTarget_iff_finite`, but this has less restrictions when applying. -/
+def RingHom.OfLocalizationSpanTarget : Prop :=
+ ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S) (s : Set S) (_ : Ideal.span s = ⊤)
+ (_ : ∀ r : s, P ((algebraMap S (Localization.Away (r : S))).comp f)), P f
+
+/-- A property `P` of ring homs satisfies `RingHom.OfLocalizationPrime`
+if `P` holds for `R` whenever `P` holds for `Rₘ` for all prime ideals `p`. -/
+def RingHom.OfLocalizationPrime : Prop :=
+ ∀ ⦃R S : Type u⦄ [CommRing R] [CommRing S] (f : R →+* S),
+ (∀ (J : Ideal S) (_ : J.IsPrime), P (Localization.localRingHom _ J f rfl)) → P f
+
+/-- A property of ring homs is local if it is preserved by localizations and compositions, and for
+each `{ r }` that spans `S`, we have `P (R →+* S) ↔ ∀ r, P (R →+* Sᵣ)`. -/
+structure RingHom.PropertyIsLocal : Prop where
+ LocalizationPreserves : RingHom.LocalizationPreserves @P
+ OfLocalizationSpanTarget : RingHom.OfLocalizationSpanTarget @P
+ StableUnderCompositionWithLocalizationAway : RingHom.StableUnderCompositionWithLocalizationAway @P
+
+theorem RingHom.ofLocalizationSpan_iff_finite :
+ RingHom.OfLocalizationSpan @P ↔ RingHom.OfLocalizationFiniteSpan @P := by
+ delta RingHom.OfLocalizationSpan RingHom.OfLocalizationFiniteSpan
+ apply forall₅_congr
+ -- TODO: Using `refine` here breaks `resetI`.
+ intros
+ constructor
+ · intro h s; exact h s
+ · intro h s hs hs'
+ obtain ⟨s', h₁, h₂⟩ := (Ideal.span_eq_top_iff_finite s).mp hs
+ exact h s' h₂ fun x => hs' ⟨_, h₁ x.prop⟩
+
+theorem RingHom.ofLocalizationSpanTarget_iff_finite :
+ RingHom.OfLocalizationSpanTarget @P ↔ RingHom.OfLocalizationFiniteSpanTarget @P := by
+ delta RingHom.OfLocalizationSpanTarget RingHom.OfLocalizationFiniteSpanTarget
+ apply forall₅_congr
+ -- TODO: Using `refine` here breaks `resetI`.
+ intros
+ constructor
+ · intro h s; exact h s
+ · intro h s hs hs'
+ obtain ⟨s', h₁, h₂⟩ := (Ideal.span_eq_top_iff_finite s).mp hs
+ exact h s' h₂ fun x => hs' ⟨_, h₁ x.prop⟩
+
+theorem RingHom.HoldsForLocalizationAway.of_bijective
+ (H : RingHom.HoldsForLocalizationAway P) (hf : Function.Bijective f) :
+ P f := by
+ letI := f.toAlgebra
+ have := IsLocalization.at_units (.powers (1 : R)) (by simp)
+ have := IsLocalization.isLocalization_of_algEquiv (.powers (1 : R))
+ (AlgEquiv.ofBijective (Algebra.ofId R S) hf)
+ exact H _ 1
+
+variable {P f R' S'}
+
+lemma RingHom.StableUnderComposition.stableUnderCompositionWithLocalizationAway
+ (hPc : RingHom.StableUnderComposition P) (hPl : HoldsForLocalizationAway P) :
+ StableUnderCompositionWithLocalizationAway P := by
+ constructor
+ · introv _ hf
+ exact hPc _ _ hf (hPl T s)
+ · introv _ hf
+ exact hPc _ _ (hPl S r) hf
+
+lemma RingHom.HoldsForLocalizationAway.containsIdentities (hPl : HoldsForLocalizationAway P) :
+ ContainsIdentities P := by
+ introv R
+ exact hPl.of_bijective _ _ Function.bijective_id
+
+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.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.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)
+ [IsLocalization.Away r R'] [IsLocalization.Away (f r) S'] (hf : P f) :
+ P (IsLocalization.Away.map R' S' f r) := by
+ have : IsLocalization ((Submonoid.powers r).map f) S' := by rw [Submonoid.map_powers]; assumption
+ exact H f (Submonoid.powers r) R' S' hf
+
+lemma RingHom.PropertyIsLocal.HoldsForLocalizationAway (hP : RingHom.PropertyIsLocal @P)
+ (hPi : ContainsIdentities P) :
+ RingHom.HoldsForLocalizationAway @P := by
+ introv R _
+ have : algebraMap R S = (algebraMap R S).comp (RingHom.id R) := by simp
+ rw [this]
+ apply (hP.StableUnderCompositionWithLocalizationAway).left S r
+ apply hPi
+
+theorem RingHom.PropertyIsLocal.ofLocalizationSpan (hP : RingHom.PropertyIsLocal @P) :
+ RingHom.OfLocalizationSpan @P := by
+ introv R hs hs'
+ apply_fun Ideal.map f at hs
+ rw [Ideal.map_span, Ideal.map_top] at hs
+ apply hP.OfLocalizationSpanTarget _ _ hs
+ rintro ⟨_, r, hr, rfl⟩
+ rw [← IsLocalization.map_comp (M := Submonoid.powers r) (S := Localization.Away r)
+ (T := Submonoid.powers (f r))]
+ · apply hP.StableUnderCompositionWithLocalizationAway.right _ r
+ exact hs' ⟨r, hr⟩
+
+lemma RingHom.OfLocalizationSpanTarget.ofIsLocalization
+ (hP : RingHom.OfLocalizationSpanTarget P) (hP' : RingHom.RespectsIso P)
+ {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) (s : Set S) (hs : Ideal.span s = ⊤)
+ (hT : ∀ r : s, ∃ (T : Type u) (_ : CommRing T) (_ : Algebra S T)
+ (_ : IsLocalization.Away (r : S) T), P ((algebraMap S T).comp f)) : P f := by
+ apply hP _ s hs
+ intros r
+ obtain ⟨T, _, _, _, hT⟩ := hT r
+ convert hP'.1 _
+ (Localization.algEquiv (R := S) (Submonoid.powers (r : S)) T).symm.toRingEquiv hT
+ rw [← RingHom.comp_assoc, RingEquiv.toRingHom_eq_coe, AlgEquiv.toRingEquiv_eq_coe,
+ 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
+
+section Ideal
+
+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) (_ : P.IsMaximal),
+ Ideal.map (algebraMap R (Localization.AtPrime P)) I ≤
+ Ideal.map (algebraMap R (Localization.AtPrime P)) J) :
+ I ≤ J := by
+ intro x hx
+ suffices J.colon (Ideal.span {x}) = ⊤ by
+ simpa using Submodule.mem_colon.mp
+ (show (1 : R) ∈ J.colon (Ideal.span {x}) from this.symm ▸ Submodule.mem_top) x
+ (Ideal.mem_span_singleton_self x)
+ refine Not.imp_symm (J.colon (Ideal.span {x})).exists_le_maximal ?_
+ push_neg
+ intro P hP le
+ obtain ⟨⟨⟨a, ha⟩, ⟨s, hs⟩⟩, eq⟩ :=
+ (IsLocalization.mem_map_algebraMap_iff P.primeCompl _).mp (h P hP (Ideal.mem_map_of_mem _ hx))
+ rw [← _root_.map_mul, ← sub_eq_zero, ← map_sub] at eq
+ obtain ⟨⟨m, hm⟩, eq⟩ := (IsLocalization.map_eq_zero_iff P.primeCompl _ _).mp eq
+ refine hs ((hP.isPrime.mem_or_mem (le (Ideal.mem_colon_singleton.mpr ?_))).resolve_right hm)
+ simp only [Subtype.coe_mk, mul_sub, sub_eq_zero, mul_comm x s, mul_left_comm] at eq
+ simpa only [mul_assoc, eq] using J.mul_mem_left m ha
+
+/-- Let `I J : Ideal R`. If the localization of `I` at each maximal ideal `P` is equal to
+the localization of `J` at `P`, then `I = J`. -/
+theorem Ideal.eq_of_localization_maximal {I J : Ideal R}
+ (h : ∀ (P : Ideal R) (_ : P.IsMaximal),
+ Ideal.map (algebraMap R (Localization.AtPrime P)) I =
+ Ideal.map (algebraMap R (Localization.AtPrime P)) J) :
+ I = J :=
+ le_antisymm (Ideal.le_of_localization_maximal fun P hP => (h P hP).le)
+ (Ideal.le_of_localization_maximal fun P hP => (h P hP).ge)
+
+/-- 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) (_ : 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
+
+-- TODO: This proof should work for all modules, once we have enough material on submodules of
+-- 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) (_ : J.IsMaximal),
+ IsLocalization.coeSubmodule (Localization.AtPrime J) I = ⊥) :
+ I = ⊥ :=
+ ideal_eq_bot_of_localization' _ fun P hP =>
+ (Ideal.map_eq_bot_iff_le_ker _).mpr fun x hx => by
+ rw [RingHom.mem_ker, ← Submodule.mem_bot R, ← h P hP, IsLocalization.mem_coeSubmodule]
+ exact ⟨x, hx, rfl⟩
+
+theorem eq_zero_of_localization (r : R)
+ (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
+ intro J hJ
+ delta IsLocalization.coeSubmodule
+ erw [Submodule.map_span, Submodule.span_eq_bot]
+ rintro _ ⟨_, h', rfl⟩
+ cases Set.mem_singleton_iff.mpr h'
+ exact h J hJ
+
+end Ideal
diff --git a/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean b/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean
new file mode 100644
index 0000000000000..3753f3c70b5be
--- /dev/null
+++ b/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean
@@ -0,0 +1,68 @@
+/-
+Copyright (c) 2024 Yongle Hu. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Yongle Hu
+-/
+import Mathlib.RingTheory.IntegralClosure.IntegrallyClosed
+import Mathlib.RingTheory.LocalProperties.Basic
+import Mathlib.RingTheory.Localization.LocalizationLocalization
+
+/-!
+# `IsIntegrallyClosed` is a local property
+
+In this file, we prove that `IsIntegrallyClosed` is a local property.
+
+## Main results
+
+* `IsIntegrallyClosed.of_localization_maximal` : An integral domain `R` is integral closed
+ if `Rₘ` is integral closed for any maximal ideal `m` of `R`.
+
+## TODO
+
+Prove that `IsIntegrallyClosed` is preserved by localization
+
+-/
+
+open scoped nonZeroDivisors
+
+open Localization Ideal IsLocalization
+
+/-- An integral domain `R` is integral closed if `Rₘ` is integral closed
+ for any maximal ideal `m` of `R`. -/
+theorem IsIntegrallyClosed.of_localization_maximal {R : Type*} [CommRing R] [IsDomain R]
+ (h : ∀ p : Ideal R, p ≠ ⊥ → [p.IsMaximal] → IsIntegrallyClosed (Localization.AtPrime p)) :
+ IsIntegrallyClosed R := by
+ by_cases hf : IsField R
+ · exact hf.toField.instIsIntegrallyClosed
+ apply (isIntegrallyClosed_iff (FractionRing R)).mpr
+ rintro ⟨x⟩ hx
+ let I : Ideal R := span {x.2.1} / span {x.1}
+ have h1 : 1 ∈ I := by
+ apply I.eq_top_iff_one.mp
+ by_contra hn
+ rcases I.exists_le_maximal hn with ⟨p, hpm, hpi⟩
+ have hic := h p (Ring.ne_bot_of_isMaximal_of_not_isField hpm hf)
+ have hxp : IsIntegral (Localization.AtPrime p) (mk x.1 x.2) := hx.tower_top
+ /- `x.1 / x.2.1 ∈ Rₚ` since it is integral over `Rₚ` and `Rₚ` is integrally closed.
+ More precisely, `x.1 / x.2.1 = y.1 / y.2.1` where `y.1, y.2.1 ∈ R` and `y.2.1 ∉ p`. -/
+ rcases (isIntegrallyClosed_iff (FractionRing R)).mp hic hxp with ⟨⟨y⟩, hy⟩
+ /- `y.2.1 ∈ I` since for all `a ∈ Ideal.span {x.1}`, say `a = b * x.1`,
+ we have `y.2 * a = b * x.1 * y.2 = b * y.1 * x.2.1 ∈ Ideal.span {x.2.1}`. -/
+ have hyi : y.2.1 ∈ I := by
+ intro a ha
+ rcases mem_span_singleton'.mp ha with ⟨b, hb⟩
+ apply mem_span_singleton'.mpr ⟨b * y.1, _⟩
+ rw [← hb, ← mul_assoc, mul_comm y.2.1 b, mul_assoc, mul_assoc]
+ exact congrArg (HMul.hMul b) <| (mul_comm y.1 x.2.1).trans <|
+ NoZeroSMulDivisors.algebraMap_injective R (Localization R⁰) <| mk'_eq_iff_eq.mp <|
+ (mk'_eq_algebraMap_mk'_of_submonoid_le _ _ p.primeCompl_le_nonZeroDivisors y.1 y.2).trans
+ <| show algebraMap (Localization.AtPrime p) _ (mk' _ y.1 y.2) = mk' _ x.1 x.2
+ by simpa only [← mk_eq_mk', ← hy] using by rfl
+ -- `y.2.1 ∈ I` implies `y.2.1 ∈ p` since `I ⊆ p`, which contradicts to the choice of `y`.
+ exact y.2.2 (hpi hyi)
+ rcases mem_span_singleton'.mp (h1 x.1 (mem_span_singleton_self x.1)) with ⟨y, hy⟩
+ exact ⟨y, (eq_mk'_of_mul_eq (hy.trans (one_mul x.1))).trans (mk_eq_mk'_apply x.1 x.2).symm⟩
+
+theorem isIntegrallyClosed_ofLocalizationMaximal :
+ OfLocalizationMaximal fun R _ => ([IsDomain R] → IsIntegrallyClosed R) :=
+ fun _ _ h _ ↦ IsIntegrallyClosed.of_localization_maximal fun p _ hpm ↦ h p hpm
diff --git a/Mathlib/RingTheory/LocalProperties/Reduced.lean b/Mathlib/RingTheory/LocalProperties/Reduced.lean
new file mode 100644
index 0000000000000..5a7cb0ef69937
--- /dev/null
+++ b/Mathlib/RingTheory/LocalProperties/Reduced.lean
@@ -0,0 +1,53 @@
+/-
+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.RingTheory.LocalProperties.Basic
+
+/-!
+# `IsReduced` is a local property
+
+In this file, we prove that `IsReduced` is a local property.
+
+## Main results
+
+Let `R` be a commutative ring, `M` be a submonoid of `R`.
+
+* `isReduced_localizationPreserves` : `M⁻¹R` is reduced if `R` is reduced.
+* `isReduced_ofLocalizationMaximal` : `R` is reduced if `Rₘ` is reduced for all maximal ideal `m`.
+
+-/
+
+/-- `M⁻¹R` is reduced if `R` is reduced. -/
+theorem isReduced_localizationPreserves : LocalizationPreserves fun R _ => IsReduced R := by
+ introv R _ _
+ constructor
+ rintro x ⟨_ | n, e⟩
+ · simpa using congr_arg (· * x) e
+ obtain ⟨⟨y, m⟩, hx⟩ := IsLocalization.surj M x
+ dsimp only at hx
+ let hx' := congr_arg (· ^ n.succ) hx
+ simp only [mul_pow, e, zero_mul, ← RingHom.map_pow] at hx'
+ rw [← (algebraMap R S).map_zero] at hx'
+ obtain ⟨m', hm'⟩ := (IsLocalization.eq_iff_exists M S).mp hx'
+ apply_fun (· * (m' : R) ^ n) at hm'
+ simp only [mul_assoc, zero_mul, mul_zero] at hm'
+ rw [← mul_left_comm, ← pow_succ', ← mul_pow] at hm'
+ replace hm' := IsNilpotent.eq_zero ⟨_, hm'.symm⟩
+ rw [← (IsLocalization.map_units S m).mul_left_inj, hx, zero_mul,
+ IsLocalization.map_eq_zero_iff M]
+ exact ⟨m', by rw [← hm', mul_comm]⟩
+
+instance {R : Type*} [CommRing R] (M : Submonoid R) [IsReduced R] : IsReduced (Localization M) :=
+ isReduced_localizationPreserves M _ inferInstance
+
+/-- `R` is reduced if `Rₘ` is reduced for all maximal ideal `m`. -/
+theorem isReduced_ofLocalizationMaximal : OfLocalizationMaximal fun R _ => IsReduced R := by
+ introv R h
+ constructor
+ intro x hx
+ apply eq_zero_of_localization
+ intro J hJ
+ specialize h J hJ
+ exact (hx.map <| algebraMap R <| Localization.AtPrime J).eq_zero
diff --git a/Mathlib/RingTheory/LocalRing/Basic.lean b/Mathlib/RingTheory/LocalRing/Basic.lean
index 8e057c3e33536..a7bb4b615fa7b 100644
--- a/Mathlib/RingTheory/LocalRing/Basic.lean
+++ b/Mathlib/RingTheory/LocalRing/Basic.lean
@@ -63,7 +63,7 @@ theorem isUnit_or_isUnit_of_isUnit_add {a b : R} (h : IsUnit (a + b)) : IsUnit a
apply Or.imp _ _ (isUnit_or_isUnit_of_add_one hu) <;> exact isUnit_of_mul_isUnit_right
theorem nonunits_add {a b : R} (ha : a ∈ nonunits R) (hb : b ∈ nonunits R) : a + b ∈ nonunits R :=
- fun H => not_or_of_not ha hb (isUnit_or_isUnit_of_isUnit_add H)
+ fun H => not_or_intro ha hb (isUnit_or_isUnit_of_isUnit_add H)
end LocalRing
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 06103c98b607e..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
@@ -171,26 +171,28 @@ theorem free_of_maximalIdeal_rTensor_injective [Module.FinitePresentation R M]
refine ⟨?_, this⟩
rw [← LinearMap.ker_eq_bot (M := k ⊗[R] (I →₀ R)) (f := i.baseChange k),
← Submodule.finrank_eq_zero (R := k) (M := k ⊗[R] (I →₀ R)),
- ← Nat.add_right_inj (n := FiniteDimensional.finrank k (LinearMap.range <| i.baseChange k)),
+ ← Nat.add_right_inj (n := Module.finrank k (LinearMap.range <| i.baseChange k)),
LinearMap.finrank_range_add_finrank_ker (V := k ⊗[R] (I →₀ R)),
LinearMap.range_eq_top.mpr this, finrank_top]
- simp only [FiniteDimensional.finrank_tensorProduct, FiniteDimensional.finrank_self,
- FiniteDimensional.finrank_finsupp_self, one_mul, add_zero]
- rw [FiniteDimensional.finrank_eq_card_chooseBasisIndex]
+ simp only [Module.finrank_tensorProduct, Module.finrank_self,
+ Module.finrank_finsupp_self, one_mul, add_zero]
+ rw [Module.finrank_eq_card_chooseBasisIndex]
-- On the other hand, `m ⊗ M → M` injective => `Tor₁(k, M) = 0` => `k ⊗ ker(i) → kᴵ` injective.
- have := @lTensor_injective_of_exact_of_exact_of_rTensor_injective
- (N₁ := LinearMap.ker i) (N₂ := I →₀ R) (N₃ := M)
- (f₁ := (𝔪).subtype) (f₂ := Submodule.mkQ 𝔪) inferInstance inferInstance inferInstance
- inferInstance inferInstance inferInstance
intro x
- apply @this (LinearMap.ker i).subtype i (LinearMap.exact_subtype_mkQ 𝔪)
- (Submodule.mkQ_surjective _) (LinearMap.exact_subtype_ker_map i) hi H
- (Module.Flat.lTensor_preserves_injective_linearMap _ Subtype.val_injective)
- apply hi'.injective
- rw [LinearMap.baseChange_eq_ltensor]
- erw [← LinearMap.comp_apply (i.lTensor k), ← LinearMap.lTensor_comp]
- rw [(LinearMap.exact_subtype_ker_map i).linearMap_comp_eq_zero]
- simp only [LinearMap.lTensor_zero, LinearMap.zero_apply, map_zero]
+ refine lTensor_injective_of_exact_of_exact_of_rTensor_injective
+ (N₁ := LinearMap.ker i) (N₂ := I →₀ R) (N₃ := M)
+ (f₁ := (𝔪).subtype) (f₂ := Submodule.mkQ 𝔪)
+ (g₁ := (LinearMap.ker i).subtype) (g₂ := i) (LinearMap.exact_subtype_mkQ 𝔪)
+ (Submodule.mkQ_surjective _) (LinearMap.exact_subtype_ker_map i) hi H ?_ ?_
+ · apply Module.Flat.lTensor_preserves_injective_linearMap
+ (N := LinearMap.ker i) (N' := I →₀ R)
+ (L := (LinearMap.ker i).subtype)
+ exact Subtype.val_injective
+ · apply hi'.injective
+ rw [LinearMap.baseChange_eq_ltensor]
+ erw [← LinearMap.comp_apply (i.lTensor k), ← LinearMap.lTensor_comp]
+ rw [(LinearMap.exact_subtype_ker_map i).linearMap_comp_eq_zero]
+ simp only [LinearMap.lTensor_zero, LinearMap.zero_apply, map_zero]
-- TODO: Generalise this to finite free modules.
theorem free_of_flat_of_localRing [Module.FinitePresentation R P] [Module.Flat R P] :
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 25391bf0ccb40..5dc19df864940 100644
--- a/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean
+++ b/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean
@@ -3,9 +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, Chris Hughes, Mario Carneiro
-/
+import Mathlib.LinearAlgebra.FiniteDimensional.Defs
import Mathlib.RingTheory.LocalRing.ResidueField.Defs
import Mathlib.RingTheory.LocalRing.RingHom.Basic
-import Mathlib.RingTheory.LocalRing.MaximalIdeal.Basic
/-!
@@ -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. -/
@@ -145,15 +145,46 @@ theorem residue_smul (g : G) (r : R) : residue R (g • r) = g • residue R r :
end MulSemiringAction
+section FiniteDimensional
+
+variable [Algebra R S] [IsLocalHom (algebraMap R S)]
+
+noncomputable instance : Algebra (ResidueField R) (ResidueField S) :=
+ (ResidueField.map (algebraMap R S)).toAlgebra
+
+noncomputable instance : Algebra R (ResidueField S) :=
+ ((ResidueField.map <| algebraMap R S).comp <| residue R).toAlgebra
+
+instance : IsScalarTower R (ResidueField R) (ResidueField S) :=
+ IsScalarTower.of_algebraMap_eq (congrFun rfl)
+
+instance finiteDimensional_of_noetherian [IsNoetherian R S] :
+ FiniteDimensional (ResidueField R) (ResidueField S) := by
+ apply IsNoetherian.iff_fg.mp <|
+ isNoetherian_of_tower R (S := ResidueField R) (M := ResidueField S) _
+ convert isNoetherian_of_surjective S (Ideal.Quotient.mkₐ R (maximalIdeal S)).toLinearMap
+ (LinearMap.range_eq_top.mpr Ideal.Quotient.mk_surjective)
+ exact Algebra.algebra_ext _ _ (fun r => rfl)
+
+-- We want to be able to refer to `hfin`
+set_option linter.unusedVariables false in
+lemma finite_of_finite [IsNoetherian R S] (hfin : Finite (ResidueField R)) :
+ 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 fc9ea8c3bc6a3..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,44 +88,35 @@ 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
- · rintro _ _ ⟨a, ha, rfl⟩
- exact map_nonunit f a ha
- tfae_have 2 → 4
- · exact Set.image_subset_iff.1
- tfae_have 3 ↔ 4
- · exact Ideal.map_le_iff_le_comap
- tfae_have 4 → 1
- · intro h
- constructor
- exact fun x => not_imp_not.1 (@h x)
+ | _, _, ⟨a, ha, rfl⟩ => map_nonunit f a ha
+ tfae_have 2 → 4 := Set.image_subset_iff.1
+ tfae_have 3 ↔ 4 := Ideal.map_le_iff_le_comap
+ tfae_have 4 → 1 := fun h ↦ ⟨fun x => not_imp_not.1 (@h x)⟩
tfae_have 1 → 5
- · intro
- ext
- exact not_iff_not.2 (isUnit_map_iff f _)
- tfae_have 5 → 4
- · exact fun h => le_of_eq h.symm
+ | _ => by ext; exact not_iff_not.2 (isUnit_map_iff f _)
+ tfae_have 5 → 4 := fun h ↦ le_of_eq h.symm
tfae_finish
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)
@@ -142,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/Algebra.lean b/Mathlib/RingTheory/Localization/Algebra.lean
index b92decb0ad796..794c17c9aea4a 100644
--- a/Mathlib/RingTheory/Localization/Algebra.lean
+++ b/Mathlib/RingTheory/Localization/Algebra.lean
@@ -56,7 +56,7 @@ variable (S) in
/-- The canonical linear map from the kernel of `g` to the kernel of its localization. -/
def RingHom.toKerIsLocalization (hy : M ≤ Submonoid.comap g T) :
RingHom.ker g →ₗ[R] RingHom.ker (IsLocalization.map Q g hy : S →+* Q) where
- toFun x := ⟨algebraMap R S x, by simp [RingHom.mem_ker, (RingHom.mem_ker g).mp x.property]⟩
+ toFun x := ⟨algebraMap R S x, by simp [RingHom.mem_ker, RingHom.mem_ker.mp x.property]⟩
map_add' x y := by
simp only [Submodule.coe_add, map_add, AddMemClass.mk_add_mk]
map_smul' a x := by
diff --git a/Mathlib/RingTheory/Localization/AtPrime.lean b/Mathlib/RingTheory/Localization/AtPrime.lean
index 6ff9e226beb8a..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
@@ -89,7 +89,7 @@ theorem AtPrime.localRing [IsLocalization.AtPrime S P] : LocalRing S :=
obtain ⟨t, ht⟩ := IsLocalization.eq.1 hxyz
simp only [mul_one, one_mul, Submonoid.coe_mul, Subtype.coe_mk] at ht
suffices (t : R) * (sx * sy * sz) ∈ P from
- not_or_of_not (mt hp.mem_or_mem <| not_or_of_not sx.2 sy.2) sz.2
+ not_or_intro (mt hp.mem_or_mem <| not_or_intro sx.2 sy.2) sz.2
(hp.mem_or_mem <| (hp.mem_or_mem this).resolve_left t.2)
rw [← ht]
exact
@@ -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 c41d650a75ef4..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
@@ -38,7 +39,8 @@ section Away
variable (x : R)
/-- Given `x : R`, the typeclass `IsLocalization.Away x S` states that `S` is
-isomorphic to the localization of `R` at the submonoid generated by `x`. -/
+isomorphic to the localization of `R` at the submonoid generated by `x`.
+See `IsLocalization.Away.mk` for a specialized constructor. -/
abbrev Away (S : Type*) [CommSemiring S] [Algebra R S] :=
IsLocalization (Submonoid.powers x) S
@@ -68,6 +70,58 @@ lemma sec_spec (s : S) : s * (algebraMap R S) (x ^ (IsLocalization.Away.sec x s)
congr
exact (IsLocalization.sec (Submonoid.powers x) s).2.property.choose_spec
+lemma algebraMap_pow_isUnit (n : ℕ) : IsUnit (algebraMap R S x ^ n) :=
+ IsUnit.pow _ <| IsLocalization.map_units _ (⟨x, 1, by simp⟩ : Submonoid.powers x)
+
+lemma algebraMap_isUnit : IsUnit (algebraMap R S x) :=
+ IsLocalization.map_units _ (⟨x, 1, by simp⟩ : Submonoid.powers x)
+
+lemma surj (z : S) : ∃ (n : ℕ) (a : R), z * algebraMap R S x ^ n = algebraMap R S a := by
+ obtain ⟨⟨a, ⟨-, n, rfl⟩⟩, h⟩ := IsLocalization.surj (Submonoid.powers x) z
+ use n, a
+ simpa using h
+
+lemma exists_of_eq {a b : R} (h : algebraMap R S a = algebraMap R S b) :
+ ∃ (n : ℕ), x ^ n * a = x ^ n * b := by
+ obtain ⟨⟨-, n, rfl⟩, hx⟩ := IsLocalization.exists_of_eq (M := Submonoid.powers x) h
+ use n
+
+/-- Specialized constructor for `IsLocalization.Away`. -/
+lemma mk (r : R) (map_unit : IsUnit (algebraMap R S r))
+ (surj : ∀ s, ∃ (n : ℕ) (a : R), s * algebraMap R S r ^ n = algebraMap R S a)
+ (exists_of_eq : ∀ a b, algebraMap R S a = algebraMap R S b → ∃ (n : ℕ), r ^ n * a = r ^ n * b) :
+ IsLocalization.Away r S where
+ map_units' := by
+ rintro ⟨-, n, rfl⟩
+ simp only [map_pow]
+ exact IsUnit.pow _ map_unit
+ surj' z := by
+ obtain ⟨n, a, hn⟩ := surj z
+ use ⟨a, ⟨r ^ n, n, rfl⟩⟩
+ simpa using hn
+ exists_of_eq {x y} h := by
+ obtain ⟨n, hn⟩ := exists_of_eq x y h
+ use ⟨r ^ n, n, rfl⟩
+
+lemma of_associated {r r' : R} (h : Associated r r') [IsLocalization.Away r S] :
+ IsLocalization.Away r' S := by
+ obtain ⟨u, rfl⟩ := h
+ refine mk _ ?_ (fun s ↦ ?_) (fun a b hab ↦ ?_)
+ · simp [algebraMap_isUnit r, IsUnit.map _ u.isUnit]
+ · obtain ⟨n, a, hn⟩ := surj r s
+ use n, a * u ^ n
+ simp [mul_pow, ← mul_assoc, hn]
+ · obtain ⟨n, hn⟩ := exists_of_eq r hab
+ use n
+ rw [mul_pow, mul_comm (r ^ n), mul_assoc, mul_assoc, hn]
+
+/-- If `r` and `r'` are associated elements of `R`, an `R`-algebra `S`
+is the localization of `R` away from `r` if and only of it is the localization of `R` away from
+`r'`. -/
+lemma iff_of_associated {r r' : R} (h : Associated r r') :
+ IsLocalization.Away r S ↔ IsLocalization.Away r' S :=
+ ⟨fun _ ↦ IsLocalization.Away.of_associated h, fun _ ↦ IsLocalization.Away.of_associated h.symm⟩
+
variable {g : R →+* P}
/-- Given `x : R`, a localization map `F : R →+* S` away from `x`, and a map of `CommSemiring`s
@@ -146,6 +200,65 @@ lemma mapₐ_surjective_of_surjective {f : A →ₐ[R] B} (a : A) [Away a Aₚ]
end Algebra
+/-- Localizing the localization of `R` at `x` at the image of `y` is the same as localizing
+`R` at `y * x`. See `IsLocalization.Away.mul'` for the `x * y` version. -/
+lemma mul (T : Type*) [CommSemiring T] [Algebra S T]
+ [Algebra R T] [IsScalarTower R S T] (x y : R)
+ [IsLocalization.Away x S] [IsLocalization.Away (algebraMap R S y) T] :
+ IsLocalization.Away (y * x) T := by
+ refine mk _ ?_ (fun z ↦ ?_) (fun a b h ↦ ?_)
+ · simp only [map_mul, IsUnit.mul_iff, IsScalarTower.algebraMap_apply R S T]
+ exact ⟨algebraMap_isUnit _, IsUnit.map _ (algebraMap_isUnit x)⟩
+ · obtain ⟨m, p, hpq⟩ := surj (algebraMap R S y) z
+ obtain ⟨n, a, hab⟩ := surj x p
+ use m + n, a * x ^ m * y ^ n
+ simp only [mul_pow, pow_add, map_pow, map_mul, ← mul_assoc, hpq,
+ IsScalarTower.algebraMap_apply R S T, ← hab]
+ ring
+ · repeat rw [IsScalarTower.algebraMap_apply R S T] at h
+ obtain ⟨n, hn⟩ := exists_of_eq (algebraMap R S y) h
+ simp only [← map_pow, ← map_mul, ← map_mul] at hn
+ obtain ⟨m, hm⟩ := exists_of_eq x hn
+ use n + m
+ convert_to y ^ m * x ^ n * (x ^ m * (y ^ n * a)) = y ^ m * x ^ n * (x ^ m * (y ^ n * b))
+ · ring
+ · ring
+ · rw [hm]
+
+/-- Localizing the localization of `R` at `x` at the image of `y` is the same as localizing
+`R` at `x * y`. See `IsLocalization.Away.mul` for the `y * x` version. -/
+lemma mul' (T : Type*) [CommSemiring T] [Algebra S T] [Algebra R T] [IsScalarTower R S T] (x y : R)
+ [IsLocalization.Away x S] [IsLocalization.Away (algebraMap R S y) T] :
+ 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₁]
+ [CommSemiring S₂] [CommSemiring T] [Algebra R S₁] [Algebra R S₂] [Algebra R T] [Algebra S₁ T]
+ [Algebra S₂ T] [IsScalarTower R S₁ T] [IsScalarTower R S₂ T] (x y : R)
+ [IsLocalization.Away x S₁] [IsLocalization.Away y S₂]
+ [IsLocalization.Away (algebraMap R S₂ x) T] :
+ IsLocalization.Away (algebraMap R S₁ y) T := by
+ haveI : IsLocalization (Algebra.algebraMapSubmonoid S₂ (Submonoid.powers x)) T := by
+ simp only [Algebra.algebraMapSubmonoid, Submonoid.map_powers]
+ infer_instance
+ convert IsLocalization.commutes S₁ S₂ T (Submonoid.powers x) (Submonoid.powers y)
+ ext x
+ simp [Algebra.algebraMapSubmonoid]
+
end Away
end Away
@@ -175,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/Away/Lemmas.lean b/Mathlib/RingTheory/Localization/Away/Lemmas.lean
new file mode 100644
index 0000000000000..640763c874cbe
--- /dev/null
+++ b/Mathlib/RingTheory/Localization/Away/Lemmas.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.RingTheory.Localization.Away.Basic
+import Mathlib.RingTheory.Localization.Submodule
+
+/-!
+# More lemmas on localization away
+
+This file contains lemmas on localization away from an element requiring more imports.
+
+-/
+
+variable {R : Type*} [CommRing R]
+
+namespace IsLocalization
+
+namespace Away
+
+/-- Given a set `s` in a ring `R` and for every `t : s` a set `p t` of fractions in
+a localization of `R` at `t`, this is the function sending a pair `(t, y)`, with
+`t : s` and `y : t a`, to `t` multiplied with a numerator of `y`. The range
+of this function spans the unit ideal, if `s` and every `p t` do. -/
+noncomputable def mulNumerator (s : Set R)
+ {Rₜ : s → Type*} [∀ t, CommRing (Rₜ t)] [∀ t, Algebra R (Rₜ t)]
+ [∀ t, IsLocalization.Away t.val (Rₜ t)]
+ (p : (t : s) → Set (Rₜ t)) (x : (t : s) × p t) : R :=
+ x.1 * (IsLocalization.Away.sec x.1.1 x.2.1).1
+
+lemma span_range_mulNumerator_eq_top {s : Set R}
+ (hsone : Ideal.span s = ⊤) {Rₜ : s → Type*} [∀ t, CommRing (Rₜ t)] [∀ t, Algebra R (Rₜ t)]
+ [∀ t, IsLocalization.Away t.val (Rₜ t)]
+ {p : (t : s) → Set (Rₜ t)} (htone : ∀ (r : s), Ideal.span (p r) = ⊤) :
+ Ideal.span (Set.range (IsLocalization.Away.mulNumerator s p)) = ⊤ := by
+ rw [← Ideal.radical_eq_top, eq_top_iff, ← hsone, Ideal.span_le]
+ intro a ha
+ haveI : IsLocalization (Submonoid.powers a) (Rₜ ⟨a, ha⟩) :=
+ inferInstanceAs <| IsLocalization.Away (⟨a, ha⟩ : s).val (Rₜ ⟨a, ha⟩)
+ have h₁ : Ideal.span (p ⟨a, ha⟩) ≤ Ideal.span
+ (algebraMap R (Rₜ ⟨a, ha⟩) '' Set.range (IsLocalization.Away.mulNumerator s p)) := by
+ rw [Ideal.span_le]
+ intro x hx
+ rw [SetLike.mem_coe, IsLocalization.mem_span_map (Submonoid.powers a)]
+ refine ⟨a * (IsLocalization.Away.sec a x).1, Ideal.subset_span ⟨⟨⟨a, ha⟩, ⟨x, hx⟩⟩, rfl⟩, ?_⟩
+ use ⟨a ^ ((IsLocalization.Away.sec a x).2 + 1), _, rfl⟩
+ rw [IsLocalization.eq_mk'_iff_mul_eq, map_pow, map_mul, ← map_pow, pow_add, map_mul,
+ ← mul_assoc, IsLocalization.Away.sec_spec a x, mul_comm, pow_one]
+ have h₂ : IsLocalization.mk' (Rₜ ⟨a, ha⟩) 1 (1 : Submonoid.powers a) ∈ Ideal.span
+ (algebraMap R (Rₜ ⟨a, ha⟩) ''
+ (Set.range <| IsLocalization.Away.mulNumerator s p)) := by
+ rw [IsLocalization.mk'_one]
+ apply h₁
+ simp [htone]
+ rw [IsLocalization.mem_span_map (Submonoid.powers a)] at h₂
+ obtain ⟨y, hy, ⟨-, m, rfl⟩, hyz⟩ := h₂
+ rw [IsLocalization.eq] at hyz
+ obtain ⟨⟨-, n, rfl⟩, hc⟩ := hyz
+ simp only [← mul_assoc, OneMemClass.coe_one, one_mul, mul_one] at hc
+ use n + m
+ simpa [pow_add, hc] using Ideal.mul_mem_left _ _ hy
+
+end Away
+
+end IsLocalization
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 ec5333ad7be07..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,222 +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 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]
@@ -311,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) :=
@@ -510,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]
@@ -675,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
@@ -693,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)
@@ -718,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
@@ -766,64 +187,51 @@ 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`. -/
+lemma commutes (S₁ S₂ T : Type*) [CommSemiring S₁]
+ [CommSemiring S₂] [CommSemiring T] [Algebra R S₁] [Algebra R S₂] [Algebra R T] [Algebra S₁ T]
+ [Algebra S₂ T] [IsScalarTower R S₁ T] [IsScalarTower R S₂ T] (M₁ M₂ : Submonoid R)
+ [IsLocalization M₁ S₁] [IsLocalization M₂ S₂]
+ [IsLocalization (Algebra.algebraMapSubmonoid S₂ M₁) T] :
+ IsLocalization (Algebra.algebraMapSubmonoid S₁ M₂) T where
+ map_units' := by
+ rintro ⟨m, ⟨a, ha, rfl⟩⟩
+ rw [← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply R S₂ T]
+ exact IsUnit.map _ (IsLocalization.map_units' ⟨a, ha⟩)
+ surj' a := by
+ obtain ⟨⟨y, -, m, hm, rfl⟩, hy⟩ := surj (M := Algebra.algebraMapSubmonoid S₂ M₁) a
+ rw [← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply R S₁ T] at hy
+ obtain ⟨⟨z, n, hn⟩, hz⟩ := IsLocalization.surj (M := M₂) y
+ have hunit : IsUnit (algebraMap R S₁ m) := map_units' ⟨m, hm⟩
+ use ⟨algebraMap R S₁ z * hunit.unit⁻¹, ⟨algebraMap R S₁ n, n, hn, rfl⟩⟩
+ rw [map_mul, ← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply R S₂ T]
+ conv_rhs => rw [← IsScalarTower.algebraMap_apply]
+ rw [IsScalarTower.algebraMap_apply R S₂ T, ← hz, map_mul, ← hy]
+ convert_to _ = a * (algebraMap S₂ T) ((algebraMap R S₂) n) *
+ (algebraMap S₁ T) (((algebraMap R S₁) m) * hunit.unit⁻¹.val)
+ · rw [map_mul]
+ ring
+ simp
+ exists_of_eq {x y} hxy := by
+ obtain ⟨r, s, d, hr, hs⟩ := IsLocalization.surj₂ M₁ S₁ x y
+ apply_fun (· * algebraMap S₁ T (algebraMap R S₁ d)) at hxy
+ simp_rw [← map_mul, hr, hs, ← IsScalarTower.algebraMap_apply,
+ IsScalarTower.algebraMap_apply R S₂ T] at hxy
+ obtain ⟨⟨-, c, hmc, rfl⟩, hc⟩ := exists_of_eq (M := Algebra.algebraMapSubmonoid S₂ M₁) hxy
+ simp_rw [← map_mul] at hc
+ obtain ⟨a, ha⟩ := IsLocalization.exists_of_eq (M := M₂) hc
+ use ⟨algebraMap R S₁ a, a, a.property, rfl⟩
+ apply (map_units S₁ d).mul_right_cancel
+ rw [mul_assoc, hr, mul_assoc, hs]
+ apply (map_units S₁ ⟨c, hmc⟩).mul_right_cancel
+ rw [← map_mul, ← map_mul, mul_assoc, mul_comm _ c, ha, map_mul, map_mul]
+ ring
end IsLocalization
@@ -831,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 := ℕ) _
@@ -909,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!]
@@ -924,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' _ _
@@ -957,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 := ℤ) _
@@ -971,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. -/
@@ -1056,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 e14b622040c88..4998718519d38 100644
--- a/Mathlib/RingTheory/Localization/Finiteness.lean
+++ b/Mathlib/RingTheory/Localization/Finiteness.lean
@@ -5,7 +5,7 @@ Authors: Christian Merten
-/
import Mathlib.Algebra.Module.LocalizedModuleIntegers
import Mathlib.RingTheory.Localization.Algebra
-import Mathlib.RingTheory.LocalProperties
+import Mathlib.RingTheory.RingHom.Finite
/-!
@@ -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 1960bbcd7e01d..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,13 +128,13 @@ 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)
- ⟨IsFractionRing.injective R K, h⟩).toMulEquiv.isField (IsFractionRing.toField R).toIsField
+ ⟨IsFractionRing.injective R K, h⟩).toMulEquiv.isField _ (IsFractionRing.toField R).toIsField
mpr h :=
letI := h.toField
(IsLocalization.atUnits R _ (S := 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 bc2b5cc8d572a..62db6f2a12761 100644
--- a/Mathlib/RingTheory/Localization/LocalizationLocalization.lean
+++ b/Mathlib/RingTheory/Localization/LocalizationLocalization.lean
@@ -183,6 +183,11 @@ noncomputable instance (x : Ideal R) [H : x.IsPrime] [IsDomain R] :
rw [mem_nonZeroDivisors_iff_ne_zero]
exact fun h => ha (h.symm ▸ x.zero_mem))
+instance {R : Type*} [CommRing R] [IsDomain R] (p : Ideal R) [p.IsPrime] :
+ IsScalarTower R (Localization.AtPrime p) (FractionRing R) :=
+ localization_isScalarTower_of_submonoid_le (Localization.AtPrime p) (FractionRing R)
+ p.primeCompl (nonZeroDivisors R) p.primeCompl_le_nonZeroDivisors
+
/-- If `M ≤ N` are submonoids of `R`, then `N⁻¹S` is also the localization of `M⁻¹S` at `N`. -/
theorem isLocalization_of_submonoid_le (M N : Submonoid R) (h : M ≤ N) [IsLocalization M S]
[IsLocalization N T] [Algebra S T] [IsScalarTower R S T] :
@@ -226,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
@@ -235,6 +240,11 @@ theorem isLocalization_of_is_exists_mul_mem (M N : Submonoid R) [IsLocalization
rw [IsLocalization.eq_iff_exists M]
exact fun ⟨x, hx⟩ => ⟨⟨_, h x.prop⟩, hx⟩ }
+theorem mk'_eq_algebraMap_mk'_of_submonoid_le {M N : Submonoid R} (h : M ≤ N) [IsLocalization M S]
+ [IsLocalization N T] [Algebra S T] [IsScalarTower R S T] (x : R) (y : {a : R // a ∈ M}) :
+ mk' T x ⟨y.1, h y.2⟩ = algebraMap S T (mk' S x y) :=
+ mk'_eq_iff_eq_mul.mpr (by simp only [IsScalarTower.algebraMap_apply R S T, ← map_mul, mk'_spec])
+
end LocalizationLocalization
end IsLocalization
@@ -276,4 +286,9 @@ theorem isFractionRing_of_isDomain_of_isLocalization [IsDomain R] (S T : Type*)
rw [← (algebraMap R S).map_one, ← @mk'_one R _ M, @comm _ Eq, mk'_eq_zero_iff]
exact ⟨⟨x, hx⟩, by simp [hx']⟩
+instance {R : Type*} [CommRing R] [IsDomain R] (p : Ideal R) [p.IsPrime] :
+ IsFractionRing (Localization.AtPrime p) (FractionRing R) :=
+ IsFractionRing.isFractionRing_of_isDomain_of_isLocalization p.primeCompl
+ (Localization.AtPrime p) (FractionRing R)
+
end IsFractionRing
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 8525a367e4fcf..0750d23424344 100644
--- a/Mathlib/RingTheory/MatrixAlgebra.lean
+++ b/Mathlib/RingTheory/MatrixAlgebra.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Eric Wieser
+Authors: Kim Morrison, Eric Wieser
-/
import Mathlib.Data.Matrix.Basis
import Mathlib.RingTheory.TensorProduct.Basic
@@ -96,16 +96,14 @@ theorem invFun_algebraMap (M : Matrix n n R) : invFun R A n (M.map (algebraMap R
simp only [Algebra.algebraMap_eq_smul_one, smul_tmul, ← tmul_sum, mul_boole]
congr
conv_rhs => rw [matrix_eq_sum_stdBasisMatrix M]
- convert Finset.sum_product (β := Matrix n n R); simp
+ 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]
- convert Finset.sum_product (β := Matrix n n A)
+ 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 effafa7779249..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_of_not (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/Ideal.lean b/Mathlib/RingTheory/MvPolynomial/Ideal.lean
index 25562372ca086..de669fd310c46 100644
--- a/Mathlib/RingTheory/MvPolynomial/Ideal.lean
+++ b/Mathlib/RingTheory/MvPolynomial/Ideal.lean
@@ -37,7 +37,7 @@ theorem mem_ideal_span_monomial_image_iff_dvd {x : MvPolynomial σ R} {s : Set (
x ∈ Ideal.span ((fun s => monomial s (1 : R)) '' s) ↔
∀ xi ∈ x.support, ∃ si ∈ s, monomial si 1 ∣ monomial xi (x.coeff xi) := by
refine mem_ideal_span_monomial_image.trans (forall₂_congr fun xi hxi => ?_)
- simp_rw [monomial_dvd_monomial, one_dvd, and_true_iff, mem_support_iff.mp hxi, false_or_iff]
+ simp_rw [monomial_dvd_monomial, one_dvd, and_true, mem_support_iff.mp hxi, false_or]
/-- `x` is in a monomial ideal generated by variables `X` iff every element of its support
has a component in `s`. -/
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.lean b/Mathlib/RingTheory/MvPolynomial/Symmetric/Defs.lean
similarity index 95%
rename from Mathlib/RingTheory/MvPolynomial/Symmetric.lean
rename to Mathlib/RingTheory/MvPolynomial/Symmetric/Defs.lean
index 691265878f204..093790197e63a 100644
--- a/Mathlib/RingTheory/MvPolynomial/Symmetric.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
new file mode 100644
index 0000000000000..b822840d8c9ce
--- /dev/null
+++ b/Mathlib/RingTheory/MvPolynomial/Symmetric/FundamentalTheorem.lean
@@ -0,0 +1,342 @@
+/-
+Copyright (c) 2023 Junyan Xu. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Junyan Xu
+-/
+import Mathlib.RingTheory.MvPolynomial.Symmetric.Defs
+import Mathlib.RingTheory.MvPolynomial.Tower
+import Mathlib.Data.Finsupp.Notation
+import Mathlib.Data.Finsupp.WellFounded
+
+/-!
+# The Fundamental Theorem of Symmetric Polynomials
+
+In a polynomial ring in `n` variables over a commutative ring, the subalgebra of symmetric
+polynomials is freely generated by the first `n` elementary symmetric polynomials (excluding
+the 0th, which is simply 1). This is expressed as an isomorphism
+`MvPolynomial.esymmAlgEquiv` between `MvPolynomial (Fin n) R` and
+the symmetric subalgebra of any polynomial ring `MvPolynomial σ R` with `#σ = n`.
+The forward map is called `MvPolynomial.esymmAlgHom`.
+
+## Proof strategy
+
+We follow the alternative proof on the Wikipedia page
+https://en.wikipedia.org/wiki/Elementary_symmetric_polynomial#Alternative_proof
+It suffices to show `esymmAlgHom` is both injective and surjective.
+
+Endow the Fintype `σ` with a linear order and endow the (monic) monomials in the polynomial ring
+`MvPolynomial σ R` with the lexicographic order on `σ →₀ ℕ`, which is a well order.
+Then any nonzero polynomial `p : MvPolynomial σ R` has a largest nonzero monomial
+(`AddMonoidAlgebra.supDegree toLex p`) and the corresponding coefficient is
+`AddMonoidAlgebra.leadingCoeff toLex p`. If `p` is symmetric, any permutation of a nonzero monomial
+in `p` must also be a nonzero monomial in `p`, so the largest nonzero monomial must be antitone
+as a function `σ → ℕ` (`MvPolynomial.IsSymmetric.antitone_supDegree`). We can then construct a
+monomial in `MvPolynomial (Fin n) R` whose image under `esymmAlgHom` has the same `supDegree` and
+`leadingCoeff` as `p`: `MvPolynomial.supDegree_esymmAlgHomMonomial` says that the `supDegree` of
+the image is given by `Fin.accumulate`, and `Fin.accumulate_invAccumulate` says that
+`Fin.invAccumulate` is inverse to `Fin.accumulate` for antitone monomials.
+If we subtract the image from `p`, we are left with a symmetric polynomial of
+lower `supDegree`, which we may assume to be in the image by induction,
+thanks to the well-orderedness of `Lex (σ →₀ ℕ)`; the surjectivity of `esymmAlgHom`
+follows. For injectivity, just notice that the images of different monic monomials in
+`MvPolynomial (Fin n) R` have different `supDegree` (`Fin.accumulate_injective`), so if there is
+at least one nonzero monomial, the images cannot all cancel out
+(`AddMonoidAlgebra.sum_ne_zero_of_injOn_supDegree`).
+
+We actually only define `Fin.accumulate` in the case `σ := Fin m` rather than an arbitrary Fintype
+with a linear order; we show that `esymmAlgHom` is in fact surjective whenever `m ≤ n` and
+injective whenever `n ≤ m`, and then transfer the results to any Fintype `σ`. See
+`MvPolynomial.injective_esymmAlgHom` and `MvPolynomial.esymmAlgHom_surjective`.
+
+-/
+
+variable {σ τ R : Type*} {n m k : ℕ}
+
+open AddMonoidAlgebra Finset
+
+namespace Fin
+
+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 : 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`. -/
+def invAccumulate (n m : ℕ) (s : Fin m → ℕ) (i : Fin n) : ℕ :=
+ (if hi : i < m then s ⟨i, hi⟩ else 0) - (if hi : i + 1 < m then s ⟨i + 1, hi⟩ else 0)
+
+lemma accumulate_rec {i n m : ℕ} (hin : i < n) (him : i + 1 < m) (t : Fin n → ℕ) :
+ accumulate n m t ⟨i, Nat.lt_of_succ_lt him⟩ = t ⟨i, hin⟩ + accumulate n m t ⟨i + 1, him⟩ := by
+ simp_rw [accumulate_apply]
+ convert (add_sum_erase _ _ _).symm
+ · ext
+ rw [mem_erase]
+ simp_rw [mem_filter, mem_univ, true_and, i.succ_le_iff, lt_iff_le_and_ne]
+ rw [and_comm, ne_comm, ← Fin.val_ne_iff]
+ · exact mem_filter.2 ⟨mem_univ _, le_rfl⟩
+
+lemma accumulate_last {i n m : ℕ} (hin : i < n) (hmi : m = i + 1) (t : Fin n → ℕ)
+ (ht : ∀ j : Fin n, m ≤ j → t j = 0) :
+ accumulate n m t ⟨i, i.lt_succ_self.trans_eq hmi.symm⟩ = t ⟨i, hin⟩ := by
+ rw [accumulate_apply]
+ apply sum_eq_single_of_mem
+ · rw [mem_filter]; exact ⟨mem_univ _, le_rfl⟩
+ refine fun j hij hji ↦ ht j ?_
+ simp_rw [mem_filter, mem_univ, true_and] at hij
+ exact hmi.trans_le (hij.lt_of_ne (Fin.val_ne_iff.2 hji).symm).nat_succ_le
+
+lemma accumulate_injective {n m} (hnm : n ≤ m) : Function.Injective (accumulate n m) := by
+ refine fun t s he ↦ funext fun i ↦ ?_
+ obtain h|h := lt_or_le (i.1 + 1) m
+ · have := accumulate_rec i.2 h s
+ rwa [← he, accumulate_rec i.2 h t, add_right_cancel_iff] at this
+ · have := h.antisymm (i.2.nat_succ_le.trans hnm)
+ rw [← accumulate_last i.2 this t, ← accumulate_last i.2 this s, he]
+ iterate 2 { intro j hj; exact ((j.2.trans_le hnm).not_le hj).elim }
+
+lemma accumulate_invAccumulate {n m} (hmn : m ≤ n) {s : Fin m → ℕ} (hs : Antitone s) :
+ accumulate n m (invAccumulate n m s) = s := funext <| fun ⟨i, hi⟩ ↦ by
+ have := Nat.le_sub_one_of_lt hi
+ revert hi
+ refine Nat.decreasingInduction' (fun i hi _ ih him ↦ ?_) this fun hm ↦ ?_
+ · rw [← Nat.pred_eq_sub_one, Nat.lt_pred_iff, Nat.succ_eq_add_one] at hi
+ rw [accumulate_rec (him.trans_le hmn) hi, ih hi, invAccumulate, dif_pos him, dif_pos hi]
+ simp only
+ exact Nat.sub_add_cancel (hs i.le_succ)
+ · have := (Nat.sub_one_add_one <| Nat.not_eq_zero_of_lt hm).symm
+ rw [accumulate_last (hm.trans_le hmn) this, invAccumulate, dif_pos hm, dif_neg this.not_gt,
+ Nat.sub_zero]
+ intro j hj
+ rw [invAccumulate, dif_neg hj.not_lt, Nat.zero_sub]
+
+end accumulate
+
+end Fin
+
+namespace MvPolynomial
+
+open Fin
+
+section CommSemiring
+
+variable [CommSemiring R] [Fintype σ] [Fintype τ]
+
+variable (σ R n) in
+/-- The `R`-algebra homomorphism from $R[x_1,\dots,x_n]$ to the symmetric subalgebra of
+ $R[\{x_i \mid i ∈ σ\}]$ sending $x_i$ to the $i$-th elementary symmetric polynomial. -/
+noncomputable def esymmAlgHom :
+ MvPolynomial (Fin n) R →ₐ[R] symmetricSubalgebra σ R :=
+ aeval (fun i ↦ ⟨esymm σ R (i + 1), esymm_isSymmetric σ R _⟩)
+
+lemma esymmAlgHom_apply (p : MvPolynomial (Fin n) R) :
+ (esymmAlgHom σ R n p).val = aeval (fun i : Fin n ↦ esymm σ R (i + 1)) p :=
+ (Subalgebra.mvPolynomial_aeval_coe _ _ _).symm
+
+lemma rename_esymmAlgHom (e : σ ≃ τ) :
+ (renameSymmetricSubalgebra e).toAlgHom.comp (esymmAlgHom σ R n) = esymmAlgHom τ R n := by
+ ext i : 2
+ simp_rw [AlgHom.comp_apply, esymmAlgHom, aeval_X, AlgEquiv.toAlgHom_eq_coe, AlgHom.coe_coe,
+ renameSymmetricSubalgebra_apply_coe, rename_esymm]
+
+variable (σ) in
+/-- The image of a monomial under `esymmAlgHom`. -/
+noncomputable def esymmAlgHomMonomial (t : Fin n →₀ ℕ) (r : R) :
+ MvPolynomial σ R := (esymmAlgHom σ R n <| monomial t r).val
+
+variable {i : Fin n} {r : R}
+
+lemma isSymmetric_esymmAlgHomMonomial (t : Fin n →₀ ℕ) (r : R) :
+ (esymmAlgHomMonomial σ t r).IsSymmetric := (esymmAlgHom _ _ _ _).2
+
+lemma esymmAlgHomMonomial_single :
+ esymmAlgHomMonomial σ (Finsupp.single i k) r = C r * esymm σ R (i + 1) ^ k := by
+ rw [esymmAlgHomMonomial, esymmAlgHom_apply, aeval_monomial, algebraMap_eq,
+ Finsupp.prod_single_index]
+ exact pow_zero _
+
+lemma esymmAlgHomMonomial_single_one :
+ esymmAlgHomMonomial σ (Finsupp.single i k) 1 = esymm σ R (i + 1) ^ k := by
+ rw [esymmAlgHomMonomial_single, map_one, one_mul]
+
+lemma esymmAlgHomMonomial_add {t s : Fin n →₀ ℕ} :
+ esymmAlgHomMonomial σ (t + s) r = esymmAlgHomMonomial σ t r * esymmAlgHomMonomial σ s 1 := by
+ simp_rw [esymmAlgHomMonomial, esymmAlgHom_apply, ← map_mul, monomial_mul, mul_one]
+
+lemma esymmAlgHom_zero : esymmAlgHomMonomial σ (0 : Fin n →₀ ℕ) r = C r := by
+ rw [esymmAlgHomMonomial, monomial_zero', esymmAlgHom_apply, aeval_C, algebraMap_eq]
+
+private lemma supDegree_monic_esymm [Nontrivial R] {i : ℕ} (him : i < m) :
+ supDegree toLex (esymm (Fin m) R (i + 1)) =
+ toLex (Finsupp.indicator (Iic ⟨i, him⟩) fun _ _ ↦ 1) ∧
+ Monic toLex (esymm (Fin m) R (i + 1)) := by
+ have := supDegree_leadingCoeff_sum_eq (D := toLex) (s := univ.powersetCard (i + 1))
+ (i := Iic (⟨i, him⟩ : Fin m)) ?_ (f := fun s ↦ monomial (∑ j in s, fun₀ | j => 1) (1 : R)) ?_
+ · rwa [← esymm_eq_sum_monomial, ← Finsupp.indicator_eq_sum_single, ← single_eq_monomial,
+ 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 = #(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]
+ rw [ne_comm, Ne, ← subset_iff_eq_of_card_le ht'.le, not_subset] at hne
+ simp_rw [← mem_sdiff] at hne
+ have hkm := mem_sdiff.1 (min'_mem _ hne)
+ refine ⟨min' _ hne, fun k hk ↦ ?_, ?_⟩
+ all_goals simp only [Pi.toLex_apply, ofLex_toLex, Finsupp.indicator_apply]
+ · have hki := mem_Iic.2 (hk.le.trans <| mem_Iic.1 hkm.1)
+ rw [dif_pos hki, dif_pos]
+ by_contra h
+ exact lt_irrefl k <| ((lt_min'_iff _ _).1 hk) _ <| mem_sdiff.2 ⟨hki, h⟩
+ · rw [dif_neg hkm.2, dif_pos hkm.1]; exact Nat.zero_lt_one
+
+lemma supDegree_esymm [Nontrivial R] (him : i < m) :
+ ofLex (supDegree toLex <| esymm (Fin m) R (i + 1)) = accumulate n m (Finsupp.single i 1) := by
+ rw [(supDegree_monic_esymm him).1, ofLex_toLex]
+ ext j
+ simp_rw [Finsupp.indicator_apply, dite_eq_ite, mem_Iic, accumulate_apply, Finsupp.single_apply,
+ sum_ite_eq, mem_filter, mem_univ, true_and, Fin.le_def]
+
+lemma monic_esymm {i : ℕ} (him : i ≤ m) : Monic toLex (esymm (Fin m) R i) := by
+ cases i with
+ | zero =>
+ rw [esymm_zero]
+ exact monic_one toLex.injective
+ | succ i =>
+ nontriviality R
+ exact (supDegree_monic_esymm him).2
+
+lemma leadingCoeff_esymmAlgHomMonomial (t : Fin n →₀ ℕ) (hnm : n ≤ m) :
+ leadingCoeff toLex (esymmAlgHomMonomial (Fin m) t r) = r := by
+ induction t using Finsupp.induction₂ with
+ | h0 => rw [esymmAlgHom_zero, leadingCoeff_toLex_C]
+ | ha i _ _ _ _ ih =>
+ rw [esymmAlgHomMonomial_add, esymmAlgHomMonomial_single_one,
+ ((monic_esymm <| i.2.trans_le hnm).pow toLex_add toLex.injective).leadingCoeff_mul_eq_left,
+ ih]
+ exacts [toLex.injective, toLex_add]
+
+lemma supDegree_esymmAlgHomMonomial (hr : r ≠ 0) (t : Fin n →₀ ℕ) (hnm : n ≤ m) :
+ ofLex (supDegree toLex <| esymmAlgHomMonomial (Fin m) t r) = accumulate n m t := by
+ nontriviality R
+ induction t using Finsupp.induction₂ with
+ | h0 => simp_rw [esymmAlgHom_zero, supDegree_toLex_C, ofLex_zero, Finsupp.coe_zero, map_zero]
+ | ha i _ _ _ _ ih =>
+ have := i.2.trans_le hnm
+ rw [esymmAlgHomMonomial_add, esymmAlgHomMonomial_single_one,
+ Monic.supDegree_mul_of_ne_zero_left toLex.injective toLex_add, ofLex_add, Finsupp.coe_add,
+ ih, Finsupp.coe_add, map_add, Monic.supDegree_pow rfl toLex_add toLex.injective, ofLex_smul,
+ Finsupp.coe_smul, supDegree_esymm this, ← map_nsmul, ← Finsupp.coe_smul,
+ Finsupp.smul_single, nsmul_one, Nat.cast_id]
+ · exact monic_esymm this
+ · exact (monic_esymm this).pow toLex_add toLex.injective
+ · rwa [Ne, ← leadingCoeff_eq_zero toLex.injective, leadingCoeff_esymmAlgHomMonomial _ hnm]
+
+omit [Fintype σ] in
+lemma IsSymmetric.antitone_supDegree [LinearOrder σ] {p : MvPolynomial σ R} (hp : p.IsSymmetric) :
+ Antitone ↑(ofLex <| p.supDegree toLex) := by
+ obtain rfl | h0 := eq_or_ne p 0
+ · rw [supDegree_zero, Finsupp.bot_eq_zero]
+ exact Pi.zero_mono
+ rw [Antitone]
+ by_contra! h
+ obtain ⟨i, j, hle, hlt⟩ := h
+ apply (le_sup (s := p.support) (f := toLex) _).not_lt
+ pick_goal 3
+ · rw [← hp (Equiv.swap i j), mem_support_iff, coeff_rename_mapDomain _ (Equiv.injective _)]
+ rw [Ne, ← leadingCoeff_eq_zero toLex.injective, leadingCoeff_toLex] at h0
+ assumption
+ refine ⟨i, fun k hk ↦ ?_, ?_⟩
+ all_goals dsimp only [Pi.toLex_apply, ofLex_toLex]
+ · conv_rhs => rw [← Equiv.swap_apply_of_ne_of_ne hk.ne (hk.trans_le hle).ne]
+ rw [Finsupp.mapDomain_apply (Equiv.injective _), supDegree]; rfl
+ · apply hlt.trans_eq
+ simp_rw [Finsupp.mapDomain_equiv_apply, Equiv.symm_swap, Equiv.swap_apply_left]
+
+end CommSemiring
+
+section CommRing
+
+variable (R)
+variable [Fintype σ] [CommRing R]
+
+open AddMonoidAlgebra
+
+/- Also holds for a cancellative CommSemiring. -/
+lemma esymmAlgHom_fin_injective (h : n ≤ m) :
+ Function.Injective (esymmAlgHom (Fin m) R n) := by
+ rw [injective_iff_map_eq_zero]
+ refine fun p ↦ (fun hp ↦ ?_).mtr
+ rw [p.as_sum, map_sum (esymmAlgHom (Fin m) R n), ← Subalgebra.coe_eq_zero,
+ AddSubmonoidClass.coe_finset_sum]
+ refine sum_ne_zero_of_injOn_supDegree (D := toLex) (support_eq_empty.not.2 hp) (fun t ht ↦ ?_)
+ (fun t ht s hs he ↦ DFunLike.ext' <| accumulate_injective h ?_)
+ · rw [← esymmAlgHomMonomial, Ne, ← leadingCoeff_eq_zero toLex.injective,
+ leadingCoeff_esymmAlgHomMonomial t h]
+ rwa [mem_support_iff] at ht
+ rw [mem_coe, mem_support_iff] at ht hs
+ dsimp only [Function.comp] at he
+ rwa [← esymmAlgHomMonomial, ← esymmAlgHomMonomial, ← ofLex_inj, DFunLike.ext'_iff,
+ supDegree_esymmAlgHomMonomial ht t h, supDegree_esymmAlgHomMonomial hs s h] at he
+
+lemma esymmAlgHom_injective (hn : n ≤ Fintype.card σ) :
+ Function.Injective (esymmAlgHom σ R n) := by
+ rw [← rename_esymmAlgHom (Fintype.equivFin σ).symm, AlgHom.coe_comp]
+ exact (AlgEquiv.injective _).comp (esymmAlgHom_fin_injective R hn)
+
+lemma esymmAlgHom_fin_bijective (n : ℕ) :
+ Function.Bijective (esymmAlgHom (Fin n) R n) := by
+ use esymmAlgHom_fin_injective R le_rfl
+ rintro ⟨p, hp⟩
+ rw [← AlgHom.mem_range]
+ obtain rfl | h0 := eq_or_ne p 0
+ · exact Subalgebra.zero_mem _
+ induction' he : p.supDegree toLex using WellFoundedLT.induction with t ih generalizing p; subst he
+ let t := Finsupp.equivFunOnFinite.symm (invAccumulate n n <| ↑(ofLex <| p.supDegree toLex))
+ have hd :
+ (esymmAlgHomMonomial _ t <| p.leadingCoeff toLex).supDegree toLex = p.supDegree toLex := by
+ rw [← ofLex_inj, DFunLike.ext'_iff, supDegree_esymmAlgHomMonomial _ _ le_rfl]
+ · exact accumulate_invAccumulate le_rfl hp.antitone_supDegree
+ · rwa [Ne, leadingCoeff_eq_zero toLex.injective]
+ obtain he | hne := eq_or_ne p (esymmAlgHomMonomial _ t <| p.leadingCoeff toLex)
+ · convert AlgHom.mem_range_self _ (monomial t <| p.leadingCoeff toLex)
+ have := (supDegree_sub_lt_of_leadingCoeff_eq toLex.injective hd.symm ?_).resolve_right hne
+ · specialize ih _ this _ (Subalgebra.sub_mem _ hp <| isSymmetric_esymmAlgHomMonomial _ _) _ rfl
+ · rwa [sub_ne_zero]
+ convert ← Subalgebra.add_mem _ ih ⟨monomial t (p.leadingCoeff toLex), rfl⟩
+ apply sub_add_cancel p
+ · rw [leadingCoeff_esymmAlgHomMonomial t le_rfl]
+
+lemma esymmAlgHom_fin_surjective (h : m ≤ n) :
+ Function.Surjective (esymmAlgHom (Fin m) R n) := by
+ intro p
+ obtain ⟨q, rfl⟩ := (esymmAlgHom_fin_bijective R m).2 p
+ rw [← AlgHom.mem_range]
+ induction q using MvPolynomial.induction_on with
+ | h_C r => rw [← algebraMap_eq, AlgHom.commutes]; apply Subalgebra.algebraMap_mem
+ | h_add p q hp hq => rw [map_add]; exact Subalgebra.add_mem _ hp hq
+ | h_X p i hp =>
+ rw [map_mul]
+ apply Subalgebra.mul_mem _ hp
+ rw [AlgHom.mem_range]
+ refine ⟨X ⟨i, i.2.trans_le h⟩, ?_⟩
+ simp_rw [esymmAlgHom, aeval_X]
+
+lemma esymmAlgHom_surjective (hn : Fintype.card σ ≤ n) :
+ Function.Surjective (esymmAlgHom σ R n) := by
+ rw [← rename_esymmAlgHom (Fintype.equivFin σ).symm, AlgHom.coe_comp]
+ exact (AlgEquiv.surjective _).comp (esymmAlgHom_fin_surjective R hn)
+
+/-- If the cardinality of `σ` is `n`, then `esymmAlgHom σ R n` is an isomorphism. -/
+@[simps! apply]
+noncomputable def esymmAlgEquiv (hn : Fintype.card σ = n) :
+ MvPolynomial (Fin n) R ≃ₐ[R] symmetricSubalgebra σ R :=
+ AlgEquiv.ofBijective (esymmAlgHom σ R n)
+ ⟨esymmAlgHom_injective R hn.ge, esymmAlgHom_surjective R hn.le⟩
+
+end CommRing
+
+end MvPolynomial
diff --git a/Mathlib/RingTheory/MvPolynomial/NewtonIdentities.lean b/Mathlib/RingTheory/MvPolynomial/Symmetric/NewtonIdentities.lean
similarity index 81%
rename from Mathlib/RingTheory/MvPolynomial/NewtonIdentities.lean
rename to Mathlib/RingTheory/MvPolynomial/Symmetric/NewtonIdentities.lean
index 5d1767881cad0..802d25319935b 100644
--- a/Mathlib/RingTheory/MvPolynomial/NewtonIdentities.lean
+++ b/Mathlib/RingTheory/MvPolynomial/Symmetric/NewtonIdentities.lean
@@ -8,7 +8,7 @@ import Mathlib.Algebra.MvPolynomial.CommRing
import Mathlib.Algebra.MvPolynomial.Rename
import Mathlib.Data.Finset.Card
import Mathlib.Data.Fintype.Basic
-import Mathlib.RingTheory.MvPolynomial.Symmetric
+import Mathlib.RingTheory.MvPolynomial.Symmetric.Defs
/-!
# Newton's Identities
@@ -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/Tower.lean b/Mathlib/RingTheory/MvPolynomial/Tower.lean
index 95f6fb384851e..77228738a64aa 100644
--- a/Mathlib/RingTheory/MvPolynomial/Tower.lean
+++ b/Mathlib/RingTheory/MvPolynomial/Tower.lean
@@ -52,7 +52,7 @@ theorem aeval_algebraMap_apply (x : σ → A) (p : MvPolynomial σ R) :
theorem aeval_algebraMap_eq_zero_iff [NoZeroSMulDivisors A B] [Nontrivial B] (x : σ → A)
(p : MvPolynomial σ R) : aeval (algebraMap A B ∘ x) p = 0 ↔ aeval x p = 0 := by
rw [aeval_algebraMap_apply, Algebra.algebraMap_eq_smul_one, smul_eq_zero,
- iff_false_intro (one_ne_zero' B), or_false_iff]
+ iff_false_intro (one_ne_zero' B), or_false]
theorem aeval_algebraMap_eq_zero_iff_of_injective {x : σ → A} {p : MvPolynomial σ R}
(h : Function.Injective (algebraMap A B)) :
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 8e2b9f0fb7e79..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,
@@ -730,7 +726,7 @@ instance [Nonempty σ] [Nontrivial R] : Nontrivial (Subalgebra R (MvPowerSeries
rw [Ne, SetLike.ext_iff, not_forall]
inhabit σ
refine ⟨X default, ?_⟩
- simp only [Algebra.mem_bot, not_exists, Set.mem_range, iff_true_iff, Algebra.mem_top]
+ simp only [Algebra.mem_bot, not_exists, Set.mem_range, iff_true, Algebra.mem_top]
intro x
rw [MvPowerSeries.ext_iff, not_forall]
refine ⟨Finsupp.single default 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/MvPowerSeries/LexOrder.lean b/Mathlib/RingTheory/MvPowerSeries/LexOrder.lean
new file mode 100644
index 0000000000000..13ecad6b47dce
--- /dev/null
+++ b/Mathlib/RingTheory/MvPowerSeries/LexOrder.lean
@@ -0,0 +1,186 @@
+/-
+Copyright (c) 2024 Antoine Chambert-Loir. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Antoine Chambert-Loir
+-/
+
+import Mathlib.RingTheory.MvPowerSeries.Basic
+import Mathlib.Data.Finsupp.WellFounded
+
+/-! LexOrder of multivariate power series
+
+Given an ordering of `σ` such that `WellOrderGT σ`,
+the lexicographic order on `σ →₀ ℕ` is a well ordering,
+which can be used to define a natural valuation `lexOrder` on the ring `MvPowerSeries σ R`:
+the smallest exponent in the support.
+
+-/
+
+namespace MvPowerSeries
+
+variable {σ R : Type*}
+variable [Semiring R]
+
+section LexOrder
+
+open Finsupp
+variable [LinearOrder σ] [WellFoundedGT σ]
+
+/-- The lex order on multivariate power series. -/
+noncomputable def lexOrder (φ : MvPowerSeries σ R) : (WithTop (Lex (σ →₀ ℕ))) := by
+ classical
+ exact if h : φ = 0 then ⊤ else by
+ have ne : Set.Nonempty (toLex '' φ.support) := by
+ simp only [Set.image_nonempty, Function.support_nonempty_iff, ne_eq, h, not_false_eq_true]
+ apply WithTop.some
+ apply WellFounded.min _ (toLex '' φ.support) ne
+ · exact Finsupp.instLTLex.lt
+ · exact wellFounded_lt
+
+theorem lexOrder_def_of_ne_zero {φ : MvPowerSeries σ R} (hφ : φ ≠ 0) :
+ ∃ (ne : Set.Nonempty (toLex '' φ.support)),
+ lexOrder φ = WithTop.some ((@wellFounded_lt (Lex (σ →₀ ℕ))
+ (instLTLex) (Lex.wellFoundedLT)).min (toLex '' φ.support) ne) := by
+ suffices ne : Set.Nonempty (toLex '' φ.support) by
+ use ne
+ unfold lexOrder
+ simp only [dif_neg hφ]
+ simp only [Set.image_nonempty, Function.support_nonempty_iff, ne_eq, hφ, not_false_eq_true]
+
+@[simp]
+theorem lexOrder_eq_top_iff_eq_zero (φ : MvPowerSeries σ R) :
+ lexOrder φ = ⊤ ↔ φ = 0 := by
+ unfold lexOrder
+ split_ifs with h
+ · simp only [h]
+ · simp only [h, WithTop.coe_ne_top]
+
+theorem lexOrder_zero : lexOrder (0 : MvPowerSeries σ R) = ⊤ := by
+ unfold lexOrder
+ rw [dif_pos rfl]
+
+theorem exists_finsupp_eq_lexOrder_of_ne_zero {φ : MvPowerSeries σ R} (hφ : φ ≠ 0) :
+ ∃ (d : σ →₀ ℕ), lexOrder φ = toLex d := by
+ simp only [ne_eq, ← lexOrder_eq_top_iff_eq_zero, WithTop.ne_top_iff_exists] at hφ
+ obtain ⟨p, hp⟩ := hφ
+ exact ⟨ofLex p, by simp only [toLex_ofLex, hp]⟩
+
+theorem coeff_ne_zero_of_lexOrder {φ : MvPowerSeries σ R} {d : σ →₀ ℕ}
+ (h : toLex d = lexOrder φ) : coeff R d φ ≠ 0 := by
+ have hφ : φ ≠ 0 := by
+ simp only [ne_eq, ← lexOrder_eq_top_iff_eq_zero, ← h, WithTop.coe_ne_top, not_false_eq_true]
+ have hφ' := lexOrder_def_of_ne_zero hφ
+ rcases hφ' with ⟨ne, hφ'⟩
+ simp only [← h, WithTop.coe_eq_coe] at hφ'
+ suffices toLex d ∈ toLex '' φ.support by
+ simp only [Set.mem_image_equiv, toLex_symm_eq, ofLex_toLex, Function.mem_support, ne_eq] at this
+ apply this
+ rw [hφ']
+ apply WellFounded.min_mem
+
+theorem coeff_eq_zero_of_lt_lexOrder {φ : MvPowerSeries σ R} {d : σ →₀ ℕ}
+ (h : toLex d < lexOrder φ) : coeff R d φ = 0 := by
+ by_cases hφ : φ = 0
+ · simp only [hφ, map_zero]
+ · rcases lexOrder_def_of_ne_zero hφ with ⟨ne, hφ'⟩
+ rw [hφ', WithTop.coe_lt_coe] at h
+ by_contra h'
+ exact WellFounded.not_lt_min _ (toLex '' φ.support) ne (Set.mem_image_equiv.mpr h') h
+
+theorem lexOrder_le_of_coeff_ne_zero {φ : MvPowerSeries σ R} {d : σ →₀ ℕ}
+ (h : coeff R d φ ≠ 0) : lexOrder φ ≤ toLex d := by
+ rw [← not_lt]
+ intro h'
+ exact h (coeff_eq_zero_of_lt_lexOrder h')
+
+theorem le_lexOrder_iff {φ : MvPowerSeries σ R} {w : WithTop (Lex (σ →₀ ℕ))} :
+ w ≤ lexOrder φ ↔ (∀ (d : σ →₀ ℕ) (_ : toLex d < w), coeff R d φ = 0) := by
+ constructor
+ · intro h d hd
+ apply coeff_eq_zero_of_lt_lexOrder
+ exact lt_of_lt_of_le hd h
+ · intro h
+ rw [← not_lt]
+ intro h'
+ have hφ : φ ≠ 0 := by
+ rw [ne_eq, ← lexOrder_eq_top_iff_eq_zero]
+ exact ne_top_of_lt h'
+ obtain ⟨d, hd⟩ := exists_finsupp_eq_lexOrder_of_ne_zero hφ
+ refine coeff_ne_zero_of_lexOrder hd.symm (h d ?_)
+ rwa [← hd]
+
+theorem min_lexOrder_le {φ ψ : MvPowerSeries σ R} :
+ min (lexOrder φ) (lexOrder ψ) ≤ lexOrder (φ + ψ) := by
+ rw [le_lexOrder_iff]
+ intro d hd
+ simp only [lt_min_iff] at hd
+ rw [map_add, coeff_eq_zero_of_lt_lexOrder hd.1, coeff_eq_zero_of_lt_lexOrder hd.2, add_zero]
+
+theorem coeff_mul_of_add_lexOrder {φ ψ : MvPowerSeries σ R}
+ {p q : σ →₀ ℕ} (hp : lexOrder φ = toLex p) (hq : lexOrder ψ = toLex q) :
+ coeff R (p + q) (φ * ψ) = coeff R p φ * coeff R q ψ := by
+ rw [coeff_mul]
+ apply Finset.sum_eq_single (⟨p, q⟩ : (σ →₀ ℕ) × (σ →₀ ℕ))
+ · rintro ⟨u, v⟩ h h'
+ simp only [Finset.mem_antidiagonal] at h
+ simp only
+ by_cases hu : toLex u < toLex p
+ · rw [coeff_eq_zero_of_lt_lexOrder (R := R) (d := u), zero_mul]
+ simp only [hp, WithTop.coe_lt_coe, hu]
+ · rw [coeff_eq_zero_of_lt_lexOrder (d := v), mul_zero]
+ simp only [hq, WithTop.coe_lt_coe, ← not_le]
+ simp only [not_lt] at hu
+ intro hv
+ simp only [WithTop.coe_le_coe] at hv
+ apply h'
+ simp only [Prod.mk.injEq]
+ constructor
+ · apply toLex.injective
+ apply Or.resolve_right (eq_or_gt_of_le hu)
+ intro hu'
+ exact not_le.mpr (add_lt_add_of_lt_of_le hu' hv) (le_of_eq h)
+ · apply toLex.injective
+ apply Or.resolve_right (eq_or_gt_of_le hv)
+ intro hv'
+ exact not_le.mpr (add_lt_add_of_le_of_lt hu hv') (le_of_eq h)
+ · intro h
+ simp only [Finset.mem_antidiagonal, not_true_eq_false] at h
+
+theorem le_lexOrder_mul (φ ψ : MvPowerSeries σ R) :
+ lexOrder φ + lexOrder ψ ≤ lexOrder (φ * ψ) := by
+ rw [le_lexOrder_iff]
+ intro d hd
+ rw [coeff_mul]
+ apply Finset.sum_eq_zero
+ rintro ⟨u, v⟩ h
+ simp only [Finset.mem_antidiagonal] at h
+ simp only
+ suffices toLex u < lexOrder φ ∨ toLex v < lexOrder ψ by
+ rcases this with (hu | hv)
+ · rw [coeff_eq_zero_of_lt_lexOrder hu, zero_mul]
+ · rw [coeff_eq_zero_of_lt_lexOrder hv, mul_zero]
+ rw [or_iff_not_imp_left, not_lt, ← not_le]
+ intro hu hv
+ rw [← not_le] at hd
+ apply hd
+ simp only [← h, toLex_add, WithTop.coe_add, add_le_add hu hv]
+
+alias lexOrder_mul_ge := le_lexOrder_mul
+
+theorem lexOrder_mul [NoZeroDivisors R] (φ ψ : MvPowerSeries σ R) :
+ lexOrder (φ * ψ) = lexOrder φ + lexOrder ψ := by
+ by_cases hφ : φ = 0
+ · simp only [hφ, zero_mul, lexOrder_zero, top_add]
+ by_cases hψ : ψ = 0
+ · simp only [hψ, mul_zero, lexOrder_zero, add_top]
+ rcases exists_finsupp_eq_lexOrder_of_ne_zero hφ with ⟨p, hp⟩
+ rcases exists_finsupp_eq_lexOrder_of_ne_zero hψ with ⟨q, hq⟩
+ apply le_antisymm _ (lexOrder_mul_ge φ ψ)
+ rw [hp, hq]
+ apply lexOrder_le_of_coeff_ne_zero (d := p + q)
+ rw [coeff_mul_of_add_lexOrder hp hq, mul_ne_zero_iff]
+ exact ⟨coeff_ne_zero_of_lexOrder hp.symm, coeff_ne_zero_of_lexOrder hq.symm⟩
+
+end LexOrder
+
+end MvPowerSeries
diff --git a/Mathlib/RingTheory/MvPowerSeries/NoZeroDivisors.lean b/Mathlib/RingTheory/MvPowerSeries/NoZeroDivisors.lean
index 76197b816b090..fb9d75cb2281a 100644
--- a/Mathlib/RingTheory/MvPowerSeries/NoZeroDivisors.lean
+++ b/Mathlib/RingTheory/MvPowerSeries/NoZeroDivisors.lean
@@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Antoine Chambert-Loir
-/
-import Mathlib.RingTheory.MvPowerSeries.Basic
import Mathlib.Data.Finsupp.WellFounded
+import Mathlib.RingTheory.MvPowerSeries.LexOrder
/-! # ZeroDivisors in a MvPowerSeries ring
@@ -65,6 +65,15 @@ theorem mem_nonZeroDivisors_of_constantCoeff {φ : MvPowerSeries σ R}
end Semiring
+instance {σ R : Type*} [Semiring R] [NoZeroDivisors R] :
+ NoZeroDivisors (MvPowerSeries σ R) where
+ eq_zero_or_eq_zero_of_mul_eq_zero {φ ψ} h := by
+ letI : LinearOrder σ := LinearOrder.swap σ WellOrderingRel.isWellOrder.linearOrder
+ letI : WellFoundedGT σ := by
+ change IsWellFounded σ fun x y ↦ WellOrderingRel x y
+ exact IsWellOrder.toIsWellFounded
+ simpa only [← lexOrder_eq_top_iff_eq_zero, lexOrder_mul, WithTop.add_eq_top] using h
+
end MvPowerSeries
end
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/Defs.lean b/Mathlib/RingTheory/Nilpotent/Defs.lean
index 0404b768832fa..cbdde6aab35bc 100644
--- a/Mathlib/RingTheory/Nilpotent/Defs.lean
+++ b/Mathlib/RingTheory/Nilpotent/Defs.lean
@@ -168,6 +168,29 @@ class IsReduced (R : Type*) [Zero R] [Pow R ℕ] : Prop where
/-- A reduced structure has no nonzero nilpotent elements. -/
eq_zero : ∀ x : R, IsNilpotent x → x = 0
+namespace IsReduced
+
+theorem pow_eq_zero [Zero R] [Pow R ℕ] [IsReduced R] {n : ℕ} (h : x ^ n = 0) :
+ x = 0 := IsReduced.eq_zero x ⟨n, h⟩
+
+@[simp]
+theorem pow_eq_zero_iff [MonoidWithZero R] [IsReduced R] {n : ℕ} (hn : n ≠ 0) :
+ x ^ n = 0 ↔ x = 0 := ⟨pow_eq_zero, fun h ↦ h.symm ▸ zero_pow hn⟩
+
+theorem pow_ne_zero_iff [MonoidWithZero R] [IsReduced R] {n : ℕ} (hn : n ≠ 0) :
+ x ^ n ≠ 0 ↔ x ≠ 0 := not_congr (pow_eq_zero_iff hn)
+
+theorem pow_ne_zero [Zero R] [Pow R ℕ] [IsReduced R] (n : ℕ) (h : x ≠ 0) :
+ x ^ n ≠ 0 := fun H ↦ h (pow_eq_zero H)
+
+/-- A variant of `IsReduced.pow_eq_zero_iff` assuming `R` is not trivial. -/
+@[simp]
+theorem pow_eq_zero_iff' [MonoidWithZero R] [IsReduced R] [Nontrivial R] {n : ℕ} :
+ x ^ n = 0 ↔ x = 0 ∧ n ≠ 0 := by
+ cases n <;> simp
+
+end IsReduced
+
instance (priority := 900) isReduced_of_noZeroDivisors [MonoidWithZero R] [NoZeroDivisors R] :
IsReduced R :=
⟨fun _ ⟨_, hn⟩ => pow_eq_zero hn⟩
diff --git a/Mathlib/RingTheory/Nilpotent/Lemmas.lean b/Mathlib/RingTheory/Nilpotent/Lemmas.lean
index d5d61f66838de..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
@@ -31,16 +31,6 @@ theorem isRadical_iff_span_singleton [CommSemiring R] :
simp_rw [IsRadical, ← Ideal.mem_span_singleton]
exact forall_swap.trans (forall_congr' fun r => exists_imp.symm)
-namespace Commute
-
-section Semiring
-
-variable [Semiring R] (h_comm : Commute x y)
-
-end Semiring
-
-end Commute
-
section CommSemiring
variable [CommSemiring R] {x y : R}
@@ -99,13 +89,31 @@ end LinearMap
namespace Module.End
-lemma isNilpotent.restrict {R M : Type*} [Semiring R] [AddCommMonoid M] [Module R M]
+section
+
+variable {M : Type*} [Semiring R] [AddCommMonoid M] [Module R M]
+
+lemma isNilpotent_restrict_of_le {f : End R M} {p q : Submodule R M}
+ {hp : MapsTo f p p} {hq : MapsTo f q q} (h : p ≤ q) (hf : IsNilpotent (f.restrict hq)) :
+ IsNilpotent (f.restrict hp) := by
+ obtain ⟨n, hn⟩ := hf
+ use n
+ ext ⟨x, hx⟩
+ replace hn := DFunLike.congr_fun hn ⟨x, h hx⟩
+ simp_rw [LinearMap.zero_apply, ZeroMemClass.coe_zero, ZeroMemClass.coe_eq_zero] at hn ⊢
+ rw [LinearMap.pow_restrict, LinearMap.restrict_apply] at hn ⊢
+ ext
+ exact (congr_arg Subtype.val hn : _)
+
+lemma isNilpotent.restrict
{f : M →ₗ[R] M} {p : Submodule R M} (hf : MapsTo f p p) (hnil : IsNilpotent f) :
IsNilpotent (f.restrict hf) := by
obtain ⟨n, hn⟩ := hnil
exact ⟨n, LinearMap.ext fun m ↦ by simp only [LinearMap.pow_restrict n, hn,
LinearMap.restrict_apply, LinearMap.zero_apply]; rfl⟩
+end
+
variable {M : Type v} [Ring R] [AddCommGroup M] [Module R M]
variable {f : Module.End R M} {p : Submodule R M} (hp : p ≤ p.comap f)
diff --git a/Mathlib/RingTheory/Noetherian.lean b/Mathlib/RingTheory/Noetherian.lean
index f3e0b396a8eb4..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 :=
@@ -145,17 +152,21 @@ variable [Semiring R] [AddCommMonoid M] [AddCommMonoid N] [Module R M] [Module R
variable (R M)
-- see Note [lower instance priority]
-instance (priority := 100) IsNoetherian.finite [IsNoetherian R M] : Finite R M :=
+instance (priority := 80) _root_.isNoetherian_of_finite [Finite M] : IsNoetherian R M :=
+ ⟨fun s => ⟨(s : Set M).toFinite.toFinset, by rw [Set.Finite.coe_toFinset, Submodule.span_eq]⟩⟩
+
+-- see Note [lower instance priority]
+instance (priority := 100) IsNoetherian.finite [IsNoetherian R M] : Module.Finite R M :=
⟨IsNoetherian.noetherian ⊤⟩
instance {R₁ S : Type*} [CommSemiring R₁] [Semiring S] [Algebra R₁ S]
- [IsNoetherian R₁ S] (I : Ideal S) : Finite R₁ I :=
+ [IsNoetherian R₁ S] (I : Ideal S) : Module.Finite R₁ I :=
IsNoetherian.finite R₁ ((I : Submodule S S).restrictScalars R₁)
variable {R M}
theorem Finite.of_injective [IsNoetherian R N] (f : M →ₗ[R] N) (hf : Function.Injective f) :
- Finite R M :=
+ Module.Finite R M :=
⟨fg_of_injective f hf⟩
end Module
@@ -184,85 +195,34 @@ 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*} {M : ι → Type*}
- [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
- [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
- cases nonempty_fintype ι
- haveI := Classical.decEq ι
- suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i) by
- let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
- letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
- exact isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R M coe_e)
- intro s
- induction' s using Finset.induction with a s has ih
- · exact ⟨fun s => by
- have : s = ⊥ := by simp only [eq_iff_true_of_subsingleton]
- rw [this]
- apply Submodule.fg_bot⟩
- refine
- @isNoetherian_of_linearEquiv R (M a × ((i : s) → M i)) _ _ _ _ _ _ ?_ <|
- @isNoetherian_prod R (M a) _ _ _ _ _ _ _ ih
- refine
- { toFun := fun f i =>
- (Finset.mem_insert.1 i.2).by_cases
- (fun h : i.1 = a => show M i.1 from Eq.recOn h.symm f.1)
- (fun h : i.1 ∈ s => show M i.1 from f.2 ⟨i.1, h⟩),
- invFun := fun f =>
- (f ⟨a, Finset.mem_insert_self _ _⟩, fun i => f ⟨i.1, Finset.mem_insert_of_mem i.2⟩),
- map_add' := ?_,
- map_smul' := ?_
- left_inv := ?_,
- right_inv := ?_ }
- · intro f g
- ext i
- unfold Or.by_cases
- cases' i with i hi
- rcases Finset.mem_insert.1 hi with (rfl | h)
- · change _ = _ + _
- simp only [dif_pos]
- rfl
- · change _ = _ + _
- have : ¬i = a := by
- rintro rfl
- exact has h
- simp only [dif_neg this, dif_pos h]
- rfl
- · intro c f
- ext i
- unfold Or.by_cases
- cases' i with i hi
- rcases Finset.mem_insert.1 hi with (rfl | h)
- · dsimp
- simp only [dif_pos]
- · dsimp
- have : ¬i = a := by
- rintro rfl
- exact has h
- simp only [dif_neg this, dif_pos h]
- · intro f
- apply Prod.ext
- · simp only [Or.by_cases, dif_pos]
- · ext ⟨i, his⟩
- have : ¬i = a := by
- rintro rfl
- exact has his
- simp only [Or.by_cases, this, not_false_iff, dif_neg]
- · intro f
- ext ⟨i, hi⟩
- rcases Finset.mem_insert.1 hi with (rfl | h)
- · simp only [Or.by_cases, dif_pos]
- · have : ¬i = a := by
- rintro rfl
- exact has h
- simp only [Or.by_cases, dif_neg this, dif_pos h]
+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)
+ · infer_instance
+ · exact fun ih ↦ isNoetherian_of_linearEquiv (LinearEquiv.piOptionEquivProd R).symm
/-- 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
@@ -289,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'
@@ -363,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
@@ -381,9 +340,6 @@ theorem LinearIndependent.set_finite_of_isNoetherian [Nontrivial R] {s : Set M}
(hi : LinearIndependent R ((↑) : s → M)) : s.Finite :=
@Set.toFinite _ _ hi.finite_of_isNoetherian
-@[deprecated (since := "2023-12-30")]
-alias finite_of_linearIndependent := LinearIndependent.set_finite_of_isNoetherian
-
/-- If the first and final modules in an exact sequence are Noetherian,
then the middle module is also Noetherian. -/
theorem isNoetherian_of_range_eq_ker [IsNoetherian R P]
@@ -392,15 +348,20 @@ theorem isNoetherian_of_range_eq_ker [IsNoetherian R P]
isNoetherian_mk <|
wellFounded_gt_exact_sequence
(LinearMap.range f)
- (Submodule.map (f.ker.liftQ f <| le_rfl))
- (Submodule.comap (f.ker.liftQ f <| le_rfl))
+ (Submodule.map (f.ker.liftQ f le_rfl))
+ (Submodule.comap (f.ker.liftQ f le_rfl))
(Submodule.comap g.rangeRestrict) (Submodule.map g.rangeRestrict)
- (Submodule.gciMapComap <| LinearMap.ker_eq_bot.mp <|
- Submodule.ker_liftQ_eq_bot _ _ _ (le_refl _))
+ (Submodule.gciMapComap <| LinearMap.ker_eq_bot.mp <| Submodule.ker_liftQ_eq_bot _ _ _ le_rfl)
(Submodule.giMapComap g.surjective_rangeRestrict)
(by simp [Submodule.map_comap_eq, inf_comm, Submodule.range_liftQ])
(by simp [Submodule.comap_map_eq, h])
+theorem isNoetherian_iff_submodule_quotient (S : Submodule R P) :
+ IsNoetherian R P ↔ IsNoetherian R S ∧ IsNoetherian R (P ⧸ S) := by
+ refine ⟨fun _ ↦ ⟨inferInstance, inferInstance⟩, fun ⟨_, _⟩ ↦ ?_⟩
+ apply isNoetherian_of_range_eq_ker S.subtype S.mkQ
+ rw [Submodule.ker_mkQ, Submodule.range_subtype]
+
/-- For an endomorphism of a Noetherian module, any sufficiently large iterate has disjoint kernel
and range. -/
theorem LinearMap.eventually_disjoint_ker_pow_range_pow (f : M →ₗ[R] M) :
@@ -503,11 +464,6 @@ theorem isNoetherianRing_iff_ideal_fg (R : Type*) [Semiring R] :
IsNoetherianRing R ↔ ∀ I : Ideal R, I.FG :=
isNoetherianRing_iff.trans isNoetherian_def
--- see Note [lower instance priority]
-instance (priority := 80) isNoetherian_of_finite (R M) [Finite M] [Semiring R] [AddCommMonoid M]
- [Module R M] : IsNoetherian R M :=
- ⟨fun s => ⟨(s : Set M).toFinite.toFinset, by rw [Set.Finite.coe_toFinset, Submodule.span_eq]⟩⟩
-
-- see Note [lower instance priority]
/-- Modules over the trivial ring are Noetherian. -/
instance (priority := 100) isNoetherian_of_subsingleton (R M) [Subsingleton R] [Semiring R]
diff --git a/Mathlib/RingTheory/NonUnitalSubring/Basic.lean b/Mathlib/RingTheory/NonUnitalSubring/Basic.lean
index 3d5642917f222..0833ddfb38894 100644
--- a/Mathlib/RingTheory/NonUnitalSubring/Basic.lean
+++ b/Mathlib/RingTheory/NonUnitalSubring/Basic.lean
@@ -71,7 +71,7 @@ universe u v w
section Basic
-variable {R : Type u} {S : Type v} {T : Type w} [NonUnitalNonAssocRing R]
+variable {R : Type u} {S : Type v} [NonUnitalNonAssocRing R]
section NonUnitalSubringClass
@@ -124,8 +124,6 @@ end NonUnitalSubringClass
end NonUnitalSubringClass
-variable [NonUnitalNonAssocRing S] [NonUnitalNonAssocRing T]
-
/-- `NonUnitalSubring R` is the type of non-unital subrings of `R`. A non-unital subring of `R`
is a subset `s` that is a multiplicative subsemigroup and an additive subgroup. Note in particular
that it shares the same 0 as R. -/
@@ -387,7 +385,7 @@ section Hom
namespace NonUnitalSubring
-variable {F : Type w} {R : Type u} {S : Type v} {T : Type*} {SR : Type*}
+variable {F : Type w} {R : Type u} {S : Type v} {T : Type*}
[NonUnitalNonAssocRing R] [NonUnitalNonAssocRing S] [NonUnitalNonAssocRing T]
[FunLike F R S] [NonUnitalRingHomClass F R S] (s : NonUnitalSubring R)
@@ -503,10 +501,7 @@ namespace NonUnitalSubring
section Order
-variable {F : Type w} {R : Type u} {S : Type v} {T : Type*}
- [NonUnitalNonAssocRing R] [NonUnitalNonAssocRing S] [NonUnitalNonAssocRing T]
- [FunLike F R S] [NonUnitalRingHomClass F R S]
- (g : S →ₙ+* T) (f : R →ₙ+* S)
+variable {R : Type u} [NonUnitalNonAssocRing R]
/-! ## bot -/
@@ -640,10 +635,9 @@ end Center
/-! ## `NonUnitalSubring` closure of a subset -/
-variable {F : Type w} {R : Type u} {S : Type v} {T : Type*}
- [NonUnitalNonAssocRing R] [NonUnitalNonAssocRing S] [NonUnitalNonAssocRing T]
+variable {F : Type w} {R : Type u} {S : Type v}
+ [NonUnitalNonAssocRing R] [NonUnitalNonAssocRing S]
[FunLike F R S] [NonUnitalRingHomClass F R S]
- (g : S →ₙ+* T) (f : R →ₙ+* S)
/-- The `NonUnitalSubring` generated by a set. -/
def closure (s : Set R) : NonUnitalSubring R :=
@@ -677,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)
@@ -800,6 +809,14 @@ theorem map_iSup {ι : Sort*} (f : F) (s : ι → NonUnitalSubring R) :
(iSup s).map f = ⨆ i, (s i).map f :=
(gc_map_comap f).l_iSup
+theorem map_inf (s t : NonUnitalSubring R) (f : F) (hf : Function.Injective f) :
+ (s ⊓ t).map f = s.map f ⊓ t.map f := SetLike.coe_injective (Set.image_inter hf)
+
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : F) (hf : Function.Injective f)
+ (s : ι → NonUnitalSubring R) : (iInf s).map f = ⨅ i, (s i).map f := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ s)
+
theorem comap_inf (s t : NonUnitalSubring S) (f : F) : (s ⊓ t).comap f = s.comap f ⊓ t.comap f :=
(gc_map_comap f).u_inf
@@ -902,11 +919,8 @@ end NonUnitalSubring
namespace NonUnitalRingHom
-variable {F : Type w} {R : Type u} {S : Type v} {T : Type*}
- [NonUnitalNonAssocRing R] [NonUnitalNonAssocRing S] [NonUnitalNonAssocRing T]
- [FunLike F R S] [NonUnitalRingHomClass F R S]
- (g : S →ₙ+* T) (f : R →ₙ+* S)
- {s : NonUnitalSubring R}
+variable {R : Type u} {S : Type v}
+ [NonUnitalNonAssocRing R] [NonUnitalNonAssocRing S]
open NonUnitalSubring
@@ -972,11 +986,8 @@ end NonUnitalRingHom
namespace NonUnitalSubring
-variable {F : Type w} {R : Type u} {S : Type v} {T : Type*}
- [NonUnitalNonAssocRing R] [NonUnitalNonAssocRing S] [NonUnitalNonAssocRing T]
- [FunLike F R S] [NonUnitalRingHomClass F R S]
- (g : S →ₙ+* T) (f : R →ₙ+* S)
- {s : NonUnitalSubring R}
+variable {R : Type u} {S : Type v}
+ [NonUnitalNonAssocRing R] [NonUnitalNonAssocRing S]
open NonUnitalRingHom
@@ -998,11 +1009,7 @@ end NonUnitalSubring
namespace RingEquiv
-variable {F : Type w} {R : Type u} {S : Type v} {T : Type*}
- [NonUnitalRing R] [NonUnitalRing S] [NonUnitalRing T]
- [FunLike F R S] [NonUnitalRingHomClass F R S]
- (g : S →ₙ+* T) (f : R →ₙ+* S)
- {s t : NonUnitalSubring R}
+variable {R : Type u} {S : Type v} [NonUnitalRing R] [NonUnitalRing S] {s t : NonUnitalSubring R}
/-- Makes the identity isomorphism from a proof two `NonUnitalSubring`s of a multiplicative
monoid are equal. -/
diff --git a/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean b/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean
index 3e465645af7db..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
@@ -29,7 +30,7 @@ variable {R : Type u} {S : Type v} {T : Type w} [NonUnitalNonAssocSemiring R] (M
/-- `NonUnitalSubsemiringClass S R` states that `S` is a type of subsets `s ⊆ R` that
are both an additive submonoid and also a multiplicative subsemigroup. -/
-class NonUnitalSubsemiringClass (S : Type*) (R : Type u) [NonUnitalNonAssocSemiring R]
+class NonUnitalSubsemiringClass (S : Type*) (R : outParam (Type u)) [NonUnitalNonAssocSemiring R]
[SetLike S R] extends AddSubmonoidClass S R : Prop where
mul_mem : ∀ {s : S} {a b : R}, a ∈ s → b ∈ s → a * b ∈ s
@@ -379,6 +380,15 @@ theorem coe_sInf (S : Set (NonUnitalSubsemiring R)) :
theorem mem_sInf {S : Set (NonUnitalSubsemiring R)} {x : R} : x ∈ sInf S ↔ ∀ p ∈ S, x ∈ p :=
Set.mem_iInter₂
+@[simp, norm_cast]
+theorem coe_iInf {ι : Sort*} {S : ι → NonUnitalSubsemiring R} :
+ (↑(⨅ i, S i) : Set R) = ⋂ i, S i := by
+ simp only [iInf, coe_sInf, Set.biInter_range]
+
+theorem mem_iInf {ι : Sort*} {S : ι → NonUnitalSubsemiring R} {x : R} :
+ (x ∈ ⨅ i, S i) ↔ ∀ i, x ∈ S i := by
+ simp only [iInf, mem_sInf, Set.forall_mem_range]
+
@[simp]
theorem sInf_toSubsemigroup (s : Set (NonUnitalSubsemiring R)) :
(sInf s).toSubsemigroup = ⨅ t ∈ s, NonUnitalSubsemiring.toSubsemigroup t :=
@@ -612,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)
@@ -670,6 +697,16 @@ theorem map_iSup {ι : Sort*} (f : F) (s : ι → NonUnitalSubsemiring R) :
(map f (iSup s) : NonUnitalSubsemiring S) = ⨆ i, map f (s i) :=
@GaloisConnection.l_iSup _ _ _ _ _ _ _ (gc_map_comap f) s
+theorem map_inf (s t : NonUnitalSubsemiring R) (f : F) (hf : Function.Injective f) :
+ (map f (s ⊓ t) : NonUnitalSubsemiring S) = map f s ⊓ map f t :=
+ SetLike.coe_injective (Set.image_inter hf)
+
+theorem map_iInf {ι : Sort*} [Nonempty ι] (f : F) (hf : Function.Injective f)
+ (s : ι → NonUnitalSubsemiring R) :
+ (map f (iInf s) : NonUnitalSubsemiring S) = ⨅ i, map f (s i) := by
+ apply SetLike.coe_injective
+ simpa using (Set.injOn_of_injective hf).image_iInter_eq (s := SetLike.coe ∘ s)
+
theorem comap_inf (s t : NonUnitalSubsemiring S) (f : F) :
(comap f (s ⊓ t) : NonUnitalSubsemiring R) = comap f s ⊓ comap f t :=
@GaloisConnection.u_inf _ _ s t _ _ _ _ (gc_map_comap f)
diff --git a/Mathlib/RingTheory/Norm/Basic.lean b/Mathlib/RingTheory/Norm/Basic.lean
index a051d47766d54..e58b1fc23e208 100644
--- a/Mathlib/RingTheory/Norm/Basic.lean
+++ b/Mathlib/RingTheory/Norm/Basic.lean
@@ -8,7 +8,7 @@ import Mathlib.FieldTheory.PrimitiveElement
import Mathlib.LinearAlgebra.Matrix.Charpoly.Minpoly
import Mathlib.LinearAlgebra.Matrix.ToLinearEquiv
import Mathlib.FieldTheory.IsAlgClosed.AlgebraicClosure
-import Mathlib.FieldTheory.Galois
+import Mathlib.FieldTheory.Galois.Basic
/-!
# Norm for (finite) ring extensions
@@ -46,7 +46,7 @@ variable {K L F : Type*} [Field K] [Field L] [Field F]
variable [Algebra K L] [Algebra K F]
variable {ι : Type w}
-open FiniteDimensional
+open Module
open LinearMap
@@ -74,7 +74,7 @@ theorem PowerBasis.norm_gen_eq_prod_roots [Algebra R F] (pb : PowerBasis R S)
have := minpoly.monic pb.isIntegral_gen
rw [PowerBasis.norm_gen_eq_coeff_zero_minpoly, ← pb.natDegree_minpoly, RingHom.map_mul,
← coeff_map,
- prod_roots_eq_coeff_zero_of_monic_of_split (this.map _) ((splits_id_iff_splits _).2 hf),
+ prod_roots_eq_coeff_zero_of_monic_of_splits (this.map _) ((splits_id_iff_splits _).2 hf),
this.natDegree_map, map_pow, ← mul_assoc, ← mul_pow]
simp only [map_neg, _root_.map_one, neg_mul, neg_neg, one_pow, one_mul]
@@ -153,7 +153,7 @@ theorem _root_.IntermediateField.AdjoinSimple.norm_gen_eq_one {x : L} (hx : ¬Is
contrapose! hx
obtain ⟨s, ⟨b⟩⟩ := hx
refine .of_mem_of_fg K⟮x⟯.toSubalgebra ?_ x ?_
- · exact (Submodule.fg_iff_finiteDimensional _).mpr (of_fintype_basis b)
+ · exact (Submodule.fg_iff_finiteDimensional _).mpr (.of_fintype_basis b)
· exact IntermediateField.subset_adjoin K _ (Set.mem_singleton x)
theorem _root_.IntermediateField.AdjoinSimple.norm_gen_eq_prod_roots (x : L)
diff --git a/Mathlib/RingTheory/Norm/Defs.lean b/Mathlib/RingTheory/Norm/Defs.lean
index 6f1c21fae5c00..14f2d89676a6d 100644
--- a/Mathlib/RingTheory/Norm/Defs.lean
+++ b/Mathlib/RingTheory/Norm/Defs.lean
@@ -35,13 +35,12 @@ 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 FiniteDimensional
+open Module
open LinearMap
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/PiTensorProduct.lean b/Mathlib/RingTheory/PiTensorProduct.lean
index ed8ee78470106..c4eeb9284a5f1 100644
--- a/Mathlib/RingTheory/PiTensorProduct.lean
+++ b/Mathlib/RingTheory/PiTensorProduct.lean
@@ -187,7 +187,7 @@ The map `Aᵢ ⟶ ⨂ᵢ Aᵢ` given by `a ↦ 1 ⊗ ... ⊗ a ⊗ 1 ⊗ ...`
def singleAlgHom [DecidableEq ι] (i : ι) : A i →ₐ[R] ⨂[R] i, A i where
toFun a := tprod R (MonoidHom.mulSingle _ i a)
map_one' := by simp only [_root_.map_one]; rfl
- map_mul' a a' := by simp
+ map_mul' a a' := by simp [_root_.map_mul]
map_zero' := MultilinearMap.map_update_zero _ _ _
map_add' _ _ := MultilinearMap.map_add _ _ _ _ _
commutes' r := show tprodCoeff R _ _ = r • tprodCoeff R _ _ by
diff --git a/Mathlib/RingTheory/Polynomial/Basic.lean b/Mathlib/RingTheory/Polynomial/Basic.lean
index 6e18f0a0e8ef5..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
@@ -605,8 +606,7 @@ theorem _root_.Polynomial.ker_mapRingHom (f : R →+* S) :
ext
simp only [LinearMap.mem_ker, RingHom.toSemilinearMap_apply, coe_mapRingHom]
rw [mem_map_C_iff, Polynomial.ext_iff]
- simp_rw [RingHom.mem_ker f]
- simp
+ simp [RingHom.mem_ker]
variable (I : Ideal R[X])
@@ -757,8 +757,7 @@ theorem isPrime_map_C_iff_isPrime (P : Ideal R) :
· rw [← not_le]
intro hnj
exact (add_lt_add_of_lt_of_le hmi hnj).ne hij.2.symm
- · simp only [eq_self_iff_true, not_true, false_or_iff, add_right_inj,
- not_and_self_iff] at hij
+ · simp only [eq_self_iff_true, not_true, false_or, add_right_inj, not_and_self_iff] at hij
· rw [mul_comm]
apply P.mul_mem_left
exact Classical.not_not.1 (Nat.find_min hf hi)
@@ -790,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]
@@ -914,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
@@ -922,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
@@ -1185,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]
@@ -1193,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
@@ -1216,6 +1215,11 @@ theorem ker_map (f : R →+* S) :
rw [MvPolynomial.mem_map_C_iff, RingHom.mem_ker, MvPolynomial.ext_iff]
simp_rw [coeff_map, coeff_zero, RingHom.mem_ker]
+lemma ker_mapAlgHom {S₁ S₂ σ : Type*} [CommRing S₁] [CommRing S₂] [Algebra R S₁]
+ [Algebra R S₂] (f : S₁ →ₐ[R] S₂) :
+ RingHom.ker (MvPolynomial.mapAlgHom (σ := σ) f) = Ideal.map MvPolynomial.C (RingHom.ker f) :=
+ MvPolynomial.ker_map (f.toRingHom : S₁ →+* S₂)
+
end MvPolynomial
section UniqueFactorizationDomain
diff --git a/Mathlib/RingTheory/Polynomial/Bernstein.lean b/Mathlib/RingTheory/Polynomial/Bernstein.lean
index d3efc2a2b5cb0..640f8b722b5e6 100644
--- a/Mathlib/RingTheory/Polynomial/Bernstein.lean
+++ b/Mathlib/RingTheory/Polynomial/Bernstein.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.MvPolynomial.PDeriv
import Mathlib.Algebra.Polynomial.AlgebraMap
@@ -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 af7686e449eba..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
@@ -147,7 +145,7 @@ theorem eval_one_cyclotomic_not_prime_pow {R : Type*} [Ring R] {n : ℕ}
rw [← Finset.prod_sdiff <| show {n} ⊆ _ from _] at this
swap
· simp only [singleton_subset_iff, mem_sdiff, mem_erase, Ne, mem_divisors, dvd_refl,
- true_and_iff, mem_image, mem_range, exists_prop, not_exists, not_and]
+ true_and, mem_image, mem_range, exists_prop, not_exists, not_and]
exact ⟨⟨hn.ne', hn'.ne'⟩, fun t _ => h hp _⟩
rw [← Int.natAbs_ofNat p, Int.natAbs_dvd_natAbs] at hpe
obtain ⟨t, ht⟩ := hpe
@@ -203,7 +201,7 @@ theorem sub_one_pow_totient_lt_cyclotomic_eval {n : ℕ} {q : ℝ} (hn' : 2 ≤
Units.val_le_val, ← NNReal.coe_le_coe, Complex.abs.nonneg, hq'.le, Units.val_mk0,
Real.coe_toNNReal', coe_nnnorm, Complex.norm_eq_abs, max_le_iff, tsub_le_iff_right]
intro x hx
- simpa only [and_true_iff, tsub_le_iff_right] using hfor x hx
+ simpa only [and_true, tsub_le_iff_right] using hfor x hx
· simp only [Subtype.coe_mk, Finset.mem_attach, exists_true_left, Subtype.exists, ←
NNReal.coe_lt_coe, ← Units.val_lt_val, Units.val_mk0 _, coe_nnnorm]
simpa [hq'.le, Real.coe_toNNReal', max_eq_left, sub_nonneg] using hex
@@ -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/Cyclotomic/Expand.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Expand.lean
index 5f2544087a31a..d66fdc3f66ab9 100644
--- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Expand.lean
+++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Expand.lean
@@ -3,8 +3,8 @@ Copyright (c) 2020 Riccardo Brasca. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Riccardo Brasca
-/
+import Mathlib.Algebra.Algebra.ZMod
import Mathlib.RingTheory.Polynomial.Cyclotomic.Roots
-import Mathlib.Data.ZMod.Algebra
/-!
# Cyclotomic polynomials and `expand`.
diff --git a/Mathlib/RingTheory/Polynomial/Dickson.lean b/Mathlib/RingTheory/Polynomial/Dickson.lean
index 6f3bfc0a478bf..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
@@ -231,7 +230,7 @@ theorem dickson_one_one_zmod_p (p : ℕ) [Fact p.Prime] : dickson 1 (1 : ZMod p)
mem_roots hφ, IsRoot, eval_add, eval_sub, eval_pow, eval_mul, eval_X, eval_C, eval_one,
Multiset.mem_singleton]
by_cases hy : y = 0
- · simp only [hy, eq_self_iff_true, or_true_iff]
+ · simp only [hy, eq_self_iff_true, or_true]
apply or_congr _ Iff.rfl
rw [← mul_left_inj' hy, eq_comm, ← sub_eq_zero, add_mul, inv_mul_cancel₀ hy]
apply eq_iff_eq_cancel_right.mpr
@@ -241,9 +240,9 @@ theorem dickson_one_one_zmod_p (p : ℕ) [Fact p.Prime] : dickson 1 (1 : ZMod p)
intro x
simp only [exists_prop, Set.mem_iUnion, Set.bind_def, Ne, Set.mem_setOf_eq]
by_cases hx : x = 0
- · simp only [hx, and_true_iff, eq_self_iff_true, inv_zero, or_true_iff]
+ · simp only [hx, and_true, eq_self_iff_true, inv_zero, or_true]
exact ⟨_, 1, rfl, one_ne_zero⟩
- · simp only [hx, or_false_iff, exists_eq_right]
+ · simp only [hx, or_false, exists_eq_right]
exact ⟨_, rfl, hx⟩
theorem dickson_one_one_charP (p : ℕ) [Fact p.Prime] [CharP R p] : dickson 1 (1 : R) p = X ^ p := by
diff --git a/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean b/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean
index a7f446664bdad..6365d391b724f 100644
--- a/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean
+++ b/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean
@@ -137,7 +137,7 @@ theorem dvd_coeff_zero_of_aeval_eq_prime_smul_of_minpoly_isEisensteinAt {B : Pow
letI := B.finite
let P := minpoly R B.gen
obtain ⟨n, hn⟩ := Nat.exists_eq_succ_of_ne_zero B.dim_pos.ne'
- have finrank_K_L : FiniteDimensional.finrank K L = B.dim := B.finrank
+ have finrank_K_L : Module.finrank K L = B.dim := B.finrank
have deg_K_P : (minpoly K B.gen).natDegree = B.dim := B.natDegree_minpoly
have deg_R_P : P.natDegree = B.dim := by
rw [← deg_K_P, minpoly.isIntegrallyClosed_eq_field_fractions' K hBint,
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/IntegralNormalization.lean b/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean
index 467b55e7f137e..b8383bd8e208a 100644
--- a/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean
+++ b/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean
@@ -1,7 +1,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, Scott Morrison, Jens Wagemaker
+Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
-/
import Mathlib.Algebra.Polynomial.AlgebraMap
import Mathlib.Algebra.Polynomial.Degree.Lemmas
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 f4d2df4b5c382..a3dc6084fd575 100644
--- a/Mathlib/RingTheory/Polynomial/Pochhammer.lean
+++ b/Mathlib/RingTheory/Polynomial/Pochhammer.lean
@@ -1,12 +1,11 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+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/Selmer.lean b/Mathlib/RingTheory/Polynomial/Selmer.lean
index 765741980303a..c6f4ed8e30afd 100644
--- a/Mathlib/RingTheory/Polynomial/Selmer.lean
+++ b/Mathlib/RingTheory/Polynomial/Selmer.lean
@@ -34,7 +34,7 @@ theorem X_pow_sub_X_sub_one_irreducible_aux (z : ℂ) : ¬(z ^ n = z + 1 ∧ z ^
rw [← Nat.mod_add_div n 3, pow_add, pow_mul, h3, one_pow, mul_one]
have : n % 3 < 3 := Nat.mod_lt n zero_lt_three
interval_cases n % 3 <;>
- simp only [this, pow_zero, pow_one, eq_self_iff_true, or_true_iff, true_or_iff]
+ simp only [this, pow_zero, pow_one, eq_self_iff_true, or_true, true_or]
have z_ne_zero : z ≠ 0 := fun h =>
zero_ne_one ((zero_pow three_ne_zero).symm.trans (show (0 : ℂ) ^ 3 = 1 from h ▸ h3))
rcases key with (key | key | key)
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/Tower.lean b/Mathlib/RingTheory/Polynomial/Tower.lean
index 2c16e8138d977..5e49599ddbda9 100644
--- a/Mathlib/RingTheory/Polynomial/Tower.lean
+++ b/Mathlib/RingTheory/Polynomial/Tower.lean
@@ -56,7 +56,7 @@ theorem aeval_algebraMap_apply (x : A) (p : R[X]) :
theorem aeval_algebraMap_eq_zero_iff [NoZeroSMulDivisors A B] [Nontrivial B] (x : A) (p : R[X]) :
aeval (algebraMap A B x) p = 0 ↔ aeval x p = 0 := by
rw [aeval_algebraMap_apply, Algebra.algebraMap_eq_smul_one, smul_eq_zero,
- iff_false_intro (one_ne_zero' B), or_false_iff]
+ iff_false_intro (one_ne_zero' B), or_false]
variable {B}
diff --git a/Mathlib/RingTheory/Polynomial/Vieta.lean b/Mathlib/RingTheory/Polynomial/Vieta.lean
index e4bb4bc99037d..6df36b563f3c0 100644
--- a/Mathlib/RingTheory/Polynomial/Vieta.lean
+++ b/Mathlib/RingTheory/Polynomial/Vieta.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Hanting Zhang
-/
import Mathlib.Algebra.Polynomial.Splits
-import Mathlib.RingTheory.MvPolynomial.Symmetric
+import Mathlib.RingTheory.MvPolynomial.Symmetric.Defs
/-!
# Vieta's Formula
@@ -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 d21058ee4247c..278543baf82c4 100644
--- a/Mathlib/RingTheory/PolynomialAlgebra.lean
+++ b/Mathlib/RingTheory/PolynomialAlgebra.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Polynomial.AlgebraMap
import Mathlib.Data.Matrix.Basis
@@ -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 b0b9c2d3d7536..f410b20ade48b 100644
--- a/Mathlib/RingTheory/PowerBasis.lean
+++ b/Mathlib/RingTheory/PowerBasis.lean
@@ -19,7 +19,7 @@ gives a `PowerBasis` structure generated by `x`.
* `PowerBasis R A`: a structure containing an `x` and an `n` such that
`1, x, ..., x^n` is a basis for the `R`-algebra `A` (viewed as an `R`-module).
-* `finrank (hf : f ≠ 0) : FiniteDimensional.finrank K (AdjoinRoot f) = f.natDegree`,
+* `finrank (hf : f ≠ 0) : Module.finrank K (AdjoinRoot f) = f.natDegree`,
the dimension of `AdjoinRoot f` equals the degree of `f`
* `PowerBasis.lift (pb : PowerBasis R S)`: if `y : S'` satisfies the same
@@ -77,8 +77,8 @@ theorem finite (pb : PowerBasis R S) : Module.Finite R S := .of_basis pb.basis
@[deprecated (since := "2024-03-05")] alias finiteDimensional := PowerBasis.finite
theorem finrank [StrongRankCondition R] (pb : PowerBasis R S) :
- FiniteDimensional.finrank R S = pb.dim := by
- rw [FiniteDimensional.finrank_eq_card_basis pb.basis, Fintype.card_fin]
+ Module.finrank R S = pb.dim := by
+ rw [Module.finrank_eq_card_basis pb.basis, Fintype.card_fin]
theorem mem_span_pow' {x y : S} {d : ℕ} :
y ∈ Submodule.span R (Set.range fun i : Fin d => x ^ (i : ℕ)) ↔
@@ -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 33cea1c3cd017..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
@@ -603,14 +601,14 @@ lemma coeff_one_pow (n : ℕ) (φ : R⟦X⟧) :
CharP.cast_eq_zero, zero_add, mul_one, not_true_eq_false] at h''
norm_num at h''
· rw [ih]
- conv => lhs; arg 2; rw [mul_comm, ← mul_assoc]
- move_mul [← (constantCoeff R) φ ^ (n' - 1)]
- conv => enter [1, 2, 1, 1, 2]; rw [← pow_one (a := constantCoeff R φ)]
- rw [← pow_add (a := constantCoeff R φ)]
- conv => enter [1, 2, 1, 1]; rw [Nat.sub_add_cancel h']
- conv => enter [1, 2, 1]; rw [mul_comm]
- rw [mul_assoc, ← one_add_mul, add_comm, mul_assoc]
- conv => enter [1, 2]; rw [mul_comm]
+ · conv => lhs; arg 2; rw [mul_comm, ← mul_assoc]
+ move_mul [← (constantCoeff R) φ ^ (n' - 1)]
+ conv => enter [1, 2, 1, 1, 2]; rw [← pow_one (a := constantCoeff R φ)]
+ rw [← pow_add (a := constantCoeff R φ)]
+ conv => enter [1, 2, 1, 1]; rw [Nat.sub_add_cancel h']
+ conv => enter [1, 2, 1]; rw [mul_comm]
+ rw [mul_assoc, ← one_add_mul, add_comm, mul_assoc]
+ conv => enter [1, 2]; rw [mul_comm]
exact h'
· decide
@@ -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 b7d31cd531382..8cdc5f61d50d6 100644
--- a/Mathlib/RingTheory/Presentation.lean
+++ b/Mathlib/RingTheory/Presentation.lean
@@ -27,11 +27,10 @@ A presentation of an `R`-algebra `S` is a distinguished family of generators and
- `Algebra.Presentation.dimension`: The dimension of a presentation is the number of generators
minus the number of relations.
-We also give constructors for localization and base change.
+We also give constructors for localization, base change and composition.
## TODO
-- Define composition of presentations.
- Define `Hom`s of presentations.
## Notes
@@ -123,6 +122,39 @@ lemma finitePresentation_of_isFinite [P.IsFinite] :
section Construction
+/-- If `algebraMap R S` is bijective, the empty generators are a presentation with no relations. -/
+noncomputable def ofBijectiveAlgebraMap (h : Function.Bijective (algebraMap R S)) :
+ Presentation.{t, w} R S where
+ __ := Generators.ofSurjectiveAlgebraMap h.surjective
+ rels := PEmpty
+ relation := PEmpty.elim
+ span_range_relation_eq_ker := by
+ simp only [Set.range_eq_empty, Ideal.span_empty]
+ symm
+ rw [← RingHom.injective_iff_ker_eq_bot]
+ show Function.Injective (aeval PEmpty.elim)
+ rw [aeval_injective_iff_of_isEmpty]
+ exact h.injective
+
+instance ofBijectiveAlgebraMap_isFinite (h : Function.Bijective (algebraMap R S)) :
+ (ofBijectiveAlgebraMap.{t, w} h).IsFinite where
+ finite_vars := inferInstanceAs (Finite PEmpty.{w + 1})
+ finite_rels := inferInstanceAs (Finite PEmpty.{t + 1})
+
+lemma ofBijectiveAlgebraMap_dimension (h : Function.Bijective (algebraMap R S)) :
+ (ofBijectiveAlgebraMap h).dimension = 0 := by
+ show Nat.card PEmpty - Nat.card PEmpty = 0
+ simp only [Nat.card_eq_fintype_card, Fintype.card_ofIsEmpty, le_refl, tsub_eq_zero_of_le]
+
+variable (R) in
+/-- The canonical `R`-presentation of `R` with no generators and no relations. -/
+noncomputable def id : Presentation.{t, w} R R := ofBijectiveAlgebraMap Function.bijective_id
+
+instance : (id R).IsFinite := ofBijectiveAlgebraMap_isFinite (R := R) Function.bijective_id
+
+lemma id_dimension : (Presentation.id R).dimension = 0 :=
+ ofBijectiveAlgebraMap_dimension (R := R) Function.bijective_id
+
section Localization
variable (r : R) [IsLocalization.Away r S]
@@ -147,6 +179,7 @@ private lemma span_range_relation_eq_ker_localizationAway :
show Ideal.span {C r * X () - 1} = Ideal.comap _ (RingHom.ker (mvPolynomialQuotientEquiv S r))
simp [RingHom.ker_equiv, ← RingHom.ker_eq_comap_bot]
+variable (S) in
/-- If `S` is the localization of `R` away from `r`, we can construct a natural
presentation of `S` as `R`-algebra with a single generator `X` and the relation `r * X - 1 = 0`. -/
@[simps relation, simps (config := .lemmasOnly) rels]
@@ -158,17 +191,22 @@ noncomputable def localizationAway : Presentation R S where
simp only [Generators.localizationAway_vars, Set.range_const]
apply span_range_relation_eq_ker_localizationAway r
-instance localizationAway_isFinite : (localizationAway r (S := S)).IsFinite where
+instance localizationAway_isFinite : (localizationAway S r).IsFinite where
finite_vars := inferInstanceAs <| Finite Unit
finite_rels := inferInstanceAs <| Finite Unit
+instance : Fintype (localizationAway S r).rels :=
+ inferInstanceAs (Fintype Unit)
+
@[simp]
-lemma localizationAway_dimension_zero : (localizationAway r (S := S)).dimension = 0 := by
+lemma localizationAway_dimension_zero : (localizationAway S r).dimension = 0 := by
simp [Presentation.dimension, localizationAway, Generators.localizationAway_vars]
end Localization
-variable {T} [CommRing T] [Algebra R T] (P : Presentation R S)
+section BaseChange
+
+variable (T) [CommRing T] [Algebra R T] (P : Presentation R S)
private lemma span_range_relation_eq_ker_baseChange :
Ideal.span (Set.range fun i ↦ (MvPolynomial.map (algebraMap R T)) (P.relation i)) =
@@ -198,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]
@@ -210,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'
@@ -227,7 +265,169 @@ def baseChange : Presentation T (T ⊗[R] S) where
__ := Generators.baseChange P.toGenerators
rels := P.rels
relation i := MvPolynomial.map (algebraMap R T) (P.relation i)
- span_range_relation_eq_ker := P.span_range_relation_eq_ker_baseChange
+ span_range_relation_eq_ker := P.span_range_relation_eq_ker_baseChange T
+
+instance baseChange_isFinite [P.IsFinite] : (P.baseChange T).IsFinite where
+ finite_vars := inferInstanceAs <| Finite (P.vars)
+ finite_rels := inferInstanceAs <| Finite (P.rels)
+
+end BaseChange
+
+section Composition
+
+/-!
+### Composition of presentations
+
+Let `S` be an `R`-algebra with presentation `P` and `T` be an `S`-algebra with
+presentation `Q`. In this section we construct a presentation of `T` as an `R`-algebra.
+
+For the underlying generators see `Algebra.Generators.comp`. The family of relations is
+indexed by `Q.rels ⊕ P.rels`.
+
+We have two canonical maps:
+`MvPolynomial P.vars R →ₐ[R] MvPolynomial (Q.vars ⊕ P.vars) R` induced by `Sum.inr`
+and `aux : MvPolynomial (Q.vars ⊕ P.vars) R →ₐ[R] MvPolynomial Q.vars S` induced by
+the evaluation `MvPolynomial P.vars R →ₐ[R] S` (see below).
+
+Now `i : P.rels` is mapped to the image of `P.relation i` under the first map and
+`j : Q.rels` is mapped to a pre-image under `aux` of `Q.relation j` (see `comp_relation_aux`
+for the construction of the pre-image and `comp_relation_aux_map` for a proof that it is indeed
+a pre-image).
+
+The evaluation map factors as:
+`MvPolynomial (Q.vars ⊕ P.vars) R →ₐ[R] MvPolynomial Q.vars S →ₐ[R] T`, where
+the first map is `aux`. The goal is to compute that the kernel of this composition
+is spanned by the relations indexed by `Q.rels ⊕ P.rels` (`span_range_relation_eq_ker_comp`).
+One easily sees that this kernel is the pre-image under `aux` of the kernel of the evaluation
+of `Q`, where the latter is by assumption spanned by the relations `Q.relation j`.
+
+Since `aux` is surjective (`aux_surjective`), the pre-image is the sum of the ideal spanned
+by the constructed pre-images of the `Q.relation j` and the kernel of `aux`. It hence
+remains to show that the kernel of `aux` is spanned by the image of the `P.relation i`
+under the canonical map `MvPolynomial P.vars R →ₐ[R] MvPolynomial (Q.vars ⊕ P.vars) R`. By
+assumption this span is the kernel of the evaluation map of `P`. For this, we use the isomorphism
+`MvPolynomial (Q.vars ⊕ P.vars) R ≃ₐ[R] MvPolynomial Q.vars (MvPolynomial P.vars R)` and
+`MvPolynomial.ker_map`.
+
+-/
+
+variable {T} [CommRing T] [Algebra S T]
+variable (Q : Presentation S T) (P : Presentation R S)
+
+/-- The evaluation map `MvPolynomial (Q.vars ⊕ P.vars) →ₐ[R] T` factors via this map. For more
+details, see the module docstring at the beginning of the section. -/
+private noncomputable def aux : MvPolynomial (Q.vars ⊕ P.vars) R →ₐ[R] MvPolynomial Q.vars S :=
+ aeval (Sum.elim X (MvPolynomial.C ∘ P.val))
+
+/-- A choice of pre-image of `Q.relation r` under `aux`. -/
+private noncomputable def comp_relation_aux (r : Q.rels) : MvPolynomial (Q.vars ⊕ P.vars) R :=
+ Finsupp.sum (Q.relation r)
+ (fun x j ↦ (MvPolynomial.rename Sum.inr <| P.σ j) * monomial (x.mapDomain Sum.inl) 1)
+
+@[simp]
+private lemma aux_X (i : Q.vars ⊕ P.vars) : (Q.aux P) (X i) = Sum.elim X (C ∘ P.val) i :=
+ aeval_X (Sum.elim X (C ∘ P.val)) i
+
+/-- The pre-images constructed in `comp_relation_aux` are indeed pre-images under `aux`. -/
+private lemma comp_relation_aux_map (r : Q.rels) :
+ (Q.aux P) (Q.comp_relation_aux P r) = Q.relation r := by
+ simp only [aux, comp_relation_aux, Generators.comp_vars, Sum.elim_inl, map_finsupp_sum]
+ simp only [_root_.map_mul, aeval_rename, aeval_monomial, Sum.elim_comp_inr]
+ conv_rhs => rw [← Finsupp.sum_single (Q.relation r)]
+ congr
+ ext u s m
+ simp only [MvPolynomial.single_eq_monomial, aeval, AlgHom.coe_mk, coe_eval₂Hom]
+ rw [monomial_eq, IsScalarTower.algebraMap_eq R S, algebraMap_eq, ← eval₂_comp_left, ← aeval_def]
+ simp [Finsupp.prod_mapDomain_index_inj (Sum.inl_injective)]
+
+private lemma aux_surjective : Function.Surjective (Q.aux P) := fun p ↦ by
+ induction' p using MvPolynomial.induction_on with a p q hp hq p i h
+ · use rename Sum.inr <| P.σ a
+ simp only [aux, aeval_rename, Sum.elim_comp_inr]
+ have (p : MvPolynomial P.vars R) :
+ aeval (C ∘ P.val) p = (C (aeval P.val p) : MvPolynomial Q.vars S) := by
+ induction' p using MvPolynomial.induction_on with a p q hp hq p i h
+ · simp
+ · simp [hp, hq]
+ · simp [h]
+ simp [this]
+ · obtain ⟨a, rfl⟩ := hp
+ obtain ⟨b, rfl⟩ := hq
+ exact ⟨a + b, map_add _ _ _⟩
+ · obtain ⟨a, rfl⟩ := h
+ exact ⟨(a * X (Sum.inl i)), by simp⟩
+
+private lemma aux_image_relation :
+ Q.aux P '' (Set.range (Algebra.Presentation.comp_relation_aux Q P)) = Set.range Q.relation := by
+ ext x
+ constructor
+ · rintro ⟨y, ⟨a, rfl⟩, rfl⟩
+ exact ⟨a, (Q.comp_relation_aux_map P a).symm⟩
+ · rintro ⟨y, rfl⟩
+ use Q.comp_relation_aux P y
+ simp only [Set.mem_range, exists_apply_eq_apply, true_and, comp_relation_aux_map]
+
+private lemma aux_eq_comp : Q.aux P =
+ (MvPolynomial.mapAlgHom (aeval P.val)).comp (sumAlgEquiv R Q.vars P.vars).toAlgHom := by
+ ext i : 1
+ cases i <;> simp
+
+private lemma aux_ker :
+ RingHom.ker (Q.aux P) = Ideal.map (rename Sum.inr) (RingHom.ker (aeval P.val)) := by
+ rw [aux_eq_comp, ← AlgHom.comap_ker, MvPolynomial.ker_mapAlgHom]
+ show Ideal.comap _ (Ideal.map (IsScalarTower.toAlgHom R (MvPolynomial P.vars R) _) _) = _
+ rw [← sumAlgEquiv_comp_rename_inr, ← Ideal.map_mapₐ, Ideal.comap_map_of_bijective]
+ simpa using AlgEquiv.bijective (sumAlgEquiv R Q.vars P.vars)
+
+variable [Algebra R T] [IsScalarTower R S T]
+
+private lemma aeval_comp_val_eq :
+ (aeval (Q.comp P.toGenerators).val) =
+ (aevalTower (IsScalarTower.toAlgHom R S T) Q.val).comp (Q.aux P) := by
+ ext i
+ simp only [AlgHom.coe_comp, Function.comp_apply]
+ erw [Q.aux_X P i]
+ cases i <;> simp
+
+private lemma span_range_relation_eq_ker_comp : Ideal.span
+ (Set.range (Sum.elim (Algebra.Presentation.comp_relation_aux Q P)
+ fun rp ↦ (rename Sum.inr) (P.relation rp))) = (Q.comp P.toGenerators).ker := by
+ rw [Generators.ker_eq_ker_aeval_val, Q.aeval_comp_val_eq, ← AlgHom.comap_ker]
+ show _ = Ideal.comap _ (Q.ker)
+ rw [← Q.span_range_relation_eq_ker, ← Q.aux_image_relation P, ← Ideal.map_span,
+ Ideal.comap_map_of_surjective' _ (Q.aux_surjective P)]
+ rw [Set.Sum.elim_range, Ideal.span_union, Q.aux_ker, ← P.ker_eq_ker_aeval_val,
+ ← P.span_range_relation_eq_ker, Ideal.map_span]
+ congr
+ ext
+ simp
+
+/-- Given presentations of `T` over `S` and of `S` over `R`,
+we may construct a presentation of `T` over `R`. -/
+@[simps rels, simps (config := .lemmasOnly) relation]
+noncomputable def comp : Presentation R T where
+ toGenerators := Q.toGenerators.comp P.toGenerators
+ rels := Q.rels ⊕ P.rels
+ relation := Sum.elim (Q.comp_relation_aux P)
+ (fun rp ↦ MvPolynomial.rename Sum.inr <| P.relation rp)
+ span_range_relation_eq_ker := Q.span_range_relation_eq_ker_comp P
+
+@[simp]
+lemma comp_relation_inr (r : P.rels) :
+ (Q.comp P).relation (Sum.inr r) = rename Sum.inr (P.relation r) :=
+ rfl
+
+lemma comp_aeval_relation_inl (r : Q.rels) :
+ aeval (Sum.elim X (MvPolynomial.C ∘ P.val)) ((Q.comp P).relation (Sum.inl r)) =
+ Q.relation r := by
+ show (Q.aux P) _ = _
+ simp [comp_relation, comp_relation_aux_map]
+
+instance comp_isFinite [P.IsFinite] [Q.IsFinite] : (Q.comp P).IsFinite where
+ finite_vars := inferInstanceAs <| Finite (Q.vars ⊕ P.vars)
+ finite_rels := inferInstanceAs <| Finite (Q.rels ⊕ P.rels)
+
+end Composition
end Construction
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/PrimeSpectrum.lean b/Mathlib/RingTheory/PrimeSpectrum.lean
index 07320e17cdf81..e97719ff6ca9f 100644
--- a/Mathlib/RingTheory/PrimeSpectrum.lean
+++ b/Mathlib/RingTheory/PrimeSpectrum.lean
@@ -5,6 +5,7 @@ Authors: Johan Commelin, Filippo A. E. Nuccio, Andrew Yang
-/
import Mathlib.LinearAlgebra.Finsupp
import Mathlib.RingTheory.Ideal.Prod
+import Mathlib.RingTheory.Localization.Ideal
import Mathlib.RingTheory.Nilpotent.Lemmas
import Mathlib.RingTheory.Noetherian
@@ -480,3 +481,112 @@ end Noetherian
end CommSemiRing
end PrimeSpectrum
+
+open PrimeSpectrum
+
+/-- The pullback of an element of `PrimeSpectrum S` along a ring homomorphism `f : R →+* S`.
+The bundled continuous version is `PrimeSpectrum.comap`. -/
+abbrev RingHom.specComap {R S : Type*} [CommSemiring R] [CommSemiring S] (f : R →+* S) :
+ PrimeSpectrum S → PrimeSpectrum R :=
+ fun y => ⟨Ideal.comap f y.asIdeal, inferInstance⟩
+
+namespace PrimeSpectrum
+
+open RingHom
+
+variable {R S} {S' : Type*} [CommSemiring R] [CommSemiring S] [CommSemiring S']
+
+theorem preimage_specComap_zeroLocus_aux (f : R →+* S) (s : Set R) :
+ f.specComap ⁻¹' zeroLocus s = zeroLocus (f '' s) := by
+ ext x
+ simp only [mem_zeroLocus, Set.image_subset_iff, Set.mem_preimage, mem_zeroLocus, Ideal.coe_comap]
+
+variable (f : R →+* S)
+
+@[simp]
+theorem specComap_asIdeal (y : PrimeSpectrum S) :
+ (f.specComap y).asIdeal = Ideal.comap f y.asIdeal :=
+ rfl
+
+@[simp]
+theorem specComap_id : (RingHom.id R).specComap = fun x => x :=
+ rfl
+
+@[simp]
+theorem specComap_comp (f : R →+* S) (g : S →+* S') :
+ (g.comp f).specComap = f.specComap.comp g.specComap :=
+ rfl
+
+theorem specComap_comp_apply (f : R →+* S) (g : S →+* S') (x : PrimeSpectrum S') :
+ (g.comp f).specComap x = f.specComap (g.specComap x) :=
+ rfl
+
+@[simp]
+theorem preimage_specComap_zeroLocus (s : Set R) :
+ f.specComap ⁻¹' zeroLocus s = zeroLocus (f '' s) :=
+ preimage_specComap_zeroLocus_aux f s
+
+theorem specComap_injective_of_surjective (f : R →+* S) (hf : Function.Surjective f) :
+ Function.Injective f.specComap := fun x y h =>
+ PrimeSpectrum.ext
+ (Ideal.comap_injective_of_surjective f hf
+ (congr_arg PrimeSpectrum.asIdeal h : (f.specComap x).asIdeal = (f.specComap y).asIdeal))
+
+variable (S)
+
+theorem localization_specComap_injective [Algebra R S] (M : Submonoid R) [IsLocalization M S] :
+ Function.Injective (algebraMap R S).specComap := by
+ intro p q h
+ replace h := _root_.congr_arg (fun x : PrimeSpectrum R => Ideal.map (algebraMap R S) x.asIdeal) h
+ dsimp only [specComap] at h
+ rw [IsLocalization.map_comap M S, IsLocalization.map_comap M S] at h
+ ext1
+ exact h
+
+theorem localization_specComap_range [Algebra R S] (M : Submonoid R) [IsLocalization M S] :
+ Set.range (algebraMap R S).specComap = { p | Disjoint (M : Set R) p.asIdeal } := by
+ ext x
+ constructor
+ · simp_rw [disjoint_iff_inf_le]
+ rintro ⟨p, rfl⟩ x ⟨hx₁, hx₂⟩
+ exact (p.2.1 : ¬_) (p.asIdeal.eq_top_of_isUnit_mem hx₂ (IsLocalization.map_units S ⟨x, hx₁⟩))
+ · intro h
+ use ⟨x.asIdeal.map (algebraMap R S), IsLocalization.isPrime_of_isPrime_disjoint M S _ x.2 h⟩
+ ext1
+ exact IsLocalization.comap_map_of_isPrime_disjoint M S _ x.2 h
+
+end PrimeSpectrum
+
+section SpecOfSurjective
+
+open Function RingHom
+
+variable [CommRing R] [CommRing S]
+variable (f : R →+* S)
+variable {R}
+
+theorem image_specComap_zeroLocus_eq_zeroLocus_comap (hf : Surjective f) (I : Ideal S) :
+ f.specComap '' zeroLocus I = zeroLocus (I.comap f) := by
+ simp only [Set.ext_iff, Set.mem_image, mem_zeroLocus, SetLike.coe_subset_coe]
+ refine fun p => ⟨?_, fun h_I_p => ?_⟩
+ · rintro ⟨p, hp, rfl⟩ a ha
+ exact hp ha
+ · have hp : ker f ≤ p.asIdeal := (Ideal.comap_mono bot_le).trans h_I_p
+ refine ⟨⟨p.asIdeal.map f, Ideal.map_isPrime_of_surjective hf hp⟩, fun x hx => ?_, ?_⟩
+ · obtain ⟨x', rfl⟩ := hf x
+ exact Ideal.mem_map_of_mem f (h_I_p hx)
+ · ext x
+ rw [specComap_asIdeal, Ideal.mem_comap, Ideal.mem_map_iff_of_surjective f hf]
+ refine ⟨?_, fun hx => ⟨x, hx, rfl⟩⟩
+ rintro ⟨x', hx', heq⟩
+ rw [← sub_sub_cancel x' x]
+ refine p.asIdeal.sub_mem hx' (hp ?_)
+ rwa [mem_ker, map_sub, sub_eq_zero]
+
+theorem range_specComap_of_surjective (hf : Surjective f) :
+ Set.range f.specComap = zeroLocus (ker f) := by
+ rw [← Set.image_univ]
+ convert image_specComap_zeroLocus_eq_zeroLocus_comap _ _ hf _
+ rw [zeroLocus_bot]
+
+end SpecOfSurjective
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/Finite.lean b/Mathlib/RingTheory/RingHom/Finite.lean
index 164f6abef7265..40a5dbe72b097 100644
--- a/Mathlib/RingTheory/RingHom/Finite.lean
+++ b/Mathlib/RingTheory/RingHom/Finite.lean
@@ -3,12 +3,22 @@ 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.RingTheory.RingHomProperties
+import Mathlib.RingTheory.LocalProperties.Basic
+import Mathlib.RingTheory.Localization.Integer
/-!
# The meta properties of finite ring homomorphisms.
+## Main results
+
+Let `R` be a commutative ring, `S` is an `R`-algebra, `M` be a submonoid of `R`.
+
+* `finite_localizationPreserves` : If `S` is a finite `R`-algebra, then `S' = M⁻¹S` is a
+ finite `R' = M⁻¹R`-algebra.
+* `finite_ofLocalizationSpan` : `S` is a finite `R`-algebra if there exists
+ a set `{ r }` that spans `R` such that `Sᵣ` is a finite `Rᵣ`-algebra.
+
-/
@@ -38,3 +48,186 @@ theorem finite_stableUnderBaseChange : StableUnderBaseChange @Finite := by
exact inferInstance
end RingHom
+
+open scoped Pointwise Classical
+
+universe u
+
+variable {R S : Type u} [CommRing R] [CommRing S] (M : Submonoid R) (f : R →+* S)
+variable (R' S' : Type u) [CommRing R'] [CommRing S']
+variable [Algebra R R'] [Algebra S S']
+
+lemma Module.Finite_of_isLocalization (R S Rₚ Sₚ) [CommSemiring R] [CommRing S] [CommRing Rₚ]
+ [CommRing Sₚ] [Algebra R S] [Algebra R Rₚ] [Algebra R Sₚ] [Algebra S Sₚ] [Algebra Rₚ Sₚ]
+ [IsScalarTower R S Sₚ] [IsScalarTower R Rₚ Sₚ] (M : Submonoid R) [IsLocalization M Rₚ]
+ [IsLocalization (Algebra.algebraMapSubmonoid S M) Sₚ] [hRS : Module.Finite R S] :
+ Module.Finite Rₚ Sₚ := by
+ classical
+ have : algebraMap Rₚ Sₚ = IsLocalization.map (T := Algebra.algebraMapSubmonoid S M) Sₚ
+ (algebraMap R S) (Submonoid.le_comap_map M) := by
+ apply IsLocalization.ringHom_ext M
+ simp only [IsLocalization.map_comp, ← IsScalarTower.algebraMap_eq]
+ -- We claim that if `S` is generated by `T` as an `R`-module,
+ -- then `S'` is generated by `T` as an `R'`-module.
+ obtain ⟨T, hT⟩ := hRS
+ use T.image (algebraMap S Sₚ)
+ rw [eq_top_iff]
+ rintro x -
+ -- By the hypotheses, for each `x : S'`, we have `x = y / (f r)` for some `y : S` and `r : M`.
+ -- Since `S` is generated by `T`, the image of `y` should fall in the span of the image of `T`.
+ obtain ⟨y, ⟨_, ⟨r, hr, rfl⟩⟩, rfl⟩ :=
+ IsLocalization.mk'_surjective (Algebra.algebraMapSubmonoid S M) x
+ rw [IsLocalization.mk'_eq_mul_mk'_one, mul_comm, Finset.coe_image]
+ have hy : y ∈ Submodule.span R ↑T := by rw [hT]; trivial
+ replace hy : algebraMap S Sₚ y ∈ Submodule.map (IsScalarTower.toAlgHom R S Sₚ).toLinearMap
+ (Submodule.span R (T : Set S)) := Submodule.mem_map_of_mem
+-- -- Note: #8386 had to specify the value of `f` below
+ (f := (IsScalarTower.toAlgHom R S Sₚ).toLinearMap) hy
+ rw [Submodule.map_span (IsScalarTower.toAlgHom R S Sₚ).toLinearMap T] at hy
+ have H : Submodule.span R (algebraMap S Sₚ '' T) ≤
+ (Submodule.span Rₚ (algebraMap S Sₚ '' T)).restrictScalars R := by
+ rw [Submodule.span_le]; exact Submodule.subset_span
+ -- Now, since `y ∈ span T`, and `(f r)⁻¹ ∈ R'`, `x / (f r)` is in `span T` as well.
+ convert (Submodule.span Rₚ (algebraMap S Sₚ '' T)).smul_mem
+ (IsLocalization.mk' Rₚ (1 : R) ⟨r, hr⟩) (H hy) using 1
+ rw [Algebra.smul_def, this, IsLocalization.map_mk', map_one]
+
+/-- If `S` is a finite `R`-algebra, then `S' = M⁻¹S` is a finite `R' = M⁻¹R`-algebra. -/
+theorem RingHom.finite_localizationPreserves : RingHom.LocalizationPreserves @RingHom.Finite := by
+ introv R hf
+ letI := f.toAlgebra
+ letI := ((algebraMap S S').comp f).toAlgebra
+ let f' : R' →+* S' := IsLocalization.map S' f (Submonoid.le_comap_map M)
+ letI := f'.toAlgebra
+ have : IsScalarTower R R' S' := IsScalarTower.of_algebraMap_eq'
+ (IsLocalization.map_comp M.le_comap_map).symm
+ have : IsScalarTower R S S' := IsScalarTower.of_algebraMap_eq' rfl
+ have : IsLocalization (Algebra.algebraMapSubmonoid S M) S' := by
+ rwa [Algebra.algebraMapSubmonoid, RingHom.algebraMap_toAlgebra]
+ have : Module.Finite R S := hf
+ apply Module.Finite_of_isLocalization R S R' S' M
+
+theorem RingHom.localization_away_map_finite (r : R) [IsLocalization.Away r R']
+ [IsLocalization.Away (f r) S'] (hf : f.Finite) : (IsLocalization.Away.map R' S' f r).Finite :=
+ finite_localizationPreserves.away r hf
+
+/-- Let `S` be an `R`-algebra, `M` a submonoid of `R`, and `S' = M⁻¹S`.
+If the image of some `x : S` falls in the span of some finite `s ⊆ S'` over `R`,
+then there exists some `m : M` such that `m • x` falls in the
+span of `IsLocalization.finsetIntegerMultiple _ s` over `R`.
+-/
+theorem IsLocalization.smul_mem_finsetIntegerMultiple_span [Algebra R S] [Algebra R S']
+ [IsScalarTower R S S'] [IsLocalization (M.map (algebraMap R S)) S'] (x : S) (s : Finset S')
+ (hx : algebraMap S S' x ∈ Submodule.span R (s : Set S')) :
+ ∃ m : M, m • x ∈
+ Submodule.span R
+ (IsLocalization.finsetIntegerMultiple (M.map (algebraMap R S)) s : Set S) := by
+ let g : S →ₐ[R] S' :=
+ AlgHom.mk' (algebraMap S S') fun c x => by simp [Algebra.algebraMap_eq_smul_one]
+ -- We first obtain the `y' ∈ M` such that `s' = y' • s` is falls in the image of `S` in `S'`.
+ let y := IsLocalization.commonDenomOfFinset (M.map (algebraMap R S)) s
+ have hx₁ : (y : S) • (s : Set S') = g '' _ :=
+ (IsLocalization.finsetIntegerMultiple_image _ s).symm
+ obtain ⟨y', hy', e : algebraMap R S y' = y⟩ := y.prop
+ have : algebraMap R S y' • (s : Set S') = y' • (s : Set S') := by
+ simp_rw [Algebra.algebraMap_eq_smul_one, smul_assoc, one_smul]
+ rw [← e, this] at hx₁
+ replace hx₁ := congr_arg (Submodule.span R) hx₁
+ rw [Submodule.span_smul] at hx₁
+ replace hx : _ ∈ y' • Submodule.span R (s : Set S') := Set.smul_mem_smul_set hx
+ rw [hx₁] at hx
+ erw [← _root_.map_smul g, ← Submodule.map_span (g : S →ₗ[R] S')] at hx
+ -- Since `x` falls in the span of `s` in `S'`, `y' • x : S` falls in the span of `s'` in `S'`.
+ -- That is, there exists some `x' : S` in the span of `s'` in `S` and `x' = y' • x` in `S'`.
+ -- Thus `a • (y' • x) = a • x' ∈ span s'` in `S` for some `a ∈ M`.
+ obtain ⟨x', hx', hx'' : algebraMap _ _ _ = _⟩ := hx
+ obtain ⟨⟨_, a, ha₁, rfl⟩, ha₂⟩ :=
+ (IsLocalization.eq_iff_exists (M.map (algebraMap R S)) S').mp hx''
+ use (⟨a, ha₁⟩ : M) * (⟨y', hy'⟩ : M)
+ convert (Submodule.span R
+ (IsLocalization.finsetIntegerMultiple (Submonoid.map (algebraMap R S) M) s : Set S)).smul_mem
+ a hx' using 1
+ convert ha₂.symm using 1
+ · rw [Subtype.coe_mk, Submonoid.smul_def, Submonoid.coe_mul, ← smul_smul]
+ exact Algebra.smul_def _ _
+ · exact Algebra.smul_def _ _
+
+/-- If `M` is an `R' = S⁻¹R` module, and `x ∈ span R' s`,
+then `t • x ∈ span R s` for some `t : S`. -/
+theorem multiple_mem_span_of_mem_localization_span
+ {N : Type*} [AddCommMonoid N] [Module R N] [Module R' N]
+ [IsScalarTower R R' N] [IsLocalization M R'] (s : Set N) (x : N)
+ (hx : x ∈ Submodule.span R' s) : ∃ (t : M), t • x ∈ Submodule.span R s := by
+ classical
+ obtain ⟨s', hss', hs'⟩ := Submodule.mem_span_finite_of_mem_span hx
+ rsuffices ⟨t, ht⟩ : ∃ t : M, t • x ∈ Submodule.span R (s' : Set N)
+ · exact ⟨t, Submodule.span_mono hss' ht⟩
+ clear hx hss' s
+ induction s' using Finset.induction_on generalizing x
+ · use 1; simpa using hs'
+ rename_i a s _ hs
+ simp only [Finset.coe_insert, Finset.image_insert, Finset.coe_image, Subtype.coe_mk,
+ Submodule.mem_span_insert] at hs' ⊢
+ rcases hs' with ⟨y, z, hz, rfl⟩
+ rcases IsLocalization.surj M y with ⟨⟨y', s'⟩, e⟩
+ apply congrArg (fun x ↦ x • a) at e
+ simp only [algebraMap_smul] at e
+ rcases hs _ hz with ⟨t, ht⟩
+ refine ⟨t * s', t * y', _, (Submodule.span R (s : Set N)).smul_mem s' ht, ?_⟩
+ rw [smul_add, ← smul_smul, mul_comm, ← smul_smul, ← smul_smul, ← e, mul_comm, ← Algebra.smul_def]
+ simp
+ rfl
+
+/-- If `S` is an `R' = M⁻¹R` algebra, and `x ∈ adjoin R' s`,
+then `t • x ∈ adjoin R s` for some `t : M`. -/
+theorem multiple_mem_adjoin_of_mem_localization_adjoin [Algebra R' S] [Algebra R S]
+ [IsScalarTower R R' S] [IsLocalization M R'] (s : Set S) (x : S)
+ (hx : x ∈ Algebra.adjoin R' s) : ∃ t : M, t • x ∈ Algebra.adjoin R s := by
+ change ∃ t : M, t • x ∈ Subalgebra.toSubmodule (Algebra.adjoin R s)
+ change x ∈ Subalgebra.toSubmodule (Algebra.adjoin R' s) at hx
+ simp_rw [Algebra.adjoin_eq_span] at hx ⊢
+ exact multiple_mem_span_of_mem_localization_span M R' _ _ hx
+
+/-- `S` is a finite `R`-algebra if there exists a set `{ r }` that
+ spans `R` such that `Sᵣ` is a finite `Rᵣ`-algebra. -/
+theorem RingHom.finite_ofLocalizationSpan : RingHom.OfLocalizationSpan @RingHom.Finite := by
+ rw [RingHom.ofLocalizationSpan_iff_finite]
+ introv R hs H
+ -- We first setup the instances
+ letI := f.toAlgebra
+ letI := fun r : s => (Localization.awayMap f r).toAlgebra
+ have : ∀ r : s,
+ IsLocalization ((Submonoid.powers (r : R)).map (algebraMap R S)) (Localization.Away (f r)) :=
+ by intro r; rw [Submonoid.map_powers]; exact Localization.isLocalization
+ haveI : ∀ r : s, IsScalarTower R (Localization.Away (r : R)) (Localization.Away (f r)) :=
+ fun r => IsScalarTower.of_algebraMap_eq'
+ (IsLocalization.map_comp (Submonoid.powers (r : R)).le_comap_map).symm
+ -- By the hypothesis, we may find a finite generating set for each `Sᵣ`. This set can then be
+ -- lifted into `R` by multiplying a sufficiently large power of `r`. I claim that the union of
+ -- these generates `S`.
+ constructor
+ replace H := fun r => (H r).1
+ choose s₁ s₂ using H
+ let sf := fun x : s => IsLocalization.finsetIntegerMultiple (Submonoid.powers (f x)) (s₁ x)
+ use s.attach.biUnion sf
+ rw [Submodule.span_attach_biUnion, eq_top_iff]
+ -- It suffices to show that `r ^ n • x ∈ span T` for each `r : s`, since `{ r ^ n }` spans `R`.
+ -- This then follows from the fact that each `x : R` is a linear combination of the generating set
+ -- of `Sᵣ`. By multiplying a sufficiently large power of `r`, we can cancel out the `r`s in the
+ -- denominators of both the generating set and the coefficients.
+ rintro x -
+ apply Submodule.mem_of_span_eq_top_of_smul_pow_mem _ (s : Set R) hs _ _
+ intro r
+ obtain ⟨⟨_, n₁, rfl⟩, hn₁⟩ :=
+ multiple_mem_span_of_mem_localization_span (Submonoid.powers (r : R))
+ (Localization.Away (r : R)) (s₁ r : Set (Localization.Away (f r))) (algebraMap S _ x)
+ (by rw [s₂ r]; trivial)
+ dsimp only at hn₁
+ rw [Submonoid.smul_def, Algebra.smul_def, IsScalarTower.algebraMap_apply R S, ← map_mul] at hn₁
+ obtain ⟨⟨_, n₂, rfl⟩, hn₂⟩ :=
+ IsLocalization.smul_mem_finsetIntegerMultiple_span (Submonoid.powers (r : R))
+ (Localization.Away (f r)) _ (s₁ r) hn₁
+ rw [Submonoid.smul_def, ← Algebra.smul_def, smul_smul, ← pow_add] at hn₂
+ simp_rw [Submonoid.map_powers] at hn₂
+ use n₂ + n₁
+ exact le_iSup (fun x : s => Submodule.span R (sf x : Set S)) r hn₂
diff --git a/Mathlib/RingTheory/RingHom/FinitePresentation.lean b/Mathlib/RingTheory/RingHom/FinitePresentation.lean
index 99b90e6894081..ad4ae18aa6419 100644
--- a/Mathlib/RingTheory/RingHom/FinitePresentation.lean
+++ b/Mathlib/RingTheory/RingHom/FinitePresentation.lean
@@ -163,8 +163,9 @@ theorem finitePresentation_ofLocalizationSpanTarget :
/-- Being finitely-presented is a local property of rings. -/
theorem finitePresentation_isLocal : PropertyIsLocal @FinitePresentation :=
⟨finitePresentation_localizationPreserves,
- finitePresentation_ofLocalizationSpanTarget, finitePresentation_stableUnderComposition,
- finitePresentation_holdsForLocalizationAway⟩
+ finitePresentation_ofLocalizationSpanTarget,
+ finitePresentation_stableUnderComposition.stableUnderCompositionWithLocalizationAway
+ finitePresentation_holdsForLocalizationAway⟩
/-- Being finitely-presented respects isomorphisms. -/
theorem finitePresentation_respectsIso : RingHom.RespectsIso @RingHom.FinitePresentation :=
diff --git a/Mathlib/RingTheory/RingHom/FiniteType.lean b/Mathlib/RingTheory/RingHom/FiniteType.lean
index fb75176c50b6e..1e07b805c0c4a 100644
--- a/Mathlib/RingTheory/RingHom/FiniteType.lean
+++ b/Mathlib/RingTheory/RingHom/FiniteType.lean
@@ -4,26 +4,154 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andrew Yang
-/
import Mathlib.RingTheory.FiniteStability
-import Mathlib.RingTheory.LocalProperties
import Mathlib.RingTheory.Localization.InvSubmonoid
+import Mathlib.RingTheory.RingHom.Finite
/-!
# The meta properties of finite-type ring homomorphisms.
-The main result is `RingHom.finiteType_is_local`.
+## Main results
+
+Let `R` be a commutative ring, `S` is an `R`-algebra, `M` be a submonoid of `R`.
+
+* `finiteType_localizationPreserves` : If `S` is a finite type `R`-algebra, then `S' = M⁻¹S` is a
+ finite type `R' = M⁻¹R`-algebra.
+* `finiteType_ofLocalizationSpan` : `S` is a finite type `R`-algebra if there exists
+ a set `{ r }` that spans `R` such that `Sᵣ` is a finite type `Rᵣ`-algebra.
+*`RingHom.finiteType_is_local`: `RingHom.FiniteType` is a local property.
-/
namespace RingHom
-open scoped Pointwise TensorProduct
+open scoped Pointwise TensorProduct Classical
+
+universe u
+
+variable {R S : Type u} [CommRing R] [CommRing S] (M : Submonoid R) (f : R →+* S)
+variable (R' S' : Type u) [CommRing R'] [CommRing S']
+variable [Algebra R R'] [Algebra S S']
theorem finiteType_stableUnderComposition : StableUnderComposition @FiniteType := by
introv R hf hg
exact hg.comp hf
+/-- If `S` is a finite type `R`-algebra, then `S' = M⁻¹S` is a finite type `R' = M⁻¹R`-algebra. -/
+theorem finiteType_localizationPreserves : RingHom.LocalizationPreserves @RingHom.FiniteType := by
+ introv R hf
+ -- mirrors the proof of `localization_map_finite`
+ letI := f.toAlgebra
+ letI := ((algebraMap S S').comp f).toAlgebra
+ let f' : R' →+* S' := IsLocalization.map S' f (Submonoid.le_comap_map M)
+ letI := f'.toAlgebra
+ haveI : IsScalarTower R R' S' :=
+ IsScalarTower.of_algebraMap_eq' (IsLocalization.map_comp M.le_comap_map).symm
+ let fₐ : S →ₐ[R] S' := AlgHom.mk' (algebraMap S S') fun c x => RingHom.map_mul _ _ _
+ obtain ⟨T, hT⟩ := hf
+ use T.image (algebraMap S S')
+ rw [eq_top_iff]
+ rintro x -
+ obtain ⟨y, ⟨_, ⟨r, hr, rfl⟩⟩, rfl⟩ := IsLocalization.mk'_surjective (M.map f) x
+ rw [IsLocalization.mk'_eq_mul_mk'_one, mul_comm, Finset.coe_image]
+ have hy : y ∈ Algebra.adjoin R (T : Set S) := by rw [hT]; trivial
+ replace hy : algebraMap S S' y ∈ (Algebra.adjoin R (T : Set S)).map fₐ :=
+ Subalgebra.mem_map.mpr ⟨_, hy, rfl⟩
+ rw [fₐ.map_adjoin T] at hy
+ have H : Algebra.adjoin R (algebraMap S S' '' T) ≤
+ (Algebra.adjoin R' (algebraMap S S' '' T)).restrictScalars R := by
+ rw [Algebra.adjoin_le_iff]; exact Algebra.subset_adjoin
+ convert (Algebra.adjoin R' (algebraMap S S' '' T)).smul_mem (H hy)
+ (IsLocalization.mk' R' (1 : R) ⟨r, hr⟩) using 1
+ rw [Algebra.smul_def]
+ erw [IsLocalization.map_mk' M.le_comap_map]
+ rw [map_one]
+
+theorem localization_away_map_finiteType (r : R) [IsLocalization.Away r R']
+ [IsLocalization.Away (f r) S'] (hf : f.FiniteType) :
+ (IsLocalization.Away.map R' S' f r).FiniteType :=
+ finiteType_localizationPreserves.away r hf
+
+variable {S'}
+
+/-- Let `S` be an `R`-algebra, `M` a submonoid of `S`, `S' = M⁻¹S`.
+Suppose the image of some `x : S` falls in the adjoin of some finite `s ⊆ S'` over `R`,
+and `A` is an `R`-subalgebra of `S` containing both `M` and the numerators of `s`.
+Then, there exists some `m : M` such that `m • x` falls in `A`.
+-/
+theorem IsLocalization.exists_smul_mem_of_mem_adjoin [Algebra R S] [Algebra R S']
+ [IsScalarTower R S S'] (M : Submonoid S) [IsLocalization M S'] (x : S) (s : Finset S')
+ (A : Subalgebra R S) (hA₁ : (IsLocalization.finsetIntegerMultiple M s : Set S) ⊆ A)
+ (hA₂ : M ≤ A.toSubmonoid) (hx : algebraMap S S' x ∈ Algebra.adjoin R (s : Set S')) :
+ ∃ m : M, m • x ∈ A := by
+ let g : S →ₐ[R] S' := IsScalarTower.toAlgHom R S S'
+ let y := IsLocalization.commonDenomOfFinset M s
+ have hx₁ : (y : S) • (s : Set S') = g '' _ :=
+ (IsLocalization.finsetIntegerMultiple_image _ s).symm
+ obtain ⟨n, hn⟩ :=
+ Algebra.pow_smul_mem_of_smul_subset_of_mem_adjoin (y : S) (s : Set S') (A.map g)
+ (by rw [hx₁]; exact Set.image_subset _ hA₁) hx (Set.mem_image_of_mem _ (hA₂ y.2))
+ obtain ⟨x', hx', hx''⟩ := hn n (le_of_eq rfl)
+ rw [Algebra.smul_def, ← _root_.map_mul] at hx''
+ obtain ⟨a, ha₂⟩ := (IsLocalization.eq_iff_exists M S').mp hx''
+ use a * y ^ n
+ convert A.mul_mem hx' (hA₂ a.prop) using 1
+ rw [Submonoid.smul_def, smul_eq_mul, Submonoid.coe_mul, SubmonoidClass.coe_pow, mul_assoc, ← ha₂,
+ mul_comm]
+
+/-- Let `S` be an `R`-algebra, `M` a submonoid of `R`, and `S' = M⁻¹S`.
+If the image of some `x : S` falls in the adjoin of some finite `s ⊆ S'` over `R`,
+then there exists some `m : M` such that `m • x` falls in the
+adjoin of `IsLocalization.finsetIntegerMultiple _ s` over `R`.
+-/
+theorem IsLocalization.lift_mem_adjoin_finsetIntegerMultiple [Algebra R S] [Algebra R S']
+ [IsScalarTower R S S'] [IsLocalization (M.map (algebraMap R S)) S'] (x : S) (s : Finset S')
+ (hx : algebraMap S S' x ∈ Algebra.adjoin R (s : Set S')) :
+ ∃ m : M, m • x ∈
+ Algebra.adjoin R
+ (IsLocalization.finsetIntegerMultiple (M.map (algebraMap R S)) s : Set S) := by
+ obtain ⟨⟨_, a, ha, rfl⟩, e⟩ :=
+ IsLocalization.exists_smul_mem_of_mem_adjoin (M.map (algebraMap R S)) x s (Algebra.adjoin R _)
+ Algebra.subset_adjoin (by rintro _ ⟨a, _, rfl⟩; exact Subalgebra.algebraMap_mem _ a) hx
+ refine ⟨⟨a, ha⟩, ?_⟩
+ simpa only [Submonoid.smul_def, algebraMap_smul] using e
+
+theorem finiteType_ofLocalizationSpan : RingHom.OfLocalizationSpan @RingHom.FiniteType := by
+ rw [RingHom.ofLocalizationSpan_iff_finite]
+ introv R hs H
+ -- mirrors the proof of `finite_ofLocalizationSpan`
+ letI := f.toAlgebra
+ letI := fun r : s => (Localization.awayMap f r).toAlgebra
+ have : ∀ r : s,
+ IsLocalization ((Submonoid.powers (r : R)).map (algebraMap R S)) (Localization.Away (f r)) :=
+ by intro r; rw [Submonoid.map_powers]; exact Localization.isLocalization
+ haveI : ∀ r : s, IsScalarTower R (Localization.Away (r : R)) (Localization.Away (f r)) :=
+ fun r => IsScalarTower.of_algebraMap_eq'
+ (IsLocalization.map_comp (Submonoid.powers (r : R)).le_comap_map).symm
+ constructor
+ replace H := fun r => (H r).1
+ choose s₁ s₂ using H
+ let sf := fun x : s => IsLocalization.finsetIntegerMultiple (Submonoid.powers (f x)) (s₁ x)
+ use s.attach.biUnion sf
+ convert (Algebra.adjoin_attach_biUnion (R := R) sf).trans _
+ rw [eq_top_iff]
+ rintro x -
+ apply (⨆ x : s, Algebra.adjoin R (sf x : Set S)).toSubmodule.mem_of_span_eq_top_of_smul_pow_mem
+ _ hs _ _
+ intro r
+ obtain ⟨⟨_, n₁, rfl⟩, hn₁⟩ :=
+ multiple_mem_adjoin_of_mem_localization_adjoin (Submonoid.powers (r : R))
+ (Localization.Away (r : R)) (s₁ r : Set (Localization.Away (f r)))
+ (algebraMap S (Localization.Away (f r)) x) (by rw [s₂ r]; trivial)
+ rw [Submonoid.smul_def, Algebra.smul_def, IsScalarTower.algebraMap_apply R S, ← map_mul] at hn₁
+ obtain ⟨⟨_, n₂, rfl⟩, hn₂⟩ :=
+ IsLocalization.lift_mem_adjoin_finsetIntegerMultiple (Submonoid.powers (r : R)) _ (s₁ r) hn₁
+ rw [Submonoid.smul_def, ← Algebra.smul_def, smul_smul, ← pow_add] at hn₂
+ simp_rw [Submonoid.map_powers] at hn₂
+ use n₂ + n₁
+ exact le_iSup (fun x : s => Algebra.adjoin R (sf x : Set S)) r hn₂
+
theorem finiteType_holdsForLocalizationAway : HoldsForLocalizationAway @FiniteType := by
introv R _
suffices Algebra.FiniteType R S by
@@ -88,8 +216,9 @@ theorem finiteType_ofLocalizationSpanTarget : OfLocalizationSpanTarget @FiniteTy
· rw [ht]; trivial
theorem finiteType_is_local : PropertyIsLocal @FiniteType :=
- ⟨localization_finiteType, finiteType_ofLocalizationSpanTarget, finiteType_stableUnderComposition,
- finiteType_holdsForLocalizationAway⟩
+ ⟨finiteType_localizationPreserves, finiteType_ofLocalizationSpanTarget,
+ finiteType_stableUnderComposition.stableUnderCompositionWithLocalizationAway
+ finiteType_holdsForLocalizationAway⟩
theorem finiteType_respectsIso : RingHom.RespectsIso @RingHom.FiniteType :=
RingHom.finiteType_is_local.respectsIso
diff --git a/Mathlib/RingTheory/RingHom/Locally.lean b/Mathlib/RingTheory/RingHom/Locally.lean
new file mode 100644
index 0000000000000..d4adb0bedebb7
--- /dev/null
+++ b/Mathlib/RingTheory/RingHom/Locally.lean
@@ -0,0 +1,348 @@
+/-
+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.Localization.BaseChange
+import Mathlib.RingTheory.Localization.Away.Lemmas
+
+/-!
+# Target local closure of ring homomorphism properties
+
+If `P` is a property of ring homomorphisms, we call `Locally P` the closure of `P` with
+respect to standard open coverings on the (algebraic) target (i.e. geometric source). Hence
+for `f : R →+* S`, the property `Locally P` holds if it holds locally on `S`, i.e. if there exists
+a subset `{ t }` of `S` generating the unit ideal, such that `P` holds for all compositions
+`R →+* Sₜ`.
+
+Assuming without further mention that `P` is stable under composition with isomorphisms,
+`Locally P` is local on the target by construction, i.e. it satisfies
+`OfLocalizationSpanTarget`. If `P` itself is local on the target, `Locally P` coincides with `P`.
+
+The `Locally` construction preserves various properties of `P`, e.g. if `P` is stable under
+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`.
+
+-/
+
+universe u v
+
+open TensorProduct
+
+namespace RingHom
+
+variable (P : ∀ {R S : Type u} [CommRing R] [CommRing S] (_ : R →+* S), Prop)
+
+/--
+For a property of ring homomorphisms `P`, `Locally P` holds for `f : R →+* S` if
+it holds locally on `S`, i.e. if there exists a subset `{ t }` of `S` generating
+the unit ideal, such that `P` holds for all compositions `R →+* Sₜ`.
+
+We may require `s` to be finite here, for the equivalence, see `locally_iff_finite`.
+-/
+def Locally {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) : Prop :=
+ ∃ (s : Set S) (_ : Ideal.span s = ⊤),
+ ∀ t ∈ s, P ((algebraMap S (Localization.Away t)).comp f)
+
+variable {R S : Type u} [CommRing R] [CommRing S]
+
+lemma locally_iff_finite (f : R →+* S) :
+ Locally P f ↔ ∃ (s : Finset S) (_ : Ideal.span (s : Set S) = ⊤),
+ ∀ t ∈ s, P ((algebraMap S (Localization.Away t)).comp f) := by
+ constructor
+ · intro ⟨s, hsone, hs⟩
+ obtain ⟨s', h₁, h₂⟩ := (Ideal.span_eq_top_iff_finite s).mp hsone
+ exact ⟨s', h₂, fun t ht ↦ hs t (h₁ ht)⟩
+ · intro ⟨s, hsone, hs⟩
+ use s, hsone, hs
+
+variable {P}
+
+/-- If `P` respects isomorphisms, to check `P` holds locally for `f : R →+* S`, it suffices
+to check `P` holds on a standard open cover. -/
+lemma locally_of_exists (hP : RespectsIso P) (f : R →+* S) {ι : Type*} (s : ι → S)
+ (hsone : Ideal.span (Set.range s) = ⊤)
+ (Sₜ : ι → Type u) [∀ i, CommRing (Sₜ i)] [∀ i, Algebra S (Sₜ i)]
+ [∀ i, IsLocalization.Away (s i) (Sₜ i)] (hf : ∀ i, P ((algebraMap S (Sₜ i)).comp f)) :
+ Locally P f := by
+ use Set.range s, hsone
+ rintro - ⟨i, rfl⟩
+ let e : Localization.Away (s i) ≃+* Sₜ i :=
+ (IsLocalization.algEquiv (Submonoid.powers (s i)) _ _).toRingEquiv
+ have : algebraMap S (Localization.Away (s i)) = e.symm.toRingHom.comp (algebraMap S (Sₜ i)) :=
+ RingHom.ext (fun x ↦ (AlgEquiv.commutes (IsLocalization.algEquiv _ _ _).symm _).symm)
+ rw [this, RingHom.comp_assoc]
+ exact hP.left _ _ (hf i)
+
+/-- Equivalence variant of `locally_of_exists`. This is sometimes easier to use, if the
+`IsLocalization.Away` instance can't be automatically inferred. -/
+lemma locally_iff_exists (hP : RespectsIso P) (f : R →+* S) :
+ Locally P f ↔ ∃ (ι : Type u) (s : ι → S) (_ : Ideal.span (Set.range s) = ⊤) (Sₜ : ι → Type u)
+ (_ : (i : ι) → CommRing (Sₜ i)) (_ : (i : ι) → Algebra S (Sₜ i))
+ (_ : (i : ι) → IsLocalization.Away (s i : S) (Sₜ i)),
+ ∀ i, P ((algebraMap S (Sₜ i)).comp f) :=
+ ⟨fun ⟨s, hsone, hs⟩ ↦ ⟨s, fun t : s ↦ (t : S), by simpa, fun t ↦ Localization.Away (t : S),
+ inferInstance, inferInstance, inferInstance, fun t ↦ hs t.val t.property⟩,
+ fun ⟨ι, s, hsone, Sₜ, _, _, hislocal, hs⟩ ↦ locally_of_exists hP f s hsone Sₜ hs⟩
+
+/-- In the definition of `Locally` we may replace `Localization.Away` with an arbitrary
+algebra satisfying `IsLocalization.Away`. -/
+lemma locally_iff_isLocalization (hP : RespectsIso P) (f : R →+* S) :
+ Locally P f ↔ ∃ (s : Finset S) (_ : Ideal.span (s : Set S) = ⊤),
+ ∀ t ∈ s, ∀ (Sₜ : Type u) [CommRing Sₜ] [Algebra S Sₜ] [IsLocalization.Away t Sₜ],
+ P ((algebraMap S Sₜ).comp f) := by
+ rw [locally_iff_finite P f]
+ refine ⟨fun ⟨s, hsone, hs⟩ ↦ ⟨s, hsone, fun t ht Sₜ _ _ _ ↦ ?_⟩, fun ⟨s, hsone, hs⟩ ↦ ?_⟩
+ · let e : Localization.Away t ≃+* Sₜ :=
+ (IsLocalization.algEquiv (Submonoid.powers t) _ _).toRingEquiv
+ have : algebraMap S Sₜ = e.toRingHom.comp (algebraMap S (Localization.Away t)) :=
+ RingHom.ext (fun x ↦ (AlgEquiv.commutes (IsLocalization.algEquiv _ _ _) _).symm)
+ rw [this, RingHom.comp_assoc]
+ exact hP.left _ _ (hs t ht)
+ · exact ⟨s, hsone, fun t ht ↦ hs t ht _⟩
+
+/-- If `f` satisfies `P`, then in particular it satisfies `Locally P`. -/
+lemma locally_of (hP : RespectsIso P) (f : R →+* S) (hf : P f) : Locally P f := by
+ use {1}
+ let e : S ≃+* Localization.Away (1 : S) :=
+ (IsLocalization.atUnits S (Submonoid.powers 1) (by simp)).toRingEquiv
+ simp only [Set.mem_singleton_iff, forall_eq, Ideal.span_singleton_one, exists_const]
+ exact hP.left f e hf
+
+/-- If `P` is local on the target, then `Locally P` coincides with `P`. -/
+lemma locally_iff_of_localizationSpanTarget (hPi : RespectsIso P)
+ (hPs : OfLocalizationSpanTarget P) {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) :
+ Locally P f ↔ P f :=
+ ⟨fun ⟨s, hsone, hs⟩ ↦ hPs f s hsone (fun a ↦ hs a.val a.property), locally_of hPi f⟩
+
+section OfLocalizationSpanTarget
+
+/-- `Locally P` is local on the target. -/
+lemma locally_ofLocalizationSpanTarget (hP : RespectsIso P) :
+ OfLocalizationSpanTarget (Locally P) := by
+ intro R S _ _ f s hsone hs
+ choose t htone ht using hs
+ rw [locally_iff_exists hP]
+ refine ⟨(a : s) × t a, IsLocalization.Away.mulNumerator s t,
+ IsLocalization.Away.span_range_mulNumerator_eq_top hsone htone,
+ fun ⟨a, b⟩ ↦ Localization.Away b.val, inferInstance, inferInstance, fun ⟨a, b⟩ ↦ ?_, ?_⟩
+ · haveI : IsLocalization.Away ((algebraMap S (Localization.Away a.val))
+ (IsLocalization.Away.sec a.val b.val).1) (Localization.Away b.val) := by
+ apply IsLocalization.Away.of_associated (r := b.val)
+ rw [← IsLocalization.Away.sec_spec]
+ apply associated_mul_unit_right
+ rw [map_pow _ _]
+ exact IsUnit.pow _ (IsLocalization.Away.algebraMap_isUnit _)
+ apply IsLocalization.Away.mul' (Localization.Away a.val) (Localization.Away b.val)
+ · intro ⟨a, b⟩
+ rw [IsScalarTower.algebraMap_eq S (Localization.Away a.val) (Localization.Away b.val)]
+ apply ht _ _ b.property
+
+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/RingHom/Surjective.lean b/Mathlib/RingTheory/RingHom/Surjective.lean
index 11bc6f10f5271..b20eeffe62179 100644
--- a/Mathlib/RingTheory/RingHom/Surjective.lean
+++ b/Mathlib/RingTheory/RingHom/Surjective.lean
@@ -3,12 +3,22 @@ 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.LocalProperties
+import Mathlib.RingTheory.LocalProperties.Basic
/-!
# The meta properties of surjective ring homomorphisms.
+## Main results
+
+Let `R` be a commutative ring, `M` be a submonoid of `R`.
+
+* `surjective_localizationPreserves` : `M⁻¹R →+* M⁻¹S` is surjective if `R →+* S` is surjective.
+* `surjective_ofLocalizationSpan` : `R →+* S` is surjective if there exists a set `{ r }` that
+ spans `R` such that `Rᵣ →+* Sᵣ` is surjective.
+* `surjective_localRingHom_of_surjective` : A surjective ring homomorphism `R →+* S` induces a
+ surjective homomorphism `R_{f⁻¹(P)} →+* S_P` for every prime ideal `P` of `S`.
+
-/
@@ -18,6 +28,8 @@ open scoped TensorProduct
open TensorProduct Algebra.TensorProduct
+universe u
+
local notation "surjective" => fun {X Y : Type _} [CommRing X] [CommRing Y] => fun f : X →+* Y =>
Function.Surjective f
@@ -40,28 +52,41 @@ theorem surjective_stableUnderBaseChange : StableUnderBaseChange surjective := b
rw [TensorProduct.smul_tmul, Algebra.algebraMap_eq_smul_one]
| add x y ex ey => obtain ⟨⟨x, rfl⟩, ⟨y, rfl⟩⟩ := ex, ey; exact ⟨x + y, map_add _ x y⟩
+/-- `M⁻¹R →+* M⁻¹S` is surjective if `R →+* S` is surjective. -/
+theorem surjective_localizationPreserves :
+ LocalizationPreserves surjective := by
+ introv R H x
+ obtain ⟨x, ⟨_, s, hs, rfl⟩, rfl⟩ := IsLocalization.mk'_surjective (M.map f) x
+ obtain ⟨y, rfl⟩ := H x
+ use IsLocalization.mk' R' y ⟨s, hs⟩
+ rw [IsLocalization.map_mk']
+
+/-- `R →+* S` is surjective if there exists a set `{ r }` that spans `R` such that
+ `Rᵣ →+* Sᵣ` is surjective. -/
theorem surjective_ofLocalizationSpan : OfLocalizationSpan surjective := by
- introv R hs H
+ introv R e H
+ rw [← Set.range_iff_surjective, Set.eq_univ_iff_forall]
letI := f.toAlgebra
- show Function.Surjective (Algebra.ofId R S)
- rw [← Algebra.range_top_iff_surjective, eq_top_iff]
- rintro x -
- obtain ⟨l, hl⟩ :=
- (Finsupp.mem_span_iff_linearCombination R s 1).mp (show _ ∈ Ideal.span s by rw [hs]; trivial)
- fapply
- Subalgebra.mem_of_finset_sum_eq_one_of_pow_smul_mem _ l.support (fun x : s => f x) fun x : s =>
- f (l x)
- · simp_rw [← _root_.map_mul, ← map_sum, ← f.map_one]; exact f.congr_arg hl
- · exact fun _ => Set.mem_range_self _
- · exact fun _ => Set.mem_range_self _
- · intro r
- obtain ⟨y, hy⟩ := H r (IsLocalization.mk' _ x (1 : Submonoid.powers (f r)))
- obtain ⟨z, ⟨_, n, rfl⟩, rfl⟩ := IsLocalization.mk'_surjective (Submonoid.powers (r : R)) y
- erw [IsLocalization.map_mk', IsLocalization.eq] at hy
- obtain ⟨⟨_, m, rfl⟩, hm⟩ := hy
- refine ⟨m + n, ?_⟩
- dsimp at hm ⊢
- simp_rw [_root_.one_mul, ← _root_.mul_assoc, ← map_pow, ← f.map_mul, ← pow_add, map_pow] at hm
- exact ⟨_, hm⟩
+ intro x
+ apply Submodule.mem_of_span_eq_top_of_smul_pow_mem
+ (LinearMap.range (Algebra.linearMap R S)) s e
+ intro r
+ obtain ⟨a, e'⟩ := H r (algebraMap _ _ x)
+ obtain ⟨b, ⟨_, n, rfl⟩, rfl⟩ := IsLocalization.mk'_surjective (Submonoid.powers (r : R)) a
+ erw [IsLocalization.map_mk'] at e'
+ rw [eq_comm, IsLocalization.eq_mk'_iff_mul_eq, Subtype.coe_mk, Subtype.coe_mk, ← map_mul] at e'
+ obtain ⟨⟨_, n', rfl⟩, e''⟩ := (IsLocalization.eq_iff_exists (Submonoid.powers (f r)) _).mp e'
+ dsimp only at e''
+ rw [mul_comm x, ← mul_assoc, ← map_pow, ← map_mul, ← map_mul, ← pow_add] at e''
+ exact ⟨n' + n, _, e''.symm⟩
+
+/-- A surjective ring homomorphism `R →+* S` induces a surjective homomorphism `R_{f⁻¹(P)} →+* S_P`
+for every prime ideal `P` of `S`. -/
+theorem surjective_localRingHom_of_surjective {R S : Type u} [CommRing R] [CommRing S]
+ (f : R →+* S) (h : Function.Surjective f) (P : Ideal S) [P.IsPrime] :
+ Function.Surjective (Localization.localRingHom (P.comap f) P f rfl) :=
+ have : IsLocalization (Submonoid.map f (Ideal.comap f P).primeCompl) (Localization.AtPrime P) :=
+ (Submonoid.map_comap_eq_of_surjective h P.primeCompl).symm ▸ Localization.isLocalization
+ surjective_localizationPreserves _ _ _ _ h
end RingHom
diff --git a/Mathlib/RingTheory/RingHomProperties.lean b/Mathlib/RingTheory/RingHomProperties.lean
index 280f3184fd167..7008cd0ef9a74 100644
--- a/Mathlib/RingTheory/RingHomProperties.lean
+++ b/Mathlib/RingTheory/RingHomProperties.lean
@@ -179,15 +179,17 @@ variable {P}
lemma toMorphismProperty_respectsIso_iff :
RespectsIso P ↔ (toMorphismProperty P).RespectsIso := by
- refine ⟨fun h ↦ ⟨?_, ?_⟩, fun h ↦ ⟨?_, ?_⟩⟩
+ refine ⟨fun h ↦ MorphismProperty.RespectsIso.mk _ ?_ ?_, fun h ↦ ⟨?_, ?_⟩⟩
· intro X Y Z e f hf
exact h.right f e.commRingCatIsoToRingEquiv hf
· intro X Y Z e f hf
exact h.left f e.commRingCatIsoToRingEquiv hf
+ · intro X Y Z _ _ _ f e hf
+ exact MorphismProperty.RespectsIso.postcomp (toMorphismProperty P)
+ e.toCommRingCatIso.hom (CommRingCat.ofHom f) hf
· intro X Y Z _ _ _ f e
- exact h.postcomp e.toCommRingCatIso (CommRingCat.ofHom f)
- · intro X Y Z _ _ _ f e
- exact h.precomp e.toCommRingCatIso (CommRingCat.ofHom f)
+ exact MorphismProperty.RespectsIso.precomp (toMorphismProperty P)
+ e.toCommRingCatIso.hom (CommRingCat.ofHom f)
end ToMorphismProperty
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 04f0e45847dbc..b90cc6d9efb53 100644
--- a/Mathlib/RingTheory/RootsOfUnity/Basic.lean
+++ b/Mathlib/RingTheory/RootsOfUnity/Basic.lean
@@ -442,7 +442,7 @@ then there is a `b`-th primitive root of unity in `R`. -/
theorem pow {n : ℕ} {a b : ℕ} (hn : 0 < n) (h : IsPrimitiveRoot ζ n) (hprod : n = a * b) :
IsPrimitiveRoot (ζ ^ a) b := by
subst n
- simp only [iff_def, ← pow_mul, h.pow_eq_one, eq_self_iff_true, true_and_iff]
+ simp only [iff_def, ← pow_mul, h.pow_eq_one, eq_self_iff_true, true_and]
intro l hl
-- Porting note: was `by rintro rfl; simpa only [Nat.not_lt_zero, zero_mul] using hn`
have ha0 : a ≠ 0 := left_ne_zero_of_mul hn.ne'
@@ -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,26 +856,26 @@ 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
refine Finset.card_bij (fun i _ ↦ ζ ^ i) ?_ ?_ ?_
- · simp only [true_and_iff, and_imp, mem_filter, mem_range, mem_univ]
+ · simp only [and_imp, mem_filter, mem_range, mem_univ]
rintro i - hi
rw [mem_primitiveRoots (Nat.pos_of_ne_zero h0)]
exact h.pow_of_coprime i hi.symm
- · simp only [true_and_iff, and_imp, mem_filter, mem_range, mem_univ]
+ · simp only [and_imp, mem_filter, mem_range, mem_univ]
rintro i hi - j hj - H
exact h.pow_inj hi hj H
- · simp only [exists_prop, true_and_iff, mem_filter, mem_range, mem_univ]
+ · simp only [exists_prop, mem_filter, mem_range, mem_univ]
intro ξ hξ
rw [mem_primitiveRoots (Nat.pos_of_ne_zero h0),
h.isPrimitiveRoot_iff (Nat.pos_of_ne_zero h0)] at hξ
@@ -898,7 +898,7 @@ theorem nthRoots_one_eq_biUnion_primitiveRoots' {ζ : R} {n : ℕ+} (h : IsPrimi
· intro x
simp only [nthRootsFinset, ← Multiset.toFinset_eq (nthRoots_one_nodup h), exists_prop,
Finset.mem_biUnion, Finset.mem_filter, Finset.mem_range, mem_nthRoots, Finset.mem_mk,
- Nat.mem_divisors, and_true_iff, Ne, PNat.ne_zero, PNat.pos, not_false_iff]
+ Nat.mem_divisors, and_true, Ne, PNat.ne_zero, PNat.pos, not_false_iff]
rintro ⟨a, ⟨d, hd⟩, ha⟩
have hazero : 0 < a := by
contrapose! hd with ha0
diff --git a/Mathlib/RingTheory/RootsOfUnity/Complex.lean b/Mathlib/RingTheory/RootsOfUnity/Complex.lean
index ec56155951282..a11bd30bfad0a 100644
--- a/Mathlib/RingTheory/RootsOfUnity/Complex.lean
+++ b/Mathlib/RingTheory/RootsOfUnity/Complex.lean
@@ -168,7 +168,7 @@ theorem IsPrimitiveRoot.arg {n : ℕ} {ζ : ℂ} (h : IsPrimitiveRoot ζ n) (hn
exact mul_nonpos_of_nonpos_of_nonneg (sub_nonpos.mpr <| mod_cast h.le)
(div_nonneg (by simp [Real.pi_pos.le]) <| by simp)
rw [← mul_rotate', mul_div_assoc, neg_lt, ← mul_neg, mul_lt_iff_lt_one_right Real.pi_pos, ←
- neg_div, ← neg_mul, neg_sub, div_lt_iff, one_mul, sub_mul, sub_lt_comm, ← mul_sub_one]
+ neg_div, ← neg_mul, neg_sub, div_lt_iff₀, one_mul, sub_mul, sub_lt_comm, ← mul_sub_one]
· norm_num
exact mod_cast not_le.mp h₂
· exact Nat.cast_pos.mpr hn.bot_lt
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 5bc001188d6d1..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
@@ -163,7 +166,7 @@ theorem isSimpleModule_self_iff_isUnit :
exact ⟨⟨x, y, left_inv_eq_right_inv hzy hyx ▸ hzy, hyx⟩, rfl⟩
theorem isSimpleModule_iff_finrank_eq_one {R} [DivisionRing R] [Module R M] :
- IsSimpleModule R M ↔ FiniteDimensional.finrank R M = 1 :=
+ IsSimpleModule R M ↔ Module.finrank R M = 1 :=
⟨fun h ↦ have := h.nontrivial; have ⟨v, hv⟩ := exists_ne (0 : M)
(finrank_eq_one_iff_of_nonzero' v hv).mpr (IsSimpleModule.toSpanSingleton_surjective R hv),
is_simple_module_of_finrank_eq_one⟩
@@ -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/SimpleRing/Basic.lean b/Mathlib/RingTheory/SimpleRing/Basic.lean
new file mode 100644
index 0000000000000..3f9711cafff02
--- /dev/null
+++ b/Mathlib/RingTheory/SimpleRing/Basic.lean
@@ -0,0 +1,87 @@
+/-
+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.RingTheory.SimpleRing.Defs
+import Mathlib.Algebra.Field.Equiv
+import Mathlib.Algebra.Ring.Subring.Basic
+
+/-! # Basic Properties of Simple rings
+
+A ring `R` is **simple** if it has only two two-sided ideals, namely `⊥` and `⊤`.
+
+## Main results
+
+- `IsSimpleRing.nontrivial`: simple rings are non-trivial.
+- `DivisionRing.IsSimpleRing`: division rings are simple.
+- `IsSimpleRing.center_isField`: the center of a simple ring is a field.
+
+-/
+
+variable (R : Type*) [NonUnitalNonAssocRing R]
+
+namespace IsSimpleRing
+
+variable {R}
+
+instance [IsSimpleRing R] : IsSimpleOrder (TwoSidedIdeal R) := IsSimpleRing.simple
+
+instance [simple : IsSimpleRing R] : Nontrivial R := by
+ obtain ⟨x, hx⟩ := SetLike.exists_of_lt (bot_lt_top : (⊥ : TwoSidedIdeal R) < ⊤)
+ have h (hx : x = 0) : False := by simp_all [TwoSidedIdeal.zero_mem]
+ use x, 0, h
+
+lemma one_mem_of_ne_bot {A : Type*} [NonAssocRing A] [IsSimpleRing A] (I : TwoSidedIdeal A)
+ (hI : I ≠ ⊥) : (1 : A) ∈ I :=
+ (eq_bot_or_eq_top I).resolve_left hI ▸ ⟨⟩
+
+lemma one_mem_of_ne_zero_mem {A : Type*} [NonAssocRing A] [IsSimpleRing A] (I : TwoSidedIdeal A)
+ {x : A} (hx : x ≠ 0) (hxI : x ∈ I) : (1 : A) ∈ I :=
+ one_mem_of_ne_bot I (by rintro rfl; exact hx hxI)
+
+lemma of_eq_bot_or_eq_top [Nontrivial R] (h : ∀ I : TwoSidedIdeal R, I = ⊥ ∨ I = ⊤) :
+ IsSimpleRing R where
+ simple := { eq_bot_or_eq_top := h }
+
+instance _root_.DivisionRing.isSimpleRing (A : Type*) [DivisionRing A] : IsSimpleRing A :=
+ .of_eq_bot_or_eq_top <| fun I ↦ by
+ rw [or_iff_not_imp_left, ← I.one_mem_iff]
+ intro H
+ obtain ⟨x, hx1, hx2 : x ≠ 0⟩ := SetLike.exists_of_lt (bot_lt_iff_ne_bot.mpr H : ⊥ < I)
+ simpa [inv_mul_cancel₀ hx2] using I.mul_mem_left x⁻¹ _ hx1
+
+open TwoSidedIdeal in
+lemma isField_center (A : Type*) [Ring A] [IsSimpleRing A] : IsField (Subring.center A) where
+ exists_pair_ne := ⟨0, 1, zero_ne_one⟩
+ mul_comm := mul_comm
+ mul_inv_cancel := by
+ rintro ⟨x, hx1⟩ hx2
+ rw [Subring.mem_center_iff] at hx1
+ replace hx2 : x ≠ 0 := by simpa [Subtype.ext_iff] using hx2
+ -- Todo: golf the following `let` once `TwoSidedIdeal.span` is defined
+ let I := TwoSidedIdeal.mk' (Set.range (x * ·)) ⟨0, by simp⟩
+ (by rintro _ _ ⟨x, rfl⟩ ⟨y, rfl⟩; exact ⟨x + y, mul_add _ _ _⟩)
+ (by rintro _ ⟨x, rfl⟩; exact ⟨-x, by simp⟩)
+ (by rintro a _ ⟨c, rfl⟩; exact ⟨a * c, by dsimp; rw [← mul_assoc, ← hx1, mul_assoc]⟩)
+ (by rintro _ b ⟨a, rfl⟩; exact ⟨a * b, by dsimp; rw [← mul_assoc, ← hx1, mul_assoc]⟩)
+ have mem : 1 ∈ I := one_mem_of_ne_zero_mem I hx2 (by simpa [I, mem_mk'] using ⟨1, by simp⟩)
+ simp only [TwoSidedIdeal.mem_mk', Set.mem_range, I] at mem
+ obtain ⟨y, hy⟩ := mem
+ refine ⟨⟨y, Subring.mem_center_iff.2 fun a ↦ ?_⟩, by ext; exact hy⟩
+ calc a * y
+ _ = (x * y) * a * y := by rw [hy, one_mul]
+ _ = (y * x) * a * y := by rw [hx1]
+ _ = y * (x * a) * y := by rw [mul_assoc y x a]
+ _ = y * (a * x) * y := by rw [hx1]
+ _ = y * ((a * x) * y) := by rw [mul_assoc]
+ _ = y * (a * (x * y)) := by rw [mul_assoc a x y]
+ _ = y * a := by rw [hy, mul_one]
+
+end IsSimpleRing
+
+lemma isSimpleRing_iff_isField (A : Type*) [CommRing A] : IsSimpleRing A ↔ IsField A :=
+ ⟨fun _ ↦ Subring.topEquiv.symm.toMulEquiv.isField _ <| by
+ rw [← Subring.center_eq_top A]; exact IsSimpleRing.isField_center A,
+ fun h ↦ letI := h.toField; inferInstance⟩
diff --git a/Mathlib/RingTheory/SimpleRing/Defs.lean b/Mathlib/RingTheory/SimpleRing/Defs.lean
new file mode 100644
index 0000000000000..ce50f0bbc7460
--- /dev/null
+++ b/Mathlib/RingTheory/SimpleRing/Defs.lean
@@ -0,0 +1,25 @@
+/-
+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.RingTheory.TwoSidedIdeal.Lattice
+import Mathlib.Order.Atoms
+
+/-! # Simple rings
+
+A ring `R` is **simple** if it has only two two-sided ideals, namely `⊥` and `⊤`.
+
+## Main definitions
+
+- `IsSimpleRing`: a predicate expressing that a ring is simple.
+
+-/
+
+
+/--
+A ring `R` is **simple** if it has only two two-sided ideals, namely `⊥` and `⊤`.
+-/
+class IsSimpleRing (R : Type*) [NonUnitalNonAssocRing R] : Prop where
+ simple : IsSimpleOrder (TwoSidedIdeal R)
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/Kaehler.lean b/Mathlib/RingTheory/Smooth/Kaehler.lean
index 0e20b7e631d12..e11be1b55e317 100644
--- a/Mathlib/RingTheory/Smooth/Kaehler.lean
+++ b/Mathlib/RingTheory/Smooth/Kaehler.lean
@@ -112,7 +112,7 @@ lemma retractionOfSectionOfKerSqZero_tmul_D (s : S) (t : P) :
lemma retractionOfSectionOfKerSqZero_comp_kerToTensor :
(retractionOfSectionOfKerSqZero g hf' hg).comp (kerToTensor R P S) = LinearMap.id := by
- ext x; simp [(RingHom.mem_ker _).mp x.2]
+ ext x; simp [RingHom.mem_ker.mp x.2]
end ofSection
@@ -172,7 +172,7 @@ lemma toAlgHom_comp_sectionOfRetractionKerToTensorAux :
(sectionOfRetractionKerToTensorAux l hl σ hσ hf') = AlgHom.id _ _ := by
ext x
obtain ⟨x, rfl⟩ := hf x
- simp [sectionOfRetractionKerToTensorAux_algebraMap, (RingHom.mem_ker _).mp]
+ simp [sectionOfRetractionKerToTensorAux_algebraMap, RingHom.mem_ker.mp]
/--
Given a surjective algebra homomorphism `f : P →ₐ[R] S` with square-zero kernel `I`.
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 33b0d6650afea..8d4159379686e 100644
--- a/Mathlib/RingTheory/Smooth/StandardSmooth.lean
+++ b/Mathlib/RingTheory/Smooth/StandardSmooth.lean
@@ -62,12 +62,6 @@ Finally, for ring homomorphisms we define:
## TODO
-- Show that the canonical presentation for localization away from an element is standard smooth
- of relative dimension 0.
-- Show that the base change of a submersive presentation is submersive of equal relative
- dimension.
-- Show that the composition of submersive presentations of relative dimensions `n` and `m` is
- submersive of relative dimension `n + m`.
- Show that the module of Kaehler differentials of a standard smooth `R`-algebra `S` of relative
dimension `n` is `S`-free of rank `n`. In particular this shows that the relative dimension
is independent of the choice of the standard smooth presentation.
@@ -89,14 +83,13 @@ in June 2024.
universe t t' w w' u v
-open TensorProduct
+open TensorProduct MvPolynomial Classical
-variable (n : ℕ)
+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`
@@ -163,10 +156,231 @@ lemma jacobian_eq_jacobiMatrix_det : P.jacobian = algebraMap P.Ring S P.jacobiMa
lemma jacobiMatrix_apply (i j : P.rels) :
P.jacobiMatrix i j = MvPolynomial.pderiv (P.map i) (P.relation j) := by
- simp [jacobiMatrix, LinearMap.toMatrix, differential]
+ simp [jacobiMatrix, LinearMap.toMatrix, differential, basis]
end Matrix
+section Constructions
+
+/-- If `algebraMap R S` is bijective, the empty generators are a pre-submersive
+presentation with no relations. -/
+noncomputable def ofBijectiveAlgebraMap (h : Function.Bijective (algebraMap R S)) :
+ PreSubmersivePresentation.{t, w} R S where
+ toPresentation := Presentation.ofBijectiveAlgebraMap.{t, w} h
+ map := PEmpty.elim
+ map_inj (a b : PEmpty) h := by contradiction
+ relations_finite := inferInstanceAs (Finite PEmpty.{t + 1})
+
+instance (h : Function.Bijective (algebraMap R S)) : Fintype (ofBijectiveAlgebraMap h).vars :=
+ inferInstanceAs (Fintype PEmpty)
+
+instance (h : Function.Bijective (algebraMap R S)) : Fintype (ofBijectiveAlgebraMap h).rels :=
+ inferInstanceAs (Fintype PEmpty)
+
+@[simp]
+lemma ofBijectiveAlgebraMap_jacobian (h : Function.Bijective (algebraMap R S)) :
+ (ofBijectiveAlgebraMap h).jacobian = 1 := by
+ have : (algebraMap (ofBijectiveAlgebraMap h).Ring S).mapMatrix
+ (ofBijectiveAlgebraMap h).jacobiMatrix = 1 := by
+ ext (i j : PEmpty)
+ contradiction
+ rw [jacobian_eq_jacobiMatrix_det, RingHom.map_det, this, Matrix.det_one]
+
+section Localization
+
+variable (r : R) [IsLocalization.Away r S]
+
+variable (S) in
+/-- If `S` is the localization of `R` at `r`, this is the canonical submersive presentation
+of `S` as `R`-algebra. -/
+@[simps map]
+noncomputable def localizationAway : PreSubmersivePresentation R S where
+ __ := Presentation.localizationAway S r
+ map _ := ()
+ map_inj _ _ h := h
+ relations_finite := inferInstanceAs <| Finite Unit
+
+instance : Fintype (localizationAway S r).rels :=
+ inferInstanceAs (Fintype Unit)
+
+instance : DecidableEq (localizationAway S r).rels :=
+ inferInstanceAs (DecidableEq Unit)
+
+@[simp]
+lemma localizationAway_jacobiMatrix :
+ (localizationAway S r).jacobiMatrix = Matrix.diagonal (fun () ↦ MvPolynomial.C r) := by
+ have h : (pderiv ()) (C r * X () - 1) = C r := by simp
+ ext (i : Unit) (j : Unit) : 1
+ rwa [jacobiMatrix_apply]
+
+@[simp]
+lemma localizationAway_jacobian : (localizationAway S r).jacobian = algebraMap R S r := by
+ rw [jacobian_eq_jacobiMatrix_det, localizationAway_jacobiMatrix]
+ simp [show Fintype.card (localizationAway r (S := S)).rels = 1 from rfl]
+
+end Localization
+
+section Composition
+
+variable {T} [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S T]
+variable (Q : PreSubmersivePresentation S T) (P : PreSubmersivePresentation R S)
+
+/-- Given an `R`-algebra `S` and an `S`-algebra `T` with pre-submersive presentations,
+this is the canonical pre-submersive presentation of `T` as an `R`-algebra. -/
+@[simps map]
+noncomputable def comp : PreSubmersivePresentation R T where
+ __ := Q.toPresentation.comp P.toPresentation
+ map := Sum.elim (fun rq ↦ Sum.inl <| Q.map rq) (fun rp ↦ Sum.inr <| P.map rp)
+ map_inj := Function.Injective.sum_elim ((Sum.inl_injective).comp (Q.map_inj))
+ ((Sum.inr_injective).comp (P.map_inj)) <| by simp
+ relations_finite := inferInstanceAs <| Finite (Q.rels ⊕ P.rels)
+
+/-- The dimension of the composition of two finite submersive presentations is
+the sum of the dimensions. -/
+lemma dimension_comp_eq_dimension_add_dimension [Q.IsFinite] [P.IsFinite] :
+ (Q.comp P).dimension = Q.dimension + P.dimension := by
+ simp only [Presentation.dimension]
+ erw [Presentation.comp_rels, Generators.comp_vars]
+ have : Nat.card P.rels ≤ Nat.card P.vars :=
+ card_relations_le_card_vars_of_isFinite P
+ have : Nat.card Q.rels ≤ Nat.card Q.vars :=
+ card_relations_le_card_vars_of_isFinite Q
+ simp only [Nat.card_sum]
+ omega
+
+section
+
+/-!
+### Jacobian of composition
+
+Let `S` be an `R`-algebra and `T` be an `S`-algebra with presentations `P` and `Q` respectively.
+In this section we compute the jacobian of the composition of `Q` and `P` to be
+the product of the jacobians. For this we use a block decomposition of the jacobi matrix and show
+that the upper-right block vanishes, the upper-left block has determinant jacobian of `Q` and
+the lower-right block has determinant jacobian of `P`.
+
+-/
+
+variable [Fintype (Q.comp P).rels]
+
+private lemma jacobiMatrix_comp_inl_inr (i : Q.rels) (j : P.rels) :
+ (Q.comp P).jacobiMatrix (Sum.inl i) (Sum.inr j) = 0 := by
+ rw [jacobiMatrix_apply]
+ refine MvPolynomial.pderiv_eq_zero_of_not_mem_vars (fun hmem ↦ ?_)
+ apply MvPolynomial.vars_rename at hmem
+ simp at hmem
+
+private lemma jacobiMatrix_comp_₁₂ : (Q.comp P).jacobiMatrix.toBlocks₁₂ = 0 := by
+ ext i j : 1
+ simp [Matrix.toBlocks₁₂, jacobiMatrix_comp_inl_inr]
+
+section Q
+
+variable [Fintype Q.rels]
+
+private lemma jacobiMatrix_comp_inl_inl (i j : Q.rels) :
+ aeval (Sum.elim X (MvPolynomial.C ∘ P.val))
+ ((Q.comp P).jacobiMatrix (Sum.inl j) (Sum.inl i)) = Q.jacobiMatrix j i := by
+ rw [jacobiMatrix_apply, jacobiMatrix_apply, comp_map, Sum.elim_inl,
+ ← Q.comp_aeval_relation_inl P.toPresentation]
+ apply aeval_sum_elim_pderiv_inl
+
+private lemma jacobiMatrix_comp_₁₁_det :
+ (aeval (Q.comp P).val) (Q.comp P).jacobiMatrix.toBlocks₁₁.det = Q.jacobian := by
+ rw [jacobian_eq_jacobiMatrix_det, AlgHom.map_det (aeval (Q.comp P).val), RingHom.map_det]
+ congr
+ ext i j : 1
+ simp only [Matrix.map_apply, RingHom.mapMatrix_apply, ← Q.jacobiMatrix_comp_inl_inl P]
+ apply aeval_sum_elim
+
+end Q
+
+section P
+
+variable [Fintype P.rels]
+
+private lemma jacobiMatrix_comp_inr_inr (i j : P.rels) :
+ (Q.comp P).jacobiMatrix (Sum.inr i) (Sum.inr j) =
+ MvPolynomial.rename Sum.inr (P.jacobiMatrix i j) := by
+ rw [jacobiMatrix_apply, jacobiMatrix_apply]
+ simp only [comp_map, Sum.elim_inr]
+ apply pderiv_rename Sum.inr_injective
+
+private lemma jacobiMatrix_comp_₂₂_det :
+ (aeval (Q.comp P).val) (Q.comp P).jacobiMatrix.toBlocks₂₂.det = algebraMap S T P.jacobian := by
+ rw [jacobian_eq_jacobiMatrix_det]
+ rw [AlgHom.map_det (aeval (Q.comp P).val), RingHom.map_det, RingHom.map_det]
+ congr
+ ext i j : 1
+ simp only [Matrix.toBlocks₂₂, AlgHom.mapMatrix_apply, Matrix.map_apply, Matrix.of_apply,
+ RingHom.mapMatrix_apply, Generators.algebraMap_apply, map_aeval, coe_eval₂Hom]
+ rw [jacobiMatrix_comp_inr_inr, ← IsScalarTower.algebraMap_eq]
+ simp only [aeval, AlgHom.coe_mk, coe_eval₂Hom]
+ generalize P.jacobiMatrix i j = p
+ induction' p using MvPolynomial.induction_on with a p q hp hq p i hp
+ · simp only [algHom_C, algebraMap_eq, eval₂_C]
+ erw [MvPolynomial.eval₂_C]
+ · simp [hp, hq]
+ · simp only [map_mul, rename_X, eval₂_mul, hp, eval₂_X]
+ erw [Generators.comp_val]
+ simp
+
+end P
+
+end
+
+/-- The jacobian of the composition of presentations is the product of the jacobians. -/
+@[simp]
+lemma comp_jacobian_eq_jacobian_smul_jacobian : (Q.comp P).jacobian = P.jacobian • Q.jacobian := by
+ cases nonempty_fintype Q.rels
+ cases nonempty_fintype P.rels
+ letI : Fintype (Q.comp P).rels := inferInstanceAs <| Fintype (Q.rels ⊕ P.rels)
+ rw [jacobian_eq_jacobiMatrix_det, ← Matrix.fromBlocks_toBlocks ((Q.comp P).jacobiMatrix),
+ jacobiMatrix_comp_₁₂]
+ convert_to
+ (aeval (Q.comp P).val) (Q.comp P).jacobiMatrix.toBlocks₁₁.det *
+ (aeval (Q.comp P).val) (Q.comp P).jacobiMatrix.toBlocks₂₂.det = P.jacobian • Q.jacobian
+ · simp only [Generators.algebraMap_apply, ← map_mul]
+ congr
+ convert Matrix.det_fromBlocks_zero₁₂ (Q.comp P).jacobiMatrix.toBlocks₁₁
+ (Q.comp P).jacobiMatrix.toBlocks₂₁ (Q.comp P).jacobiMatrix.toBlocks₂₂
+ · rw [jacobiMatrix_comp_₁₁_det, jacobiMatrix_comp_₂₂_det, mul_comm, Algebra.smul_def]
+
+end Composition
+
+section BaseChange
+
+variable (T) [CommRing T] [Algebra R T] (P : PreSubmersivePresentation R S)
+
+/-- If `P` is a pre-submersive presentation of `S` over `R` and `T` is an `R`-algebra, we
+obtain a natural pre-submersive presentation of `T ⊗[R] S` over `T`. -/
+noncomputable def baseChange : PreSubmersivePresentation T (T ⊗[R] S) where
+ __ := P.toPresentation.baseChange T
+ map := P.map
+ map_inj := P.map_inj
+ relations_finite := P.relations_finite
+
+@[simp]
+lemma baseChange_jacobian : (P.baseChange T).jacobian = 1 ⊗ₜ P.jacobian := by
+ classical
+ cases nonempty_fintype P.rels
+ letI : Fintype (P.baseChange T).rels := inferInstanceAs <| Fintype P.rels
+ simp_rw [jacobian_eq_jacobiMatrix_det]
+ have h : (baseChange T P).jacobiMatrix =
+ (MvPolynomial.map (algebraMap R T)).mapMatrix P.jacobiMatrix := by
+ ext i j : 1
+ simp only [baseChange, jacobiMatrix_apply, Presentation.baseChange_relation,
+ RingHom.mapMatrix_apply, Matrix.map_apply]
+ erw [MvPolynomial.pderiv_map]
+ rfl
+ rw [h]
+ erw [← RingHom.map_det, aeval_map_algebraMap]
+ apply aeval_one_tmul
+
+end BaseChange
+
+end Constructions
+
end PreSubmersivePresentation
/--
@@ -180,6 +394,75 @@ structure SubmersivePresentation extends PreSubmersivePresentation.{t, w} R S wh
attribute [instance] SubmersivePresentation.isFinite
+namespace SubmersivePresentation
+
+open PreSubmersivePresentation
+
+section Constructions
+
+variable {R S} in
+/-- If `algebraMap R S` is bijective, the empty generators are a submersive
+presentation with no relations. -/
+noncomputable def ofBijectiveAlgebraMap (h : Function.Bijective (algebraMap R S)) :
+ SubmersivePresentation.{t, w} R S where
+ __ := PreSubmersivePresentation.ofBijectiveAlgebraMap.{t, w} h
+ jacobian_isUnit := by
+ rw [ofBijectiveAlgebraMap_jacobian]
+ exact isUnit_one
+ isFinite := Presentation.ofBijectiveAlgebraMap_isFinite h
+
+/-- The canonical submersive `R`-presentation of `R` with no generators and no relations. -/
+noncomputable def id : SubmersivePresentation.{t, w} R R :=
+ ofBijectiveAlgebraMap Function.bijective_id
+
+section Composition
+
+variable {R S T} [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S T]
+variable (Q : SubmersivePresentation S T) (P : SubmersivePresentation R S)
+
+/-- Given an `R`-algebra `S` and an `S`-algebra `T` with submersive presentations,
+this is the canonical submersive presentation of `T` as an `R`-algebra. -/
+noncomputable def comp : SubmersivePresentation R T where
+ __ := Q.toPreSubmersivePresentation.comp P.toPreSubmersivePresentation
+ jacobian_isUnit := by
+ rw [comp_jacobian_eq_jacobian_smul_jacobian, Algebra.smul_def, IsUnit.mul_iff]
+ exact ⟨RingHom.isUnit_map _ <| P.jacobian_isUnit, Q.jacobian_isUnit⟩
+ isFinite := Presentation.comp_isFinite Q.toPresentation P.toPresentation
+
+end Composition
+
+section Localization
+
+variable {R} (r : R) [IsLocalization.Away r S]
+
+/-- If `S` is the localization of `R` at `r`, this is the canonical submersive presentation
+of `S` as `R`-algebra. -/
+noncomputable def localizationAway : SubmersivePresentation R S where
+ __ := PreSubmersivePresentation.localizationAway S r
+ jacobian_isUnit := by
+ rw [localizationAway_jacobian]
+ apply IsLocalization.map_units' (⟨r, 1, by simp⟩ : Submonoid.powers r)
+ isFinite := Presentation.localizationAway_isFinite r
+
+end Localization
+
+section BaseChange
+
+variable (T) [CommRing T] [Algebra R T] (P : SubmersivePresentation R S)
+
+/-- If `P` is a submersive presentation of `S` over `R` and `T` is an `R`-algebra, we
+obtain a natural submersive presentation of `T ⊗[R] S` over `T`. -/
+noncomputable def baseChange : SubmersivePresentation T (T ⊗[R] S) where
+ toPreSubmersivePresentation := P.toPreSubmersivePresentation.baseChange T
+ jacobian_isUnit := P.baseChange_jacobian T ▸ P.jacobian_isUnit.map TensorProduct.includeRight
+ isFinite := Presentation.baseChange_isFinite T P.toPresentation
+
+end BaseChange
+
+end Constructions
+
+end SubmersivePresentation
+
/--
An `R`-algebra `S` is called standard smooth, if there
exists a submersive presentation.
@@ -211,27 +494,64 @@ lemma IsStandardSmoothOfRelativeDimension.isStandardSmooth
IsStandardSmooth.{t, w} R S :=
⟨‹IsStandardSmoothOfRelativeDimension n R S›.out.nonempty⟩
-end Algebra
+lemma IsStandardSmoothOfRelativeDimension.of_algebraMap_bijective
+ (h : Function.Bijective (algebraMap R S)) :
+ IsStandardSmoothOfRelativeDimension.{t, w} 0 R S :=
+ ⟨SubmersivePresentation.ofBijectiveAlgebraMap h, Presentation.ofBijectiveAlgebraMap_dimension h⟩
+
+variable (R) in
+instance IsStandardSmoothOfRelativeDimension.id :
+ IsStandardSmoothOfRelativeDimension.{t, w} 0 R R :=
+ IsStandardSmoothOfRelativeDimension.of_algebraMap_bijective Function.bijective_id
-namespace RingHom
+section Composition
-variable {R : Type u} [CommRing R]
-variable {S : Type v} [CommRing S]
+variable (R S T) [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S T]
-/-- 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
+lemma IsStandardSmooth.trans [IsStandardSmooth.{t, w} R S] [IsStandardSmooth.{t', w'} S T] :
+ IsStandardSmooth.{max t t', max w w'} R T where
+ out := by
+ obtain ⟨⟨P⟩⟩ := ‹IsStandardSmooth R S›
+ obtain ⟨⟨Q⟩⟩ := ‹IsStandardSmooth S T›
+ exact ⟨Q.comp P⟩
-/-- 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.trans [IsStandardSmoothOfRelativeDimension.{t, w} n R S]
+ [IsStandardSmoothOfRelativeDimension.{t', w'} m S T] :
+ IsStandardSmoothOfRelativeDimension.{max t t', max w w'} (m + n) R T where
+ out := by
+ obtain ⟨P, hP⟩ := ‹IsStandardSmoothOfRelativeDimension n R S›
+ obtain ⟨Q, hQ⟩ := ‹IsStandardSmoothOfRelativeDimension m S T›
+ refine ⟨Q.comp P, hP ▸ hQ ▸ ?_⟩
+ apply PreSubmersivePresentation.dimension_comp_eq_dimension_add_dimension
-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 Composition
-end RingHom
+lemma IsStandardSmooth.localization_away (r : R) [IsLocalization.Away r S] :
+ IsStandardSmooth.{0, 0} R S where
+ out := ⟨SubmersivePresentation.localizationAway S r⟩
+
+lemma IsStandardSmoothOfRelativeDimension.localization_away (r : R) [IsLocalization.Away r S] :
+ IsStandardSmoothOfRelativeDimension.{0, 0} 0 R S where
+ out := ⟨SubmersivePresentation.localizationAway S r,
+ Presentation.localizationAway_dimension_zero r⟩
+
+section BaseChange
+
+variable (T) [CommRing T] [Algebra R T]
+
+instance IsStandardSmooth.baseChange [IsStandardSmooth.{t, w} R S] :
+ IsStandardSmooth.{t, w} T (T ⊗[R] S) where
+ out := by
+ obtain ⟨⟨P⟩⟩ := ‹IsStandardSmooth R S›
+ exact ⟨P.baseChange R S T⟩
+
+instance IsStandardSmoothOfRelativeDimension.baseChange
+ [IsStandardSmoothOfRelativeDimension.{t, w} n R S] :
+ IsStandardSmoothOfRelativeDimension.{t, w} n T (T ⊗[R] S) where
+ out := by
+ obtain ⟨P, hP⟩ := ‹IsStandardSmoothOfRelativeDimension n R S›
+ exact ⟨P.baseChange R S T, hP⟩
+
+end BaseChange
+
+end Algebra
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 31824342a497b..15539b8a077a5 100644
--- a/Mathlib/RingTheory/TensorProduct/Basic.lean
+++ b/Mathlib/RingTheory/TensorProduct/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Johan Commelin
+Authors: Kim Morrison, Johan Commelin
-/
import Mathlib.GroupTheory.MonoidLocalization.Basic
import Mathlib.LinearAlgebra.FreeModule.Basic
@@ -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 10e82ca9edd87..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*}
@@ -229,6 +228,15 @@ lemma algebraTensorAlgEquiv_symm_monomial (m : σ →₀ ℕ) (a : A) :
nth_rw 2 [← mul_one a]
rw [Algebra.TensorProduct.tmul_mul_tmul]
+lemma aeval_one_tmul (f : σ → S) (p : MvPolynomial σ R) :
+ (aeval fun x ↦ (1 ⊗ₜ[R] f x : N ⊗[R] S)) p = 1 ⊗ₜ[R] (aeval f) p := by
+ induction' p using MvPolynomial.induction_on with a p q hp hq p i h
+ · simp only [map_C, algHom_C, Algebra.TensorProduct.algebraMap_apply,
+ RingHomCompTriple.comp_apply]
+ rw [← mul_one ((algebraMap R N) a), ← Algebra.smul_def, smul_tmul, Algebra.smul_def, mul_one]
+ · simp [hp, hq, tmul_add]
+ · simp [h]
+
end Algebra
end MvPolynomial
diff --git a/Mathlib/RingTheory/Trace/Basic.lean b/Mathlib/RingTheory/Trace/Basic.lean
index ee8a5a44c08f7..5d15d4fac0ac3 100644
--- a/Mathlib/RingTheory/Trace/Basic.lean
+++ b/Mathlib/RingTheory/Trace/Basic.lean
@@ -5,7 +5,7 @@ Authors: Anne Baanen
-/
import Mathlib.RingTheory.Trace.Defs
import Mathlib.LinearAlgebra.Determinant
-import Mathlib.FieldTheory.Galois
+import Mathlib.FieldTheory.Galois.Basic
import Mathlib.LinearAlgebra.Matrix.Charpoly.Minpoly
import Mathlib.LinearAlgebra.Vandermonde
import Mathlib.FieldTheory.Minpoly.MinpolyDiv
@@ -47,7 +47,7 @@ variable [Algebra R S] [Algebra R T]
variable {K L : Type*} [Field K] [Field L] [Algebra K L]
variable {ι κ : Type w} [Fintype ι]
-open FiniteDimensional
+open Module
open LinearMap (BilinForm)
open LinearMap
@@ -435,7 +435,7 @@ variable (K L)
theorem traceForm_nondegenerate [FiniteDimensional K L] [Algebra.IsSeparable K L] :
(traceForm K L).Nondegenerate :=
BilinForm.nondegenerate_of_det_ne_zero (traceForm K L) _
- (det_traceForm_ne_zero (FiniteDimensional.finBasis K L))
+ (det_traceForm_ne_zero (Module.finBasis K L))
theorem Algebra.trace_ne_zero [FiniteDimensional K L] [Algebra.IsSeparable K L] :
Algebra.trace K L ≠ 0 := by
@@ -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 86218f0b3ecff..936a15a3b644d 100644
--- a/Mathlib/RingTheory/Trace/Defs.lean
+++ b/Mathlib/RingTheory/Trace/Defs.lean
@@ -42,13 +42,13 @@ 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 FiniteDimensional
+open Module
open LinearMap (BilinForm)
open LinearMap
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 0358a0fe72767..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
@@ -45,6 +46,10 @@ section NonUnitalNonAssocRing
variable {R : Type*} [NonUnitalNonAssocRing R] (I : TwoSidedIdeal R)
+instance [Nontrivial R] : Nontrivial (TwoSidedIdeal R) := by
+ obtain ⟨I, J, h⟩ : Nontrivial (RingCon R) := inferInstance
+ exact ⟨⟨I⟩, ⟨J⟩, by contrapose! h; aesop⟩
+
instance setLike : SetLike (TwoSidedIdeal R) R where
coe t := {r | t.ringCon r 0}
coe_injective' := by
@@ -152,17 +157,18 @@ def mk' (carrier : Set R)
rw [show a + c - (b + d) = (a - b) + (c - d) by abel]
exact add_mem h1 h2 }
-lemma mem_mk' (carrier : Set R)
- (zero_mem : 0 ∈ carrier)
- (add_mem : ∀ {x y}, x ∈ carrier → y ∈ carrier → x + y ∈ carrier)
- (neg_mem : ∀ {x}, x ∈ carrier → -x ∈ carrier)
- (mul_mem_left : ∀ {x y}, y ∈ carrier → x * y ∈ carrier)
- (mul_mem_right : ∀ {x y}, x ∈ carrier → x * y ∈ carrier)
- (x : R) :
+@[simp]
+lemma mem_mk' (carrier : Set R) (zero_mem add_mem neg_mem mul_mem_left mul_mem_right) (x : R) :
x ∈ mk' carrier zero_mem add_mem neg_mem mul_mem_left mul_mem_right ↔ x ∈ carrier := by
rw [mem_iff]
simp [mk']
+set_option linter.docPrime false in
+@[simp]
+lemma coe_mk' (carrier : Set R) (zero_mem add_mem neg_mem mul_mem_left mul_mem_right) :
+ (mk' carrier zero_mem add_mem neg_mem mul_mem_left mul_mem_right : Set R) = carrier :=
+ Set.ext <| mem_mk' carrier zero_mem add_mem neg_mem mul_mem_left mul_mem_right
+
instance : SMulMemClass (TwoSidedIdeal R) R R where
smul_mem _ _ h := TwoSidedIdeal.mul_mem_left _ _ _ h
diff --git a/Mathlib/RingTheory/TwoSidedIdeal/BigOperators.lean b/Mathlib/RingTheory/TwoSidedIdeal/BigOperators.lean
new file mode 100644
index 0000000000000..8ed5a222e9ed2
--- /dev/null
+++ b/Mathlib/RingTheory/TwoSidedIdeal/BigOperators.lean
@@ -0,0 +1,74 @@
+/-
+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.RingTheory.Congruence.BigOperators
+import Mathlib.RingTheory.TwoSidedIdeal.Basic
+
+/-!
+# Interactions between `∑, ∏` and two sided ideals
+
+-/
+
+namespace TwoSidedIdeal
+
+section sum
+
+variable {R : Type*} [NonUnitalNonAssocRing R] (I : TwoSidedIdeal R)
+
+lemma listSum_mem {ι : Type*} (l : List ι) (f : ι → R) (hl : ∀ x ∈ l, f x ∈ I) :
+ (l.map f).sum ∈ I := by
+ rw [mem_iff, ← List.sum_map_zero]
+ exact I.ringCon.listSum l hl
+
+lemma multisetSum_mem {ι : Type*} (s : Multiset ι) (f : ι → R) (hs : ∀ x ∈ s, f x ∈ I) :
+ (s.map f).sum ∈ I := by
+ rw [mem_iff, ← Multiset.sum_map_zero]
+ exact I.ringCon.multisetSum s hs
+
+lemma finsetSum_mem {ι : Type*} (s : Finset ι) (f : ι → R) (hs : ∀ x ∈ s, f x ∈ I) :
+ s.sum f ∈ I := by
+ rw [mem_iff, ← Finset.sum_const_zero]
+ exact I.ringCon.finsetSum s hs
+
+end sum
+
+section prod
+
+section ring
+
+variable {R : Type*} [Ring R] (I : TwoSidedIdeal R)
+
+lemma listProd_mem {ι : Type*} (l : List ι) (f : ι → R) (hl : ∃ x ∈ l, f x ∈ I) :
+ (l.map f).prod ∈ I := by
+ induction l with
+ | nil => simp only [List.not_mem_nil, false_and, exists_false] at hl
+ | cons x l ih =>
+ simp only [List.mem_cons, exists_eq_or_imp] at hl
+ rcases hl with h | hal
+ · simpa only [List.map_cons, List.prod_cons] using I.mul_mem_right _ _ h
+ · simpa only [List.map_cons, List.prod_cons] using I.mul_mem_left _ _ <| ih hal
+
+end ring
+
+section commRing
+
+variable {R : Type*} [CommRing R] (I : TwoSidedIdeal R)
+
+lemma multiSetProd_mem {ι : Type*} (s : Multiset ι) (f : ι → R) (hs : ∃ x ∈ s, f x ∈ I) :
+ (s.map f).prod ∈ I := by
+ rcases s
+ simpa using listProd_mem (hl := hs)
+
+lemma finsetProd_mem {ι : Type*} (s : Finset ι) (f : ι → R) (hs : ∃ x ∈ s, f x ∈ I) :
+ s.prod f ∈ I := by
+ rcases s
+ simpa using multiSetProd_mem (hs := hs)
+
+end commRing
+
+end prod
+
+end TwoSidedIdeal
diff --git a/Mathlib/RingTheory/TwoSidedIdeal/Lattice.lean b/Mathlib/RingTheory/TwoSidedIdeal/Lattice.lean
index 9d596c74f10e6..55d3b2a16a8c7 100644
--- a/Mathlib/RingTheory/TwoSidedIdeal/Lattice.lean
+++ b/Mathlib/RingTheory/TwoSidedIdeal/Lattice.lean
@@ -113,6 +113,9 @@ instance : Top (TwoSidedIdeal R) where
lemma top_ringCon : (⊤ : TwoSidedIdeal R).ringCon = ⊤ := rfl
+@[simp]
+lemma mem_top {x : R} : x ∈ (⊤: TwoSidedIdeal R) := trivial
+
instance : Bot (TwoSidedIdeal R) where
bot := { ringCon := ⊥ }
@@ -129,4 +132,10 @@ instance : CompleteLattice (TwoSidedIdeal R) where
le_top _ := by rw [ringCon_le_iff]; exact le_top
bot_le _ := by rw [ringCon_le_iff]; exact bot_le
+lemma one_mem_iff {R : Type*} [NonAssocRing R] (I : TwoSidedIdeal R) :
+ (1 : R) ∈ I ↔ I = ⊤ :=
+ ⟨fun h => eq_top_iff.2 fun x _ => by simpa using I.mul_mem_left x _ h, fun h ↦ h.symm ▸ trivial⟩
+
+alias ⟨eq_top, one_mem⟩ := one_mem_iff
+
end TwoSidedIdeal
diff --git a/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean b/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean
new file mode 100644
index 0000000000000..b8295f7547e9c
--- /dev/null
+++ b/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean
@@ -0,0 +1,300 @@
+/-
+Copyright (c) 2024 Jujian Zhang. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Jujian Zhang, Jireh Loreaux
+-/
+
+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
+
+This file defines operations on two-sided ideals of a ring `R`.
+
+## Main definitions and results
+
+- `TwoSidedIdeal.span`: the span of `s ⊆ R` is the smallest two-sided ideal containing the set.
+- `TwoSidedIdeal.mem_span_iff_mem_addSubgroup_closure_nonunital`: in an associative but non-unital
+ ring, an element `x` is in the two-sided ideal spanned by `s` if and only if `x` is in the closure
+ of `s ∪ {y * a | y ∈ s, a ∈ R} ∪ {a * y | y ∈ s, a ∈ R} ∪ {a * y * b | y ∈ s, a, b ∈ R}` as an
+ additive subgroup.
+- `TwoSidedIdeal.mem_span_iff_mem_addSubgroup_closure`: in a unital and associative ring, an
+ element `x` is in the two-sided ideal spanned by `s` if and only if `x` is in the closure of
+ `{a*y*b | a, b ∈ R, y ∈ s}` as an additive subgroup.
+
+
+- `TwoSidedIdeal.comap`: pullback of a two-sided ideal; defined as the preimage of a
+ two-sided ideal.
+- `TwoSidedIdeal.map`: pushforward of a two-sided ideal; defined as the span of the image of a
+ two-sided ideal.
+- `TwoSidedIdeal.ker`: the kernel of a ring homomorphism as a two-sided ideal.
+
+- `TwoSidedIdeal.gc`: `fromIdeal` and `asIdeal` form a Galois connection where
+ `fromIdeal : Ideal R → TwoSidedIdeal R` is defined as the smallest two-sided ideal containing an
+ ideal and `asIdeal : TwoSidedIdeal R → Ideal R` the inclusion map.
+-/
+
+namespace TwoSidedIdeal
+
+section NonUnitalNonAssocRing
+
+variable {R S : Type*} [NonUnitalNonAssocRing R] [NonUnitalNonAssocRing S]
+variable {F : Type*} [FunLike F R S]
+variable (f : F)
+
+/--
+The smallest two-sided ideal containing a set.
+-/
+abbrev span (s : Set R) : TwoSidedIdeal R :=
+ { ringCon := ringConGen (fun a b ↦ a - b ∈ s) }
+
+lemma subset_span {s : Set R} : s ⊆ (span s : Set R) := by
+ intro x hx
+ rw [SetLike.mem_coe, mem_iff]
+ exact RingConGen.Rel.of _ _ (by simpa using hx)
+
+lemma mem_span_iff {s : Set R} {x} :
+ x ∈ span s ↔ ∀ (I : TwoSidedIdeal R), s ⊆ I → x ∈ I := by
+ refine ⟨?_, fun h => h _ subset_span⟩
+ delta span
+ rw [RingCon.ringConGen_eq]
+ intro h I hI
+ refine sInf_le (α := RingCon R) ?_ h
+ intro x y hxy
+ specialize hI hxy
+ rwa [SetLike.mem_coe, ← rel_iff] at hI
+
+lemma span_mono {s t : Set R} (h : s ⊆ t) : span s ≤ span t := by
+ intro x hx
+ rw [mem_span_iff] at hx ⊢
+ exact fun I hI => hx I <| h.trans hI
+
+/--
+Pushout of a two-sided ideal. Defined as the span of the image of a two-sided ideal under a ring
+homomorphism.
+-/
+def map (I : TwoSidedIdeal R) : TwoSidedIdeal S :=
+ span (f '' I)
+
+lemma map_mono {I J : TwoSidedIdeal R} (h : I ≤ J) :
+ map f I ≤ map f J :=
+ span_mono <| Set.image_mono h
+
+variable [NonUnitalRingHomClass F R S]
+
+/--
+Preimage of a two-sided ideal, as a two-sided ideal. -/
+def comap (I : TwoSidedIdeal S) : TwoSidedIdeal R :=
+{ ringCon := I.ringCon.comap f }
+
+lemma mem_comap {I : TwoSidedIdeal S} {x : R} :
+ x ∈ I.comap f ↔ f x ∈ I := by
+ simp [comap, RingCon.comap, mem_iff]
+
+/--
+The kernel of a ring homomorphism, as a two-sided ideal.
+-/
+def ker : TwoSidedIdeal R :=
+ .mk'
+ {r | f r = 0} (map_zero _) (by rintro _ _ (h1 : f _ = 0) (h2 : f _ = 0); simp [h1, h2])
+ (by rintro _ (h : f _ = 0); simp [h]) (by rintro _ _ (h : f _ = 0); simp [h])
+ (by rintro _ _ (h : f _ = 0); simp [h])
+
+lemma mem_ker {x : R} : x ∈ ker f ↔ f x = 0 := by
+ delta ker; rw [mem_mk']; rfl
+
+end NonUnitalNonAssocRing
+
+section NonUnitalRing
+
+variable {R : Type*} [NonUnitalRing R]
+
+open AddSubgroup in
+/-- If `s : Set R` is absorbing under multiplication, then its `TwoSidedIdeal.span` coincides with
+its `AddSubgroup.closure`, as sets. -/
+lemma mem_span_iff_mem_addSubgroup_closure_absorbing {s : Set R}
+ (h_left : ∀ x y, y ∈ s → x * y ∈ s) (h_right : ∀ y x, y ∈ s → y * x ∈ s) {z : R} :
+ z ∈ span s ↔ z ∈ closure s := by
+ have h_left' {x y} (hy : y ∈ closure s) : x * y ∈ closure s := by
+ have := (AddMonoidHom.mulLeft x).map_closure s ▸ mem_map_of_mem _ hy
+ refine closure_mono ?_ this
+ rintro - ⟨y, hy, rfl⟩
+ exact h_left x y hy
+ have h_right' {y x} (hy : y ∈ closure s) : y * x ∈ closure s := by
+ have := (AddMonoidHom.mulRight x).map_closure s ▸ mem_map_of_mem _ hy
+ refine closure_mono ?_ this
+ rintro - ⟨y, hy, rfl⟩
+ exact h_right y x hy
+ let I : TwoSidedIdeal R := .mk' (closure s) (AddSubgroup.zero_mem _)
+ (AddSubgroup.add_mem _) (AddSubgroup.neg_mem _) h_left' h_right'
+ suffices z ∈ span s ↔ z ∈ I by simpa only [I, mem_mk', SetLike.mem_coe]
+ rw [mem_span_iff]
+ -- Suppose that for every ideal `J` with `s ⊆ J`, then `z ∈ J`. Apply this to `I` to get `z ∈ I`.
+ refine ⟨fun h ↦ h I fun x hx ↦ ?mem_closure_of_forall, fun hz J hJ ↦ ?mem_ideal_of_subset⟩
+ case mem_closure_of_forall => simpa only [I, SetLike.mem_coe, mem_mk'] using subset_closure hx
+ /- Conversely, suppose that `z ∈ I` and that `J` is any ideal containing `s`. Then by the
+ 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
+ | mem x hx => exact hJ hx
+ | one => exact zero_mem _
+ | mul x y _ _ hx hy => exact J.add_mem hx hy
+ | inv x _ hx => exact J.neg_mem hx
+
+open Pointwise Set
+
+lemma set_mul_subset {s : Set R} {I : TwoSidedIdeal R} (h : s ⊆ I) (t : Set R):
+ t * s ⊆ I := by
+ rintro - ⟨r, -, x, hx, rfl⟩
+ exact mul_mem_left _ _ _ (h hx)
+
+lemma subset_mul_set {s : Set R} {I : TwoSidedIdeal R} (h : s ⊆ I) (t : Set R):
+ s * t ⊆ I := by
+ rintro - ⟨x, hx, r, -, rfl⟩
+ exact mul_mem_right _ _ _ (h hx)
+
+lemma mem_span_iff_mem_addSubgroup_closure_nonunital {s : Set R} {z : R} :
+ z ∈ span s ↔ z ∈ AddSubgroup.closure (s ∪ s * univ ∪ univ * s ∪ univ * s * univ) := by
+ trans z ∈ span (s ∪ s * univ ∪ univ * s ∪ univ * s * univ)
+ · refine ⟨(span_mono (by simp only [Set.union_assoc, Set.subset_union_left]) ·), fun h ↦ ?_⟩
+ refine mem_span_iff.mp h (span s) ?_
+ simp only [union_subset_iff, union_assoc]
+ exact ⟨subset_span, subset_mul_set subset_span _, set_mul_subset subset_span _,
+ subset_mul_set (set_mul_subset subset_span _) _⟩
+ · refine mem_span_iff_mem_addSubgroup_closure_absorbing ?_ ?_
+ · rintro x y (((hy | ⟨y, hy, r, -, rfl⟩) | ⟨r, -, y, hy, rfl⟩) |
+ ⟨-, ⟨r', -, y, hy, rfl⟩, r, -, rfl⟩)
+ · exact .inl <| .inr <| ⟨x, mem_univ _, y, hy, rfl⟩
+ · exact .inr <| ⟨x * y, ⟨x, mem_univ _, y, hy, rfl⟩, r, mem_univ _, mul_assoc ..⟩
+ · exact .inl <| .inr <| ⟨x * r, mem_univ _, y, hy, mul_assoc ..⟩
+ · refine .inr <| ⟨x * r' * y, ⟨x * r', mem_univ _, y, hy, ?_⟩, ⟨r, mem_univ _, ?_⟩⟩
+ all_goals simp [mul_assoc]
+ · rintro y x (((hy | ⟨y, hy, r, -, rfl⟩) | ⟨r, -, y, hy, rfl⟩) |
+ ⟨-, ⟨r', -, y, hy, rfl⟩, r, -, rfl⟩)
+ · exact .inl <| .inl <| .inr ⟨y, hy, x, mem_univ _, rfl⟩
+ · exact .inl <| .inl <| .inr ⟨y, hy, r * x, mem_univ _, (mul_assoc ..).symm⟩
+ · exact .inr <| ⟨r * y, ⟨r, mem_univ _, y, hy, rfl⟩, x, mem_univ _, rfl⟩
+ · refine .inr <| ⟨r' * y, ⟨r', mem_univ _, y, hy, rfl⟩, r * x, mem_univ _, ?_⟩
+ simp [mul_assoc]
+
+end NonUnitalRing
+
+section Ring
+
+variable {R : Type*} [Ring R]
+
+open Pointwise Set in
+lemma mem_span_iff_mem_addSubgroup_closure {s : Set R} {z : R} :
+ z ∈ span s ↔ z ∈ AddSubgroup.closure (univ * s * univ) := by
+ trans z ∈ span (univ * s * univ)
+ · refine ⟨(span_mono (fun x hx ↦ ?_) ·), fun hz ↦ ?_⟩
+ · exact ⟨1 * x, ⟨1, mem_univ _, x, hx, rfl⟩, 1, mem_univ _, by simp⟩
+ · exact mem_span_iff.mp hz (span s) <| subset_mul_set (set_mul_subset subset_span _) _
+ · refine mem_span_iff_mem_addSubgroup_closure_absorbing ?_ ?_
+ · intro x y hy
+ rw [mul_assoc] at hy ⊢
+ obtain ⟨r, -, y, hy, rfl⟩ := hy
+ exact ⟨x * r, mem_univ _, y, hy, mul_assoc ..⟩
+ · rintro - x ⟨y, hy, r, -, rfl⟩
+ exact ⟨y, hy, r * x, mem_univ _, (mul_assoc ..).symm⟩
+
+/-- Given an ideal `I`, `span I` is the smallest two-sided ideal containing `I`. -/
+def fromIdeal : Ideal R →o TwoSidedIdeal R where
+ toFun I := span I
+ monotone' _ _ := span_mono
+
+lemma mem_fromIdeal {I : Ideal R} {x : R} :
+ x ∈ fromIdeal I ↔ x ∈ span I := by simp [fromIdeal]
+
+/-- Every two-sided ideal is also a left ideal. -/
+def asIdeal : TwoSidedIdeal R →o Ideal R where
+ toFun I :=
+ { carrier := I
+ add_mem' := I.add_mem
+ zero_mem' := I.zero_mem
+ smul_mem' := fun r x hx => I.mul_mem_left r x hx }
+ monotone' _ _ h _ h' := h h'
+
+@[simp]
+lemma mem_asIdeal {I : TwoSidedIdeal R} {x : R} :
+ x ∈ asIdeal I ↔ x ∈ I := by simp [asIdeal]
+
+lemma gc : GaloisConnection fromIdeal (asIdeal (R := R)) :=
+ fun I J => ⟨fun h x hx ↦ h <| mem_span_iff.2 fun _ H ↦ H hx, fun h x hx ↦ by
+ simp only [fromIdeal, OrderHom.coe_mk, mem_span_iff] at hx
+ exact hx _ h⟩
+
+@[simp]
+lemma coe_asIdeal {I : TwoSidedIdeal R} : (asIdeal I : Set R) = I := rfl
+
+/-- Every two-sided ideal is also a right ideal. -/
+def asIdealOpposite : TwoSidedIdeal R →o Ideal Rᵐᵒᵖ where
+ toFun I := asIdeal ⟨I.ringCon.op⟩
+ monotone' I J h x h' := by
+ simp only [mem_asIdeal, mem_iff, RingCon.op_iff, MulOpposite.unop_zero] at h' ⊢
+ exact J.rel_iff _ _ |>.2 <| h <| I.rel_iff 0 x.unop |>.1 h'
+
+lemma mem_asIdealOpposite {I : TwoSidedIdeal R} {x : Rᵐᵒᵖ} :
+ x ∈ asIdealOpposite I ↔ x.unop ∈ I := by
+ simpa [asIdealOpposite, asIdeal, TwoSidedIdeal.mem_iff, RingCon.op_iff] using
+ ⟨I.ringCon.symm, I.ringCon.symm⟩
+
+end Ring
+
+section CommRing
+
+variable {R : Type*} [CommRing R]
+
+/--
+When the ring is commutative, two-sided ideals are exactly the same as left ideals.
+-/
+def orderIsoIdeal : TwoSidedIdeal R ≃o Ideal R where
+ toFun := asIdeal
+ invFun := fromIdeal
+ map_rel_iff' := ⟨fun h _ hx ↦ h hx, fun h ↦ asIdeal.monotone' h⟩
+ left_inv _ := SetLike.ext fun _ ↦ mem_span_iff.trans <| by aesop
+ right_inv J := SetLike.ext fun x ↦ mem_span_iff.trans
+ ⟨fun h ↦ mem_mk' _ _ _ _ _ _ _ |>.1 <| h (mk'
+ J J.zero_mem J.add_mem J.neg_mem (J.mul_mem_left _) (J.mul_mem_right _))
+ (fun x => by simp), by aesop⟩
+
+end CommRing
+
+end TwoSidedIdeal
+
+namespace Ideal
+variable {R : Type*} [Ring R]
+
+/-- Bundle an `Ideal` that is already two-sided as a `TwoSidedIdeal`. -/
+def toTwoSided (I : Ideal R) (mul_mem_right : ∀ {x y}, x ∈ I → x * y ∈ I) : TwoSidedIdeal R :=
+ TwoSidedIdeal.mk' I I.zero_mem I.add_mem I.neg_mem (I.smul_mem _) mul_mem_right
+
+@[simp]
+lemma mem_toTwoSided {I : Ideal R} {h} {x : R} :
+ x ∈ I.toTwoSided h ↔ x ∈ I := by
+ simp [toTwoSided]
+
+@[simp]
+lemma coe_toTwoSided (I : Ideal R) (h) : (I.toTwoSided h : Set R) = I := by
+ simp [toTwoSided]
+
+@[simp]
+lemma toTwoSided_asIdeal (I : TwoSidedIdeal R) (h) : (TwoSidedIdeal.asIdeal I).toTwoSided h = I :=
+ by ext; simp
+
+@[simp]
+lemma asIdeal_toTwoSided (I : Ideal R) (h) : TwoSidedIdeal.asIdeal (I.toTwoSided h) = I := by
+ ext
+ simp
+
+instance : CanLift (Ideal R) (TwoSidedIdeal R) TwoSidedIdeal.asIdeal
+ (fun I => ∀ {x y}, x ∈ I → x * y ∈ I) where
+ prf I mul_mem_right := ⟨I.toTwoSided mul_mem_right, asIdeal_toTwoSided ..⟩
+
+end Ideal
diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain.lean b/Mathlib/RingTheory/UniqueFactorizationDomain.lean
index df5977afdc34d..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 α :=
@@ -323,8 +322,7 @@ theorem WfDvdMonoid.of_exists_prime_factors : WfDvdMonoid α :=
rw [dif_neg ane0]
by_cases h : b = 0
· simp [h, lt_top_iff_ne_top]
- · rw [dif_neg h]
- erw [WithTop.coe_lt_coe]
+ · rw [dif_neg h, Nat.cast_lt]
have cne0 : c ≠ 0 := by
refine mt (fun con => ?_) h
rw [b_eq, con, mul_zero]
@@ -390,8 +388,8 @@ theorem MulEquiv.uniqueFactorizationMonoid (e : α ≃* β) (hα : UniqueFactori
he ▸ e.prime_iff.1 (hp c hc),
Units.map e.toMonoidHom u,
by
- erw [Multiset.prod_hom, ← map_mul e, h]
- simp⟩
+ rw [Multiset.prod_hom, toMonoidHom_eq_coe, Units.coe_map, MonoidHom.coe_coe, ← map_mul e, h,
+ apply_symm_apply]⟩
theorem MulEquiv.uniqueFactorizationMonoid_iff (e : α ≃* β) :
UniqueFactorizationMonoid α ↔ UniqueFactorizationMonoid β :=
@@ -495,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
@@ -555,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
@@ -570,7 +575,7 @@ noncomputable def normalizedFactors (a : α) : Multiset α :=
if `M` has a trivial group of units. -/
@[simp]
theorem factors_eq_normalizedFactors {M : Type*} [CancelCommMonoidWithZero M]
- [UniqueFactorizationMonoid M] [Unique Mˣ] (x : M) : factors x = normalizedFactors x := by
+ [UniqueFactorizationMonoid M] [Subsingleton Mˣ] (x : M) : factors x = normalizedFactors x := by
unfold normalizedFactors
convert (Multiset.map_id (factors x)).symm
ext p
@@ -628,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 <|
@@ -722,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
@@ -743,7 +752,7 @@ theorem dvd_of_mem_normalizedFactors {a p : α} (H : p ∈ normalizedFactors a)
exact dvd_zero p
· exact dvd_trans (Multiset.dvd_prod H) (Associated.dvd (normalizedFactors_prod hcases))
-theorem mem_normalizedFactors_iff [Unique αˣ] {p x : α} (hx : x ≠ 0) :
+theorem mem_normalizedFactors_iff [Subsingleton αˣ] {p x : α} (hx : x ≠ 0) :
p ∈ normalizedFactors x ↔ Prime p ∧ p ∣ x := by
constructor
· intro h
@@ -759,11 +768,16 @@ theorem exists_associated_prime_pow_of_unique_normalized_factor {p r : α}
have := UniqueFactorizationMonoid.normalizedFactors_prod hr
rwa [Multiset.eq_replicate_of_mem fun b => h, Multiset.prod_replicate] at this
-theorem normalizedFactors_prod_of_prime [Nontrivial α] [Unique αˣ] {m : Multiset α}
+theorem normalizedFactors_prod_of_prime [Subsingleton αˣ] {m : Multiset α}
(h : ∀ p ∈ m, Prime p) : normalizedFactors m.prod = m := by
- simpa only [← Multiset.rel_eq, ← associated_eq_eq] using
- prime_factors_unique prime_of_normalized_factor h
- (normalizedFactors_prod (m.prod_ne_zero_of_prime h))
+ cases subsingleton_or_nontrivial α
+ · obtain rfl : m = 0 := by
+ refine Multiset.eq_zero_of_forall_not_mem fun x hx ↦ ?_
+ simpa [Subsingleton.elim x 0] using h x hx
+ simp
+ · simpa only [← Multiset.rel_eq, ← associated_eq_eq] using
+ prime_factors_unique prime_of_normalized_factor h
+ (normalizedFactors_prod (m.prod_ne_zero_of_prime h))
theorem mem_normalizedFactors_eq_of_associated {a b c : α} (ha : a ∈ normalizedFactors c)
(hb : b ∈ normalizedFactors c) (h : Associated a b) : a = b := by
@@ -912,34 +926,21 @@ theorem exists_reduced_factors' (a b : R) (hb : b ≠ 0) :
let ⟨b', a', c', no_factor, hb, ha⟩ := exists_reduced_factors b hb a
⟨a', b', c', fun _ hpb hpa => no_factor hpa hpb, ha, hb⟩
-theorem pow_right_injective {a : R} (ha0 : a ≠ 0) (ha1 : ¬IsUnit a) :
- Function.Injective (a ^ · : ℕ → R) := by
- letI := Classical.decEq R
- intro i j hij
- letI : Nontrivial R := ⟨⟨a, 0, ha0⟩⟩
- letI : NormalizationMonoid R := UniqueFactorizationMonoid.normalizationMonoid
- obtain ⟨p', hp', dvd'⟩ := WfDvdMonoid.exists_irreducible_factor ha1 ha0
- obtain ⟨p, mem, _⟩ := exists_mem_normalizedFactors_of_dvd ha0 hp' dvd'
- have := congr_arg (fun x => Multiset.count p (normalizedFactors x)) hij
- simp only [normalizedFactors_pow, Multiset.count_nsmul] at this
- exact mul_right_cancel₀ (Multiset.count_ne_zero.mpr mem) this
-
-theorem pow_eq_pow_iff {a : R} (ha0 : a ≠ 0) (ha1 : ¬IsUnit a) {i j : ℕ} : a ^ i = a ^ j ↔ i = j :=
- (pow_right_injective ha0 ha1).eq_iff
+@[deprecated (since := "2024-09-21")] alias pow_right_injective := pow_injective_of_not_isUnit
+@[deprecated (since := "2024-09-21")] alias pow_eq_pow_iff := pow_inj_of_not_isUnit
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
@@ -960,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
@@ -978,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
@@ -1035,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))
@@ -1074,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)
@@ -1210,15 +1209,15 @@ 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
unfold FactorSet at p
induction p -- TODO: `induction_eliminator` doesn't work with `abbrev`
- · simp only [iff_self_iff, eq_self_iff_true, Associates.prod_top]
+ · simp only [eq_self_iff_true, Associates.prod_top]
· rw [prod_coe, Multiset.prod_eq_zero_iff, Multiset.mem_map, eq_false WithTop.coe_ne_top,
- iff_false_iff, not_exists]
+ iff_false, not_exists]
exact fun a => not_and_of_not_right _ a.prop.ne_zero
section count
@@ -1871,7 +1870,7 @@ noncomputable def fintypeSubtypeDvd {M : Type*} [CancelCommMonoidWithZero M]
(((normalizedFactors y).powerset.toFinset ×ˢ (Finset.univ : Finset Mˣ)).image fun s =>
(s.snd : M) * s.fst.prod)
fun x => ?_
- simp only [exists_prop, Finset.mem_image, Finset.mem_product, Finset.mem_univ, and_true_iff,
+ simp only [exists_prop, Finset.mem_image, Finset.mem_product, Finset.mem_univ, and_true,
Multiset.mem_toFinset, Multiset.mem_powerset, exists_eq_right, Multiset.mem_map]
constructor
· rintro ⟨s, hs, rfl⟩
diff --git a/Mathlib/RingTheory/Unramified/Basic.lean b/Mathlib/RingTheory/Unramified/Basic.lean
index af45772e8e3eb..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,26 +128,31 @@ 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)
end
+instance {R : Type*} [CommRing R] : FormallyUnramified R R := by
+ rw [iff_comp_injective]
+ intros B _ _ _ _ f₁ f₂ _
+ exact Subsingleton.elim _ _
+
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*} [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
- constructor
+ 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
@@ -124,13 +163,13 @@ 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)
@@ -144,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
@@ -155,17 +194,43 @@ theorem of_comp [FormallyUnramified R B] : FormallyUnramified A B := by
end Comp
+section of_surjective
+
+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
+ rw [iff_comp_injective]
+ intro Q _ _ I hI f₁ f₂ e
+ ext x
+ obtain ⟨x, rfl⟩ := H x
+ rw [← AlgHom.comp_apply, ← AlgHom.comp_apply]
+ congr 1
+ apply FormallyUnramified.comp_injective I hI
+ ext x; exact DFunLike.congr_fun e (f x)
+
+instance quotient {A} [CommRing A] [Algebra R A] [FormallyUnramified R A] (I : Ideal A) :
+ FormallyUnramified R (A ⧸ I) :=
+ FormallyUnramified.of_surjective (IsScalarTower.toAlgHom R A (A ⧸ I)) Ideal.Quotient.mk_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
+
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
@@ -177,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ₘ]
@@ -189,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 ?_
@@ -220,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.
@@ -239,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
new file mode 100644
index 0000000000000..b2faae3e80dec
--- /dev/null
+++ b/Mathlib/RingTheory/Unramified/Field.lean
@@ -0,0 +1,213 @@
+/-
+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.FieldTheory.PurelyInseparable
+import Mathlib.RingTheory.Artinian
+import Mathlib.RingTheory.LocalProperties.Basic
+import Mathlib.Algebra.Polynomial.Taylor
+import Mathlib.RingTheory.Unramified.Finite
+
+/-!
+# Unramified algebras over fields
+
+## Main results
+
+Let `K` be a field, `A` be a `K`-algebra and `L` be a field extension of `K`.
+
+- `Algebra.FormallyUnramified.bijective_of_isAlgClosed_of_localRing`:
+ If `A` is `K`-unramified and `K` is alg-closed, then `K = A`.
+- `Algebra.FormallyUnramified.isReduced_of_field`:
+ If `A` is `K`-unramified then `A` is reduced.
+- `Algebra.FormallyUnramified.iff_isSeparable`:
+ `L` is unramified over `K` iff `L` is separable over `K`.
+
+## References
+
+- [B. Iversen, *Generic Local Structure of the Morphisms in Commutative Algebra*][iversen]
+
+-/
+
+universe u
+
+variable (K A L : Type u) [Field K] [Field L] [CommRing A] [Algebra K A] [Algebra K L]
+
+open Algebra Polynomial
+
+open scoped TensorProduct
+
+namespace Algebra.FormallyUnramified
+
+theorem of_isSeparable [Algebra.IsSeparable K L] : FormallyUnramified K L := by
+ rw [iff_comp_injective]
+ intros B _ _ I hI f₁ f₂ e
+ ext x
+ have : f₁ x - f₂ x ∈ I := by
+ simpa [Ideal.Quotient.mk_eq_mk_iff_sub_mem] using AlgHom.congr_fun e x
+ have := Polynomial.eval_add_of_sq_eq_zero ((minpoly K x).map (algebraMap K B)) (f₂ x)
+ (f₁ x - f₂ x) (show (f₁ x - f₂ x) ^ 2 ∈ ⊥ from hI ▸ Ideal.pow_mem_pow this 2)
+ simp only [add_sub_cancel, eval_map_algebraMap, aeval_algHom_apply, minpoly.aeval, map_zero,
+ derivative_map, zero_add] at this
+ rwa [eq_comm, ((isUnit_iff_ne_zero.mpr
+ ((Algebra.IsSeparable.isSeparable K x).aeval_derivative_ne_zero
+ (minpoly.aeval K x))).map f₂).mul_right_eq_zero, sub_eq_zero] at this
+
+variable [FormallyUnramified K A] [EssFiniteType K A]
+variable [FormallyUnramified K L] [EssFiniteType K L]
+
+theorem bijective_of_isAlgClosed_of_localRing
+ [IsAlgClosed K] [LocalRing A] :
+ Function.Bijective (algebraMap K A) := by
+ have := finite_of_free (R := K) (S := A)
+ have : IsArtinianRing A := isArtinian_of_tower K inferInstance
+ have hA : IsNilpotent (LocalRing.maximalIdeal A) := by
+ rw [← LocalRing.jacobson_eq_maximalIdeal ⊥]
+ · exact IsArtinianRing.isNilpotent_jacobson_bot
+ · exact bot_ne_top
+ have : Function.Bijective (Algebra.ofId K (A ⧸ LocalRing.maximalIdeal A)) :=
+ ⟨RingHom.injective _, IsAlgClosed.algebraMap_surjective_of_isIntegral⟩
+ let e : K ≃ₐ[K] A ⧸ LocalRing.maximalIdeal A := {
+ __ := Algebra.ofId K (A ⧸ LocalRing.maximalIdeal A)
+ __ := Equiv.ofBijective _ this }
+ let e' : A ⊗[K] (A ⧸ LocalRing.maximalIdeal A) ≃ₐ[A] A :=
+ (Algebra.TensorProduct.congr AlgEquiv.refl e.symm).trans (Algebra.TensorProduct.rid K A A)
+ let f : A ⧸ LocalRing.maximalIdeal A →ₗ[A] A := e'.toLinearMap.comp (sec K A _)
+ have hf : (Algebra.ofId _ _).toLinearMap ∘ₗ f = LinearMap.id := by
+ dsimp [f]
+ rw [← LinearMap.comp_assoc, ← comp_sec K A]
+ congr 1
+ apply LinearMap.restrictScalars_injective K
+ apply _root_.TensorProduct.ext'
+ intros r s
+ obtain ⟨s, rfl⟩ := e.surjective s
+ suffices s • (Ideal.Quotient.mk (LocalRing.maximalIdeal A)) r = r • e s by
+ simpa [ofId, e']
+ simp [Algebra.smul_def, e, ofId, mul_comm]
+ have hf₁ : f 1 • (1 : A ⧸ LocalRing.maximalIdeal A) = 1 := by
+ rw [← algebraMap_eq_smul_one]
+ exact LinearMap.congr_fun hf 1
+ have hf₂ : 1 - f 1 ∈ LocalRing.maximalIdeal A := by
+ rw [← Ideal.Quotient.eq_zero_iff_mem, map_sub, map_one, ← Ideal.Quotient.algebraMap_eq,
+ algebraMap_eq_smul_one, hf₁, sub_self]
+ have hf₃ : IsIdempotentElem (1 - f 1) := by
+ apply IsIdempotentElem.one_sub
+ rw [IsIdempotentElem, ← smul_eq_mul, ← map_smul, hf₁]
+ have hf₄ : f 1 = 1 := by
+ obtain ⟨n, hn⟩ := hA
+ have : (1 - f 1) ^ n = 0 := by
+ rw [← Ideal.mem_bot, ← Ideal.zero_eq_bot, ← hn]
+ exact Ideal.pow_mem_pow hf₂ n
+ rw [eq_comm, ← sub_eq_zero, ← hf₃.pow_succ_eq n, pow_succ, this, zero_mul]
+ refine Equiv.bijective ⟨algebraMap K A, ⇑e.symm ∘ ⇑(algebraMap A _), fun x ↦ by simp, fun x ↦ ?_⟩
+ have : ⇑(algebraMap K A) = ⇑f ∘ ⇑e := by
+ ext k
+ conv_rhs => rw [← mul_one k, ← smul_eq_mul, Function.comp_apply, map_smul,
+ LinearMap.map_smul_of_tower, map_one, hf₄, ← algebraMap_eq_smul_one]
+ rw [this]
+ simp only [Function.comp_apply, AlgEquiv.apply_symm_apply, algebraMap_eq_smul_one,
+ map_smul, hf₄, smul_eq_mul, mul_one]
+
+theorem isField_of_isAlgClosed_of_localRing
+ [IsAlgClosed K] [LocalRing A] : IsField A := by
+ rw [LocalRing.isField_iff_maximalIdeal_eq, eq_bot_iff]
+ intro x hx
+ obtain ⟨x, rfl⟩ := (bijective_of_isAlgClosed_of_localRing K A).surjective x
+ show _ = 0
+ rw [← (algebraMap K A).map_zero]
+ by_contra hx'
+ exact hx ((isUnit_iff_ne_zero.mpr
+ (fun e ↦ hx' ((algebraMap K A).congr_arg e))).map (algebraMap K A))
+
+include K in
+theorem isReduced_of_field :
+ IsReduced A := by
+ constructor
+ intro x hx
+ let f := (Algebra.TensorProduct.includeRight (R := K) (A := AlgebraicClosure K) (B := A))
+ have : Function.Injective f := by
+ have : ⇑f = (LinearMap.rTensor A (Algebra.ofId K (AlgebraicClosure K)).toLinearMap).comp
+ (Algebra.TensorProduct.lid K A).symm.toLinearMap := by
+ ext x; simp [f]
+ rw [this]
+ suffices Function.Injective
+ (LinearMap.rTensor A (Algebra.ofId K (AlgebraicClosure K)).toLinearMap) by
+ exact this.comp (Algebra.TensorProduct.lid K A).symm.injective
+ apply Module.Flat.rTensor_preserves_injective_linearMap
+ exact (algebraMap K _).injective
+ apply this
+ rw [map_zero]
+ apply eq_zero_of_localization
+ intro M hM
+ have hy := (hx.map f).map (algebraMap _ (Localization.AtPrime M))
+ generalize algebraMap _ (Localization.AtPrime M) (f x) = y at *
+ have := EssFiniteType.of_isLocalization (Localization.AtPrime M) M.primeCompl
+ have := of_isLocalization (Rₘ := Localization.AtPrime M) M.primeCompl
+ have := EssFiniteType.comp (AlgebraicClosure K) (AlgebraicClosure K ⊗[K] A)
+ (Localization.AtPrime M)
+ have := comp (AlgebraicClosure K) (AlgebraicClosure K ⊗[K] A)
+ (Localization.AtPrime M)
+ letI := (isField_of_isAlgClosed_of_localRing (AlgebraicClosure K)
+ (A := Localization.AtPrime M)).toField
+ exact hy.eq_zero
+
+theorem range_eq_top_of_isPurelyInseparable
+ [IsPurelyInseparable K L] : (algebraMap K L).range = ⊤ := by
+ classical
+ have : Nontrivial (L ⊗[K] L) := by
+ rw [← not_subsingleton_iff_nontrivial, ← rank_zero_iff (R := K), rank_tensorProduct',
+ mul_eq_zero, or_self, rank_zero_iff, not_subsingleton_iff_nontrivial]
+ infer_instance
+ rw [← top_le_iff]
+ intro x _
+ obtain ⟨n, hn⟩ := IsPurelyInseparable.pow_mem K (ringExpChar K) x
+ have : ExpChar (L ⊗[K] L) (ringExpChar K) := by
+ refine expChar_of_injective_ringHom (algebraMap K _).injective (ringExpChar K)
+ have : (1 ⊗ₜ x - x ⊗ₜ 1 : L ⊗[K] L) ^ (ringExpChar K) ^ n = 0 := by
+ rw [sub_pow_expChar_pow, TensorProduct.tmul_pow, one_pow, TensorProduct.tmul_pow, one_pow]
+ obtain ⟨r, hr⟩ := hn
+ rw [← hr, algebraMap_eq_smul_one, TensorProduct.smul_tmul, sub_self]
+ have H : (1 ⊗ₜ x : L ⊗[K] L) = x ⊗ₜ 1 := by
+ have inst : IsReduced (L ⊗[K] L) := isReduced_of_field L _
+ exact sub_eq_zero.mp (IsNilpotent.eq_zero ⟨_, this⟩)
+ by_cases h' : LinearIndependent K ![1, x]
+ · have h := h'.coe_range
+ let S := h.extend (Set.subset_univ _)
+ let a : S := ⟨1, h.subset_extend _ (by simp)⟩; have ha : Basis.extend h a = 1 := by simp
+ let b : S := ⟨x, h.subset_extend _ (by simp)⟩; have hb : Basis.extend h b = x := by simp
+ by_cases e : a = b
+ · obtain rfl : 1 = x := congr_arg Subtype.val e
+ exact ⟨1, map_one _⟩
+ have := DFunLike.congr_fun
+ (DFunLike.congr_arg ((Basis.extend h).tensorProduct (Basis.extend h)).repr H) (a, b)
+ simp only [Basis.tensorProduct_repr_tmul_apply, ← ha, ← hb, Basis.repr_self, smul_eq_mul,
+ Finsupp.single_apply, e, Ne.symm e, ↓reduceIte, mul_one, mul_zero, one_ne_zero] at this
+ · rw [LinearIndependent.pair_iff] at h'
+ simp only [not_forall, not_and, exists_prop] at h'
+ obtain ⟨a, b, e, hab⟩ := h'
+ have : IsUnit b := by
+ rw [isUnit_iff_ne_zero]
+ rintro rfl
+ rw [zero_smul, ← algebraMap_eq_smul_one, add_zero,
+ (injective_iff_map_eq_zero' _).mp (algebraMap K L).injective] at e
+ cases hab e rfl
+ use (-this.unit⁻¹ * a)
+ rw [map_mul, ← Algebra.smul_def, algebraMap_eq_smul_one, eq_neg_iff_add_eq_zero.mpr e,
+ smul_neg, neg_smul, neg_neg, smul_smul, this.val_inv_mul, one_smul]
+
+theorem isSeparable : Algebra.IsSeparable K L := by
+ have := finite_of_free (R := K) (S := L)
+ rw [← separableClosure.eq_top_iff]
+ have := of_comp K (separableClosure K L) L
+ have := EssFiniteType.of_comp K (separableClosure K L) L
+ have := separableClosure.isPurelyInseparable K L
+ ext
+ show _ ↔ _ ∈ (⊤ : Subring _)
+ rw [← range_eq_top_of_isPurelyInseparable (separableClosure K L) L]
+ simp
+
+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⟩
+
+end Algebra.FormallyUnramified
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
new file mode 100644
index 0000000000000..755c16a601f58
--- /dev/null
+++ b/Mathlib/RingTheory/Unramified/Pi.lean
@@ -0,0 +1,98 @@
+/-
+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.Unramified.Basic
+
+/-!
+
+# Formal-unramification of finite products of rings
+
+## Main result
+
+- `Algebra.FormallyUnramified.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.
+
+-/
+
+namespace Algebra.FormallyUnramified
+
+universe u v
+
+variable {R : Type max u v} {I : Type v} [Finite I] (f : I → Type max u v)
+variable [CommRing R] [∀ i, CommRing (f i)] [∀ i, Algebra R (f i)]
+
+theorem pi_iff :
+ FormallyUnramified R (∀ i, f i) ↔ ∀ i, FormallyUnramified R (f i) := by
+ classical
+ cases nonempty_fintype I
+ constructor
+ · intro _ i
+ exact FormallyUnramified.of_surjective (Pi.evalAlgHom R f i) (Function.surjective_eval i)
+ · intro H
+ rw [iff_comp_injective]
+ intros B _ _ J hJ f₁ f₂ e
+ ext g
+ rw [← Finset.univ_sum_single g, map_sum, map_sum]
+ refine Finset.sum_congr rfl ?_
+ rintro x -
+ have hf : ∀ x, f₁ x - f₂ x ∈ J := by
+ intro g
+ rw [← Ideal.Quotient.eq_zero_iff_mem, map_sub, sub_eq_zero]
+ exact AlgHom.congr_fun e g
+ let e : ∀ i, f i := Pi.single x 1
+ have he : IsIdempotentElem e := by simp [IsIdempotentElem, e, ← Pi.single_mul]
+ have h₁ : (f₁ e) * (1 - f₂ e) = 0 := by
+ rw [← Ideal.mem_bot, ← hJ, ← ((he.map f₁).mul (he.map f₂).one_sub).eq, ← pow_two]
+ apply Ideal.pow_mem_pow
+ convert Ideal.mul_mem_left _ (f₁ e) (hf e) using 1
+ rw [mul_sub, mul_sub, mul_one, (he.map f₁).eq]
+ have h₂ : (f₂ e) * (1 - f₁ e) = 0 := by
+ rw [← Ideal.mem_bot, ← hJ, ← ((he.map f₂).mul (he.map f₁).one_sub).eq, ← pow_two]
+ apply Ideal.pow_mem_pow
+ convert Ideal.mul_mem_left _ (-f₂ e) (hf e) using 1
+ rw [neg_mul, mul_sub, mul_sub, mul_one, neg_sub, (he.map f₂).eq]
+ have H : f₁ e = f₂ e := by
+ trans f₁ e * f₂ e
+ · rw [← sub_eq_zero, ← h₁, mul_sub, mul_one]
+ · rw [eq_comm, ← sub_eq_zero, ← h₂, mul_sub, mul_one, mul_comm]
+ let J' := Ideal.span {1 - f₁ e}
+ let f₁' : f x →ₐ[R] B ⧸ J' := by
+ apply AlgHom.ofLinearMap
+ (((Ideal.Quotient.mkₐ R J').comp f₁).toLinearMap.comp (LinearMap.single _ _ x))
+ · simp only [AlgHom.comp_toLinearMap, LinearMap.coe_comp, LinearMap.coe_single,
+ Function.comp_apply, AlgHom.toLinearMap_apply, Ideal.Quotient.mkₐ_eq_mk]
+ rw [eq_comm, ← sub_eq_zero, ← (Ideal.Quotient.mk J').map_one, ← map_sub,
+ Ideal.Quotient.eq_zero_iff_mem, Ideal.mem_span_singleton]
+ · intros r s; simp [Pi.single_mul]
+ let f₂' : f x →ₐ[R] B ⧸ J' := by
+ apply AlgHom.ofLinearMap
+ (((Ideal.Quotient.mkₐ R J').comp f₂).toLinearMap.comp (LinearMap.single _ _ x))
+ · simp only [AlgHom.comp_toLinearMap, LinearMap.coe_comp, LinearMap.coe_single,
+ Function.comp_apply, AlgHom.toLinearMap_apply, Ideal.Quotient.mkₐ_eq_mk]
+ rw [eq_comm, ← sub_eq_zero, ← (Ideal.Quotient.mk J').map_one, ← map_sub,
+ Ideal.Quotient.eq_zero_iff_mem, Ideal.mem_span_singleton, H]
+ · intros r s; simp [Pi.single_mul]
+ suffices f₁' = f₂' by
+ have := AlgHom.congr_fun this (g x)
+ simp only [AlgHom.comp_toLinearMap, AlgHom.ofLinearMap_apply, LinearMap.coe_comp,
+ LinearMap.coe_single, Function.comp_apply, AlgHom.toLinearMap_apply, ← map_sub,
+ Ideal.Quotient.mkₐ_eq_mk, ← sub_eq_zero (b := Ideal.Quotient.mk J' _), sub_zero, f₁', f₂',
+ Ideal.Quotient.eq_zero_iff_mem, Ideal.mem_span_singleton, J'] at this
+ obtain ⟨c, hc⟩ := this
+ apply_fun (f₁ e * ·) at hc
+ rwa [← mul_assoc, mul_sub, mul_sub, mul_one, (he.map f₁).eq, sub_self, zero_mul,
+ ← map_mul, H, ← map_mul, ← Pi.single_mul, one_mul, sub_eq_zero] at hc
+ apply FormallyUnramified.comp_injective (I := J.map (algebraMap _ _))
+ · rw [← Ideal.map_pow, hJ, Ideal.map_bot]
+ · ext r
+ rw [← sub_eq_zero]
+ simp only [Ideal.Quotient.algebraMap_eq, AlgHom.coe_comp, Ideal.Quotient.mkₐ_eq_mk,
+ Function.comp_apply, ← map_sub, Ideal.Quotient.eq_zero_iff_mem, f₁', f₂',
+ AlgHom.comp_toLinearMap, AlgHom.ofLinearMap_apply, LinearMap.coe_comp,
+ LinearMap.coe_single, Function.comp_apply, AlgHom.toLinearMap_apply,
+ Ideal.Quotient.mkₐ_eq_mk]
+ exact Ideal.mem_map_of_mem (Ideal.Quotient.mk J') (hf (Pi.single x r))
+
+end Algebra.FormallyUnramified
diff --git a/Mathlib/RingTheory/Valuation/AlgebraInstances.lean b/Mathlib/RingTheory/Valuation/AlgebraInstances.lean
index e3339c12fafec..91ff35d526b16 100644
--- a/Mathlib/RingTheory/Valuation/AlgebraInstances.lean
+++ b/Mathlib/RingTheory/Valuation/AlgebraInstances.lean
@@ -25,7 +25,7 @@ of a field with a valuation, as well as their unit balls.
open Function Valuation
-open scoped DiscreteValuation
+open scoped Multiplicative
variable {K : Type*} [Field K] (v : Valuation K ℤₘ₀) (L : Type*) [Field L] [Algebra K L]
diff --git a/Mathlib/RingTheory/Valuation/Basic.lean b/Mathlib/RingTheory/Valuation/Basic.lean
index e32f03f67f513..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
@@ -412,8 +409,16 @@ theorem isEquiv_of_map_strictMono [LinearOrderedCommMonoidWithZero Γ₀]
(H : StrictMono f) : IsEquiv (v.map f H.monotone) v := fun _x _y =>
⟨H.le_iff_le.mp, fun h => H.monotone h⟩
+theorem isEquiv_iff_val_lt_val [LinearOrderedCommGroupWithZero Γ₀]
+ [LinearOrderedCommGroupWithZero Γ'₀] {v : Valuation K Γ₀} {v' : Valuation K Γ'₀} :
+ v.IsEquiv v' ↔ ∀ {x y : K}, v x < v y ↔ v' x < v' y := by
+ simp only [IsEquiv, le_iff_le_iff_lt_iff_lt]
+ exact forall_comm
+
+alias ⟨IsEquiv.lt_iff_lt, _⟩ := isEquiv_iff_val_lt_val
+
theorem isEquiv_of_val_le_one [LinearOrderedCommGroupWithZero Γ₀]
- [LinearOrderedCommGroupWithZero Γ'₀] (v : Valuation K Γ₀) (v' : Valuation K Γ'₀)
+ [LinearOrderedCommGroupWithZero Γ'₀] {v : Valuation K Γ₀} {v' : Valuation K Γ'₀}
(h : ∀ {x : K}, v x ≤ 1 ↔ v' x ≤ 1) : v.IsEquiv v' := by
intro x y
obtain rfl | hy := eq_or_ne y 0
@@ -422,12 +427,14 @@ theorem isEquiv_of_val_le_one [LinearOrderedCommGroupWithZero Γ₀]
rwa [zero_lt_iff, ne_zero_iff]
theorem isEquiv_iff_val_le_one [LinearOrderedCommGroupWithZero Γ₀]
- [LinearOrderedCommGroupWithZero Γ'₀] (v : Valuation K Γ₀) (v' : Valuation K Γ'₀) :
+ [LinearOrderedCommGroupWithZero Γ'₀] {v : Valuation K Γ₀} {v' : Valuation K Γ'₀} :
v.IsEquiv v' ↔ ∀ {x : K}, v x ≤ 1 ↔ v' x ≤ 1 :=
- ⟨fun h x => by simpa using h x 1, isEquiv_of_val_le_one _ _⟩
+ ⟨fun h x => by simpa using h x 1, isEquiv_of_val_le_one⟩
+
+alias ⟨IsEquiv.le_one_iff_le_one, _⟩ := isEquiv_iff_val_le_one
theorem isEquiv_iff_val_eq_one [LinearOrderedCommGroupWithZero Γ₀]
- [LinearOrderedCommGroupWithZero Γ'₀] (v : Valuation K Γ₀) (v' : Valuation K Γ'₀) :
+ [LinearOrderedCommGroupWithZero Γ'₀] {v : Valuation K Γ₀} {v' : Valuation K Γ'₀} :
v.IsEquiv v' ↔ ∀ {x : K}, v x = 1 ↔ v' x = 1 := by
constructor
· intro h x
@@ -461,13 +468,15 @@ theorem isEquiv_iff_val_eq_one [LinearOrderedCommGroupWithZero Γ₀]
· rw [← h] at hx'
exact le_of_eq hx'
+alias ⟨IsEquiv.eq_one_iff_eq_one, _⟩ := isEquiv_iff_val_eq_one
+
theorem isEquiv_iff_val_lt_one [LinearOrderedCommGroupWithZero Γ₀]
- [LinearOrderedCommGroupWithZero Γ'₀] (v : Valuation K Γ₀) (v' : Valuation K Γ'₀) :
+ [LinearOrderedCommGroupWithZero Γ'₀] {v : Valuation K Γ₀} {v' : Valuation K Γ'₀} :
v.IsEquiv v' ↔ ∀ {x : K}, v x < 1 ↔ v' x < 1 := by
constructor
· intro h x
simp only [lt_iff_le_and_ne,
- and_congr ((isEquiv_iff_val_le_one _ _).1 h) ((isEquiv_iff_val_eq_one _ _).1 h).not]
+ and_congr h.le_one_iff_le_one h.eq_one_iff_eq_one.not]
· rw [isEquiv_iff_val_eq_one]
intro h x
by_cases hx : x = 0
@@ -488,20 +497,29 @@ theorem isEquiv_iff_val_lt_one [LinearOrderedCommGroupWithZero Γ₀]
rw [← inv_one, ← inv_eq_iff_eq_inv, ← map_inv₀] at hh
exact hh.not_lt (h.1 ((one_lt_val_iff v hx).1 h_2))
+alias ⟨IsEquiv.lt_one_iff_lt_one, _⟩ := isEquiv_iff_val_lt_one
+
theorem isEquiv_iff_val_sub_one_lt_one [LinearOrderedCommGroupWithZero Γ₀]
- [LinearOrderedCommGroupWithZero Γ'₀] (v : Valuation K Γ₀) (v' : Valuation K Γ'₀) :
+ [LinearOrderedCommGroupWithZero Γ'₀] {v : Valuation K Γ₀} {v' : Valuation K Γ'₀} :
v.IsEquiv v' ↔ ∀ {x : K}, v (x - 1) < 1 ↔ v' (x - 1) < 1 := by
rw [isEquiv_iff_val_lt_one]
exact (Equiv.subRight 1).surjective.forall
+alias ⟨IsEquiv.val_sub_one_lt_one_iff, _⟩ := isEquiv_iff_val_sub_one_lt_one
+
theorem isEquiv_tfae [LinearOrderedCommGroupWithZero Γ₀] [LinearOrderedCommGroupWithZero Γ'₀]
(v : Valuation K Γ₀) (v' : Valuation K Γ'₀) :
- [v.IsEquiv v', ∀ {x}, v x ≤ 1 ↔ v' x ≤ 1, ∀ {x}, v x = 1 ↔ v' x = 1, ∀ {x}, v x < 1 ↔ v' x < 1,
- ∀ {x}, v (x - 1) < 1 ↔ v' (x - 1) < 1].TFAE := by
- tfae_have 1 ↔ 2; · apply isEquiv_iff_val_le_one
- tfae_have 1 ↔ 3; · apply isEquiv_iff_val_eq_one
- tfae_have 1 ↔ 4; · apply isEquiv_iff_val_lt_one
- tfae_have 1 ↔ 5; · apply isEquiv_iff_val_sub_one_lt_one
+ [ v.IsEquiv v',
+ ∀ {x y}, v x < v y ↔ v' x < v' y,
+ ∀ {x}, v x ≤ 1 ↔ v' x ≤ 1,
+ ∀ {x}, v x = 1 ↔ v' x = 1,
+ ∀ {x}, v x < 1 ↔ v' x < 1,
+ ∀ {x}, v (x - 1) < 1 ↔ v' (x - 1) < 1 ].TFAE := by
+ tfae_have 1 ↔ 2; · apply isEquiv_iff_val_lt_val
+ tfae_have 1 ↔ 3; · apply isEquiv_iff_val_le_one
+ tfae_have 1 ↔ 4; · apply isEquiv_iff_val_eq_one
+ tfae_have 1 ↔ 5; · apply isEquiv_iff_val_lt_one
+ tfae_have 1 ↔ 6; · apply isEquiv_iff_val_sub_one_lt_one
tfae_finish
end
@@ -831,13 +849,3 @@ end Supp
-- end of section
end AddValuation
-
-section ValuationNotation
-
-/-- Notation for `WithZero (Multiplicative ℕ)` -/
-scoped[DiscreteValuation] notation "ℕₘ₀" => WithZero (Multiplicative ℕ)
-
-/-- Notation for `WithZero (Multiplicative ℤ)` -/
-scoped[DiscreteValuation] notation "ℤₘ₀" => WithZero (Multiplicative ℤ)
-
-end ValuationNotation
diff --git a/Mathlib/RingTheory/Valuation/Integers.lean b/Mathlib/RingTheory/Valuation/Integers.lean
index ae1c553270829..83132e005a57e 100644
--- a/Mathlib/RingTheory/Valuation/Integers.lean
+++ b/Mathlib/RingTheory/Valuation/Integers.lean
@@ -13,6 +13,7 @@ The elements with valuation less than or equal to 1.
TODO: Define characteristic predicate.
-/
+open Set
universe u v w
@@ -144,6 +145,50 @@ theorem eq_algebraMap_or_inv_eq_algebraMap (hv : Integers v O) (x : F) :
obtain ⟨a, ha⟩ := exists_of_le_one hv h
exacts [⟨a, Or.inl ha.symm⟩, ⟨a, Or.inr ha.symm⟩]
+lemma isPrincipal_iff_exists_isGreatest (hv : Integers v O) {I : Ideal O} :
+ I.IsPrincipal ↔ ∃ x, IsGreatest (v ∘ algebraMap O F '' I) x := by
+ constructor <;> rintro ⟨x, hx⟩
+ · refine ⟨(v ∘ algebraMap O F) x, ?_, ?_⟩
+ · refine Set.mem_image_of_mem _ ?_
+ simp [hx, Ideal.mem_span_singleton_self]
+ · intro y hy
+ simp only [Function.comp_apply, hx, Ideal.submodule_span_eq, Set.mem_image,
+ SetLike.mem_coe, Ideal.mem_span_singleton] at hy
+ obtain ⟨y, hy, rfl⟩ := hy
+ exact le_of_dvd hv hy
+ · obtain ⟨a, ha, rfl⟩ : ∃ a ∈ I, (v ∘ algebraMap O F) a = x := by simpa using hx.left
+ refine ⟨a, ?_⟩
+ ext b
+ simp only [Ideal.submodule_span_eq, Ideal.mem_span_singleton]
+ exact ⟨fun hb ↦ dvd_of_le hv (hx.2 <| mem_image_of_mem _ hb), fun hb ↦ I.mem_of_dvd hb ha⟩
+
+lemma not_denselyOrdered_of_isPrincipalIdealRing [IsPrincipalIdealRing O] (hv : Integers v O) :
+ ¬ DenselyOrdered (range v) := by
+ intro H
+ -- nonunits as an ideal isn't defined here, nor shown to be equivalent to `v x < 1`
+ set I : Ideal O := {
+ carrier := v ∘ algebraMap O F ⁻¹' Iio (1 : Γ₀)
+ add_mem' := fun {a b} ha hb ↦ by simpa using map_add_lt v ha hb
+ zero_mem' := by simp
+ smul_mem' := by
+ intro c x
+ simp only [mem_preimage, Function.comp_apply, mem_Iio, smul_eq_mul, _root_.map_mul]
+ intro hx
+ exact Right.mul_lt_one_of_le_of_lt (hv.map_le_one c) hx
+ }
+ obtain ⟨x, hx₁, hx⟩ :
+ ∃ x, v (algebraMap O F x) < 1 ∧
+ v (algebraMap O F x) ∈ upperBounds (Iio 1 ∩ range (v ∘ algebraMap O F)) := by
+ simpa [I, IsGreatest, hv.isPrincipal_iff_exists_isGreatest, ← image_preimage_eq_inter_range]
+ using IsPrincipalIdealRing.principal I
+ obtain ⟨y, hy, hy₁⟩ : ∃ y, v (algebraMap O F x) < v y ∧ v y < 1 := by
+ simpa only [Subtype.exists, Subtype.mk_lt_mk, exists_range_iff, exists_prop]
+ using H.dense ⟨v (algebraMap O F x), mem_range_self _⟩ ⟨1, 1, v.map_one⟩ hx₁
+ obtain ⟨z, rfl⟩ := hv.exists_of_le_one hy₁.le
+ exact hy.not_le <| hx ⟨hy₁, mem_range_self _⟩
+
+-- TODO: isPrincipalIdealRing_iff_not_denselyOrdered when MulArchimedean
+
end Integers
end Field
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/Minpoly.lean b/Mathlib/RingTheory/Valuation/Minpoly.lean
index 3448962da4e70..00094cc933c86 100644
--- a/Mathlib/RingTheory/Valuation/Minpoly.lean
+++ b/Mathlib/RingTheory/Valuation/Minpoly.lean
@@ -21,7 +21,7 @@ Let `K` be a field with a valuation `v` and let `L` be a field extension of `K`.
is helpful for defining the valuation on `L` inducing `v`.
-/
-open FiniteDimensional minpoly Polynomial
+open Module minpoly Polynomial
variable {K : Type*} [Field K] {Γ₀ : Type*} [LinearOrderedCommGroupWithZero Γ₀]
(v : Valuation K Γ₀) (L : Type*) [Field L] [Algebra K L]
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
new file mode 100644
index 0000000000000..11ee048743d9c
--- /dev/null
+++ b/Mathlib/RingTheory/Valuation/ValExtension.lean
@@ -0,0 +1,162 @@
+/-
+Copyright (c) 2024 Jiedong Jiang. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Jiedong Jiang, Bichang Lei
+-/
+import Mathlib.RingTheory.Valuation.Integers
+import Mathlib.Algebra.Group.Units.Hom
+
+/-!
+# Extension of Valuation
+
+In this file, we define the typeclass for valuation extensions and prove basic facts about the
+extension of valuations. Let `A` be an `R` algebra, equipped with valuations `vA` and `vR`
+respectively. Here, the extension of a valuation means that the pullback of valuation `vA` to `R`
+is equivalent to the valuation `vR` on `R`. We only require equivalence, not equality, of
+valuations here.
+
+Note that we do not require the ring map from `R` to `A` to be injective. This holds automatically
+when `R` is a division ring and `A` is nontrivial.
+
+A motivation for choosing the more flexible `Valuation.Equiv` rather than strict equality here is
+to allow for possible normalization. As an example, consider a finite extension `K` of `ℚ_[p]`,
+which is a discretely valued field. We may choose the valuation on `K` to be either:
+
+1. the valuation where the uniformizer is mapped to one (more precisely, `-1` in `ℤₘ₀`) or
+
+2. the valuation where `p` is mapped to one.
+
+For the algebraic closure of `ℚ_[p]`, if we choose the valuation of `p` to be one, then the
+restriction of this valuation to `K` equals the second valuation, but is only equivalent to the
+first valuation. The flexibility of equivalence here allows us to develop theory for both cases
+without first determining the normalizations once and for all.
+
+## Main Definition
+
+* `IsValExtension vR vA` : The valuation `vA` on `A` is an extension of the valuation `vR` on `R`.
+
+## References
+
+* [Bourbaki, Nicolas. *Commutative algebra*] Chapter VI §3, Valuations.
+*
+
+## Tags
+Valuation, Extension of Valuations
+
+-/
+open Valuation
+
+variable {R A ΓR ΓA : Type*} [CommRing R] [Ring A]
+ [LinearOrderedCommMonoidWithZero ΓR] [LinearOrderedCommMonoidWithZero ΓA] [Algebra R A]
+ (vR : Valuation R ΓR) (vA : Valuation A Γ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 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` -/
+ val_isEquiv_comap : vR.IsEquiv <| vA.comap (algebraMap R A)
+
+namespace IsValExtension
+
+section algebraMap
+
+variable [IsValExtension vR vA]
+
+-- @[simp] does not work because `vR` cannot be inferred from `R`.
+theorem val_map_le_iff (x y : R) : vA (algebraMap R A x) ≤ vA (algebraMap R A y) ↔ vR x ≤ vR y :=
+ val_isEquiv_comap.symm x y
+
+theorem val_map_lt_iff (x y : R) : vA (algebraMap R A x) < vA (algebraMap R A y) ↔ vR x < vR y := by
+ simpa only [not_le] using ((val_map_le_iff vR vA _ _).not)
+
+theorem val_map_eq_iff (x y : R) : vA (algebraMap R A x) = vA (algebraMap R A y) ↔ vR x = vR y :=
+ (IsEquiv.val_eq val_isEquiv_comap).symm
+
+theorem val_map_le_one_iff (x : R) : vA (algebraMap R A x) ≤ 1 ↔ vR x ≤ 1 := by
+ simpa only [_root_.map_one] using val_map_le_iff vR vA x 1
+
+theorem val_map_lt_one_iff (x : R) : vA (algebraMap R A x) < 1 ↔ vR x < 1 := by
+ simpa only [_root_.map_one, not_le] using (val_map_le_iff vR vA 1 x).not
+
+theorem val_map_eq_one_iff (x : R) : vA (algebraMap R A x) = 1 ↔ vR x = 1 := by
+ simpa only [le_antisymm_iff, _root_.map_one] using
+ and_congr (val_map_le_iff vR vA x 1) (val_map_le_iff vR vA 1 x)
+
+end algebraMap
+
+instance id : IsValExtension vR vR where
+ val_isEquiv_comap := by
+ simp only [Algebra.id.map_eq_id, comap_id, IsEquiv.refl]
+
+section integer
+
+variable {K : Type*} [Field K] [Algebra K A] {ΓR ΓA ΓK: Type*}
+ [LinearOrderedCommGroupWithZero ΓR] [LinearOrderedCommGroupWithZero ΓK]
+ [LinearOrderedCommGroupWithZero ΓA] {vR : Valuation R ΓR} {vK : Valuation K ΓK}
+ {vA : Valuation A ΓA} [IsValExtension vR vA]
+
+/--
+When `K` is a field, if the preimage of the valuation integers of `A` equals to the valuation
+integers of `K`, then the valuation on `A` is an extension of the valuation on `K`.
+-/
+theorem ofComapInteger (h : vA.integer.comap (algebraMap K A) = vK.integer) :
+ IsValExtension vK vA where
+ val_isEquiv_comap := by
+ rw [isEquiv_iff_val_le_one]
+ intro x
+ simp_rw [← Valuation.mem_integer_iff, ← h, Subring.mem_comap, mem_integer_iff, comap_apply]
+
+instance instAlgebraInteger : Algebra vR.integer vA.integer where
+ smul r a := ⟨r • a,
+ Algebra.smul_def r (a : A) ▸ mul_mem ((val_map_le_one_iff vR vA _).mpr r.2) a.2⟩
+ __ := (algebraMap R A).restrict vR.integer vA.integer
+ (by simp [Valuation.mem_integer_iff, val_map_le_one_iff vR vA])
+ commutes' _ _ := Subtype.ext (Algebra.commutes _ _)
+ smul_def' _ _ := Subtype.ext (Algebra.smul_def _ _)
+
+@[simp, norm_cast]
+theorem val_smul (r : vR.integer) (a : vA.integer) : ↑(r • a : vA.integer) = (r : R) • (a : A) := by
+ rfl
+
+@[simp, norm_cast]
+theorem val_algebraMap (r : vR.integer) :
+ ((algebraMap vR.integer vA.integer) r : A) = (algebraMap R A) (r : R) := by
+ rfl
+
+instance instIsScalarTowerInteger : IsScalarTower vR.integer vA.integer A where
+ smul_assoc x y z := by
+ simp only [Algebra.smul_def]
+ exact mul_assoc _ _ _
+
+instance instNoZeroSMulDivisorsInteger [NoZeroSMulDivisors R A] :
+ NoZeroSMulDivisors vR.integer vA.integer := by
+ refine ⟨fun {x y} e ↦ ?_⟩
+ have : (x : R) • (y : A) = 0 := by simpa [Subtype.ext_iff, Algebra.smul_def] using e
+ simpa only [Subtype.ext_iff, smul_eq_zero] using this
+
+theorem algebraMap_injective [IsValExtension vK vA] [Nontrivial A] :
+ Function.Injective (algebraMap vK.integer vA.integer) := by
+ intro x y h
+ simp only [Subtype.ext_iff, val_algebraMap] at h
+ ext
+ apply RingHom.injective (algebraMap K A) h
+
+@[instance]
+theorem instIsLocalHomValuationInteger {S ΓS: Type*} [CommRing S]
+ [LinearOrderedCommGroupWithZero ΓS]
+ [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 3aa7cd60c9a41..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
@@ -363,10 +363,10 @@ protected theorem TFAE (R : Type u) [CommRing R] [IsDomain R] :
[ValuationRing R,
∀ x : FractionRing R, IsLocalization.IsInteger R x ∨ IsLocalization.IsInteger R x⁻¹,
IsTotal R (· ∣ ·), IsTotal (Ideal R) (· ≤ ·), LocalRing R ∧ IsBezout R] := by
- tfae_have 1 ↔ 2; · exact iff_isInteger_or_isInteger R _
- tfae_have 1 ↔ 3; · exact iff_dvd_total
- tfae_have 1 ↔ 4; · exact iff_ideal_total
- tfae_have 1 ↔ 5; · exact iff_local_bezout_domain
+ tfae_have 1 ↔ 2 := iff_isInteger_or_isInteger R _
+ tfae_have 1 ↔ 3 := iff_dvd_total
+ tfae_have 1 ↔ 4 := iff_ideal_total
+ tfae_have 1 ↔ 5 := iff_local_bezout_domain
tfae_finish
end
diff --git a/Mathlib/RingTheory/Valuation/ValuationSubring.lean b/Mathlib/RingTheory/Valuation/ValuationSubring.lean
index d3e74258289fb..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
@@ -788,6 +787,6 @@ variable {Γ : Type*} [LinearOrderedCommGroupWithZero Γ] (v : Valuation K Γ) (
-- @[simp] -- Porting note: not in simpNF
theorem mem_unitGroup_iff : x ∈ v.valuationSubring.unitGroup ↔ v x = 1 :=
- (Valuation.isEquiv_iff_val_eq_one _ _).mp (Valuation.isEquiv_valuation_valuationSubring _).symm
+ IsEquiv.eq_one_iff_eq_one (Valuation.isEquiv_valuation_valuationSubring _).symm
end Valuation
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 0492664ca9471..91f21547ab839 100644
--- a/Mathlib/RingTheory/WittVector/Frobenius.lean
+++ b/Mathlib/RingTheory/WittVector/Frobenius.lean
@@ -3,11 +3,11 @@ 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.Algebra.ZMod
import Mathlib.Data.Nat.Multiplicity
-import Mathlib.Data.ZMod.Algebra
+import Mathlib.FieldTheory.Perfect
import Mathlib.RingTheory.WittVector.Basic
import Mathlib.RingTheory.WittVector.IsPoly
-import Mathlib.FieldTheory.Perfect
/-!
## The Frobenius operator
@@ -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/Isocrystal.lean b/Mathlib/RingTheory/WittVector/Isocrystal.lean
index 5ba7feb02f7c6..0f5d266cc6c93 100644
--- a/Mathlib/RingTheory/WittVector/Isocrystal.lean
+++ b/Mathlib/RingTheory/WittVector/Isocrystal.lean
@@ -54,7 +54,7 @@ This file introduces notation in the locale `Isocrystal`.
noncomputable section
-open FiniteDimensional
+open Module
namespace WittVector
@@ -181,7 +181,7 @@ admits an isomorphism to one of the standard (indexed by `m : ℤ`) one-dimensio
theorem isocrystal_classification (k : Type*) [Field k] [IsAlgClosed k] [CharP k p] (V : Type*)
[AddCommGroup V] [Isocrystal p k V] (h_dim : finrank K(p, k) V = 1) :
∃ m : ℤ, Nonempty (StandardOneDimIsocrystal p k m ≃ᶠⁱ[p, k] V) := by
- haveI : Nontrivial V := FiniteDimensional.nontrivial_of_finrank_eq_succ h_dim
+ haveI : Nontrivial V := Module.nontrivial_of_finrank_eq_succ h_dim
obtain ⟨x, hx⟩ : ∃ x : V, x ≠ 0 := exists_ne 0
have : Φ(p, k) x ≠ 0 := by simpa only [map_zero] using Φ(p, k).injective.ne hx
obtain ⟨a, ha, hax⟩ : ∃ a : K(p, k), a ≠ 0 ∧ Φ(p, k) x = a • x := by
diff --git a/Mathlib/RingTheory/WittVector/MulCoeff.lean b/Mathlib/RingTheory/WittVector/MulCoeff.lean
index 52cb2c116b25b..fa74982d2d6fa 100644
--- a/Mathlib/RingTheory/WittVector/MulCoeff.lean
+++ b/Mathlib/RingTheory/WittVector/MulCoeff.lean
@@ -118,11 +118,10 @@ theorem mul_polyOfInterest_aux1 (n : ℕ) :
congr 1
have hsupp : (Finsupp.single i (p ^ (n - i))).support = {i} := by
rw [Finsupp.support_eq_singleton]
- simp only [and_true_iff, Finsupp.single_eq_same, eq_self_iff_true, Ne]
+ simp only [and_true, Finsupp.single_eq_same, eq_self_iff_true, Ne]
exact pow_ne_zero _ hp.out.ne_zero
simp only [bind₁_monomial, hsupp, Int.cast_natCast, prod_singleton, eq_intCast,
- Finsupp.single_eq_same, C_pow, mul_eq_mul_left_iff, true_or_iff, eq_self_iff_true,
- Int.cast_pow]
+ Finsupp.single_eq_same, C_pow, mul_eq_mul_left_iff, eq_self_iff_true, Int.cast_pow]
· simp only [map_mul, bind₁_X_right]
theorem mul_polyOfInterest_aux2 (n : ℕ) :
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/StructurePolynomial.lean b/Mathlib/RingTheory/WittVector/StructurePolynomial.lean
index ad4f137a05748..5a89447cb88ff 100644
--- a/Mathlib/RingTheory/WittVector/StructurePolynomial.lean
+++ b/Mathlib/RingTheory/WittVector/StructurePolynomial.lean
@@ -370,7 +370,7 @@ theorem wittStructureRat_vars [Fintype idx] (Φ : MvPolynomial idx ℚ) (n : ℕ
(wittStructureRat p Φ n).vars ⊆ Finset.univ ×ˢ Finset.range (n + 1) := by
rw [wittStructureRat]
intro x hx
- simp only [Finset.mem_product, true_and_iff, Finset.mem_univ, Finset.mem_range]
+ simp only [Finset.mem_product, true_and, Finset.mem_univ, Finset.mem_range]
obtain ⟨k, hk, hx'⟩ := mem_vars_bind₁ _ _ hx
obtain ⟨i, -, hx''⟩ := mem_vars_bind₁ _ _ hx'
obtain ⟨j, hj, rfl⟩ := mem_vars_rename _ _ hx''
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/RingTheory/WittVector/WittPolynomial.lean b/Mathlib/RingTheory/WittVector/WittPolynomial.lean
index aab99256bb5a2..ea728fea38133 100644
--- a/Mathlib/RingTheory/WittVector/WittPolynomial.lean
+++ b/Mathlib/RingTheory/WittVector/WittPolynomial.lean
@@ -230,7 +230,7 @@ theorem xInTermsOfW_vars_aux (n : ℕ) :
rw [xInTermsOfW_eq, mul_comm, vars_C_mul _ (Invertible.ne_zero _),
vars_sub_of_disjoint, vars_X, range_succ, insert_eq]
on_goal 1 =>
- simp only [true_and_iff, true_or_iff, eq_self_iff_true, mem_union, mem_singleton]
+ simp only [true_and, true_or, eq_self_iff_true, mem_union, mem_singleton]
intro i
rw [mem_union, mem_union]
apply Or.imp id
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 56%
rename from Mathlib/SetTheory/Cardinal/Ordinal.lean
rename to Mathlib/SetTheory/Cardinal/Arithmetic.lean
index b9f6c63e10014..0bdbc4b83972d 100644
--- a/Mathlib/SetTheory/Cardinal/Ordinal.lean
+++ b/Mathlib/SetTheory/Cardinal/Arithmetic.lean
@@ -3,39 +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.
+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 definitions
-
-* The function `Cardinal.aleph'` gives the cardinals listed by their ordinal
- index, and is the inverse of `Cardinal.aleph/idx`.
- `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`.
-
-## Main Statements
+## 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.
-* simp lemmas for inequalities between `bit0 a` and `bit1 b` are registered, making `simp`
- able to prove inequalities about numeral cardinals.
+* `Cardinal.mk_list_eq_mk`: when `α` is infinite, `α` and `List α` have the same cardinality.
## Tags
@@ -53,387 +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 omega_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'` 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`. -/
-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.)
- For an upgraded version stating that the range is everything, see `AlephIdx.rel_iso`. -/
-def alephIdx : Cardinal → Ordinal :=
- alephIdx.initialSeg
-
-@[simp]
-theorem alephIdx.initialSeg_coe : (alephIdx.initialSeg : Cardinal → Ordinal) = alephIdx :=
- rfl
-
-@[simp]
-theorem alephIdx_lt {a b} : alephIdx a < alephIdx b ↔ a < b :=
- alephIdx.initialSeg.toRelEmbedding.map_rel_iff
-
-@[simp]
-theorem alephIdx_le {a b} : alephIdx a ≤ alephIdx b ↔ a ≤ b := by
- rw [← not_lt, ← not_lt, alephIdx_lt]
-
-theorem alephIdx.init {a b} : b < alephIdx a → ∃ c, alephIdx c = b :=
- alephIdx.initialSeg.init
-
-/-- 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`. -/
-def alephIdx.relIso : @RelIso Cardinal.{u} Ordinal.{u} (· < ·) (· < ·) :=
- @RelIso.ofSurjective Cardinal.{u} Ordinal.{u} (· < ·) (· < ·) alephIdx.initialSeg.{u} <|
- (InitialSeg.eq_or_principal alephIdx.initialSeg.{u}).resolve_right fun ⟨o, e⟩ => by
- have : ∀ c, alephIdx c < o := fun c => (e _).2 ⟨_, rfl⟩
- refine Ordinal.inductionOn o ?_ this; intro α r _ h
- let s := ⨆ a, invFun alephIdx (Ordinal.typein r a)
- apply (lt_succ s).not_le
- have I : Injective.{u+2, u+2} alephIdx := alephIdx.initialSeg.toEmbedding.injective
- simpa only [typein_enum, leftInverse_invFun I (succ s)] using
- le_ciSup
- (Cardinal.bddAbove_range.{u, u} fun a : α => invFun alephIdx (Ordinal.typein r a))
- (Ordinal.enum r ⟨_, h (succ s)⟩)
-
-@[simp]
-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 ⟨alephIdx.relIso⟩
-
-@[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'`. -/
-def Aleph'.relIso :=
- Cardinal.alephIdx.relIso.symm
-
-/-- 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. -/
-def aleph' : Ordinal → Cardinal :=
- Aleph'.relIso
-
-@[simp]
-theorem aleph'.relIso_coe : (Aleph'.relIso : Ordinal → Cardinal) = aleph' :=
- rfl
-
-@[simp]
-theorem aleph'_lt {o₁ o₂ : Ordinal} : aleph' o₁ < aleph' o₂ ↔ o₁ < o₂ :=
- Aleph'.relIso.map_rel_iff
-
-@[simp]
-theorem aleph'_le {o₁ o₂ : Ordinal} : aleph' o₁ ≤ aleph' o₂ ↔ o₁ ≤ o₂ :=
- le_iff_le_iff_lt_iff_lt.2 aleph'_lt
-
-@[simp]
-theorem aleph'_alephIdx (c : Cardinal) : aleph' c.alephIdx = c :=
- Cardinal.alephIdx.relIso.toEquiv.symm_apply_apply c
-
-@[simp]
-theorem alephIdx_aleph' (o : Ordinal) : (aleph' o).alephIdx = o :=
- Cardinal.alephIdx.relIso.toEquiv.apply_symm_apply o
-
-@[simp]
-theorem aleph'_zero : aleph' 0 = 0 := by
- rw [← nonpos_iff_eq_zero, ← aleph'_alephIdx 0, aleph'_le]
- apply Ordinal.zero_le
-
-@[simp]
-theorem aleph'_succ {o : Ordinal} : aleph' (succ o) = succ (aleph' o) := by
- apply (succ_le_of_lt <| aleph'_lt.2 <| lt_succ o).antisymm' (Cardinal.alephIdx_le.1 <| _)
- rw [alephIdx_aleph', succ_le_iff, ← aleph'_lt, aleph'_alephIdx]
- apply lt_succ
-
-@[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'_alephIdx c, aleph'_le, limit_le l]
- intro x h'
- rw [← aleph'_le, aleph'_alephIdx]
- 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'_omega : aleph' ω = ℵ₀ :=
- eq_of_forall_ge_iff fun c => by
- simp only [aleph'_le_of_limit omega_isLimit, lt_omega, exists_imp, aleph0_le]
- exact forall_swap.trans (forall_congr' fun n => by simp only [forall_eq, aleph'_nat])
-
-/-- `aleph'` and `aleph_idx` form an equivalence between `Ordinal` and `Cardinal` -/
-@[simp]
-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. -/
-def aleph (o : Ordinal) : Cardinal :=
- aleph' (ω + o)
-
-@[simp]
-theorem aleph_lt {o₁ o₂ : Ordinal} : aleph o₁ < aleph o₂ ↔ o₁ < o₂ :=
- aleph'_lt.trans (add_lt_add_iff_left _)
-
-@[simp]
-theorem aleph_le {o₁ o₂ : Ordinal} : aleph o₁ ≤ aleph o₂ ↔ o₁ ≤ o₂ :=
- le_iff_le_iff_lt_iff_lt.2 aleph_lt
-
-@[simp]
-theorem max_aleph_eq (o₁ o₂ : Ordinal) : max (aleph o₁) (aleph o₂) = aleph (max o₁ o₂) := by
- rcases le_total (aleph o₁) (aleph o₂) with h | h
- · rw [max_eq_right h, max_eq_right (aleph_le.1 h)]
- · rw [max_eq_left h, max_eq_left (aleph_le.1 h)]
-
-@[simp]
-theorem aleph_succ {o : Ordinal} : aleph (succ o) = succ (aleph o) := by
- rw [aleph, add_succ, aleph'_succ, aleph]
-
-@[simp]
-theorem aleph_zero : aleph 0 = ℵ₀ := by rw [aleph, add_zero, aleph'_omega]
-
-theorem aleph_limit {o : Ordinal} (ho : o.IsLimit) : aleph o = ⨆ a : Iio o, aleph a := by
- apply le_antisymm _ (ciSup_le' _)
- · rw [aleph, aleph'_limit (ho.add _)]
- refine ciSup_mono' (bddAbove_of_small _) ?_
- rintro ⟨i, hi⟩
- cases' lt_or_le i ω with h h
- · rcases lt_omega.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'_omega, aleph'_le]
-
-theorem aleph0_le_aleph (o : Ordinal) : ℵ₀ ≤ aleph o := by
- rw [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 =>
- ⟨alephIdx c - ω, by
- rw [aleph, Ordinal.add_sub_cancel_of_le, aleph'_alephIdx]
- rwa [← aleph0_le_aleph', aleph'_alephIdx]⟩,
- 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]
-
-/-- Ordinals that are cardinals are unbounded. -/
-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⟩⟩
-
-theorem eq_aleph'_of_eq_card_ord {o : Ordinal} (ho : o.card.ord = o) : ∃ a, (aleph' a).ord = o :=
- ⟨Cardinal.alephIdx.relIso o.card, by simpa using ho⟩
-
-/-- `ord ∘ aleph'` enumerates the ordinals that are cardinals. -/
-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. -/
-theorem ord_card_unbounded' : Unbounded (· < ·) { b : Ordinal | b.card.ord = b ∧ ω ≤ b } :=
- (unbounded_lt_inter_le ω).2 ord_card_unbounded
-
-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 - ω
- unfold aleph
- rwa [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. -/
-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 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
@@ -470,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 :=
@@ -497,8 +100,8 @@ 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
- rw [Cardinal.mul_eq_max (aleph0_le_aleph o₁) (aleph0_le_aleph o₂), max_aleph_eq]
+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]
theorem aleph0_mul_eq {a : Cardinal} (ha : ℵ₀ ≤ a) : ℵ₀ * a = a :=
@@ -508,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 :=
@@ -722,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 α)
@@ -753,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})
@@ -767,8 +368,8 @@ protected theorem ciSup_add (hf : BddAbove (range f)) (c : Cardinal.{v}) :
refine le_antisymm ?_ (ciSup_le' this)
have bdd : BddAbove (range (f · + c)) := ⟨_, forall_mem_range.mpr this⟩
obtain hs | hs := lt_or_le (⨆ i, f i) ℵ₀
- · obtain ⟨i, hi⟩ := exists_eq_of_iSup_eq_of_not_isLimit
- f hf _ (fun h ↦ hs.not_le h.aleph0_le) rfl
+ · obtain ⟨i, hi⟩ := exists_eq_of_iSup_eq_of_not_isSuccLimit
+ f hf (not_isSuccLimit_of_lt_aleph0 hs) rfl
exact hi ▸ le_ciSup bdd i
rw [add_eq_max hs, max_le_iff]
exact ⟨ciSup_mono bdd fun i ↦ self_le_add_right _ c,
@@ -796,8 +397,8 @@ protected theorem ciSup_mul (c : Cardinal.{v}) : (⨆ i, f i) * c = ⨆ i, f i *
refine le_antisymm ?_ (ciSup_le' this)
have bdd : BddAbove (range (f · * c)) := ⟨_, forall_mem_range.mpr this⟩
obtain hs | hs := lt_or_le (⨆ i, f i) ℵ₀
- · obtain ⟨i, hi⟩ := exists_eq_of_iSup_eq_of_not_isLimit
- f hf _ (fun h ↦ hs.not_le h.aleph0_le) rfl
+ · obtain ⟨i, hi⟩ := exists_eq_of_iSup_eq_of_not_isSuccLimit
+ f hf (not_isSuccLimit_of_lt_aleph0 hs) rfl
exact hi ▸ le_ciSup bdd i
rw [mul_eq_max_of_aleph0_le_left hs h0, max_le_iff]
obtain ⟨i, hi⟩ := exists_lt_of_lt_ciSup' (one_lt_aleph0.trans_le hs)
@@ -813,16 +414,19 @@ 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
- rw [Cardinal.add_eq_max (aleph0_le_aleph o₁), max_aleph_eq]
+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 :=
fun a b ha hb => by
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) : α + γ = β + γ ↔ α = β :=
@@ -836,7 +440,7 @@ theorem add_nat_inj {α β : Cardinal} (n : ℕ) : α + n = β + n ↔ α = β :
theorem add_one_inj {α β : Cardinal} : α + 1 = β + 1 ↔ α = β :=
add_right_inj_of_lt_aleph0 one_lt_aleph0
-theorem add_le_add_iff_of_lt_aleph0 {α β γ : Cardinal} (γ₀ : γ < Cardinal.aleph0) :
+theorem add_le_add_iff_of_lt_aleph0 {α β γ : Cardinal} (γ₀ : γ < ℵ₀) :
α + γ ≤ β + γ ↔ α ≤ β := by
refine ⟨fun h => ?_, fun h => add_le_add_right h γ⟩
contrapose h
@@ -857,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
@@ -933,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
@@ -1177,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
@@ -1206,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 omega_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
@@ -1451,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 07f003b340470..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,14 +81,16 @@ 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
-universe u v w
+universe u v w v' w'
variable {α β : Type u}
+/-! ### Definition of cardinals -/
+
/-- The equivalence relation on types given by equivalence (bijective correspondence) of types.
Quotienting by this equivalence relation gives the cardinal numbers.
-/
@@ -130,10 +134,15 @@ theorem inductionOn₃ {p : Cardinal → Cardinal → Cardinal → Prop} (c₁ :
(c₃ : Cardinal) (h : ∀ α β γ, p #α #β #γ) : p c₁ c₂ c₃ :=
Quotient.inductionOn₃ c₁ c₂ c₃ h
+theorem induction_on_pi {ι : Type u} {p : (ι → Cardinal.{v}) → Prop}
+ (f : ι → Cardinal.{v}) (h : ∀ f : ι → Type v, p fun i ↦ #(f i)) : p f :=
+ Quotient.induction_on_pi f h
+
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
@@ -164,52 +173,6 @@ def map₂ (f : Type u → Type v → Type w) (hf : ∀ α β γ δ, α ≃ β
Cardinal.{u} → Cardinal.{v} → Cardinal.{w} :=
Quotient.map₂ f fun α β ⟨e₁⟩ γ δ ⟨e₂⟩ => ⟨hf α β γ δ e₁ e₂⟩
-/-- The universe lift operation on cardinals. You can specify the universes explicitly with
- `lift.{u v} : Cardinal.{v} → Cardinal.{max v u}` -/
-@[pp_with_univ]
-def lift (c : Cardinal.{v}) : Cardinal.{max v u} :=
- map ULift.{u, v} (fun _ _ e => Equiv.ulift.trans <| e.trans Equiv.ulift.symm) c
-
-@[simp]
-theorem mk_uLift (α) : #(ULift.{v, u} α) = lift.{v} #α :=
- rfl
-
--- Porting note: simpNF is not happy with universe levels, but this is needed as simp lemma
--- further down in this file
-/-- `lift.{max u v, u}` equals `lift.{v, u}`. -/
-@[simp, nolint simpNF]
-theorem lift_umax : lift.{max u v, u} = lift.{v, u} :=
- funext fun a => inductionOn a fun _ => (Equiv.ulift.trans Equiv.ulift.symm).cardinal_eq
-
--- Porting note: simpNF is not happy with universe levels, but this is needed as simp lemma
--- further down in this file
-/-- `lift.{max v u, u}` equals `lift.{v, u}`. -/
-@[simp, nolint simpNF]
-theorem lift_umax' : lift.{max v u, u} = lift.{v, u} :=
- lift_umax
-
--- Porting note: simpNF is not happy with universe levels, but this is needed as simp lemma
--- further down in this file
-/-- A cardinal lifted to a lower or equal universe equals itself. -/
-@[simp, nolint simpNF]
-theorem lift_id' (a : Cardinal.{max u v}) : lift.{u} a = a :=
- inductionOn a fun _ => mk_congr Equiv.ulift
-
-/-- A cardinal lifted to the same universe equals itself. -/
-@[simp]
-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
-
-@[simp]
-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
-
/-- We define the order on cardinal numbers by `#α ≤ #β` if and only if
there exists an embedding (injective function) from α to β. -/
instance : LE Cardinal.{u} :=
@@ -258,6 +221,56 @@ theorem mk_subtype_le {α : Type u} (p : α → Prop) : #(Subtype p) ≤ #α :=
theorem mk_set_le (s : Set α) : #s ≤ #α :=
mk_subtype_le s
+/-! ### Lifting cardinals to a higher universe -/
+
+/-- The universe lift operation on cardinals. You can specify the universes explicitly with
+ `lift.{u v} : Cardinal.{v} → Cardinal.{max v u}` -/
+@[pp_with_univ]
+def lift (c : Cardinal.{v}) : Cardinal.{max v u} :=
+ map ULift.{u, v} (fun _ _ e => Equiv.ulift.trans <| e.trans Equiv.ulift.symm) c
+
+@[simp]
+theorem mk_uLift (α) : #(ULift.{v, u} α) = lift.{v} #α :=
+ rfl
+
+-- Porting note: simpNF is not happy with universe levels, but this is needed as simp lemma
+-- further down in this file
+/-- `lift.{max u v, u}` equals `lift.{v, u}`. -/
+@[simp, nolint simpNF]
+theorem lift_umax : lift.{max u v, u} = lift.{v, u} :=
+ funext fun a => inductionOn a fun _ => (Equiv.ulift.trans Equiv.ulift.symm).cardinal_eq
+
+-- Porting note: simpNF is not happy with universe levels, but this is needed as simp lemma
+-- further down in this file
+/-- `lift.{max v u, u}` equals `lift.{v, u}`. -/
+@[simp, nolint simpNF]
+theorem lift_umax' : lift.{max v u, u} = lift.{v, u} :=
+ lift_umax
+
+-- Porting note: simpNF is not happy with universe levels, but this is needed as simp lemma
+-- further down in this file
+/-- A cardinal lifted to a lower or equal universe equals itself. -/
+@[simp, nolint simpNF]
+theorem lift_id' (a : Cardinal.{max u v}) : lift.{u} a = a :=
+ inductionOn a fun _ => mk_congr Equiv.ulift
+
+/-- A cardinal lifted to the same universe equals itself. -/
+@[simp]
+theorem lift_id (a : Cardinal) : lift.{u, u} a = a :=
+ lift_id'.{u, u} a
+
+/-- A cardinal lifted to the zero universe equals itself. -/
+theorem lift_uzero (a : Cardinal.{u}) : lift.{0} a = a :=
+ lift_id'.{0, u} a
+
+@[simp]
+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]
@@ -268,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 (α ↪ β) :=
@@ -297,34 +308,94 @@ 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}
+-- Porting note: simpNF is not happy with universe levels.
+@[simp, nolint simpNF]
+theorem lift_mk_shrink (α : Type u) [Small.{v} α] :
+ Cardinal.lift.{max u w} #(Shrink.{v} α) = Cardinal.lift.{max v w} #α :=
+ lift_mk_eq.2 ⟨(equivShrink α).symm⟩
+
@[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}
+theorem lift_mk_shrink' (α : Type u) [Small.{v} α] :
+ Cardinal.lift.{u} #(Shrink.{v} α) = Cardinal.lift.{v} #α :=
+ lift_mk_shrink.{u, v, 0} α
+
+@[simp]
+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 :=
+ mem_range_lift_of_le
--- Porting note: changed `simps` to `simps!` because the linter told to do so.
/-- `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
theorem lift_monotone : Monotone lift :=
lift_strictMono.monotone
+@[simp]
+theorem lift_min {a b : Cardinal} : lift.{u, v} (min a b) = min (lift.{u, v} a) (lift.{u, v} b) :=
+ lift_monotone.map_min
+
+@[simp]
+theorem lift_max {a b : Cardinal} : lift.{u, v} (max a b) = max (lift.{u, v} a) (lift.{u, v} b) :=
+ lift_monotone.map_max
+
+-- Porting note: simpNF is not happy with universe levels.
+@[simp, nolint simpNF]
+theorem lift_umax_eq {a : Cardinal.{u}} {b : Cardinal.{v}} :
+ lift.{max v w} a = lift.{max u w} b ↔ lift.{v} a = lift.{u} b := by
+ 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' ≤ 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' < a, lift.{v, u} a' = b :=
+ liftInitialSeg.lt_apply_iff
+
+/-! ### Basic cardinals -/
+
instance : Zero Cardinal.{u} :=
-- `PEmpty` might be more canonical, but this is convenient for defeq with natCast
⟨lift #(Fin 0)⟩
@@ -363,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⟩ =>
@@ -401,11 +472,6 @@ theorem mk_psum (α : Type u) (β : Type v) : #(α ⊕' β) = lift.{v} #α + lif
theorem mk_fintype (α : Type u) [h : Fintype α] : #α = Fintype.card α :=
mk_congr (Fintype.equivOfCardEq (by simp))
-protected theorem cast_succ (n : ℕ) : ((n + 1 : ℕ) : Cardinal.{u}) = n + 1 := by
- change #(ULift.{u} (Fin (n+1))) = # (ULift.{u} (Fin n)) + 1
- rw [← mk_option, mk_fintype, mk_fintype]
- simp only [Fintype.card_ulift, Fintype.card_fin, Fintype.card_option]
-
instance : Mul Cardinal.{u} :=
⟨map₂ Prod fun _ _ _ _ => Equiv.prodCongr⟩
@@ -416,9 +482,6 @@ theorem mul_def (α β : Type u) : #α * #β = #(α × β) :=
theorem mk_prod (α : Type u) (β : Type v) : #(α × β) = lift.{v, u} #α * lift.{u, v} #β :=
mk_congr (Equiv.ulift.symm.prodCongr Equiv.ulift.symm)
-private theorem mul_comm' (a b : Cardinal.{u}) : a * b = b * a :=
- inductionOn₂ a b fun α β => mk_congr <| Equiv.prodComm α β
-
/-- The cardinal exponential. `#α ^ #β` is the cardinal of `β → α`. -/
instance instPowCardinal : Pow Cardinal.{u} Cardinal.{u} :=
⟨map₂ (fun α β => β → α) fun _ _ _ _ e₁ e₂ => e₂.arrowCongr e₁⟩
@@ -435,52 +498,52 @@ theorem lift_power (a b : Cardinal.{u}) : lift.{v} (a ^ b) = lift.{v} a ^ lift.{
mk_congr <| Equiv.ulift.trans (Equiv.ulift.arrowCongr Equiv.ulift).symm
@[simp]
-theorem power_zero {a : Cardinal} : a ^ (0 : Cardinal) = 1 :=
+theorem power_zero (a : Cardinal) : a ^ (0 : Cardinal) = 1 :=
inductionOn a fun _ => mk_eq_one _
@[simp]
-theorem power_one {a : Cardinal.{u}} : a ^ (1 : Cardinal) = a :=
+theorem power_one (a : Cardinal.{u}) : a ^ (1 : Cardinal) = a :=
inductionOn a fun α => mk_congr (Equiv.funUnique (ULift.{u} (Fin 1)) α)
-theorem power_add {a b c : Cardinal} : a ^ (b + c) = a ^ b * a ^ c :=
+theorem power_add (a b c : Cardinal) : a ^ (b + c) = a ^ b * a ^ c :=
inductionOn₃ a b c fun α β γ => mk_congr <| Equiv.sumArrowEquivProdArrow β γ α
+private theorem cast_succ (n : ℕ) : ((n + 1 : ℕ) : Cardinal.{u}) = n + 1 := by
+ change #(ULift.{u} _) = #(ULift.{u} _) + 1
+ rw [← mk_option]
+ simp
+
instance commSemiring : CommSemiring Cardinal.{u} where
zero := 0
one := 1
add := (· + ·)
mul := (· * ·)
- zero_add a := inductionOn a fun α => mk_congr <| Equiv.emptySum (ULift (Fin 0)) α
- add_zero a := inductionOn a fun α => mk_congr <| Equiv.sumEmpty α (ULift (Fin 0))
+ zero_add a := inductionOn a fun α => mk_congr <| Equiv.emptySum _ α
+ 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 _
- one_mul a := inductionOn a fun α => mk_congr <| Equiv.uniqueProd α (ULift (Fin 1))
- mul_one a := inductionOn a fun α => mk_congr <| Equiv.prodUnique α (ULift (Fin 1))
+ 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 α β γ
- mul_comm := mul_comm'
+ mul_comm a b := inductionOn₂ a b fun α β => mk_congr <| Equiv.prodComm α β
left_distrib a b c := inductionOn₃ a b c fun α β γ => mk_congr <| Equiv.prodSumDistrib α β γ
right_distrib a b c := inductionOn₃ a b c fun α β γ => mk_congr <| Equiv.sumProdDistrib α β γ
nsmul := nsmulRec
npow n c := c ^ (n : Cardinal)
- npow_zero := @power_zero
- npow_succ n c := show c ^ (↑(n + 1) : Cardinal) = c ^ (↑n : Cardinal) * c
- by rw [Cardinal.cast_succ, power_add, power_one, mul_comm']
- natCast := (fun n => lift.{u} #(Fin n) : ℕ → Cardinal.{u})
+ npow_zero := power_zero
+ npow_succ n c := by dsimp; rw [cast_succ, power_add, power_one]
+ natCast n := lift #(Fin n)
natCast_zero := rfl
- natCast_succ := Cardinal.cast_succ
+ natCast_succ n := cast_succ n
@[simp]
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]
@@ -503,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 _
@@ -538,9 +604,7 @@ theorem mk_powerset {α : Type u} (s : Set α) : #(↥(𝒫 s)) = 2 ^ #(↥s) :=
theorem lift_two_power (a : Cardinal) : lift.{v} (2 ^ a) = 2 ^ lift.{v} a := by
simp [← one_add_one_eq_two]
-section OrderProperties
-
-open Sum
+/-! ### Order properties -/
protected theorem zero_le : ∀ a : Cardinal, 0 ≤ a := by
rintro ⟨α⟩
@@ -549,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} :=
@@ -560,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
@@ -568,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 }
@@ -610,7 +674,7 @@ theorem self_le_power (a : Cardinal) {b : Cardinal} (hb : 1 ≤ b) : a ≤ a ^ b
rcases eq_or_ne a 0 with (rfl | ha)
· exact zero_le _
· convert power_le_power_left ha hb
- exact power_one.symm
+ exact (power_one a).symm
/-- **Cantor's theorem** -/
theorem cantor (a : Cardinal.{u}) : a < 2 ^ a := by
@@ -639,8 +703,6 @@ theorem power_le_power_right {a b c : Cardinal} : a ≤ b → a ^ c ≤ b ^ c :=
theorem power_pos {a : Cardinal} (b : Cardinal) (ha : 0 < a) : 0 < a ^ b :=
(power_ne_zero _ ha.ne').bot_lt
-end OrderProperties
-
protected theorem lt_wf : @WellFounded Cardinal.{u} (· < ·) :=
⟨fun a =>
by_contradiction fun h => by
@@ -682,6 +744,22 @@ lemma iInf_eq_zero_iff {ι : Sort*} {f : ι → Cardinal} :
(⨅ i, f i) = 0 ↔ IsEmpty ι ∨ ∃ i, f i = 0 := by
simp [iInf, sInf_eq_zero_iff]
+/-- A variant of `ciSup_of_empty` but with `0` on the RHS for convenience -/
+protected theorem iSup_of_empty {ι} (f : ι → Cardinal) [IsEmpty ι] : iSup f = 0 :=
+ ciSup_of_empty f
+
+@[simp]
+theorem lift_sInf (s : Set Cardinal) : lift.{u, v} (sInf s) = sInf (lift.{u, v} '' s) := by
+ rcases eq_empty_or_nonempty s with (rfl | hs)
+ · simp
+ · exact lift_monotone.map_csInf hs
+
+@[simp]
+theorem lift_iInf {ι} (f : ι → Cardinal) : lift.{u, v} (iInf f) = ⨅ i, lift.{u, v} (f i) := by
+ unfold iInf
+ convert lift_sInf (range f)
+ simp_rw [← comp_apply (f := lift), range_comp]
+
/-- Note that the successor of `c` is not the same as `c + 1` except in the case of finite `c`. -/
instance : SuccOrder Cardinal := ConditionallyCompleteLinearOrder.toSuccOrder
@@ -708,44 +786,104 @@ theorem add_one_le_succ (c : Cardinal.{u}) : c + 1 ≤ succ c := by
#γ + 1 = #(Option γ) := mk_option.symm
_ ≤ #β := (f.optionElim b hb).cardinal_le
+@[simp]
+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, 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)
+
/-- A cardinal is a limit if it is not zero or a successor cardinal. Note that `ℵ₀` is a limit
cardinal by this definition, but `0` isn't.
-
- Use `IsSuccPrelimit` if you want to include the `c = 0` case. -/
+Deprecated. Use `Order.IsSuccLimit` instead. -/
+@[deprecated IsSuccLimit (since := "2024-09-17")]
def IsLimit (c : Cardinal) : Prop :=
c ≠ 0 ∧ IsSuccPrelimit c
-protected theorem IsLimit.ne_zero {c} (h : IsLimit c) : c ≠ 0 :=
- h.1
+theorem ne_zero_of_isSuccLimit {c} (h : IsSuccLimit c) : c ≠ 0 :=
+ h.ne_bot
+
+theorem isSuccPrelimit_zero : IsSuccPrelimit (0 : Cardinal) :=
+ isSuccPrelimit_bot
+
+protected theorem isSuccLimit_iff {c : Cardinal} : IsSuccLimit c ↔ c ≠ 0 ∧ IsSuccPrelimit c :=
+ isSuccLimit_iff
+
+section deprecated
+set_option linter.deprecated false
+
+@[deprecated IsSuccLimit.isSuccPrelimit (since := "2024-09-17")]
protected theorem IsLimit.isSuccPrelimit {c} (h : IsLimit c) : IsSuccPrelimit c :=
h.2
+@[deprecated ne_zero_of_isSuccLimit (since := "2024-09-17")]
+protected theorem IsLimit.ne_zero {c} (h : IsLimit c) : c ≠ 0 :=
+ h.1
+
@[deprecated IsLimit.isSuccPrelimit (since := "2024-09-05")]
alias IsLimit.isSuccLimit := IsLimit.isSuccPrelimit
+@[deprecated IsSuccLimit.succ_lt (since := "2024-09-17")]
theorem IsLimit.succ_lt {x c} (h : IsLimit c) : x < c → succ x < c :=
h.isSuccPrelimit.succ_lt
-theorem isSuccPrelimit_zero : IsSuccPrelimit (0 : Cardinal) :=
- isSuccPrelimit_bot
-
@[deprecated isSuccPrelimit_zero (since := "2024-09-05")]
alias isSuccLimit_zero := isSuccPrelimit_zero
+end deprecated
+
+/-! ### Indexed cardinal `sum` -/
+
/-- The indexed sum of cardinals is the cardinality of the
indexed disjoint union, i.e. sigma type. -/
def sum {ι} (f : ι → Cardinal) : Cardinal :=
- mk (Σi, (f i).out)
+ mk (Σ i, (f i).out)
theorem le_sum {ι} (f : ι → Cardinal) (i) : f i ≤ sum f := by
rw [← Quotient.out_eq (f i)]
exact ⟨⟨fun a => ⟨i, a⟩, fun a b h => by injection h⟩⟩
+theorem iSup_le_sum {ι} (f : ι → Cardinal) : iSup f ≤ sum f :=
+ ciSup_le' <| le_sum _
+
@[simp]
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 _ _ ↦ α
+
@[simp]
theorem sum_const (ι : Type u) (a : Cardinal.{v}) :
(sum fun _ : ι => a) = lift.{v} #ι * lift.{u} a :=
@@ -804,6 +942,48 @@ theorem lift_mk_le_lift_mk_mul_of_lift_mk_preimage_le {α : Type u} {β : Type v
Equiv.ulift.symm)).trans_le
(hf b)
+theorem sum_nat_eq_add_sum_succ (f : ℕ → Cardinal.{u}) :
+ Cardinal.sum f = f 0 + Cardinal.sum fun i => f (i + 1) := by
+ refine (Equiv.sigmaNatSucc fun i => Quotient.out (f i)).cardinal_eq.trans ?_
+ simp only [mk_sum, mk_out, lift_id, mk_sigma]
+
+end Cardinal
+
+/-! ### Well-ordering theorem -/
+
+open Cardinal in
+theorem nonempty_embedding_to_cardinal : Nonempty (α ↪ Cardinal.{u}) :=
+ (Embedding.total _ _).resolve_left fun ⟨⟨f, hf⟩⟩ =>
+ let g : α → Cardinal.{u} := invFun f
+ let ⟨x, (hx : g x = 2 ^ sum g)⟩ := invFun_surjective hf (2 ^ sum g)
+ have : g x ≤ sum g := le_sum.{u, u} g x
+ not_le_of_gt (by rw [hx]; exact cantor _) this
+
+/-- An embedding of any type to the set of cardinals in its universe. -/
+def embeddingToCardinal : α ↪ Cardinal.{u} :=
+ Classical.choice nonempty_embedding_to_cardinal
+
+/-- Any type can be endowed with a well order, obtained by pulling back the well order over
+cardinals by some embedding. -/
+def WellOrderingRel : α → α → Prop :=
+ embeddingToCardinal ⁻¹'o (· < ·)
+
+instance WellOrderingRel.isWellOrder : IsWellOrder α WellOrderingRel :=
+ (RelEmbedding.preimage _ _).isWellOrder
+
+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
+
/-- The range of an indexed cardinal function, whose outputs live in a higher universe than the
inputs, is always bounded above. -/
theorem bddAbove_range {ι : Type u} (f : ι → Cardinal.{max u v}) : BddAbove (Set.range f) :=
@@ -811,18 +991,21 @@ theorem bddAbove_range {ι : Type u} (f : ι → Cardinal.{max u v}) : BddAbove
rintro a ⟨i, rfl⟩
exact le_sum f i⟩
-instance (a : Cardinal.{u}) : Small.{u} (Set.Iic a) := by
+instance small_Iic (a : Cardinal.{u}) : Small.{u} (Iic a) := by
rw [← mk_out a]
apply @small_of_surjective (Set a.out) (Iic #a.out) _ fun x => ⟨#x, mk_set_le x⟩
rintro ⟨x, hx⟩
simpa using le_mk_iff_exists_set.1 hx
-instance (a : Cardinal.{u}) : Small.{u} (Set.Iio a) :=
- small_subset Iio_subset_Iic_self
+instance small_Iio (a : Cardinal.{u}) : Small.{u} (Iio a) := small_subset Iio_subset_Iic_self
+instance small_Icc (a b : Cardinal.{u}) : Small.{u} (Icc a b) := small_subset Icc_subset_Iic_self
+instance small_Ico (a b : Cardinal.{u}) : Small.{u} (Ico a b) := small_subset Ico_subset_Iio_self
+instance small_Ioc (a b : Cardinal.{u}) : Small.{u} (Ioc a b) := small_subset Ioc_subset_Iic_self
+instance small_Ioo (a b : Cardinal.{u}) : Small.{u} (Ioo a b) := small_subset Ioo_subset_Iio_self
/-- 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]
@@ -846,8 +1029,7 @@ theorem bddAbove_range_comp {ι : Type u} {f : ι → Cardinal.{v}} (hf : BddAbo
rw [range_comp]
exact bddAbove_image g hf
-theorem iSup_le_sum {ι} (f : ι → Cardinal) : iSup f ≤ sum f :=
- ciSup_le' <| le_sum _
+/-! ### Bounds on suprema -/
theorem sum_le_iSup_lift {ι : Type u}
(f : ι → Cardinal.{max u v}) : sum f ≤ Cardinal.lift #ι * iSup f := by
@@ -858,20 +1040,58 @@ theorem sum_le_iSup {ι : Type u} (f : ι → Cardinal.{u}) : sum f ≤ #ι * iS
rw [← lift_id #ι]
exact sum_le_iSup_lift f
-theorem sum_nat_eq_add_sum_succ (f : ℕ → Cardinal.{u}) :
- Cardinal.sum f = f 0 + Cardinal.sum fun i => f (i + 1) := by
- refine (Equiv.sigmaNatSucc fun i => Quotient.out (f i)).cardinal_eq.trans ?_
- simp only [mk_sum, mk_out, lift_id, mk_sigma]
+/-- The lift of a supremum is the supremum of the lifts. -/
+theorem lift_sSup {s : Set Cardinal} (hs : BddAbove s) :
+ lift.{u} (sSup s) = sSup (lift.{u} '' s) := by
+ 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.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)
+ · rintro i ⟨j, hj, rfl⟩
+ exact lift_le.2 (le_csSup hs hj)
--- Porting note: LFS is not in normal form.
--- @[simp]
-/-- A variant of `ciSup_of_empty` but with `0` on the RHS for convenience -/
-protected theorem iSup_of_empty {ι} (f : ι → Cardinal) [IsEmpty ι] : iSup f = 0 :=
- ciSup_of_empty f
+/-- The lift of a supremum is the supremum of the lifts. -/
+theorem lift_iSup {ι : Type v} {f : ι → Cardinal.{w}} (hf : BddAbove (range f)) :
+ lift.{u} (iSup f) = ⨆ i, lift.{u} (f i) := by
+ rw [iSup, iSup, lift_sSup hf, ← range_comp]
+ simp [Function.comp_def]
+
+/-- To prove that the lift of a supremum is bounded by some cardinal `t`,
+it suffices to show that the lift of each cardinal is bounded by `t`. -/
+theorem lift_iSup_le {ι : Type v} {f : ι → Cardinal.{w}} {t : Cardinal} (hf : BddAbove (range f))
+ (w : ∀ i, lift.{u} (f i) ≤ t) : lift.{u} (iSup f) ≤ t := by
+ rw [lift_iSup hf]
+ exact ciSup_le' w
+
+@[simp]
+theorem lift_iSup_le_iff {ι : Type v} {f : ι → Cardinal.{w}} (hf : BddAbove (range f))
+ {t : Cardinal} : lift.{u} (iSup f) ≤ t ↔ ∀ i, lift.{u} (f i) ≤ t := by
+ rw [lift_iSup hf]
+ exact ciSup_le_iff' (bddAbove_range_comp.{_,_,u} hf _)
+
+/-- To prove an inequality between the lifts to a common universe of two different supremums,
+it suffices to show that the lift of each cardinal from the smaller supremum
+if bounded by the lift of some cardinal from the larger supremum.
+-/
+theorem lift_iSup_le_lift_iSup {ι : Type v} {ι' : Type v'} {f : ι → Cardinal.{w}}
+ {f' : ι' → Cardinal.{w'}} (hf : BddAbove (range f)) (hf' : BddAbove (range f')) {g : ι → ι'}
+ (h : ∀ i, lift.{w'} (f i) ≤ lift.{w} (f' (g i))) : lift.{w'} (iSup f) ≤ lift.{w} (iSup f') := by
+ rw [lift_iSup hf, lift_iSup hf']
+ exact ciSup_mono' (bddAbove_range_comp.{_,_,w} hf' _) fun i => ⟨_, h i⟩
+
+/-- A variant of `lift_iSup_le_lift_iSup` with universes specialized via `w = v` and `w' = v'`.
+This is sometimes necessary to avoid universe unification issues. -/
+theorem lift_iSup_le_lift_iSup' {ι : Type v} {ι' : Type v'} {f : ι → Cardinal.{v}}
+ {f' : ι' → Cardinal.{v'}} (hf : BddAbove (range f)) (hf' : BddAbove (range f')) (g : ι → ι')
+ (h : ∀ i, lift.{v'} (f i) ≤ lift.{v} (f' (g i))) : lift.{v'} (iSup f) ≤ lift.{v} (iSup f') :=
+ lift_iSup_le_lift_iSup hf hf' h
lemma exists_eq_of_iSup_eq_of_not_isSuccPrelimit
{ι : Type u} (f : ι → Cardinal.{v}) (ω : Cardinal.{v})
- (hω : ¬ Order.IsSuccPrelimit ω)
+ (hω : ¬ IsSuccPrelimit ω)
(h : ⨆ i : ι, f i = ω) : ∃ i, f i = ω := by
subst h
refine (isLUB_csSup' ?_).exists_of_not_isSuccPrelimit hω
@@ -879,9 +1099,19 @@ lemma exists_eq_of_iSup_eq_of_not_isSuccPrelimit
rw [iSup, csSup_of_not_bddAbove hf, csSup_empty]
exact isSuccPrelimit_bot
-@[deprecated exists_eq_of_iSup_eq_of_not_isSuccPrelimit (since := "2024-09-05")]
-alias exists_eq_of_iSup_eq_of_not_isSuccLimit := exists_eq_of_iSup_eq_of_not_isSuccPrelimit
+lemma exists_eq_of_iSup_eq_of_not_isSuccLimit
+ {ι : Type u} [hι : Nonempty ι] (f : ι → Cardinal.{v}) (hf : BddAbove (range f))
+ {c : Cardinal.{v}} (hc : ¬ IsSuccLimit c)
+ (h : ⨆ i, f i = c) : ∃ i, f i = c := by
+ rw [Cardinal.isSuccLimit_iff] at hc
+ refine (not_and_or.mp hc).elim (fun e ↦ ⟨hι.some, ?_⟩)
+ (Cardinal.exists_eq_of_iSup_eq_of_not_isSuccPrelimit.{u, v} f c · h)
+ cases not_not.mp e
+ rw [← le_zero_iff] at h ⊢
+ exact (le_ciSup hf _).trans h
+set_option linter.deprecated false in
+@[deprecated exists_eq_of_iSup_eq_of_not_isSuccLimit (since := "2024-09-17")]
lemma exists_eq_of_iSup_eq_of_not_isLimit
{ι : Type u} [hι : Nonempty ι] (f : ι → Cardinal.{v}) (hf : BddAbove (range f))
(ω : Cardinal.{v}) (hω : ¬ ω.IsLimit)
@@ -892,31 +1122,45 @@ lemma exists_eq_of_iSup_eq_of_not_isLimit
rw [← le_zero_iff] at h ⊢
exact (le_ciSup hf _).trans h
--- Porting note: simpNF is not happy with universe levels.
-@[simp, nolint simpNF]
-theorem lift_mk_shrink (α : Type u) [Small.{v} α] :
- Cardinal.lift.{max u w} #(Shrink.{v} α) = Cardinal.lift.{max v w} #α :=
- lift_mk_eq.2 ⟨(equivShrink α).symm⟩
-
-@[simp]
-theorem lift_mk_shrink' (α : Type u) [Small.{v} α] :
- Cardinal.lift.{u} #(Shrink.{v} α) = Cardinal.lift.{v} #α :=
- lift_mk_shrink.{u, v, 0} α
-
-@[simp]
-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]
+/-! ### Indexed cardinal `prod` -/
/-- The indexed product of cardinals is the cardinality of the Pi type
(dependent product). -/
def prod {ι : Type u} (f : ι → Cardinal) : Cardinal :=
- #(∀ i, (f i).out)
+ #(Π i, (f i).out)
@[simp]
-theorem mk_pi {ι : Type u} (α : ι → Type v) : #(∀ i, α i) = prod fun i => #(α i) :=
+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} #ι :=
@@ -937,6 +1181,17 @@ theorem prod_eq_zero {ι} (f : ι → Cardinal.{u}) : prod f = 0 ↔ ∃ i, f i
theorem prod_ne_zero {ι} (f : ι → Cardinal) : prod f ≠ 0 ↔ ∀ i, f i ≠ 0 := by simp [prod_eq_zero]
+theorem power_sum {ι} (a : Cardinal) (f : ι → Cardinal) :
+ a ^ sum f = prod fun i ↦ a ^ f i := by
+ induction a using Cardinal.inductionOn with | _ α =>
+ induction f using induction_on_pi with | _ f =>
+ simp_rw [prod, sum, power_def]
+ apply mk_congr
+ refine (Equiv.piCurry fun _ _ => α).trans ?_
+ refine Equiv.piCongrRight fun b => ?_
+ refine (Equiv.arrowCongr outMkEquiv (Equiv.refl α)).trans ?_
+ exact outMkEquiv.symm
+
@[simp]
theorem lift_prod {ι : Type u} (c : ι → Cardinal.{v}) :
lift.{w} (prod c) = prod fun i => lift.{w} (c i) := by
@@ -959,115 +1214,26 @@ theorem prod_eq_of_fintype {α : Type u} [h : Fintype α] (f : α → Cardinal.{
Cardinal.prod, lift_prod, Fintype.prod_option, lift_mul, ← h fun a => f (some a)]
simp only [lift_id]
-@[simp]
-theorem lift_sInf (s : Set Cardinal) : lift.{u, v} (sInf s) = sInf (lift.{u, v} '' s) := by
- rcases eq_empty_or_nonempty s with (rfl | hs)
- · simp
- · exact lift_monotone.map_csInf hs
-
-@[simp]
-theorem lift_iInf {ι} (f : ι → Cardinal) : lift.{u, v} (iInf f) = ⨅ i, lift.{u, v} (f i) := by
- unfold iInf
- convert lift_sInf (range f)
- simp_rw [← comp_apply (f := lift), range_comp]
-
-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⟩⟩⟩
-
-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⟩
-
-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⟩
-
-@[simp]
-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⟩
- 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)
-
--- Porting note: simpNF is not happy with universe levels.
-@[simp, nolint simpNF]
-theorem lift_umax_eq {a : Cardinal.{u}} {b : Cardinal.{v}} :
- lift.{max v w} a = lift.{max u w} b ↔ lift.{v} a = lift.{u} b := by
- rw [← lift_lift.{v, w, u}, ← lift_lift.{u, w, v}, lift_inj]
-
-@[simp]
-theorem lift_min {a b : Cardinal} : lift.{u, v} (min a b) = min (lift.{u, v} a) (lift.{u, v} b) :=
- lift_monotone.map_min
-
-@[simp]
-theorem lift_max {a b : Cardinal} : lift.{u, v} (max a b) = max (lift.{u, v} a) (lift.{u, v} b) :=
- lift_monotone.map_max
-
-/-- The lift of a supremum is the supremum of the lifts. -/
-theorem lift_sSup {s : Set Cardinal} (hs : BddAbove s) :
- lift.{u} (sSup s) = sSup (lift.{u} '' s) := by
- 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
- 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)
- · rintro i ⟨j, hj, rfl⟩
- exact lift_le.2 (le_csSup hs hj)
-
-/-- The lift of a supremum is the supremum of the lifts. -/
-theorem lift_iSup {ι : Type v} {f : ι → Cardinal.{w}} (hf : BddAbove (range f)) :
- lift.{u} (iSup f) = ⨆ i, lift.{u} (f i) := by
- rw [iSup, iSup, lift_sSup hf, ← range_comp]
- simp [Function.comp_def]
-
-/-- To prove that the lift of a supremum is bounded by some cardinal `t`,
-it suffices to show that the lift of each cardinal is bounded by `t`. -/
-theorem lift_iSup_le {ι : Type v} {f : ι → Cardinal.{w}} {t : Cardinal} (hf : BddAbove (range f))
- (w : ∀ i, lift.{u} (f i) ≤ t) : lift.{u} (iSup f) ≤ t := by
- rw [lift_iSup hf]
- exact ciSup_le' w
-
-@[simp]
-theorem lift_iSup_le_iff {ι : Type v} {f : ι → Cardinal.{w}} (hf : BddAbove (range f))
- {t : Cardinal} : lift.{u} (iSup f) ≤ t ↔ ∀ i, lift.{u} (f i) ≤ t := by
- rw [lift_iSup hf]
- exact ciSup_le_iff' (bddAbove_range_comp.{_,_,u} hf _)
-
-universe v' w'
-
-/-- To prove an inequality between the lifts to a common universe of two different supremums,
-it suffices to show that the lift of each cardinal from the smaller supremum
-if bounded by the lift of some cardinal from the larger supremum.
--/
-theorem lift_iSup_le_lift_iSup {ι : Type v} {ι' : Type v'} {f : ι → Cardinal.{w}}
- {f' : ι' → Cardinal.{w'}} (hf : BddAbove (range f)) (hf' : BddAbove (range f')) {g : ι → ι'}
- (h : ∀ i, lift.{w'} (f i) ≤ lift.{w} (f' (g i))) : lift.{w'} (iSup f) ≤ lift.{w} (iSup f') := by
- rw [lift_iSup hf, lift_iSup hf']
- exact ciSup_mono' (bddAbove_range_comp.{_,_,w} hf' _) fun i => ⟨_, h i⟩
+/-- **König's theorem** -/
+theorem sum_lt_prod {ι} (f g : ι → Cardinal) (H : ∀ i, f i < g i) : sum f < prod g :=
+ lt_of_not_ge fun ⟨F⟩ => by
+ have : Inhabited (∀ i : ι, (g i).out) := by
+ refine ⟨fun i => Classical.choice <| mk_ne_zero_iff.1 ?_⟩
+ rw [mk_out]
+ exact (H i).ne_bot
+ let G := invFun F
+ have sG : Surjective G := invFun_surjective F.2
+ choose C hc using
+ show ∀ i, ∃ b, ∀ a, G ⟨i, a⟩ i ≠ b by
+ intro i
+ simp only [not_exists.symm, not_forall.symm]
+ refine fun h => (H i).not_le ?_
+ rw [← mk_out (f i), ← mk_out (g i)]
+ exact ⟨Embedding.ofSurjective _ h⟩
+ let ⟨⟨i, a⟩, h⟩ := sG C
+ exact hc i a (congr_fun h _)
-/-- A variant of `lift_iSup_le_lift_iSup` with universes specialized via `w = v` and `w' = v'`.
-This is sometimes necessary to avoid universe unification issues. -/
-theorem lift_iSup_le_lift_iSup' {ι : Type v} {ι' : Type v'} {f : ι → Cardinal.{v}}
- {f' : ι' → Cardinal.{v'}} (hf : BddAbove (range f)) (hf' : BddAbove (range f')) (g : ι → ι')
- (h : ∀ i, lift.{v'} (f i) ≤ lift.{v} (f' (g i))) : lift.{v'} (iSup f) ≤ lift.{v} (iSup f') :=
- lift_iSup_le_lift_iSup hf hf' h
+/-! ### The first infinite cardinal `aleph0` -/
/-- `ℵ₀` is the smallest infinite cardinal. -/
def aleph0 : Cardinal.{u} :=
@@ -1091,25 +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 `ℕ` -/
-section castFromN
--- porting note (#10618): simp can prove this
--- @[simp]
theorem mk_fin (n : ℕ) : #(Fin n) = n := by simp
@[simp]
@@ -1222,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]
@@ -1273,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 α
@@ -1301,6 +1466,8 @@ theorem one_le_iff_ne_zero {c : Cardinal} : 1 ≤ c ↔ c ≠ 0 := by
theorem lt_one_iff_zero {c : Cardinal} : c < 1 ↔ c = 0 := by
simpa using lt_succ_bot_iff (a := c)
+/-! ### Properties about `aleph0` -/
+
theorem nat_lt_aleph0 (n : ℕ) : (n : Cardinal.{u}) < ℵ₀ :=
succ_le_iff.1
(by
@@ -1310,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
@@ -1340,24 +1508,46 @@ theorem isSuccPrelimit_aleph0 : IsSuccPrelimit ℵ₀ :=
rw [← nat_succ]
apply nat_lt_aleph0
-@[deprecated isSuccPrelimit_aleph0 (since := "2024-09-05")]
-alias isSuccLimit_aleph0 := isSuccPrelimit_aleph0
+theorem isSuccLimit_aleph0 : IsSuccLimit ℵ₀ := by
+ rw [Cardinal.isSuccLimit_iff]
+ exact ⟨aleph0_ne_zero, isSuccPrelimit_aleph0⟩
+
+lemma not_isSuccLimit_natCast : (n : ℕ) → ¬ IsSuccLimit (n : Cardinal.{u})
+ | 0, e => e.1 isMin_bot
+ | Nat.succ n, e => Order.not_isSuccPrelimit_succ _ (nat_succ n ▸ e.2)
+
+theorem not_isSuccLimit_of_lt_aleph0 {c : Cardinal} (h : c < ℵ₀) : ¬ IsSuccLimit c := by
+ obtain ⟨n, rfl⟩ := lt_aleph0.1 h
+ exact not_isSuccLimit_natCast n
+
+theorem aleph0_le_of_isSuccLimit {c : Cardinal} (h : IsSuccLimit c) : ℵ₀ ≤ c := by
+ contrapose! h
+ exact not_isSuccLimit_of_lt_aleph0 h
+section deprecated
+
+set_option linter.deprecated false
+
+@[deprecated isSuccLimit_aleph0 (since := "2024-09-17")]
theorem isLimit_aleph0 : IsLimit ℵ₀ :=
⟨aleph0_ne_zero, isSuccPrelimit_aleph0⟩
+@[deprecated not_isSuccLimit_natCast (since := "2024-09-17")]
lemma not_isLimit_natCast : (n : ℕ) → ¬ IsLimit (n : Cardinal.{u})
| 0, e => e.1 rfl
| Nat.succ n, e => Order.not_isSuccPrelimit_succ _ (nat_succ n ▸ e.2)
+@[deprecated aleph0_le_of_isSuccLimit (since := "2024-09-17")]
theorem IsLimit.aleph0_le {c : Cardinal} (h : IsLimit c) : ℵ₀ ≤ c := by
by_contra! h'
rcases lt_aleph0.1 h' with ⟨n, rfl⟩
exact not_isLimit_natCast n h
+end deprecated
+
lemma exists_eq_natCast_of_iSup_eq {ι : Type u} [Nonempty ι] (f : ι → Cardinal.{v})
(hf : BddAbove (range f)) (n : ℕ) (h : ⨆ i, f i = n) : ∃ i, f i = n :=
- exists_eq_of_iSup_eq_of_not_isLimit.{u, v} f hf _ (not_isLimit_natCast n) h
+ exists_eq_of_iSup_eq_of_not_isSuccLimit.{u, v} f hf (not_isSuccLimit_natCast n) h
@[simp]
theorem range_natCast : range ((↑) : ℕ → Cardinal) = Iio ℵ₀ :=
@@ -1375,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
@@ -1393,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
@@ -1425,7 +1611,7 @@ theorem nsmul_lt_aleph0_iff {n : ℕ} {a : Cardinal} : n • a < ℵ₀ ↔ n =
cases n with
| zero => simpa using nat_lt_aleph0 0
| succ n =>
- simp only [Nat.succ_ne_zero, false_or_iff]
+ simp only [Nat.succ_ne_zero, false_or]
induction' n with n ih
· simp
rw [succ_nsmul, add_lt_aleph0_iff, ih, and_self_iff]
@@ -1470,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
@@ -1497,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 ⟨‹_›⟩
@@ -1517,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]
@@ -1564,62 +1748,33 @@ theorem mk_int : #ℤ = ℵ₀ :=
theorem mk_pNat : #ℕ+ = ℵ₀ :=
mk_denumerable ℕ+
-end castFromN
+/-! ### Cardinalities of basic sets and types -/
-variable {c : Cardinal}
-
-/-- **König's theorem** -/
-theorem sum_lt_prod {ι} (f g : ι → Cardinal) (H : ∀ i, f i < g i) : sum f < prod g :=
- lt_of_not_ge fun ⟨F⟩ => by
- have : Inhabited (∀ i : ι, (g i).out) := by
- refine ⟨fun i => Classical.choice <| mk_ne_zero_iff.1 ?_⟩
- rw [mk_out]
- exact (H i).ne_bot
- let G := invFun F
- have sG : Surjective G := invFun_surjective F.2
- choose C hc using
- show ∀ i, ∃ b, ∀ a, G ⟨i, a⟩ i ≠ b by
- intro i
- simp only [not_exists.symm, not_forall.symm]
- refine fun h => (H i).not_le ?_
- rw [← mk_out (f i), ← mk_out (g i)]
- exact ⟨Embedding.ofSurjective _ h⟩
- let ⟨⟨i, a⟩, h⟩ := sG C
- exact hc i a (congr_fun h _)
-
-/-! Cardinalities of sets: cardinality of empty, finite sets, unions, subsets etc. -/
-section sets
-
--- 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 _
@@ -1642,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 _
@@ -1659,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⟩
@@ -1793,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
@@ -1928,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
@@ -1936,9 +2097,7 @@ theorem three_le {α : Type*} (h : 3 ≤ #α) (x : α) (y : α) : ∃ z : α, z
have := exists_not_mem_of_length_lt [x, y] this
simpa [not_or] using this
-end sets
-
-section powerlt
+/-! ### `powerlt` operation -/
/-- The function `a ^< b`, defined as the supremum of `a ^ c` for `c < b`. -/
def powerlt (a b : Cardinal.{u}) : Cardinal.{u} :=
@@ -1983,7 +2142,6 @@ theorem powerlt_zero {a : Cardinal} : a ^< 0 = 0 := by
convert Cardinal.iSup_of_empty _
exact Subtype.isEmpty_of_false fun x => mem_Iio.not.mpr (Cardinal.zero_le x).not_lt
-end powerlt
end Cardinal
-- namespace Tactic
@@ -2006,4 +2164,4 @@ end Cardinal
-- end Tactic
-set_option linter.style.longFile 2100
+set_option linter.style.longFile 2200
diff --git a/Mathlib/SetTheory/Cardinal/Cofinality.lean b/Mathlib/SetTheory/Cardinal/Cofinality.lean
index d846f86c10426..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⟩)
@@ -303,30 +291,59 @@ theorem lsub_lt_ord {ι} {f : ι → Ordinal} {c : Ordinal} (hι : #ι < c.cof)
(∀ i, f i < c) → lsub.{u, u} f < c :=
lsub_lt_ord_lift (by rwa [(#ι).lift_id])
+set_option linter.deprecated false in
+theorem cof_iSup_le_lift {ι} {f : ι → Ordinal} (H : ∀ i, f i < iSup f) :
+ cof (iSup f) ≤ Cardinal.lift.{v, u} #ι := by
+ rw [← Ordinal.sup] at *
+ rw [← sup_eq_lsub_iff_lt_sup.{u, v}] at H
+ rw [H]
+ exact cof_lsub_le_lift f
+
+set_option linter.deprecated false in
+@[deprecated cof_iSup_le_lift (since := "2024-08-27")]
theorem cof_sup_le_lift {ι} {f : ι → Ordinal} (H : ∀ i, f i < sup.{u, v} f) :
cof (sup.{u, v} f) ≤ Cardinal.lift.{v, u} #ι := by
rw [← sup_eq_lsub_iff_lt_sup.{u, v}] at H
rw [H]
exact cof_lsub_le_lift f
+theorem cof_iSup_le {ι} {f : ι → Ordinal} (H : ∀ i, f i < iSup f) :
+ cof (iSup f) ≤ #ι := by
+ rw [← (#ι).lift_id]
+ exact cof_iSup_le_lift H
+
+set_option linter.deprecated false in
+@[deprecated cof_iSup_le (since := "2024-08-27")]
theorem cof_sup_le {ι} {f : ι → Ordinal} (H : ∀ i, f i < sup.{u, u} f) :
cof (sup.{u, u} f) ≤ #ι := by
rw [← (#ι).lift_id]
exact cof_sup_le_lift H
+theorem iSup_lt_ord_lift {ι} {f : ι → Ordinal} {c : Ordinal} (hι : Cardinal.lift.{v, u} #ι < c.cof)
+ (hf : ∀ i, f i < c) : iSup f < c :=
+ (sup_le_lsub.{u, v} f).trans_lt (lsub_lt_ord_lift hι hf)
+
+set_option linter.deprecated false in
+@[deprecated iSup_lt_ord_lift (since := "2024-08-27")]
theorem sup_lt_ord_lift {ι} {f : ι → Ordinal} {c : Ordinal} (hι : Cardinal.lift.{v, u} #ι < c.cof)
(hf : ∀ i, f i < c) : sup.{u, v} f < c :=
- (sup_le_lsub.{u, v} f).trans_lt (lsub_lt_ord_lift hι hf)
+ iSup_lt_ord_lift hι hf
+
+theorem iSup_lt_ord {ι} {f : ι → Ordinal} {c : Ordinal} (hι : #ι < c.cof) :
+ (∀ i, f i < c) → iSup f < c :=
+ iSup_lt_ord_lift (by rwa [(#ι).lift_id])
+set_option linter.deprecated false in
+@[deprecated iSup_lt_ord (since := "2024-08-27")]
theorem sup_lt_ord {ι} {f : ι → Ordinal} {c : Ordinal} (hι : #ι < c.cof) :
(∀ i, f i < c) → sup.{u, u} f < c :=
sup_lt_ord_lift (by rwa [(#ι).lift_id])
theorem iSup_lt_lift {ι} {f : ι → Cardinal} {c : Cardinal}
(hι : Cardinal.lift.{v, u} #ι < c.ord.cof)
- (hf : ∀ i, f i < c) : iSup.{max u v + 1, u + 1} f < c := by
+ (hf : ∀ i, f i < c) : iSup f < c := by
rw [← ord_lt_ord, iSup_ord (Cardinal.bddAbove_range.{u, v} _)]
- refine sup_lt_ord_lift hι fun i => ?_
+ refine iSup_lt_ord_lift hι fun i => ?_
rw [ord_lt_ord]
apply hf
@@ -337,7 +354,7 @@ theorem iSup_lt {ι} {f : ι → Cardinal} {c : Cardinal} (hι : #ι < c.ord.cof
theorem nfpFamily_lt_ord_lift {ι} {f : ι → Ordinal → Ordinal} {c} (hc : ℵ₀ < cof c)
(hc' : Cardinal.lift.{v, u} #ι < cof c) (hf : ∀ (i), ∀ b < c, f i b < c) {a} (ha : a < c) :
nfpFamily.{u, v} f a < c := by
- refine sup_lt_ord_lift ((Cardinal.lift_le.2 (mk_list_le_max ι)).trans_lt ?_) fun l => ?_
+ refine iSup_lt_ord_lift ((Cardinal.lift_le.2 (mk_list_le_max ι)).trans_lt ?_) fun l => ?_
· rw [lift_max]
apply max_lt _ hc'
rwa [Cardinal.lift_aleph0]
@@ -352,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} :
@@ -427,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]⟩
@@ -512,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⟩
@@ -623,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)
@@ -643,19 +660,27 @@ 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_omega : cof ω = ℵ₀ :=
- (aleph0_le_cof.2 omega_isLimit).antisymm' <| by
- rw [← card_omega]
+theorem cof_omega0 : cof ω = ℵ₀ :=
+ (aleph0_le_cof.2 isLimit_omega0).antisymm' <| by
+ rw [← card_omega0]
apply cof_le_card
+@[deprecated (since := "2024-09-30")]
+alias cof_omega := cof_omega0
+
theorem cof_eq' (r : α → α → Prop) [IsWellOrder α r] (h : IsLimit (type r)) :
∃ S : Set α, (∀ a, ∃ b ∈ S, r a b) ∧ #S = cof (type r) :=
let ⟨S, H, e⟩ := cof_eq r
@@ -680,16 +705,16 @@ 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
let g a := (f a).1
- let o := succ (sup.{u, u} g)
+ let o := succ (iSup g)
rcases H o with ⟨b, h, l⟩
refine l (lt_succ_iff.2 ?_)
rw [← show g (f.symm ⟨b, h⟩) = b by simp [g]]
- apply le_sup)
+ apply Ordinal.le_iSup)
/-! ### Infinite pigeonhole principle -/
@@ -777,16 +802,23 @@ theorem isStrongLimit_aleph0 : IsStrongLimit ℵ₀ :=
rcases lt_aleph0.1 hx with ⟨n, rfl⟩
exact mod_cast nat_lt_aleph0 (2 ^ n)⟩
+protected theorem IsStrongLimit.isSuccLimit {c} (H : IsStrongLimit c) : IsSuccLimit c := by
+ rw [Cardinal.isSuccLimit_iff]
+ exact ⟨H.ne_zero, isSuccPrelimit_of_succ_lt fun x h =>
+ (succ_le_of_lt <| cantor x).trans_lt (H.two_power_lt h)⟩
+
protected theorem IsStrongLimit.isSuccPrelimit {c} (H : IsStrongLimit c) : IsSuccPrelimit c :=
- isSuccPrelimit_of_succ_lt fun x h => (succ_le_of_lt <| cantor x).trans_lt (H.two_power_lt h)
+ H.isSuccLimit.isSuccPrelimit
-@[deprecated IsStrongLimit.isSuccPrelimit (since := "2024-09-05")]
-alias IsStrongLimit.isSuccLimit := IsStrongLimit.isSuccPrelimit
+theorem IsStrongLimit.aleph0_le {c} (H : IsStrongLimit c) : ℵ₀ ≤ c :=
+ aleph0_le_of_isSuccLimit H.isSuccLimit
+set_option linter.deprecated false in
+@[deprecated IsStrongLimit.isSuccLimit (since := "2024-09-17")]
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
@@ -807,7 +839,7 @@ theorem mk_bounded_subset {α : Type*} (h : ∀ x < #α, (2^x) < #α) {r : α
rintro ⟨s, hs⟩
exact (not_unbounded_iff s).2 hs (unbounded_of_isEmpty s)
have h' : IsStrongLimit #α := ⟨ha, h⟩
- have ha := h'.isLimit.aleph0_le
+ have ha := h'.aleph0_le
apply le_antisymm
· have : { s : Set α | Bounded r s } = ⋃ i, 𝒫{ j | r j i } := setOf_exists _
rw [← coe_setOf, this]
@@ -823,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
@@ -842,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'.isLimit.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
@@ -876,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]
@@ -893,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)
@@ -955,13 +994,25 @@ theorem lsub_lt_ord_of_isRegular {ι} {f : ι → Ordinal} {c} (hc : IsRegular c
(∀ i, f i < c.ord) → Ordinal.lsub f < c.ord :=
lsub_lt_ord (by rwa [hc.cof_eq])
+theorem iSup_lt_ord_lift_of_isRegular {ι} {f : ι → Ordinal} {c} (hc : IsRegular c)
+ (hι : Cardinal.lift.{v, u} #ι < c) : (∀ i, f i < c.ord) → iSup f < c.ord :=
+ iSup_lt_ord_lift (by rwa [hc.cof_eq])
+
+set_option linter.deprecated false in
+@[deprecated iSup_lt_ord_lift_of_isRegular (since := "2024-08-27")]
theorem sup_lt_ord_lift_of_isRegular {ι} {f : ι → Ordinal} {c} (hc : IsRegular c)
(hι : Cardinal.lift.{v, u} #ι < c) : (∀ i, f i < c.ord) → Ordinal.sup.{u, v} f < c.ord :=
- sup_lt_ord_lift (by rwa [hc.cof_eq])
+ iSup_lt_ord_lift_of_isRegular hc hι
+
+theorem iSup_lt_ord_of_isRegular {ι} {f : ι → Ordinal} {c} (hc : IsRegular c) (hι : #ι < c) :
+ (∀ i, f i < c.ord) → iSup f < c.ord :=
+ iSup_lt_ord (by rwa [hc.cof_eq])
+set_option linter.deprecated false in
+@[deprecated iSup_lt_ord_of_isRegular (since := "2024-08-27")]
theorem sup_lt_ord_of_isRegular {ι} {f : ι → Ordinal} {c} (hc : IsRegular c) (hι : #ι < c) :
(∀ i, f i < c.ord) → Ordinal.sup f < c.ord :=
- sup_lt_ord (by rwa [hc.cof_eq])
+ iSup_lt_ord_of_isRegular hc hι
theorem blsub_lt_ord_lift_of_isRegular {o : Ordinal} {f : ∀ a < o, Ordinal} {c} (hc : IsRegular c)
(ho : Cardinal.lift.{v, u} o.card < c) :
@@ -1040,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 ≠ ℵ₀)
@@ -1072,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]
@@ -1089,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} :
@@ -1117,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 ⊢
@@ -1148,9 +1199,11 @@ namespace Ordinal
open Cardinal
open scoped Ordinal
-lemma sup_sequence_lt_omega1 {α} [Countable α] (o : α → Ordinal) (ho : ∀ n, o n < ω₁) :
- sup o < ω₁ := by
- apply sup_lt_ord_lift _ ho
+-- TODO: generalize universes, and use ω₁.
+lemma iSup_sequence_lt_omega1 {α : Type u} [Countable α]
+ (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
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 658f7943b383d..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
/-!
@@ -134,7 +134,7 @@ theorem is_prime_iff {a : Cardinal} : Prime a ↔ ℵ₀ ≤ a ∨ ∃ p : ℕ,
theorem isPrimePow_iff {a : Cardinal} : IsPrimePow a ↔ ℵ₀ ≤ a ∨ ∃ n : ℕ, a = n ∧ IsPrimePow n := by
by_cases h : ℵ₀ ≤ a
· simp [h, (prime_of_aleph0_le h).isPrimePow]
- simp only [h, Nat.cast_inj, exists_eq_left', false_or_iff, isPrimePow_nat_iff]
+ simp only [h, Nat.cast_inj, exists_eq_left', false_or, isPrimePow_nat_iff]
lift a to ℕ using not_le.mp h
rw [isPrimePow_def]
refine
diff --git a/Mathlib/SetTheory/Cardinal/Finite.lean b/Mathlib/SetTheory/Cardinal/Finite.lean
index 16ceb279b9710..350d46ef5b8f2 100644
--- a/Mathlib/SetTheory/Cardinal/Finite.lean
+++ b/Mathlib/SetTheory/Cardinal/Finite.lean
@@ -98,7 +98,7 @@ protected theorem bijective_iff_injective_and_card [Finite β] (f : α → β) :
protected theorem bijective_iff_surjective_and_card [Finite α] (f : α → β) :
Bijective f ↔ Surjective f ∧ Nat.card α = Nat.card β := by
classical
- rw [and_comm, Bijective, and_congr_left_iff]
+ rw [_root_.and_comm, Bijective, and_congr_left_iff]
intro h
have := Fintype.ofFinite α
have := Fintype.ofSurjective f h
@@ -152,6 +152,14 @@ lemma card_preimage_of_injOn {f : α → β} {s : Set β} (hf : (f ⁻¹' s).Inj
lemma card_preimage_of_injective {f : α → β} {s : Set β} (hf : Injective f) (hsf : s ⊆ range f) :
Nat.card (f ⁻¹' s) = Nat.card s := card_preimage_of_injOn hf.injOn hsf
+@[simp] lemma card_univ : Nat.card (univ : Set α) = Nat.card α :=
+ card_congr (Equiv.Set.univ α)
+
+lemma card_range_of_injective {f : α → β} (hf : Injective f) :
+ Nat.card (range f) = Nat.card α := by
+ rw [← Nat.card_preimage_of_injective hf le_rfl]
+ simp
+
end Set
/-- If the cardinality is positive, that means it is a finite type, so there is
@@ -165,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 bdfb2d1ce7699..c7ac5c82b8191 100644
--- a/Mathlib/SetTheory/Game/Basic.lean
+++ b/Mathlib/SetTheory/Game/Basic.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2019 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Mario Carneiro, Isabel Longbottom, Scott Morrison, Apurva Nakade
+Authors: Reid Barton, Mario Carneiro, Isabel Longbottom, Kim Morrison, Apurva Nakade
-/
import Mathlib.Algebra.Order.Group.Defs
import Mathlib.Algebra.Ring.Int
@@ -78,8 +78,11 @@ instance instAddCommGroupWithOneGame : AddCommGroupWithOne Game where
instance : Inhabited Game :=
⟨0⟩
+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
@@ -90,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
@@ -161,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⟩
@@ -191,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}) :
@@ -225,10 +228,17 @@ namespace PGame
@[simp] theorem quot_add (a b : PGame) : ⟦a + b⟧ = (⟦a⟧ : Game) + ⟦b⟧ := rfl
@[simp] theorem quot_sub (a b : PGame) : ⟦a - b⟧ = (⟦a⟧ : Game) - ⟦b⟧ := rfl
+@[simp]
+theorem quot_natCast : ∀ n : ℕ, ⟦(n : PGame)⟧ = (n : Game)
+ | 0 => rfl
+ | n + 1 => by
+ rw [PGame.nat_succ, quot_add, Nat.cast_add, Nat.cast_one, quot_natCast]
+ rfl
+
theorem quot_eq_of_mk'_quot_eq {x y : PGame} (L : x.LeftMoves ≃ y.LeftMoves)
(R : x.RightMoves ≃ y.RightMoves) (hl : ∀ i, (⟦x.moveLeft i⟧ : Game) = ⟦y.moveLeft (L i)⟧)
(hr : ∀ j, (⟦x.moveRight j⟧ : Game) = ⟦y.moveRight (R j)⟧) : (⟦x⟧ : Game) = ⟦y⟧ :=
- game_eq (equiv_of_mk_equiv L R (fun _ => equiv_iff_game_eq.2 (hl _))
+ game_eq (.of_equiv L R (fun _ => equiv_iff_game_eq.2 (hl _))
(fun _ => equiv_iff_game_eq.2 (hr _)))
/-! Multiplicative operations can be defined at the level of pre-games,
@@ -237,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 => _
@@ -595,7 +605,7 @@ def mulOneRelabelling : ∀ x : PGame.{u}, x * 1 ≡r x
(try rintro (⟨i, ⟨⟩⟩ | ⟨i, ⟨⟩⟩)) <;>
{ dsimp
apply (Relabelling.subCongr (Relabelling.refl _) (mulZeroRelabelling _)).trans
- rw [sub_zero]
+ rw [sub_zero_eq_add_zero]
exact (addZeroRelabelling _).trans <|
(((mulOneRelabelling _).addCongr (mulZeroRelabelling _)).trans <| addZeroRelabelling _) }
diff --git a/Mathlib/SetTheory/Game/Birthday.lean b/Mathlib/SetTheory/Game/Birthday.lean
index 28f8edebd14c0..c211b6f8b75e4 100644
--- a/Mathlib/SetTheory/Game/Birthday.lean
+++ b/Mathlib/SetTheory/Game/Birthday.lean
@@ -3,27 +3,32 @@ 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.Algebra.Order.Group.OrderIso
import Mathlib.SetTheory.Game.Ordinal
import Mathlib.SetTheory.Ordinal.NaturalOps
/-!
# Birthdays of games
-The birthday of a game is an ordinal that represents at which "step" the game was constructed. We
-define it recursively as the least ordinal larger than the birthdays of its left and right games. We
-prove the basic properties about these.
+There are two related but distinct notions of a birthday within combinatorial game theory. One is
+the birthday of a pre-game, which represents the "step" at which it is constructed. We define it
+recursively as the least ordinal larger than the birthdays of its left and right options. On the
+other hand, the birthday of a game is the smallest birthday among all pre-games that quotient to it.
+
+The birthday of a pre-game can be understood as representing the depth of its game tree. On the
+other hand, the birthday of a game more closely matches Conway's original description. The lemma
+`SetTheory.Game.birthday_eq_pGameBirthday` links both definitions together.
# Main declarations
- `SetTheory.PGame.birthday`: The birthday of a pre-game.
+- `SetTheory.Game.birthday`: The birthday of a game.
# Todo
-- Define the birthdays of `SetTheory.Game`s and `Surreal`s.
-- Characterize the birthdays of basic arithmetical operations.
+- Characterize the birthdays of other basic arithmetical operations.
-/
-
universe u
open Ordinal
@@ -99,13 +104,13 @@ theorem birthday_one : birthday 1 = 1 := by rw [birthday_def]; simp
theorem birthday_star : birthday star = 1 := by rw [birthday_def]; simp
@[simp]
-theorem neg_birthday : ∀ x : PGame, (-x).birthday = x.birthday
+theorem birthday_neg : ∀ x : PGame, (-x).birthday = x.birthday
| ⟨xl, xr, xL, xR⟩ => by
rw [birthday_def, birthday_def, max_comm]
- congr <;> funext <;> apply neg_birthday
+ congr <;> funext <;> apply birthday_neg
@[simp]
-theorem toPGame_birthday (o : Ordinal) : o.toPGame.birthday = o := by
+theorem birthday_ordinalToPGame (o : Ordinal) : o.toPGame.birthday = o := by
induction' o using Ordinal.induction with o IH
rw [toPGame_def, PGame.birthday]
simp only [lsub_empty, max_zero_right]
@@ -121,19 +126,17 @@ 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 [neg_birthday, ← neg_le_iff] using le_birthday (-x)
+ simpa only [birthday_neg, ← neg_le_iff] using le_birthday (-x)
@[simp]
-theorem birthday_add : ∀ x y : PGame.{u}, (x + y).birthday = x.birthday ♯ y.birthday
+theorem birthday_add : ∀ x y : PGame, (x + y).birthday = x.birthday ♯ y.birthday
| ⟨xl, xr, xL, xR⟩, ⟨yl, yr, yL, yR⟩ => by
- rw [birthday_def, nadd_def]
- -- Porting note: `simp` doesn't apply
- erw [lsub_sum, lsub_sum]
- simp only [lsub_sum, mk_add_moveLeft_inl, moveLeft_mk, mk_add_moveLeft_inr,
- mk_add_moveRight_inl, moveRight_mk, mk_add_moveRight_inr]
+ rw [birthday_def, nadd_def, lsub_sum, lsub_sum]
+ simp only [mk_add_moveLeft_inl, mk_add_moveLeft_inr, mk_add_moveRight_inl, mk_add_moveRight_inr,
+ moveLeft_mk, moveRight_mk]
-- Porting note: Originally `simp only [birthday_add]`, but this causes an error in
-- `termination_by`. Use a workaround.
conv_lhs => left; left; right; intro a; rw [birthday_add (xL a) ⟨yl, yr, yL, yR⟩]
@@ -156,26 +159,117 @@ theorem birthday_add : ∀ x y : PGame.{u}, (x + y).birthday = x.birthday ♯ y.
· exact lt_max_of_lt_right ((nadd_le_nadd_left hj _).trans_lt (lt_lsub _ _))
termination_by a b => (a, b)
-theorem birthday_add_zero : (a + 0).birthday = a.birthday := by simp
-
-theorem birthday_zero_add : (0 + a).birthday = a.birthday := by simp
-
-theorem birthday_add_one : (a + 1).birthday = Order.succ a.birthday := by simp
-
-theorem birthday_one_add : (1 + a).birthday = Order.succ a.birthday := by simp
+@[simp]
+theorem birthday_sub (x y : PGame) : (x - y).birthday = x.birthday ♯ y.birthday := by
+ apply (birthday_add x _).trans
+ rw [birthday_neg]
@[simp]
theorem birthday_natCast : ∀ n : ℕ, birthday n = n
| 0 => birthday_zero
| n + 1 => by simp [birthday_natCast]
-@[deprecated (since := "2024-04-17")]
-alias birthday_nat_cast := birthday_natCast
+end PGame
-theorem birthday_add_nat (n : ℕ) : (a + n).birthday = a.birthday + n := by simp
+namespace Game
-theorem birthday_nat_add (n : ℕ) : (↑n + a).birthday = a.birthday + n := by simp
+/-- The birthday of a game is defined as the least birthday among all pre-games that define it. -/
+noncomputable def birthday (x : Game.{u}) : Ordinal.{u} :=
+ sInf (PGame.birthday '' (Quotient.mk' ⁻¹' {x}))
-end PGame
+theorem birthday_eq_pGameBirthday (x : Game) :
+ ∃ y : PGame.{u}, ⟦y⟧ = x ∧ y.birthday = birthday x := by
+ refine csInf_mem (Set.image_nonempty.2 ?_)
+ exact ⟨_, x.out_eq⟩
+
+theorem birthday_quot_le_pGameBirthday (x : PGame) : birthday ⟦x⟧ ≤ x.birthday :=
+ csInf_le' ⟨x, rfl, rfl⟩
+
+@[simp]
+theorem birthday_zero : birthday 0 = 0 := by
+ rw [← Ordinal.le_zero, ← PGame.birthday_zero]
+ exact birthday_quot_le_pGameBirthday _
+
+@[simp]
+theorem birthday_eq_zero {x : Game} : birthday x = 0 ↔ x = 0 := by
+ constructor
+ · intro h
+ let ⟨y, hy₁, hy₂⟩ := birthday_eq_pGameBirthday x
+ rw [← hy₁]
+ rw [h, PGame.birthday_eq_zero] at hy₂
+ exact PGame.game_eq (@PGame.Equiv.isEmpty _ hy₂.1 hy₂.2)
+ · rintro rfl
+ exact birthday_zero
+
+@[simp]
+theorem birthday_ordinalToGame (o : Ordinal) : birthday o.toGame = o := by
+ apply le_antisymm
+ · conv_rhs => rw [← PGame.birthday_ordinalToPGame o]
+ apply birthday_quot_le_pGameBirthday
+ · let ⟨x, hx₁, hx₂⟩ := birthday_eq_pGameBirthday o.toGame
+ rw [← hx₂, ← toPGame_le_iff]
+ rw [← PGame.equiv_iff_game_eq] at hx₁
+ exact hx₁.2.trans (PGame.le_birthday x)
+
+@[simp, norm_cast]
+theorem birthday_natCast (n : ℕ) : birthday n = n := by
+ rw [← toGame_natCast]
+ exact birthday_ordinalToGame _
+
+-- See note [no_index around OfNat.ofNat]
+@[simp]
+theorem birthday_ofNat (n : ℕ) [n.AtLeastTwo] :
+ birthday (no_index (OfNat.ofNat n)) = OfNat.ofNat n :=
+ birthday_natCast n
+
+@[simp]
+theorem birthday_one : birthday 1 = 1 := by
+ rw [← Nat.cast_one, birthday_natCast, Nat.cast_one]
+
+@[simp]
+theorem birthday_star : birthday ⟦PGame.star⟧ = 1 := by
+ apply le_antisymm
+ · rw [← PGame.birthday_star]
+ exact birthday_quot_le_pGameBirthday _
+ · rw [Ordinal.one_le_iff_ne_zero, ne_eq, birthday_eq_zero, Game.zero_def,
+ ← PGame.equiv_iff_game_eq]
+ exact PGame.star_fuzzy_zero.not_equiv
+
+private theorem birthday_neg' (x : Game) : (-x).birthday ≤ x.birthday := by
+ let ⟨y, hy₁, hy₂⟩ := birthday_eq_pGameBirthday x
+ rw [← hy₂, ← PGame.birthday_neg y]
+ conv_lhs => rw [← hy₁]
+ apply birthday_quot_le_pGameBirthday
+
+@[simp]
+theorem birthday_neg (x : Game) : (-x).birthday = x.birthday := by
+ apply le_antisymm (birthday_neg' x)
+ conv_lhs => rw [← neg_neg x]
+ exact birthday_neg' _
+
+theorem le_birthday (x : Game) : x ≤ x.birthday.toGame := by
+ let ⟨y, hy₁, hy₂⟩ := birthday_eq_pGameBirthday x
+ rw [← hy₁]
+ apply (y.le_birthday).trans
+ rw [toPGame_le_iff, hy₁, hy₂]
+
+theorem neg_birthday_le (x : Game) : -x.birthday.toGame ≤ x := by
+ rw [neg_le, ← birthday_neg]
+ exact le_birthday _
+
+theorem birthday_add_le (x y : Game) : (x + y).birthday ≤ x.birthday ♯ y.birthday := by
+ let ⟨a, ha₁, ha₂⟩ := birthday_eq_pGameBirthday x
+ let ⟨b, hb₁, hb₂⟩ := birthday_eq_pGameBirthday y
+ rw [← ha₂, ← hb₂, ← ha₁, ← hb₁, ← PGame.birthday_add]
+ exact birthday_quot_le_pGameBirthday _
+
+theorem birthday_sub_le (x y : Game) : (x - y).birthday ≤ x.birthday ♯ y.birthday := by
+ apply (birthday_add_le x _).trans_eq
+ rw [birthday_neg]
+
+/- The bound `(x * y).birthday ≤ x.birthday ⨳ y.birthday` is currently an open problem. See
+ https://mathoverflow.net/a/476829/147705. -/
+
+end Game
end SetTheory
diff --git a/Mathlib/SetTheory/Game/Domineering.lean b/Mathlib/SetTheory/Game/Domineering.lean
index e542ce9026c9b..e2301050c9961 100644
--- a/Mathlib/SetTheory/Game/Domineering.lean
+++ b/Mathlib/SetTheory/Game/Domineering.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.SetTheory.Game.State
diff --git a/Mathlib/SetTheory/Game/Nim.lean b/Mathlib/SetTheory/Game/Nim.lean
index 9253e4a97b9c6..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
@@ -206,61 +206,79 @@ theorem nim_add_fuzzy_zero_iff {o₁ o₂ : Ordinal} : nim o₁ + nim o₂ ‖ 0
theorem nim_equiv_iff_eq {o₁ o₂ : Ordinal} : (nim o₁ ≈ nim o₂) ↔ o₁ = o₂ := by
rw [Impartial.equiv_iff_add_equiv_zero, nim_add_equiv_zero_iff]
-/-- The Grundy value of an impartial game, the ordinal which corresponds to the game of nim that the
- game is equivalent to -/
-noncomputable def grundyValue : PGame.{u} → Ordinal.{u}
- | G => Ordinal.mex.{u, u} fun i => grundyValue (G.moveLeft i)
-termination_by G => G
+/-- 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.
+
+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
+
+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.{u, u} fun i => grundyValue (G.moveLeft i) := by rw [grundyValue]
-
-/-- The Sprague-Grundy theorem which states that every impartial game is equivalent to a game of
- nim, namely the game of nim corresponding to the games Grundy value -/
-theorem equiv_nim_grundyValue : ∀ (G : PGame.{u}) [G.Impartial], G ≈ nim (grundyValue G)
- | G => by
- rw [Impartial.equiv_iff_add_equiv_zero, ← Impartial.forall_leftMoves_fuzzy_iff_equiv_zero]
- intro i
- apply leftMoves_add_cases i
- · intro i₁
- rw [add_moveLeft_inl]
- apply
- (fuzzy_congr_left (add_congr_left (Equiv.symm (equiv_nim_grundyValue (G.moveLeft i₁))))).1
- rw [nim_add_fuzzy_zero_iff]
- intro heq
- rw [eq_comm, grundyValue_eq_mex_left G] at heq
- -- Porting note: added universe annotation, argument
- have h := Ordinal.ne_mex.{u, u} (fun i ↦ grundyValue (moveLeft G i))
- rw [heq] at h
- exact (h i₁).irrefl
- · intro i₂
- rw [add_moveLeft_inr, ← Impartial.exists_left_move_equiv_iff_fuzzy_zero]
- revert i₂
- rw [nim_def]
- intro i₂
- have h' :
- ∃ i : G.LeftMoves,
- grundyValue (G.moveLeft i) = Ordinal.typein (α := toType (grundyValue G)) (· < ·) i₂ := by
- revert i₂
- rw [grundyValue_eq_mex_left]
- intro i₂
- have hnotin : _ ∉ _ := fun hin => not_le_of_lt (Ordinal.typein_lt_self i₂) (csInf_le' hin)
- simpa using hnotin
- cases' h' with i hi
- use toLeftMovesAdd (Sum.inl i)
- rw [add_moveLeft_inl, moveLeft_mk]
- apply Equiv.trans (add_congr_left (equiv_nim_grundyValue (G.moveLeft i)))
- simpa only [hi] using Impartial.add_self (nim (grundyValue (G.moveLeft i)))
-termination_by G => G
-decreasing_by all_goals pgame_wf_tac
-
-theorem grundyValue_eq_iff_equiv_nim {G : PGame} [G.Impartial] {o : Ordinal} :
- grundyValue G = o ↔ (G ≈ nim o) :=
+ grundyValue G = Ordinal.mex fun i => grundyValue (G.moveLeft i) :=
+ grundyValue_eq_sInf_moveLeft G
+
+theorem grundyValue_ne_moveLeft {G : PGame} (i : G.LeftMoves) :
+ grundyValue (G.moveLeft i) ≠ grundyValue G := by
+ conv_rhs => rw [grundyValue_eq_sInf_moveLeft]
+ have := csInf_mem (nonempty_of_not_bddAbove <|
+ not_bddAbove_compl_of_small (Set.range fun i => grundyValue (G.moveLeft i)))
+ rw [Set.mem_compl_iff, Set.mem_range, not_exists] at this
+ exact this _
+
+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 : 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 : 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 (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 <;>
+ intro i
+ · rw [add_moveLeft_inl,
+ ← fuzzy_congr_left (add_congr_left (Equiv.symm (equiv_nim_grundyValue _))),
+ nim_add_fuzzy_zero_iff]
+ exact grundyValue_ne_moveLeft i
+ · rw [add_moveLeft_inr, ← Impartial.exists_left_move_equiv_iff_fuzzy_zero]
+ obtain ⟨j, hj⟩ := exists_grundyValue_moveLeft_of_lt <| toLeftMovesNim_symm_lt i
+ use toLeftMovesAdd (Sum.inl j)
+ rw [add_moveLeft_inl, moveLeft_nim']
+ 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 : 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] :
@@ -271,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]
@@ -282,67 +300,69 @@ theorem grundyValue_star : grundyValue star = 1 :=
theorem grundyValue_neg (G : PGame) [G.Impartial] : grundyValue (-G) = grundyValue G := by
rw [grundyValue_eq_iff_equiv_nim, neg_equiv_iff, neg_nim, ← grundyValue_eq_iff_equiv_nim]
-theorem grundyValue_eq_mex_right :
- ∀ (G : PGame) [G.Impartial],
- grundyValue G = Ordinal.mex.{u, u} fun i => grundyValue (G.moveRight i)
- | ⟨l, r, L, R⟩, _ => by
- rw [← grundyValue_neg, grundyValue_eq_mex_left]
- congr
- ext i
- haveI : (R i).Impartial := @Impartial.moveRight_impartial ⟨l, r, L, R⟩ _ i
- apply grundyValue_neg
-
--- Todo: this actually generalizes to all ordinals, by defining `Ordinal.lxor` as the pairwise
--- `Nat.xor` of base `ω` Cantor normal forms.
-/-- 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
- -- We do strong induction on both variables.
- induction' n using Nat.strong_induction_on with n hn generalizing m
- induction' m using Nat.strong_induction_on with m hm
- rw [grundyValue_eq_mex_left]
- refine (Ordinal.mex_le_of_ne.{u, u} fun i => ?_).antisymm
- (Ordinal.le_mex_of_forall fun ou hu => ?_)
- -- The Grundy value `n ^^^ m` can't be reached by left moves.
- · apply leftMoves_add_cases i <;>
- · -- A left move leaves us with a Grundy value of `k ^^^ m` for `k < n`, or
- -- `n ^^^ k` for `k < m`.
- refine fun a => leftMovesNimRecOn a fun ok hk => ?_
- obtain ⟨k, rfl⟩ := Ordinal.lt_omega.1 (hk.trans (Ordinal.nat_lt_omega _))
- simp only [add_moveLeft_inl, add_moveLeft_inr, moveLeft_nim', Equiv.symm_apply_apply]
- -- The inequality follows from injectivity.
- rw [natCast_lt] at hk
- first
- | rw [hn _ hk]
- | rw [hm _ hk]
- refine fun h => hk.ne ?_
- rw [Ordinal.natCast_inj] at h
- first
- | rwa [Nat.xor_left_inj] at h
- | rwa [Nat.xor_right_inj] at h
- -- Every other smaller Grundy value can be reached by left moves.
- · -- If `u < m ^^^ n`, then either `u ^^^ n < m` or `u ^^^ m < n`.
- obtain ⟨u, rfl⟩ := Ordinal.lt_omega.1 (hu.trans (Ordinal.nat_lt_omega _))
- replace hu := Ordinal.natCast_lt.1 hu
- cases' Nat.lt_xor_cases hu with h h
- -- In the first case, reducing the `m` pile to `u ^^^ n` gives the desired Grundy value.
- · refine ⟨toLeftMovesAdd (Sum.inl <| toLeftMovesNim ⟨_, Ordinal.natCast_lt.2 h⟩), ?_⟩
- simp [Nat.xor_cancel_right, hn _ h]
- -- In the second case, reducing the `n` pile to `u ^^^ m` gives the desired Grundy value.
- · refine ⟨toLeftMovesAdd (Sum.inr <| toLeftMovesNim ⟨_, Ordinal.natCast_lt.2 h⟩), ?_⟩
- have : n ^^^ (u ^^^ n) = u := by rw [Nat.xor_comm u, Nat.xor_cancel_left]
- simpa [hm _ h] using this
-
-theorem nim_add_nim_equiv {n m : ℕ} : nim n + nim m ≈ nim (n ^^^ m) := by
+theorem grundyValue_eq_sInf_moveRight (G : PGame) [G.Impartial] :
+ grundyValue G = sInf (Set.range (grundyValue ∘ G.moveRight))ᶜ := by
+ obtain ⟨l, r, L, R⟩ := G
+ rw [← grundyValue_neg, grundyValue_eq_sInf_moveLeft]
+ iterate 3 apply congr_arg
+ 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) :=
+ grundyValue_eq_sInf_moveRight G
+
+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 : 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 : 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 : Nimber}
+ (h : ∀ i, grundyValue (G.moveRight i) ≠ o) : G.grundyValue ≤ o := by
+ contrapose! h
+ exact exists_grundyValue_moveRight_of_lt h
+
+/-- 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 _)
+ · intro i
+ 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 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/Ordinal.lean b/Mathlib/SetTheory/Game/Ordinal.lean
index 5fdf75f21eaa4..b04e1d965c6ca 100644
--- a/Mathlib/SetTheory/Game/Ordinal.lean
+++ b/Mathlib/SetTheory/Game/Ordinal.lean
@@ -200,4 +200,15 @@ termination_by (a, b)
theorem toGame_nmul (a b : Ordinal) : (a ⨳ b).toGame = ⟦a.toPGame * b.toPGame⟧ :=
Quot.sound (toPGame_nmul a b)
+@[simp, norm_cast]
+theorem toGame_natCast : ∀ n : ℕ, toGame n = n
+ | 0 => Quot.sound (zeroToPGameRelabelling).equiv
+ | n + 1 => by
+ have : toGame 1 = 1 := Quot.sound oneToPGameRelabelling.equiv
+ rw [Nat.cast_add, ← nadd_nat, toGame_nadd, toGame_natCast, Nat.cast_one, this]
+ rfl
+
+theorem toPGame_natCast (n : ℕ) : toPGame n ≈ n := by
+ rw [PGame.equiv_iff_game_eq, ← toGame, toGame_natCast, quot_natCast]
+
end Ordinal
diff --git a/Mathlib/SetTheory/Game/PGame.lean b/Mathlib/SetTheory/Game/PGame.lean
index dec9ea13bd617..f67af28a88468 100644
--- a/Mathlib/SetTheory/Game/PGame.lean
+++ b/Mathlib/SetTheory/Game/PGame.lean
@@ -1,10 +1,10 @@
/-
Copyright (c) 2019 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Mario Carneiro, Isabel Longbottom, Scott Morrison
+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
@@ -822,13 +827,15 @@ theorem equiv_congr_right {x₁ x₂ : PGame} : (x₁ ≈ x₂) ↔ ∀ y₁, (x
⟨fun h _ => ⟨fun h' => Equiv.trans (Equiv.symm h) h', fun h' => Equiv.trans h h'⟩,
fun h => (h x₂).2 <| equiv_rfl⟩
-theorem equiv_of_mk_equiv {x y : PGame} (L : x.LeftMoves ≃ y.LeftMoves)
+theorem Equiv.of_equiv {x y : PGame} (L : x.LeftMoves ≃ y.LeftMoves)
(R : x.RightMoves ≃ y.RightMoves) (hl : ∀ i, x.moveLeft i ≈ y.moveLeft (L i))
(hr : ∀ j, x.moveRight j ≈ y.moveRight (R j)) : x ≈ y := by
constructor <;> rw [le_def]
· exact ⟨fun i => Or.inl ⟨_, (hl i).1⟩, fun j => Or.inr ⟨_, by simpa using (hr (R.symm j)).1⟩⟩
· exact ⟨fun i => Or.inl ⟨_, by simpa using (hl (L.symm i)).2⟩, fun j => Or.inr ⟨_, (hr j).2⟩⟩
+@[deprecated (since := "2024-09-26")] alias equiv_of_mk_equiv := Equiv.of_equiv
+
/-- The fuzzy, confused, or incomparable relation on pre-games.
If `x ‖ 0`, then the first player can always win `x`. -/
@@ -995,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) :=
@@ -1275,7 +1282,8 @@ instance : Add PGame.{u} :=
Note that this is **not** the usual recursive definition `n = {0, 1, … | }`. For instance,
`2 = 0 + 1 + 1 = {0 + 0 + 1, 0 + 1 + 0 | }` does not contain any left option equivalent to `0`. For
-an implementation of said definition, see `Ordinal.toPGame`. -/
+an implementation of said definition, see `Ordinal.toPGame`. For the proof that these games are
+equivalent, see `Ordinal.toPGame_natCast`. -/
instance : NatCast PGame :=
⟨Nat.unaryCast⟩
@@ -1431,9 +1439,11 @@ instance : Sub PGame :=
⟨fun x y => x + -y⟩
@[simp]
-theorem sub_zero (x : PGame) : x - 0 = x + 0 :=
+theorem sub_zero_eq_add_zero (x : PGame) : x - 0 = x + 0 :=
show x + -0 = x + 0 by rw [neg_zero]
+@[deprecated (since := "2024-09-26")] alias sub_zero := sub_zero_eq_add_zero
+
/-- If `w` has the same moves as `x` and `y` has the same moves as `z`,
then `w - y` has the same moves as `x - z`. -/
def Relabelling.subCongr {w x y z : PGame} (h₁ : w ≡r x) (h₂ : y ≡r z) : w - y ≡r x - z :=
@@ -1537,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 :=
@@ -1561,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 :=
@@ -1732,15 +1742,18 @@ instance uniqueStarLeftMoves : Unique star.LeftMoves :=
instance uniqueStarRightMoves : Unique star.RightMoves :=
PUnit.unique
+theorem zero_lf_star : 0 ⧏ star := by
+ rw [zero_lf]
+ use default
+ rintro ⟨⟩
+
+theorem star_lf_zero : star ⧏ 0 := by
+ rw [lf_zero]
+ use default
+ rintro ⟨⟩
+
theorem star_fuzzy_zero : star ‖ 0 :=
- ⟨by
- rw [lf_zero]
- use default
- rintro ⟨⟩,
- by
- rw [zero_lf]
- use default
- rintro ⟨⟩⟩
+ ⟨star_lf_zero, zero_lf_star⟩
@[simp]
theorem neg_star : -star = star := by simp [star]
diff --git a/Mathlib/SetTheory/Game/Short.lean b/Mathlib/SetTheory/Game/Short.lean
index fa9a0a1b91291..37fa7839716d3 100644
--- a/Mathlib/SetTheory/Game/Short.lean
+++ b/Mathlib/SetTheory/Game/Short.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Data.Fintype.Basic
@@ -136,7 +136,7 @@ def moveRightShort' {xl xr} (xL xR) [S : Short (mk xl xr xL xR)] (j : xr) : Shor
attribute [local instance] moveRightShort'
-theorem short_birthday (x : PGame.{u}) : [Short x] → x.birthday < Ordinal.omega := by
+theorem short_birthday (x : PGame.{u}) : [Short x] → x.birthday < Ordinal.omega0 := by
-- Porting note: Again `induction` is used instead of `pgame_wf_tac`
induction x with
| mk xl xr xL xR ihl ihr =>
@@ -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.
@@ -234,21 +231,25 @@ def leLFDecidable : ∀ (x y : PGame.{u}) [Short x] [Short y], Decidable (x ≤
| mk xl xr xL xR, mk yl yr yL yR, shortx, shorty => by
constructor
· refine @decidable_of_iff' _ _ mk_le_mk (id ?_)
- apply @And.decidable _ _ ?_ ?_
- · apply @Fintype.decidableForallFintype xl _ ?_ _
+ have : Decidable (∀ (i : xl), xL i ⧏ mk yl yr yL yR) := by
+ apply @Fintype.decidableForallFintype xl _ ?_ _
intro i
apply (leLFDecidable _ _).2
- · apply @Fintype.decidableForallFintype yr _ ?_ _
+ have : Decidable (∀ (j : yr), mk xl xr xL xR ⧏ yR j) := by
+ apply @Fintype.decidableForallFintype yr _ ?_ _
intro i
apply (leLFDecidable _ _).2
+ exact inferInstanceAs (Decidable (_ ∧ _))
· refine @decidable_of_iff' _ _ mk_lf_mk (id ?_)
- apply @Or.decidable _ _ ?_ ?_
- · apply @Fintype.decidableExistsFintype yl _ ?_ _
+ have : Decidable (∃ i, mk xl xr xL xR ≤ yL i) := by
+ apply @Fintype.decidableExistsFintype yl _ ?_ _
intro i
apply (leLFDecidable _ _).1
- · apply @Fintype.decidableExistsFintype xr _ ?_ _
+ have : Decidable (∃ j, xR j ≤ mk yl yr yL yR) := by
+ apply @Fintype.decidableExistsFintype xr _ ?_ _
intro i
apply (leLFDecidable _ _).1
+ exact inferInstanceAs (Decidable (_ ∨ _))
termination_by x y => (x, y)
instance leDecidable (x y : PGame.{u}) [Short x] [Short y] : Decidable (x ≤ y) :=
@@ -258,10 +259,10 @@ instance lfDecidable (x y : PGame.{u}) [Short x] [Short y] : Decidable (x ⧏ y)
(leLFDecidable x y).2
instance ltDecidable (x y : PGame.{u}) [Short x] [Short y] : Decidable (x < y) :=
- And.decidable
+ inferInstanceAs (Decidable (_ ∧ _))
instance equivDecidable (x y : PGame.{u}) [Short x] [Short y] : Decidable (x ≈ y) :=
- And.decidable
+ inferInstanceAs (Decidable (_ ∧ _))
example : Short 0 := by infer_instance
diff --git a/Mathlib/SetTheory/Game/State.lean b/Mathlib/SetTheory/Game/State.lean
index 79423b09551f8..01df81444246b 100644
--- a/Mathlib/SetTheory/Game/State.lean
+++ b/Mathlib/SetTheory/Game/State.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.SetTheory.Game.Short
@@ -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 9d6aa595b5a5a..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,37 +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.init (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]
@@ -116,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
@@ -135,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
@@ -173,7 +154,7 @@ theorem pred_eq_iff_not_succ' {o} : pred o = o ↔ ∀ a, o ≠ succ a := by
simpa using pred_eq_iff_not_succ
theorem pred_lt_iff_is_succ {o} : pred o < o ↔ ∃ a, o = succ a :=
- Iff.trans (by simp only [le_antisymm_iff, pred_le_self, true_and_iff, not_le])
+ Iff.trans (by simp only [le_antisymm_iff, pred_le_self, true_and, not_le])
(iff_not_comm.1 pred_eq_iff_not_succ).symm
@[simp]
@@ -199,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]⟩⟩
@@ -212,7 +193,9 @@ theorem lift_pred (o : Ordinal.{v}) : lift.{u} (pred o) = pred (lift.{u} o) := b
/-! ### Limit ordinals -/
-/-- A limit ordinal is an ordinal which is not zero and not a successor. -/
+/-- A limit ordinal is an ordinal which is not zero and not a successor.
+
+TODO: deprecate this in favor of `Order.IsSuccLimit`. -/
def IsLimit (o : Ordinal) : Prop :=
o ≠ 0 ∧ ∀ a < o, succ a < o
@@ -258,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)⟩
@@ -279,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]
@@ -289,23 +285,51 @@ def limitRecOn {C : Ordinal → Sort*} (o : Ordinal) (H₁ : C 0) (H₂ : ∀ o,
@[simp]
theorem limitRecOn_zero {C} (H₁ H₂ H₃) : @limitRecOn C 0 H₁ H₂ H₃ = H₁ := by
- rw [limitRecOn, SuccOrder.prelimitRecOn_limit _ _ isSuccPrelimit_zero, dif_pos rfl]
+ rw [limitRecOn, SuccOrder.prelimitRecOn_of_isSuccPrelimit _ _ isSuccPrelimit_zero, dif_pos rfl]
@[simp]
theorem limitRecOn_succ {C} (o H₁ H₂ H₃) :
@limitRecOn C (succ o) H₁ H₂ H₃ = H₂ o (@limitRecOn C o H₁ H₂ H₃) := by
- rw [limitRecOn, limitRecOn, SuccOrder.prelimitRecOn_succ _ _ (not_isMax _)]
+ rw [limitRecOn, limitRecOn, SuccOrder.prelimitRecOn_succ]
@[simp]
theorem limitRecOn_limit {C} (o H₁ H₂ H₃ h) :
@limitRecOn C o H₁ H₂ H₃ = H₃ o h fun x _h => @limitRecOn C x H₁ H₂ H₃ := by
- simp_rw [limitRecOn, SuccOrder.prelimitRecOn_limit _ _ h.isSuccPrelimit, dif_neg h.1]
+ simp_rw [limitRecOn, SuccOrder.prelimitRecOn_of_isSuccPrelimit _ _ h.isSuccPrelimit, dif_neg h.1]
+
+/-- Bounded recursion on ordinals. Similar to `limitRecOn`, with the assumption `o < l`
+ added to all cases. The final term's domain is the ordinals below `l`. -/
+@[elab_as_elim]
+def boundedLimitRecOn {l : Ordinal} (lLim : l.IsLimit) {C : Iio l → Sort*} (o : Iio l)
+ (H₁ : C ⟨0, lLim.pos⟩) (H₂ : (o : Iio l) → C o → C ⟨succ o, lLim.succ_lt o.2⟩)
+ (H₃ : (o : Iio l) → IsLimit o → (Π o' < o, C o') → C o) : C o :=
+ limitRecOn (C := fun p ↦ (h : p < l) → C ⟨p, h⟩) o.1 (fun _ ↦ H₁)
+ (fun o ih h ↦ H₂ ⟨o, _⟩ <| ih <| (lt_succ o).trans h)
+ (fun _o ho ih _ ↦ H₃ _ ho fun _o' h ↦ ih _ h _) o.2
+
+@[simp]
+theorem boundedLimitRec_zero {l} (lLim : l.IsLimit) {C} (H₁ H₂ H₃) :
+ @boundedLimitRecOn l lLim C ⟨0, lLim.pos⟩ H₁ H₂ H₃ = H₁ := by
+ rw [boundedLimitRecOn, limitRecOn_zero]
+
+@[simp]
+theorem boundedLimitRec_succ {l} (lLim : l.IsLimit) {C} (o H₁ H₂ H₃) :
+ @boundedLimitRecOn l lLim C ⟨succ o.1, lLim.succ_lt o.2⟩ H₁ H₂ H₃ = H₂ o
+ (@boundedLimitRecOn l lLim C o H₁ H₂ H₃) := by
+ rw [boundedLimitRecOn, limitRecOn_succ]
+ rfl
+
+theorem boundedLimitRec_limit {l} (lLim : l.IsLimit) {C} (o H₁ H₂ H₃ oLim) :
+ @boundedLimitRecOn l lLim C o H₁ H₂ H₃ = H₃ o oLim (fun x _ ↦
+ @boundedLimitRecOn l lLim C x H₁ H₂ H₃) := by
+ rw [boundedLimitRecOn, limitRecOn_limit]
+ rfl
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]
@@ -316,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
@@ -330,16 +354,28 @@ theorem bounded_singleton {r : α → α → Prop} [IsWellOrder α r] (hr : (typ
rw [@enum_lt_enum _ r, Subtype.mk_lt_mk]
apply lt_succ
--- Porting note: `· < ·` requires a type ascription for an `IsWellOrder` instance.
-theorem type_subrel_lt (o : Ordinal.{u}) :
- type (@Subrel Ordinal (· < ·) { o' : Ordinal | o' < o }) = Ordinal.lift.{u + 1} o := by
+@[simp]
+theorem typein_ordinal (o : Ordinal.{u}) :
+ @typein Ordinal (· < ·) _ o = Ordinal.lift.{u + 1} o := by
refine Quotient.inductionOn o ?_
rintro ⟨α, r, wo⟩; apply Quotient.sound
constructor; refine ((RelIso.preimage Equiv.ulift r).trans (enum r).symm).symm
+-- Porting note: `· < ·` requires a type ascription for an `IsWellOrder` instance.
+@[deprecated typein_ordinal (since := "2024-09-19")]
+theorem type_subrel_lt (o : Ordinal.{u}) :
+ type (@Subrel Ordinal (· < ·) { o' : Ordinal | o' < o }) = Ordinal.lift.{u + 1} o :=
+ typein_ordinal o
+
+theorem mk_Iio_ordinal (o : Ordinal.{u}) :
+ #(Iio o) = Cardinal.lift.{u + 1} o.card := by
+ rw [lift_card, ← typein_ordinal]
+ rfl
+
+@[deprecated mk_Iio_ordinal (since := "2024-09-19")]
theorem mk_initialSeg (o : Ordinal.{u}) :
- #{ o' : Ordinal | o' < o } = Cardinal.lift.{u + 1} o.card := by
- rw [lift_card, ← type_subrel_lt, card_type]
+ #{ o' : Ordinal | o' < o } = Cardinal.lift.{u + 1} o.card := mk_Iio_ordinal o
+
/-! ### Normal ordinal functions -/
@@ -382,12 +418,22 @@ theorem IsNormal.le_iff {f} (H : IsNormal f) {a b} : f a ≤ f b ↔ a ≤ b :=
theorem IsNormal.inj {f} (H : IsNormal f) {a b} : f a = f b ↔ a = b := by
simp only [le_antisymm_iff, H.le_iff]
+theorem IsNormal.id_le {f} (H : IsNormal f) : id ≤ f :=
+ H.strictMono.id_le
+
+theorem IsNormal.le_apply {f} (H : IsNormal f) {a} : a ≤ f a :=
+ H.strictMono.le_apply
+
+@[deprecated IsNormal.le_apply (since := "2024-09-11")]
theorem IsNormal.self_le {f} (H : IsNormal f) (a) : a ≤ f a :=
- lt_wf.self_le_of_strictMono H.strictMono a
+ H.strictMono.le_apply
+
+theorem IsNormal.le_iff_eq {f} (H : IsNormal f) {a} : f a ≤ a ↔ f a = a :=
+ H.le_apply.le_iff_eq
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₁ =>
@@ -419,11 +465,8 @@ theorem IsNormal.isLimit {f} (H : IsNormal f) {o} (l : IsLimit o) : IsLimit (f o
let ⟨_b, h₁, h₂⟩ := (H.limit_lt l).1 h
(succ_le_of_lt h₂).trans_lt (H.lt_iff.2 h₁)⟩
-theorem IsNormal.le_iff_eq {f} (H : IsNormal f) {a} : f a ≤ a ↔ f a = a :=
- (H.self_le a).le_iff_eq
-
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
@@ -449,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
@@ -461,7 +510,7 @@ alias IsLimit.add := add_isLimit
/-- The set in the definition of subtraction is nonempty. -/
-theorem sub_nonempty {a b : Ordinal} : { o | a ≤ b + o }.Nonempty :=
+private theorem sub_nonempty {a b : Ordinal} : { o | a ≤ b + o }.Nonempty :=
⟨a, le_add_left _ _⟩
/-- `a - b` is the unique ordinal satisfying `b + (a - b) = a` when `b ≤ a`. -/
@@ -524,14 +573,16 @@ 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
-theorem one_add_omega : 1 + ω = ω := by
+@[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 [omega, ← lift_one.{0}, ← lift_add, lift_le, ← type_unit, ← type_sum_lex]
+ rw [omega0, ← lift_one.{0}, ← lift_add, lift_le, ← type_unit, ← type_sum_lex]
refine ⟨RelEmbedding.collapse (RelEmbedding.ofMonotone ?_ ?_)⟩
· apply Sum.rec
· exact fun _ => 0
@@ -540,9 +591,15 @@ theorem one_add_omega : 1 + ω = ω := by
cases a <;> cases b <;> intro H <;> cases' H with _ _ H _ _ H <;>
[exact H.elim; exact Nat.succ_pos _; exact Nat.succ_lt_succ H]
+@[deprecated (since := "2024-09-30")]
+alias one_add_omega := one_add_omega0
+
@[simp]
-theorem one_add_of_omega_le {o} (h : ω ≤ o) : 1 + o = o := by
- rw [← Ordinal.add_sub_cancel_of_le h, ← add_assoc, one_add_omega]
+theorem one_add_of_omega0_le {o} (h : ω ≤ o) : 1 + o = o := by
+ rw [← Ordinal.add_sub_cancel_of_le h, ← add_assoc, one_add_omega0]
+
+@[deprecated (since := "2024-09-30")]
+alias one_add_of_omega_le := one_add_of_omega0_le
/-! ### Multiplication of ordinals -/
@@ -552,10 +609,9 @@ theorem one_add_of_omega_le {o} (h : ω ≤ o) : 1 + o = o := by
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, _⟩ =>
@@ -570,15 +626,15 @@ instance monoid : Monoid Ordinal.{u} where
Quotient.sound
⟨⟨punitProd _, @fun a b => by
rcases a with ⟨⟨⟨⟩⟩, a⟩; rcases b with ⟨⟨⟨⟩⟩, b⟩
- simp only [Prod.lex_def, EmptyRelation, false_or_iff]
- simp only [eq_self_iff_true, true_and_iff]
+ simp only [Prod.lex_def, EmptyRelation, false_or]
+ simp only [eq_self_iff_true, true_and]
rfl⟩⟩
one_mul a :=
inductionOn a fun α r _ =>
Quotient.sound
⟨⟨prodPUnit _, @fun a b => by
rcases a with ⟨a, ⟨⟨⟩⟩⟩; rcases b with ⟨b, ⟨⟨⟩⟩⟩
- simp only [Prod.lex_def, EmptyRelation, and_false_iff, or_false_iff]
+ simp only [Prod.lex_def, EmptyRelation, and_false, or_false]
rfl⟩⟩
@[simp]
@@ -623,13 +679,12 @@ instance leftDistribClass : LeftDistribClass Ordinal.{u} :=
simp only [Prod.lex_def, Sum.lex_inl_inl, Sum.Lex.sep, Sum.lex_inr_inl, Sum.lex_inr_inr,
sumProdDistrib_apply_left, sumProdDistrib_apply_right, reduceCtorEq] <;>
-- Porting note: `Sum.inr.inj_iff` is required.
- simp only [Sum.inl.inj_iff, Sum.inr.inj_iff,
- true_or_iff, false_and_iff, false_or_iff]⟩⟩⟩
+ simp only [Sum.inl.inj_iff, Sum.inr.inj_iff, true_or, false_and, false_or]⟩⟩⟩
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
@@ -638,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
@@ -684,18 +738,18 @@ private theorem mul_le_of_limit_aux {α β r s} [IsWellOrder α r] [IsWellOrder
intro h
by_cases e₁ : b = b₁ <;> by_cases e₂ : b = b₂
· substs b₁ b₂
- simpa only [subrel_val, Prod.lex_def, @irrefl _ s _ b, true_and_iff, false_or_iff,
+ simpa only [subrel_val, Prod.lex_def, @irrefl _ s _ b, true_and, false_or,
eq_self_iff_true, dif_pos, Sum.lex_inr_inr] using h
· subst b₁
simp only [subrel_val, Prod.lex_def, e₂, Prod.lex_def, dif_pos, subrel_val, eq_self_iff_true,
- or_false_iff, dif_neg, not_false_iff, Sum.lex_inr_inl, false_and_iff] at h ⊢
+ or_false, dif_neg, not_false_iff, Sum.lex_inr_inl, false_and] at h ⊢
cases' h₂ with _ _ _ _ h₂_h h₂_h <;> [exact asymm h h₂_h; exact e₂ rfl]
· simp [e₂, dif_neg e₁, show b₂ ≠ b₁ from e₂ ▸ e₁]
· simpa only [dif_neg e₁, dif_neg e₂, Prod.lex_def, subrel_val, Subtype.mk_eq_mk,
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
@@ -704,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
@@ -735,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 mul_isLimit {a b : Ordinal} (a0 : 0 < a) : IsLimit b → IsLimit (a * b) :=
- (mul_isNormal a0).isLimit
+theorem isLimit_mul {a b : Ordinal} (a0 : 0 < a) : IsLimit b → IsLimit (a * b) :=
+ (isNormal_mul_right a0).isLimit
-theorem mul_isLimit_left {a b : Ordinal} (l : IsLimit a) (b0 : 0 < b) : IsLimit (a * b) := by
+@[deprecated isLimit_mul (since := "2024-10-11")]
+alias mul_isLimit := isLimit_mul
+
+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]
@@ -755,7 +818,7 @@ theorem smul_eq_mul : ∀ (n : ℕ) (a : Ordinal), n • a = a * n
/-- The set in the definition of division is nonempty. -/
-theorem div_nonempty {a b : Ordinal} (h : b ≠ 0) : { o | a < b * succ o }.Nonempty :=
+private theorem div_nonempty {a b : Ordinal} (h : b ≠ 0) : { o | a < b * succ o }.Nonempty :=
⟨a, (succ_le_iff (a := a) (b := b * succ a)).1 <| by
simpa only [succ_zero, one_mul] using
mul_le_mul_right' (succ_le_of_lt (Ordinal.pos_iff_ne_zero.2 h)) (succ a)⟩
@@ -768,7 +831,7 @@ instance div : Div Ordinal :=
theorem div_zero (a : Ordinal) : a / 0 = 0 :=
dif_pos rfl
-theorem div_def (a) {b : Ordinal} (h : b ≠ 0) : a / b = sInf { o | a < b * succ o } :=
+private theorem div_def (a) {b : Ordinal} (h : b ≠ 0) : a / b = sInf { o | a < b * succ o } :=
dif_neg h
theorem lt_mul_succ_div (a) {b : Ordinal} (h : b ≠ 0) : a < b * succ (a / b) := by
@@ -792,8 +855,7 @@ theorem le_div {a b c : Ordinal} (c0 : c ≠ 0) : a ≤ b / c ↔ c * a ≤ b :=
| H₂ _ _ => rw [succ_le_iff, lt_div c0]
| H₃ _ h₁ h₂ =>
revert h₁ h₂
- simp (config := { contextual := true }) only [mul_le_of_limit, limit_le, iff_self_iff,
- forall_true_iff]
+ simp (config := { contextual := true }) only [mul_le_of_limit, limit_le, forall_true_iff]
theorem div_lt {a b c : Ordinal} (b0 : b ≠ 0) : a / b < c ↔ a < b * c :=
lt_iff_lt_of_le_iff_le <| le_div b0
@@ -813,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
@@ -870,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)
@@ -1014,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) :
@@ -1034,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 α :=
@@ -1097,13 +1166,14 @@ theorem comp_familyOfBFamily {o} (f : ∀ a < o, α) (g : α → β) :
/-! ### Supremum of a family of ordinals -/
--- Porting note: Universes should be specified in `sup`s.
-
/-- The supremum of a family of ordinals -/
+
+@[deprecated iSup (since := "2024-08-27")]
def sup {ι : Type u} (f : ι → Ordinal.{max u v}) : Ordinal.{max u v} :=
iSup f
-@[simp]
+set_option linter.deprecated false in
+@[deprecated (since := "2024-08-27")]
theorem sSup_eq_sup {ι : Type u} (f : ι → Ordinal.{max u v}) : sSup (Set.range f) = sup.{_, v} f :=
rfl
@@ -1115,29 +1185,103 @@ 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} _) _)))⟩
+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 =>
- le_csSup (bddAbove_range.{_, v} f) (mem_range_self i)
+ Ordinal.le_iSup f i
+/-- `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_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 :=
- (csSup_le_iff' (bddAbove_range.{_, v} f)).trans (by simp)
+ Ordinal.iSup_le_iff
+
+/-- An alias of `ciSup_le'` for discoverability. -/
+protected theorem iSup_le {ι} {f : ι → Ordinal} {a} :
+ (∀ i, f i ≤ a) → iSup f ≤ a :=
+ ciSup_le'
+set_option linter.deprecated false in
+@[deprecated Ordinal.iSup_le (since := "2024-08-27")]
theorem sup_le {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : (∀ i, f i ≤ a) → sup.{_, v} f ≤ a :=
- sup_le_iff.2
+ Ordinal.iSup_le
+
+/-- `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")]
theorem lt_sup {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : a < sup.{_, v} f ↔ ∃ i, a < f i := by
simpa only [not_forall, not_le] using not_congr (@sup_le_iff.{_, v} _ f a)
+@[deprecated (since := "2024-08-27")]
+theorem ne_iSup_iff_lt_iSup {ι : Type u} {f : ι → Ordinal.{max u v}} :
+ (∀ i, f i ≠ iSup f) ↔ ∀ i, f i < iSup f :=
+ forall_congr' fun i => (Ordinal.le_iSup f i).lt_iff_ne.symm
+
+set_option linter.deprecated false in
+@[deprecated ne_iSup_iff_lt_iSup (since := "2024-08-27")]
theorem ne_sup_iff_lt_sup {ι : Type u} {f : ι → Ordinal.{max u v}} :
(∀ i, f i ≠ sup.{_, v} f) ↔ ∀ i, f i < sup.{_, v} f :=
- ⟨fun hf _ => lt_of_le_of_ne (le_sup _ _) (hf _), fun hf _ => ne_of_lt (hf _)⟩
+ ne_iSup_iff_lt_iSup
+
+-- TODO: state in terms of `IsSuccLimit`.
+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 <|
+ (lt_of_le_of_ne (Ordinal.le_iSup _ _) (hf i)).trans_le hoa)
+set_option linter.deprecated false in
+@[deprecated succ_lt_iSup_of_ne_iSup (since := "2024-08-27")]
theorem sup_not_succ_of_ne_sup {ι : Type u} {f : ι → Ordinal.{max u v}}
(hf : ∀ i, f i ≠ sup.{_, v} f) {a} (hao : a < sup.{_, v} f) : succ a < sup.{_, v} f := by
by_contra! hoa
exact
hao.not_le (sup_le fun i => le_of_lt_succ <| (lt_of_le_of_ne (le_sup _ _) (hf i)).trans_le hoa)
-@[simp]
+-- TODO: generalize to conditionally complete lattices.
+theorem iSup_eq_zero_iff {ι} {f : ι → Ordinal.{u}} [Small.{u} ι] :
+ iSup f = 0 ↔ ∀ i, f i = 0 := by
+ refine
+ ⟨fun h i => ?_, fun h =>
+ le_antisymm (Ordinal.iSup_le fun i => Ordinal.le_zero.2 (h i)) (Ordinal.zero_le _)⟩
+ rw [← Ordinal.le_zero, ← h]
+ exact Ordinal.le_iSup f i
+
+set_option linter.deprecated false in
+@[deprecated iSup_eq_zero_iff (since := "2024-08-27")]
theorem sup_eq_zero_iff {ι : Type u} {f : ι → Ordinal.{max u v}} :
sup.{_, v} f = 0 ↔ ∀ i, f i = 0 := by
refine
@@ -1146,35 +1290,53 @@ theorem sup_eq_zero_iff {ι : Type u} {f : ι → Ordinal.{max u v}} :
rw [← Ordinal.le_zero, ← h]
exact le_sup f i
-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) :=
- eq_of_forall_ge_iff fun a => by
- rw [sup_le_iff]; simp only [comp]; rw [H.le_set' Set.univ Set.univ_nonempty g] <;>
- simp [sup_le_iff]
-
-@[simp]
+set_option linter.deprecated false in
+@[deprecated ciSup_of_empty (since := "2024-08-27")]
theorem sup_empty {ι} [IsEmpty ι] (f : ι → Ordinal) : sup f = 0 :=
ciSup_of_empty f
-@[simp]
+set_option linter.deprecated false in
+@[deprecated ciSup_const (since := "2024-08-27")]
theorem sup_const {ι} [_hι : Nonempty ι] (o : Ordinal) : (sup fun _ : ι => o) = o :=
ciSup_const
-@[simp]
+set_option linter.deprecated false in
+@[deprecated ciSup_unique (since := "2024-08-27")]
theorem sup_unique {ι} [Unique ι] (f : ι → Ordinal) : sup f = f default :=
ciSup_unique
+set_option linter.deprecated false in
+@[deprecated csSup_le_csSup' (since := "2024-08-27")]
theorem sup_le_of_range_subset {ι ι'} {f : ι → Ordinal} {g : ι' → Ordinal}
(h : Set.range f ⊆ Set.range g) : sup.{u, max v w} f ≤ sup.{v, max u w} g :=
- sup_le fun i =>
- match h (mem_range_self i) with
- | ⟨_j, hj⟩ => hj ▸ le_sup _ _
+ csSup_le_csSup' (bddAbove_range.{v, max u w} _) h
-theorem sup_eq_of_range_eq {ι ι'} {f : ι → Ordinal} {g : ι' → Ordinal}
+-- TODO: generalize or remove
+theorem iSup_eq_of_range_eq {ι ι'} {f : ι → Ordinal} {g : ι' → Ordinal}
+ (h : Set.range f = Set.range g) : iSup f = iSup g :=
+ congr_arg _ h
+
+set_option linter.deprecated false in
+@[deprecated iSup_eq_of_range_eq (since := "2024-08-27")]
+theorem sup_eq_of_range_eq {ι : Type u} {ι' : Type v}
+ {f : ι → Ordinal.{max u v w}} {g : ι' → Ordinal.{max u v w}}
(h : Set.range f = Set.range g) : sup.{u, max v w} f = sup.{v, max u w} g :=
- (sup_le_of_range_subset.{u, v, w} h.le).antisymm (sup_le_of_range_subset.{v, u, w} h.ge)
+ Ordinal.iSup_eq_of_range_eq h
-@[simp]
+-- TODO: generalize to conditionally complete lattices
+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 (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_of_small _)
+ rintro i ⟨a, rfl⟩
+ apply mem_range_self
+
+set_option linter.deprecated false in
+@[deprecated iSup_sum (since := "2024-08-27")]
theorem sup_sum {α : Type u} {β : Type v} (f : α ⊕ β → Ordinal) :
sup.{max u v, w} f =
max (sup.{u, max v w} fun a => f (Sum.inl a)) (sup.{v, max u w} fun b => f (Sum.inr b)) := by
@@ -1187,41 +1349,66 @@ theorem sup_sum {α : Type u} {β : Type v} (f : α ⊕ β → Ordinal) :
rintro i ⟨a, rfl⟩
apply mem_range_self
+theorem unbounded_range_of_le_iSup {α β : Type u} (r : α → α → Prop) [IsWellOrder α r] (f : β → α)
+ (h : type r ≤ ⨆ i, typein r (f i)) : Unbounded r (range f) :=
+ (not_bounded_iff _).1 fun ⟨x, hx⟩ =>
+ h.not_lt <| lt_of_le_of_lt
+ (Ordinal.iSup_le fun y => ((typein_lt_typein r).2 <| hx _ <| mem_range_self y).le)
+ (typein_lt_type r x)
+
+set_option linter.deprecated false in
+@[deprecated unbounded_range_of_le_iSup (since := "2024-08-27")]
theorem unbounded_range_of_sup_ge {α β : Type u} (r : α → α → Prop) [IsWellOrder α r] (f : β → α)
(h : type r ≤ sup.{u, u} (typein r ∘ f)) : Unbounded r (range f) :=
- (not_bounded_iff _).1 fun ⟨x, hx⟩ =>
- not_lt_of_le h <|
- lt_of_le_of_lt
- (sup_le fun y => le_of_lt <| (typein_lt_typein r).2 <| hx _ <| mem_range_self y)
- (typein_lt_type r x)
+ unbounded_range_of_le_iSup r f h
+set_option linter.deprecated false in
+@[deprecated (since := "2024-08-27")]
theorem le_sup_shrink_equiv {s : Set Ordinal.{u}} (hs : Small.{u} s) (a) (ha : a ∈ s) :
a ≤ sup.{u, u} fun x => ((@equivShrink s hs).symm x).val := by
convert le_sup.{u, u} (fun x => ((@equivShrink s hs).symm x).val) ((@equivShrink s hs) ⟨a, ha⟩)
rw [symm_apply_apply]
-instance small_Iio (o : Ordinal.{u}) : Small.{u} (Set.Iio o) :=
- let f : o.toType → Set.Iio o :=
- fun x => ⟨typein (α := o.toType) (· < ·) x, typein_lt_self x⟩
- let hf : Surjective f := fun b =>
- ⟨enum (α := o.toType) (· < ·) ⟨b.val,
- by
- rw [type_lt]
- exact b.prop⟩,
- Subtype.ext (typein_enum _ _)⟩
- small_of_surjective hf
-
-instance small_Iic (o : Ordinal.{u}) : Small.{u} (Set.Iic o) := by
- rw [← Iio_succ]
- infer_instance
-
-theorem bddAbove_iff_small {s : Set Ordinal.{u}} : BddAbove s ↔ Small.{u} s :=
- ⟨fun ⟨a, h⟩ => small_subset <| show s ⊆ Iic a from fun _x hx => h hx, fun h =>
- ⟨sup.{u, u} fun x => ((@equivShrink s h).symm x).val, le_sup_shrink_equiv h⟩⟩
+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
+
+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_of_small (s : Set Ordinal.{u}) [h : Small.{u} s] : BddAbove s :=
- bddAbove_iff_small.2 h
+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")]
theorem sup_eq_sSup {s : Set Ordinal.{u}} (hs : Small.{u} s) :
(sup.{u, u} fun x => (@equivShrink s hs).symm x) = sSup s :=
let hs' := bddAbove_iff_small.2 hs
@@ -1243,6 +1430,27 @@ 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
+set_option linter.deprecated false
+
private theorem sup_le_sup {ι ι' : Type u} (r : ι → ι → Prop) (r' : ι' → ι' → Prop)
[IsWellOrder ι r] [IsWellOrder ι' r'] {o} (ho : type r = o) (ho' : type r' = o)
(f : ∀ a < o, Ordinal.{max u v}) :
@@ -1312,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 :=
@@ -1382,6 +1590,13 @@ theorem bsup_eq_of_brange_eq {o o'} {f : ∀ a < o, Ordinal} {g : ∀ a < o', Or
(h : brange o f = brange o' g) : bsup.{u, max v w} o f = bsup.{v, max u w} o' g :=
(bsup_le_of_brange_subset.{u, v, w} h.le).antisymm (bsup_le_of_brange_subset.{v, u, w} h.ge)
+end bsup
+
+-- TODO: bring the lsub API in line with the sSup / iSup API, or deprecate it altogether.
+
+section lsub
+set_option linter.deprecated false
+
/-- The least strict upper bound of a family of ordinals. -/
def lsub {ι} (f : ι → Ordinal) : Ordinal :=
sup (succ ∘ f)
@@ -1526,6 +1741,14 @@ theorem sup_typein_succ {o : Ordinal} :
rw [← succ_eq_succ_iff, h]
apply lsub_typein
+end lsub
+
+-- TODO: either deprecate this in favor of `lsub` when its universes are generalized, or deprecate
+-- both of them at once.
+
+section blsub
+set_option linter.deprecated false
+
/-- The least strict upper bound of a family of ordinals indexed by the set of ordinals less than
some `o : Ordinal.{u}`.
@@ -1744,11 +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))
+@[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
@@ -1756,34 +1983,47 @@ theorem lt_blsub₂ {o₁ o₂ : Ordinal}
(enum (· < ·) ⟨b, by rwa [type_lt]⟩))
simp only [typein_enum]
+end blsub
+
+section mex
+set_option linter.deprecated false
+
/-! ### Minimum excluded ordinals -/
/-- 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 => ?_
@@ -1791,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
@@ -1811,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})
@@ -1830,29 +2075,36 @@ 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]
exact mex_lt_ord_succ_mk (familyOfBFamily o f)
+end mex
+
end Ordinal
/-! ### Results about injectivity and surjectivity -/
@@ -1875,135 +2127,22 @@ the Burali-Forti paradox. -/
theorem not_small_ordinal : ¬Small.{u} Ordinal.{max u v} := fun h =>
@not_injective_of_ordinal_of_small _ h _ fun _a _b => Ordinal.lift_inj.{v, u}.1
-/-! ### Enumerating unbounded sets of ordinals with ordinals -/
-
-
-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 Ordinal.not_bddAbove_compl_of_small (s : Set Ordinal.{u}) [hs : Small.{u} s] :
+ ¬BddAbove sᶜ := by
+ rw [bddAbove_iff_small]
+ intro h
+ have := small_union s sᶜ
+ rw [union_compl_self, small_univ_iff] at this
+ exact not_small_ordinal this
-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)⟩
+/-! ### Casting naturals into ordinals, compatibility with operations -/
-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 => (lt_wf.self_le_of_strictMono (enumOrd_strictMono hS) 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 [← lt_wf.eq_strictMono_iff_eq_range h₁ (enumOrd_strictMono hS), range_enumOrd hS]
- · rintro rfl
- exact ⟨enumOrd_strictMono hS, range_enumOrd hS⟩
-
-end
-/-! ### Casting naturals into ordinals, compatibility with operations -/
+namespace Ordinal
+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
@@ -2027,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")]
@@ -2071,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
@@ -2083,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")]
@@ -2118,24 +2252,16 @@ theorem lift_ofNat (n : ℕ) [n.AtLeastTwo] :
end Ordinal
-/-! ### Properties of `omega` -/
+/-! ### Properties of ω -/
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_omega_le]
+ rw [add_comm, ← card_ord c, ← card_one, ← card_add, one_add_of_omega0_le]
rwa [← ord_aleph0, ord_le_ord]
end Cardinal
@@ -2145,36 +2271,66 @@ 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_omega {o : Ordinal} : o < ω ↔ ∃ n : ℕ, o = n := by
+theorem lt_omega0 {o : Ordinal} : o < ω ↔ ∃ n : ℕ, o = n := by
simp_rw [← Cardinal.ord_aleph0, Cardinal.lt_ord, lt_aleph0, card_eq_nat]
-theorem nat_lt_omega (n : ℕ) : ↑n < ω :=
- lt_omega.2 ⟨_, rfl⟩
+@[deprecated (since := "2024-09-30")]
+alias lt_omega := lt_omega0
+
+theorem nat_lt_omega0 (n : ℕ) : ↑n < ω :=
+ lt_omega0.2 ⟨_, rfl⟩
+@[deprecated (since := "2024-09-30")]
+alias nat_lt_omega := nat_lt_omega0
+
+theorem omega0_pos : 0 < ω :=
+ nat_lt_omega0 0
+
+@[deprecated (since := "2024-09-30")]
theorem omega_pos : 0 < ω :=
- nat_lt_omega 0
+ nat_lt_omega0 0
+
+theorem omega0_ne_zero : ω ≠ 0 :=
+ omega0_pos.ne'
+
+@[deprecated (since := "2024-09-30")]
+alias omega_ne_zero := omega0_ne_zero
+
+theorem one_lt_omega0 : 1 < ω := by simpa only [Nat.cast_one] using nat_lt_omega0 1
-theorem omega_ne_zero : ω ≠ 0 :=
- omega_pos.ne'
+@[deprecated (since := "2024-09-30")]
+alias one_lt_omega := one_lt_omega0
-theorem one_lt_omega : 1 < ω := by simpa only [Nat.cast_one] using nat_lt_omega 1
+theorem isLimit_omega0 : IsLimit ω :=
+ ⟨omega0_ne_zero, fun o h => by
+ let ⟨n, e⟩ := lt_omega0.1 h
+ rw [e]; exact nat_lt_omega0 (n + 1)⟩
-theorem omega_isLimit : IsLimit ω :=
- ⟨omega_ne_zero, fun o h => by
- let ⟨n, e⟩ := lt_omega.1 h
- rw [e]; exact nat_lt_omega (n + 1)⟩
+@[deprecated (since := "2024-10-14")]
+alias omega0_isLimit := isLimit_omega0
-theorem omega_le {o : Ordinal} : ω ≤ o ↔ ∀ n : ℕ, ↑n ≤ o :=
- ⟨fun h n => (nat_lt_omega _).le.trans h, fun H =>
+@[deprecated (since := "2024-09-30")]
+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 =>
le_of_forall_lt fun a h => by
- let ⟨n, e⟩ := lt_omega.1 h
+ let ⟨n, e⟩ := lt_omega0.1 h
rw [e, ← succ_le_iff]; exact H (n + 1)⟩
+@[deprecated (since := "2024-09-30")]
+alias omega_le := omega0_le
+
@[simp]
+theorem iSup_natCast : iSup Nat.cast = ω :=
+ (Ordinal.iSup_le fun n => (nat_lt_omega0 n).le).antisymm <| omega0_le.2 <| Ordinal.le_iSup _
+
+set_option linter.deprecated false in
+@[deprecated iSup_natCast (since := "2024-04-17")]
theorem sup_natCast : sup Nat.cast = ω :=
- (sup_le fun n => (nat_lt_omega n).le).antisymm <| omega_le.2 <| le_sup _
+ iSup_natCast
@[deprecated (since := "2024-04-17")]
alias sup_nat_cast := sup_natCast
@@ -2183,24 +2339,30 @@ theorem nat_lt_limit {o} (h : IsLimit o) : ∀ n : ℕ, ↑n < o
| 0 => lt_of_le_of_ne (Ordinal.zero_le o) h.1.symm
| n + 1 => h.2 _ (nat_lt_limit h n)
-theorem omega_le_of_isLimit {o} (h : IsLimit o) : ω ≤ o :=
- omega_le.2 fun n => le_of_lt <| nat_lt_limit h n
+theorem omega0_le_of_isLimit {o} (h : IsLimit o) : ω ≤ o :=
+ omega0_le.2 fun n => le_of_lt <| nat_lt_limit h n
-theorem isLimit_iff_omega_dvd {a : Ordinal} : IsLimit a ↔ a ≠ 0 ∧ ω ∣ a := by
+@[deprecated (since := "2024-09-30")]
+alias omega_le_of_isLimit := omega0_le_of_isLimit
+
+theorem isLimit_iff_omega0_dvd {a : Ordinal} : IsLimit a ↔ a ≠ 0 ∧ ω ∣ a := by
refine ⟨fun l => ⟨l.1, ⟨a / ω, le_antisymm ?_ (mul_div_le _ _)⟩⟩, fun h => ?_⟩
· refine (limit_le l).2 fun x hx => le_of_lt ?_
- rw [← div_lt omega_ne_zero, ← succ_le_iff, le_div omega_ne_zero, mul_succ,
- add_le_of_limit omega_isLimit]
+ rw [← div_lt omega0_ne_zero, ← succ_le_iff, le_div omega0_ne_zero, mul_succ,
+ add_le_of_limit isLimit_omega0]
intro b hb
- rcases lt_omega.1 hb with ⟨n, rfl⟩
+ 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 omega_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]
+@[deprecated (since := "2024-09-30")]
+alias isLimit_iff_omega_dvd := isLimit_iff_omega0_dvd
+
theorem add_mul_limit_aux {a b c : Ordinal} (ba : b + a = a) (l : IsLimit c)
(IH : ∀ c' < c, (a + b) * succ c' = a * succ c' + b) : (a + b) * c = a * c :=
le_antisymm
@@ -2239,70 +2401,59 @@ theorem add_le_of_forall_add_lt {a b c : Ordinal} (hb : 0 < b) (h : ∀ d < b, a
by_contra! hb
exact (h _ hb).ne H
-theorem IsNormal.apply_omega {f : Ordinal.{u} → Ordinal.{u}} (hf : IsNormal f) :
- Ordinal.sup.{0, u} (f ∘ Nat.cast) = f ω := by rw [← sup_natCast, IsNormal.sup.{0, u, u} hf]
+theorem IsNormal.apply_omega0 {f : Ordinal.{u} → Ordinal.{v}} (hf : IsNormal f) :
+ ⨆ n : ℕ, f n = f ω := by rw [← iSup_natCast, hf.map_iSup]
+
+@[deprecated (since := "2024-09-30")]
+alias IsNormal.apply_omega := IsNormal.apply_omega0
@[simp]
+theorem iSup_add_nat (o : Ordinal) : ⨆ n : ℕ, o + n = o + ω :=
+ (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_omega
+ (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 (isNormal_mul_right ho).apply_omega0
+
+set_option linter.deprecated false in
+@[deprecated iSup_add_nat (since := "2024-08-27")]
theorem sup_mul_nat (o : Ordinal) : (sup fun n : ℕ => o * n) = o * ω := by
rcases eq_zero_or_pos o with (rfl | ho)
· rw [zero_mul]
exact sup_eq_zero_iff.2 fun n => zero_mul (n : Ordinal)
- · exact (mul_isNormal ho).apply_omega
+ · exact (mul_isNormal ho).apply_omega0
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 => Ordinal.sup.{u, u} fun b : { b // r b a } => Order.succ <| ih b b.2
-
-theorem rank_eq (h : Acc r a) :
- h.rank = Ordinal.sup.{u, u} fun 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_sup _ ⟨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 = Ordinal.sup.{u, u} fun 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 2400
+set_option linter.style.longFile 2600
diff --git a/Mathlib/SetTheory/Ordinal/Basic.lean b/Mathlib/SetTheory/Ordinal/Basic.lean
index 59d519bb5d82d..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
@@ -28,12 +27,13 @@ initial segment (or, equivalently, in any way). This total order is well founded
* `Ordinal.card o`: the cardinality of an ordinal `o`.
* `Ordinal.lift` lifts an ordinal in universe `u` to an ordinal in universe `max u v`.
For a version registering additionally that this is an initial segment embedding, see
- `Ordinal.lift.initialSeg`.
+ `Ordinal.liftInitialSeg`.
For a version registering that it is a principal segment embedding if `u < v`, see
- `Ordinal.lift.principalSeg`.
-* `Ordinal.omega` or `ω` is the order type of `ℕ`. This definition is universe polymorphic:
- `Ordinal.omega.{u} : Ordinal.{u}` (contrast with `ℕ : Type`, which lives in a specific
- universe). In some cases the universe level has to be given explicitly.
+ `Ordinal.liftPrincipalSeg`.
+* `Ordinal.omega0` or `ω` is the order type of `ℕ`. It is called this to match `Cardinal.aleph0`
+ and so that the omega function can be named `Ordinal.omega`. This definition is universe
+ polymorphic: `Ordinal.omega0.{u} : Ordinal.{u}` (contrast with `ℕ : Type`, which lives in
+ a specific universe). In some cases the universe level has to be given explicitly.
* `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₂`.
@@ -67,42 +67,6 @@ universe u v w
variable {α : Type u} {β : Type*} {γ : Type*} {r : α → α → Prop} {s : β → β → Prop}
{t : γ → γ → Prop}
-/-! ### Well order on an arbitrary type -/
-
-
-section WellOrderingThm
-
--- Porting note: `parameter` does not work
--- parameter {σ : Type u}
-variable {σ : Type u}
-
-
-open Function
-
-theorem nonempty_embedding_to_cardinal : Nonempty (σ ↪ Cardinal.{u}) :=
- (Embedding.total _ _).resolve_left fun ⟨⟨f, hf⟩⟩ =>
- let g : σ → Cardinal.{u} := invFun f
- let ⟨x, (hx : g x = 2 ^ sum g)⟩ := invFun_surjective hf (2 ^ sum g)
- have : g x ≤ sum g := le_sum.{u, u} g x
- not_le_of_gt (by rw [hx]; exact cantor _) this
-
-/-- An embedding of any type to the set of cardinals. -/
-def embeddingToCardinal : σ ↪ Cardinal.{u} :=
- Classical.choice nonempty_embedding_to_cardinal
-
-/-- Any type can be endowed with a well order, obtained by pulling back the well order over
-cardinals by some embedding. -/
-def WellOrderingRel : σ → σ → Prop :=
- embeddingToCardinal ⁻¹'o (· < ·)
-
-instance WellOrderingRel.isWellOrder : IsWellOrder σ WellOrderingRel :=
- (RelEmbedding.preimage _ _).isWellOrder
-
-instance IsWellOrder.subtype_nonempty : Nonempty { r // IsWellOrder σ r } :=
- ⟨⟨WellOrderingRel, inferInstance⟩⟩
-
-end WellOrderingThm
-
/-! ### Definition of ordinals -/
@@ -175,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
@@ -190,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) :=
@@ -226,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
@@ -244,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
@@ -258,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
@@ -283,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 -/
/--
@@ -290,9 +264,11 @@ For `Ordinal`:
* less-equal is defined such that well orders `r` and `s` satisfy `type r ≤ type s` if there exists
a function embedding `r` as an *initial* segment of `s`.
-
* less-than is defined such that well orders `r` and `s` satisfy `type r < type s` if there exists
a function embedding `r` as a *principal* segment of `s`.
+
+Note that most of the relevant results on initial and principal segments are proved in the
+`Order.InitialSeg` file.
-/
instance partialOrder : PartialOrder Ordinal where
le a b :=
@@ -313,11 +289,17 @@ instance partialOrder : PartialOrder Ordinal where
lt_iff_le_not_le a b :=
Quotient.inductionOn₂ a b fun _ _ =>
⟨fun ⟨f⟩ => ⟨⟨f⟩, fun ⟨g⟩ => (f.ltLe g).irrefl⟩, fun ⟨⟨f⟩, h⟩ =>
- Sum.recOn f.ltOrEq (fun g => ⟨g⟩) fun g => (h ⟨InitialSeg.ofIso g.symm⟩).elim⟩
+ f.ltOrEq.recOn (fun g => ⟨g⟩) fun g => (h ⟨InitialSeg.ofIso g.symm⟩).elim⟩
le_antisymm a b :=
Quotient.inductionOn₂ a b fun _ _ ⟨h₁⟩ ⟨h₂⟩ =>
Quot.sound ⟨InitialSeg.antisymm h₁ h₂⟩
+instance linearOrder : LinearOrder Ordinal :=
+ {inferInstanceAs (PartialOrder Ordinal) with
+ 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 _ }
+
theorem type_le_iff {α β} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r]
[IsWellOrder β s] : type r ≤ type s ↔ Nonempty (r ≼i s) :=
Iff.rfl
@@ -376,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.init 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. -/
@@ -470,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 : α) :
@@ -509,12 +491,24 @@ theorem lt_wf : @WellFounded Ordinal (· < ·) :=
instance wellFoundedRelation : WellFoundedRelation Ordinal :=
⟨(· < ·), lt_wf⟩
+instance wellFoundedLT : WellFoundedLT Ordinal :=
+ ⟨lt_wf⟩
+
+instance isWellOrder : IsWellOrder Ordinal (· < ·) where
+
+instance : ConditionallyCompleteLinearOrderBot Ordinal :=
+ WellFoundedLT.conditionallyCompleteLinearOrderBot _
+
/-- Reformulation of well founded induction on ordinals as a lemma that works with the
`induction` tactic, as in `induction i using Ordinal.induction with | h i IH => ?_`. -/
theorem induction {p : Ordinal.{u} → Prop} (i : Ordinal.{u}) (h : ∀ j, (∀ k, k < j → p k) → p 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 -/
@@ -546,7 +540,7 @@ theorem card_one : card 1 = 1 := mk_eq_one _
-- Porting note: Needed to add universe hint .{u} below
/-- The universe lift operation for ordinals, which embeds `Ordinal.{u}` as
a proper initial segment of `Ordinal.{v}` for `v > u`. For the initial segment version,
- see `lift.initialSeg`. -/
+ see `liftInitialSeg`. -/
@[pp_with_univ]
def lift (o : Ordinal.{v}) : Ordinal.{max v u} :=
Quotient.liftOn o (fun w => type <| ULift.down.{u} ⁻¹'o w.r) fun ⟨_, r, _⟩ ⟨_, s, _⟩ ⟨f⟩ =>
@@ -606,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⟩ =>
@@ -644,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_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_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 lift_inj {a b : Ordinal} : lift.{u,v} a = lift.{u,v} b ↔ a = b := by
- simp only [le_antisymm_iff, lift_le]
+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_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_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 :=
@@ -667,75 +685,55 @@ 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 lift.initialSeg : @InitialSeg Ordinal.{u} Ordinal.{max u v} (· < ·) (· < ·) :=
- ⟨⟨⟨lift.{v}, fun _ _ => lift_inj.1⟩, lift_lt⟩, fun _ _ h => lift_down (le_of_lt h)⟩
+ b < lift.{v} a ↔ ∃ a' < a, lift.{v} a' = b :=
+ liftInitialSeg.lt_apply_iff
-@[simp]
-theorem lift.initialSeg_coe : (lift.initialSeg.{u,v} : Ordinal → Ordinal) = lift.{v,u} :=
- rfl
-
-/-! ### The first infinite ordinal `omega` -/
+/-! ### The first infinite ordinal ω -/
/-- `ω` is the first infinite ordinal, defined as the order type of `ℕ`. -/
-def omega : Ordinal.{u} :=
+def omega0 : Ordinal.{u} :=
lift <| @type ℕ (· < ·) _
@[inherit_doc]
-scoped notation "ω" => Ordinal.omega
+scoped notation "ω" => Ordinal.omega0
-/-- Note that the presence of this lemma makes `simp [omega]` form a loop. -/
+/-- Note that the presence of this lemma makes `simp [omega0]` form a loop. -/
@[simp]
theorem type_nat_lt : @type ℕ (· < ·) _ = ω :=
(lift_id _).symm
@[simp]
-theorem card_omega : card ω = ℵ₀ :=
+theorem card_omega0 : card ω = ℵ₀ :=
rfl
+@[deprecated (since := "2024-09-30")]
+alias card_omega := card_omega0
+
@[simp]
-theorem lift_omega : lift ω = ω :=
+theorem lift_omega0 : lift ω = ω :=
lift_lift _
+@[deprecated (since := "2024-09-30")]
+alias lift_omega := lift_omega0
+
/-!
### Definition and first properties of addition on ordinals
@@ -747,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, _⟩ =>
@@ -792,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
@@ -838,32 +807,6 @@ theorem le_add_right (a b : Ordinal) : a ≤ a + b := by
theorem le_add_left (a b : Ordinal) : a ≤ b + a := by
simpa only [zero_add] using add_le_add_right (Ordinal.zero_le b) a
-instance linearOrder : LinearOrder Ordinal :=
- {inferInstanceAs (PartialOrder Ordinal) with
- le_total := fun a b =>
- match lt_or_eq_of_le (le_add_left b a), lt_or_eq_of_le (le_add_right a b) with
- | Or.inr h, _ => by rw [h]; exact Or.inl (le_add_right _ _)
- | _, Or.inr h => by rw [h]; exact Or.inr (le_add_left _ _)
- | Or.inl h₁, Or.inl h₂ => by
- revert h₁ h₂
- refine inductionOn a ?_
- intro α₁ r₁ _
- refine inductionOn b ?_
- intro α₂ r₂ _ ⟨f⟩ ⟨g⟩
- rw [← typein_top f, ← typein_top g, le_iff_lt_or_eq, le_iff_lt_or_eq,
- typein_lt_typein, typein_lt_typein]
- rcases trichotomous_of (Sum.Lex r₁ r₂) g.top f.top with (h | h | h) <;>
- [exact Or.inl (Or.inl h); (left; right; rw [h]); exact Or.inr (Or.inl h)]
- decidableLE := Classical.decRel _ }
-
-instance wellFoundedLT : WellFoundedLT Ordinal :=
- ⟨lt_wf⟩
-
-instance isWellOrder : IsWellOrder Ordinal (· < ·) where
-
-instance : ConditionallyCompleteLinearOrderBot Ordinal :=
- WellFoundedLT.conditionallyCompleteLinearOrderBot _
-
theorem max_zero_left : ∀ a : Ordinal, max 0 a = a :=
max_bot_left
@@ -880,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.init _ _ _ _ _ ⟨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⟩⟩
@@ -1015,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
@@ -1030,22 +953,29 @@ theorem enum_inj {r : α → α → Prop} [IsWellOrder α r] {o₁ o₂ : {o //
rw [EmbeddingLike.apply_eq_iff_eq, Subtype.mk.injEq]
/-- The order isomorphism between ordinals less than `o` and `o.toType`. -/
-@[simps!]
+@[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
+instance small_Iio (o : Ordinal.{u}) : Small.{u} (Iio o) :=
+ ⟨_, ⟨(enumIsoToType _).toEquiv⟩⟩
+
+instance small_Iic (o : Ordinal.{u}) : Small.{u} (Iic o) := by
+ rw [← Iio_succ]
+ exact small_Iio _
+
+instance small_Ico (a b : Ordinal.{u}) : Small.{u} (Ico a b) := small_subset Ico_subset_Iio_self
+instance small_Icc (a b : Ordinal.{u}) : Small.{u} (Icc a b) := small_subset Icc_subset_Iic_self
+instance small_Ioo (a b : Ordinal.{u}) : Small.{u} (Ioo a b) := small_subset Ioo_subset_Iio_self
+instance small_Ioc (a b : Ordinal.{u}) : Small.{u} (Ioc a b) := small_subset Ioc_subset_Iic_self
+
/-- `o.toType` is an `OrderBot` whenever `0 < o`. -/
def toTypeOrderBotOfPos {o : Ordinal} (ho : 0 < o) : OrderBot o.toType where
bot_le := enum_zero_le' ho
@@ -1054,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
@@ -1079,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 lift.principalSeg : @PrincipalSeg Ordinal.{u} Ordinal.{max (u + 1) v} (· < ·) (· < ·) :=
- ⟨↑lift.initialSeg.{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
@@ -1093,34 +1028,46 @@ def lift.principalSeg : @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
@[simp]
+theorem liftPrincipalSeg_coe :
+ (liftPrincipalSeg.{u, v} : Ordinal → Ordinal) = lift.{max (u + 1) v} :=
+ rfl
+
+set_option linter.deprecated false in
+@[deprecated liftPrincipalSeg_coe (since := "2024-09-21")]
theorem lift.principalSeg_coe :
(lift.principalSeg.{u, v} : Ordinal → Ordinal) = lift.{max (u + 1) v} :=
rfl
--- Porting note: Added universe hints below
@[simp]
-theorem lift.principalSeg_top : (lift.principalSeg.{u,v}).top = univ.{u,v} :=
+theorem liftPrincipalSeg_top : (liftPrincipalSeg.{u, v}).top = univ.{u, v} :=
rfl
+set_option linter.deprecated false in
+@[deprecated liftPrincipalSeg_top (since := "2024-09-21")]
+theorem lift.principalSeg_top : (lift.principalSeg.{u, v}).top = univ.{u, v} :=
+ rfl
+
+theorem liftPrincipalSeg_top' : liftPrincipalSeg.{u, u + 1}.top = @type Ordinal (· < ·) _ := by
+ simp only [liftPrincipalSeg_top, univ_id]
+
+set_option linter.deprecated false in
+@[deprecated liftPrincipalSeg_top (since := "2024-09-21")]
theorem lift.principalSeg_top' : lift.principalSeg.{u, u + 1}.top = @type Ordinal (· < ·) _ := by
simp only [lift.principalSeg_top, univ_id]
@@ -1135,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
@@ -1188,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 :=
@@ -1242,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
@@ -1252,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]
@@ -1287,6 +1242,18 @@ theorem ord_injective : Injective ord := by
intro c c' h
rw [← card_ord c, ← card_ord c', h]
+@[simp]
+theorem ord_inj {a b : Cardinal} : a.ord = b.ord ↔ a = b :=
+ ord_injective.eq_iff
+
+@[simp]
+theorem ord_eq_zero {a : Cardinal} : a.ord = 0 ↔ a = 0 :=
+ ord_injective.eq_iff' ord_zero
+
+@[simp]
+theorem ord_eq_one {a : Cardinal} : a.ord = 1 ↔ a = 1 :=
+ ord_injective.eq_iff' ord_one
+
/-- The ordinal corresponding to a cardinal `c` is the least ordinal
whose cardinal is `c`. This is the order-embedding version. For the regular function, see `ord`.
-/
@@ -1317,8 +1284,8 @@ theorem univ_umax : univ.{u, max (u + 1) v} = univ.{u, v} :=
congr_fun lift_umax _
theorem lift_lt_univ (c : Cardinal) : lift.{u + 1, u} c < univ.{u, u + 1} := by
- simpa only [lift.principalSeg_coe, lift_ord, lift_succ, ord_le, succ_le_iff] using
- le_of_lt (lift.principalSeg.{u, u + 1}.lt_top (succ c).ord)
+ simpa only [liftPrincipalSeg_coe, lift_ord, lift_succ, ord_le, succ_le_iff] using
+ le_of_lt (liftPrincipalSeg.{u, u + 1}.lt_top (succ c).ord)
theorem lift_lt_univ' (c : Cardinal) : lift.{max (u + 1) v, u} c < univ.{u, v} := by
have := lift_lt.{_, max (u+1) v}.2 (lift_lt_univ c)
@@ -1328,26 +1295,26 @@ 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 := lift.principalSeg.{u, v}.down.1 (by simpa only [lift.principalSeg_coe] using h)
+ have := liftPrincipalSeg.mem_range_of_rel_top (by simpa only [liftPrincipalSeg_coe] using h)
rcases this with ⟨o, h'⟩
- rw [← h', lift.principalSeg_coe, ← lift_card]
+ rw [← h', liftPrincipalSeg_coe, ← lift_card]
apply lift_lt_univ'
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' lift.principalSeg.{u, u + 1}.down.1 (by simpa only [lift.principalSeg_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, lift.principalSeg_coe, ← lift_card] at this
- exact ⟨_, this.symm⟩, fun ⟨c', e⟩ => e.symm ▸ lift_lt_univ _⟩
+ rw [← e, liftPrincipalSeg_coe, ← lift_card] at this
+ 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
@@ -1435,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 6753d1d6c71f1..57fe4e7e7b0e4 100644
--- a/Mathlib/SetTheory/Ordinal/Exponential.lean
+++ b/Mathlib/SetTheory/Ordinal/Exponential.lean
@@ -86,35 +86,52 @@ theorem opow_pos {a : Ordinal} (b : Ordinal) (a0 : 0 < a) : 0 < a ^ b := by
theorem opow_ne_zero {a : Ordinal} (b : Ordinal) (a0 : a ≠ 0) : a ^ b ≠ 0 :=
Ordinal.pos_iff_ne_zero.1 <| opow_pos b <| Ordinal.pos_iff_ne_zero.2 a0
+@[simp]
+theorem opow_eq_zero {a b : Ordinal} : a ^ b = 0 ↔ a = 0 ∧ b ≠ 0 := by
+ obtain rfl | ha := eq_or_ne a 0
+ · obtain rfl | hb := eq_or_ne b 0
+ · simp
+ · simp [hb]
+ · simp [opow_ne_zero b ha, ha]
+
@[simp, norm_cast]
theorem opow_natCast (a : Ordinal) (n : ℕ) : a ^ (n : Ordinal) = a ^ n := by
induction n with
| 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₁
@@ -140,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
@@ -150,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).self_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]
@@ -174,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]
@@ -211,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 :=
@@ -261,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
@@ -286,17 +325,67 @@ theorem opow_log_le_self (b : Ordinal) {x : Ordinal} (hx : x ≠ 0) : b ^ log b
rwa [← succ_log_def hb hx] at this
· rwa [one_opow, one_le_iff_ne_zero]
-/-- `opow b` and `log b` (almost) form a Galois connection. -/
-theorem opow_le_iff_le_log {b x c : Ordinal} (hb : 1 < b) (hx : x ≠ 0) : b ^ c ≤ x ↔ c ≤ log b x :=
- ⟨fun h =>
- le_of_not_lt fun hn =>
- (lt_opow_succ_log_self hb x).not_le <|
- ((opow_le_opow_iff_right hb).2 (succ_le_of_lt hn)).trans h,
- fun h => ((opow_le_opow_iff_right hb).2 h).trans (opow_log_le_self b hx)⟩
-
+/-- `opow b` and `log b` (almost) form a Galois connection.
+
+See `opow_le_iff_le_log'` for a variant assuming `c ≠ 0` rather than `x ≠ 0`. See also
+`le_log_of_opow_le` and `opow_le_of_le_log`, which are both separate implications under weaker
+assumptions. -/
+theorem opow_le_iff_le_log {b x c : Ordinal} (hb : 1 < b) (hx : x ≠ 0) :
+ b ^ c ≤ x ↔ c ≤ log b x := by
+ constructor <;>
+ intro h
+ · apply le_of_not_lt
+ intro hn
+ apply (lt_opow_succ_log_self hb x).not_le <|
+ ((opow_le_opow_iff_right hb).2 <| succ_le_of_lt hn).trans h
+ · exact ((opow_le_opow_iff_right hb).2 h).trans <| opow_log_le_self b hx
+
+/-- `opow b` and `log b` (almost) form a Galois connection.
+
+See `opow_le_iff_le_log` for a variant assuming `x ≠ 0` rather than `c ≠ 0`. See also
+`le_log_of_opow_le` and `opow_le_of_le_log`, which are both separate implications under weaker
+assumptions. -/
+theorem opow_le_iff_le_log' {b x c : Ordinal} (hb : 1 < b) (hc : c ≠ 0) :
+ b ^ c ≤ x ↔ c ≤ log b x := by
+ obtain rfl | hx := eq_or_ne x 0
+ · rw [log_zero_right, Ordinal.le_zero, Ordinal.le_zero, opow_eq_zero]
+ simp [hc, (zero_lt_one.trans hb).ne']
+ · exact opow_le_iff_le_log hb hx
+
+theorem le_log_of_opow_le {b x c : Ordinal} (hb : 1 < b) (h : b ^ c ≤ x) : c ≤ log b x := by
+ obtain rfl | hx := eq_or_ne x 0
+ · rw [Ordinal.le_zero, opow_eq_zero] at h
+ exact (zero_lt_one.asymm <| h.1 ▸ hb).elim
+ · exact (opow_le_iff_le_log hb hx).1 h
+
+theorem opow_le_of_le_log {b x c : Ordinal} (hc : c ≠ 0) (h : c ≤ log b x) : b ^ c ≤ x := by
+ obtain hb | hb := le_or_lt b 1
+ · rw [log_of_left_le_one hb] at h
+ exact (h.not_lt (Ordinal.pos_iff_ne_zero.2 hc)).elim
+ · rwa [opow_le_iff_le_log' hb hc]
+
+/-- `opow b` and `log b` (almost) form a Galois connection.
+
+See `lt_opow_iff_log_lt'` for a variant assuming `c ≠ 0` rather than `x ≠ 0`. See also
+`lt_opow_of_log_lt` and `lt_log_of_lt_opow`, which are both separate implications under weaker
+assumptions. -/
theorem lt_opow_iff_log_lt {b x c : Ordinal} (hb : 1 < b) (hx : x ≠ 0) : x < b ^ c ↔ log b x < c :=
lt_iff_lt_of_le_iff_le (opow_le_iff_le_log hb hx)
+/-- `opow b` and `log b` (almost) form a Galois connection.
+
+See `lt_opow_iff_log_lt` for a variant assuming `x ≠ 0` rather than `c ≠ 0`. See also
+`lt_opow_of_log_lt` and `lt_log_of_lt_opow`, which are both separate implications under weaker
+assumptions. -/
+theorem lt_opow_iff_log_lt' {b x c : Ordinal} (hb : 1 < b) (hc : c ≠ 0) : x < b ^ c ↔ log b x < c :=
+ lt_iff_lt_of_le_iff_le (opow_le_iff_le_log' hb hc)
+
+theorem lt_opow_of_log_lt {b x c : Ordinal} (hb : 1 < b) : log b x < c → x < b ^ c :=
+ lt_imp_lt_of_le_imp_le <| le_log_of_opow_le hb
+
+theorem lt_log_of_lt_opow {b x c : Ordinal} (hc : c ≠ 0) : x < b ^ c → log b x < c :=
+ lt_imp_lt_of_le_imp_le <| opow_le_of_le_log hc
+
theorem log_pos {b o : Ordinal} (hb : 1 < b) (ho : o ≠ 0) (hbo : b ≤ o) : 0 < log b o := by
rwa [← succ_le_iff, succ_zero, ← opow_le_iff_le_log hb ho, opow_one]
@@ -310,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)
@@ -386,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` -/
@@ -400,13 +514,20 @@ theorem natCast_opow (m : ℕ) : ∀ n : ℕ, ↑(m ^ n : ℕ) = (m : Ordinal) ^
| n + 1 => by
rw [pow_succ, natCast_mul, natCast_opow m n, Nat.cast_succ, add_one_eq_succ, opow_succ]
-@[deprecated (since := "2024-04-17")]
-alias nat_cast_opow := natCast_opow
+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 (isNormal_opow ho₁).apply_omega0
+ · rw [one_opow]
+ refine le_antisymm (Ordinal.iSup_le fun n => by rw [one_opow]) ?_
+ 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_omega
+ · 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 c7a4b2b31ea32..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
/-!
@@ -21,8 +21,8 @@ Moreover, we prove some lemmas about the fixed points of specific normal functio
* `nfpFamily`, `nfpBFamily`, `nfp`: the next fixed point of a (family of) normal function(s).
* `fp_family_unbounded`, `fp_bfamily_unbounded`, `fp_unbounded`: the (common) fixed points of a
(family of) normal function(s) are unbounded in the ordinals.
-* `deriv_add_eq_mul_omega_add`: a characterization of the derivative of addition.
-* `deriv_mul_eq_opow_omega_mul`: a characterization of the derivative of multiplication.
+* `deriv_add_eq_mul_omega0_add`: a characterization of the derivative of addition.
+* `deriv_mul_eq_opow_omega0_mul`: a characterization of the derivative of multiplication.
-/
@@ -48,44 +48,48 @@ finitely many functions in the family to `a`.
`Ordinal.nfpFamily_fp` shows this is a fixed point, `Ordinal.le_nfpFamily` shows it's at
least `a`, and `Ordinal.nfpFamily_le_fp` shows this is the least ordinal with these properties. -/
-def nfpFamily (f : ι → Ordinal → Ordinal) (a : Ordinal) : Ordinal :=
- sup (List.foldr f a)
+def nfpFamily (f : ι → Ordinal.{max u v} → Ordinal.{max u v}) (a : Ordinal.{max u v}) : Ordinal :=
+ ⨆ i, List.foldr f a i
theorem nfpFamily_eq_sup (f : ι → Ordinal.{max u v} → Ordinal.{max u v}) (a : Ordinal.{max u v}) :
- nfpFamily.{u, v} f a = sup.{u, v} (List.foldr f a) :=
+ nfpFamily.{u, v} f a = ⨆ i, List.foldr f a i :=
rfl
theorem foldr_le_nfpFamily (f : ι → Ordinal → Ordinal)
(a l) : List.foldr f a l ≤ nfpFamily.{u, v} f a :=
- le_sup.{u, v} _ _
+ Ordinal.le_iSup _ _
theorem le_nfpFamily (f : ι → Ordinal → Ordinal) (a) : a ≤ nfpFamily f a :=
- le_sup _ []
+ 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 :=
- lt_sup.{u, v}
+ Ordinal.lt_iSup
theorem nfpFamily_le_iff {a b} : nfpFamily.{u, v} f a ≤ b ↔ ∀ l, List.foldr f a l ≤ b :=
- sup_le_iff
+ Ordinal.iSup_le_iff
theorem nfpFamily_le {a b} : (∀ l, List.foldr f a l ≤ b) → nfpFamily.{u, v} f a ≤ b :=
- sup_le.{u, v}
+ Ordinal.iSup_le
-theorem nfpFamily_monotone (hf : ∀ i, Monotone (f i)) : Monotone (nfpFamily.{u, v} f) :=
- fun _ _ h => sup_le.{u, v} fun l => (List.foldr_monotone hf l h).trans (le_sup.{u, v} _ l)
+theorem nfpFamily_monotone (hf : ∀ i, Monotone (f i)) : Monotone (nfpFamily.{u, v} f) := by
+ intro _ _ h
+ apply Ordinal.iSup_le
+ intro l
+ exact (List.foldr_monotone hf l h).trans (Ordinal.le_iSup _ l)
theorem apply_lt_nfpFamily (H : ∀ i, IsNormal (f i)) {a b} (hb : b < nfpFamily.{u, v} f a) (i) :
f i b < nfpFamily.{u, v} f a :=
let ⟨l, hl⟩ := lt_nfpFamily.1 hb
- lt_sup.2 ⟨i::l, (H i).strictMono hl⟩
+ Ordinal.lt_iSup.2 ⟨i::l, (H i).strictMono hl⟩
theorem apply_lt_nfpFamily_iff [Nonempty ι] (H : ∀ i, IsNormal (f i)) {a b} :
- (∀ i, f i b < nfpFamily.{u, v} f a) ↔ b < nfpFamily.{u, v} f a :=
- ⟨fun h =>
- lt_nfpFamily.2 <|
- let ⟨l, hl⟩ := lt_sup.1 <| h <| Classical.arbitrary ι
- ⟨l, ((H _).self_le b).trans_lt hl⟩,
- apply_lt_nfpFamily H⟩
+ (∀ i, f i b < nfpFamily.{u, v} f a) ↔ b < nfpFamily.{u, v} f a := by
+ constructor
+ · intro h
+ exact lt_nfpFamily.2 <|
+ let ⟨l, hl⟩ := Ordinal.lt_iSup.1 <| h <| Classical.arbitrary ι
+ ⟨l, (H _).le_apply.trans_lt hl⟩
+ · exact apply_lt_nfpFamily H
theorem nfpFamily_le_apply [Nonempty ι] (H : ∀ i, IsNormal (f i)) {a b} :
(∃ i, nfpFamily.{u, v} f a ≤ f i b) ↔ nfpFamily.{u, v} f a ≤ b := by
@@ -94,37 +98,45 @@ theorem nfpFamily_le_apply [Nonempty ι] (H : ∀ i, IsNormal (f i)) {a b} :
exact apply_lt_nfpFamily_iff H
theorem nfpFamily_le_fp (H : ∀ i, Monotone (f i)) {a b} (ab : a ≤ b) (h : ∀ i, f i b ≤ b) :
- nfpFamily.{u, v} f a ≤ b :=
- sup_le fun l => by
- by_cases hι : IsEmpty ι
- · rwa [Unique.eq_default l]
- · induction' l with i l IH generalizing a
- · exact ab
- exact (H i (IH ab)).trans (h i)
+ nfpFamily.{u, v} f a ≤ b := by
+ apply Ordinal.iSup_le
+ intro l
+ induction' l with i l IH generalizing a
+ · exact ab
+ · exact (H i (IH ab)).trans (h i)
theorem nfpFamily_fp {i} (H : IsNormal (f i)) (a) :
f i (nfpFamily.{u, v} f a) = nfpFamily.{u, v} f a := by
- unfold nfpFamily
- rw [@IsNormal.sup.{u, v, v} _ H _ _ ⟨[]⟩]
- apply le_antisymm <;> refine Ordinal.sup_le fun l => ?_
- · exact le_sup _ (i::l)
- · exact (H.self_le _).trans (le_sup _ _)
+ rw [nfpFamily, H.map_iSup]
+ apply le_antisymm <;> refine Ordinal.iSup_le fun l => ?_
+ · exact Ordinal.le_iSup _ (i::l)
+ · exact H.le_apply.trans (Ordinal.le_iSup _ _)
theorem apply_le_nfpFamily [hι : Nonempty ι] {f : ι → Ordinal → Ordinal} (H : ∀ i, IsNormal (f i))
{a b} : (∀ i, f i b ≤ nfpFamily.{u, v} f a) ↔ b ≤ nfpFamily.{u, v} f a := by
refine ⟨fun h => ?_, fun h i => ?_⟩
· cases' hι with i
- exact ((H i).self_le b).trans (h i)
+ exact (H i).le_apply.trans (h i)
rw [← nfpFamily_fp (H i)]
exact (H i).monotone h
theorem nfpFamily_eq_self {f : ι → Ordinal → Ordinal} {a} (h : ∀ i, f i a = a) :
- nfpFamily f a = a :=
- le_antisymm (sup_le fun l => by rw [List.foldr_fixed' h l]) <| le_nfpFamily f a
+ nfpFamily f a = a := by
+ apply (Ordinal.iSup_le ?_).antisymm (le_nfpFamily f a)
+ intro l
+ rw [List.foldr_fixed' h l]
-- 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
@@ -153,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
@@ -173,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 _).self_le _)
+ this a (isNormal_derivFamily _).le_apply
intro o
induction' o using limitRecOn with o IH o l IH
· intro h₁
@@ -193,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 :=
@@ -202,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⟩
@@ -234,23 +249,23 @@ theorem nfpBFamily_eq_nfpFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordina
theorem foldr_le_nfpBFamily {o : Ordinal}
(f : ∀ b < o, Ordinal → Ordinal) (a l) :
List.foldr (familyOfBFamily o f) a l ≤ nfpBFamily.{u, v} o f a :=
- le_sup.{u, v} _ _
+ Ordinal.le_iSup _ _
theorem le_nfpBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) (a) :
a ≤ nfpBFamily.{u, v} o f a :=
- le_sup.{u, v} _ []
+ 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 :=
- lt_sup.{u, v}
+ Ordinal.lt_iSup
theorem nfpBFamily_le_iff {o : Ordinal} {f : ∀ b < o, Ordinal → Ordinal} {a b} :
nfpBFamily.{u, v} o f a ≤ b ↔ ∀ l, List.foldr (familyOfBFamily o f) a l ≤ b :=
- sup_le_iff.{u, v}
+ Ordinal.iSup_le_iff
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 :=
- sup_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 _ _
@@ -288,7 +303,7 @@ theorem apply_le_nfpBFamily (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a
(∀ i hi, f i hi b ≤ nfpBFamily.{u, v} o f a) ↔ b ≤ nfpBFamily.{u, v} o f a := by
refine ⟨fun h => ?_, fun h i hi => ?_⟩
· have ho' : 0 < o := Ordinal.pos_iff_ne_zero.2 ho
- exact ((H 0 ho').self_le b).trans (h 0 ho')
+ exact (H 0 ho').le_apply.trans (h 0 ho')
· rw [← nfpBFamily_fp (H i hi)]
exact (H i hi).monotone h
@@ -297,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
@@ -313,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
@@ -343,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
@@ -368,6 +396,20 @@ def nfp (f : Ordinal → Ordinal) : Ordinal → Ordinal :=
theorem nfp_eq_nfpFamily (f : Ordinal → Ordinal) : nfp f = nfpFamily fun _ : Unit => f :=
rfl
+theorem iSup_iterate_eq_nfp (f : Ordinal.{u} → Ordinal.{u}) (a : Ordinal.{u}) :
+ ⨆ n : ℕ, f^[n] a = nfp f a := by
+ apply le_antisymm
+ · rw [Ordinal.iSup_le_iff]
+ intro n
+ rw [← List.length_replicate n Unit.unit, ← List.foldr_const f a]
+ exact Ordinal.le_iSup _ _
+ · apply Ordinal.iSup_le
+ intro l
+ rw [List.foldr_const f a l]
+ exact Ordinal.le_iSup _ _
+
+set_option linter.deprecated false in
+@[deprecated (since := "2024-08-27")]
theorem sup_iterate_eq_nfp (f : Ordinal.{u} → Ordinal.{u}) (a : Ordinal.{u}) :
(sup fun n : ℕ => f^[n] a) = nfp f a := by
refine le_antisymm ?_ (sup_le fun l => ?_)
@@ -379,28 +421,28 @@ theorem sup_iterate_eq_nfp (f : Ordinal.{u} → Ordinal.{u}) (a : Ordinal.{u}) :
exact le_sup _ _
theorem iterate_le_nfp (f a n) : f^[n] a ≤ nfp f a := by
- rw [← sup_iterate_eq_nfp]
- exact le_sup _ n
+ rw [← iSup_iterate_eq_nfp]
+ 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
theorem lt_nfp {a b} : a < nfp f b ↔ ∃ n, a < f^[n] b := by
- rw [← sup_iterate_eq_nfp]
- exact lt_sup
+ rw [← iSup_iterate_eq_nfp]
+ exact Ordinal.lt_iSup
theorem nfp_le_iff {a b} : nfp f a ≤ b ↔ ∀ n, f^[n] a ≤ b := by
- rw [← sup_iterate_eq_nfp]
- exact sup_le_iff
+ rw [← iSup_iterate_eq_nfp]
+ exact Ordinal.iSup_le_iff
theorem nfp_le {a b} : (∀ n, f^[n] a ≤ b) → nfp f a ≤ b :=
nfp_le_iff.2
@[simp]
-theorem nfp_id : nfp id = id :=
- funext fun a => by
- simp_rw [← sup_iterate_eq_nfp, iterate_id]
- exact sup_const a
+theorem nfp_id : nfp id = id := by
+ ext
+ simp_rw [← iSup_iterate_eq_nfp, iterate_id]
+ exact ciSup_const
theorem nfp_monotone (hf : Monotone f) : Monotone (nfp f) :=
nfpFamily_monotone fun _ => hf
@@ -420,13 +462,21 @@ theorem IsNormal.nfp_fp {f} (H : IsNormal f) : ∀ a, f (nfp f a) = nfp f a :=
@nfpFamily_fp Unit (fun _ => f) Unit.unit H
theorem IsNormal.apply_le_nfp {f} (H : IsNormal f) {a b} : f b ≤ nfp f a ↔ b ≤ nfp f a :=
- ⟨le_trans (H.self_le _), fun h => by simpa only [H.nfp_fp] using H.le_iff.2 h⟩
+ ⟨H.le_apply.trans, fun h => by simpa only [H.nfp_fp] using H.le_iff.2 h⟩
theorem nfp_eq_self {f : Ordinal → Ordinal} {a} (h : f a = a) : nfp f a = a :=
nfpFamily_eq_self fun _ => h
/-- 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
@@ -451,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
@@ -474,11 +527,12 @@ 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 [← sup_iterate_eq_nfp]
- apply (sup_le fun n => ?_).antisymm (le_sup (fun n => 0^[n] a) 0)
+ rw [← iSup_iterate_eq_nfp]
+ apply (Ordinal.iSup_le ?_).antisymm (Ordinal.le_iSup _ 0)
+ intro n
induction' n with n _
· rfl
· rw [Function.iterate_succ']
@@ -502,47 +556,59 @@ end
/-! ### Fixed points of addition -/
@[simp]
-theorem nfp_add_zero (a) : nfp (a + ·) 0 = a * omega := by
- simp_rw [← sup_iterate_eq_nfp, ← sup_mul_nat]
+theorem nfp_add_zero (a) : nfp (a + ·) 0 = a * ω := by
+ simp_rw [← iSup_iterate_eq_nfp, ← iSup_mul_nat]
congr; funext n
induction' n with n hn
· rw [Nat.cast_zero, mul_zero, iterate_zero_apply]
· rw [iterate_succ_apply', Nat.add_comm, Nat.cast_add, Nat.cast_one, mul_one_add, hn]
-theorem nfp_add_eq_mul_omega {a b} (hba : b ≤ a * omega) : nfp (a + ·) b = a * omega := by
- apply le_antisymm (nfp_le_fp (add_isNormal a).monotone hba _)
+theorem nfp_add_eq_mul_omega0 {a b} (hba : b ≤ a * ω) : nfp (a + ·) b = a * ω := by
+ 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)
- · dsimp; rw [← mul_one_add, one_add_omega]
+ 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")]
+alias nfp_add_eq_mul_omega := nfp_add_eq_mul_omega0
-theorem add_eq_right_iff_mul_omega_le {a b : Ordinal} : a + b = b ↔ a * omega ≤ b := by
+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_omega]
+ rwa [← add_assoc, ← mul_one_add, one_add_omega0]
-theorem add_le_right_iff_mul_omega_le {a b : Ordinal} : a + b ≤ b ↔ a * omega ≤ b := by
- rw [← add_eq_right_iff_mul_omega_le]
- exact (add_isNormal a).le_iff_eq
+@[deprecated (since := "2024-09-30")]
+alias add_eq_right_iff_mul_omega_le := add_eq_right_iff_mul_omega0_le
-theorem deriv_add_eq_mul_omega_add (a b : Ordinal.{u}) : deriv (a + ·) b = a * omega + b := by
+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 (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
· rw [deriv_succ, h, add_succ]
- exact nfp_eq_self (add_eq_right_iff_mul_omega_le.2 ((le_add_right _ _).trans (le_succ _)))
+ exact nfp_eq_self (add_eq_right_iff_mul_omega0_le.2 ((le_add_right _ _).trans (le_succ _)))
+
+@[deprecated (since := "2024-09-30")]
+alias deriv_add_eq_mul_omega_add := deriv_add_eq_mul_omega0_add
/-! ### Fixed points of multiplication -/
@[simp]
-theorem nfp_mul_one {a : Ordinal} (ha : 0 < a) : nfp (a * ·) 1 = (a^omega) := by
- rw [← sup_iterate_eq_nfp, ← sup_opow_nat ha]
+theorem nfp_mul_one {a : Ordinal} (ha : 0 < a) : nfp (a * ·) 1 = (a ^ ω) := by
+ rw [← iSup_iterate_eq_nfp, ← iSup_pow ha]
congr
funext n
induction' n with n hn
@@ -556,74 +622,92 @@ theorem nfp_mul_zero (a : Ordinal) : nfp (a * ·) 0 = 0 := by
induction' n with n hn; · rfl
dsimp only; rwa [iterate_succ_apply, mul_zero]
-theorem nfp_mul_eq_opow_omega {a b : Ordinal} (hb : 0 < b) (hba : b ≤ (a^omega)) :
- nfp (a * ·) b = (a^omega.{u}) := by
+theorem nfp_mul_eq_opow_omega0 {a b : Ordinal} (hb : 0 < b) (hba : b ≤ (a ^ ω)) :
+ nfp (a * ·) b = (a ^ (ω : Ordinal.{u})) := by
rcases eq_zero_or_pos a with ha | ha
- · rw [ha, zero_opow omega_ne_zero] at hba ⊢
+ · rw [ha, zero_opow omega0_ne_zero] at hba ⊢
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
- rw [← opow_one_add, one_add_omega]
+ · 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)
-theorem eq_zero_or_opow_omega_le_of_mul_eq_right {a b : Ordinal} (hab : a * b = b) :
- b = 0 ∨ (a^omega.{u}) ≤ b := by
+@[deprecated (since := "2024-09-30")]
+alias nfp_mul_eq_opow_omega := nfp_mul_eq_opow_omega0
+
+theorem eq_zero_or_opow_omega0_le_of_mul_eq_right {a b : Ordinal} (hab : a * b = b) :
+ b = 0 ∨ (a ^ (ω : Ordinal.{u})) ≤ b := by
rcases eq_zero_or_pos a with ha | ha
- · rw [ha, zero_opow omega_ne_zero]
+ · rw [ha, zero_opow omega0_ne_zero]
exact Or.inr (Ordinal.zero_le b)
rw [or_iff_not_imp_left]
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
-theorem mul_eq_right_iff_opow_omega_dvd {a b : Ordinal} : a * b = b ↔ (a^omega) ∣ b := by
+theorem mul_eq_right_iff_opow_omega0_dvd {a b : Ordinal} : a * b = b ↔ (a ^ ω) ∣ b := by
rcases eq_zero_or_pos a with ha | ha
- · rw [ha, zero_mul, zero_opow omega_ne_zero, zero_dvd_iff]
+ · rw [ha, zero_mul, zero_opow omega0_ne_zero, zero_dvd_iff]
exact eq_comm
refine ⟨fun hab => ?_, fun h => ?_⟩
· rw [dvd_iff_mod_eq_zero]
- rw [← div_add_mod b (a^omega), mul_add, ← mul_assoc, ← opow_one_add, one_add_omega,
+ rw [← div_add_mod b (a ^ ω), mul_add, ← mul_assoc, ← opow_one_add, one_add_omega0,
add_left_cancel] at hab
- cases' eq_zero_or_opow_omega_le_of_mul_eq_right hab with hab hab
+ cases' eq_zero_or_opow_omega0_le_of_mul_eq_right hab with hab hab
· exact hab
- refine (not_lt_of_le hab (mod_lt b (opow_ne_zero omega ?_))).elim
+ refine (not_lt_of_le hab (mod_lt b (opow_ne_zero ω ?_))).elim
rwa [← Ordinal.pos_iff_ne_zero]
cases' h with c hc
- rw [hc, ← mul_assoc, ← opow_one_add, one_add_omega]
+ rw [hc, ← mul_assoc, ← opow_one_add, one_add_omega0]
+
+@[deprecated (since := "2024-09-30")]
+alias mul_eq_right_iff_opow_omega_dvd := mul_eq_right_iff_opow_omega0_dvd
-theorem mul_le_right_iff_opow_omega_dvd {a b : Ordinal} (ha : 0 < a) :
- a * b ≤ b ↔ (a^omega) ∣ b := by
- rw [← mul_eq_right_iff_opow_omega_dvd]
- exact (mul_isNormal ha).le_iff_eq
+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 (isNormal_mul_right ha).le_iff_eq
-theorem nfp_mul_opow_omega_add {a c : Ordinal} (b) (ha : 0 < a) (hc : 0 < c) (hca : c ≤ (a^omega)) :
- nfp (a * ·) ((a^omega) * b + c) = (a^omega.{u}) * succ b := by
+@[deprecated (since := "2024-09-30")]
+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_omega]
- · cases' mul_eq_right_iff_opow_omega_dvd.1 ((mul_isNormal ha).nfp_fp ((a^omega) * b + c)) with
- d hd
+ · dsimp only; rw [← mul_assoc, ← opow_one_add, one_add_omega0]
+ · 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 (Mul.mul a) ((a^omega) * b + c)
- erw [hd] at this
- have := (add_lt_add_left hc ((a^omega) * b)).trans_le this
- rw [add_zero, mul_lt_mul_iff_left (opow_pos omega ha)] at this
+ have := le_nfp (a * ·) (a ^ ω * b + c)
+ 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]
-theorem deriv_mul_eq_opow_omega_mul {a : Ordinal.{u}} (ha : 0 < a) (b) :
- deriv (a * ·) b = (a^omega) * b := by
+@[deprecated (since := "2024-09-30")]
+alias nfp_mul_opow_omega_add := nfp_mul_opow_omega0_add
+
+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 omega 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]
- exact nfp_mul_opow_omega_add c ha zero_lt_one (one_le_iff_pos.2 (opow_pos _ ha))
+ exact nfp_mul_opow_omega0_add c ha zero_lt_one (one_le_iff_pos.2 (opow_pos _ ha))
+
+@[deprecated (since := "2024-09-30")]
+alias deriv_mul_eq_opow_omega_mul := deriv_mul_eq_opow_omega0_mul
end Ordinal
diff --git a/Mathlib/SetTheory/Ordinal/FixedPointApproximants.lean b/Mathlib/SetTheory/Ordinal/FixedPointApproximants.lean
index 7cb80b64b2db5..97272de665f4f 100644
--- a/Mathlib/SetTheory/Ordinal/FixedPointApproximants.lean
+++ b/Mathlib/SetTheory/Ordinal/FixedPointApproximants.lean
@@ -8,7 +8,7 @@ import Mathlib.SetTheory.Ordinal.Arithmetic
/-!
# Ordinal Approximants for the Fixed points on complete lattices
-This file sets up the ordinal approximation theory of fixed points
+This file sets up the ordinal-indexed approximation theory of fixed points
of a monotone function in a complete lattice [Cousot1979].
The proof follows loosely the one from [Echenique2005].
@@ -17,15 +17,15 @@ ordinals from mathlib. It still allows an approximation scheme indexed over the
## Main definitions
-* `OrdinalApprox.lfpApprox`: The ordinal approximation of the least fixed point
- greater or equal then an initial value of a bundled monotone function.
-* `OrdinalApprox.gfpApprox`: The ordinal approximation of the greatest fixed point
- less or equal then an initial value of a bundled monotone function.
+* `OrdinalApprox.lfpApprox`: The ordinal-indexed approximation of the least fixed point
+ greater or equal than an initial value of a bundled monotone function.
+* `OrdinalApprox.gfpApprox`: The ordinal-indexed approximation of the greatest fixed point
+ less or equal than an initial value of a bundled monotone function.
## Main theorems
-* `OrdinalApprox.lfp_mem_range_lfpApprox`: The approximation of
+* `OrdinalApprox.lfp_mem_range_lfpApprox`: The ordinal-indexed approximation of
the least fixed point eventually reaches the least fixed point
-* `OrdinalApprox.gfp_mem_range_gfpApprox`: The approximation of
+* `OrdinalApprox.gfp_mem_range_gfpApprox`: The ordinal-indexed approximation of
the greatest fixed point eventually reaches the greatest fixed point
## References
@@ -50,12 +50,10 @@ theorem not_injective_limitation_set : ¬ InjOn g (Iio (ord <| succ #α)) := by
have h := lift_mk_le_lift_mk_of_injective <| injOn_iff_injective.1 h_inj
have mk_initialSeg_subtype :
#(Iio (ord <| succ #α)) = lift.{u + 1} (succ #α) := by
- simpa only [coe_setOf, card_typein, card_ord] using mk_initialSeg (ord <| succ #α)
+ simpa only [coe_setOf, card_typein, card_ord] using mk_Iio_ordinal (ord <| succ #α)
rw [mk_initialSeg_subtype, lift_lift, lift_le] at h
exact not_le_of_lt (Order.lt_succ #α) h
-
-
end Cardinal
namespace OrdinalApprox
@@ -67,14 +65,17 @@ variable [CompleteLattice α] (f : α →o α) (x : α)
open Function fixedPoints Cardinal Order OrderHom
set_option linter.unusedVariables false in
-/-- Ordinal approximants of the least fixed point greater then an initial value x -/
+/-- The ordinal-indexed sequence approximating the least fixed point greater than
+an initial value `x`. It is defined in such a way that we have `lfpApprox 0 x = x` and
+`lfpApprox a x = ⨆ b < a, f (lfpApprox b x)`. -/
def lfpApprox (a : Ordinal.{u}) : α :=
sSup ({ f (lfpApprox b) | (b : Ordinal) (h : b < a) } ∪ {x})
termination_by a
decreasing_by exact h
theorem lfpApprox_monotone : Monotone (lfpApprox f x) := by
- unfold Monotone; intros a b h; unfold lfpApprox
+ intros a b h
+ rw [lfpApprox, lfpApprox]
refine sSup_le_sSup ?h
apply sup_le_sup_right
simp only [exists_prop, Set.le_eq_subset, Set.setOf_subset_setOf, forall_exists_index, and_imp,
@@ -84,14 +85,14 @@ theorem lfpApprox_monotone : Monotone (lfpApprox f x) := by
exact ⟨lt_of_lt_of_le h' h, rfl⟩
theorem le_lfpApprox {a : Ordinal} : x ≤ lfpApprox f x a := by
- unfold lfpApprox
+ rw [lfpApprox]
apply le_sSup
simp only [exists_prop, Set.union_singleton, Set.mem_insert_iff, Set.mem_setOf_eq, true_or]
theorem lfpApprox_add_one (h : x ≤ f x) (a : Ordinal) :
lfpApprox f x (a+1) = f (lfpApprox f x a) := by
apply le_antisymm
- · conv => left; unfold lfpApprox
+ · conv => left; rw [lfpApprox]
apply sSup_le
simp only [Ordinal.add_one_eq_succ, lt_succ_iff, exists_prop, Set.union_singleton,
Set.mem_insert_iff, Set.mem_setOf_eq, forall_eq_or_imp, forall_exists_index, and_imp,
@@ -102,7 +103,7 @@ theorem lfpApprox_add_one (h : x ≤ f x) (a : Ordinal) :
exact le_lfpApprox f x
· intros a' h
apply f.2; apply lfpApprox_monotone; exact h
- · conv => right; unfold lfpApprox
+ · conv => right; rw [lfpApprox]
apply le_sSup
simp only [Ordinal.add_one_eq_succ, lt_succ_iff, exists_prop]
rw [Set.mem_union]
@@ -110,14 +111,46 @@ theorem lfpApprox_add_one (h : x ≤ f x) (a : Ordinal) :
simp only [Set.mem_setOf_eq]
use a
-/-- The ordinal approximants of the least fixed point are stabilizing
- when reaching a fixed point of f -/
+theorem lfpApprox_mono_left : Monotone (lfpApprox : (α →o α) → _) := by
+ intro f g h x a
+ induction a using Ordinal.induction with
+ | h i ih =>
+ rw [lfpApprox, lfpApprox]
+ apply sSup_le
+ simp only [exists_prop, Set.union_singleton, Set.mem_insert_iff, Set.mem_setOf_eq, sSup_insert,
+ forall_eq_or_imp, le_sup_left, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂,
+ true_and]
+ intro i' h_lt
+ apply le_sup_of_le_right
+ apply le_sSup_of_le
+ · use i'
+ · apply le_trans (h _)
+ simp only [OrderHom.toFun_eq_coe]
+ exact g.monotone (ih i' h_lt)
+
+theorem lfpApprox_mono_mid : Monotone (lfpApprox f) := by
+ intro x₁ x₂ h a
+ induction a using Ordinal.induction with
+ | h i ih =>
+ rw [lfpApprox, lfpApprox]
+ apply sSup_le
+ simp only [exists_prop, Set.union_singleton, Set.mem_insert_iff, Set.mem_setOf_eq, sSup_insert,
+ forall_eq_or_imp, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
+ constructor
+ · exact le_sup_of_le_left h
+ · intro i' h_i'
+ apply le_sup_of_le_right
+ apply le_sSup_of_le
+ · use i'
+ · exact f.monotone (ih i' h_i')
+
+/-- The approximations of the least fixed point stabilize at a fixed point of `f` -/
theorem lfpApprox_eq_of_mem_fixedPoints {a b : Ordinal} (h_init : x ≤ f x) (h_ab : a ≤ b)
(h : lfpApprox f x a ∈ fixedPoints f) : lfpApprox f x b = lfpApprox f x a := by
rw [mem_fixedPoints_iff] at h
induction b using Ordinal.induction with | h b IH =>
apply le_antisymm
- · conv => left; unfold lfpApprox
+ · conv => left; rw [lfpApprox]
apply sSup_le
simp only [exists_prop, Set.union_singleton, Set.mem_insert_iff, Set.mem_setOf_eq,
forall_eq_or_imp, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
@@ -131,8 +164,8 @@ theorem lfpApprox_eq_of_mem_fixedPoints {a b : Ordinal} (h_init : x ≤ f x) (h_
· rw [IH a' ha'b (le_of_not_lt haa), h]
· exact lfpApprox_monotone f x h_ab
-/-- There are distinct ordinals smaller than the successor of the domains cardinals
- with equal value -/
+/-- There are distinct indices smaller than the successor of the domain's cardinality
+yielding the same value -/
theorem exists_lfpApprox_eq_lfpApprox : ∃ a < ord <| succ #α, ∃ b < ord <| succ #α,
a ≠ b ∧ lfpApprox f x a = lfpApprox f x b := by
have h_ninj := not_injective_limitation_set <| lfpApprox f x
@@ -144,8 +177,8 @@ theorem exists_lfpApprox_eq_lfpApprox : ∃ a < ord <| succ #α, ∃ b < ord <|
· intro h_eq; rw [Subtype.coe_inj] at h_eq; exact h_nab h_eq
· exact h_fab
-/-- If there are distinct ordinals with equal value then
- every value succeeding the smaller ordinal are fixed points -/
+/-- If the sequence of ordinal-indexed approximations takes a value twice,
+then it actually stabilised at that value. -/
lemma lfpApprox_mem_fixedPoints_of_eq {a b c : Ordinal}
(h_init : x ≤ f x) (h_ab : a < b) (h_ac : a ≤ c) (h_fab : lfpApprox f x a = lfpApprox f x b) :
lfpApprox f x c ∈ fixedPoints f := by
@@ -159,7 +192,7 @@ lemma lfpApprox_mem_fixedPoints_of_eq {a b c : Ordinal}
· exact h_ac
· exact lfpApprox_mem_fixedPoint
-/-- A fixed point of f is reached after the successor of the domains cardinality -/
+/-- The approximation at the index of the successor of the domain's cardinality is a fixed point -/
theorem lfpApprox_ord_mem_fixedPoint (h_init : x ≤ f x) :
lfpApprox f x (ord <| succ #α) ∈ fixedPoints f := by
let ⟨a, h_a, b, h_b, h_nab, h_fab⟩ := exists_lfpApprox_eq_lfpApprox f x
@@ -171,13 +204,13 @@ theorem lfpApprox_ord_mem_fixedPoint (h_init : x ≤ f x) :
exact lfpApprox_mem_fixedPoints_of_eq f x h_init
(h_nab.symm.lt_of_le h_ba) (le_of_lt h_b) (h_fab.symm)
-/-- Every value of the ordinal approximants are less or equal than every fixed point of f greater
- then the initial value -/
+/-- Every value of the approximation is less or equal than every fixed point of `f`
+greater or equal than the initial value -/
theorem lfpApprox_le_of_mem_fixedPoints {a : α}
(h_a : a ∈ fixedPoints f) (h_le_init : x ≤ a) (i : Ordinal) : lfpApprox f x i ≤ a := by
induction i using Ordinal.induction with
| h i IH =>
- unfold lfpApprox
+ rw [lfpApprox]
apply sSup_le
simp only [exists_prop]
intro y h_y
@@ -186,13 +219,13 @@ theorem lfpApprox_le_of_mem_fixedPoints {a : α}
| inl h_y =>
let ⟨j, h_j_lt, h_j⟩ := h_y
rw [← h_j, ← h_a]
- apply f.monotone'
- exact IH j h_j_lt
+ exact f.monotone' (IH j h_j_lt)
| inr h_y =>
rw [h_y]
exact h_le_init
-/-- The least fixed point of f is reached after the successor of the domains cardinality -/
+/-- The approximation sequence converges at the successor of the domain's cardinality
+to the least fixed point if starting from `⊥` -/
theorem lfpApprox_ord_eq_lfp : lfpApprox f ⊥ (ord <| succ #α) = lfp f := by
apply le_antisymm
· have h_lfp : ∃ y : fixedPoints f, lfp f = y := by use ⊥; exact rfl
@@ -204,13 +237,15 @@ theorem lfpApprox_ord_eq_lfp : lfpApprox f ⊥ (ord <| succ #α) = lfp f := by
let ⟨x, h_x⟩ := h_fix; rw [h_x]
exact lfp_le_fixed f x.prop
-/-- Some ordinal approximation of the least fixed point is the least fixed point. -/
+/-- Some approximation of the least fixed point starting from `⊥` is the least fixed point. -/
theorem lfp_mem_range_lfpApprox : lfp f ∈ Set.range (lfpApprox f ⊥) := by
use ord <| succ #α
exact lfpApprox_ord_eq_lfp f
set_option linter.unusedVariables false in
-/-- Ordinal approximants of the greatest fixed point -/
+/-- The ordinal-indexed sequence approximating the greatest fixed point greater than
+an initial value `x`. It is defined in such a way that we have `gfpApprox 0 x = x` and
+`gfpApprox a x = ⨅ b < a, f (lfpApprox b x)`. -/
def gfpApprox (a : Ordinal.{u}) : α :=
sInf ({ f (gfpApprox b) | (b : Ordinal) (h : b < a) } ∪ {x})
termination_by a
@@ -230,34 +265,42 @@ theorem gfpApprox_add_one (h : f x ≤ x) (a : Ordinal) :
gfpApprox f x (a+1) = f (gfpApprox f x a) :=
lfpApprox_add_one (OrderHom.dual f) x h a
-/-- The ordinal approximants of the least fixed point are stabilizing
- when reaching a fixed point of f -/
+theorem gfpApprox_mono_left : Monotone (gfpApprox : (α →o α) → _) := by
+ intro f g h
+ have : OrderHom.dual g ≤ OrderHom.dual f := h
+ exact lfpApprox_mono_left this
+
+theorem gfpApprox_mono_mid : Monotone (gfpApprox f) :=
+ fun _ _ h => lfpApprox_mono_mid (OrderHom.dual f) h
+
+/-- The approximations of the greatest fixed point stabilize at a fixed point of `f` -/
theorem gfpApprox_eq_of_mem_fixedPoints {a b : Ordinal} (h_init : f x ≤ x) (h_ab : a ≤ b)
(h : gfpApprox f x a ∈ fixedPoints f) : gfpApprox f x b = gfpApprox f x a :=
lfpApprox_eq_of_mem_fixedPoints (OrderHom.dual f) x h_init h_ab h
-/-- There are distinct ordinals smaller than the successor of the domains cardinals with
- equal value -/
+/-- There are distinct indices smaller than the successor of the domain's cardinality
+yielding the same value -/
theorem exists_gfpApprox_eq_gfpApprox : ∃ a < ord <| succ #α, ∃ b < ord <| succ #α,
a ≠ b ∧ gfpApprox f x a = gfpApprox f x b :=
exists_lfpApprox_eq_lfpApprox (OrderHom.dual f) x
-/-- A fixed point of f is reached after the successor of the domains cardinality -/
+/-- The approximation at the index of the successor of the domain's cardinality is a fixed point -/
lemma gfpApprox_ord_mem_fixedPoint (h_init : f x ≤ x) :
gfpApprox f x (ord <| succ #α) ∈ fixedPoints f :=
lfpApprox_ord_mem_fixedPoint (OrderHom.dual f) x h_init
-/-- Every value of the ordinal approximants are greater or equal than every fixed point of f
- that is smaller then the initial value -/
+/-- Every value of the approximation is greater or equal than every fixed point of `f`
+less or equal than the initial value -/
lemma le_gfpApprox_of_mem_fixedPoints {a : α}
(h_a : a ∈ fixedPoints f) (h_le_init : a ≤ x) (i : Ordinal) : a ≤ gfpApprox f x i :=
lfpApprox_le_of_mem_fixedPoints (OrderHom.dual f) x h_a h_le_init i
-/-- The greatest fixed point of f is reached after the successor of the domains cardinality -/
+/-- The approximation sequence converges at the successor of the domain's cardinality
+to the greatest fixed point if starting from `⊥` -/
theorem gfpApprox_ord_eq_gfp : gfpApprox f ⊤ (ord <| succ #α) = gfp f :=
lfpApprox_ord_eq_lfp (OrderHom.dual f)
-/-- Some ordinal approximation of the greatest fixed point is the greatest fixed point. -/
+/-- Some approximation of the least fixed point starting from `⊤` is the greatest fixed point. -/
theorem gfp_mem_range_gfpApprox : gfp f ∈ Set.range (gfpApprox f ⊤) :=
lfp_mem_range_lfpApprox (OrderHom.dual f)
diff --git a/Mathlib/SetTheory/Ordinal/NaturalOps.lean b/Mathlib/SetTheory/Ordinal/NaturalOps.lean
index 6d70654a17e00..e4d93ce91b40d 100644
--- a/Mathlib/SetTheory/Ordinal/NaturalOps.lean
+++ b/Mathlib/SetTheory/Ordinal/NaturalOps.lean
@@ -106,19 +106,19 @@ 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 : NatOrdinal} : toOrdinal (max a b) = max (toOrdinal a) (toOrdinal b) :=
+theorem toOrdinal_max (a b : NatOrdinal) : toOrdinal (max a b) = max (toOrdinal a) (toOrdinal b) :=
rfl
@[simp]
-theorem toOrdinal_min {a b : NatOrdinal} : toOrdinal (min a b) = min (toOrdinal a) (toOrdinal b) :=
+theorem toOrdinal_min (a b : NatOrdinal) : toOrdinal (min a b) = min (toOrdinal a) (toOrdinal b) :=
rfl
theorem succ_def (a : NatOrdinal) : succ a = toNatOrdinal (toOrdinal a + 1) :=
@@ -192,7 +192,7 @@ scoped[NaturalOps] infixl:65 " ♯ " => Ordinal.nadd
open NaturalOps
/-- Natural multiplication on ordinals `a ⨳ b`, also known as the Hessenberg product, is recursively
-defined as the least ordinal such that `a ⨳ b + a' ⨳ b'` is greater than `a' ⨳ b + a ⨳ b'` for all
+defined as the least ordinal such that `a ⨳ b ♯ a' ⨳ b'` is greater than `a' ⨳ b ♯ a ⨳ b'` for all
`a' < a` and `b < b'`. In contrast to normal ordinal multiplication, it is commutative and
distributive (over natural addition).
@@ -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
@@ -446,9 +445,12 @@ theorem nmul_def (a b : Ordinal) :
a ⨳ b = sInf {c | ∀ a' < a, ∀ b' < b, a' ⨳ b ♯ a ⨳ b' < c ♯ a' ⨳ b'} := by rw [nmul]
/-- The set in the definition of `nmul` is nonempty. -/
-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⟩
+private theorem nmul_nonempty (a b : Ordinal.{u}) :
+ {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
new file mode 100644
index 0000000000000..b38f2ccbca68f
--- /dev/null
+++ b/Mathlib/SetTheory/Ordinal/Nimber.lean
@@ -0,0 +1,397 @@
+/-
+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
+
+/-!
+# Nimbers
+
+The goal of this file is to define the field of nimbers, constructed as ordinals endowed with new
+arithmetical operations. The nim sum `a + b` is recursively defined as the least ordinal not equal
+to any `a' + b` or `a + b'` for `a' < a` and `b' < b`. The nim product `a * b` is likewise
+recursively defined as the least ordinal not equal to any `a' * b + a * b' + a' * b'` for `a' < a`
+and `b' < b`.
+
+Nim addition arises within the context of impartial games. By the Sprague-Grundy theorem, each
+impartial game is equivalent to some game of nim. If `x ≈ nim o₁` and `y ≈ nim o₂`, then
+`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
+much more convenient. However, the fact that nimbers are of characteristic 2 prevents the order from
+interacting with the arithmetic in any nice way.
+
+To reduce API duplication, we opt not to implement operations on `Nimber` on `Ordinal`. The order
+isomorphisms `Ordinal.toNimber` and `Nimber.toOrdinal` allow us to cast between them whenever
+needed.
+
+## Todo
+
+- Add a `CharP 2` instance.
+- Define nim multiplication and prove nimbers are a commutative ring.
+- Define nim division and prove nimbers are a field.
+- Show the nimbers are algebraically closed.
+-/
+
+universe u v
+
+open Function Order
+
+noncomputable section
+
+/-! ### Basic casts between `Ordinal` and `Nimber` -/
+
+/-- A type synonym for ordinals with natural addition and multiplication. -/
+def Nimber : Type _ :=
+ Ordinal deriving Zero, Inhabited, One, WellFoundedRelation
+
+instance Nimber.linearOrder : LinearOrder Nimber := {Ordinal.linearOrder with}
+instance Nimber.succOrder : SuccOrder Nimber := {Ordinal.instSuccOrder with}
+instance Nimber.orderBot : OrderBot Nimber := {Ordinal.orderBot with}
+instance Nimber.noMaxOrder : NoMaxOrder Nimber := {Ordinal.noMaxOrder with}
+instance Nimber.zeroLEOneClass : ZeroLEOneClass Nimber := {Ordinal.zeroLEOneClass with}
+
+/-- The identity function between `Ordinal` and `Nimber`. -/
+@[match_pattern]
+def Ordinal.toNimber : Ordinal ≃o Nimber :=
+ OrderIso.refl _
+
+/-- The identity function between `Nimber` and `Ordinal`. -/
+@[match_pattern]
+def Nimber.toOrdinal : Nimber ≃o Ordinal :=
+ OrderIso.refl _
+
+@[inherit_doc]
+scoped[Nimber] prefix:75 "∗" => Ordinal.toNimber
+
+namespace Nimber
+
+open Ordinal
+
+@[simp]
+theorem toOrdinal_symm_eq : Nimber.toOrdinal.symm = Ordinal.toNimber :=
+ rfl
+
+@[simp]
+theorem toOrdinal_toNimber (a : Nimber) : ∗(Nimber.toOrdinal a) = a :=
+ rfl
+
+theorem lt_wf : @WellFounded Nimber (· < ·) :=
+ Ordinal.lt_wf
+
+instance : WellFoundedLT Nimber :=
+ Ordinal.wellFoundedLT
+
+instance : IsWellOrder Nimber (· < ·) :=
+ { }
+
+instance : ConditionallyCompleteLinearOrderBot Nimber :=
+ WellFoundedLT.conditionallyCompleteLinearOrderBot _
+
+@[simp]
+theorem bot_eq_zero : ⊥ = 0 :=
+ rfl
+
+@[simp]
+theorem toOrdinal_zero : toOrdinal 0 = 0 :=
+ rfl
+
+@[simp]
+theorem toOrdinal_one : toOrdinal 1 = 1 :=
+ rfl
+
+@[simp]
+theorem toOrdinal_eq_zero {a} : toOrdinal a = 0 ↔ a = 0 :=
+ Iff.rfl
+
+@[simp]
+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) :=
+ rfl
+
+@[simp]
+theorem toOrdinal_min (a b : Nimber) : toOrdinal (min a b) = min (toOrdinal a) (toOrdinal b) :=
+ rfl
+
+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, β (∗a)) : ∀ a, β a := fun a =>
+ h (toOrdinal a)
+
+/-- `Ordinal.induction` but for `Nimber`. -/
+theorem induction {p : Nimber → Prop} : ∀ (i) (_ : ∀ j, (∀ k, k < j → p k) → p j), p i :=
+ Ordinal.induction
+
+protected theorem le_zero {a : Nimber} : a ≤ 0 ↔ a = 0 :=
+ Ordinal.le_zero
+
+protected theorem not_lt_zero (a : Nimber) : ¬ a < 0 :=
+ Ordinal.not_lt_zero a
+
+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
+instance small_Icc (a b : Nimber.{u}) : Small.{u} (Set.Icc a b) := Ordinal.small_Icc a b
+instance small_Ioo (a b : Nimber.{u}) : Small.{u} (Set.Ioo a b) := Ordinal.small_Ioo a b
+instance small_Ioc (a b : Nimber.{u}) : Small.{u} (Set.Ioc a b) := Ordinal.small_Ioc a b
+
+end Nimber
+
+theorem not_small_nimber : ¬ Small.{u} Nimber.{max u v} :=
+ not_small_ordinal
+
+open Nimber
+
+namespace Ordinal
+
+@[simp]
+theorem toNimber_symm_eq : toNimber.symm = Nimber.toOrdinal :=
+ rfl
+
+@[simp]
+theorem toNimber_toOrdinal (a : Ordinal) : Nimber.toOrdinal (∗a) = a :=
+ rfl
+
+@[simp]
+theorem toNimber_zero : ∗0 = 0 :=
+ rfl
+
+@[simp]
+theorem toNimber_one : ∗1 = 1 :=
+ rfl
+
+@[simp]
+theorem toNimber_eq_zero {a} : ∗a = 0 ↔ a = 0 :=
+ Iff.rfl
+
+@[simp]
+theorem toNimber_eq_one {a} : ∗a = 1 ↔ a = 1 :=
+ Iff.rfl
+
+@[simp]
+theorem toNimber_max (a b : Ordinal) : ∗(max a b) = max (∗a) (∗b) :=
+ rfl
+
+@[simp]
+theorem toNimber_min (a b : Ordinal) : ∗(min a b) = min (∗a) (∗b) :=
+ rfl
+
+end Ordinal
+
+/-! ### Nimber addition -/
+
+namespace Nimber
+
+variable {a b c : Nimber.{u}}
+
+/-- Nimber addition is recursively defined so that `a + b` is the smallest number not equal to
+`a' + b` or `a + b'` for `a' < a` and `b' < b`. -/
+-- We write the binders like this so that the termination checker works.
+protected def add (a b : Nimber.{u}) : Nimber.{u} :=
+ sInf {x | (∃ a', ∃ (_ : a' < a), Nimber.add a' b = x) ∨
+ ∃ b', ∃ (_ : b' < b), Nimber.add a b' = x}ᶜ
+termination_by (a, b)
+
+instance : Add Nimber :=
+ ⟨Nimber.add⟩
+
+theorem add_def (a b : Nimber) :
+ a + b = sInf {x | (∃ a' < a, a' + b = x) ∨ ∃ b' < b, a + b' = x}ᶜ := by
+ change Nimber.add a b = _
+ rw [Nimber.add]
+ simp_rw [exists_prop]
+ rfl
+
+/-- The set in the definition of `Nimber.add` is nonempty. -/
+private theorem add_nonempty (a b : Nimber.{u}) :
+ {x | (∃ a' < a, a' + b = x) ∨ ∃ b' < b, a + b' = x}ᶜ.Nonempty := by
+ simp_rw [Set.nonempty_compl, Set.setOf_or, ← Set.mem_Iio, ← Set.image.eq_1]
+ apply_fun (fun a : Set Nimber ↦ Small.{u} a)
+ have : Small.{u} ↑((· + b) '' Set.Iio a ∪ (a + ·) '' Set.Iio b) := inferInstance
+ simpa [this, small_congr (Equiv.Set.univ _)] using not_small_nimber
+
+theorem exists_of_lt_add (h : c < a + b) : (∃ a' < a, a' + b = c) ∨ ∃ b' < b, a + b' = c := by
+ rw [add_def] at h
+ have := not_mem_of_lt_csInf h ⟨_, bot_mem_lowerBounds _⟩
+ rwa [Set.mem_compl_iff, not_not] at this
+
+theorem add_le_of_forall_ne (h₁ : ∀ a' < a, a' + b ≠ c) (h₂ : ∀ b' < b, a + b' ≠ c) :
+ a + b ≤ c := by
+ by_contra! h
+ have := exists_of_lt_add h
+ tauto
+
+private theorem add_ne_of_lt (a b : Nimber) :
+ (∀ a' < a, a' + b ≠ a + b) ∧ ∀ b' < b, a + b' ≠ a + b := by
+ have H := csInf_mem (add_nonempty a b)
+ rw [← add_def] at H
+ simpa using H
+
+instance : IsLeftCancelAdd Nimber := by
+ constructor
+ intro a b c h
+ apply le_antisymm <;>
+ apply le_of_not_lt
+ · exact fun hc => (add_ne_of_lt a b).2 c hc h.symm
+ · exact fun hb => (add_ne_of_lt a c).2 b hb h
+
+instance : IsRightCancelAdd Nimber := by
+ constructor
+ intro a b c h
+ apply le_antisymm <;>
+ apply le_of_not_lt
+ · exact fun hc => (add_ne_of_lt a b).1 c hc h.symm
+ · exact fun ha => (add_ne_of_lt c b).1 a ha h
+
+protected theorem add_comm (a b : Nimber) : a + b = b + a := by
+ rw [add_def, add_def]
+ simp_rw [or_comm]
+ congr! 7 <;>
+ (rw [and_congr_right_iff]; intro; rw [Nimber.add_comm])
+termination_by (a, b)
+
+theorem add_eq_zero {a b : Nimber} : a + b = 0 ↔ a = b := by
+ constructor <;>
+ intro hab
+ · obtain h | rfl | h := lt_trichotomy a b
+ · have ha : a + a = 0 := add_eq_zero.2 rfl
+ rwa [← ha, add_right_inj, eq_comm] at hab
+ · rfl
+ · have hb : b + b = 0 := add_eq_zero.2 rfl
+ rwa [← hb, add_left_inj] at hab
+ · rw [← Nimber.le_zero]
+ apply add_le_of_forall_ne <;>
+ simp_rw [ne_eq] <;>
+ intro x hx
+ · rw [add_eq_zero, ← hab]
+ exact hx.ne
+ · rw [add_eq_zero, hab]
+ exact hx.ne'
+termination_by (a, b)
+
+theorem add_ne_zero_iff : a + b ≠ 0 ↔ a ≠ b :=
+ add_eq_zero.not
+
+@[simp]
+theorem add_self (a : Nimber) : a + a = 0 :=
+ add_eq_zero.2 rfl
+
+protected theorem add_assoc (a b c : Nimber) : a + b + c = a + (b + c) := by
+ apply le_antisymm <;>
+ apply add_le_of_forall_ne <;>
+ intro x hx <;>
+ try obtain ⟨y, hy, rfl⟩ | ⟨y, hy, rfl⟩ := exists_of_lt_add hx
+ on_goal 1 => rw [Nimber.add_assoc y, add_ne_add_left]
+ on_goal 2 => rw [Nimber.add_assoc _ y, add_ne_add_right, add_ne_add_left]
+ on_goal 3 => rw [Nimber.add_assoc _ _ x, add_ne_add_right, add_ne_add_right]
+ on_goal 4 => rw [← Nimber.add_assoc x, add_ne_add_left, add_ne_add_left]
+ on_goal 5 => rw [← Nimber.add_assoc _ y, add_ne_add_left, add_ne_add_right]
+ on_goal 6 => rw [← Nimber.add_assoc _ _ y, add_ne_add_right]
+ all_goals apply ne_of_lt; assumption
+termination_by (a, b, c)
+
+protected theorem add_zero (a : Nimber) : a + 0 = a := by
+ apply le_antisymm
+ · apply add_le_of_forall_ne
+ · intro a' ha
+ rw [Nimber.add_zero]
+ exact ha.ne
+ · intro _ h
+ exact (Nimber.not_lt_zero _ h).elim
+ · -- by_contra! doesn't work for whatever reason.
+ by_contra h
+ replace h := lt_of_not_le h
+ have := Nimber.add_zero (a + 0)
+ rw [add_left_inj] at this
+ exact this.not_lt h
+termination_by a
+
+protected theorem zero_add (a : Nimber) : 0 + a = a := by
+ rw [Nimber.add_comm, Nimber.add_zero]
+
+instance : Neg Nimber :=
+ ⟨id⟩
+
+@[simp]
+protected theorem neg_eq (a : Nimber) : -a = a :=
+ rfl
+
+instance : AddCommGroupWithOne Nimber where
+ add_assoc := Nimber.add_assoc
+ add_zero := Nimber.add_zero
+ zero_add := Nimber.zero_add
+ nsmul := nsmulRec
+ zsmul := zsmulRec
+ neg_add_cancel := add_self
+ add_comm := Nimber.add_comm
+
+@[simp]
+theorem add_cancel_right (a b : Nimber) : a + b + b = a := by
+ rw [add_assoc, add_self, add_zero]
+
+@[simp]
+theorem add_cancel_left (a b : Nimber) : a + (a + b) = b := by
+ rw [← add_assoc, add_self, zero_add]
+
+theorem add_trichotomy {a b c : Nimber} (h : a + b + c ≠ 0) :
+ b + c < a ∨ c + a < b ∨ a + b < c := by
+ rw [← Nimber.pos_iff_ne_zero] at h
+ obtain ⟨x, hx, hx'⟩ | ⟨x, hx, hx'⟩ := exists_of_lt_add h <;>
+ rw [add_eq_zero] at hx'
+ · obtain ⟨x, hx, hx'⟩ | ⟨x, hx, hx'⟩ := exists_of_lt_add (hx' ▸ hx)
+ · rw [← hx', add_comm, add_cancel_right]
+ exact Or.inl hx
+ · rw [← hx', add_comm a, add_cancel_right]
+ exact Or.inr <| Or.inl hx
+ · 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 d57c7f29037cc..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,23 +134,28 @@ 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 omega_le_oadd (e n a) : ω ^ repr e ≤ repr (oadd e n a) := by
+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) omega_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
theorem oadd_pos (e n a) : 0 < oadd e n a :=
- @lt_of_lt_of_le _ _ _ (ω ^ repr e) _ (opow_pos (repr e) omega_pos) (omega_le_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
| 0, _ => Ordering.lt
| _o₁@(oadd e₁ n₁ a₁), _o₂@(oadd e₂ n₂ a₂) =>
- (cmp e₁ e₂).orElse <| (_root_.cmp (n₁ : ℕ) n₂).orElse (cmp a₁ a₂)
+ (cmp e₁ e₂).then <| (_root_.cmp (n₁ : ℕ) n₂).then (cmp a₁ a₂)
theorem eq_of_cmp_eq : ∀ {o₁ o₂}, cmp o₁ o₂ = Ordering.eq → o₁ = o₂
| 0, 0, _ => rfl
@@ -172,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ₖ`
- 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. -/
+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. -/
class NF (o : ONote) : Prop where
out : Exists (NFBelow o)
@@ -231,14 +232,14 @@ theorem NF.zero_of_zero {e n a} (h : NF (ONote.oadd e n a)) (e0 : e = 0) : a = 0
theorem NFBelow.repr_lt {o b} (h : NFBelow o b) : repr o < ω ^ b := by
induction h with
- | zero => exact opow_pos _ omega_pos
+ | zero => exact opow_pos _ omega0_pos
| oadd' _ _ h₃ _ IH =>
rw [repr]
apply ((add_lt_add_iff_left _).2 IH).trans_le
rw [← mul_succ]
- apply (mul_le_mul_left' (succ_le_of_lt (nat_lt_omega _)) _).trans
+ apply (mul_le_mul_left' (succ_le_of_lt (nat_lt_omega0 _)) _).trans
rw [← opow_succ]
- exact opow_le_opow_right omega_pos (succ_le_of_lt h₃)
+ exact opow_le_opow_right omega0_pos (succ_le_of_lt h₃)
theorem NFBelow.mono {o b₁ b₂} (bb : b₁ ≤ b₂) (h : NFBelow o b₁) : NFBelow o b₂ := by
induction h with
@@ -253,7 +254,7 @@ theorem NF.below_of_lt' : ∀ {o b}, repr o < ω ^ b → NF o → NFBelow o b
| 0, _, _, _ => NFBelow.zero
| ONote.oadd _ _ _, _, H, h =>
h.below_of_lt <|
- (opow_lt_opow_iff_right one_lt_omega).1 <| lt_of_le_of_lt (omega_le_oadd _ _ _) H
+ (opow_lt_opow_iff_right one_lt_omega0).1 <| lt_of_le_of_lt (omega0_le_oadd _ _ _) H
theorem nfBelow_ofNat : ∀ n, NFBelow (ofNat n) 1
| 0 => NFBelow.zero
@@ -267,13 +268,13 @@ instance nf_one : NF 1 := by rw [← ofNat_one]; infer_instance
theorem oadd_lt_oadd_1 {e₁ n₁ o₁ e₂ n₂ o₂} (h₁ : NF (oadd e₁ n₁ o₁)) (h : e₁ < e₂) :
oadd e₁ n₁ o₁ < oadd e₂ n₂ o₂ :=
@lt_of_lt_of_le _ _ (repr (oadd e₁ n₁ o₁)) _ _
- (NF.below_of_lt h h₁).repr_lt (omega_le_oadd e₂ n₂ o₂)
+ (NF.below_of_lt h h₁).repr_lt (omega0_le_oadd e₂ n₂ o₂)
theorem oadd_lt_oadd_2 {e o₁ o₂ : ONote} {n₁ n₂ : ℕ+} (h₁ : NF (oadd e n₁ o₁)) (h : (n₁ : ℕ) < n₂) :
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 _ omega_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
@@ -281,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
@@ -325,7 +326,7 @@ theorem repr_inj {a b} [NF a] [NF b] : repr a = repr b ↔ a = b :=
| Ordering.eq, h => h,
congr_arg _⟩
-theorem NF.of_dvd_omega_opow {b e n a} (h : NF (ONote.oadd e n a))
+theorem NF.of_dvd_omega0_opow {b e n a} (h : NF (ONote.oadd e n a))
(d : ω ^ b ∣ repr (ONote.oadd e n a)) :
b ≤ repr e ∧ ω ^ b ∣ repr a := by
have := mt repr_inj.1 (fun h => by injection h : ONote.oadd e n a ≠ 0)
@@ -333,13 +334,18 @@ theorem NF.of_dvd_omega_opow {b e n a} (h : NF (ONote.oadd e n a))
simp only [repr] at d
exact ⟨L, (dvd_add_iff <| (opow_dvd_opow _ L).mul_right _).1 d⟩
-theorem NF.of_dvd_omega {e n a} (h : NF (ONote.oadd e n a)) :
+@[deprecated (since := "2024-09-30")]
+alias NF.of_dvd_omega_opow := NF.of_dvd_omega0_opow
+
+theorem NF.of_dvd_omega0 {e n a} (h : NF (ONote.oadd e n a)) :
ω ∣ repr (ONote.oadd e n a) → repr e ≠ 0 ∧ ω ∣ repr a := by
- (rw [← opow_one ω, ← one_le_iff_ne_zero]; exact h.of_dvd_omega_opow)
+ (rw [← opow_one ω, ← one_le_iff_ne_zero]; exact h.of_dvd_omega0_opow)
+
+@[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
@@ -443,8 +449,8 @@ theorem repr_add : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ + o₂) = rep
unfold repr at this
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') omega_pos).2
- (natCast_le.2 n'.pos)
+ · simpa using (Ordinal.mul_le_mul_iff_left <| opow_pos (repr e') omega0_pos).2
+ (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
@@ -472,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]
@@ -500,10 +506,10 @@ 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 <| omega_le_oadd _ _ _).symm
+ add_absorp (h₂.below_of_lt ee).repr_lt <| omega0_le_oadd _ _ _).symm
/-- Multiplication of ordinal notations (correct only for normal input) -/
def mul : ONote → ONote → ONote
@@ -528,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]
@@ -544,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 =>
@@ -557,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 _ omega_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]
@@ -570,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 omega_isLimit this), mul_assoc,
- mul_omega_dvd (natCast_pos.2 n₁.pos) (nat_lt_omega _)]
+ 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 =>
@@ -584,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 =>
@@ -605,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
@@ -628,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 :=
@@ -654,9 +659,7 @@ theorem split_eq_scale_split' : ∀ {o o' m} [NF o], split' o = (o', m) → spli
simp only [repr_add, repr, opow_zero, Nat.succPNat_coe, Nat.cast_one, mul_one, add_zero,
repr_sub]
have := mt repr_inj.1 e0
- refine Ordinal.add_sub_cancel_of_le ?_
- have := one_le_iff_ne_zero.2 this
- exact this
+ exact Ordinal.add_sub_cancel_of_le <| one_le_iff_ne_zero.2 this
intros
substs o' m
simp [scale, this]
@@ -682,7 +685,7 @@ theorem nf_repr_split' : ∀ {o o' m} [NF o], split' o = (o', m) → NF o' ∧ r
· simp at this ⊢
refine
IH₁.below_of_lt'
- ((Ordinal.mul_lt_mul_iff_left omega_pos).1 <| lt_of_le_of_lt (le_add_right _ m') ?_)
+ ((Ordinal.mul_lt_mul_iff_left omega0_pos).1 <| lt_of_le_of_lt (le_add_right _ m') ?_)
rw [← this, ← IH₂]
exact h.snd'.repr_lt
· rw [this]
@@ -725,9 +728,9 @@ theorem split_dvd {o o' m} [NF o] (h : split o = (o', m)) : ω ∣ repr o' := by
theorem split_add_lt {o e n a m} [NF o] (h : split o = (oadd e n a, m)) :
repr a + m < ω ^ repr e := by
cases' nf_repr_split h with h₁ h₂
- cases' h₁.of_dvd_omega (split_dvd h) with e0 d
- apply principal_add_omega_opow _ h₁.snd'.repr_lt (lt_of_lt_of_le (nat_lt_omega _) _)
- simpa using opow_le_opow_right omega_pos (one_le_iff_ne_zero.2 e0)
+ cases' h₁.of_dvd_omega0 (split_dvd h) with e0 d
+ apply principal_add_omega0_opow _ h₁.snd'.repr_lt (lt_of_lt_of_le (nat_lt_omega0 _) _)
+ simpa using opow_le_opow_right omega0_pos (one_le_iff_ne_zero.2 e0)
@[simp]
theorem mulNat_eq_mul (n o) : mulNat o n = o * ofNat n := by cases o <;> cases n <;> rfl
@@ -783,22 +786,22 @@ theorem repr_opow_aux₁ {e a} [Ne : NF e] [Na : NF a] {a' : Ordinal} (e0 : repr
(ω ^ repr e) ^ (ω : Ordinal.{0}) := by
subst aa
have No := Ne.oadd n (Na.below_of_lt' h)
- have := omega_le_oadd e n a
+ 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 _ omega_pos).trans_le this).ne' omega_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
apply (opow_le_opow_left b <| this.le).trans
rw [← opow_mul, ← opow_mul]
- apply opow_le_opow_right omega_pos
+ apply opow_le_opow_right omega0_pos
rcases le_or_lt ω (repr e) with h | h
· apply (mul_le_mul_left' (le_succ b) _).trans
- rw [← add_one_eq_succ, add_mul_succ _ (one_add_of_omega_le h), add_one_eq_succ, succ_le_iff,
+ 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 omega_isLimit.2 _ l
- · apply (principal_mul_omega (omega_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
@@ -829,31 +832,31 @@ theorem repr_opow_aux₂ {a0 a'} [N0 : NF a0] [Na' : NF a'] (m : ℕ) (d : ω
· simp only [R', ONote.repr_scale, ONote.repr, ONote.mulNat_eq_mul, ONote.opowAux,
ONote.repr_ofNat, ONote.repr_mul, ONote.repr_add, Ordinal.opow_mul, ONote.zero_add]
have α0 : 0 < α' := by simpa [lt_def, repr] using oadd_pos a0 n a'
- have ω00 : 0 < ω0 ^ (k : Ordinal) := opow_pos _ (opow_pos _ omega_pos)
+ have ω00 : 0 < ω0 ^ (k : Ordinal) := opow_pos _ (opow_pos _ omega0_pos)
have Rl : R < ω ^ (repr a0 * succ ↑k) := by
by_cases k0 : k = 0
· simp only [k0, Nat.cast_zero, succ_zero, mul_one, R]
- refine lt_of_lt_of_le ?_ (opow_le_opow_right omega_pos (one_le_iff_ne_zero.2 e0))
- cases' m with m <;> simp [opowAux, omega_pos]
+ refine lt_of_lt_of_le ?_ (opow_le_opow_right omega0_pos (one_le_iff_ne_zero.2 e0))
+ cases' m with m <;> simp [opowAux, omega0_pos]
rw [← add_one_eq_succ, ← Nat.cast_succ]
- apply nat_lt_omega
+ apply nat_lt_omega0
· rw [opow_mul]
exact IH.1 k0
refine ⟨fun _ => ?_, ?_⟩
· rw [RR, ← opow_mul _ _ (succ k.succ)]
have e0 := Ordinal.pos_iff_ne_zero.2 e0
have rr0 : 0 < repr a0 + repr a0 := lt_of_lt_of_le e0 (le_add_left _ _)
- apply principal_add_omega_opow
+ apply principal_add_omega0_opow
· simp only [Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, add_one_eq_succ,
opow_mul, opow_succ, mul_assoc]
rw [Ordinal.mul_lt_mul_iff_left ω00, ← Ordinal.opow_add]
have : _ < ω ^ (repr a0 + repr a0) := (No.below_of_lt ?_).repr_lt
- · exact mul_lt_omega_opow rr0 this (nat_lt_omega _)
+ · exact mul_lt_omega0_opow rr0 this (nat_lt_omega0 _)
· simpa using (add_lt_add_iff_left (repr a0)).2 e0
· exact
lt_of_lt_of_le Rl
- (opow_le_opow_right omega_pos <|
- mul_le_mul_left' (succ_le_succ_iff.2 (natCast_le.2 (le_of_lt k.lt_succ_self))) _)
+ (opow_le_opow_right omega0_pos <|
+ 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
@@ -864,13 +867,13 @@ theorem repr_opow_aux₂ {a0 a'} [N0 : NF a0] [Na' : NF a'] (m : ℕ) (d : ω
· have α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_omega_dvd.2 ⟨ne_of_gt α0, αd⟩), mul_assoc,
- @mul_omega_dvd n (natCast_pos.2 n.pos) (nat_lt_omega _) _ αd]
+ add_mul_limit _ (isLimit_iff_omega0_dvd.2 ⟨ne_of_gt α0, αd⟩), mul_assoc,
+ @mul_omega0_dvd n (Nat.cast_pos'.2 n.pos) (nat_lt_omega0 _) _ αd]
apply @add_absorp _ (repr a0 * succ ↑k)
- · refine principal_add_omega_opow _ ?_ Rl
+ · 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
@@ -880,7 +883,7 @@ theorem repr_opow_aux₂ {a0 a'} [N0 : NF a0] [Na' : NF a'] (m : ℕ) (d : ω
apply add_absorp Rl
rw [opow_mul, opow_succ]
apply mul_le_mul_left'
- simpa [repr] using omega_le_oadd a0 n a'
+ simpa [repr] using omega0_le_oadd a0 n a'
end
@@ -899,18 +902,18 @@ theorem repr_opow (o₁ o₂) [NF o₁] [NF o₂] : repr (o₁ ^ o₂) = repr o
simp only [opow_def, opowAux2, opow, e₁, h, r₁, e₂, r₂, repr,
opow_zero, Nat.succPNat_coe, Nat.cast_succ, Nat.cast_zero, _root_.zero_add, mul_one,
add_zero, one_opow, npow_eq_pow]
- rw [opow_add, opow_mul, opow_omega, add_one_eq_succ]
+ rw [opow_add, opow_mul, opow_omega0, add_one_eq_succ]
· congr
conv_lhs =>
dsimp [(· ^ ·)]
simp [Pow.pow, opow, Ordinal.succ_ne_zero]
rw [opow_natCast]
· simpa [Nat.one_le_iff_ne_zero]
- · rw [← Nat.cast_succ, lt_omega]
+ · rw [← Nat.cast_succ, lt_omega0]
exact ⟨_, rfl⟩
· haveI := N₁.fst
haveI := N₁.snd
- cases' N₁.of_dvd_omega (split_dvd e₁) with a00 ad
+ cases' N₁.of_dvd_omega0 (split_dvd e₁) with a00 ad
have al := split_add_lt e₁
have aa : repr (a' + ofNat m) = repr a' + m := by
simp only [eq_self_iff_true, ONote.repr_ofNat, ONote.repr_add]
@@ -931,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 =>
@@ -957,23 +963,24 @@ private theorem exists_lt_add {α} [hα : Nonempty α] {o : Ordinal} {f : α →
refine (H h).imp fun i H => ?_
rwa [← Ordinal.add_sub_cancel_of_le h', add_lt_add_iff_left]
-private theorem exists_lt_mul_omega' {o : Ordinal} ⦃a⦄ (h : a < o * ω) :
+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 omega_isLimit).1 h
- obtain ⟨i, rfl⟩ := lt_omega.1 hi
+ 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 _ _)⟩
-private theorem exists_lt_omega_opow' {α} {o b : Ordinal} (hb : 1 < b) (ho : o.IsLimit)
+private theorem exists_lt_omega0_opow' {α} {o b : Ordinal} (hb : 1 < b) (ho : o.IsLimit)
{f : α → Ordinal} (H : ∀ ⦃a⦄, a < o → ∃ i, a < f i) ⦃a⦄ (h : a < b ^ o) :
∃ i, a < b ^ f i := by
obtain ⟨d, hd, h'⟩ := (lt_opow_of_limit (zero_lt_one.trans hb).ne' ho).1 h
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)
@@ -996,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]
@@ -1016,39 +1016,40 @@ theorem fundamentalSequence_has_prop (o) : FundamentalSequenceProp o (fundamenta
have := PNat.natPred_add_one m; rw [e'] at this; exact PNat.coe_inj.1 this.symm]) <;>
(try rw [show m = (m' + 1).succPNat by
rw [← e', ← PNat.coe_inj, Nat.succPNat_coe, ← Nat.add_one, PNat.natPred_add_one]]) <;>
- simp only [repr, iha, ihb, opow_lt_opow_iff_right one_lt_omega, add_lt_add_iff_left, add_zero,
- eq_self_iff_true, lt_add_iff_pos_right, lt_def, mul_one, Nat.cast_zero, Nat.cast_succ,
- Nat.succPNat_coe, opow_succ, opow_zero, mul_add_one, PNat.one_coe, succ_zero,
- true_and_iff, _root_.zero_add, zero_def]
+ simp only [repr, iha, ihb, opow_lt_opow_iff_right one_lt_omega0, add_lt_add_iff_left,
+ add_zero, eq_self_iff_true, lt_add_iff_pos_right, lt_def, mul_one, Nat.cast_zero,
+ Nat.cast_succ, Nat.succPNat_coe, opow_succ, opow_zero, mul_add_one, PNat.one_coe, succ_zero,
+ _root_.zero_add, zero_def]
· decide
· exact ⟨rfl, inferInstance⟩
- · have := opow_pos (repr a') omega_pos
+ · have := opow_pos (repr a') omega0_pos
refine
- ⟨mul_isLimit this omega_isLimit, fun i =>
- ⟨this, ?_, fun H => @NF.oadd_zero _ _ (iha.2 H.fst)⟩, exists_lt_mul_omega'⟩
+ ⟨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_omega
- · have := opow_pos (repr a') omega_pos
+ apply nat_lt_omega0
+ · have := opow_pos (repr a') omega0_pos
refine
- ⟨add_isLimit _ (mul_isLimit this omega_isLimit), fun i => ⟨this, ?_, ?_⟩,
- exists_lt_add exists_lt_mul_omega'⟩
+ ⟨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_omega
+ apply nat_lt_omega0
· refine fun H => H.fst.oadd _ (NF.below_of_lt' ?_ (@NF.oadd_zero _ _ (iha.2 H.fst)))
rw [repr, ← zero_def, repr, add_zero, iha.1, opow_succ, Ordinal.mul_lt_mul_iff_left this]
- apply nat_lt_omega
+ apply nat_lt_omega0
· rcases iha with ⟨h1, h2, h3⟩
- refine ⟨opow_isLimit one_lt_omega h1, fun i => ?_, exists_lt_omega_opow' one_lt_omega h1 h3⟩
+ 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_omega h1), fun i => ?_,
- exists_lt_add (exists_lt_omega_opow' one_lt_omega h1 h3)⟩
+ ⟨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)))⟩
rwa [repr, ← zero_def, repr, add_zero, PNat.one_coe, Nat.cast_one, mul_one,
- opow_lt_opow_iff_right one_lt_omega]
+ opow_lt_opow_iff_right one_lt_omega0]
· refine ⟨by
rw [repr, ihb.1, add_succ, repr], fun H => H.fst.oadd _ (NF.below_of_lt' ?_ (ihb.2 H.snd))⟩
have := H.snd'.repr_lt
@@ -1057,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
@@ -1080,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 =
@@ -1117,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]
@@ -1126,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
@@ -1146,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 }
@@ -1163,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
@@ -1225,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)
@@ -1233,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 8d13d1a443605..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.
-* `principal_add_iff_zero_or_omega_opow`: The main characterization theorem for additive principal
+* `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_omega_opow_opow`: The main characterization theorem for
+* `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
@@ -75,7 +86,7 @@ theorem Principal.iterate_lt {a o : Ordinal} (hao : a < o) (ho : Principal op o)
theorem op_eq_self_of_principal {a o : Ordinal.{u}} (hao : a < o) (H : IsNormal (op a))
(ho : Principal op o) (ho' : IsLimit o) : op a o = o := by
- refine le_antisymm ?_ (H.self_le _)
+ apply H.le_apply.antisymm'
rw [← IsNormal.bsup_eq.{u, u} H ho', bsup_le_iff]
exact fun b hbo => (ho hao hbo).le
@@ -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,57 +193,69 @@ 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⟩
-theorem add_omega {a : Ordinal} (h : a < ω) : a + ω = ω := by
- rcases lt_omega.1 h with ⟨n, rfl⟩
+theorem add_omega0 {a : Ordinal} (h : a < ω) : a + ω = ω := by
+ rcases lt_omega0.1 h with ⟨n, rfl⟩
clear h; induction' n with n IH
· rw [Nat.cast_zero, zero_add]
- · rwa [Nat.cast_succ, add_assoc, one_add_of_omega_le (le_refl _)]
+ · rwa [Nat.cast_succ, add_assoc, one_add_of_omega0_le (le_refl _)]
-theorem principal_add_omega : Principal (· + ·) ω :=
- principal_add_iff_add_left_eq_self.2 fun _ => add_omega
+@[deprecated (since := "2024-09-30")]
+alias add_omega := add_omega0
-theorem add_omega_opow {a b : Ordinal} (h : a < ω ^ b) : a + ω ^ b = ω ^ b := by
+theorem principal_add_omega0 : Principal (· + ·) ω :=
+ principal_add_iff_add_left_eq_self.2 fun _ => add_omega0
+
+@[deprecated (since := "2024-09-30")]
+alias principal_add_omega := principal_add_omega0
+
+theorem add_omega0_opow {a b : Ordinal} (h : a < ω ^ b) : a + ω ^ b = ω ^ b := by
refine le_antisymm ?_ (le_add_left _ a)
induction' b using limitRecOn with b _ b l IH
· 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 omega_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_omega xo]
- · rcases (lt_opow_of_limit omega_ne_zero l).1 h with ⟨x, xb, ax⟩
- apply (((add_isNormal a).trans <| opow_isNormal one_lt_omega).limit_le l).2
+ rw [opow_succ, ← mul_add, add_omega0 xo]
+ · rcases (lt_opow_of_limit omega0_ne_zero l).1 h with ⟨x, xb, ax⟩
+ 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 omega_pos (le_max_right x y)) _
+ add_le_add_left (opow_le_opow_right omega0_pos (le_max_right x y)) _
_ ≤ ω ^ max x y :=
- IH _ (max_lt xb yb) <| ax.trans_le <| opow_le_opow_right omega_pos <| le_max_left x y
+ IH _ (max_lt xb yb) <| ax.trans_le <| opow_le_opow_right omega0_pos <| le_max_left x y
_ ≤ ω ^ b :=
- opow_le_opow_right omega_pos <| (max_lt xb yb).le
+ opow_le_opow_right omega0_pos <| (max_lt xb yb).le
+
+@[deprecated (since := "2024-09-30")]
+alias add_omega_opow := add_omega0_opow
-theorem principal_add_omega_opow (o : Ordinal) : Principal (· + ·) (ω ^ o) :=
- principal_add_iff_add_left_eq_self.2 fun _ => add_omega_opow
+theorem principal_add_omega0_opow (o : Ordinal) : Principal (· + ·) (ω ^ o) :=
+ principal_add_iff_add_left_eq_self.2 fun _ => add_omega0_opow
+
+@[deprecated (since := "2024-09-30")]
+alias principal_add_omega_opow := principal_add_omega0_opow
/-- The main characterization theorem for additive principal ordinals. -/
-theorem principal_add_iff_zero_or_omega_opow {o : Ordinal} :
+theorem principal_add_iff_zero_or_omega0_opow {o : Ordinal} :
Principal (· + ·) o ↔ o = 0 ∨ o ∈ Set.range (ω ^ · : Ordinal → Ordinal) := by
rcases eq_or_ne o 0 with (rfl | ho)
· simp only [principal_zero, Or.inl]
· rw [principal_add_iff_add_left_eq_self]
- simp only [ho, false_or_iff]
+ simp only [ho, false_or]
refine
⟨fun H => ⟨_, ((lt_or_eq_of_le (opow_log_le_self _ ho)).resolve_left fun h => ?_)⟩,
- fun ⟨b, e⟩ => e.symm ▸ fun a => add_omega_opow⟩
+ fun ⟨b, e⟩ => e.symm ▸ fun a => add_omega0_opow⟩
have := H _ h
- have := lt_opow_succ_log_self one_lt_omega o
- rw [opow_succ, lt_mul_of_limit omega_isLimit] at this
+ have := lt_opow_succ_log_self one_lt_omega0 o
+ rw [opow_succ, lt_mul_of_limit isLimit_omega0] at this
rcases this with ⟨a, ao, h'⟩
- rcases lt_omega.1 ao with ⟨n, rfl⟩
+ rcases lt_omega0.1 ao with ⟨n, rfl⟩
clear ao
revert h'
apply not_lt_of_le
@@ -218,18 +265,21 @@ theorem principal_add_iff_zero_or_omega_opow {o : Ordinal} :
· simp [Nat.cast_zero, mul_zero, zero_add]
· simp only [Nat.cast_succ, mul_add_one, add_assoc, this, IH]
+@[deprecated (since := "2024-09-30")]
+alias principal_add_iff_zero_or_omega_opow := principal_add_iff_zero_or_omega0_opow
+
theorem opow_principal_add_of_principal_add {a} (ha : Principal (· + ·) a) (b : Ordinal) :
Principal (· + ·) (a ^ b) := by
- rcases principal_add_iff_zero_or_omega_opow.1 ha with (rfl | ⟨c, rfl⟩)
+ rcases principal_add_iff_zero_or_omega0_opow.1 ha with (rfl | ⟨c, rfl⟩)
· rcases eq_or_ne b 0 with (rfl | hb)
· rw [opow_zero]
exact principal_add_one
· rwa [zero_opow hb]
· rw [← opow_mul]
- exact principal_add_omega_opow _
+ exact principal_add_omega0_opow _
theorem add_absorp {a b c : Ordinal} (h₁ : a < ω ^ b) (h₂ : ω ^ b ≤ c) : a + c = c := by
- rw [← Ordinal.add_sub_cancel_of_le h₂, ← add_assoc, add_omega_opow h₁]
+ rw [← Ordinal.add_sub_cancel_of_le h₂, ← add_assoc, add_omega0_opow h₁]
theorem mul_principal_add_is_principal_add (a : Ordinal.{u}) {b : Ordinal.{u}} (hb₁ : b ≠ 1)
(hb : Principal (· + ·) b) : Principal (· + ·) (a * b) := by
@@ -250,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 _
@@ -273,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₂)
@@ -283,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} :
@@ -292,54 +341,70 @@ 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_omega : Principal (· * ·) ω := fun a b ha hb =>
- match a, b, lt_omega.1 ha, lt_omega.1 hb with
+theorem principal_mul_omega0 : Principal (· * ·) ω := fun a b ha hb =>
+ match a, b, lt_omega0.1 ha, lt_omega0.1 hb with
| _, _, ⟨m, rfl⟩, ⟨n, rfl⟩ => by
dsimp only; rw [← natCast_mul]
- apply nat_lt_omega
+ apply nat_lt_omega0
+
+@[deprecated (since := "2024-09-30")]
+alias principal_mul_omega := principal_mul_omega0
-theorem mul_omega {a : Ordinal} (a0 : 0 < a) (ha : a < ω) : a * ω = ω :=
- principal_mul_iff_mul_left_eq.1 principal_mul_omega a a0 ha
+theorem mul_omega0 {a : Ordinal} (a0 : 0 < a) (ha : a < ω) : a * ω = ω :=
+ principal_mul_iff_mul_left_eq.1 principal_mul_omega0 a a0 ha
-theorem mul_lt_omega_opow {a b c : Ordinal} (c0 : 0 < c) (ha : a < ω ^ c) (hb : b < ω) :
+@[deprecated (since := "2024-09-30")]
+alias mul_omega := mul_omega0
+
+theorem mul_lt_omega0_opow {a b c : Ordinal} (c0 : 0 < c) (ha : a < ω ^ c) (hb : b < ω) :
a * b < ω ^ c := by
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 _ omega_pos).limit_lt omega_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 _ omega_pos)]
- exact principal_mul_omega hn hb
- · rcases ((opow_isNormal one_lt_omega).limit_lt l).1 ha with ⟨x, hx, ax⟩
+ rw [opow_succ, mul_assoc, mul_lt_mul_iff_left (opow_pos _ omega0_pos)]
+ exact principal_mul_omega0 hn hb
+ · 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_omega]
+ rw [← opow_succ, opow_lt_opow_iff_right one_lt_omega0]
exact l.2 _ hx
-theorem mul_omega_opow_opow {a b : Ordinal} (a0 : 0 < a) (h : a < ω ^ ω ^ b) :
+@[deprecated (since := "2024-09-30")]
+alias mul_lt_omega_opow := mul_lt_omega0_opow
+
+theorem mul_omega0_opow_opow {a b : Ordinal} (a0 : 0 < a) (h : a < ω ^ ω ^ b) :
a * ω ^ ω ^ b = ω ^ ω ^ b := by
obtain rfl | b0 := eq_or_ne b 0
· rw [opow_zero, opow_one] at h ⊢
- exact mul_omega a0 h
+ exact mul_omega0 a0 h
· apply le_antisymm
· obtain ⟨x, xb, ax⟩ :=
- (lt_opow_of_limit omega_ne_zero (opow_isLimit_left omega_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_omega_opow xb]
+ rw [← opow_add, add_omega0_opow xb]
· conv_lhs => rw [← one_mul (ω ^ _)]
exact mul_le_mul_right' (one_le_iff_pos.2 a0) _
-theorem principal_mul_omega_opow_opow (o : Ordinal) : Principal (· * ·) (ω ^ ω ^ o) :=
- principal_mul_iff_mul_left_eq.2 fun _ => mul_omega_opow_opow
+@[deprecated (since := "2024-09-30")]
+alias mul_omega_opow_opow := mul_omega0_opow_opow
+
+theorem principal_mul_omega0_opow_opow (o : Ordinal) : Principal (· * ·) (ω ^ ω ^ o) :=
+ principal_mul_iff_mul_left_eq.2 fun _ => mul_omega0_opow_opow
+
+@[deprecated (since := "2024-09-30")]
+alias principal_mul_omega_opow_opow := principal_mul_omega0_opow_opow
theorem principal_add_of_principal_mul_opow {o b : Ordinal} (hb : 1 < b)
(ho : Principal (· * ·) (b ^ o)) : Principal (· + ·) o := by
@@ -349,32 +414,38 @@ theorem principal_add_of_principal_mul_opow {o b : Ordinal} (hb : 1 < b)
rwa [← opow_add, opow_lt_opow_iff_right hb] at this
/-- The main characterization theorem for multiplicative principal ordinals. -/
-theorem principal_mul_iff_le_two_or_omega_opow_opow {o : Ordinal} :
+theorem principal_mul_iff_le_two_or_omega0_opow_opow {o : Ordinal} :
Principal (· * ·) o ↔ o ≤ 2 ∨ o ∈ Set.range (ω ^ ω ^ · : Ordinal → Ordinal) := by
refine ⟨fun ho => ?_, ?_⟩
· rcases le_or_lt o 2 with ho₂ | ho₂
· exact Or.inl ho₂
- · rcases principal_add_iff_zero_or_omega_opow.1 (principal_add_of_principal_mul ho ho₂.ne') with
- (rfl | ⟨a, rfl⟩)
+ · rcases principal_add_iff_zero_or_omega0_opow.1 (principal_add_of_principal_mul ho ho₂.ne')
+ with (rfl | ⟨a, rfl⟩)
· exact (Ordinal.not_lt_zero 2 ho₂).elim
- · rcases principal_add_iff_zero_or_omega_opow.1
- (principal_add_of_principal_mul_opow one_lt_omega ho) with (rfl | ⟨b, rfl⟩)
+ · rcases principal_add_iff_zero_or_omega0_opow.1
+ (principal_add_of_principal_mul_opow one_lt_omega0 ho) with (rfl | ⟨b, rfl⟩)
· simp
· exact Or.inr ⟨b, rfl⟩
· rintro (ho₂ | ⟨a, rfl⟩)
· exact principal_mul_of_le_two ho₂
- · exact principal_mul_omega_opow_opow a
+ · exact principal_mul_omega0_opow_opow a
+
+@[deprecated (since := "2024-09-30")]
+alias principal_mul_iff_le_two_or_omega_opow_opow := principal_mul_iff_le_two_or_omega0_opow_opow
+
+theorem mul_omega0_dvd {a : Ordinal} (a0 : 0 < a) (ha : a < ω) : ∀ {b}, ω ∣ b → a * b = b
+ | _, ⟨b, rfl⟩ => by rw [← mul_assoc, mul_omega0 a0 ha]
-theorem mul_omega_dvd {a : Ordinal} (a0 : 0 < a) (ha : a < ω) : ∀ {b}, ω ∣ b → a * b = b
- | _, ⟨b, rfl⟩ => by rw [← mul_assoc, mul_omega a0 ha]
+@[deprecated (since := "2024-09-30")]
+alias mul_omega_dvd := mul_omega0_dvd
theorem mul_eq_opow_log_succ {a b : Ordinal.{u}} (ha : a ≠ 0) (hb : Principal (· * ·) b)
(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]
@@ -386,16 +457,21 @@ theorem mul_eq_opow_log_succ {a b : Ordinal.{u}} (ha : a ≠ 0) (hb : Principal
/-! #### Exponential principal ordinals -/
-
-theorem principal_opow_omega : Principal (· ^ ·) ω := fun a b ha hb =>
- match a, b, lt_omega.1 ha, lt_omega.1 hb with
+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
simp_rw [← natCast_opow]
- apply nat_lt_omega
+ apply nat_lt_omega0
+
+@[deprecated (since := "2024-09-30")]
+alias principal_opow_omega := principal_opow_omega0
-theorem opow_omega {a : Ordinal} (a1 : 1 < a) (h : a < ω) : a ^ ω = ω :=
- ((opow_le_of_limit (one_le_iff_ne_zero.1 <| le_of_lt a1) omega_isLimit).2 fun _ hb =>
- (principal_opow_omega h hb).le).antisymm
+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) isLimit_omega0).2 fun _ hb =>
+ (principal_opow_omega0 h hb).le).antisymm
(right_le_opow _ a1)
+@[deprecated (since := "2024-09-30")]
+alias opow_omega := opow_omega0
+
end Ordinal
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 427fe767bdbf7..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
@@ -14,7 +14,7 @@ We prove some miscellaneous results involving the order topology of ordinals.
### Main results
-* `Ordinal.isClosed_iff_sup` / `Ordinal.isClosed_iff_bsup`: A set of ordinals is closed iff it's
+* `Ordinal.isClosed_iff_iSup` / `Ordinal.isClosed_iff_bsup`: A set of ordinals is closed iff it's
closed under suprema.
* `Ordinal.isNormal_iff_strictMono_and_continuous`: A characterization of normal ordinal
functions.
@@ -86,20 +86,20 @@ theorem mem_closure_tfae (a : Ordinal.{u}) (s : Set Ordinal) :
∃ t, t ⊆ s ∧ t.Nonempty ∧ BddAbove t ∧ sSup t = a,
∃ (o : Ordinal.{u}), o ≠ 0 ∧ ∃ (f : ∀ x < o, Ordinal),
(∀ x hx, f x hx ∈ s) ∧ bsup.{u, u} o f = a,
- ∃ (ι : Type u), Nonempty ι ∧ ∃ f : ι → Ordinal, (∀ i, f i ∈ s) ∧ sup.{u, u} f = a] := by
- tfae_have 1 → 2
- · simp only [mem_closure_iff_nhdsWithin_neBot, inter_comm s, nhdsWithin_inter', nhds_left_eq_nhds]
+ ∃ (ι : Type u), Nonempty ι ∧ ∃ f : ι → Ordinal, (∀ i, f i ∈ s) ∧ ⨆ i, f i = a] := by
+ tfae_have 1 → 2 := by
+ simp only [mem_closure_iff_nhdsWithin_neBot, inter_comm s, nhdsWithin_inter', nhds_left_eq_nhds]
exact id
tfae_have 2 → 3
- · intro h
+ | h => by
rcases (s ∩ Iic a).eq_empty_or_nonempty with he | hne
· simp [he] at h
· refine ⟨hne, (isLUB_of_mem_closure ?_ h).csSup_eq hne⟩
exact fun x hx => hx.2
tfae_have 3 → 4
- · exact fun h => ⟨_, inter_subset_left, h.1, bddAbove_Iic.mono inter_subset_right, h.2⟩
- tfae_have 4 → 5
- · rintro ⟨t, hts, hne, hbdd, rfl⟩
+ | h => ⟨_, inter_subset_left, h.1, bddAbove_Iic.mono inter_subset_right, h.2⟩
+ tfae_have 4 → 5 := by
+ rintro ⟨t, hts, hne, hbdd, rfl⟩
have hlub : IsLUB t (sSup t) := isLUB_csSup hne hbdd
let ⟨y, hyt⟩ := hne
classical
@@ -109,37 +109,46 @@ theorem mem_closure_tfae (a : Ordinal.{u}) (s : Set Ordinal) :
· refine le_antisymm (bsup_le fun x _ => ?_) (csSup_le hne fun x hx => ?_)
· split_ifs <;> exact hlub.1 ‹_›
· refine (if_pos hx).symm.trans_le (le_bsup _ _ <| (hlub.1 hx).trans_lt (lt_succ _))
- tfae_have 5 → 6
- · rintro ⟨o, h₀, f, hfs, rfl⟩
+ tfae_have 5 → 6 := by
+ rintro ⟨o, h₀, f, hfs, rfl⟩
exact ⟨_, toType_nonempty_iff_ne_zero.2 h₀, familyOfBFamily o f, fun _ => hfs _ _, rfl⟩
- tfae_have 6 → 1
- · rintro ⟨ι, hne, f, hfs, rfl⟩
- rw [sup, iSup]
+ tfae_have 6 → 1 := by
+ rintro ⟨ι, hne, f, hfs, rfl⟩
exact closure_mono (range_subset_iff.2 hfs) <| csSup_mem_closure (range_nonempty f)
(bddAbove_range.{u, u} f)
tfae_finish
+theorem mem_closure_iff_iSup :
+ a ∈ closure s ↔
+ ∃ (ι : Type u) (_ : Nonempty ι) (f : ι → Ordinal), (∀ i, f i ∈ s) ∧ ⨆ i, f i = a := by
+ apply ((mem_closure_tfae a s).out 0 5).trans
+ simp_rw [exists_prop]
+
+set_option linter.deprecated false in
+@[deprecated mem_closure_iff_iSup (since := "2024-08-27")]
theorem mem_closure_iff_sup :
a ∈ closure s ↔
- ∃ (ι : Type u) (_ : Nonempty ι) (f : ι → Ordinal), (∀ i, f i ∈ s) ∧ sup.{u, u} f = a :=
- calc
- _ ↔ (∃ (ι : Type u), Nonempty ι ∧ ∃ f, (∀ (i : ι), f i ∈ s) ∧ sup f = a) :=
- (mem_closure_tfae a s).out 0 5
- _ ↔ _ := by simp only [exists_prop]
+ ∃ (ι : Type u) (_ : Nonempty ι) (f : ι → Ordinal), (∀ i, f i ∈ s) ∧ sup f = a :=
+ mem_closure_iff_iSup
+theorem mem_iff_iSup_of_isClosed (hs : IsClosed s) :
+ a ∈ s ↔ ∃ (ι : Type u) (_hι : Nonempty ι) (f : ι → Ordinal),
+ (∀ i, f i ∈ s) ∧ ⨆ i, f i = a := by
+ rw [← mem_closure_iff_iSup, hs.closure_eq]
+
+set_option linter.deprecated false in
+@[deprecated mem_iff_iSup_of_isClosed (since := "2024-08-27")]
theorem mem_closed_iff_sup (hs : IsClosed s) :
a ∈ s ↔ ∃ (ι : Type u) (_hι : Nonempty ι) (f : ι → Ordinal),
- (∀ i, f i ∈ s) ∧ sup.{u, u} f = a := by
- rw [← mem_closure_iff_sup, hs.closure_eq]
+ (∀ i, f i ∈ s) ∧ sup f = a :=
+ mem_iff_iSup_of_isClosed hs
theorem mem_closure_iff_bsup :
a ∈ closure s ↔
∃ (o : Ordinal) (_ho : o ≠ 0) (f : ∀ a < o, Ordinal),
- (∀ i hi, f i hi ∈ s) ∧ bsup.{u, u} o f = a :=
- calc
- _ ↔ ∃ o, o ≠ 0 ∧ ∃ f, (∀ (x : Ordinal.{u}) (hx : x < o), f x hx ∈ s) ∧ o.bsup f = a :=
- (mem_closure_tfae a s).out 0 4
- _ ↔ _ := by simp only [exists_prop]
+ (∀ i hi, f i hi ∈ s) ∧ bsup.{u, u} o f = a := by
+ apply ((mem_closure_tfae a s).out 0 4).trans
+ simp_rw [exists_prop]
theorem mem_closed_iff_bsup (hs : IsClosed s) :
a ∈ s ↔
@@ -147,9 +156,20 @@ theorem mem_closed_iff_bsup (hs : IsClosed s) :
(∀ i hi, f i hi ∈ s) ∧ bsup.{u, u} o f = a := by
rw [← mem_closure_iff_bsup, hs.closure_eq]
+theorem isClosed_iff_iSup :
+ IsClosed s ↔
+ ∀ {ι : Type u}, Nonempty ι → ∀ f : ι → Ordinal, (∀ i, f i ∈ s) → ⨆ i, f i ∈ s := by
+ use fun hs ι hι f hf => (mem_iff_iSup_of_isClosed hs).2 ⟨ι, hι, f, hf, rfl⟩
+ rw [← closure_subset_iff_isClosed]
+ intro h x hx
+ rcases mem_closure_iff_iSup.1 hx with ⟨ι, hι, f, hf, rfl⟩
+ exact h hι f hf
+
+set_option linter.deprecated false in
+@[deprecated mem_iff_iSup_of_isClosed (since := "2024-08-27")]
theorem isClosed_iff_sup :
IsClosed s ↔
- ∀ {ι : Type u}, Nonempty ι → ∀ f : ι → Ordinal, (∀ i, f i ∈ s) → sup.{u, u} f ∈ s := by
+ ∀ {ι : Type u}, Nonempty ι → ∀ f : ι → Ordinal, (∀ i, f i ∈ s) → ⨆ i, f i ∈ s := by
use fun hs ι hι f hf => (mem_closed_iff_sup hs).2 ⟨ι, hι, f, hf, rfl⟩
rw [← closure_subset_iff_isClosed]
intro h x hx
@@ -160,10 +180,10 @@ theorem isClosed_iff_bsup :
IsClosed s ↔
∀ {o : Ordinal}, o ≠ 0 → ∀ f : ∀ a < o, Ordinal,
(∀ i hi, f i hi ∈ s) → bsup.{u, u} o f ∈ s := by
- rw [isClosed_iff_sup]
+ rw [isClosed_iff_iSup]
refine ⟨fun H o ho f hf => H (toType_nonempty_iff_ne_zero.2 ho) _ ?_, fun H ι hι f hf => ?_⟩
· exact fun i => hf _ _
- · rw [← bsup_eq_sup]
+ · rw [← Ordinal.sup, ← bsup_eq_sup]
apply H (type_ne_zero_iff_nonempty.2 hι)
exact fun i hi => hf _
@@ -194,32 +214,31 @@ theorem isNormal_iff_strictMono_and_continuous (f : Ordinal.{u} → Ordinal.{u})
rintro ⟨h, h'⟩
refine ⟨h, fun o ho a h => ?_⟩
suffices o ∈ f ⁻¹' Set.Iic a from Set.mem_preimage.1 this
- rw [mem_closed_iff_sup (IsClosed.preimage h' (@isClosed_Iic _ _ _ _ a))]
+ rw [mem_iff_iSup_of_isClosed (IsClosed.preimage h' (@isClosed_Iic _ _ _ _ a))]
exact
⟨_, toType_nonempty_iff_ne_zero.2 ho.1, typein (· < ·), fun i => h _ (typein_lt_self i),
sup_typein_limit ho.2⟩
-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_sup.2 fun {ι} hι f hf => ?_, fun h =>
+ ⟨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⟩
- suffices enumOrd s (sup.{u, u} g) = sup.{u, u} f by
+ · 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.sup.{u, u, u} _ h ι g hι]
+ 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
@@ -227,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/Basic.lean b/Mathlib/SetTheory/Surreal/Basic.lean
index bbb97f8232f9c..6b466f6a32173 100644
--- a/Mathlib/SetTheory/Surreal/Basic.lean
+++ b/Mathlib/SetTheory/Surreal/Basic.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2019 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Scott Morrison
+Authors: Mario Carneiro, Kim Morrison
-/
import Mathlib.Algebra.Order.Hom.Monoid
import Mathlib.SetTheory.Game.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/Surreal/Multiplication.lean b/Mathlib/SetTheory/Surreal/Multiplication.lean
index 29f0f225bedb8..581ee2b7acc94 100644
--- a/Mathlib/SetTheory/Surreal/Multiplication.lean
+++ b/Mathlib/SetTheory/Surreal/Multiplication.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2024 Theodore Hwa. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Scott Morrison, Violeta Hernández Palacios, Junyan Xu, Theodore Hwa
+Authors: Mario Carneiro, Kim Morrison, Violeta Hernández Palacios, Junyan Xu, Theodore Hwa
-/
import Mathlib.Logic.Hydra
import Mathlib.SetTheory.Surreal.Basic
diff --git a/Mathlib/SetTheory/ZFC/Basic.lean b/Mathlib/SetTheory/ZFC/Basic.lean
index a556cdab50f44..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
@@ -834,6 +831,10 @@ theorem mem_sep {p : ZFSet.{u} → Prop} {x y : ZFSet.{u}} :
Quotient.inductionOn₂ x y fun _ _ =>
PSet.mem_sep (p := p ∘ mk) fun _ _ h => (Quotient.sound h).subst
+@[simp]
+theorem sep_empty (p : ZFSet → Prop) : (∅ : ZFSet).sep p = ∅ :=
+ (eq_empty _).mpr fun _ h ↦ not_mem_empty _ (mem_sep.mp h).1
+
@[simp]
theorem toSet_sep (a : ZFSet) (p : ZFSet → Prop) :
(ZFSet.sep p a).toSet = { x ∈ a.toSet | p x } := by
@@ -886,9 +887,8 @@ def sUnion : ZFSet → ZFSet :=
prefix:110 "⋃₀ " => ZFSet.sUnion
/-- The intersection operator, the collection of elements in all of the elements of a ZFC set. We
-special-case `⋂₀ ∅ = ∅`. -/
-noncomputable def sInter (x : ZFSet) : ZFSet := by
- classical exact if h : x.Nonempty then ZFSet.sep (fun y => ∀ z ∈ x, y ∈ z) h.some else ∅
+define `⋂₀ ∅ = ∅`. -/
+def sInter (x : ZFSet) : ZFSet := (⋃₀ x).sep (fun y => ∀ z ∈ x, y ∈ z)
@[inherit_doc]
prefix:110 "⋂₀ " => ZFSet.sInter
@@ -899,9 +899,12 @@ theorem mem_sUnion {x y : ZFSet.{u}} : y ∈ ⋃₀ x ↔ ∃ z ∈ x, y ∈ z :
⟨fun ⟨z, h⟩ => ⟨⟦z⟧, h⟩, fun ⟨z, h⟩ => Quotient.inductionOn z (fun z h => ⟨z, h⟩) h⟩
theorem mem_sInter {x y : ZFSet} (h : x.Nonempty) : y ∈ ⋂₀ x ↔ ∀ z ∈ x, y ∈ z := by
- rw [sInter, dif_pos h]
- simp only [mem_toSet, mem_sep, and_iff_right_iff_imp]
- exact fun H => H _ h.some_mem
+ unfold sInter
+ simp only [and_iff_right_iff_imp, mem_sep]
+ intro mem
+ apply mem_sUnion.mpr
+ replace ⟨s, h⟩ := h
+ exact ⟨_, h, mem _ h⟩
@[simp]
theorem sUnion_empty : ⋃₀ (∅ : ZFSet.{u}) = ∅ := by
@@ -909,7 +912,7 @@ theorem sUnion_empty : ⋃₀ (∅ : ZFSet.{u}) = ∅ := by
simp
@[simp]
-theorem sInter_empty : ⋂₀ (∅ : ZFSet) = ∅ := dif_neg <| by simp
+theorem sInter_empty : ⋂₀ (∅ : ZFSet) = ∅ := by simp [sInter]
theorem mem_of_mem_sInter {x y z : ZFSet} (hy : y ∈ ⋂₀ x) (hz : z ∈ x) : y ∈ z := by
rcases eq_empty_or_nonempty x with (rfl | hx)
@@ -1011,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 =>
@@ -1120,7 +1119,7 @@ theorem pair_injective : Function.Injective2 pair := fun x x' y y' H => by
rw [mem_singleton.mp m]
have he : x = y → y = y' := by
rintro rfl
- cases' (ae {x, y'}).2 (by simp only [eq_self_iff_true, or_true_iff]) with xy'x xy'xx
+ cases' (ae {x, y'}).2 (by simp only [eq_self_iff_true, or_true]) with xy'x xy'xx
· rw [eq_comm, ← mem_singleton, ← xy'x, mem_pair]
exact Or.inr rfl
· simpa [eq_comm] using (ZFSet.ext_iff.1 xy'xx y').1 (by simp)
@@ -1282,7 +1281,7 @@ theorem not_empty_hom (x : ZFSet.{u}) : ¬(∅ : Class.{u}) x :=
@[simp]
theorem mem_univ {A : Class.{u}} : A ∈ univ.{u} ↔ ∃ x : ZFSet.{u}, ↑x = A :=
- exists_congr fun _ => and_true_iff _
+ exists_congr fun _ => iff_of_eq (and_true _)
@[simp]
theorem mem_univ_hom (x : ZFSet.{u}) : univ.{u} x :=
@@ -1304,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
@@ -1333,7 +1328,7 @@ def congToClass (x : Set Class.{u}) : Class.{u} :=
@[simp]
theorem congToClass_empty : congToClass ∅ = ∅ := by
ext z
- simp only [congToClass, not_empty_hom, iff_false_iff]
+ simp only [congToClass, not_empty_hom, iff_false]
exact Set.not_mem_empty z
/-- Convert a class into a conglomerate (a collection of classes) -/
@@ -1391,7 +1386,7 @@ theorem coe_sep (p : Class.{u}) (x : ZFSet.{u}) :
@[simp, norm_cast]
theorem coe_empty : ↑(∅ : ZFSet.{u}) = (∅ : Class.{u}) :=
- ext fun y => iff_false_iff.2 <| ZFSet.not_mem_empty y
+ ext fun y => iff_false _ ▸ ZFSet.not_mem_empty y
@[simp, norm_cast]
theorem coe_insert (x y : ZFSet.{u}) : ↑(insert x y) = @insert ZFSet.{u} Class.{u} _ x y :=
@@ -1558,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 6f530248ce6e9..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.sup_le _) <;> intro h
+ apply (le_of_forall_lt _).antisymm (Ordinal.iSup_le _) <;> intro h
· rw [lt_lift_iff]
- rintro ⟨o, rfl, h⟩
- simpa [Ordinal.lt_sup] 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.sup_le _) <;> intro h
+ apply (le_of_forall_lt _).antisymm (Ordinal.iSup_le _) <;> intro h
· rw [lt_lift_iff]
- rintro ⟨o, rfl, h⟩
- simpa [Ordinal.lt_sup] 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
new file mode 100644
index 0000000000000..5226d253de305
--- /dev/null
+++ b/Mathlib/Std/Data/HashMap.lean
@@ -0,0 +1,23 @@
+/-
+Copyright (c) 2024 Lean FRO. All rights reserved.
+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
+
+These will be reimplemented in the Lean standard library.
+-/
+
+namespace Std.HashMap
+
+variable {α β γ : Type _} [BEq α] [Hashable α]
+
+/-- Apply a function to the values of a hash map. -/
+def mapVal (f : α → β → γ) (m : HashMap α β) : HashMap α γ :=
+ m.fold (fun acc k v => acc.insert k (f k v)) HashMap.empty
+
+end Std.HashMap
diff --git a/Mathlib/Tactic.lean b/Mathlib/Tactic.lean
index 5a1021dc9c802..a3fe4d46b7e75 100644
--- a/Mathlib/Tactic.lean
+++ b/Mathlib/Tactic.lean
@@ -1,5 +1,6 @@
import Mathlib.Tactic.Abel
import Mathlib.Tactic.AdaptationNote
+import Mathlib.Tactic.Algebraize
import Mathlib.Tactic.ApplyAt
import Mathlib.Tactic.ApplyCongr
import Mathlib.Tactic.ApplyFun
@@ -22,13 +23,25 @@ import Mathlib.Tactic.CancelDenoms.Core
import Mathlib.Tactic.Cases
import Mathlib.Tactic.CasesM
import Mathlib.Tactic.CategoryTheory.BicategoricalComp
+import Mathlib.Tactic.CategoryTheory.Bicategory.Basic
+import Mathlib.Tactic.CategoryTheory.Bicategory.Datatypes
+import Mathlib.Tactic.CategoryTheory.Bicategory.Normalize
+import Mathlib.Tactic.CategoryTheory.Bicategory.PureCoherence
import Mathlib.Tactic.CategoryTheory.BicategoryCoherence
import Mathlib.Tactic.CategoryTheory.Coherence
+import Mathlib.Tactic.CategoryTheory.Coherence.Basic
+import Mathlib.Tactic.CategoryTheory.Coherence.Datatypes
+import Mathlib.Tactic.CategoryTheory.Coherence.Normalize
+import Mathlib.Tactic.CategoryTheory.Coherence.PureCoherence
import Mathlib.Tactic.CategoryTheory.Elementwise
-import Mathlib.Tactic.CategoryTheory.Monoidal
+import Mathlib.Tactic.CategoryTheory.Monoidal.Basic
+import Mathlib.Tactic.CategoryTheory.Monoidal.Datatypes
+import Mathlib.Tactic.CategoryTheory.Monoidal.Normalize
+import Mathlib.Tactic.CategoryTheory.Monoidal.PureCoherence
import Mathlib.Tactic.CategoryTheory.MonoidalComp
import Mathlib.Tactic.CategoryTheory.Reassoc
import Mathlib.Tactic.CategoryTheory.Slice
+import Mathlib.Tactic.CategoryTheory.ToApp
import Mathlib.Tactic.Change
import Mathlib.Tactic.Check
import Mathlib.Tactic.Choose
@@ -49,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
@@ -68,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
@@ -84,6 +100,7 @@ import Mathlib.Tactic.FunProp.ToBatteries
import Mathlib.Tactic.FunProp.Types
import Mathlib.Tactic.GCongr
import Mathlib.Tactic.GCongr.Core
+import Mathlib.Tactic.GCongr.CoreAttrs
import Mathlib.Tactic.GCongr.ForwardAttr
import Mathlib.Tactic.Generalize
import Mathlib.Tactic.GeneralizeProofs
@@ -118,15 +135,20 @@ import Mathlib.Tactic.Linarith.Preprocessing
import Mathlib.Tactic.Linarith.Verification
import Mathlib.Tactic.LinearCombination
import Mathlib.Tactic.LinearCombination'
+import Mathlib.Tactic.LinearCombination.Lemmas
import Mathlib.Tactic.Linter
import Mathlib.Tactic.Linter.AdmitLinter
+import Mathlib.Tactic.Linter.DocPrime
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
@@ -136,6 +158,7 @@ import Mathlib.Tactic.Measurability.Init
import Mathlib.Tactic.MinImports
import Mathlib.Tactic.MkIffOfInductiveProp
import Mathlib.Tactic.ModCases
+import Mathlib.Tactic.Module
import Mathlib.Tactic.Monotonicity
import Mathlib.Tactic.Monotonicity.Attr
import Mathlib.Tactic.Monotonicity.Basic
@@ -159,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
@@ -183,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
@@ -191,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/Abel.lean b/Mathlib/Tactic/Abel.lean
index a0c5c9ec31aff..5ccbf7d2844fd 100644
--- a/Mathlib/Tactic/Abel.lean
+++ b/Mathlib/Tactic/Abel.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro, Scott Morrison
+Authors: Mario Carneiro, Kim Morrison
-/
import Mathlib.Tactic.NormNum.Basic
import Mathlib.Tactic.TryThis
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
new file mode 100644
index 0000000000000..1218a802e04ae
--- /dev/null
+++ b/Mathlib/Tactic/Algebraize.lean
@@ -0,0 +1,286 @@
+/-
+Copyright (c) 2024 Calle Sönne. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Johan Commelin, Nick Kuhn, Arend Mellendijk, Christian Merten, Calle Sönne, Adam Topaz
+-/
+
+import Mathlib.Algebra.Algebra.Tower
+
+/-!
+
+## Algebraize tactic
+
+This file defines the `algebraize` tactic. The basic functionality of this tactic is to
+automatically add `Algebra` instances given `RingHom`s. For example, `algebraize [f, g]` where
+`f : A →+* B` and `g : B →+* C` are `RingHom`s, will add the instances `Algebra A B` and
+`Algebra B C` corresponding to these `RingHom`s.
+
+## Further functionality
+
+When given a composition of `RingHom`s, e.g. `algebraize [g.comp f]`, the tactic will also try to
+add the instance `IsScalarTower A B C` if possible.
+
+After having added suitable `Algebra` and `IsScalarTower` instances, the tactic will search through
+the local context for `RingHom` properties that can be converted to properties of the corresponding
+`Algebra`. For example, given `f : A →+* B` and `hf : f.FiniteType`, then `algebraize [f]` will add
+the instance `Algebra A B` and the corresponding property `Algebra.FiniteType A B`. The tactic knows
+which `RingHom` properties have a corresponding `Algebra` property through the `algebraize`
+attribute.
+
+## Algebraize attribute
+
+The `algebraize` attribute is used to tag `RingHom` properties that can be converted to `Algebra`
+properties. It assumes that the tagged declaration has a name of the form `RingHom.Property` and
+that the corresponding `Algebra` property has the name `Algebra.Property`.
+
+If not, the `Name` of the corresponding algebra property can be provided as optional argument. The
+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. 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:
+```
+@[algebraize]
+def RingHom.FiniteType (f : A →+* B) : Prop :=
+ @Algebra.FiniteType A B _ _ f.toAlgebra
+```
+An example when the `Name` is provided (as the `Algebra` does not have the expected name):
+```
+@[algebraize Module.Finite]
+def RingHom.Finite (f : A →+* B) : Prop :=
+ letI : Algebra A B := f.toAlgebra
+ Module.Finite A B
+```
+An example with a constructor as parameter (as the two properties are not definitonally the same):
+```
+@[algebraize Algebra.Flat.out]
+class RingHom.Flat {R : Type u} {S : Type v} [CommRing R] [CommRing S] (f : R →+* S) : Prop where
+ out : f.toAlgebra.Flat := by infer_instance
+```
+
+## algebraize_only
+
+To avoid searching through the local context and adding corresponding `Algebra` properties, use
+`algebraize_only` which only adds `Algebra` and `IsScalarTower` instances.
+-/
+
+open Lean Elab Tactic Term Meta
+
+namespace Lean.Attr
+
+/-- Function that extracts the name of the corresponding `Algebra` property from a `RingHom`
+property that has been tagged with the `algebraize` attribute. This is done by either returning the
+parameter of the attribute, or by assuming that the tagged declaration has name `RingHom.Property`
+and then returning `Algebra.Property`. -/
+def algebraizeGetParam (thm : Name) (stx : Syntax) : AttrM Name := do
+ match stx with
+ | `(attr| algebraize $name:ident) => return name.getId
+ /- If no argument is provided, assume `thm` is of the form `RingHom.Property`,
+ and return `Algebra.Property` -/
+ | `(attr| algebraize) =>
+ match thm with
+ | .str `RingHom t => return .str `Algebra t
+ | _ =>
+ throwError "theorem name must be of the form `RingHom.Property` if no argument is provided"
+ | _ => throwError "unexpected algebraize argument"
+
+/-- A user attribute that is used to tag `RingHom` properties that can be converted to `Algebra`
+properties. Using an (optional) parameter, it will also generate a `Name` of a declaration which
+will help the `algebraize` tactic access the corresponding `Algebra` property.
+
+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 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
+`Algebra.Property`. The attribute then returns `Algebra.Property` (so assume case 1 above). -/
+initialize algebraizeAttr : ParametricAttribute Name ←
+ registerParametricAttribute {
+ name := `algebraize,
+ descr :=
+"Tag that lets the `algebraize` tactic know which `Algebra` property corresponds to this `RingHom`
+property.",
+ getParam := algebraizeGetParam }
+
+end Lean.Attr
+
+namespace Mathlib.Tactic
+
+namespace Algebraize
+
+/-- Given an expression `f` of type `RingHom A B` where `A` and `B` are commutative semirings,
+this function adds the instance `Algebra A B` to the context (if it does not already exist).
+
+This function also requries the type of `f`, given by the parameter `ft`. The reason this is done
+(even though `ft` can be inferred from `f`) is to avoid recomputing `ft` in the `algebraize` tactic,
+as when `algebraize` calls `addAlgebraInstanceFromRingHom` it has already computed `ft`. -/
+def addAlgebraInstanceFromRingHom (f ft : Expr) : TacticM Unit := withMainContext do
+ let (_, l) := ft.getAppFnArgs
+ -- The type of the corresponding algebra instance
+ let alg ← mkAppOptM ``Algebra #[l[0]!, l[1]!, none, none]
+ -- If the instance already exists, we do not do anything
+ unless (← synthInstance? alg).isSome do
+ liftMetaTactic fun mvarid => do
+ let nm ← mkFreshBinderNameForTactic `algInst
+ let mvar ← mvarid.define nm alg (← mkAppM ``RingHom.toAlgebra #[f])
+ let (_, mvar) ← mvar.intro1P
+ return [mvar]
+
+/-- Given an expression `g.comp f` which is the composition of two `RingHom`s, this function adds
+the instance `IsScalarTower A B C` to the context (if it does not already exist). -/
+def addIsScalarTowerInstanceFromRingHomComp (fn : Expr) : TacticM Unit := withMainContext do
+ let (_, l) := fn.getAppFnArgs
+ let tower ← mkAppOptM ``IsScalarTower #[l[0]!, l[1]!, l[2]!, none, none, none]
+ -- If the instance already exists, we do not do anything
+ unless (← synthInstance? tower).isSome do
+ liftMetaTactic fun mvarid => do
+ let nm ← mkFreshBinderNameForTactic `scalarTowerInst
+ let h ← mkFreshExprMVar (← mkAppM ``Eq #[
+ ← mkAppOptM ``algebraMap #[l[0]!, l[2]!, none, none, none],
+ ← mkAppM ``RingHom.comp #[
+ ← mkAppOptM ``algebraMap #[l[1]!, l[2]!, none, none, none],
+ ← mkAppOptM ``algebraMap #[l[0]!, l[1]!, none, none, none]]])
+ -- Note: this could fail, but then `algebraize` will just continue, and won't add this instance
+ h.mvarId!.refl
+ let val ← mkAppOptM ``IsScalarTower.of_algebraMap_eq'
+ #[l[0]!, l[1]!, l[2]!, none, none, none, none, none, none, h]
+ let mvar ← mvarid.define nm tower val
+ let (_, mvar) ← mvar.intro1P
+ return [mvar]
+
+/-- This function takes an array of expressions `t`, all of which are assumed to be `RingHom`s,
+and searches through the local context to find any additional properties of these `RingHoms`, after
+which it tries to add the corresponding `Algebra` properties to the context. It only looks for
+properties that have been tagged with the `algebraize` attribute, and uses this tag to find the
+corresponding `Algebra` property. -/
+def addProperties (t : Array Expr) : TacticM Unit := withMainContext do
+ let ctx ← getLCtx
+ ctx.forM fun decl => do
+ if decl.isImplementationDetail then return
+ 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 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]!
+ -- Check that `f` appears in the list of functions given to `algebraize`
+ if ¬ (← t.anyM (Meta.isDefEq · f)) then return
+
+ let cinfo ← getConstInfo p
+ let n ← getExpectedNumArgs cinfo.type
+ let pargs := Array.mkArray n (none : Option Expr)
+ /- 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. -/
+ 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.note nm decl.toExpr tp
+ return [mvar]
+ /- 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
+ let tp ← inferType val
+ unless (← synthInstance? tp).isSome do
+ liftMetaTactic fun mvarid => do
+ let nm ← mkFreshBinderNameForTactic `algebraizeInst
+ let (_, mvar) ← mvarid.note nm val
+ return [mvar]
+ | none => return
+
+/-- Configuration for `algebraize`. -/
+structure Config where
+ /-- If true (default), the tactic will search the local context for `RingHom` properties
+ that can be converted to `Algebra` properties. -/
+ properties : Bool := true
+deriving Inhabited
+
+/-- Function elaborating `Algebraize.Config`. -/
+declare_config_elab elabAlgebraizeConfig Algebraize.Config
+
+end Algebraize
+
+open Algebraize Lean.Parser.Tactic
+
+/-- A list of terms passed to `algebraize` as argument. -/
+syntax algebraizeTermSeq := " [" withoutPosition(term,*,?) "]"
+
+/-- Tactic that, given `RingHom`s, adds the corresponding `Algebra` and (if possible)
+`IsScalarTower` instances, as well as `Algebra` corresponding to `RingHom` properties available
+as hypotheses.
+
+Example: given `f : A →+* B` and `g : B →+* C`, and `hf : f.FiniteType`, `algebraize [f, g]` will
+add the instances `Algebra A B`, `Algebra B C`, and `Algebra.FiniteType A B`.
+
+See the `algebraize` tag for instructions on what properties can be added.
+
+The tactic also comes with a configuration option `properties`. If set to `true` (default), the
+tactic searches through the local context for `RingHom` properties that can be converted to
+`Algebra` properties. The macro `algebraize_only` calls
+`algebraize (config := {properties := false})`,
+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) => withMainContext do
+ let cfg ← elabAlgebraizeConfig (mkOptionalNode config)
+ let t ← match args with
+ | `(algebraizeTermSeq| [$rs,*]) => rs.getElems.mapM fun i => Term.elabTerm i none
+ | _ =>
+ throwError ""
+ if t.size == 0 then
+ logWarningAt args "`algebraize []` without arguments has no effect!"
+ -- We loop through the given terms and add algebra instances
+ for f in t do
+ let ft ← inferType f
+ match ft.getAppFn with
+ | Expr.const ``RingHom _ => addAlgebraInstanceFromRingHom f ft
+ | _ => throwError m!"{f} is not of type `RingHom`"
+ -- After having added the algebra instances we try to add scalar tower instances
+ for f in t do
+ match f.getAppFn with
+ | Expr.const ``RingHom.comp _ =>
+ try addIsScalarTowerInstanceFromRingHomComp f
+ catch _ => continue
+ | _ => continue
+
+ -- Search through the local context to find other instances of algebraize
+ if cfg.properties then
+ addProperties t
+ | `(tactic| algebraize $[$config]?) => do
+ throwError "`algebraize` expects a list of arguments: `algebraize [f]`"
+
+/-- Version of `algebraize`, which only adds `Algebra` instances and `IsScalarTower` instances,
+but does not try to add any instances about any properties tagged with
+`@[algebraize]`, like for example `Finite` or `IsIntegral`. -/
+syntax "algebraize_only" (ppSpace algebraizeTermSeq)? : tactic
+
+macro_rules
+ | `(tactic| algebraize_only $args) =>
+ `(tactic| algebraize (config := {properties := false}) $args)
+ | `(tactic| algebraize_only) =>
+ `(tactic| algebraize (config := {properties := false}))
+
+end Mathlib.Tactic
diff --git a/Mathlib/Tactic/ApplyCongr.lean b/Mathlib/Tactic/ApplyCongr.lean
index f2ae29d7ee7c3..ee79d93eba02a 100644
--- a/Mathlib/Tactic/ApplyCongr.lean
+++ b/Mathlib/Tactic/ApplyCongr.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Lucas Allen, Scott Morrison
+Authors: Lucas Allen, Kim Morrison
-/
import Mathlib.Tactic.Conv
diff --git a/Mathlib/Tactic/ApplyFun.lean b/Mathlib/Tactic/ApplyFun.lean
index e9aa791b2eb59..2b55685474bb7 100644
--- a/Mathlib/Tactic/ApplyFun.lean
+++ b/Mathlib/Tactic/ApplyFun.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2019 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Keeley Hoek, Patrick Massot, Scott Morrison
+Authors: Keeley Hoek, Patrick Massot, Kim Morrison
-/
import Mathlib.Lean.Expr.Basic
import Mathlib.Order.Monotone.Basic
diff --git a/Mathlib/Tactic/Attr/Register.lean b/Mathlib/Tactic/Attr/Register.lean
index 98101a86367d7..cc80f10b4abbf 100644
--- a/Mathlib/Tactic/Attr/Register.lean
+++ b/Mathlib/Tactic/Attr/Register.lean
@@ -84,3 +84,6 @@ register_simp_attr nontriviality
/-- A stub attribute for `is_poly`. -/
register_label_attr is_poly
+
+/-- A simp set for the `fin_omega` wrapper around `omega`. -/
+register_simp_attr fin_omega
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/Bound/Attribute.lean b/Mathlib/Tactic/Bound/Attribute.lean
index a33e962df9870..83685e229820e 100644
--- a/Mathlib/Tactic/Bound/Attribute.lean
+++ b/Mathlib/Tactic/Bound/Attribute.lean
@@ -6,6 +6,7 @@ Authors: Geoffrey Irving
import Mathlib.Algebra.Group.ZeroOne
import Mathlib.Tactic.Bound.Init
import Qq
+import Aesop
/-!
# The `bound` attribute
diff --git a/Mathlib/Tactic/CC.lean b/Mathlib/Tactic/CC.lean
index 97367e1d058d8..e256310915550 100644
--- a/Mathlib/Tactic/CC.lean
+++ b/Mathlib/Tactic/CC.lean
@@ -125,7 +125,7 @@ def proofFor (ccs : CCState) (e : Expr) : MetaM Expr := do
def refutationFor (ccs : CCState) (e : Expr) : MetaM Expr := do
let (some r, _) ← CCM.run (CCM.getEqProof e (.const ``False [])) { ccs with }
| throwError "CCState.refutationFor failed to build proof"
- mkAppM ``not_of_eq_false #[r]
+ mkAppM ``of_eq_false #[r]
/-- If the given state is inconsistent, return a proof for `False`. Otherwise fail. -/
def proofForFalse (ccs : CCState) : MetaM Expr := do
diff --git a/Mathlib/Tactic/CC/Addition.lean b/Mathlib/Tactic/CC/Addition.lean
index 3c63cb79c8fa9..51dcb46a44da0 100644
--- a/Mathlib/Tactic/CC/Addition.lean
+++ b/Mathlib/Tactic/CC/Addition.lean
@@ -842,7 +842,7 @@ def dbgTraceACState : CCM Unit := do
def mkACProof (e₁ e₂ : Expr) : MetaM Expr := do
let eq ← mkEq e₁ e₂
let .mvar m ← mkFreshExprSyntheticOpaqueMVar eq | failure
- AC.rewriteUnnormalized m
+ AC.rewriteUnnormalizedRefl m
let pr ← instantiateMVars (.mvar m)
mkExpectedTypeHint pr eq
@@ -1470,7 +1470,8 @@ partial def propagateEqUp (e : Expr) : CCM Unit := do
if ← isInterpretedValue ra <&&> isInterpretedValue rb <&&>
pure (ra.int?.isNone || ra.int? != rb.int?) then
raNeRb := some
- (Expr.app (.proj ``Iff 0 (← mkAppM ``bne_iff_ne #[ra, rb])) (← mkEqRefl (.const ``true [])))
+ (Expr.app (.proj ``Iff 0 (← mkAppOptM ``bne_iff_ne #[none, none, none, ra, rb]))
+ (← mkEqRefl (.const ``true [])))
else
if let some c₁ ← isConstructorApp? ra then
if let some c₂ ← isConstructorApp? rb then
@@ -1808,7 +1809,8 @@ def propagateValueInconsistency (e₁ e₂ : Expr) : CCM Unit := do
let some eqProof ← getEqProof e₁ e₂ | failure
let trueEqFalse ← mkEq (.const ``True []) (.const ``False [])
let neProof :=
- Expr.app (.proj ``Iff 0 (← mkAppM ``bne_iff_ne #[e₁, e₂])) (← mkEqRefl (.const ``true []))
+ Expr.app (.proj ``Iff 0 (← mkAppOptM ``bne_iff_ne #[none, none, none, e₁, e₂]))
+ (← mkEqRefl (.const ``true []))
let H ← mkAbsurd trueEqFalse eqProof neProof
pushEq (.const ``True []) (.const ``False []) H
@@ -1848,7 +1850,7 @@ def propagateEqDown (e : Expr) : CCM Unit := do
/-- Propagate equality from `¬∃ x, p x` to `∀ x, ¬p x`. -/
def propagateExistsDown (e : Expr) : CCM Unit := do
if ← isEqFalse e then
- let hNotE ← mkAppM ``not_of_eq_false #[← getEqFalseProof e]
+ let hNotE ← mkAppM ``of_eq_false #[← getEqFalseProof e]
let (all, hAll) ← e.forallNot_of_notExists hNotE
internalizeCore all none
pushEq all (.const ``True []) (← mkEqTrue hAll)
diff --git a/Mathlib/Tactic/CC/Lemmas.lean b/Mathlib/Tactic/CC/Lemmas.lean
index cd6fc4d14d2c8..1ebda77fc703d 100644
--- a/Mathlib/Tactic/CC/Lemmas.lean
+++ b/Mathlib/Tactic/CC/Lemmas.lean
@@ -4,47 +4,47 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
-import Mathlib.Init.Logic
+import Mathlib.Init
/-! Lemmas use by the congruence closure module -/
namespace Mathlib.Tactic.CC
theorem iff_eq_of_eq_true_left {a b : Prop} (h : a = True) : (a ↔ b) = b :=
- h.symm ▸ propext true_iff_iff
+ h.symm ▸ true_iff _
theorem iff_eq_of_eq_true_right {a b : Prop} (h : b = True) : (a ↔ b) = a :=
- h.symm ▸ propext iff_true_iff
+ h.symm ▸ iff_true _
theorem iff_eq_true_of_eq {a b : Prop} (h : a = b) : (a ↔ b) = True :=
- h ▸ propext (iff_self_iff _)
+ h ▸ iff_self _
theorem and_eq_of_eq_true_left {a b : Prop} (h : a = True) : (a ∧ b) = b :=
- h.symm ▸ propext (true_and_iff _)
+ h.symm ▸ true_and _
theorem and_eq_of_eq_true_right {a b : Prop} (h : b = True) : (a ∧ b) = a :=
- h.symm ▸ propext (and_true_iff _)
+ h.symm ▸ and_true _
theorem and_eq_of_eq_false_left {a b : Prop} (h : a = False) : (a ∧ b) = False :=
- h.symm ▸ propext (false_and_iff _)
+ h.symm ▸ false_and _
theorem and_eq_of_eq_false_right {a b : Prop} (h : b = False) : (a ∧ b) = False :=
- h.symm ▸ propext (and_false_iff _)
+ h.symm ▸ and_false _
theorem and_eq_of_eq {a b : Prop} (h : a = b) : (a ∧ b) = a :=
h ▸ propext and_self_iff
theorem or_eq_of_eq_true_left {a b : Prop} (h : a = True) : (a ∨ b) = True :=
- h.symm ▸ propext (true_or_iff _)
+ h.symm ▸ true_or _
theorem or_eq_of_eq_true_right {a b : Prop} (h : b = True) : (a ∨ b) = True :=
- h.symm ▸ propext (or_true_iff _)
+ h.symm ▸ or_true _
theorem or_eq_of_eq_false_left {a b : Prop} (h : a = False) : (a ∨ b) = b :=
- h.symm ▸ propext (false_or_iff _)
+ h.symm ▸ false_or _
theorem or_eq_of_eq_false_right {a b : Prop} (h : b = False) : (a ∨ b) = a :=
- h.symm ▸ propext (or_false_iff _)
+ h.symm ▸ or_false _
theorem or_eq_of_eq {a b : Prop} (h : a = b) : (a ∨ b) = a :=
h ▸ propext or_self_iff
@@ -88,7 +88,7 @@ theorem if_eq_of_eq_true {c : Prop} [d : Decidable c] {α : Sort u} (t e : α) (
theorem if_eq_of_eq_false {c : Prop} [d : Decidable c] {α : Sort u} (t e : α) (h : c = False) :
@ite α c d t e = e :=
- if_neg (not_of_eq_false h)
+ if_neg (of_eq_false h)
theorem if_eq_of_eq (c : Prop) [d : Decidable c] {α : Sort u} {t e : α} (h : t = e) :
@ite α c d t e = t :=
diff --git a/Mathlib/Tactic/CategoryTheory/BicategoricalComp.lean b/Mathlib/Tactic/CategoryTheory/BicategoricalComp.lean
index ec242f570e977..a43d5c5ea901b 100644
--- a/Mathlib/Tactic/CategoryTheory/BicategoricalComp.lean
+++ b/Mathlib/Tactic/CategoryTheory/BicategoricalComp.lean
@@ -26,27 +26,22 @@ Used by the `⊗≫` bicategorical composition operator, and the `coherence` tac
-/
class BicategoricalCoherence (f g : a ⟶ b) where
/-- The chosen structural isomorphism between to 1-morphisms. -/
- hom : f ⟶ g
- [isIso : IsIso hom]
+ iso : f ≅ g
/-- Notation for identities up to unitors and associators. -/
scoped[CategoryTheory.Bicategory] notation " ⊗𝟙 " =>
- BicategoricalCoherence.hom -- type as \ot 𝟙
-
-attribute [instance] BicategoricalCoherence.isIso
-
-noncomputable section
+ BicategoricalCoherence.iso -- type as \ot 𝟙
/-- Construct an isomorphism between two objects in a bicategorical category
out of unitors and associators. -/
-def bicategoricalIso (f g : a ⟶ b) [BicategoricalCoherence f g] : f ≅ g :=
- asIso ⊗𝟙
+abbrev bicategoricalIso (f g : a ⟶ b) [BicategoricalCoherence f g] : f ≅ g :=
+ ⊗𝟙
/-- Compose two morphisms in a bicategorical category,
inserting unitors and associators between as necessary. -/
def bicategoricalComp {f g h i : a ⟶ b} [BicategoricalCoherence g h]
(η : f ⟶ g) (θ : h ⟶ i) : f ⟶ i :=
- η ≫ ⊗𝟙 ≫ θ
+ η ≫ ⊗𝟙.hom ≫ θ
-- type as \ot \gg
@[inherit_doc bicategoricalComp]
@@ -56,7 +51,7 @@ scoped[CategoryTheory.Bicategory] infixr:80 " ⊗≫ " => bicategoricalComp
inserting unitors and associators between as necessary. -/
def bicategoricalIsoComp {f g h i : a ⟶ b} [BicategoricalCoherence g h]
(η : f ≅ g) (θ : h ≅ i) : f ≅ i :=
- η ≪≫ asIso ⊗𝟙 ≪≫ θ
+ η ≪≫ ⊗𝟙 ≪≫ θ
@[inherit_doc bicategoricalIsoComp]
scoped[CategoryTheory.Bicategory] infixr:80 " ≪⊗≫ " =>
@@ -66,59 +61,59 @@ namespace BicategoricalCoherence
@[simps]
instance refl (f : a ⟶ b) : BicategoricalCoherence f f :=
- ⟨𝟙 _⟩
+ ⟨Iso.refl _⟩
@[simps]
instance whiskerLeft (f : a ⟶ b) (g h : b ⟶ c)
[BicategoricalCoherence g h] : BicategoricalCoherence (f ≫ g) (f ≫ h) :=
- ⟨f ◁ ⊗𝟙⟩
+ ⟨whiskerLeftIso f ⊗𝟙⟩
@[simps]
instance whiskerRight (f g : a ⟶ b) (h : b ⟶ c)
[BicategoricalCoherence f g] : BicategoricalCoherence (f ≫ h) (g ≫ h) :=
- ⟨⊗𝟙 ▷ h⟩
+ ⟨whiskerRightIso ⊗𝟙 h⟩
@[simps]
instance tensorRight (f : a ⟶ b) (g : b ⟶ b)
[BicategoricalCoherence (𝟙 b) g] : BicategoricalCoherence f (f ≫ g) :=
- ⟨(ρ_ f).inv ≫ f ◁ ⊗𝟙⟩
+ ⟨(ρ_ f).symm ≪≫ (whiskerLeftIso f ⊗𝟙)⟩
@[simps]
instance tensorRight' (f : a ⟶ b) (g : b ⟶ b)
[BicategoricalCoherence g (𝟙 b)] : BicategoricalCoherence (f ≫ g) f :=
- ⟨f ◁ ⊗𝟙 ≫ (ρ_ f).hom⟩
+ ⟨whiskerLeftIso f ⊗𝟙 ≪≫ (ρ_ f)⟩
@[simps]
instance left (f g : a ⟶ b) [BicategoricalCoherence f g] :
BicategoricalCoherence (𝟙 a ≫ f) g :=
- ⟨(λ_ f).hom ≫ ⊗𝟙⟩
+ ⟨λ_ f ≪≫ ⊗𝟙⟩
@[simps]
instance left' (f g : a ⟶ b) [BicategoricalCoherence f g] :
BicategoricalCoherence f (𝟙 a ≫ g) :=
- ⟨⊗𝟙 ≫ (λ_ g).inv⟩
+ ⟨⊗𝟙 ≪≫ (λ_ g).symm⟩
@[simps]
instance right (f g : a ⟶ b) [BicategoricalCoherence f g] :
BicategoricalCoherence (f ≫ 𝟙 b) g :=
- ⟨(ρ_ f).hom ≫ ⊗𝟙⟩
+ ⟨ρ_ f ≪≫ ⊗𝟙⟩
@[simps]
instance right' (f g : a ⟶ b) [BicategoricalCoherence f g] :
BicategoricalCoherence f (g ≫ 𝟙 b) :=
- ⟨⊗𝟙 ≫ (ρ_ g).inv⟩
+ ⟨⊗𝟙 ≪≫ (ρ_ g).symm⟩
@[simps]
instance assoc (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) (i : a ⟶ d)
[BicategoricalCoherence (f ≫ g ≫ h) i] :
BicategoricalCoherence ((f ≫ g) ≫ h) i :=
- ⟨(α_ f g h).hom ≫ ⊗𝟙⟩
+ ⟨α_ f g h ≪≫ ⊗𝟙⟩
@[simps]
instance assoc' (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) (i : a ⟶ d)
[BicategoricalCoherence i (f ≫ g ≫ h)] :
BicategoricalCoherence i ((f ≫ g) ≫ h) :=
- ⟨⊗𝟙 ≫ (α_ f g h).inv⟩
+ ⟨⊗𝟙 ≪≫ (α_ f g h).symm⟩
end BicategoricalCoherence
@@ -126,16 +121,4 @@ end BicategoricalCoherence
theorem bicategoricalComp_refl {f g h : a ⟶ b} (η : f ⟶ g) (θ : g ⟶ h) : η ⊗≫ θ = η ≫ θ := by
dsimp [bicategoricalComp]; simp
-example {f' : a ⟶ d} {f : a ⟶ b} {g : b ⟶ c} {h : c ⟶ d} {h' : a ⟶ d} (η : f' ⟶ f ≫ g ≫ h)
- (θ : (f ≫ g) ≫ h ⟶ h') : f' ⟶ h' :=
- η ⊗≫ θ
-
--- To automatically insert unitors/associators at the beginning or end,
--- you can use `η ⊗≫ 𝟙 _`
-example {f' : a ⟶ d} {f : a ⟶ b} {g : b ⟶ c} {h : c ⟶ d} (η : f' ⟶ (f ≫ g) ≫ h) :
- f' ⟶ f ≫ g ≫ h :=
- η ⊗≫ 𝟙 _
-
-end
-
end CategoryTheory
diff --git a/Mathlib/Tactic/CategoryTheory/Bicategory/Basic.lean b/Mathlib/Tactic/CategoryTheory/Bicategory/Basic.lean
new file mode 100644
index 0000000000000..4a85534c5839e
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Bicategory/Basic.lean
@@ -0,0 +1,55 @@
+/-
+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.Tactic.CategoryTheory.Coherence.Basic
+import Mathlib.Tactic.CategoryTheory.Bicategory.Normalize
+import Mathlib.Tactic.CategoryTheory.Bicategory.PureCoherence
+
+/-!
+# `bicategory` tactic
+
+This file provides `bicategory` tactic, which solves equations in a bicategory, where
+the two sides only differ by replacing strings of bicategory structural morphisms (that is,
+associators, unitors, and identities) with different strings of structural morphisms with the same
+source and target. In other words, `bicategory` solves equalities where both sides have the same
+string diagrams.
+
+The core function for the `bicategory` tactic is provided in
+`Mathlib.Tactic.CategoryTheory.Coherence.Basic`. See this file for more details about the
+implementation.
+
+-/
+
+open Lean Meta Elab Tactic
+open CategoryTheory Mathlib.Tactic.BicategoryLike
+
+namespace Mathlib.Tactic.Bicategory
+
+/-- Normalize the both sides of an equality. -/
+def bicategoryNf (mvarId : MVarId) : MetaM (List MVarId) := do
+ BicategoryLike.normalForm Bicategory.Context `bicategory mvarId
+
+@[inherit_doc bicategoryNf]
+elab "bicategory_nf" : tactic => withMainContext do
+ replaceMainGoal (← bicategoryNf (← getMainGoal))
+
+/--
+Use the coherence theorem for bicategories to solve equations in a bicategory,
+where the two sides only differ by replacing strings of bicategory structural morphisms
+(that is, associators, unitors, and identities)
+with different strings of structural morphisms with the same source and target.
+
+That is, `bicategory` can handle goals of the form
+`a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'`
+where `a = a'`, `b = b'`, and `c = c'` can be proved using `bicategory_coherence`.
+-/
+def bicategory (mvarId : MVarId) : MetaM (List MVarId) :=
+ BicategoryLike.main Bicategory.Context `bicategory mvarId
+
+@[inherit_doc bicategory]
+elab "bicategory" : tactic => withMainContext do
+ replaceMainGoal <| ← bicategory <| ← getMainGoal
+
+end Mathlib.Tactic.Bicategory
diff --git a/Mathlib/Tactic/CategoryTheory/Bicategory/Datatypes.lean b/Mathlib/Tactic/CategoryTheory/Bicategory/Datatypes.lean
new file mode 100644
index 0000000000000..42225947c25da
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Bicategory/Datatypes.lean
@@ -0,0 +1,511 @@
+/-
+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.Tactic.CategoryTheory.Coherence.Datatypes
+import Mathlib.Tactic.CategoryTheory.BicategoricalComp
+
+/-!
+# Expressions for bicategories
+
+This file converts lean expressions representing 2-morphisms in bicategories into `Mor₂Iso`
+or `Mor` terms. The converted expressions are used in the coherence tactics and the string diagram
+widgets.
+
+-/
+
+open Lean Meta Elab Qq
+open CategoryTheory Mathlib.Tactic.BicategoryLike Bicategory
+
+namespace Mathlib.Tactic.Bicategory
+
+/-- The domain of a morphism. -/
+def srcExpr (η : Expr) : MetaM Expr := do
+ match (← whnfR (← inferType η)).getAppFnArgs with
+ | (``Quiver.Hom, #[_, _, f, _]) => return f
+ | _ => throwError m!"{η} is not a morphism"
+
+/-- The codomain of a morphism. -/
+def tgtExpr (η : Expr) : MetaM Expr := do
+ match (← whnfR (← inferType η)).getAppFnArgs with
+ | (``Quiver.Hom, #[_, _, _, g]) => return g
+ | _ => throwError m!"{η} is not a morphism"
+
+/-- The domain of an isomorphism. -/
+def srcExprOfIso (η : Expr) : MetaM Expr := do
+ match (← whnfR (← inferType η)).getAppFnArgs with
+ | (``Iso, #[_, _, f, _]) => return f
+ | _ => throwError m!"{η} is not a morphism"
+
+/-- The codomain of an isomorphism. -/
+def tgtExprOfIso (η : Expr) : MetaM Expr := do
+ match (← whnfR (← inferType η)).getAppFnArgs with
+ | (``Iso, #[_, _, _, g]) => return g
+ | _ => throwError m!"{η} is not a morphism"
+
+initialize registerTraceClass `bicategory
+
+/-- The context for evaluating expressions. -/
+structure Context where
+ /-- The level for 2-morphisms. -/
+ level₂ : Level
+ /-- The level for 1-morphisms. -/
+ level₁ : Level
+ /-- The level for objects. -/
+ level₀ : Level
+ /-- The expression for the underlying category. -/
+ B : Q(Type level₀)
+ /-- The bicategory instance. -/
+ instBicategory : Q(Bicategory.{level₂, level₁} $B)
+
+/-- Populate a `context` object for evaluating `e`. -/
+def mkContext? (e : Expr) : MetaM (Option Context) := do
+ let e ← instantiateMVars e
+ let type ← instantiateMVars <| ← inferType e
+ match (← whnfR (← inferType e)).getAppFnArgs with
+ | (``Quiver.Hom, #[_, _, f, _]) =>
+ let fType ← instantiateMVars <| ← inferType f
+ match (← whnfR fType).getAppFnArgs with
+ | (``Quiver.Hom, #[_, _, a, _]) =>
+ let B ← inferType a
+ let .succ level₀ ← getLevel B | return none
+ let .succ level₁ ← getLevel fType | return none
+ let .succ level₂ ← getLevel type | return none
+ let .some instBicategory ← synthInstance?
+ (mkAppN (.const ``Bicategory [level₂, level₁, level₀]) #[B]) | return none
+ return some ⟨level₂, level₁, level₀, B, instBicategory⟩
+ | _ => return none
+ | _ => return none
+
+instance : BicategoryLike.Context Bicategory.Context where
+ mkContext? := Bicategory.mkContext?
+
+/-- The monad for the normalization of 2-morphisms. -/
+abbrev BicategoryM := CoherenceM Context
+
+instance : MonadMor₁ BicategoryM where
+ id₁M a := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a_e : Q($ctx.B) := a.e
+ return .id q(𝟙 $a_e) a
+ comp₁M f g := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := g.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($b ⟶ $c) := g.e
+ return .comp q($f_e ≫ $g_e) f g
+
+section
+
+universe w v u
+variable {B : Type u} [Bicategory.{w, v} B] {a b c : B}
+
+theorem structuralIso_inv {f g : a ⟶ b} (η : f ≅ g) :
+ η.symm.hom = η.inv := by
+ simp only [Iso.symm_hom]
+
+theorem structuralIsoOfExpr_comp {f g h : a ⟶ b}
+ (η : f ⟶ g) (η' : f ≅ g) (ih_η : η'.hom = η)
+ (θ : g ⟶ h) (θ' : g ≅ h) (ih_θ : θ'.hom = θ) :
+ (η' ≪≫ θ').hom = η ≫ θ := by
+ simp [ih_η, ih_θ]
+
+theorem structuralIsoOfExpr_whiskerLeft (f : a ⟶ b) {g h : b ⟶ c}
+ (η : g ⟶ h) (η' : g ≅ h) (ih_η : η'.hom = η) :
+ (whiskerLeftIso f η').hom = f ◁ η := by
+ simp [ih_η]
+
+theorem structuralIsoOfExpr_whiskerRight {f g : a ⟶ b} (h : b ⟶ c)
+ (η : f ⟶ g) (η' : f ≅ g) (ih_η : η'.hom = η) :
+ (whiskerRightIso η' h).hom = η ▷ h := by
+ simp [ih_η]
+
+theorem StructuralOfExpr_bicategoricalComp {f g h i : a ⟶ b} [BicategoricalCoherence g h]
+ (η : f ⟶ g) (η' : f ≅ g) (ih_η : η'.hom = η) (θ : h ⟶ i) (θ' : h ≅ i) (ih_θ : θ'.hom = θ) :
+ (bicategoricalIsoComp η' θ').hom = η ⊗≫ θ := by
+ simp [ih_η, ih_θ, bicategoricalIsoComp, bicategoricalComp]
+
+end
+
+open MonadMor₁
+
+instance : MonadMor₂Iso BicategoryM where
+ associatorM f g h := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := g.tgt.e
+ have d : Q($ctx.B) := h.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($b ⟶ $c) := g.e
+ have h_e : Q($c ⟶ $d) := h.e
+ return .associator q(α_ $f_e $g_e $h_e) f g h
+ leftUnitorM f := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ return .leftUnitor q(λ_ $f_e) f
+ rightUnitorM f := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ return .rightUnitor q(ρ_ $f_e) f
+ id₂M f := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ return .id q(Iso.refl $f_e) f
+ coherenceHomM f g inst := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have inst : Q(BicategoricalCoherence $f_e $g_e) := inst
+ match (← whnfI inst).getAppFnArgs with
+ | (``BicategoricalCoherence.mk, #[_, _, _, _, _, _, α]) =>
+ let e : Q($f_e ≅ $g_e) := q(BicategoricalCoherence.iso)
+ return ⟨e, f, g, inst, α⟩
+ | _ => throwError m!"failed to unfold {inst}"
+ comp₂M η θ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ let h ← θ.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have h_e : Q($a ⟶ $b) := h.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ have θ_e : Q($g_e ≅ $h_e) := θ.e
+ return .comp q($η_e ≪≫ $θ_e) f g h η θ
+ whiskerLeftM f η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let g ← η.srcM
+ let h ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := g.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($b ⟶ $c) := g.e
+ have h_e : Q($b ⟶ $c) := h.e
+ have η_e : Q($g_e ≅ $h_e) := η.e
+ return .whiskerLeft q(whiskerLeftIso $f_e $η_e) f g h η
+ whiskerRightM η h := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := h.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have h_e : Q($b ⟶ $c) := h.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ return .whiskerRight q(whiskerRightIso $η_e $h_e) f g η h
+ horizontalCompM _ _ := throwError "horizontal composition is not implemented"
+ symmM η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ return .inv q(Iso.symm $η_e) f g η
+ coherenceCompM α η θ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ let h ← θ.srcM
+ let i ← θ.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have h_e : Q($a ⟶ $b) := h.e
+ have i_e : Q($a ⟶ $b) := i.e
+ have _inst : Q(BicategoricalCoherence $g_e $h_e) := α.inst
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ have θ_e : Q($h_e ≅ $i_e) := θ.e
+ return .coherenceComp q($η_e ≪⊗≫ $θ_e) f g h i α η θ
+
+open MonadMor₂Iso
+
+instance : MonadMor₂ BicategoryM where
+ homM η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ let e : Q($f_e ⟶ $g_e) := q(Iso.hom $η_e)
+ have eq : Q(Iso.hom $η_e = $e) := q(rfl)
+ return .isoHom q(Iso.hom $η_e) ⟨η, eq⟩ η
+ atomHomM η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f := η.src
+ let g := η.tgt
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ return .mk q(Iso.hom $η_e) f g
+ invM η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ let e : Q($g_e ⟶ $f_e) := q(Iso.inv $η_e)
+ let η_inv ← symmM η
+ let eq : Q(Iso.inv $η_e = $e) := q(Iso.symm_hom $η_e)
+ return .isoInv e ⟨η_inv, eq⟩ η
+ atomInvM η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f := η.src
+ let g := η.tgt
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ return .mk q(Iso.inv $η_e) g f
+ id₂M f := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ let e : Q($f_e ⟶ $f_e) := q(𝟙 $f_e)
+ let eq : Q(𝟙 $f_e = $e) := q(Iso.refl_hom $f_e)
+ return .id e ⟨.structuralAtom <| ← id₂M f, eq⟩ f
+ comp₂M η θ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ let h ← θ.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have h_e : Q($a ⟶ $b) := h.e
+ have η_e : Q($f_e ⟶ $g_e) := η.e
+ have θ_e : Q($g_e ⟶ $h_e) := θ.e
+ let iso_lift? ← (match (η.isoLift?, θ.isoLift?) with
+ | (some η_iso, some θ_iso) =>
+ have η_iso_e : Q($f_e ≅ $g_e) := η_iso.e.e
+ have θ_iso_e : Q($g_e ≅ $h_e) := θ_iso.e.e
+ have η_iso_eq : Q(Iso.hom $η_iso_e = $η_e) := η_iso.eq
+ have θ_iso_eq : Q(Iso.hom $θ_iso_e = $θ_e) := θ_iso.eq
+ let eq := q(structuralIsoOfExpr_comp _ _ $η_iso_eq _ _ $θ_iso_eq)
+ return .some ⟨← comp₂M η_iso.e θ_iso.e, eq⟩
+ | _ => return none)
+ let e : Q($f_e ⟶ $h_e) := q($η_e ≫ $θ_e)
+ return .comp e iso_lift? f g h η θ
+ whiskerLeftM f η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let g ← η.srcM
+ let h ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := g.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($b ⟶ $c) := g.e
+ have h_e : Q($b ⟶ $c) := h.e
+ have η_e : Q($g_e ⟶ $h_e) := η.e
+ let iso_lift? ← (match η.isoLift? with
+ | some η_iso => do
+ have η_iso_e : Q($g_e ≅ $h_e) := η_iso.e.e
+ have η_iso_eq : Q(Iso.hom $η_iso_e = $η_e) := η_iso.eq
+ let eq := q(structuralIsoOfExpr_whiskerLeft $f_e _ _ $η_iso_eq)
+ return .some ⟨← whiskerLeftM f η_iso.e, eq⟩
+ | _ => return none)
+ let e : Q($f_e ≫ $g_e ⟶ $f_e ≫ $h_e) := q($f_e ◁ $η_e)
+ return .whiskerLeft e iso_lift? f g h η
+ whiskerRightM η h := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := h.src.e
+ have c : Q($ctx.B) := h.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have h_e : Q($b ⟶ $c) := h.e
+ have η_e : Q($f_e ⟶ $g_e) := η.e
+ let iso_lift? ← (match η.isoLift? with
+ | some η_iso => do
+ have η_iso_e : Q($f_e ≅ $g_e) := η_iso.e.e
+ have η_iso_eq : Q(Iso.hom $η_iso_e = $η_e) := η_iso.eq
+ let eq := q(structuralIsoOfExpr_whiskerRight $h_e _ _ $η_iso_eq)
+ return .some ⟨← whiskerRightM η_iso.e h, eq⟩
+ | _ => return none)
+ let e : Q($f_e ≫ $h_e ⟶ $g_e ≫ $h_e) := q($η_e ▷ $h_e)
+ return .whiskerRight e iso_lift? f g η h
+ horizontalCompM _ _ := throwError "horizontal composition is not implemented"
+ coherenceCompM α η θ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ let h ← θ.srcM
+ let i ← θ.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f_e : Q($a ⟶ $b) := f.e
+ have g_e : Q($a ⟶ $b) := g.e
+ have h_e : Q($a ⟶ $b) := h.e
+ have i_e : Q($a ⟶ $b) := i.e
+ have _inst : Q(BicategoricalCoherence $g_e $h_e) := α.inst
+ have η_e : Q($f_e ⟶ $g_e) := η.e
+ have θ_e : Q($h_e ⟶ $i_e) := θ.e
+ let iso_lift? ← (match (η.isoLift?, θ.isoLift?) with
+ | (some η_iso, some θ_iso) => do
+ have η_iso_e : Q($f_e ≅ $g_e) := η_iso.e.e
+ have θ_iso_e : Q($h_e ≅ $i_e) := θ_iso.e.e
+ have η_iso_eq : Q(Iso.hom $η_iso_e = $η_e) := η_iso.eq
+ have θ_iso_eq : Q(Iso.hom $θ_iso_e = $θ_e) := θ_iso.eq
+ let eq := q(StructuralOfExpr_bicategoricalComp _ _ $η_iso_eq _ _ $θ_iso_eq)
+ return .some ⟨← coherenceCompM α η_iso.e θ_iso.e, eq⟩
+ | _ => return none)
+ let e : Q($f_e ⟶ $i_e) := q($η_e ⊗≫ $θ_e)
+ return .coherenceComp e iso_lift? f g h i α η θ
+
+/-- Check that `e` is definitionally equal to `𝟙 a`. -/
+def id₁? (e : Expr) : BicategoryM (Option Obj) := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let a : Q($ctx.B) ← mkFreshExprMVar ctx.B
+ if ← withDefault <| isDefEq e q(𝟙 $a) then
+ return .some ⟨← instantiateMVars a⟩
+ else
+ return none
+
+/-- Return `(f, g)` if `e` is definitionally equal to `f ≫ g`. -/
+def comp? (e : Expr) : BicategoryM (Option (Mor₁ × Mor₁)) := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let a ← mkFreshExprMVarQ ctx.B
+ let b ← mkFreshExprMVarQ ctx.B
+ let c ← mkFreshExprMVarQ ctx.B
+ let f ← mkFreshExprMVarQ q($a ⟶ $b)
+ let g ← mkFreshExprMVarQ q($b ⟶ $c)
+ if ← withDefault <| isDefEq e q($f ≫ $g) then
+ let a ← instantiateMVars a
+ let b ← instantiateMVars b
+ let c ← instantiateMVars c
+ let f ← instantiateMVars f
+ let g ← instantiateMVars g
+ return some ((.of ⟨f, ⟨a⟩, ⟨b⟩⟩), .of ⟨g, ⟨b⟩, ⟨c⟩⟩)
+ else
+ return none
+
+/-- Construct a `Mor₁` expression from a Lean expression. -/
+partial def mor₁OfExpr (e : Expr) : BicategoryM Mor₁ := do
+ if let some f := (← get).cache.find? e then
+ return f
+ let f ←
+ if let some a ← id₁? e then
+ MonadMor₁.id₁M a
+ else if let some (f, g) ← comp? e then
+ MonadMor₁.comp₁M (← mor₁OfExpr f.e) (← mor₁OfExpr g.e)
+ else
+ return Mor₁.of ⟨e, ⟨← srcExpr e⟩, ⟨ ← tgtExpr e⟩⟩
+ modify fun s => { s with cache := s.cache.insert e f }
+ return f
+
+instance : MkMor₁ BicategoryM where
+ ofExpr := mor₁OfExpr
+
+/-- Construct a `Mor₂Iso` term from a Lean expression. -/
+partial def Mor₂IsoOfExpr (e : Expr) : BicategoryM Mor₂Iso := do
+ match (← whnfR e).getAppFnArgs with
+ | (``Bicategory.associator, #[_, _, _, _, _, _, f, g, h]) =>
+ associatorM' (← MkMor₁.ofExpr f) (← MkMor₁.ofExpr g) (← MkMor₁.ofExpr h)
+ | (``Bicategory.leftUnitor, #[_, _, _, _, f]) =>
+ leftUnitorM' (← MkMor₁.ofExpr f)
+ | (``Bicategory.rightUnitor, #[_, _, _, _, f]) =>
+ rightUnitorM' (← MkMor₁.ofExpr f)
+ | (``Iso.refl, #[_, _, f]) =>
+ id₂M' (← MkMor₁.ofExpr f)
+ | (``Iso.symm, #[_, _, _, _, η]) =>
+ symmM (← Mor₂IsoOfExpr η)
+ | (``Iso.trans, #[_, _, _, _, _, η, θ]) =>
+ comp₂M (← Mor₂IsoOfExpr η) (← Mor₂IsoOfExpr θ)
+ | (``Bicategory.whiskerLeftIso, #[_, _, _, _, _, f, _, _, η]) =>
+ whiskerLeftM (← MkMor₁.ofExpr f) (← Mor₂IsoOfExpr η)
+ | (``Bicategory.whiskerRightIso, #[_, _, _, _, _, _, _, η, h]) =>
+ whiskerRightM (← Mor₂IsoOfExpr η) (← MkMor₁.ofExpr h)
+ | (``bicategoricalIsoComp, #[_, _, _, _, _, g, h, _, inst, η, θ]) =>
+ let α ← coherenceHomM (← MkMor₁.ofExpr g) (← MkMor₁.ofExpr h) inst
+ coherenceCompM α (← Mor₂IsoOfExpr η) (← Mor₂IsoOfExpr θ)
+ | (``BicategoricalCoherence.iso, #[_, _, _, _, f, g, inst]) =>
+ coherenceHomM' (← MkMor₁.ofExpr f) (← MkMor₁.ofExpr g) inst
+ | _ =>
+ return .of ⟨e, ← MkMor₁.ofExpr (← srcExprOfIso e), ← MkMor₁.ofExpr (← tgtExprOfIso e)⟩
+
+open MonadMor₂ in
+/-- Construct a `Mor₂` term from a Lean expression. -/
+partial def Mor₂OfExpr (e : Expr) : BicategoryM Mor₂ := do
+ match ← whnfR e with
+ -- whnfR version of `Iso.hom η`
+ | .proj ``Iso 0 η => homM (← Mor₂IsoOfExpr η)
+ -- whnfR version of `Iso.inv η`
+ | .proj ``Iso 1 η => invM (← Mor₂IsoOfExpr η)
+ | .app .. => match (← whnfR e).getAppFnArgs with
+ | (``CategoryStruct.id, #[_, _, f]) => id₂M (← MkMor₁.ofExpr f)
+ | (``CategoryStruct.comp, #[_, _, _, _, _, η, θ]) =>
+ comp₂M (← Mor₂OfExpr η) (← Mor₂OfExpr θ)
+ | (``Bicategory.whiskerLeft, #[_, _, _, _, _, f, _, _, η]) =>
+ whiskerLeftM (← MkMor₁.ofExpr f) (← Mor₂OfExpr η)
+ | (``Bicategory.whiskerRight, #[_, _, _, _, _, _, _, η, h]) =>
+ whiskerRightM (← Mor₂OfExpr η) (← MkMor₁.ofExpr h)
+ | (``bicategoricalComp, #[_, _, _, _, _, g, h, _, inst, η, θ]) =>
+ let α ← coherenceHomM (← MkMor₁.ofExpr g) (← MkMor₁.ofExpr h) inst
+ coherenceCompM α (← Mor₂OfExpr η) (← Mor₂OfExpr θ)
+ | _ => return .of ⟨e, ← MkMor₁.ofExpr (← srcExpr e), ← MkMor₁.ofExpr (← tgtExpr e)⟩
+ | _ =>
+ return .of ⟨e, ← MkMor₁.ofExpr (← srcExpr e), ← MkMor₁.ofExpr (← tgtExpr e)⟩
+
+instance : BicategoryLike.MkMor₂ BicategoryM where
+ ofExpr := Mor₂OfExpr
+
+instance : MonadCoherehnceHom BicategoryM where
+ unfoldM α := Mor₂IsoOfExpr α.unfold
+
+end Mathlib.Tactic.Bicategory
diff --git a/Mathlib/Tactic/CategoryTheory/Bicategory/Normalize.lean b/Mathlib/Tactic/CategoryTheory/Bicategory/Normalize.lean
new file mode 100644
index 0000000000000..d53255094d5ee
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Bicategory/Normalize.lean
@@ -0,0 +1,548 @@
+/-
+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.Tactic.CategoryTheory.Coherence.Normalize
+import Mathlib.Tactic.CategoryTheory.Bicategory.Datatypes
+
+/-!
+# Normalization of 2-morphisms in bicategories
+
+This file provides the implementation of the normalization given in
+`Mathlib.Tactic.CategoryTheory.Coherence.Normalize`. See this file for more details.
+
+-/
+
+open Lean Meta Elab Qq
+open CategoryTheory Mathlib.Tactic.BicategoryLike Bicategory
+
+namespace Mathlib.Tactic.Bicategory
+
+section
+
+universe w v u
+
+variable {B : Type u} [Bicategory.{w, v} B]
+
+variable {a b c d : B}
+variable {f f' g g' h i j : a ⟶ b}
+
+@[nolint synTaut]
+theorem evalComp_nil_nil (α : f ≅ g) (β : g ≅ h) :
+ (α ≪≫ β).hom = (α ≪≫ β).hom := by
+ simp
+
+theorem evalComp_nil_cons (α : f ≅ g) (β : g ≅ h) (η : h ⟶ i) (ηs : i ⟶ j) :
+ α.hom ≫ (β.hom ≫ η ≫ ηs) = (α ≪≫ β).hom ≫ η ≫ ηs := by
+ simp
+
+theorem evalComp_cons (α : f ≅ g) (η : g ⟶ h) {ηs : h ⟶ i} {θ : i ⟶ j} {ι : h ⟶ j}
+ (e_ι : ηs ≫ θ = ι) :
+ (α.hom ≫ η ≫ ηs) ≫ θ = α.hom ≫ η ≫ ι := by
+ simp [e_ι]
+
+theorem eval_comp
+ {η η' : f ⟶ g} {θ θ' : g ⟶ h} {ι : f ⟶ h}
+ (e_η : η = η') (e_θ : θ = θ') (e_ηθ : η' ≫ θ' = ι) :
+ η ≫ θ = ι := by
+ simp [e_η, e_θ, e_ηθ]
+
+theorem eval_of (η : f ⟶ g) :
+ η = (Iso.refl _).hom ≫ η ≫ (Iso.refl _).hom := by
+ simp
+
+theorem eval_monoidalComp
+ {η η' : f ⟶ g} {α : g ≅ h} {θ θ' : h ⟶ i} {αθ : g ⟶ i} {ηαθ : f ⟶ i}
+ (e_η : η = η') (e_θ : θ = θ') (e_αθ : α.hom ≫ θ' = αθ) (e_ηαθ : η' ≫ αθ = ηαθ) :
+ η ≫ α.hom ≫ θ = ηαθ := by
+ simp [e_η, e_θ, e_αθ, e_ηαθ]
+
+@[nolint synTaut]
+theorem evalWhiskerLeft_nil (f : a ⟶ b) {g h : b ⟶ c} (α : g ≅ h) :
+ (whiskerLeftIso f α).hom = (whiskerLeftIso f α).hom := by
+ simp
+
+theorem evalWhiskerLeft_of_cons
+ {f : a ⟶ b} {g h i j : b ⟶ c}
+ (α : g ≅ h) (η : h ⟶ i) {ηs : i ⟶ j} {θ : f ≫ i ⟶ f ≫ j} (e_θ : f ◁ ηs = θ) :
+ f ◁ (α.hom ≫ η ≫ ηs) = (whiskerLeftIso f α).hom ≫ f ◁ η ≫ θ := by
+ simp [e_θ]
+
+theorem evalWhiskerLeft_comp
+ {f : a ⟶ b} {g : b ⟶ c} {h i : c ⟶ d}
+ {η : h ⟶ i} {η₁ : g ≫ h ⟶ g ≫ i} {η₂ : f ≫ g ≫ h ⟶ f ≫ g ≫ i}
+ {η₃ : f ≫ g ≫ h ⟶ (f ≫ g) ≫ i} {η₄ : (f ≫ g) ≫ h ⟶ (f ≫ g) ≫ i}
+ (e_η₁ : g ◁ η = η₁) (e_η₂ : f ◁ η₁ = η₂)
+ (e_η₃ : η₂ ≫ (α_ _ _ _).inv = η₃) (e_η₄ : (α_ _ _ _).hom ≫ η₃ = η₄) :
+ (f ≫ g) ◁ η = η₄ := by
+ simp [e_η₁, e_η₂, e_η₃, e_η₄]
+
+theorem evalWhiskerLeft_id {η : f ⟶ g}
+ {η₁ : f ⟶ 𝟙 a ≫ g} {η₂ : 𝟙 a ≫ f ⟶ 𝟙 a ≫ g}
+ (e_η₁ : η ≫ (λ_ _).inv = η₁) (e_η₂ : (λ_ _).hom ≫ η₁ = η₂) :
+ 𝟙 a ◁ η = η₂ := by
+ simp [e_η₁, e_η₂]
+
+theorem eval_whiskerLeft
+ {f : a ⟶ b} {g h : b ⟶ c}
+ {η η' : g ⟶ h} {θ : f ≫ g ⟶ f ≫ h}
+ (e_η : η = η') (e_θ : f ◁ η' = θ) :
+ f ◁ η = θ := by
+ simp [e_η, e_θ]
+
+theorem eval_whiskerRight
+ {f g : a ⟶ b} {h : b ⟶ c}
+ {η η' : f ⟶ g} {θ : f ≫ h ⟶ g ≫ h}
+ (e_η : η = η') (e_θ : η' ▷ h = θ) :
+ η ▷ h = θ := by
+ simp [e_η, e_θ]
+
+@[nolint synTaut]
+theorem evalWhiskerRight_nil (α : f ≅ g) (h : b ⟶ c) :
+ α.hom ▷ h = α.hom ▷ h := by
+ simp
+
+theorem evalWhiskerRightAux_of {f g : a ⟶ b} (η : f ⟶ g) (h : b ⟶ c) :
+ η ▷ h = (Iso.refl _).hom ≫ η ▷ h ≫ (Iso.refl _).hom := by
+ simp
+
+theorem evalWhiskerRight_cons_of_of
+ {f g h i : a ⟶ b} {j : b ⟶ c}
+ {α : f ≅ g} {η : g ⟶ h} {ηs : h ⟶ i} {ηs₁ : h ≫ j ⟶ i ≫ j}
+ {η₁ : g ≫ j ⟶ h ≫ j} {η₂ : g ≫ j ⟶ i ≫ j} {η₃ : f ≫ j ⟶ i ≫ j}
+ (e_ηs₁ : ηs ▷ j = ηs₁) (e_η₁ : η ▷ j = η₁)
+ (e_η₂ : η₁ ≫ ηs₁ = η₂) (e_η₃ : (whiskerRightIso α j).hom ≫ η₂ = η₃) :
+ (α.hom ≫ η ≫ ηs) ▷ j = η₃ := by
+ simp_all
+
+theorem evalWhiskerRight_cons_whisker
+ {f : a ⟶ b} {g : a ⟶ c} {h i : b ⟶ c} {j : a ⟶ c} {k : c ⟶ d}
+ {α : g ≅ f ≫ h} {η : h ⟶ i} {ηs : f ≫ i ⟶ j}
+ {η₁ : h ≫ k ⟶ i ≫ k} {η₂ : f ≫ (h ≫ k) ⟶ f ≫ (i ≫ k)} {ηs₁ : (f ≫ i) ≫ k ⟶ j ≫ k}
+ {ηs₂ : f ≫ (i ≫ k) ⟶ j ≫ k} {η₃ : f ≫ (h ≫ k) ⟶ j ≫ k} {η₄ : (f ≫ h) ≫ k ⟶ j ≫ k}
+ {η₅ : g ≫ k ⟶ j ≫ k}
+ (e_η₁ : ((Iso.refl _).hom ≫ η ≫ (Iso.refl _).hom) ▷ k = η₁) (e_η₂ : f ◁ η₁ = η₂)
+ (e_ηs₁ : ηs ▷ k = ηs₁) (e_ηs₂ : (α_ _ _ _).inv ≫ ηs₁ = ηs₂)
+ (e_η₃ : η₂ ≫ ηs₂ = η₃) (e_η₄ : (α_ _ _ _).hom ≫ η₃ = η₄)
+ (e_η₅ : (whiskerRightIso α k).hom ≫ η₄ = η₅) :
+ (α.hom ≫ (f ◁ η) ≫ ηs) ▷ k = η₅ := by
+ simp at e_η₁ e_η₅
+ simp [e_η₁, e_η₂, e_ηs₁, e_ηs₂, e_η₃, e_η₄, e_η₅]
+
+theorem evalWhiskerRight_comp
+ {f f' : a ⟶ b} {g : b ⟶ c} {h : c ⟶ d}
+ {η : f ⟶ f'} {η₁ : f ≫ g ⟶ f' ≫ g} {η₂ : (f ≫ g) ≫ h ⟶ (f' ≫ g) ≫ h}
+ {η₃ : (f ≫ g) ≫ h ⟶ f' ≫ (g ≫ h)} {η₄ : f ≫ (g ≫ h) ⟶ f' ≫ (g ≫ h)}
+ (e_η₁ : η ▷ g = η₁) (e_η₂ : η₁ ▷ h = η₂)
+ (e_η₃ : η₂ ≫ (α_ _ _ _).hom = η₃) (e_η₄ : (α_ _ _ _).inv ≫ η₃ = η₄) :
+ η ▷ (g ≫ h) = η₄ := by
+ simp [e_η₁, e_η₂, e_η₃, e_η₄]
+
+theorem evalWhiskerRight_id
+ {η : f ⟶ g} {η₁ : f ⟶ g ≫ 𝟙 b} {η₂ : f ≫ 𝟙 b ⟶ g ≫ 𝟙 b}
+ (e_η₁ : η ≫ (ρ_ _).inv = η₁) (e_η₂ : (ρ_ _).hom ≫ η₁ = η₂) :
+ η ▷ 𝟙 b = η₂ := by
+ simp [e_η₁, e_η₂]
+
+theorem eval_bicategoricalComp
+ {η η' : f ⟶ g} {α : g ≅ h} {θ θ' : h ⟶ i} {αθ : g ⟶ i} {ηαθ : f ⟶ i}
+ (e_η : η = η') (e_θ : θ = θ') (e_αθ : α.hom ≫ θ' = αθ) (e_ηαθ : η' ≫ αθ = ηαθ) :
+ η ≫ α.hom ≫ θ = ηαθ := by
+ simp [e_η, e_θ, e_αθ, e_ηαθ]
+
+end
+
+open Mor₂Iso
+
+instance : MkEvalComp BicategoryM where
+ mkEvalCompNilNil α β := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← β.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have h : Q($a ⟶ $b) := h.e
+ have α : Q($f ≅ $g) := α.e
+ have β : Q($g ≅ $h) := β.e
+ return q(evalComp_nil_nil $α $β)
+ mkEvalCompNilCons α β η ηs := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← β.tgtM
+ let i ← η.tgtM
+ let j ← ηs.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have h : Q($a ⟶ $b) := h.e
+ have i : Q($a ⟶ $b) := i.e
+ have j : Q($a ⟶ $b) := j.e
+ have α : Q($f ≅ $g) := α.e
+ have β : Q($g ≅ $h) := β.e
+ have η : Q($h ⟶ $i) := η.e.e
+ have ηs : Q($i ⟶ $j) := ηs.e.e
+ return q(evalComp_nil_cons $α $β $η $ηs)
+ mkEvalCompCons α η ηs θ ι e_ι := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← η.tgtM
+ let i ← ηs.tgtM
+ let j ← θ.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have h : Q($a ⟶ $b) := h.e
+ have i : Q($a ⟶ $b) := i.e
+ have j : Q($a ⟶ $b) := j.e
+ have α : Q($f ≅ $g) := α.e
+ have η : Q($g ⟶ $h) := η.e.e
+ have ηs : Q($h ⟶ $i) := ηs.e.e
+ have θ : Q($i ⟶ $j) := θ.e.e
+ have ι : Q($h ⟶ $j) := ι.e.e
+ have e_ι : Q($ηs ≫ $θ = $ι) := e_ι
+ return q(evalComp_cons $α $η $e_ι)
+
+instance : MkEvalWhiskerLeft BicategoryM where
+ mkEvalWhiskerLeftNil f α := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let g ← α.srcM
+ let h ← α.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := g.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($b ⟶ $c) := g.e
+ have h : Q($b ⟶ $c) := h.e
+ have α : Q($g ≅ $h) := α.e
+ return q(evalWhiskerLeft_nil $f $α)
+ mkEvalWhiskerLeftOfCons f α η ηs θ e_θ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let g ← α.srcM
+ let h ← α.tgtM
+ let i ← η.tgtM
+ let j ← ηs.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := g.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($b ⟶ $c) := g.e
+ have h : Q($b ⟶ $c) := h.e
+ have i : Q($b ⟶ $c) := i.e
+ have j : Q($b ⟶ $c) := j.e
+ have α : Q($g ≅ $h) := α.e
+ have η : Q($h ⟶ $i) := η.e.e
+ have ηs : Q($i ⟶ $j) := ηs.e.e
+ have θ : Q($f ≫ $i ⟶ $f ≫ $j) := θ.e.e
+ have e_θ : Q($f ◁ $ηs = $θ) := e_θ
+ return q(evalWhiskerLeft_of_cons $α $η $e_θ)
+ mkEvalWhiskerLeftComp f g η η₁ η₂ η₃ η₄ e_η₁ e_η₂ e_η₃ e_η₄ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let h ← η.srcM
+ let i ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := g.tgt.e
+ have d : Q($ctx.B) := h.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($b ⟶ $c) := g.e
+ have h : Q($c ⟶ $d) := h.e
+ have i : Q($c ⟶ $d) := i.e
+ have η : Q($h ⟶ $i) := η.e.e
+ have η₁ : Q($g ≫ $h ⟶ $g ≫ $i) := η₁.e.e
+ have η₂ : Q($f ≫ $g ≫ $h ⟶ $f ≫ $g ≫ $i) := η₂.e.e
+ have η₃ : Q($f ≫ $g ≫ $h ⟶ ($f ≫ $g) ≫ $i) := η₃.e.e
+ have η₄ : Q(($f ≫ $g) ≫ $h ⟶ ($f ≫ $g) ≫ $i) := η₄.e.e
+ have e_η₁ : Q($g ◁ $η = $η₁) := e_η₁
+ have e_η₂ : Q($f ◁ $η₁ = $η₂) := e_η₂
+ have e_η₃ : Q($η₂ ≫ (α_ _ _ _).inv = $η₃) := e_η₃
+ have e_η₄ : Q((α_ _ _ _).hom ≫ $η₃ = $η₄) := e_η₄
+ return q(evalWhiskerLeft_comp $e_η₁ $e_η₂ $e_η₃ $e_η₄)
+ mkEvalWhiskerLeftId η η₁ η₂ e_η₁ e_η₂ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have η : Q($f ⟶ $g) := η.e.e
+ have η₁ : Q($f ⟶ 𝟙 $a ≫ $g) := η₁.e.e
+ have η₂ : Q(𝟙 $a ≫ $f ⟶ 𝟙 $a ≫ $g) := η₂.e.e
+ have e_η₁ : Q($η ≫ (λ_ _).inv = $η₁) := e_η₁
+ have e_η₂ : Q((λ_ _).hom ≫ $η₁ = $η₂) := e_η₂
+ return q(evalWhiskerLeft_id $e_η₁ $e_η₂)
+
+instance : MkEvalWhiskerRight BicategoryM where
+ mkEvalWhiskerRightAuxOf η h := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := h.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have h : Q($b ⟶ $c) := h.e
+ have η : Q($f ⟶ $g) := η.e.e
+ return q(evalWhiskerRightAux_of $η $h)
+ mkEvalWhiskerRightAuxCons _ _ _ _ _ _ _ _ _ _ _ := do
+ throwError "not implemented"
+ mkEvalWhiskerRightNil α h := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← α.srcM
+ let g ← α.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := h.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have h : Q($b ⟶ $c) := h.e
+ have α : Q($f ≅ $g) := α.e
+ return q(evalWhiskerRight_nil $α $h)
+ mkEvalWhiskerRightConsOfOf j α η ηs ηs₁ η₁ η₂ η₃ e_ηs₁ e_η₁ e_η₂ e_η₃ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← η.tgtM
+ let i ← ηs.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := j.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have h : Q($a ⟶ $b) := h.e
+ have i : Q($a ⟶ $b) := i.e
+ have j : Q($b ⟶ $c) := j.e
+ have α : Q($f ≅ $g) := α.e
+ have η : Q($g ⟶ $h) := η.e.e
+ have ηs : Q($h ⟶ $i) := ηs.e.e
+ have ηs₁ : Q($h ≫ $j ⟶ $i ≫ $j) := ηs₁.e.e
+ have η₁ : Q($g ≫ $j ⟶ $h ≫ $j) := η₁.e.e
+ have η₂ : Q($g ≫ $j ⟶ $i ≫ $j) := η₂.e.e
+ have η₃ : Q($f ≫ $j ⟶ $i ≫ $j) := η₃.e.e
+ have e_ηs₁ : Q($ηs ▷ $j = $ηs₁) := e_ηs₁
+ have e_η₁ : Q($η ▷ $j = $η₁) := e_η₁
+ have e_η₂ : Q($η₁ ≫ $ηs₁ = $η₂) := e_η₂
+ have e_η₃ : Q((whiskerRightIso $α $j).hom ≫ $η₂ = $η₃) := e_η₃
+ return q(evalWhiskerRight_cons_of_of $e_ηs₁ $e_η₁ $e_η₂ $e_η₃)
+ mkEvalWhiskerRightConsWhisker f k α η ηs η₁ η₂ ηs₁ ηs₂ η₃ η₄ η₅
+ e_η₁ e_η₂ e_ηs₁ e_ηs₂ e_η₃ e_η₄ e_η₅ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let g ← α.srcM
+ let h ← η.srcM
+ let i ← η.tgtM
+ let j ← ηs.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := h.tgt.e
+ have d : Q($ctx.B) := k.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $c) := g.e
+ have h : Q($b ⟶ $c) := h.e
+ have i : Q($b ⟶ $c) := i.e
+ have j : Q($a ⟶ $c) := j.e
+ have k : Q($c ⟶ $d) := k.e
+ have α : Q($g ≅ $f ≫ $h) := α.e
+ have η : Q($h ⟶ $i) := η.e.e
+ have ηs : Q($f ≫ $i ⟶ $j) := ηs.e.e
+ have η₁ : Q($h ≫ $k ⟶ $i ≫ $k) := η₁.e.e
+ have η₂ : Q($f ≫ ($h ≫ $k) ⟶ $f ≫ ($i ≫ $k)) := η₂.e.e
+ have ηs₁ : Q(($f ≫ $i) ≫ $k ⟶ $j ≫ $k) := ηs₁.e.e
+ have ηs₂ : Q($f ≫ ($i ≫ $k) ⟶ $j ≫ $k) := ηs₂.e.e
+ have η₃ : Q($f ≫ ($h ≫ $k) ⟶ $j ≫ $k) := η₃.e.e
+ have η₄ : Q(($f ≫ $h) ≫ $k ⟶ $j ≫ $k) := η₄.e.e
+ have η₅ : Q($g ≫ $k ⟶ $j ≫ $k) := η₅.e.e
+ have e_η₁ : Q(((Iso.refl _).hom ≫ $η ≫ (Iso.refl _).hom) ▷ $k = $η₁) := e_η₁
+ have e_η₂ : Q($f ◁ $η₁ = $η₂) := e_η₂
+ have e_ηs₁ : Q($ηs ▷ $k = $ηs₁) := e_ηs₁
+ have e_ηs₂ : Q((α_ _ _ _).inv ≫ $ηs₁ = $ηs₂) := e_ηs₂
+ have e_η₃ : Q($η₂ ≫ $ηs₂ = $η₃) := e_η₃
+ have e_η₄ : Q((α_ _ _ _).hom ≫ $η₃ = $η₄) := e_η₄
+ have e_η₅ : Q((whiskerRightIso $α $k).hom ≫ $η₄ = $η₅) := e_η₅
+ return q(evalWhiskerRight_cons_whisker $e_η₁ $e_η₂ $e_ηs₁ $e_ηs₂ $e_η₃ $e_η₄ $e_η₅)
+ mkEvalWhiskerRightComp g h η η₁ η₂ η₃ η₄ e_η₁ e_η₂ e_η₃ e_η₄ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let f' ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := g.tgt.e
+ have d : Q($ctx.B) := h.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have f' : Q($a ⟶ $b) := f'.e
+ have g : Q($b ⟶ $c) := g.e
+ have h : Q($c ⟶ $d) := h.e
+ have η : Q($f ⟶ $f') := η.e.e
+ have η₁ : Q($f ≫ $g ⟶ $f' ≫ $g) := η₁.e.e
+ have η₂ : Q(($f ≫ $g) ≫ $h ⟶ ($f' ≫ $g) ≫ $h) := η₂.e.e
+ have η₃ : Q(($f ≫ $g) ≫ $h ⟶ $f' ≫ ($g ≫ $h)) := η₃.e.e
+ have η₄ : Q($f ≫ ($g ≫ $h) ⟶ $f' ≫ ($g ≫ $h)) := η₄.e.e
+ have e_η₁ : Q($η ▷ $g = $η₁) := e_η₁
+ have e_η₂ : Q($η₁ ▷ $h = $η₂) := e_η₂
+ have e_η₃ : Q($η₂ ≫ (α_ _ _ _).hom = $η₃) := e_η₃
+ have e_η₄ : Q((α_ _ _ _).inv ≫ $η₃ = $η₄) := e_η₄
+ return q(evalWhiskerRight_comp $e_η₁ $e_η₂ $e_η₃ $e_η₄)
+ mkEvalWhiskerRightId η η₁ η₂ e_η₁ e_η₂ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η.srcM
+ let g ← η.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have η : Q($f ⟶ $g) := η.e.e
+ have η₁ : Q($f ⟶ $g ≫ 𝟙 $b) := η₁.e.e
+ have η₂ : Q($f ≫ 𝟙 $b ⟶ $g ≫ 𝟙 $b) := η₂.e.e
+ have e_η₁ : Q($η ≫ (ρ_ _).inv = $η₁) := e_η₁
+ have e_η₂ : Q((ρ_ _).hom ≫ $η₁ = $η₂) := e_η₂
+ return q(evalWhiskerRight_id $e_η₁ $e_η₂)
+
+instance : MkEvalHorizontalComp BicategoryM where
+ mkEvalHorizontalCompAuxOf _ _ := do
+ throwError "not implemented"
+ mkEvalHorizontalCompAuxCons _ _ _ _ _ _ _ _ _ _ _ := do
+ throwError "not implemented"
+ mkEvalHorizontalCompAux'Whisker _ _ _ _ _ _ _ _ _ _ _ := do
+ throwError "not implemented"
+ mkEvalHorizontalCompAux'OfWhisker _ _ _ _ _ _ _ _ _ _ _ := do
+ throwError "not implemented"
+ mkEvalHorizontalCompNilNil _ _ := do
+ throwError "not implemented"
+ mkEvalHorizontalCompNilCons _ _ _ _ _ _ _ _ _ _ _ _ := do
+ throwError "not implemented"
+ mkEvalHorizontalCompConsNil _ _ _ _ _ _ _ _ _ _ _ _ := do
+ throwError "not implemented"
+ mkEvalHorizontalCompConsCons _ _ _ _ _ _ _ _ _ _ _ _ _ _ := do
+ throwError "not implemented"
+
+instance : MkEval BicategoryM where
+ mkEvalComp η θ η' θ' ι e_η e_θ e_ηθ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η'.srcM
+ let g ← η'.tgtM
+ let h ← θ'.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have h : Q($a ⟶ $b) := h.e
+ have η : Q($f ⟶ $g) := η.e
+ have η' : Q($f ⟶ $g) := η'.e.e
+ have θ : Q($g ⟶ $h) := θ.e
+ have θ' : Q($g ⟶ $h) := θ'.e.e
+ have ι : Q($f ⟶ $h) := ι.e.e
+ have e_η : Q($η = $η') := e_η
+ have e_θ : Q($θ = $θ') := e_θ
+ have e_ηθ : Q($η' ≫ $θ' = $ι) := e_ηθ
+ return q(eval_comp $e_η $e_θ $e_ηθ)
+ mkEvalWhiskerLeft f η η' θ e_η e_θ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let g ← η'.srcM
+ let h ← η'.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := g.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($b ⟶ $c) := g.e
+ have h : Q($b ⟶ $c) := h.e
+ have η : Q($g ⟶ $h) := η.e
+ have η' : Q($g ⟶ $h) := η'.e.e
+ have θ : Q($f ≫ $g ⟶ $f ≫ $h) := θ.e.e
+ have e_η : Q($η = $η') := e_η
+ have e_θ : Q($f ◁ $η' = $θ) := e_θ
+ return q(eval_whiskerLeft $e_η $e_θ)
+ mkEvalWhiskerRight η h η' θ e_η e_θ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η'.srcM
+ let g ← η'.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have c : Q($ctx.B) := h.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have h : Q($b ⟶ $c) := h.e
+ have η : Q($f ⟶ $g) := η.e
+ have η' : Q($f ⟶ $g) := η'.e.e
+ have θ : Q($f ≫ $h ⟶ $g ≫ $h) := θ.e.e
+ have e_η : Q($η = $η') := e_η
+ have e_θ : Q($η' ▷ $h = $θ) := e_θ
+ return q(eval_whiskerRight $e_η $e_θ)
+ mkEvalHorizontalComp _ _ _ _ _ _ _ _ := do
+ throwError "not implemented"
+ mkEvalOf η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f := η.src
+ let g := η.tgt
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have η : Q($f ⟶ $g) := η.e
+ return q(eval_of $η)
+ mkEvalMonoidalComp η θ α η' θ' αθ ηαθ e_η e_θ e_αθ e_ηαθ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let f ← η'.srcM
+ let g ← η'.tgtM
+ let h ← α.tgtM
+ let i ← θ'.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have h : Q($a ⟶ $b) := h.e
+ have i : Q($a ⟶ $b) := i.e
+ have η : Q($f ⟶ $g) := η.e
+ have η' : Q($f ⟶ $g) := η'.e.e
+ have α : Q($g ≅ $h) := α.e
+ have θ : Q($h ⟶ $i) := θ.e
+ have θ' : Q($h ⟶ $i) := θ'.e.e
+ have αθ : Q($g ⟶ $i) := αθ.e.e
+ have ηαθ : Q($f ⟶ $i) := ηαθ.e.e
+ have e_η : Q($η = $η') := e_η
+ have e_θ : Q($θ = $θ') := e_θ
+ have e_αθ : Q(Iso.hom $α ≫ $θ' = $αθ) := e_αθ
+ have e_ηαθ : Q($η' ≫ $αθ = $ηαθ) := e_ηαθ
+ return q(eval_bicategoricalComp $e_η $e_θ $e_αθ $e_ηαθ)
+
+instance : MonadNormalExpr BicategoryM where
+ whiskerRightM η h := do
+ return .whisker (← MonadMor₂.whiskerRightM η.e (.of h)) η h
+ hConsM _ _ := do
+ throwError "not implemented"
+ whiskerLeftM f η := do
+ return .whisker (← MonadMor₂.whiskerLeftM (.of f) η.e) f η
+ nilM α := do
+ return .nil (← MonadMor₂.homM α) α
+ consM α η ηs := do
+ return .cons (← MonadMor₂.comp₂M (← MonadMor₂.homM α) (← MonadMor₂.comp₂M η.e ηs.e)) α η ηs
+
+instance : MkMor₂ BicategoryM where
+ ofExpr := Mor₂OfExpr
+
+end Mathlib.Tactic.Bicategory
diff --git a/Mathlib/Tactic/CategoryTheory/Bicategory/PureCoherence.lean b/Mathlib/Tactic/CategoryTheory/Bicategory/PureCoherence.lean
new file mode 100644
index 0000000000000..6185cb4adb483
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Bicategory/PureCoherence.lean
@@ -0,0 +1,280 @@
+/-
+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.Tactic.CategoryTheory.Coherence.PureCoherence
+import Mathlib.Tactic.CategoryTheory.Bicategory.Datatypes
+
+/-!
+# Coherence tactic for bicategories
+
+We provide a `bicategory_coherence` tactic,
+which proves that any two morphisms (with the same source and target)
+in a bicategory which are built out of associators and unitors
+are equal.
+
+-/
+
+open Lean Meta Elab Qq
+open CategoryTheory Mathlib.Tactic.BicategoryLike Bicategory
+
+namespace Mathlib.Tactic.Bicategory
+
+section
+
+universe w v u
+
+variable {B : Type u} [Bicategory.{w, v} B] {a b c d e : B}
+
+local infixr:81 " ◁ " => Bicategory.whiskerLeftIso
+local infixl:81 " ▷ " => Bicategory.whiskerRightIso
+
+/-- The composition of the normalizing isomorphisms `η_f : p ≫ f ≅ pf` and `η_g : pf ≫ g ≅ pfg`. -/
+abbrev normalizeIsoComp {p : a ⟶ b} {f : b ⟶ c} {g : c ⟶ d} {pf : a ⟶ c} {pfg : a ⟶ d}
+ (η_f : p ≫ f ≅ pf) (η_g : pf ≫ g ≅ pfg) :=
+ (α_ _ _ _).symm ≪≫ whiskerRightIso η_f g ≪≫ η_g
+
+theorem naturality_associator
+ {p : a ⟶ b} {f : b ⟶ c} {g : c ⟶ d} {h : d ⟶ e} {pf : a ⟶ c} {pfg : a ⟶ d} {pfgh : a ⟶ e}
+ (η_f : p ≫ f ≅ pf) (η_g : pf ≫ g ≅ pfg) (η_h : pfg ≫ h ≅ pfgh) :
+ p ◁ (α_ f g h) ≪≫ (normalizeIsoComp η_f (normalizeIsoComp η_g η_h)) =
+ (normalizeIsoComp (normalizeIsoComp η_f η_g) η_h) :=
+ Iso.ext (by simp)
+
+theorem naturality_leftUnitor {p : a ⟶ b} {f : b ⟶ c} {pf : a ⟶ c} (η_f : p ≫ f ≅ pf) :
+ p ◁ (λ_ f) ≪≫ η_f = normalizeIsoComp (ρ_ p) η_f :=
+ Iso.ext (by simp)
+
+theorem naturality_rightUnitor {p : a ⟶ b} {f : b ⟶ c} {pf : a ⟶ c} (η_f : p ≫ f ≅ pf) :
+ p ◁ (ρ_ f) ≪≫ η_f = normalizeIsoComp η_f (ρ_ pf) :=
+ Iso.ext (by simp)
+
+theorem naturality_id {p : a ⟶ b} {f : b ⟶ c} {pf : a ⟶ c} (η_f : p ≫ f ≅ pf) :
+ p ◁ Iso.refl f ≪≫ η_f = η_f :=
+ Iso.ext (by simp)
+
+theorem naturality_comp {p : a ⟶ b} {f g h : b ⟶ c} {pf : a ⟶ c} {η : f ≅ g} {θ : g ≅ h}
+ (η_f : p ≫ f ≅ pf) (η_g : p ≫ g ≅ pf) (η_h : p ≫ h ≅ pf)
+ (ih_η : p ◁ η ≪≫ η_g = η_f) (ih_θ : p ◁ θ ≪≫ η_h = η_g) :
+ p ◁ (η ≪≫ θ) ≪≫ η_h = η_f := by
+ rw [← ih_η, ← ih_θ]
+ apply Iso.ext (by simp)
+
+theorem naturality_whiskerLeft {p : a ⟶ b} {f : b ⟶ c} {g h : c ⟶ d} {pf : a ⟶ c} {pfg : a ⟶ d}
+ {η : g ≅ h} (η_f : p ≫ f ≅ pf) (η_fg : pf ≫ g ≅ pfg) (η_fh : pf ≫ h ≅ pfg)
+ (ih_η : pf ◁ η ≪≫ η_fh = η_fg) :
+ p ◁ (f ◁ η) ≪≫ normalizeIsoComp η_f η_fh = normalizeIsoComp η_f η_fg := by
+ rw [← ih_η]
+ apply Iso.ext (by simp [← whisker_exchange_assoc])
+
+theorem naturality_whiskerRight {p : a ⟶ b} {f g : b ⟶ c} {h : c ⟶ d} {pf : a ⟶ c} {pfh : a ⟶ d}
+ {η : f ≅ g} (η_f : p ≫ f ≅ pf) (η_g : p ≫ g ≅ pf) (η_fh : pf ≫ h ≅ pfh)
+ (ih_η : p ◁ η ≪≫ η_g = η_f) :
+ p ◁ (η ▷ h) ≪≫ normalizeIsoComp η_g η_fh = normalizeIsoComp η_f η_fh := by
+ rw [← ih_η]
+ apply Iso.ext (by simp)
+
+theorem naturality_inv {p : a ⟶ b} {f g : b ⟶ c} {pf : a ⟶ c}
+ {η : f ≅ g} (η_f : p ≫ f ≅ pf) (η_g : p ≫ g ≅ pf) (ih : p ◁ η ≪≫ η_g = η_f) :
+ p ◁ η.symm ≪≫ η_f = η_g := by
+ rw [← ih]
+ apply Iso.ext (by simp)
+
+instance : MonadNormalizeNaturality BicategoryM where
+ mkNaturalityAssociator p pf pfg pfgh f g h η_f η_g η_h := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := p.src.e
+ have b : Q($ctx.B) := p.tgt.e
+ have c : Q($ctx.B) := f.tgt.e
+ have d : Q($ctx.B) := g.tgt.e
+ have e : Q($ctx.B) := h.tgt.e
+ have p : Q($a ⟶ $b) := p.e.e
+ have f : Q($b ⟶ $c) := f.e
+ have g : Q($c ⟶ $d) := g.e
+ have h : Q($d ⟶ $e) := h.e
+ have pf : Q($a ⟶ $c) := pf.e.e
+ have pfg : Q($a ⟶ $d) := pfg.e.e
+ have pfgh : Q($a ⟶ $e) := pfgh.e.e
+ have η_f : Q($p ≫ $f ≅ $pf) := η_f.e
+ have η_g : Q($pf ≫ $g ≅ $pfg) := η_g.e
+ have η_h : Q($pfg ≫ $h ≅ $pfgh) := η_h.e
+ return q(naturality_associator $η_f $η_g $η_h)
+ mkNaturalityLeftUnitor p pf f η_f := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := p.src.e
+ have b : Q($ctx.B) := p.tgt.e
+ have c : Q($ctx.B) := f.tgt.e
+ have p : Q($a ⟶ $b) := p.e.e
+ have f : Q($b ⟶ $c) := f.e
+ have pf : Q($a ⟶ $c) := pf.e.e
+ have η_f : Q($p ≫ $f ≅ $pf) := η_f.e
+ return q(naturality_leftUnitor $η_f)
+ mkNaturalityRightUnitor p pf f η_f := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := p.src.e
+ have b : Q($ctx.B) := p.tgt.e
+ have c : Q($ctx.B) := f.tgt.e
+ have p : Q($a ⟶ $b) := p.e.e
+ have f : Q($b ⟶ $c) := f.e
+ have pf : Q($a ⟶ $c) := pf.e.e
+ have η_f : Q($p ≫ $f ≅ $pf) := η_f.e
+ return q(naturality_rightUnitor $η_f)
+ mkNaturalityId p pf f η_f := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := p.src.e
+ have b : Q($ctx.B) := p.tgt.e
+ have c : Q($ctx.B) := f.tgt.e
+ have p : Q($a ⟶ $b) := p.e.e
+ have f : Q($b ⟶ $c) := f.e
+ have pf : Q($a ⟶ $c) := pf.e.e
+ have η_f : Q($p ≫ $f ≅ $pf) := η_f.e
+ return q(naturality_id $η_f)
+ mkNaturalityComp p pf f g h η θ η_f η_g η_h ih_η ih_θ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := p.src.e
+ have b : Q($ctx.B) := p.tgt.e
+ have c : Q($ctx.B) := f.tgt.e
+ have p : Q($a ⟶ $b) := p.e.e
+ have f : Q($b ⟶ $c) := f.e
+ have g : Q($b ⟶ $c) := g.e
+ have h : Q($b ⟶ $c) := h.e
+ have pf : Q($a ⟶ $c) := pf.e.e
+ have η : Q($f ≅ $g) := η.e
+ have θ : Q($g ≅ $h) := θ.e
+ have η_f : Q($p ≫ $f ≅ $pf) := η_f.e
+ have η_g : Q($p ≫ $g ≅ $pf) := η_g.e
+ have η_h : Q($p ≫ $h ≅ $pf) := η_h.e
+ have ih_η : Q($p ◁ $η ≪≫ $η_g = $η_f) := ih_η
+ have ih_θ : Q($p ◁ $θ ≪≫ $η_h = $η_g) := ih_θ
+ return q(naturality_comp $η_f $η_g $η_h $ih_η $ih_θ)
+ mkNaturalityWhiskerLeft p pf pfg f g h η η_f η_fg η_fh ih_η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := p.src.e
+ have b : Q($ctx.B) := p.tgt.e
+ have c : Q($ctx.B) := f.tgt.e
+ have d : Q($ctx.B) := g.tgt.e
+ have p : Q($a ⟶ $b) := p.e.e
+ have f : Q($b ⟶ $c) := f.e
+ have g : Q($c ⟶ $d) := g.e
+ have h : Q($c ⟶ $d) := h.e
+ have pf : Q($a ⟶ $c) := pf.e.e
+ have pfg : Q($a ⟶ $d) := pfg.e.e
+ have η : Q($g ≅ $h) := η.e
+ have η_f : Q($p ≫ $f ≅ $pf) := η_f.e
+ have η_fg : Q($pf ≫ $g ≅ $pfg) := η_fg.e
+ have η_fh : Q($pf ≫ $h ≅ $pfg) := η_fh.e
+ have ih_η : Q($pf ◁ $η ≪≫ $η_fh = $η_fg) := ih_η
+ return q(naturality_whiskerLeft $η_f $η_fg $η_fh $ih_η)
+ mkNaturalityWhiskerRight p pf pfh f g h η η_f η_g η_fh ih_η := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := p.src.e
+ have b : Q($ctx.B) := p.tgt.e
+ have c : Q($ctx.B) := f.tgt.e
+ have d : Q($ctx.B) := h.tgt.e
+ have p : Q($a ⟶ $b) := p.e.e
+ have f : Q($b ⟶ $c) := f.e
+ have g : Q($b ⟶ $c) := g.e
+ have h : Q($c ⟶ $d) := h.e
+ have pf : Q($a ⟶ $c) := pf.e.e
+ have pfh : Q($a ⟶ $d) := pfh.e.e
+ have η : Q($f ≅ $g) := η.e
+ have η_f : Q($p ≫ $f ≅ $pf) := η_f.e
+ have η_g : Q($p ≫ $g ≅ $pf) := η_g.e
+ have η_fh : Q($pf ≫ $h ≅ $pfh) := η_fh.e
+ have ih_η : Q($p ◁ $η ≪≫ $η_g = $η_f) := ih_η
+ return q(naturality_whiskerRight $η_f $η_g $η_fh $ih_η)
+ mkNaturalityHorizontalComp _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ := do
+ throwError "horizontal composition is not implemented"
+ mkNaturalityInv p pf f g η η_f η_g ih := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ have a : Q($ctx.B) := p.src.e
+ have b : Q($ctx.B) := p.tgt.e
+ have c : Q($ctx.B) := f.tgt.e
+ have p : Q($a ⟶ $b) := p.e.e
+ have f : Q($b ⟶ $c) := f.e
+ have g : Q($b ⟶ $c) := g.e
+ have pf : Q($a ⟶ $c) := pf.e.e
+ have η : Q($f ≅ $g) := η.e
+ have η_f : Q($p ≫ $f ≅ $pf) := η_f.e
+ have η_g : Q($p ≫ $g ≅ $pf) := η_g.e
+ have ih : Q($p ◁ $η ≪≫ $η_g = $η_f) := ih
+ return q(naturality_inv $η_f $η_g $ih)
+
+theorem of_normalize_eq {f g f' : a ⟶ b} {η θ : f ≅ g} (η_f : 𝟙 a ≫ f ≅ f') (η_g : 𝟙 a ≫ g ≅ f')
+ (h_η : 𝟙 a ◁ η ≪≫ η_g = η_f)
+ (h_θ : 𝟙 a ◁ θ ≪≫ η_g = η_f) : η = θ := by
+ apply Iso.ext
+ calc
+ η.hom = (λ_ f).inv ≫ η_f.hom ≫ η_g.inv ≫ (λ_ g).hom := by
+ simp [← reassoc_of% (congrArg Iso.hom h_η)]
+ _ = θ.hom := by
+ simp [← reassoc_of% (congrArg Iso.hom h_θ)]
+
+theorem mk_eq_of_naturality {f g f' : a ⟶ b} {η θ : f ⟶ g} {η' θ' : f ≅ g}
+ (η_f : 𝟙 a ≫ f ≅ f') (η_g : 𝟙 a ≫ g ≅ f')
+ (Hη : η'.hom = η) (Hθ : θ'.hom = θ)
+ (Hη' : whiskerLeftIso (𝟙 a) η' ≪≫ η_g = η_f)
+ (Hθ' : whiskerLeftIso (𝟙 a) θ' ≪≫ η_g = η_f) : η = θ :=
+ calc
+ η = η'.hom := Hη.symm
+ _ = (λ_ f).inv ≫ η_f.hom ≫ η_g.inv ≫ (λ_ g).hom := by
+ simp [← reassoc_of% (congrArg Iso.hom Hη')]
+ _ = θ'.hom := by
+ simp [← reassoc_of% (congrArg Iso.hom Hθ')]
+ _ = θ := Hθ
+
+end
+
+instance : MkEqOfNaturality BicategoryM where
+ mkEqOfNaturality η θ ηIso θIso η_f η_g Hη Hθ := do
+ let ctx ← read
+ let _bicat := ctx.instBicategory
+ let η' := ηIso.e
+ let θ' := θIso.e
+ let f ← η'.srcM
+ let g ← η'.tgtM
+ let f' ← η_f.tgtM
+ have a : Q($ctx.B) := f.src.e
+ have b : Q($ctx.B) := f.tgt.e
+ have f : Q($a ⟶ $b) := f.e
+ have g : Q($a ⟶ $b) := g.e
+ have f' : Q($a ⟶ $b) := f'.e
+ have η : Q($f ⟶ $g) := η
+ have θ : Q($f ⟶ $g) := θ
+ have η'_e : Q($f ≅ $g) := η'.e
+ have θ'_e : Q($f ≅ $g) := θ'.e
+ have η_f : Q(𝟙 $a ≫ $f ≅ $f') := η_f.e
+ have η_g : Q(𝟙 $a ≫ $g ≅ $f') := η_g.e
+ have η_hom : Q(Iso.hom $η'_e = $η) := ηIso.eq
+ have Θ_hom : Q(Iso.hom $θ'_e = $θ) := θIso.eq
+ have Hη : Q(whiskerLeftIso (𝟙 $a) $η'_e ≪≫ $η_g = $η_f) := Hη
+ have Hθ : Q(whiskerLeftIso (𝟙 $a) $θ'_e ≪≫ $η_g = $η_f) := Hθ
+ return q(mk_eq_of_naturality $η_f $η_g $η_hom $Θ_hom $Hη $Hθ)
+
+open Elab.Tactic
+
+/-- Close the goal of the form `η = θ`, where `η` and `θ` are 2-isomorphisms made up only of
+associators, unitors, and identities.
+```lean
+example {B : Type} [Bicategory B] {a : B} :
+ (λ_ (𝟙 a)).hom = (ρ_ (𝟙 a)).hom := by
+ bicategory_coherence
+```
+-/
+def pureCoherence (mvarId : MVarId) : MetaM (List MVarId) :=
+ BicategoryLike.pureCoherence Bicategory.Context `bicategory mvarId
+
+@[inherit_doc pureCoherence]
+elab "bicategory_coherence" : tactic => withMainContext do
+ replaceMainGoal <| ← Bicategory.pureCoherence <| ← getMainGoal
+
+end Mathlib.Tactic.Bicategory
diff --git a/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean b/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean
index 3973e6312e46f..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
@@ -112,8 +112,10 @@ def mkLiftMap₂LiftExpr (e : Expr) : TermElabM Expr := do
def bicategory_coherence (g : MVarId) : TermElabM Unit := g.withContext do
withOptions (fun opts => synthInstance.maxSize.set opts
(max 256 (synthInstance.maxSize.get opts))) do
- let (ty, _) ← dsimp (← g.getType)
- { simpTheorems := #[.addDeclToUnfoldCore {} ``BicategoricalCoherence.hom] }
+ let thms := [``BicategoricalCoherence.iso, ``Iso.trans, ``Iso.symm, ``Iso.refl,
+ ``Bicategory.whiskerRightIso, ``Bicategory.whiskerLeftIso].foldl
+ (·.addDeclToUnfoldCore ·) {}
+ let (ty, _) ← dsimp (← g.getType) { simpTheorems := #[thms] }
let some (_, lhs, rhs) := (← whnfR ty).eq? | exception g "Not an equation of morphisms."
let lift_lhs ← mkLiftMap₂LiftExpr lhs
let lift_rhs ← mkLiftMap₂LiftExpr rhs
diff --git a/Mathlib/Tactic/CategoryTheory/Coherence.lean b/Mathlib/Tactic/CategoryTheory/Coherence.lean
index 43e1b97ac26dd..a479585f2c608 100644
--- a/Mathlib/Tactic/CategoryTheory/Coherence.lean
+++ b/Mathlib/Tactic/CategoryTheory/Coherence.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2022. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Yuma Mizuno, Oleksandr Manzyuk
+Authors: Kim Morrison, Yuma Mizuno, Oleksandr Manzyuk
-/
import Mathlib.CategoryTheory.Monoidal.Free.Coherence
import Mathlib.Lean.Meta
@@ -121,8 +121,10 @@ def mkProjectMapExpr (e : Expr) : TermElabM Expr := do
def monoidal_coherence (g : MVarId) : TermElabM Unit := g.withContext do
withOptions (fun opts => synthInstance.maxSize.set opts
(max 512 (synthInstance.maxSize.get opts))) do
- let (ty, _) ← dsimp (← g.getType)
- { simpTheorems := #[.addDeclToUnfoldCore {} ``MonoidalCoherence.hom] }
+ let thms := [``MonoidalCoherence.iso, ``Iso.trans, ``Iso.symm, ``Iso.refl,
+ ``MonoidalCategory.whiskerRightIso, ``MonoidalCategory.whiskerLeftIso].foldl
+ (·.addDeclToUnfoldCore ·) {}
+ let (ty, _) ← dsimp (← g.getType) { simpTheorems := #[thms] }
let some (_, lhs, rhs) := (← whnfR ty).eq? | exception g "Not an equation of morphisms."
let projectMap_lhs ← mkProjectMapExpr lhs
let projectMap_rhs ← mkProjectMapExpr rhs
@@ -184,7 +186,10 @@ elab (name := liftable_prefixes) "liftable_prefixes" : tactic => do
(max 256 (synthInstance.maxSize.get opts))) do
evalTactic (← `(tactic|
(simp (config := {failIfUnchanged := false}) only
- [monoidalComp, Category.assoc, MonoidalCoherence.hom, BicategoricalCoherence.hom]) <;>
+ [monoidalComp, bicategoricalComp, Category.assoc, BicategoricalCoherence.iso,
+ MonoidalCoherence.iso, Iso.trans, Iso.symm, Iso.refl,
+ MonoidalCategory.whiskerRightIso, MonoidalCategory.whiskerLeftIso,
+ Bicategory.whiskerRightIso, Bicategory.whiskerLeftIso]) <;>
(apply (cancel_epi (𝟙 _)).1 <;> try infer_instance) <;>
(simp (config := {failIfUnchanged := false}) only
[assoc_liftHom, Mathlib.Tactic.BicategoryCoherence.assoc_liftHom₂])))
diff --git a/Mathlib/Tactic/CategoryTheory/Coherence/Basic.lean b/Mathlib/Tactic/CategoryTheory/Coherence/Basic.lean
new file mode 100644
index 0000000000000..53facfd616c82
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Coherence/Basic.lean
@@ -0,0 +1,107 @@
+/-
+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.Tactic.CategoryTheory.Coherence.Normalize
+import Mathlib.Tactic.CategoryTheory.Coherence.PureCoherence
+import Mathlib.CategoryTheory.Category.Basic
+
+/-!
+# The Core function for `monoidal` and `bicategory` tactics
+
+This file provides the function `BicategoryLike.main` for proving equalities in monoidal categories
+and bicategories. Using `main`, we will define the following tactics:
+- `monoidal` at `Mathlib.Tactic.CategoryTheory.Monoidal.Basic`
+- `bicategory` at `Mathlib.Tactic.CategoryTheory.Bicategory.Basic`
+
+The `main` first normalizes the both sides using `eval`, then compares the corresponding components.
+It closes the goal at non-structural parts with `rfl` and the goal at structural parts by
+`pureCoherence`.
+
+-/
+
+open Lean Meta Elab
+open CategoryTheory Mathlib.Tactic.BicategoryLike
+
+namespace Mathlib.Tactic.BicategoryLike
+
+theorem mk_eq {α : Type _} (a b a' b' : α) (ha : a = a') (hb : b = b') (h : a' = b') : a = b := by
+ simp [h, ha, hb]
+
+/-- Transform an equality between 2-morphisms into the equality between their normalizations. -/
+def normalForm (ρ : Type) [Context ρ]
+ [MonadMor₁ (CoherenceM ρ)]
+ [MonadMor₂Iso (CoherenceM ρ)]
+ [MonadNormalExpr (CoherenceM ρ)] [MkEval (CoherenceM ρ)]
+ [MkMor₂ (CoherenceM ρ)]
+ [MonadMor₂ (CoherenceM ρ)]
+ (nm : Name) (mvarId : MVarId) : MetaM (List MVarId) := do
+ mvarId.withContext do
+ let e ← instantiateMVars <| ← mvarId.getType
+ withTraceNode nm (fun _ => return m!"normalize: {e}") do
+ let some (_, e₁, e₂) := (← whnfR <| ← instantiateMVars <| e).eq?
+ | throwError "{nm}_nf requires an equality goal"
+ let ctx : ρ ← mkContext e₁
+ CoherenceM.run (ctx := ctx) do
+ let e₁' ← MkMor₂.ofExpr e₁
+ let e₂' ← MkMor₂.ofExpr e₂
+ let e₁'' ← eval nm e₁'
+ let e₂'' ← eval nm e₂'
+ let H ← mkAppM ``mk_eq #[e₁, e₂, e₁''.expr.e.e, e₂''.expr.e.e, e₁''.proof, e₂''.proof]
+ mvarId.apply H
+
+universe v u
+
+theorem mk_eq_of_cons {C : Type u} [CategoryStruct.{v} C]
+ {f₁ f₂ f₃ f₄ : C}
+ (α α' : f₁ ⟶ f₂) (η η' : f₂ ⟶ f₃) (ηs ηs' : f₃ ⟶ f₄)
+ (e_α : α = α') (e_η : η = η') (e_ηs : ηs = ηs') :
+ α ≫ η ≫ ηs = α' ≫ η' ≫ ηs' := by
+ simp [e_α, e_η, e_ηs]
+
+/-- Split the goal `α ≫ η ≫ ηs = α' ≫ η' ≫ ηs'` into `α = α'`, `η = η'`, and `ηs = ηs'`. -/
+def ofNormalizedEq (mvarId : MVarId) : MetaM (List MVarId) := do
+ mvarId.withContext do
+ let e ← instantiateMVars <| ← mvarId.getType
+ let some (_, e₁, e₂) := (← whnfR e).eq? | throwError "requires an equality goal"
+ match (← whnfR e₁).getAppFnArgs, (← whnfR e₂).getAppFnArgs with
+ | (``CategoryStruct.comp, #[_, _, _, _, _, α, η]) ,
+ (``CategoryStruct.comp, #[_, _, _, _, _, α', η']) =>
+ match (← whnfR η).getAppFnArgs, (← whnfR η').getAppFnArgs with
+ | (``CategoryStruct.comp, #[_, _, _, _, _, η, ηs]),
+ (``CategoryStruct.comp, #[_, _, _, _, _, η', ηs']) =>
+ let e_α ← mkFreshExprMVar (← Meta.mkEq α α')
+ let e_η ← mkFreshExprMVar (← Meta.mkEq η η')
+ let e_ηs ← mkFreshExprMVar (← Meta.mkEq ηs ηs')
+ let x ← mvarId.apply (← mkAppM ``mk_eq_of_cons #[α, α', η, η', ηs, ηs', e_α, e_η, e_ηs])
+ return x
+ | _, _ => throwError "failed to make a normalized equality for {e}"
+ | _, _ => throwError "failed to make a normalized equality for {e}"
+
+/-- List.splitEvenOdd [0, 1, 2, 3, 4] = ([0, 2, 4], [1, 3]) -/
+def List.splitEvenOdd {α : Type u} : List α → List α × List α
+ | [] => ([], [])
+ | [a] => ([a], [])
+ | a::b::xs =>
+ let (as, bs) := List.splitEvenOdd xs
+ (a::as, b::bs)
+
+/-- The core function for `monoidal` and `bicategory` tactics. -/
+def main (ρ : Type) [Context ρ] [MonadMor₁ (CoherenceM ρ)] [MonadMor₂Iso (CoherenceM ρ)]
+ [MonadNormalExpr (CoherenceM ρ)] [MkEval (CoherenceM ρ)] [MkMor₂ (CoherenceM ρ)]
+ [MonadMor₂ (CoherenceM ρ)] [MonadCoherehnceHom (CoherenceM ρ)]
+ [MonadNormalizeNaturality (CoherenceM ρ)] [MkEqOfNaturality (CoherenceM ρ)]
+ (nm : Name) (mvarId : MVarId) : MetaM (List MVarId) :=
+ mvarId.withContext do
+ let mvarIds ← normalForm ρ nm mvarId
+ let (mvarIdsCoherence, mvarIdsRefl) := List.splitEvenOdd (← repeat' ofNormalizedEq mvarIds)
+ for mvarId in mvarIdsRefl do mvarId.refl
+ let mvarIds'' ← mvarIdsCoherence.mapM fun mvarId => do
+ withTraceNode nm (fun _ => do return m!"goal: {← mvarId.getType}") do
+ try
+ pureCoherence ρ nm mvarId
+ catch _ => return [mvarId]
+ return mvarIds''.join
+
+end Mathlib.Tactic.BicategoryLike
diff --git a/Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean b/Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean
new file mode 100644
index 0000000000000..4fb144875c348
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean
@@ -0,0 +1,468 @@
+/-
+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.Basic
+import Mathlib.Init
+
+/-!
+# Datatypes for bicategory like structures
+
+This file defines the basic datatypes for bicategory like structures. We will use these datatypes
+to write tactics that can be applied to both monoidal categories and bicategories:
+- `Obj`: objects type
+- `Atom₁`: atomic 1-morphisms type
+- `Mor₁`: 1-morphisms type
+- `Atom`: atomic non-structural 2-morphisms type
+- `Mor₂`: 2-morphisms type
+- `AtomIso`: atomic non-structural 2-isomorphisms type
+- `Mor₂Iso`: 2-isomorphisms type
+- `NormalizedHom`: normalized 1-morphisms type
+
+A term of these datatypes wraps the corresponding `Expr` term, which can be extracted by
+e.g. `η.e` for `η : Mor₂`.
+
+The operations of these datatypes are defined in a monad `m` with the corresponding typeclasses:
+- `MonadMor₁`: operations on `Mor₁`
+- `MonadMor₂Iso`: operations on `Mor₂Iso`
+- `MonadMor₂`: operations on `Mor₂`
+
+For example, a monad `m` with `[MonadMor₂ m]` provides the operation
+`MonadMor₂.comp₂M : Mor₂Iso → Mor₂Iso → m Mor₂Iso`, which constructs the expression for the
+composition `η ≫ θ` of 2-morphisms `η` and `θ` in the monad `m`.
+
+-/
+
+open Lean Meta
+
+namespace Mathlib.Tactic
+
+namespace BicategoryLike
+
+/-- Expressions for objects. -/
+structure Obj where
+ /-- Extracts a lean expression from an `Obj` term. Return `none` in the monoidal
+ category context. -/
+ e? : Option Expr
+ deriving Inhabited
+
+/-- Extract a lean expression from an `Obj` term. -/
+def Obj.e (a : Obj) : Expr :=
+ a.e?.get!
+
+/-- Expressions for atomic 1-morphisms. -/
+structure Atom₁ : Type where
+ /-- Extract a lean expression from an `Atom₁` term. -/
+ e : Expr
+ /-- The domain of the 1-morphism. -/
+ src : Obj
+ /-- The codomain of the 1-morphism. -/
+ tgt : Obj
+ deriving Inhabited
+
+/-- A monad equipped with the ability to construct `Atom₁` terms. -/
+class MkAtom₁ (m : Type → Type) where
+ /-- Construct a `Atom₁` term from a lean expression. -/
+ ofExpr (e : Expr) : m Atom₁
+
+/-- Expressions for 1-morphisms. -/
+inductive Mor₁ : Type
+ /-- `id e a` is the expression for `𝟙 a`, where `e` is the underlying lean expression. -/
+ | id (e : Expr) (a : Obj) : Mor₁
+ /-- `comp e f g` is the expression for `f ≫ g`, where `e` is the underlying lean expression. -/
+ | comp (e : Expr) : Mor₁ → Mor₁ → Mor₁
+ /-- The expression for an atomic 1-morphism. -/
+ | of : Atom₁ → Mor₁
+ deriving Inhabited
+
+/-- A monad equipped with the ability to construct `Mor₁` terms. -/
+class MkMor₁ (m : Type → Type) where
+ /-- Construct a `Mor₁` term from a lean expression. -/
+ ofExpr (e : Expr) : m Mor₁
+
+/-- The underlying lean expression of a 1-morphism. -/
+def Mor₁.e : Mor₁ → Expr
+ | .id e _ => e
+ | .comp e _ _ => e
+ | .of a => a.e
+
+/-- The domain of a 1-morphism. -/
+def Mor₁.src : Mor₁ → Obj
+ | .id _ a => a
+ | .comp _ f _ => f.src
+ | .of f => f.src
+
+/-- The codomain of a 1-morphism. -/
+def Mor₁.tgt : Mor₁ → Obj
+ | .id _ a => a
+ | .comp _ _ g => g.tgt
+ | .of f => f.tgt
+
+/-- Converts a 1-morphism into a list of its components. -/
+def Mor₁.toList : Mor₁ → List Atom₁
+ | .id _ _ => []
+ | .comp _ f g => f.toList ++ g.toList
+ | .of f => [f]
+
+/-- A monad equipped with the ability to manipulate 1-morphisms. -/
+class MonadMor₁ (m : Type → Type) where
+ /-- The expression for `𝟙 a`. -/
+ id₁M (a : Obj) : m Mor₁
+ /-- The expression for `f ≫ g`. -/
+ comp₁M (f g : Mor₁) : m Mor₁
+
+/-- Expressions for coherence isomorphisms (i.e., structural 2-morphisms
+giveb by `BicategorycalCoherence.iso`). -/
+structure CoherenceHom where
+ /-- The underlying lean expression of a coherence isomorphism. -/
+ e : Expr
+ /-- The domain of a coherence isomorphism. -/
+ src : Mor₁
+ /-- The codomain of a coherence isomorphism. -/
+ tgt : Mor₁
+ /-- The `BicategoricalCoherence` instance. -/
+ inst : Expr
+ /-- Extract the structural 2-isomorphism. -/
+ unfold : Expr
+ deriving Inhabited
+
+/-- Expressions for atomic non-structural 2-isomorphisms. -/
+structure AtomIso where
+ /-- The underlying lean expression of an `AtomIso` term. -/
+ e : Expr
+ /-- The domain of a 2-isomorphism. -/
+ src : Mor₁
+ /-- The codomain of a 2-isomorphism. -/
+ tgt : Mor₁
+ deriving Inhabited
+
+/-- Expressions for atomic structural 2-morphisms. -/
+inductive StructuralAtom : Type
+ /-- The expression for the associator `α_ f g h`. -/
+ | associator (e : Expr) (f g h : Mor₁) : StructuralAtom
+ /-- The expression for the left unitor `λ_ f`. -/
+ | leftUnitor (e : Expr) (f : Mor₁) : StructuralAtom
+ /-- The expression for the right unitor `ρ_ f`. -/
+ | rightUnitor (e : Expr) (f : Mor₁) : StructuralAtom
+ | id (e : Expr) (f : Mor₁) : StructuralAtom
+ | coherenceHom (α : CoherenceHom) : StructuralAtom
+ deriving Inhabited
+
+/-- Expressions for 2-isomorphisms. -/
+inductive Mor₂Iso : Type where
+ | structuralAtom (α : StructuralAtom) : Mor₂Iso
+ | comp (e : Expr) (f g h : Mor₁) (η θ : Mor₂Iso) : Mor₂Iso
+ | whiskerLeft (e : Expr) (f g h : Mor₁) (η : Mor₂Iso) : Mor₂Iso
+ | whiskerRight (e : Expr) (f g : Mor₁) (η : Mor₂Iso) (h : Mor₁) : Mor₂Iso
+ | horizontalComp (e : Expr) (f₁ g₁ f₂ g₂ : Mor₁) (η θ : Mor₂Iso) : Mor₂Iso
+ | inv (e : Expr) (f g : Mor₁) (η : Mor₂Iso) : Mor₂Iso
+ | coherenceComp (e : Expr) (f g h i : Mor₁) (α : CoherenceHom) (η θ : Mor₂Iso) : Mor₂Iso
+ | of (η : AtomIso) : Mor₂Iso
+ deriving Inhabited
+
+/-- A monad equipped with the ability to unfold `BicategoricalCoherence.iso`. -/
+class MonadCoherehnceHom (m : Type → Type) where
+ /-- Unfold a coherence isomorphism. -/
+ unfoldM (α : CoherenceHom) : m Mor₂Iso
+
+/-- The underlying lean expression of a 2-isomorphism. -/
+def StructuralAtom.e : StructuralAtom → Expr
+ | .associator e .. => e
+ | .leftUnitor e .. => e
+ | .rightUnitor e .. => e
+ | .id e .. => e
+ | .coherenceHom α => α.e
+
+open MonadMor₁
+
+variable {m : Type → Type} [Monad m]
+
+/-- The domain of a 2-isomorphism. -/
+def StructuralAtom.srcM [MonadMor₁ m] : StructuralAtom → m Mor₁
+ | .associator _ f g h => do comp₁M (← comp₁M f g) h
+ | .leftUnitor _ f => do comp₁M (← id₁M f.src) f
+ | .rightUnitor _ f => do comp₁M f (← id₁M f.tgt)
+ | .id _ f => return f
+ | .coherenceHom α => return α.src
+
+/-- The codomain of a 2-isomorphism. -/
+def StructuralAtom.tgtM [MonadMor₁ m] : StructuralAtom → m Mor₁
+ | .associator _ f g h => do comp₁M f (← comp₁M g h)
+ | .leftUnitor _ f => return f
+ | .rightUnitor _ f => return f
+ | .id _ f => return f
+ | .coherenceHom α => return α.tgt
+
+/-- The underlying lean expression of a 2-isomorphism. -/
+def Mor₂Iso.e : Mor₂Iso → Expr
+ | .structuralAtom α => α.e
+ | .comp e .. => e
+ | .whiskerLeft e .. => e
+ | .whiskerRight e .. => e
+ | .horizontalComp e .. => e
+ | .inv e .. => e
+ | .coherenceComp e .. => e
+ | .of η => η.e
+
+/-- The domain of a 2-isomorphism. -/
+def Mor₂Iso.srcM {m : Type → Type} [Monad m] [MonadMor₁ m] : Mor₂Iso → m Mor₁
+ | .structuralAtom α => α.srcM
+ | .comp _ f .. => return f
+ | .whiskerLeft _ f g .. => do comp₁M f g
+ | .whiskerRight _ f _ _ h => do comp₁M f h
+ | .horizontalComp _ f₁ _ f₂ .. => do comp₁M f₁ f₂
+ | .inv _ _ g _ => return g
+ | .coherenceComp _ f .. => return f
+ | .of η => return η.src
+
+/-- The codomain of a 2-isomorphism. -/
+def Mor₂Iso.tgtM {m : Type → Type} [Monad m] [MonadMor₁ m] : Mor₂Iso → m Mor₁
+ | .structuralAtom α => α.tgtM
+ | .comp _ _ _ h .. => return h
+ | .whiskerLeft _ f _ h _ => do comp₁M f h
+ | .whiskerRight _ _ g _ h => do comp₁M g h
+ | .horizontalComp _ _ g₁ _ g₂ _ _ => do comp₁M g₁ g₂
+ | .inv _ f _ _ => return f
+ | .coherenceComp _ _ _ _ i .. => return i
+ | .of η => return η.tgt
+
+/-- A monad equipped with the ability to construct `Mor₂Iso` terms. -/
+class MonadMor₂Iso (m : Type → Type) where
+ /-- The expression for the associator `α_ f g h`. -/
+ associatorM (f g h : Mor₁) : m StructuralAtom
+ /-- The expression for the left unitor `λ_ f`. -/
+ leftUnitorM (f : Mor₁) : m StructuralAtom
+ /-- The expression for the right unitor `ρ_ f`. -/
+ rightUnitorM (f : Mor₁) : m StructuralAtom
+ /-- The expression for the identity `Iso.refl f`. -/
+ id₂M (f : Mor₁) : m StructuralAtom
+ /-- The expression for the coherence isomorphism `⊗𝟙 : f ⟶ g`. -/
+ coherenceHomM (f g : Mor₁) (inst : Expr) : m CoherenceHom
+ /-- The expression for the composition `η ≪≫ θ`. -/
+ comp₂M (η θ : Mor₂Iso) : m Mor₂Iso
+ /-- The expression for the left whiskering `whiskerLeftIso f η`. -/
+ whiskerLeftM (f : Mor₁) (η : Mor₂Iso) : m Mor₂Iso
+ /-- The expression for the right whiskering `whiskerRightIso η h`. -/
+ whiskerRightM (η : Mor₂Iso) (h : Mor₁) : m Mor₂Iso
+ /-- The expression for the horizontal composition `η ◫ θ`. -/
+ horizontalCompM (η θ : Mor₂Iso) : m Mor₂Iso
+ /-- The expression for the inverse `Iso.symm η`. -/
+ symmM (η : Mor₂Iso) : m Mor₂Iso
+ /-- The expression for the coherence composition `η ≪⊗≫ θ := η ≪≫ α ≪≫ θ`. -/
+ coherenceCompM (α : CoherenceHom) (η θ : Mor₂Iso) : m Mor₂Iso
+
+namespace MonadMor₂Iso
+
+variable {m : Type → Type} [Monad m] [MonadMor₂Iso m]
+
+/-- The expression for the associator `α_ f g h`. -/
+def associatorM' (f g h : Mor₁) : m Mor₂Iso := do
+ return .structuralAtom <| ← MonadMor₂Iso.associatorM f g h
+
+/-- The expression for the left unitor `λ_ f`. -/
+def leftUnitorM' (f : Mor₁) : m Mor₂Iso := do
+ return .structuralAtom <| ← MonadMor₂Iso.leftUnitorM f
+
+/-- The expression for the right unitor `ρ_ f`. -/
+def rightUnitorM' (f : Mor₁) : m Mor₂Iso := do
+ return .structuralAtom <| ← MonadMor₂Iso.rightUnitorM f
+
+/-- The expression for the identity `Iso.refl f`. -/
+def id₂M' (f : Mor₁) : m Mor₂Iso := do
+ return .structuralAtom <| ← MonadMor₂Iso.id₂M f
+
+/-- The expression for the coherence isomorphism `⊗𝟙 : f ⟶ g`. -/
+def coherenceHomM' (f g : Mor₁) (inst : Expr) : m Mor₂Iso := do
+ return .structuralAtom <| .coherenceHom <| ← MonadMor₂Iso.coherenceHomM f g inst
+
+end MonadMor₂Iso
+
+/-- Expressions for atomic non-structural 2-morphisms. -/
+structure Atom where
+ /-- Extract a lean expression from an `Atom` expression. -/
+ e : Expr
+ /-- The domain of a 2-morphism. -/
+ src : Mor₁
+ /-- The codomain of a 2-morphism. -/
+ tgt : Mor₁
+ deriving Inhabited
+
+/-- `Mor₂` expressions defined below will have the `isoLift? : Option IsoLift` field.
+For `η : Mor₂` such that `η.isoLift? = .some isoLift`, we have the following data:
+- `isoLift.e`: an expression for a 2-isomorphism `η'`, given as a `Mor₂Iso` term,
+- `isoLift.eq`: a lean expression for the proof that `η'.hom = η`.
+-/
+structure IsoLift where
+ /-- The expression for the 2-isomorphism. -/
+ e : Mor₂Iso
+ /-- The expression for the proof that the forward direction of the 2-isomorphism is equal to
+ the original 2-morphism. -/
+ eq : Expr
+
+/-- Expressions for 2-morphisms. -/
+inductive Mor₂ : Type where
+ /-- The expression for `Iso.hom`. -/
+ | isoHom (e : Expr) (isoLift : IsoLift) (iso : Mor₂Iso) : Mor₂
+ /-- The expression for `Iso.inv`. -/
+ | isoInv (e : Expr) (isoLift : IsoLift) (iso : Mor₂Iso) : Mor₂
+ /-- The expression for the identity `𝟙 f`. -/
+ | id (e : Expr) (isoLift : IsoLift) (f : Mor₁) : Mor₂
+ /-- The expression for the composition `η ≫ θ`. -/
+ | comp (e : Expr) (isoLift? : Option IsoLift) (f g h : Mor₁) (η θ : Mor₂) : Mor₂
+ /-- The expression for the left whiskering `f ◁ η` with `η : g ⟶ h`. -/
+ | whiskerLeft (e : Expr) (isoLift? : Option IsoLift) (f g h : Mor₁) (η : Mor₂) : Mor₂
+ /-- The expression for the right whiskering `η ▷ h` with `η : f ⟶ g`. -/
+ | whiskerRight (e : Expr) (isoLift? : Option IsoLift) (f g : Mor₁) (η : Mor₂) (h : Mor₁) : Mor₂
+ /-- The expression for the horizontal composition `η ◫ θ` with `η : f₁ ⟶ g₁` and `θ : f₂ ⟶ g₂`. -/
+ | horizontalComp (e : Expr) (isoLift? : Option IsoLift) (f₁ g₁ f₂ g₂ : Mor₁) (η θ : Mor₂) : Mor₂
+ /-- The expression for the coherence composition `η ⊗≫ θ := η ≫ α ≫ θ` with `η : f ⟶ g`
+ and `θ : h ⟶ i`. -/
+ | coherenceComp (e : Expr) (isoLift? : Option IsoLift) (f g h i : Mor₁)
+ (α : CoherenceHom) (η θ : Mor₂) : Mor₂
+ /-- The expression for an atomic non-structural 2-morphism. -/
+ | of (η : Atom) : Mor₂
+ deriving Inhabited
+
+/-- A monad equipped with the ability to construct `Mor₂` terms. -/
+class MkMor₂ (m : Type → Type) where
+ /-- Construct a `Mor₂` term from a lean expression. -/
+ ofExpr (e : Expr) : m Mor₂
+
+/-- The underlying lean expression of a 2-morphism. -/
+def Mor₂.e : Mor₂ → Expr
+ | .isoHom e .. => e
+ | .isoInv e .. => e
+ | .id e .. => e
+ | .comp e .. => e
+ | .whiskerLeft e .. => e
+ | .whiskerRight e .. => e
+ | .horizontalComp e .. => e
+ | .coherenceComp e .. => e
+ | .of η => η.e
+
+/-- `η.isoLift?` is a pair of a 2-isomorphism `η'` and a proof that `η'.hom = η`. If no such `η'`
+is found, returns `none`. This function does not seek `IsIso` instance. -/
+def Mor₂.isoLift? : Mor₂ → Option IsoLift
+ | .isoHom _ isoLift .. => some isoLift
+ | .isoInv _ isoLift .. => some isoLift
+ | .id _ isoLift .. => some isoLift
+ | .comp _ isoLift? .. => isoLift?
+ | .whiskerLeft _ isoLift? .. => isoLift?
+ | .whiskerRight _ isoLift? .. => isoLift?
+ | .horizontalComp _ isoLift? .. => isoLift?
+ | .coherenceComp _ isoLift? .. => isoLift?
+ | .of _ => none
+
+/-- The domain of a 2-morphism. -/
+def Mor₂.srcM {m : Type → Type} [Monad m] [MonadMor₁ m] : Mor₂ → m Mor₁
+ | .isoHom _ _ iso => iso.srcM
+ | .isoInv _ _ iso => iso.tgtM
+ | .id _ _ f => return f
+ | .comp _ _ f .. => return f
+ | .whiskerLeft _ _ f g .. => do comp₁M f g
+ | .whiskerRight _ _ f _ _ h => do comp₁M f h
+ | .horizontalComp _ _ f₁ _ f₂ .. => do comp₁M f₁ f₂
+ | .coherenceComp _ _ f .. => return f
+ | .of η => return η.src
+
+/-- The codomain of a 2-morphism. -/
+def Mor₂.tgtM {m : Type → Type} [Monad m] [MonadMor₁ m] : Mor₂ → m Mor₁
+ | .isoHom _ _ iso => iso.tgtM
+ | .isoInv _ _ iso => iso.srcM
+ | .id _ _ f => return f
+ | .comp _ _ _ _ h .. => return h
+ | .whiskerLeft _ _ f _ h _ => do comp₁M f h
+ | .whiskerRight _ _ _ g _ h => do comp₁M g h
+ | .horizontalComp _ _ _ g₁ _ g₂ _ _ => do comp₁M g₁ g₂
+ | .coherenceComp _ _ _ _ _ i .. => return i
+ | .of η => return η.tgt
+
+/-- A monad equipped with the ability to manipulate 2-morphisms. -/
+class MonadMor₂ (m : Type → Type) where
+ /-- The expression for `Iso.hom η`. -/
+ homM (η : Mor₂Iso) : m Mor₂
+ /-- The expression for `Iso.hom η`. -/
+ atomHomM (η : AtomIso) : m Atom
+ /-- The expression for `Iso.inv η`. -/
+ invM (η : Mor₂Iso) : m Mor₂
+ /-- The expression for `Iso.inv η`. -/
+ atomInvM (η : AtomIso) : m Atom
+ /-- The expression for the identity `𝟙 f`. -/
+ id₂M (f : Mor₁) : m Mor₂
+ /-- The expression for the composition `η ≫ θ`. -/
+ comp₂M (η θ : Mor₂) : m Mor₂
+ /-- The expression for the left whiskering `f ◁ η`. -/
+ whiskerLeftM (f : Mor₁) (η : Mor₂) : m Mor₂
+ /-- The expression for the right whiskering `η ▷ h`. -/
+ whiskerRightM (η : Mor₂) (h : Mor₁) : m Mor₂
+ /-- The expression for the horizontal composition `η ◫ θ`. -/
+ horizontalCompM (η θ : Mor₂) : m Mor₂
+ /-- The expression for the coherence composition `η ⊗≫ θ := η ≫ α ≫ θ`. -/
+ coherenceCompM (α : CoherenceHom) (η θ : Mor₂) : m Mor₂
+
+/-- Type of normalized 1-morphisms `((... ≫ h) ≫ g) ≫ f`. -/
+inductive NormalizedHom : Type
+ /-- The identity 1-morphism `𝟙 a`. -/
+ | nil (e : Mor₁) (a : Obj) : NormalizedHom
+ /-- The `cons` composes an atomic 1-morphism at the end of a normalized 1-morphism. -/
+ | cons (e : Mor₁) : NormalizedHom → Atom₁ → NormalizedHom
+ deriving Inhabited
+
+/-- The underlying expression of a normalized 1-morphism. -/
+def NormalizedHom.e : NormalizedHom → Mor₁
+ | NormalizedHom.nil e _ => e
+ | NormalizedHom.cons e _ _ => e
+
+/-- The domain of a normalized 1-morphism. -/
+def NormalizedHom.src : NormalizedHom → Obj
+ | NormalizedHom.nil _ a => a
+ | NormalizedHom.cons _ p _ => p.src
+
+/-- The codomain of a normalized 1-morphism. -/
+def NormalizedHom.tgt : NormalizedHom → Obj
+ | NormalizedHom.nil _ a => a
+ | NormalizedHom.cons _ _ f => f.tgt
+
+/-- Construct the `NormalizedHom.nil` term in `m`. -/
+def normalizedHom.nilM [MonadMor₁ m] (a : Obj) : m NormalizedHom := do
+ return NormalizedHom.nil (← id₁M a) a
+
+/-- Construct a `NormalizedHom.cons` term in `m`. -/
+def NormalizedHom.consM [MonadMor₁ m] (p : NormalizedHom) (f : Atom₁) :
+ m NormalizedHom := do
+ return NormalizedHom.cons (← comp₁M p.e (.of f)) p f
+
+/-- `Context ρ` provides the context for manipulating 2-morphisms in a monoidal category or
+bicategory. In particular, we will store `MonoidalCategory` or `Bicategory` instance in a context,
+and use this through a reader monad when we construct the lean expressions for 2-morphisms. -/
+class Context (ρ : Type) where
+ /-- Construct a context from a lean expression for a 2-morphism. -/
+ mkContext? : Expr → MetaM (Option ρ)
+
+export Context (mkContext?)
+
+/-- Construct a context from a lean expression for a 2-morphism. -/
+def mkContext {ρ : Type} [Context ρ] (e : Expr) : MetaM ρ := do
+ match ← mkContext? e with
+ | some c => return c
+ | none => throwError "failed to construct a monoidal category or bicategory context from {e}"
+
+/-- The state for the `CoherenceM ρ` monad. -/
+structure State where
+ /-- The cache for evaluating lean expressions of 1-morphisms into `Mor₁` terms. -/
+ cache : PersistentExprMap Mor₁ := {}
+
+/-- The monad for manipulating 2-morphisms in a monoidal category or bicategory. -/
+abbrev CoherenceM (ρ : Type) := ReaderT ρ <| StateT State MetaM
+
+/-- Run the `CoherenceM ρ` monad. -/
+def CoherenceM.run {α ρ : Type} (x : CoherenceM ρ α) (ctx : ρ) (s : State := {}) :
+ MetaM α := do
+ Prod.fst <$> ReaderT.run x ctx s
+
+end BicategoryLike
+
+end Tactic
+
+end Mathlib
diff --git a/Mathlib/Tactic/CategoryTheory/Coherence/Normalize.lean b/Mathlib/Tactic/CategoryTheory/Coherence/Normalize.lean
new file mode 100644
index 0000000000000..3fec5a6a72318
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Coherence/Normalize.lean
@@ -0,0 +1,586 @@
+/-
+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
+
+/-!
+# Normalization of 2-morphisms in bicategories
+
+This file provides a function that normalizes 2-morphisms in bicategories. The function also
+used to normalize morphisms in monoidal categories. This is used in the string diagram widget given
+in `Mathlib.Tactic.StringDiagram`, as well as `monoidal` and `bicategory` tactics.
+
+We say that the 2-morphism `η` in a bicategory is in normal form if
+1. `η` is of the form `α₀ ≫ η₀ ≫ α₁ ≫ η₁ ≫ ... αₘ ≫ ηₘ ≫ αₘ₊₁` where each `αᵢ` is a
+ structural 2-morphism (consisting of associators and unitors),
+2. each `ηᵢ` is a non-structural 2-morphism of the form `f₁ ◁ ... ◁ fₙ ◁ θ`, and
+3. `θ` is of the form `ι₁ ◫ ... ◫ ιₗ`, and
+4. each `ιᵢ` is of the form `κ ▷ g₁ ▷ ... ▷ gₖ`.
+
+Note that the horizontal composition `◫` is not currently defined for bicategories. In the monoidal
+category setting, the horizontal composition is defined as the `tensorHom`, denoted by `⊗`.
+
+Note that the structural morphisms `αᵢ` are not necessarily normalized, as the main purpose
+is to get a list of the non-structural morphisms out.
+
+Currently, the primary application of the normalization tactic in mind is drawing string diagrams,
+which are graphical representations of morphisms in monoidal categories, in the infoview. When
+drawing string diagrams, we often ignore associators and unitors (i.e., drawing morphisms in
+strict monoidal categories). On the other hand, in Lean, it is considered difficult to formalize
+the concept of strict monoidal categories due to the feature of dependent type theory. The
+normalization tactic can remove associators and unitors from the expression, extracting the
+necessary data for drawing string diagrams.
+
+The string diagrams widget is to use Penrose (https://github.com/penrose) via ProofWidget.
+However, it should be noted that the normalization procedure in this file does not rely on specific
+settings, allowing for broader application. Future plans include the following. At least I (Yuma)
+would like to work on these in the future, but it might not be immediate. If anyone is interested,
+I would be happy to discuss.
+
+- Currently, the string diagrams widget only do drawing. It would be better they also generate
+ proofs. That is, by manipulating the string diagrams displayed in the infoview with a mouse to
+ generate proofs. In #10581, the string diagram widget only uses the morphisms generated by the
+ normalization tactic and does not use proof terms ensuring that the original morphism and the
+ normalized morphism are equal. Proof terms will be necessary for proof generation.
+
+- There is also the possibility of using homotopy.io (https://github.com/homotopy-io), a graphical
+ proof assistant for category theory, from Lean. At this point, I have very few ideas regarding
+ this approach.
+
+## Main definitions
+- `Tactic.BicategoryLike.eval`: Given a Lean expression `e` that represents a morphism in a monoidal
+category, this function returns a pair of `⟨e', pf⟩` where `e'` is the normalized expression of `e`
+and `pf` is a proof that `e = e'`.
+
+-/
+
+open Lean Meta
+
+namespace Mathlib.Tactic.BicategoryLike
+
+section
+
+/-- Expressions of the form `η ▷ f₁ ▷ ... ▷ fₙ`. -/
+inductive WhiskerRight : Type
+ /-- Construct the expression for an atomic 2-morphism. -/
+ | of (η : Atom) : WhiskerRight
+ /-- Construct the expression for `η ▷ f`. -/
+ | whisker (e : Mor₂) (η : WhiskerRight) (f : Atom₁) : WhiskerRight
+ deriving Inhabited
+
+/-- The underlying `Mor₂` term of a `WhiskerRight` term. -/
+def WhiskerRight.e : WhiskerRight → Mor₂
+ | .of η => .of η
+ | .whisker e .. => e
+
+/-- Expressions of the form `η₁ ⊗ ... ⊗ ηₙ`. -/
+inductive HorizontalComp : Type
+ | of (η : WhiskerRight) : HorizontalComp
+ | cons (e : Mor₂) (η : WhiskerRight) (ηs : HorizontalComp) :
+ HorizontalComp
+ deriving Inhabited
+
+/-- The underlying `Mor₂` term of a `HorizontalComp` term. -/
+def HorizontalComp.e : HorizontalComp → Mor₂
+ | .of η => η.e
+ | .cons e .. => e
+
+/-- Expressions of the form `f₁ ◁ ... ◁ fₙ ◁ η`. -/
+inductive WhiskerLeft : Type
+ /-- Construct the expression for a right-whiskered 2-morphism. -/
+ | of (η : HorizontalComp) : WhiskerLeft
+ /-- Construct the expression for `f ◁ η`. -/
+ | whisker (e : Mor₂) (f : Atom₁) (η : WhiskerLeft) : WhiskerLeft
+ deriving Inhabited
+
+/-- The underlying `Mor₂` term of a `WhiskerLeft` term. -/
+def WhiskerLeft.e : WhiskerLeft → Mor₂
+ | .of η => η.e
+ | .whisker e .. => e
+
+/-- Whether a given 2-isomorphism is structural or not. -/
+def Mor₂Iso.isStructural (α : Mor₂Iso) : Bool :=
+ match α with
+ | .structuralAtom _ => true
+ | .comp _ _ _ _ η θ => η.isStructural && θ.isStructural
+ | .whiskerLeft _ _ _ _ η => η.isStructural
+ | .whiskerRight _ _ _ η _ => η.isStructural
+ | .horizontalComp _ _ _ _ _ η θ => η.isStructural && θ.isStructural
+ | .inv _ _ _ η => η.isStructural
+ | .coherenceComp _ _ _ _ _ _ η θ => η.isStructural && θ.isStructural
+ | .of _ => false
+
+/-- Expressions for structural isomorphisms. We do not impose the condition `isStructural` since
+it is not needed to write the tactic. -/
+abbrev Structural := Mor₂Iso
+
+/-- Normalized expressions for 2-morphisms. -/
+inductive NormalExpr : Type
+ /-- Construct the expression for a structural 2-morphism. -/
+ | nil (e : Mor₂) (α : Structural) : NormalExpr
+ /-- Construct the normalized expression of a 2-morphism `α ≫ η ≫ ηs` recursively. -/
+ | cons (e : Mor₂) (α : Structural) (η : WhiskerLeft) (ηs : NormalExpr) : NormalExpr
+ deriving Inhabited
+
+/-- The underlying `Mor₂` term of a `NormalExpr` term. -/
+def NormalExpr.e : NormalExpr → Mor₂
+ | .nil e .. => e
+ | .cons e .. => e
+
+/-- A monad equipped with the ability to construct `WhiskerRight` terms. -/
+class MonadWhiskerRight (m : Type → Type) where
+ /-- The expression for the right whiskering `η ▷ f`. -/
+ whiskerRightM (η : WhiskerRight) (f : Atom₁) : m WhiskerRight
+
+/-- A monad equipped with the ability to construct `HorizontalComp` terms. -/
+class MonadHorizontalComp (m : Type → Type) extends MonadWhiskerRight m where
+ /-- The expression for the horizontal composition `η ◫ ηs`. -/
+ hConsM (η : WhiskerRight) (ηs : HorizontalComp) : m HorizontalComp
+
+/-- A monad equipped with the ability to construct `WhiskerLeft` terms. -/
+class MonadWhiskerLeft (m : Type → Type) extends MonadHorizontalComp m where
+ /-- The expression for the left whiskering `f ▷ η`. -/
+ whiskerLeftM (f : Atom₁) (η : WhiskerLeft) : m WhiskerLeft
+
+/-- A monad equipped with the ability to construct `NormalExpr` terms. -/
+class MonadNormalExpr (m : Type → Type) extends MonadWhiskerLeft m where
+ /-- The expression for the structural 2-morphism `α`. -/
+ nilM (α : Structural) : m NormalExpr
+ /-- The expression for the normalized 2-morphism `α ≫ η ≫ ηs`. -/
+ consM (headStructural : Structural) (η : WhiskerLeft) (ηs : NormalExpr) : m NormalExpr
+
+variable {m : Type → Type} [Monad m]
+
+open MonadMor₁
+
+/-- The domain of a 2-morphism. -/
+def WhiskerRight.srcM [MonadMor₁ m] : WhiskerRight → m Mor₁
+ | WhiskerRight.of η => return η.src
+ | WhiskerRight.whisker _ η f => do comp₁M (← η.srcM) (.of f)
+
+/-- The codomain of a 2-morphism. -/
+def WhiskerRight.tgtM [MonadMor₁ m] : WhiskerRight → m Mor₁
+ | WhiskerRight.of η => return η.tgt
+ | WhiskerRight.whisker _ η f => do comp₁M (← η.tgtM) (.of f)
+
+/-- The domain of a 2-morphism. -/
+def HorizontalComp.srcM [MonadMor₁ m] : HorizontalComp → m Mor₁
+ | HorizontalComp.of η => η.srcM
+ | HorizontalComp.cons _ η ηs => do comp₁M (← η.srcM) (← ηs.srcM)
+
+/-- The codomain of a 2-morphism. -/
+def HorizontalComp.tgtM [MonadMor₁ m] : HorizontalComp → m Mor₁
+ | HorizontalComp.of η => η.tgtM
+ | HorizontalComp.cons _ η ηs => do comp₁M (← η.tgtM) (← ηs.tgtM)
+
+/-- The domain of a 2-morphism. -/
+def WhiskerLeft.srcM [MonadMor₁ m] : WhiskerLeft → m Mor₁
+ | WhiskerLeft.of η => η.srcM
+ | WhiskerLeft.whisker _ f η => do comp₁M (.of f) (← η.srcM)
+
+/-- The codomain of a 2-morphism. -/
+def WhiskerLeft.tgtM [MonadMor₁ m] : WhiskerLeft → m Mor₁
+ | WhiskerLeft.of η => η.tgtM
+ | WhiskerLeft.whisker _ f η => do comp₁M (.of f) (← η.tgtM)
+
+/-- The domain of a 2-morphism. -/
+def NormalExpr.srcM [MonadMor₁ m] : NormalExpr → m Mor₁
+ | NormalExpr.nil _ η => η.srcM
+ | NormalExpr.cons _ α _ _ => α.srcM
+
+/-- The codomain of a 2-morphism. -/
+def NormalExpr.tgtM [MonadMor₁ m] : NormalExpr → m Mor₁
+ | NormalExpr.nil _ η => η.tgtM
+ | NormalExpr.cons _ _ _ ηs => ηs.tgtM
+
+namespace NormalExpr
+
+variable [MonadMor₂Iso m] [MonadNormalExpr m]
+
+/-- The identity 2-morphism as a term of `normalExpr`. -/
+def idM (f : Mor₁) : m NormalExpr := do
+ MonadNormalExpr.nilM <| .structuralAtom <| ← MonadMor₂Iso.id₂M f
+
+/-- The associator as a term of `normalExpr`. -/
+def associatorM (f g h : Mor₁) : m NormalExpr := do
+ MonadNormalExpr.nilM <| .structuralAtom <| ← MonadMor₂Iso.associatorM f g h
+
+/-- The inverse of the associator as a term of `normalExpr`. -/
+def associatorInvM (f g h : Mor₁) : m NormalExpr := do
+ MonadNormalExpr.nilM <| ← MonadMor₂Iso.symmM <|
+ .structuralAtom <| ← MonadMor₂Iso.associatorM f g h
+
+/-- The left unitor as a term of `normalExpr`. -/
+def leftUnitorM (f : Mor₁) : m NormalExpr := do
+ MonadNormalExpr.nilM <| .structuralAtom <| ← MonadMor₂Iso.leftUnitorM f
+
+/-- The inverse of the left unitor as a term of `normalExpr`. -/
+def leftUnitorInvM (f : Mor₁) : m NormalExpr := do
+ MonadNormalExpr.nilM <| ← MonadMor₂Iso.symmM <| .structuralAtom <| ← MonadMor₂Iso.leftUnitorM f
+
+/-- The right unitor as a term of `normalExpr`. -/
+def rightUnitorM (f : Mor₁) : m NormalExpr := do
+ MonadNormalExpr.nilM <| .structuralAtom <| ← MonadMor₂Iso.rightUnitorM f
+
+/-- The inverse of the right unitor as a term of `normalExpr`. -/
+def rightUnitorInvM (f : Mor₁) : m NormalExpr := do
+ MonadNormalExpr.nilM <| ← MonadMor₂Iso.symmM <| .structuralAtom <| ← MonadMor₂Iso.rightUnitorM f
+
+/-- Construct a `NormalExpr` expression from a `WhiskerLeft` expression. -/
+def ofM [MonadMor₁ m] (η : WhiskerLeft) : m NormalExpr := do
+ MonadNormalExpr.consM ((.structuralAtom <| ← MonadMor₂Iso.id₂M (← η.srcM))) η
+ (← MonadNormalExpr.nilM ((.structuralAtom <| ← MonadMor₂Iso.id₂M (← η.tgtM))))
+
+/-- Construct a `NormalExpr` expression from a Lean expression for an atomic 2-morphism. -/
+def ofAtomM [MonadMor₁ m] (η : Atom) : m NormalExpr :=
+ NormalExpr.ofM <| .of <| .of <| .of η
+
+end NormalExpr
+
+/-- Convert a `NormalExpr` expression into a list of `WhiskerLeft` expressions. -/
+def NormalExpr.toList : NormalExpr → List WhiskerLeft
+ | NormalExpr.nil _ _ => []
+ | NormalExpr.cons _ _ η ηs => η :: NormalExpr.toList ηs
+
+end
+
+section
+
+/-- The result of evaluating an expression into normal form. -/
+structure Eval.Result where
+ /-- The normalized expression of the 2-morphism. -/
+ expr : NormalExpr
+ /-- The proof that the normalized expression is equal to the original expression. -/
+ proof : Expr
+ deriving Inhabited
+
+variable {m : Type → Type}
+
+/-- Evaluate the expression `α ≫ β`. -/
+class MkEvalComp (m : Type → Type) where
+ /-- Evaluate `α ≫ β` -/
+ mkEvalCompNilNil (α β : Structural) : m Expr
+ /-- Evaluate `α ≫ (β ≫ η ≫ ηs)` -/
+ mkEvalCompNilCons (α β : Structural) (η : WhiskerLeft) (ηs : NormalExpr) : m Expr
+ /-- Evaluate `(α ≫ η ≫ ηs) ≫ θ` -/
+ mkEvalCompCons (α : Structural) (η : WhiskerLeft) (ηs θ ι : NormalExpr) (e_η : Expr) : m Expr
+
+/-- Evaluatte the expression `f ◁ η`. -/
+class MkEvalWhiskerLeft (m : Type → Type) where
+ /-- Evaluatte `f ◁ α` -/
+ mkEvalWhiskerLeftNil (f : Mor₁) (α : Structural) : m Expr
+ /-- Evaluate `f ◁ (α ≫ η ≫ ηs)`. -/
+ mkEvalWhiskerLeftOfCons (f : Atom₁) (α : Structural) (η : WhiskerLeft) (ηs θ : NormalExpr)
+ (e_θ : Expr) : m Expr
+ /-- Evaluate `(f ≫ g) ◁ η` -/
+ mkEvalWhiskerLeftComp (f g : Mor₁) (η η₁ η₂ η₃ η₄ : NormalExpr)
+ (e_η₁ e_η₂ e_η₃ e_η₄ : Expr) : m Expr
+ /-- Evaluate `𝟙 _ ◁ η` -/
+ mkEvalWhiskerLeftId (η η₁ η₂ : NormalExpr) (e_η₁ e_η₂ : Expr) : m Expr
+
+/-- Evaluate the expression `η ▷ f`. -/
+class MkEvalWhiskerRight (m : Type → Type) where
+ /-- Evaluate `η ▷ f` -/
+ mkEvalWhiskerRightAuxOf (η : WhiskerRight) (f : Atom₁) : m Expr
+ /-- Evaluate `(η ◫ ηs) ▷ f` -/
+ mkEvalWhiskerRightAuxCons (f : Atom₁) (η : WhiskerRight) (ηs : HorizontalComp)
+ (ηs' η₁ η₂ η₃ : NormalExpr) (e_ηs' e_η₁ e_η₂ e_η₃ : Expr) : m Expr
+ /-- Evaluate `α ▷ f` -/
+ mkEvalWhiskerRightNil (α : Structural) (f : Mor₁) : m Expr
+ /-- Evaluate ` (α ≫ η ≫ ηs) ▷ j` -/
+ mkEvalWhiskerRightConsOfOf (f : Atom₁) (α : Structural) (η : HorizontalComp)
+ (ηs ηs₁ η₁ η₂ η₃ : NormalExpr)
+ (e_ηs₁ e_η₁ e_η₂ e_η₃ : Expr) : m Expr
+ /-- Evaluate `(α ≫ (f ◁ η) ≫ ηs) ▷ g` -/
+ mkEvalWhiskerRightConsWhisker (f : Atom₁) (g : Mor₁) (α : Structural) (η : WhiskerLeft)
+ (ηs η₁ η₂ ηs₁ ηs₂ η₃ η₄ η₅ : NormalExpr) (e_η₁ e_η₂ e_ηs₁ e_ηs₂ e_η₃ e_η₄ e_η₅ : Expr) : m Expr
+ /-- Evaluate `η ▷ (g ⊗ h)` -/
+ mkEvalWhiskerRightComp (g h : Mor₁)
+ (η η₁ η₂ η₃ η₄ : NormalExpr) (e_η₁ e_η₂ e_η₃ e_η₄ : Expr) : m Expr
+ /-- Evaluate `η ▷ 𝟙 _` -/
+ mkEvalWhiskerRightId (η η₁ η₂ : NormalExpr) (e_η₁ e_η₂ : Expr) : m Expr
+
+/-- Evaluate the expression `η ◫ θ`. -/
+class MkEvalHorizontalComp (m : Type → Type) where
+ /-- Evaluate `η ◫ θ` -/
+ mkEvalHorizontalCompAuxOf (η : WhiskerRight) (θ : HorizontalComp) : m Expr
+ /-- Evaluate `(η ◫ ηs) ◫ θ` -/
+ mkEvalHorizontalCompAuxCons (η : WhiskerRight) (ηs θ : HorizontalComp)
+ (ηθ η₁ ηθ₁ ηθ₂ : NormalExpr) (e_ηθ e_η₁ e_ηθ₁ e_ηθ₂ : Expr) : m Expr
+ /-- Evaluate `(f ◁ η) ◫ θ` -/
+ mkEvalHorizontalCompAux'Whisker (f : Atom₁) (η θ : WhiskerLeft)
+ (ηθ ηθ₁ ηθ₂ ηθ₃ : NormalExpr) (e_ηθ e_ηθ₁ e_ηθ₂ e_ηθ₃ : Expr) : m Expr
+ /-- Evaluate `η ◫ (f ◁ θ)` -/
+ mkEvalHorizontalCompAux'OfWhisker (f : Atom₁) (η : HorizontalComp) (θ : WhiskerLeft)
+ (η₁ ηθ ηθ₁ ηθ₂ : NormalExpr) (e_ηθ e_η₁ e_ηθ₁ e_ηθ₂ : Expr) : m Expr
+ /-- Evaluate `α ◫ β` -/
+ mkEvalHorizontalCompNilNil (α β : Structural) : m Expr
+ /-- Evaluate `α ◫ (β ≫ η ≫ ηs)` -/
+ mkEvalHorizontalCompNilCons (α β : Structural) (η : WhiskerLeft)
+ (ηs η₁ ηs₁ η₂ η₃ : NormalExpr) (e_η₁ e_ηs₁ e_η₂ e_η₃ : Expr) : m Expr
+ /-- Evaluate `(α ≫ η ≫ ηs) ◫ β` -/
+ mkEvalHorizontalCompConsNil (α β : Structural) (η : WhiskerLeft) (ηs : NormalExpr)
+ (η₁ ηs₁ η₂ η₃ : NormalExpr) (e_η₁ e_ηs₁ e_η₂ e_η₃ : Expr) : m Expr
+ /-- Evaluate `(α ≫ η ≫ ηs) ◫ (β ≫ θ ≫ θs)` -/
+ mkEvalHorizontalCompConsCons (α β : Structural) (η θ : WhiskerLeft)
+ (ηs θs ηθ ηθs ηθ₁ ηθ₂ : NormalExpr) (e_ηθ e_ηθs e_ηθ₁ e_ηθ₂ : Expr) : m Expr
+
+/-- Evaluate the expression of a 2-morphism into a normalized form. -/
+class MkEval (m : Type → Type) extends
+ MkEvalComp m, MkEvalWhiskerLeft m, MkEvalWhiskerRight m, MkEvalHorizontalComp m where
+ /-- Evaluate the expression `η ≫ θ` into a normalized form. -/
+ mkEvalComp (η θ : Mor₂) (η' θ' ηθ : NormalExpr) (e_η e_θ e_ηθ : Expr) : m Expr
+ /-- Evaluate the expression `f ◁ η` into a normalized form. -/
+ mkEvalWhiskerLeft (f : Mor₁) (η : Mor₂) (η' θ : NormalExpr) (e_η e_θ : Expr) : m Expr
+ /-- Evaluate the expression `η ▷ f` into a normalized form. -/
+ mkEvalWhiskerRight (η : Mor₂) (h : Mor₁) (η' θ : NormalExpr) (e_η e_θ : Expr) : m Expr
+ /-- Evaluate the expression `η ◫ θ` into a normalized form. -/
+ mkEvalHorizontalComp (η θ : Mor₂) (η' θ' ι : NormalExpr) (e_η e_θ e_ι : Expr) : m Expr
+ /-- Evaluate the atomic 2-morphism `η` into a normalized form. -/
+ mkEvalOf (η : Atom) : m Expr
+ /-- Evaluate the expression `η ⊗≫ θ := η ≫ α ≫ θ` into a normalized form. -/
+ mkEvalMonoidalComp (η θ : Mor₂) (α : Structural) (η' θ' αθ ηαθ : NormalExpr)
+ (e_η e_θ e_αθ e_ηαθ : Expr) : m Expr
+
+variable {ρ : Type}
+variable [MonadMor₂Iso (CoherenceM ρ)] [MonadNormalExpr (CoherenceM ρ)] [MkEval (CoherenceM ρ)]
+
+open MkEvalComp MonadMor₂Iso MonadNormalExpr
+
+/-- Evaluate the expression `α ≫ η` into a normalized form. -/
+def evalCompNil (α : Structural) : NormalExpr → CoherenceM ρ Eval.Result
+ | .nil _ β => do return ⟨← nilM (← comp₂M α β), ← mkEvalCompNilNil α β⟩
+ | .cons _ β η ηs => do return ⟨← consM (← comp₂M α β) η ηs, ← mkEvalCompNilCons α β η ηs⟩
+
+/-- Evaluate the expression `η ≫ θ` into a normalized form. -/
+def evalComp : NormalExpr → NormalExpr → CoherenceM ρ Eval.Result
+ | .nil _ α, η => do evalCompNil α η
+ | .cons _ α η ηs, θ => do
+ let ⟨ι, e_ι⟩ ← evalComp ηs θ
+ return ⟨← consM α η ι, ← mkEvalCompCons α η ηs θ ι e_ι⟩
+
+open MkEvalWhiskerLeft
+
+variable [MonadMor₁ (CoherenceM ρ)] [MonadMor₂Iso (CoherenceM ρ)]
+
+/-- Evaluate the expression `f ◁ η` into a normalized form. -/
+def evalWhiskerLeft : Mor₁ → NormalExpr → CoherenceM ρ Eval.Result
+ | f, .nil _ α => do
+ return ⟨← nilM (← whiskerLeftM f α), ← mkEvalWhiskerLeftNil f α⟩
+ | .of f, .cons _ α η ηs => do
+ let η' ← MonadWhiskerLeft.whiskerLeftM f η
+ let ⟨θ, e_θ⟩ ← evalWhiskerLeft (.of f) ηs
+ let η'' ← consM (← whiskerLeftM (.of f) α) η' θ
+ return ⟨η'', ← mkEvalWhiskerLeftOfCons f α η ηs θ e_θ⟩
+ | .comp _ f g, η => do
+ let ⟨θ, e_θ⟩ ← evalWhiskerLeft g η
+ let ⟨ι, e_ι⟩ ← evalWhiskerLeft f θ
+ let h ← η.srcM
+ let h' ← η.tgtM
+ let ⟨ι', e_ι'⟩ ← evalComp ι (← NormalExpr.associatorInvM f g h')
+ let ⟨ι'', e_ι''⟩ ← evalComp (← NormalExpr.associatorM f g h) ι'
+ return ⟨ι'', ← mkEvalWhiskerLeftComp f g η θ ι ι' ι'' e_θ e_ι e_ι' e_ι''⟩
+ | .id _ _, η => do
+ let f ← η.srcM
+ let g ← η.tgtM
+ let ⟨η', e_η'⟩ ← evalComp η (← NormalExpr.leftUnitorInvM g)
+ let ⟨η'', e_η''⟩ ← evalComp (← NormalExpr.leftUnitorM f) η'
+ return ⟨η'', ← mkEvalWhiskerLeftId η η' η'' e_η' e_η''⟩
+
+open MkEvalWhiskerRight MkEvalHorizontalComp
+
+mutual
+
+/-- Evaluate the expression `η ▷ f` into a normalized form. -/
+partial def evalWhiskerRightAux : HorizontalComp → Atom₁ → CoherenceM ρ Eval.Result
+ | .of η, f => do
+ let η' ← NormalExpr.ofM <| .of <| .of <| ← MonadWhiskerRight.whiskerRightM η f
+ return ⟨η', ← mkEvalWhiskerRightAuxOf η f⟩
+ | .cons _ η ηs, f => do
+ let ⟨ηs', e_ηs'⟩ ← evalWhiskerRightAux ηs f
+ let ⟨η₁, e_η₁⟩ ← evalHorizontalComp (← NormalExpr.ofM <| .of <| .of η) ηs'
+ let ⟨η₂, e_η₂⟩ ← evalComp η₁ (← NormalExpr.associatorInvM (← η.tgtM) (← ηs.tgtM) (.of f))
+ let ⟨η₃, e_η₃⟩ ← evalComp (← NormalExpr.associatorM (← η.srcM) (← ηs.srcM) (.of f)) η₂
+ return ⟨η₃, ← mkEvalWhiskerRightAuxCons f η ηs ηs' η₁ η₂ η₃ e_ηs' e_η₁ e_η₂ e_η₃⟩
+
+/-- Evaluate the expression `η ▷ f` into a normalized form. -/
+partial def evalWhiskerRight : NormalExpr → Mor₁ → CoherenceM ρ Eval.Result
+ | .nil _ α, h => do
+ return ⟨← nilM (← whiskerRightM α h), ← mkEvalWhiskerRightNil α h⟩
+ | .cons _ α (.of η) ηs, .of f => do
+ let ⟨ηs₁, e_ηs₁⟩ ← evalWhiskerRight ηs (.of f)
+ let ⟨η₁, e_η₁⟩ ← evalWhiskerRightAux η f
+ let ⟨η₂, e_η₂⟩ ← evalComp η₁ ηs₁
+ let ⟨η₃, e_η₃⟩ ← evalCompNil (← whiskerRightM α (.of f)) η₂
+ return ⟨η₃, ← mkEvalWhiskerRightConsOfOf f α η ηs ηs₁ η₁ η₂ η₃ e_ηs₁ e_η₁ e_η₂ e_η₃⟩
+ | .cons _ α (.whisker _ f η) ηs, h => do
+ let g ← η.srcM
+ let g' ← η.tgtM
+ let ⟨η₁, e_η₁⟩ ← evalWhiskerRight (← consM (← id₂M' g) η (← NormalExpr.idM g')) h
+ let ⟨η₂, e_η₂⟩ ← evalWhiskerLeft (.of f) η₁
+ let ⟨ηs₁, e_ηs₁⟩ ← evalWhiskerRight ηs h
+ let α' ← whiskerRightM α h
+ let ⟨ηs₂, e_ηs₂⟩ ← evalComp (← NormalExpr.associatorInvM (.of f) g' h) ηs₁
+ let ⟨η₃, e_η₃⟩ ← evalComp η₂ ηs₂
+ let ⟨η₄, e_η₄⟩ ← evalComp (← NormalExpr.associatorM (.of f) g h) η₃
+ let ⟨η₅, e_η₅⟩ ← evalComp (← nilM α') η₄
+ return ⟨η₅, ← mkEvalWhiskerRightConsWhisker f h α η ηs η₁ η₂ ηs₁ ηs₂ η₃ η₄ η₅
+ e_η₁ e_η₂ e_ηs₁ e_ηs₂ e_η₃ e_η₄ e_η₅⟩
+ | η, .comp _ g h => do
+ let ⟨η₁, e_η₁⟩ ← evalWhiskerRight η g
+ let ⟨η₂, e_η₂⟩ ← evalWhiskerRight η₁ h
+ let f ← η.srcM
+ let f' ← η.tgtM
+ let ⟨η₃, e_η₃⟩ ← evalComp η₂ (← NormalExpr.associatorM f' g h)
+ let ⟨η₄, e_η₄⟩ ← evalComp (← NormalExpr.associatorInvM f g h) η₃
+ return ⟨η₄, ← mkEvalWhiskerRightComp g h η η₁ η₂ η₃ η₄ e_η₁ e_η₂ e_η₃ e_η₄⟩
+ | η, .id _ _ => do
+ let f ← η.srcM
+ let g ← η.tgtM
+ let ⟨η₁, e_η₁⟩ ← evalComp η (← NormalExpr.rightUnitorInvM g)
+ let ⟨η₂, e_η₂⟩ ← evalComp (← NormalExpr.rightUnitorM f) η₁
+ return ⟨η₂, ← mkEvalWhiskerRightId η η₁ η₂ e_η₁ e_η₂⟩
+
+/-- Evaluate the expression `η ⊗ θ` into a normalized form. -/
+partial def evalHorizontalCompAux : HorizontalComp → HorizontalComp → CoherenceM ρ Eval.Result
+ | .of η, θ => do
+ return ⟨← NormalExpr.ofM <| .of <| ← MonadHorizontalComp.hConsM η θ,
+ ← mkEvalHorizontalCompAuxOf η θ⟩
+ | .cons _ η ηs, θ => do
+ let α ← NormalExpr.associatorM (← η.srcM) (← ηs.srcM) (← θ.srcM)
+ let α' ← NormalExpr.associatorInvM (← η.tgtM) (← ηs.tgtM) (← θ.tgtM)
+ let ⟨ηθ, e_ηθ⟩ ← evalHorizontalCompAux ηs θ
+ let ⟨η₁, e_η₁⟩ ← evalHorizontalComp (← NormalExpr.ofM <| .of <| .of η) ηθ
+ let ⟨ηθ₁, e_ηθ₁⟩ ← evalComp η₁ α'
+ let ⟨ηθ₂, e_ηθ₂⟩ ← evalComp α ηθ₁
+ return ⟨ηθ₂, ← mkEvalHorizontalCompAuxCons η ηs θ ηθ η₁ ηθ₁ ηθ₂ e_ηθ e_η₁ e_ηθ₁ e_ηθ₂⟩
+
+/-- Evaluate the expression `η ⊗ θ` into a normalized form. -/
+partial def evalHorizontalCompAux' : WhiskerLeft → WhiskerLeft → CoherenceM ρ Eval.Result
+ | .of η, .of θ => evalHorizontalCompAux η θ
+ | .whisker _ f η, θ => do
+ let ⟨ηθ, e_ηθ⟩ ← evalHorizontalCompAux' η θ
+ let ⟨ηθ₁, e_ηθ₁⟩ ← evalWhiskerLeft (.of f) ηθ
+ let ⟨ηθ₂, e_ηθ₂⟩ ← evalComp ηθ₁ (← NormalExpr.associatorInvM (.of f) (← η.tgtM) (← θ.tgtM))
+ let ⟨ηθ₃, e_ηθ₃⟩ ← evalComp (← NormalExpr.associatorM (.of f) (← η.srcM) (← θ.srcM)) ηθ₂
+ return ⟨ηθ₃, ← mkEvalHorizontalCompAux'Whisker f η θ ηθ ηθ₁ ηθ₂ ηθ₃ e_ηθ e_ηθ₁ e_ηθ₂ e_ηθ₃⟩
+ | .of η, .whisker _ f θ => do
+ let ⟨η₁, e_η₁⟩ ← evalWhiskerRightAux η f
+ let ⟨ηθ, e_ηθ⟩ ← evalHorizontalComp η₁ (← NormalExpr.ofM θ)
+ let ⟨ηθ₁, e_ηθ₁⟩ ← evalComp ηθ (← NormalExpr.associatorM (← η.tgtM) (.of f) (← θ.tgtM))
+ let ⟨ηθ₂, e_ηθ₂⟩ ← evalComp (← NormalExpr.associatorInvM (← η.srcM) (.of f) (← θ.srcM)) ηθ₁
+ return ⟨ηθ₂, ← mkEvalHorizontalCompAux'OfWhisker f η θ ηθ η₁ ηθ₁ ηθ₂ e_η₁ e_ηθ e_ηθ₁ e_ηθ₂⟩
+
+/-- Evaluate the expression `η ⊗ θ` into a normalized form. -/
+partial def evalHorizontalComp : NormalExpr → NormalExpr → CoherenceM ρ Eval.Result
+ | .nil _ α, .nil _ β => do
+ return ⟨← nilM <| ← horizontalCompM α β, ← mkEvalHorizontalCompNilNil α β⟩
+ | .nil _ α, .cons _ β η ηs => do
+ let ⟨η₁, e_η₁⟩ ← evalWhiskerLeft (← α.tgtM) (← NormalExpr.ofM η)
+ let ⟨ηs₁, e_ηs₁⟩ ← evalWhiskerLeft (← α.tgtM) ηs
+ let ⟨η₂, e_η₂⟩ ← evalComp η₁ ηs₁
+ let ⟨η₃, e_η₃⟩ ← evalCompNil (← horizontalCompM α β) η₂
+ return ⟨η₃, ← mkEvalHorizontalCompNilCons α β η ηs η₁ ηs₁ η₂ η₃ e_η₁ e_ηs₁ e_η₂ e_η₃⟩
+ | .cons _ α η ηs, .nil _ β => do
+ let ⟨η₁, e_η₁⟩ ← evalWhiskerRight (← NormalExpr.ofM η) (← β.tgtM)
+ let ⟨ηs₁, e_ηs₁⟩ ← evalWhiskerRight ηs (← β.tgtM)
+ let ⟨η₂, e_η₂⟩ ← evalComp η₁ ηs₁
+ let ⟨η₃, e_η₃⟩ ← evalCompNil (← horizontalCompM α β) η₂
+ return ⟨η₃, ← mkEvalHorizontalCompConsNil α β η ηs η₁ ηs₁ η₂ η₃ e_η₁ e_ηs₁ e_η₂ e_η₃⟩
+ | .cons _ α η ηs, .cons _ β θ θs => do
+ let ⟨ηθ, e_ηθ⟩ ← evalHorizontalCompAux' η θ
+ let ⟨ηθs, e_ηθs⟩ ← evalHorizontalComp ηs θs
+ let ⟨ηθ₁, e_ηθ₁⟩ ← evalComp ηθ ηθs
+ let ⟨ηθ₂, e_ηθ₂⟩ ← evalCompNil (← horizontalCompM α β) ηθ₁
+ return ⟨ηθ₂,
+ ← mkEvalHorizontalCompConsCons α β η θ ηs θs ηθ ηθs ηθ₁ ηθ₂ e_ηθ e_ηθs e_ηθ₁ e_ηθ₂⟩
+
+end
+
+open MkEval
+
+variable {ρ : Type}
+ [MonadMor₁ (CoherenceM ρ)]
+ [MonadMor₂Iso (CoherenceM ρ)]
+ [MonadNormalExpr (CoherenceM ρ)] [MkEval (CoherenceM ρ)]
+ [MonadMor₂ (CoherenceM ρ)]
+
+/-- Trace the proof of the normalization. -/
+def traceProof (nm : Name) (result : Expr) : CoherenceM ρ Unit := do
+ withTraceNode nm (fun _ => return m!"{checkEmoji} {← inferType result}") do
+ if ← isTracingEnabledFor nm then addTrace nm m!"proof: {result}"
+
+-- TODO: It takes a while to compile. Find out why.
+/-- Evaluate the expression of a 2-morphism into a normalized form. -/
+def eval (nm : Name) (e : Mor₂) : CoherenceM ρ Eval.Result := do
+ withTraceNode nm (fun _ => return m!"eval: {e.e}") do
+ match e with
+ | .isoHom _ _ α => withTraceNode nm (fun _ => return m!"Iso.hom") do match α with
+ | .structuralAtom α => return ⟨← nilM <| .structuralAtom α, ← mkEqRefl e.e⟩
+ | .of η =>
+ let η ← MonadMor₂.atomHomM η
+ let result ← mkEvalOf η
+ traceProof nm result
+ return ⟨← NormalExpr.ofAtomM η, result⟩
+ | _ => throwError "not implemented. try dsimp first."
+ | .isoInv _ _ α => withTraceNode nm (fun _ => return m!"Iso.inv") do match α with
+ | .structuralAtom α => return ⟨← nilM <| (← symmM (.structuralAtom α)), ← mkEqRefl e.e⟩
+ | .of η =>
+ let η ← MonadMor₂.atomInvM η
+ let result ← mkEvalOf η
+ traceProof nm result
+ return ⟨← NormalExpr.ofAtomM η, result⟩
+ | _ => throwError "not implemented. try dsimp first."
+ | .id _ _ f =>
+ let α ← MonadMor₂Iso.id₂M f
+ return ⟨← nilM <| .structuralAtom α, ← mkEqRefl e.e⟩
+ | .comp _ _ _ _ _ η θ => withTraceNode nm (fun _ => return m!"comp") do
+ let ⟨η', e_η⟩ ← eval nm η
+ let ⟨θ', e_θ⟩ ← eval nm θ
+ let ⟨ηθ, pf⟩ ← evalComp η' θ'
+ let result ← mkEvalComp η θ η' θ' ηθ e_η e_θ pf
+ traceProof nm result
+ return ⟨ηθ, result⟩
+ | .whiskerLeft _ _ f _ _ η => withTraceNode nm (fun _ => return m!"whiskerLeft") do
+ let ⟨η', e_η⟩ ← eval nm η
+ let ⟨θ, e_θ⟩ ← evalWhiskerLeft f η'
+ let result ← mkEvalWhiskerLeft f η η' θ e_η e_θ
+ traceProof nm result
+ return ⟨θ, result⟩
+ | .whiskerRight _ _ _ _ η h =>
+ withTraceNode nm (fun _ => return m!"whiskerRight") do
+ let ⟨η', e_η⟩ ← eval nm η
+ let ⟨θ, e_θ⟩ ← evalWhiskerRight η' h
+ let result ← mkEvalWhiskerRight η h η' θ e_η e_θ
+ traceProof nm result
+ return ⟨θ, result⟩
+ | .coherenceComp _ _ _ _ _ _ α₀ η θ =>
+ withTraceNode nm (fun _ => return m!"monoidalComp") do
+ let ⟨η', e_η⟩ ← eval nm η
+ let α₀ := .structuralAtom <| .coherenceHom α₀
+ let α ← nilM α₀
+ let ⟨θ', e_θ⟩ ← eval nm θ
+ let ⟨αθ, e_αθ⟩ ← evalComp α θ'
+ let ⟨ηαθ, e_ηαθ⟩ ← evalComp η' αθ
+ let result ← mkEvalMonoidalComp η θ α₀ η' θ' αθ ηαθ e_η e_θ e_αθ e_ηαθ
+ traceProof nm result
+ return ⟨ηαθ, result⟩
+ | .horizontalComp _ _ _ _ _ _ η θ =>
+ withTraceNode nm (fun _ => return m!"horizontalComp") do
+ let ⟨η', e_η⟩ ← eval nm η
+ let ⟨θ', e_θ⟩ ← eval nm θ
+ let ⟨ηθ, e_ηθ⟩ ← evalHorizontalComp η' θ'
+ let result ← mkEvalHorizontalComp η θ η' θ' ηθ e_η e_θ e_ηθ
+ traceProof nm result
+ return ⟨ηθ, result⟩
+ | .of η =>
+ let result ← mkEvalOf η
+ traceProof nm result
+ return ⟨← NormalExpr.ofAtomM η, result⟩
+
+end
+
+end Mathlib.Tactic.BicategoryLike
diff --git a/Mathlib/Tactic/CategoryTheory/Coherence/PureCoherence.lean b/Mathlib/Tactic/CategoryTheory/Coherence/PureCoherence.lean
new file mode 100644
index 0000000000000..a8b1adeae88c4
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Coherence/PureCoherence.lean
@@ -0,0 +1,198 @@
+/-
+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
+
+/-!
+# Coherence tactic
+
+This file provides a meta framework for the coherence tactic, which solves goals of the form
+`η = θ`, where `η` and `θ` are 2-morphism in a bicategory or morphisms in a monoidal category
+made up only of associators, unitors, and identities.
+
+The function defined here is a meta reimplementation of the formalized coherence theorems provided
+in the following files:
+- Mathlib.CategoryTheory.Monoidal.Free.Coherence
+- Mathlib.CategoryTheory.Bicategory.Coherence
+See these files for a mathematical explanation of the proof of the coherence theorem.
+
+The actual tactics that users will use are given in
+- `Mathlib.Tactic.CategoryTheory.Monoidal.PureCoherence`
+- `Mathlib.Tactic.CategoryTheory.Bicategory.PureCoherence`
+
+-/
+
+open Lean Meta
+
+namespace Mathlib.Tactic
+
+namespace BicategoryLike
+
+/-- The result of normalizing a 1-morphism. -/
+structure Normalize.Result where
+ /-- The normalized 1-morphism. -/
+ normalizedHom : NormalizedHom
+ /-- The 2-morphism from the original 1-morphism to the normalized 1-morphism. -/
+ toNormalize : Mor₂Iso
+ deriving Inhabited
+
+open Mor₂Iso MonadMor₂Iso
+
+variable {ρ : Type} [Context ρ] [MonadMor₁ (CoherenceM ρ)] [MonadMor₂Iso (CoherenceM ρ)]
+
+/-- Meta version of `CategoryTheory.FreeBicategory.normalizeIso`. -/
+def normalize (p : NormalizedHom) (f : Mor₁) :
+ CoherenceM ρ Normalize.Result := do
+ match f with
+ | .id _ _ =>
+ return ⟨p, ← rightUnitorM' p.e⟩
+ | .comp _ f g =>
+ let ⟨pf, η_f⟩ ← normalize p f
+ let η_f' ← whiskerRightM η_f g
+ let ⟨pfg, η_g⟩ ← normalize pf g
+ let η ← comp₂M η_f' η_g
+ let α ← symmM (← associatorM' p.e f g)
+ let η' ← comp₂M α η
+ return ⟨pfg, η'⟩
+ | .of f =>
+ let pf ← NormalizedHom.consM p f
+ let α ← id₂M' pf.e
+ return ⟨pf, α⟩
+
+/-- Lemmas to prove the meta version of `CategoryTheory.FreeBicategory.normalize_naturality`. -/
+class MonadNormalizeNaturality (m : Type → Type) where
+ /-- The naturality for the associator. -/
+ mkNaturalityAssociator (p pf pfg pfgh : NormalizedHom) (f g h : Mor₁)
+ (η_f η_g η_h : Mor₂Iso) : m Expr
+ /-- The naturality for the left unitor. -/
+ mkNaturalityLeftUnitor (p pf : NormalizedHom) (f : Mor₁) (η_f : Mor₂Iso) : m Expr
+ /-- The naturality for the right unitor. -/
+ mkNaturalityRightUnitor (p pf : NormalizedHom) (f : Mor₁) (η_f : Mor₂Iso) : m Expr
+ /-- The naturality for the identity. -/
+ mkNaturalityId (p pf : NormalizedHom) (f : Mor₁) (η_f : Mor₂Iso) : m Expr
+ /-- The naturality for the composition. -/
+ mkNaturalityComp (p pf : NormalizedHom) (f g h : Mor₁) (η θ η_f η_g η_h : Mor₂Iso)
+ (ih_η ih_θ : Expr) : m Expr
+ /-- The naturality for the left whiskering. -/
+ mkNaturalityWhiskerLeft (p pf pfg : NormalizedHom) (f g h : Mor₁)
+ (η η_f η_fg η_fh : Mor₂Iso) (ih_η : Expr) : m Expr
+ /-- The naturality for the right whiskering. -/
+ mkNaturalityWhiskerRight (p pf pfh : NormalizedHom) (f g h : Mor₁) (η η_f η_g η_fh : Mor₂Iso)
+ (ih_η : Expr) : m Expr
+ /-- The naturality for the horizontal composition. -/
+ mkNaturalityHorizontalComp (p pf₁ pf₁f₂ : NormalizedHom) (f₁ g₁ f₂ g₂ : Mor₁)
+ (η θ η_f₁ η_g₁ η_f₂ η_g₂ : Mor₂Iso) (ih_η ih_θ : Expr) : m Expr
+ /-- The naturality for the inverse. -/
+ mkNaturalityInv (p pf : NormalizedHom) (f g : Mor₁) (η η_f η_g : Mor₂Iso) (ih_η : Expr) : m Expr
+
+open MonadNormalizeNaturality
+
+variable [MonadCoherehnceHom (CoherenceM ρ)] [MonadNormalizeNaturality (CoherenceM ρ)]
+
+/-- Meta version of `CategoryTheory.FreeBicategory.normalize_naturality`. -/
+partial def naturality (nm : Name) (p : NormalizedHom) (η : Mor₂Iso) : CoherenceM ρ Expr := do
+ let result ← match η with
+ | .of _ => throwError m!"could not find a structural isomorphism, but {η.e}"
+ | .coherenceComp _ _ _ _ _ α η θ => withTraceNode nm (fun _ => return m!"monoidalComp") do
+ let α ← MonadCoherehnceHom.unfoldM α
+ let αθ ← comp₂M α θ
+ let ηαθ ← comp₂M η αθ
+ naturality nm p ηαθ
+ | .structuralAtom η => match η with
+ | .coherenceHom α => withTraceNode nm (fun _ => return m!"coherenceHom") do
+ let α ← MonadCoherehnceHom.unfoldM α
+ naturality nm p α
+ | .associator _ f g h => withTraceNode nm (fun _ => return m!"associator") do
+ let ⟨pf, η_f⟩ ← normalize p f
+ let ⟨pfg, η_g⟩ ← normalize pf g
+ let ⟨pfgh, η_h⟩ ← normalize pfg h
+ mkNaturalityAssociator p pf pfg pfgh f g h η_f η_g η_h
+ | .leftUnitor _ f => withTraceNode nm (fun _ => return m!"leftUnitor") do
+ let ⟨pf, η_f⟩ ← normalize p f
+ mkNaturalityLeftUnitor p pf f η_f
+ | .rightUnitor _ f => withTraceNode nm (fun _ => return m!"rightUnitor") do
+ let ⟨pf, η_f⟩ ← normalize p f
+ mkNaturalityRightUnitor p pf f η_f
+ | .id _ f => withTraceNode nm (fun _ => return m!"id") do
+ let ⟨pf, η_f⟩ ← normalize p f
+ mkNaturalityId p pf f η_f
+ | .comp _ f g h η θ => withTraceNode nm (fun _ => return m!"comp") do
+ let ⟨pf, η_f⟩ ← normalize p f
+ let ⟨_, η_g⟩ ← normalize p g
+ let ⟨_, η_h⟩ ← normalize p h
+ let ih_η ← naturality nm p η
+ let ih_θ ← naturality nm p θ
+ mkNaturalityComp p pf f g h η θ η_f η_g η_h ih_η ih_θ
+ | .whiskerLeft _ f g h η => withTraceNode nm (fun _ => return m!"whiskerLeft") do
+ let ⟨pf, η_f⟩ ← normalize p f
+ let ⟨pfg, η_fg⟩ ← normalize pf g
+ let ⟨_, η_fh⟩ ← normalize pf h
+ let ih ← naturality nm pf η
+ mkNaturalityWhiskerLeft p pf pfg f g h η η_f η_fg η_fh ih
+ | .whiskerRight _ f g η h => withTraceNode nm (fun _ => return m!"whiskerRight") do
+ let ⟨pf, η_f⟩ ← normalize p f
+ let ⟨_, η_g⟩ ← normalize p g
+ let ⟨pfh, η_fh⟩ ← normalize pf h
+ let ih ← naturality nm p η
+ mkNaturalityWhiskerRight p pf pfh f g h η η_f η_g η_fh ih
+ | .horizontalComp _ f₁ g₁ f₂ g₂ η θ => withTraceNode nm (fun _ => return m!"hComp") do
+ let ⟨pf₁, η_f₁⟩ ← normalize p f₁
+ let ⟨_, η_g₁⟩ ← normalize p g₁
+ let ⟨pf₁f₂, η_f₂⟩ ← normalize pf₁ f₂
+ let ⟨_, η_g₂⟩ ← normalize pf₁ g₂
+ let ih_η ← naturality nm p η
+ let ih_θ ← naturality nm pf₁ θ
+ mkNaturalityHorizontalComp p pf₁ pf₁f₂ f₁ g₁ f₂ g₂ η θ η_f₁ η_g₁ η_f₂ η_g₂ ih_η ih_θ
+ | .inv _ f g η => withTraceNode nm (fun _ => return m!"inv") do
+ let ⟨pf, η_f⟩ ← normalize p f
+ let ⟨_, η_g⟩ ← normalize p g
+ let ih_η ← naturality nm p η
+ mkNaturalityInv p pf f g η η_f η_g ih_η
+ withTraceNode nm (fun _ => return m!"{checkEmoji} {← inferType result}") do
+ if ← isTracingEnabledFor nm then addTrace nm m!"proof: {result}"
+ return result
+
+/-- Prove the equality between structural isomorphisms using the naturality of `normalize`. -/
+class MkEqOfNaturality (m : Type → Type) where
+ /-- Auxiliary function for `pureCoherence`. -/
+ mkEqOfNaturality (η θ : Expr) (η' θ' : IsoLift) (η_f η_g : Mor₂Iso) (Hη Hθ : Expr) : m Expr
+
+export MkEqOfNaturality (mkEqOfNaturality)
+
+/-- Close the goal of the form `η = θ`, where `η` and `θ` are 2-isomorphisms made up only of
+associators, unitors, and identities. -/
+def pureCoherence (ρ : Type) [Context ρ] [MkMor₂ (CoherenceM ρ)]
+ [MonadMor₁ (CoherenceM ρ)] [MonadMor₂Iso (CoherenceM ρ)]
+ [MonadCoherehnceHom (CoherenceM ρ)] [MonadNormalizeNaturality (CoherenceM ρ)]
+ [MkEqOfNaturality (CoherenceM ρ)]
+ (nm : Name) (mvarId : MVarId) : MetaM (List MVarId) :=
+ mvarId.withContext do
+ withTraceNode nm (fun ex => match ex with
+ | .ok _ => return m!"{checkEmoji} coherence equality: {← mvarId.getType}"
+ | .error err => return m!"{crossEmoji} {err.toMessageData}") do
+ let e ← instantiateMVars <| ← mvarId.getType
+ let some (_, η, θ) := (← whnfR e).eq?
+ | throwError "coherence requires an equality goal"
+ let ctx : ρ ← mkContext η
+ CoherenceM.run (ctx := ctx) do
+ let .some ηIso := (← MkMor₂.ofExpr η).isoLift? |
+ throwError "could not find a structural isomorphism, but {η}"
+ let .some θIso := (← MkMor₂.ofExpr θ).isoLift? |
+ throwError "could not find a structural isomorphism, but {θ}"
+ let f ← ηIso.e.srcM
+ let g ← ηIso.e.tgtM
+ let a := f.src
+ let nil ← normalizedHom.nilM a
+ let ⟨_, η_f⟩ ← normalize nil f
+ let ⟨_, η_g⟩ ← normalize nil g
+ let Hη ← withTraceNode nm (fun ex => do return m!"{exceptEmoji ex} LHS") do
+ naturality nm nil ηIso.e
+ let Hθ ← withTraceNode nm (fun ex => do return m!"{exceptEmoji ex} RHS") do
+ naturality nm nil θIso.e
+ let H ← mkEqOfNaturality η θ ηIso θIso η_f η_g Hη Hθ
+ mvarId.apply H
+
+end Mathlib.Tactic.BicategoryLike
diff --git a/Mathlib/Tactic/CategoryTheory/Elementwise.lean b/Mathlib/Tactic/CategoryTheory/Elementwise.lean
index d59751db664cf..4a108c00b9927 100644
--- a/Mathlib/Tactic/CategoryTheory/Elementwise.lean
+++ b/Mathlib/Tactic/CategoryTheory/Elementwise.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Kyle Miller
+Authors: Kim Morrison, Kyle Miller
-/
import Mathlib.CategoryTheory.ConcreteCategory.Basic
@@ -29,7 +29,7 @@ For more details, see the documentation attached to the `syntax` declaration.
## Implementation
This closely follows the implementation of the `@[reassoc]` attribute, due to Simon Hudon and
-reimplemented by Scott Morrison in Lean 4.
+reimplemented by Kim Morrison in Lean 4.
-/
open Lean Meta Elab Tactic
@@ -93,7 +93,7 @@ def elementwiseExpr (src : Name) (type pf : Expr) (simpSides := true) :
-- check that it's not a simp-trivial equality:
forallTelescope ty' fun _ ty' => do
if let some (_, lhs, rhs) := ty'.eq? then
- if ← Std.Tactic.Lint.isSimpEq lhs rhs then
+ if ← Batteries.Tactic.Lint.isSimpEq lhs rhs then
throwError "applying simp to both sides reduces elementwise lemma for {src} \
to the trivial equality {ty'}. \
Either add `nosimp` or remove the `elementwise` attribute."
diff --git a/Mathlib/Tactic/CategoryTheory/Monoidal.lean b/Mathlib/Tactic/CategoryTheory/Monoidal.lean
deleted file mode 100644
index 102a73c29e2a4..0000000000000
--- a/Mathlib/Tactic/CategoryTheory/Monoidal.lean
+++ /dev/null
@@ -1,684 +0,0 @@
-/-
-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.Tactic.CategoryTheory.MonoidalComp
-
-/-!
-# Normalization of morphisms in monoidal categories
-This file provides a tactic that normalizes morphisms in monoidal categories. This is used in the
-string diagram widget given in `Mathlib.Tactic.StringDiagram`.
-We say that the morphism `η` in a monoidal category is in normal form if
-1. `η` is of the form `α₀ ≫ η₀ ≫ α₁ ≫ η₁ ≫ ... αₘ ≫ ηₘ ≫ αₘ₊₁` where each `αᵢ` is a
- structural 2-morphism (consisting of associators and unitors),
-2. each `ηᵢ` is a non-structural 2-morphism of the form `f₁ ◁ ... ◁ fₘ ◁ θ`, and
-3. `θ` is of the form `ι ▷ g₁ ▷ ... ▷ gₗ`
-
-Note that the structural morphisms `αᵢ` are not necessarily normalized, as the main purpose
-is to get a list of the non-structural morphisms out.
-
-Currently, the primary application of the normalization tactic in mind is drawing string diagrams,
-which are graphical representations of morphisms in monoidal categories, in the infoview. When
-drawing string diagrams, we often ignore associators and unitors (i.e., drawing morphisms in
-strict monoidal categories). On the other hand, in Lean, it is considered difficult to formalize
-the concept of strict monoidal categories due to the feature of dependent type theory. The
-normalization tactic can remove associators and unitors from the expression, extracting the
-necessary data for drawing string diagrams.
-
-The current plan on drawing string diagrams (#10581) is to use
-Penrose (https://github.com/penrose) via ProofWidget. However, it should be noted that the
-normalization procedure in this file does not rely on specific settings, allowing for broader
-application.
-
-Future plans include the following. At least I (Yuma) would like to work on these in the future,
-but it might not be immediate. If anyone is interested, I would be happy to discuss.
-
-- Currently (#10581), the string diagrams only do drawing. It would be better they also generate
- proofs. That is, by manipulating the string diagrams displayed in the infoview with a mouse to
- generate proofs. In #10581, the string diagram widget only uses the morphisms generated by the
- normalization tactic and does not use proof terms ensuring that the original morphism and the
- normalized morphism are equal. Proof terms will be necessary for proof generation.
-
-- There is also the possibility of using homotopy.io (https://github.com/homotopy-io), a graphical
- proof assistant for category theory, from Lean. At this point, I have very few ideas regarding
- this approach.
-
-- The normalization tactic allows for an alternative implementation of the coherent tactic.
-
-## Main definitions
-- `Tactic.Monoidal.eval`: Given a Lean expression `e` that represents a morphism in a monoidal
-category, this function returns a pair of `⟨e', pf⟩` where `e'` is the normalized expression of `e`
-and `pf` is a proof that `e = e'`.
-
--/
-
-open Lean Meta Elab
-open CategoryTheory
-
-namespace Mathlib.Tactic.Monoidal
-
-/-- The context for evaluating expressions. -/
-structure Context where
- /-- The expression for the underlying category. -/
- C : Expr
-
-/-- Populate a `context` object for evaluating `e`. -/
-def mkContext? (e : Expr) : MetaM (Option Context) := do
- match (← inferType e).getAppFnArgs with
- | (``Quiver.Hom, #[_, _, f, _]) =>
- let C ← inferType f
- return some ⟨C⟩
- | _ => return none
-
-/-- The monad for the normalization of 2-morphisms. -/
-abbrev MonoidalM := ReaderT Context MetaM
-
-/-- Run a computation in the `M` monad. -/
-abbrev MonoidalM.run {α : Type} (c : Context) (m : MonoidalM α) : MetaM α :=
- ReaderT.run m c
-
-/-- Expressions for atomic 1-morphisms. -/
-structure Atom₁ : Type where
- /-- Extract a Lean expression from an `Atom₁` expression. -/
- e : Expr
-
-/-- Expressions for 1-morphisms. -/
-inductive Mor₁ : Type
- /-- `id` is the expression for `𝟙_ C`. -/
- | id : Mor₁
- /-- `comp X Y` is the expression for `X ⊗ Y` -/
- | comp : Mor₁ → Mor₁ → Mor₁
- /-- Construct the expression for an atomic 1-morphism. -/
- | of : Atom₁ → Mor₁
- deriving Inhabited
-
-/-- Converts a 1-morphism into a list of its components. -/
-def Mor₁.toList : Mor₁ → List Atom₁
- | .id => []
- | .comp f g => f.toList ++ g.toList
- | .of f => [f]
-
-/-- Returns `𝟙_ C` if the expression `e` is of the form `𝟙_ C`. -/
-def isTensorUnit? (e : Expr) : MetaM (Option Expr) := do
- let C ← mkFreshExprMVar none
- let instC ← mkFreshExprMVar none
- let instMC ← mkFreshExprMVar none
- let unit := mkAppN (← mkConstWithFreshMVarLevels
- ``MonoidalCategoryStruct.tensorUnit) #[C, instC, instMC]
- if ← withDefault <| isDefEq e unit then
- return ← instantiateMVars unit
- else
- return none
-
-/-- Returns `(f, g)` if the expression `e` is of the form `f ⊗ g`. -/
-def isTensorObj? (e : Expr) : MetaM (Option (Expr × Expr)) := do
- let C ← mkFreshExprMVar none
- let f ← mkFreshExprMVar C
- let g ← mkFreshExprMVar C
- let instC ← mkFreshExprMVar none
- let instMC ← mkFreshExprMVar none
- let fg := mkAppN (← mkConstWithFreshMVarLevels
- ``MonoidalCategoryStruct.tensorObj) #[C, instC, instMC, f, g]
- if ← withDefault <| isDefEq e fg then
- return (← instantiateMVars f, ← instantiateMVars g)
- else
- return none
-
-/-- Construct a `Mor₁` expression from a Lean expression. -/
-partial def toMor₁ (e : Expr) : MetaM Mor₁ := do
- if let some _ ← isTensorUnit? e then
- return Mor₁.id
- else if let some (f, g) ← isTensorObj? e then
- return (← toMor₁ f).comp (← toMor₁ g)
- else
- return Mor₁.of ⟨e⟩
-
-/-- Expressions for atomic structural 2-morphisms. -/
-inductive StructuralAtom : Type
- /-- The expression for the associator `(α_ f g h).hom`. -/
- | associator (f g h : Mor₁) : StructuralAtom
- /-- The expression for the inverse of the associator `(α_ f g h).inv`. -/
- | associatorInv (f g h : Mor₁) : StructuralAtom
- /-- The expression for the left unitor `(λ_ f).hom`. -/
- | leftUnitor (f : Mor₁) : StructuralAtom
- /-- The expression for the inverse of the left unitor `(λ_ f).inv`. -/
- | leftUnitorInv (f : Mor₁) : StructuralAtom
- /-- The expression for the right unitor `(ρ_ f).hom`. -/
- | rightUnitor (f : Mor₁) : StructuralAtom
- /-- The expression for the inverse of the right unitor `(ρ_ f).inv`. -/
- | rightUnitorInv (f : Mor₁) : StructuralAtom
- /-- Expressions for `α` in the monoidal composition `η ⊗≫ θ := η ≫ α ≫ θ`. -/
- | monoidalCoherence (f g : Mor₁) (e : Expr) : StructuralAtom
- deriving Inhabited
-
-/-- Construct a `StructuralAtom` expression from a Lean expression. -/
-def structuralAtom? (e : Expr) : MetaM (Option StructuralAtom) := do
- match e.getAppFnArgs with
- | (``Iso.hom, #[_, _, _, _, η]) =>
- match (← whnfR η).getAppFnArgs with
- | (``MonoidalCategoryStruct.associator, #[_, _, _, f, g, h]) =>
- return some <| .associator (← toMor₁ f) (← toMor₁ g) (← toMor₁ h)
- | (``MonoidalCategoryStruct.leftUnitor, #[_, _, _, f]) =>
- return some <| .leftUnitor (← toMor₁ f)
- | (``MonoidalCategoryStruct.rightUnitor, #[_, _, _, f]) =>
- return some <| .rightUnitor (← toMor₁ f)
- | _ => return none
- | (``Iso.inv, #[_, _, _, _, η]) =>
- match (← whnfR η).getAppFnArgs with
- | (``MonoidalCategoryStruct.associator, #[_, _, _, f, g, h]) =>
- return some <| .associatorInv (← toMor₁ f) (← toMor₁ g) (← toMor₁ h)
- | (``MonoidalCategoryStruct.leftUnitor, #[_, _, _, f]) =>
- return some <| .leftUnitorInv (← toMor₁ f)
- | (``MonoidalCategoryStruct.rightUnitor, #[_, _, _, f]) =>
- return some <| .rightUnitorInv (← toMor₁ f)
- | _ => return none
- | _ =>
- match (← whnfR e).getAppFnArgs with
- | (``MonoidalCoherence.hom, #[_, _, f, g, inst]) =>
- return some <| .monoidalCoherence (← toMor₁ f) (← toMor₁ g) inst
- | _ => return none
-
-/-- Expressions for atomic non-structural 2-morphisms. -/
-structure Atom where
- /-- Extract a Lean expression from an `Atom` expression. -/
- e : Expr
- deriving Inhabited
-
-/-- Expressions of the form `η ▷ f₁ ▷ ... ▷ fₙ`. -/
-inductive WhiskerRightExpr : Type
- /-- Construct the expression for an atomic 2-morphism. -/
- | of (η : Atom) : WhiskerRightExpr
- /-- Construct the expression for `η ▷ f`. -/
- | whisker (η : WhiskerRightExpr) (f : Atom₁) : WhiskerRightExpr
- deriving Inhabited
-
-/-- Expressions of the form `f₁ ◁ ... ◁ fₙ ◁ η`. -/
-inductive WhiskerLeftExpr : Type
- /-- Construct the expression for a right-whiskered 2-morphism. -/
- | of (η : WhiskerRightExpr) : WhiskerLeftExpr
- /-- Construct the expression for `f ◁ η`. -/
- | whisker (f : Atom₁) (η : WhiskerLeftExpr) : WhiskerLeftExpr
- deriving Inhabited
-
-/-- Expressions for structural 2-morphisms. -/
-inductive Structural : Type
- /-- Expressions for atomic structural 2-morphisms. -/
- | atom (η : StructuralAtom) : Structural
- /-- Expressions for the identity `𝟙 f`. -/
- | id (f : Mor₁) : Structural
- /-- Expressions for the composition `η ≫ θ`. -/
- | comp (α β : Structural) : Structural
- /-- Expressions for the left whiskering `f ◁ η`. -/
- | whiskerLeft (f : Mor₁) (η : Structural) : Structural
- /-- Expressions for the right whiskering `η ▷ f`. -/
- | whiskerRight (η : Structural) (f : Mor₁) : Structural
- deriving Inhabited
-
-/-- Normalized expressions for 2-morphisms. -/
-inductive NormalExpr : Type
- /-- Construct the expression for a structural 2-morphism. -/
- | nil (α : Structural) : NormalExpr
- /-- Construct the normalized expression of 2-morphisms recursively. -/
- | cons (head_structural : Structural) (head : WhiskerLeftExpr) (tail : NormalExpr) : NormalExpr
- deriving Inhabited
-
-/-- The domain of a morphism. -/
-def src (η : Expr) : MetaM Mor₁ := do
- match (← inferType η).getAppFnArgs with
- | (``Quiver.Hom, #[_, _, f, _]) => toMor₁ f
- | _ => throwError "{η} is not a morphism"
-
-/-- The codomain of a morphism. -/
-def tgt (η : Expr) : MetaM Mor₁ := do
- match (← inferType η).getAppFnArgs with
- | (``Quiver.Hom, #[_, _, _, g]) => toMor₁ g
- | _ => throwError "{η} is not a morphism"
-
-/-- The domain of a 2-morphism. -/
-def Atom.src (η : Atom) : MetaM Mor₁ := do Monoidal.src η.e
-
-/-- The codomain of a 2-morphism. -/
-def Atom.tgt (η : Atom) : MetaM Mor₁ := do Monoidal.tgt η.e
-
-/-- The domain of a 2-morphism. -/
-def WhiskerRightExpr.src : WhiskerRightExpr → MetaM Mor₁
- | WhiskerRightExpr.of η => η.src
- | WhiskerRightExpr.whisker η f => return (← WhiskerRightExpr.src η).comp (Mor₁.of f)
-
-/-- The codomain of a 2-morphism. -/
-def WhiskerRightExpr.tgt : WhiskerRightExpr → MetaM Mor₁
- | WhiskerRightExpr.of η => η.tgt
- | WhiskerRightExpr.whisker η f => return (← WhiskerRightExpr.tgt η).comp (Mor₁.of f)
-
-/-- The domain of a 2-morphism. -/
-def WhiskerLeftExpr.src : WhiskerLeftExpr → MetaM Mor₁
- | WhiskerLeftExpr.of η => WhiskerRightExpr.src η
- | WhiskerLeftExpr.whisker f η => return (Mor₁.of f).comp (← WhiskerLeftExpr.src η)
-
-/-- The codomain of a 2-morphism. -/
-def WhiskerLeftExpr.tgt : WhiskerLeftExpr → MetaM Mor₁
- | WhiskerLeftExpr.of η => WhiskerRightExpr.tgt η
- | WhiskerLeftExpr.whisker f η => return (Mor₁.of f).comp (← WhiskerLeftExpr.tgt η)
-
-/-- The domain of a 2-morphism. -/
-def StructuralAtom.src : StructuralAtom → Mor₁
- | .associator f g h => (f.comp g).comp h
- | .associatorInv f g h => f.comp (g.comp h)
- | .leftUnitor f => Mor₁.id.comp f
- | .leftUnitorInv f => f
- | .rightUnitor f => f.comp Mor₁.id
- | .rightUnitorInv f => f
- | .monoidalCoherence f _ _ => f
-
-/-- The codomain of a 2-morphism. -/
-def StructuralAtom.tgt : StructuralAtom → Mor₁
- | .associator f g h => f.comp (g.comp h)
- | .associatorInv f g h => (f.comp g).comp h
- | .leftUnitor f => f
- | .leftUnitorInv f => Mor₁.id.comp f
- | .rightUnitor f => f
- | .rightUnitorInv f => f.comp Mor₁.id
- | .monoidalCoherence _ g _ => g
-
-/-- The domain of a 2-morphism. -/
-def Structural.src : Structural → Mor₁
- | .atom η => η.src
- | .id f => f
- | .comp α _ => α.src
- | .whiskerLeft f η => f.comp η.src
- | .whiskerRight η f => η.src.comp f
-
-/-- The codomain of a 2-morphism. -/
-def Structural.tgt : Structural → Mor₁
- | .atom η => η.tgt
- | .id f => f
- | .comp _ β => β.tgt
- | .whiskerLeft f η => f.comp η.tgt
- | .whiskerRight η f => η.tgt.comp f
-
-/-- The domain of a 2-morphism. -/
-def NormalExpr.src : NormalExpr → Mor₁
- | NormalExpr.nil η => η.src
- | NormalExpr.cons α _ _ => α.src
-
-/-- The codomain of a 2-morphism. -/
-def NormalExpr.tgt : NormalExpr → Mor₁
- | NormalExpr.nil η => η.tgt
- | NormalExpr.cons _ _ ηs => ηs.tgt
-
-/-- The associator as a term of `normalExpr`. -/
-def NormalExpr.associator (f g h : Mor₁) : NormalExpr :=
- .nil <| .atom <| .associator f g h
-
-/-- The inverse of the associator as a term of `normalExpr`. -/
-def NormalExpr.associatorInv (f g h : Mor₁) : NormalExpr :=
- .nil <| .atom <| .associatorInv f g h
-
-/-- The left unitor as a term of `normalExpr`. -/
-def NormalExpr.leftUnitor (f : Mor₁) : NormalExpr :=
- .nil <| .atom <| .leftUnitor f
-
-/-- The inverse of the left unitor as a term of `normalExpr`. -/
-def NormalExpr.leftUnitorInv (f : Mor₁) : NormalExpr :=
- .nil <| .atom <| .leftUnitorInv f
-
-/-- The right unitor as a term of `normalExpr`. -/
-def NormalExpr.rightUnitor (f : Mor₁) : NormalExpr :=
- .nil <| .atom <| .rightUnitor f
-
-/-- The inverse of the right unitor as a term of `normalExpr`. -/
-def NormalExpr.rightUnitorInv (f : Mor₁) : NormalExpr :=
- .nil <| .atom <| .rightUnitorInv f
-
-/-- Construct a `NormalExpr` expression from a `WhiskerLeftExpr` expression. -/
-def NormalExpr.of (η : WhiskerLeftExpr) : MetaM NormalExpr := do
- return .cons (.id (← η.src)) η (.nil (.id (← η.tgt)))
-
-/-- Construct a `NormalExpr` expression from a Lean expression for an atomic 2-morphism. -/
-def NormalExpr.ofExpr (η : Expr) : MetaM NormalExpr :=
- NormalExpr.of <| .of <| .of ⟨η⟩
-
-/-- If `e` is an expression of the form `η ⊗≫ θ := η ≫ α ≫ θ` in the monoidal category `C`,
-return the expression for `α` .-/
-def structuralOfMonoidalComp (C e : Expr) : MetaM Structural := do
- let v ← mkFreshLevelMVar
- let u ← mkFreshLevelMVar
- _ ← isDefEq (.sort (.succ v)) (← inferType (← inferType e))
- _ ← isDefEq (.sort (.succ u)) (← inferType C)
- let W ← mkFreshExprMVar none
- let X ← mkFreshExprMVar none
- let Y ← mkFreshExprMVar none
- let Z ← mkFreshExprMVar none
- let f ← mkFreshExprMVar none
- let g ← mkFreshExprMVar none
- let α₀ ← mkFreshExprMVar none
- let instC ← mkFreshExprMVar none
- let αg := mkAppN (.const ``CategoryStruct.comp [v, u]) #[C, instC, X, Y, Z, α₀, g]
- let fαg := mkAppN (.const ``CategoryStruct.comp [v, u]) #[C, instC, W, X, Z, f, αg]
- _ ← isDefEq e fαg
- match ← structuralAtom? α₀ with
- | some η => return .atom η
- | none => throwError "not a structural 2-morphism"
-
-section
-
-open scoped MonoidalCategory
-
-universe v u
-
-variable {C : Type u} [Category.{v} C]
-
-variable {f f' g g' h i j : C}
-
-theorem evalComp_nil_cons {f g h i j : C} (α : f ⟶ g) (β : g ⟶ h) (η : h ⟶ i) (ηs : i ⟶ j) :
- α ≫ (β ≫ η ≫ ηs) = (α ≫ β) ≫ η ≫ ηs := by
- simp
-
-@[nolint synTaut]
-theorem evalComp_nil_nil {f g h : C} (α : f ⟶ g) (β : g ⟶ h) :
- α ≫ β = α ≫ β := by
- simp
-
-theorem evalComp_cons {f g h i j : C} (α : f ⟶ g) (η : g ⟶ h) {ηs : h ⟶ i} {θ : i ⟶ j} {ι : h ⟶ j}
- (pf_ι : ηs ≫ θ = ι) :
- (α ≫ η ≫ ηs) ≫ θ = α ≫ η ≫ ι := by
- simp [pf_ι]
-
-theorem eval_comp
- {η η' : f ⟶ g} {θ θ' : g ⟶ h} {ι : f ⟶ h}
- (pf_η : η = η') (pf_θ : θ = θ') (pf_ηθ : η' ≫ θ' = ι) :
- η ≫ θ = ι := by
- simp [pf_η, pf_θ, pf_ηθ]
-
-theorem eval_of (η : f ⟶ g) :
- η = 𝟙 _ ≫ η ≫ 𝟙 _ := by
- simp
-
-theorem eval_monoidalComp
- {η η' : f ⟶ g} {α : g ⟶ h} {θ θ' : h ⟶ i} {αθ : g ⟶ i} {ηαθ : f ⟶ i}
- (pf_η : η = η') (pf_θ : θ = θ') (pf_αθ : α ≫ θ' = αθ) (pf_ηαθ : η' ≫ αθ = ηαθ) :
- η ≫ α ≫ θ = ηαθ := by
- simp [pf_η, pf_θ, pf_αθ, pf_ηαθ]
-
-variable [MonoidalCategory C]
-
-@[nolint synTaut]
-theorem evalWhiskerLeft_nil (f : C) (α : g ⟶ h) :
- f ◁ α = f ◁ α := by
- simp
-
-theorem evalWhiskerLeft_of_cons
- (α : g ⟶ h) (η : h ⟶ i) {ηs : i ⟶ j} {θ : f ⊗ i ⟶ f ⊗ j} (pf_θ : f ◁ ηs = θ) :
- f ◁ (α ≫ η ≫ ηs) = f ◁ α ≫ f ◁ η ≫ θ := by
- simp [pf_θ]
-
-theorem evalWhiskerLeft_comp {η : h ⟶ i} {θ : g ⊗ h ⟶ g ⊗ i} {ι : f ⊗ g ⊗ h ⟶ f ⊗ g ⊗ i}
- {ι' : f ⊗ g ⊗ h ⟶ (f ⊗ g) ⊗ i} {ι'' : (f ⊗ g) ⊗ h ⟶ (f ⊗ g) ⊗ i}
- (pf_θ : g ◁ η = θ) (pf_ι : f ◁ θ = ι)
- (pf_ι' : ι ≫ (α_ _ _ _).inv = ι') (pf_ι'' : (α_ _ _ _).hom ≫ ι' = ι'') :
- (f ⊗ g) ◁ η = ι'' := by
- simp [pf_θ, pf_ι, pf_ι', pf_ι'']
-
-theorem evalWhiskerLeft_id {f g : C} {η : f ⟶ g}
- {η' : f ⟶ 𝟙_ C ⊗ g} {η'' : 𝟙_ C ⊗ f ⟶ 𝟙_ C ⊗ g}
- (pf_η' : η ≫ (λ_ _).inv = η') (pf_η'' : (λ_ _).hom ≫ η' = η'') :
- 𝟙_ C ◁ η = η'' := by
- simp [pf_η', pf_η'']
-
-theorem eval_whiskerLeft
- {η η' : g ⟶ h} {θ : f ⊗ g ⟶ f ⊗ h}
- (pf_η : η = η') (pf_θ : f ◁ η' = θ) :
- f ◁ η = θ := by
- simp [pf_η, pf_θ]
-
-theorem eval_whiskerRight
- {η η' : f ⟶ g} {θ : f ⊗ h ⟶ g ⊗ h}
- (pf_η : η = η') (pf_θ : η' ▷ h = θ) :
- η ▷ h = θ := by
- simp [pf_η, pf_θ]
-
-@[nolint synTaut]
-theorem evalWhiskerRight_nil (α : f ⟶ g) (h : C) :
- α ▷ h = α ▷ h := by
- simp
-
-theorem evalWhiskerRight_cons_of_of
- (α : f ⟶ g) (η : g ⟶ h) {ηs : h ⟶ i} {θ : h ⊗ j ⟶ i ⊗ j}
- (pf_θ : ηs ▷ j = θ) :
- (α ≫ η ≫ ηs) ▷ j = α ▷ j ≫ η ▷ j ≫ θ := by
- simp [pf_θ]
-
-theorem evalWhiskerRight_cons_whisker
- {α : g ⟶ f ⊗ h} {η : h ⟶ i} {ηs : f ⊗ i ⟶ j} {k : C}
- {η₁ : h ⊗ k ⟶ i ⊗ k} {η₂ : f ⊗ (h ⊗ k) ⟶ f ⊗ (i ⊗ k)} {ηs₁ : (f ⊗ i) ⊗ k ⟶ j ⊗ k}
- {ηs₂ : f ⊗ (i ⊗ k) ⟶ j ⊗ k} {η₃ : f ⊗ (h ⊗ k) ⟶ j ⊗ k} {η₄ : (f ⊗ h) ⊗ k ⟶ j ⊗ k}
- {η₅ : g ⊗ k ⟶ j ⊗ k}
- (pf_η₁ : (𝟙 _ ≫ η ≫ 𝟙 _ ) ▷ k = η₁) (pf_η₂ : f ◁ η₁ = η₂)
- (pf_ηs₁ : ηs ▷ k = ηs₁) (pf_ηs₂ : (α_ _ _ _).inv ≫ ηs₁ = ηs₂)
- (pf_η₃ : η₂ ≫ ηs₂ = η₃) (pf_η₄ : (α_ _ _ _).hom ≫ η₃ = η₄) (pf_η₅ : α ▷ k ≫ η₄ = η₅) :
- (α ≫ (f ◁ η) ≫ ηs) ▷ k = η₅ := by
- simp at pf_η₁
- simp [pf_η₁, pf_η₂, pf_ηs₁, pf_ηs₂, pf_η₃, pf_η₄, pf_η₅]
-
-theorem evalWhiskerRight_comp
- {η : f ⟶ f'} {η₁ : f ⊗ g ⟶ f' ⊗ g} {η₂ : (f ⊗ g) ⊗ h ⟶ (f' ⊗ g) ⊗ h}
- {η₃ : (f ⊗ g) ⊗ h ⟶ f' ⊗ (g ⊗ h)} {η₄ : f ⊗ (g ⊗ h) ⟶ f' ⊗ (g ⊗ h)}
- (pf_η₁ : η ▷ g = η₁) (pf_η₂ : η₁ ▷ h = η₂)
- (pf_η₃ : η₂ ≫ (α_ _ _ _).hom = η₃) (pf_η₄ : (α_ _ _ _).inv ≫ η₃ = η₄) :
- η ▷ (g ⊗ h) = η₄ := by
- simp [pf_η₁, pf_η₂, pf_η₃, pf_η₄]
-
-theorem evalWhiskerRight_id
- {η : f ⟶ g} {η₁ : f ⟶ g ⊗ 𝟙_ C} {η₂ : f ⊗ 𝟙_ C ⟶ g ⊗ 𝟙_ C}
- (pf_η₁ : η ≫ (ρ_ _).inv = η₁) (pf_η₂ : (ρ_ _).hom ≫ η₁ = η₂) :
- η ▷ 𝟙_ C = η₂ := by
- simp [pf_η₁, pf_η₂]
-
-end
-
-/-- Extract a Lean expression from a `Mor₁` expression. -/
-def Mor₁.e : Mor₁ → MonoidalM Expr
- | .id => do
- let ctx ← read
- mkAppOptM ``MonoidalCategoryStruct.tensorUnit #[ctx.C, none, none]
- | .comp f g => do
- mkAppM ``MonoidalCategoryStruct.tensorObj #[← Mor₁.e f, ← Mor₁.e g]
- | .of f => return f.e
-
-/-- Extract a Lean expression from a `StructuralAtom` expression. -/
-def StructuralAtom.e : StructuralAtom → MonoidalM Expr
- | .associator f g h => do
- mkAppM ``Iso.hom #[← mkAppM ``MonoidalCategoryStruct.associator #[← f.e, ← g.e, ← h.e]]
- | .associatorInv f g h => do
- mkAppM ``Iso.inv #[← mkAppM ``MonoidalCategoryStruct.associator #[← f.e, ← g.e, ← h.e]]
- | .leftUnitor f => do
- mkAppM ``Iso.hom #[← mkAppM ``MonoidalCategoryStruct.leftUnitor #[← f.e]]
- | .leftUnitorInv f => do
- mkAppM ``Iso.inv #[← mkAppM ``MonoidalCategoryStruct.leftUnitor #[← f.e]]
- | .rightUnitor f => do
- mkAppM ``Iso.hom #[← mkAppM ``MonoidalCategoryStruct.rightUnitor #[← f.e]]
- | .rightUnitorInv f => do
- mkAppM ``Iso.inv #[← mkAppM ``MonoidalCategoryStruct.rightUnitor #[← f.e]]
- | .monoidalCoherence _ _ e => do
- mkAppOptM ``MonoidalCoherence.hom #[none, none, none, none, e]
-
-/-- Extract a Lean expression from a `Structural` expression. -/
-partial def Structural.e : Structural → MonoidalM Expr
- | .atom η => η.e
- | .id f => do mkAppM ``CategoryStruct.id #[← f.e]
- | .comp α β => do mkAppM ``CategoryStruct.comp #[← α.e, ← β.e]
- | .whiskerLeft f η => do mkAppM ``MonoidalCategoryStruct.whiskerLeft #[← f.e, ← η.e]
- | .whiskerRight η f => do mkAppM ``MonoidalCategoryStruct.whiskerRight #[← η.e, ← f.e]
-
-/-- Extract a Lean expression from a `WhiskerRightExpr` expression. -/
-def WhiskerRightExpr.e : WhiskerRightExpr → MonoidalM Expr
- | WhiskerRightExpr.of η => return η.e
- | WhiskerRightExpr.whisker η f => do
- mkAppM ``MonoidalCategoryStruct.whiskerRight #[← η.e, f.e]
-
-/-- Extract a Lean expression from a `WhiskerLeftExpr` expression. -/
-def WhiskerLeftExpr.e : WhiskerLeftExpr → MonoidalM Expr
- | WhiskerLeftExpr.of η => η.e
- | WhiskerLeftExpr.whisker f η => do
- mkAppM ``MonoidalCategoryStruct.whiskerLeft #[f.e, ← η.e]
-
-/-- Extract a Lean expression from a `NormalExpr` expression. -/
-def NormalExpr.e : NormalExpr → MonoidalM Expr
- | NormalExpr.nil α => α.e
- | NormalExpr.cons α η θ => do
- mkAppM ``CategoryStruct.comp #[← α.e, ← mkAppM ``CategoryStruct.comp #[← η.e, ← θ.e]]
-
-/-- The result of evaluating an expression into normal form. -/
-structure Result where
- /-- The normalized expression of the 2-morphism. -/
- expr : NormalExpr
- /-- The proof that the normalized expression is equal to the original expression. -/
- proof : Expr
-
-/-- Evaluate the expression `η ≫ θ` into a normalized form. -/
-partial def evalComp : NormalExpr → NormalExpr → MonoidalM Result
- | .nil α, .cons β η ηs => do
- let η' := .cons (α.comp β) η ηs
- return ⟨η', ← mkAppM ``evalComp_nil_cons #[← α.e, ← β.e, ← η.e, ← ηs.e]⟩
- | .nil α, .nil α' => do
- return ⟨.nil (α.comp α'), ← mkAppM ``evalComp_nil_nil #[← α.e, ← α'.e]⟩
- | .cons α η ηs, θ => do
- let ⟨ι, pf_ι⟩ ← evalComp ηs θ
- let ι' := .cons α η ι
- return ⟨ι', ← mkAppM ``evalComp_cons #[← α.e, ← η.e, pf_ι]⟩
-
-/-- Evaluate the expression `f ◁ η` into a normalized form. -/
-partial def evalWhiskerLeftExpr : Mor₁ → NormalExpr → MonoidalM Result
- | f, .nil α => do
- return ⟨.nil (.whiskerLeft f α), ← mkAppM ``evalWhiskerLeft_nil #[← f.e, ← α.e]⟩
- | .of f, .cons α η ηs => do
- let η' := WhiskerLeftExpr.whisker f η
- let ⟨θ, pf_θ⟩ ← evalWhiskerLeftExpr (.of f) ηs
- let η'' := .cons (.whiskerLeft (.of f) α) η' θ
- return ⟨η'', ← mkAppM ``evalWhiskerLeft_of_cons #[← α.e, ← η.e, pf_θ]⟩
- | .comp f g, η => do
- let ⟨θ, pf_θ⟩ ← evalWhiskerLeftExpr g η
- let ⟨ι, pf_ι⟩ ← evalWhiskerLeftExpr f θ
- let h := η.src
- let h' := η.tgt
- let ⟨ι', pf_ι'⟩ ← evalComp ι (NormalExpr.associatorInv f g h')
- let ⟨ι'', pf_ι''⟩ ← evalComp (NormalExpr.associator f g h) ι'
- return ⟨ι'', ← mkAppM ``evalWhiskerLeft_comp #[pf_θ, pf_ι, pf_ι', pf_ι'']⟩
- | .id, η => do
- let f := η.src
- let g := η.tgt
- let ⟨η', pf_η'⟩ ← evalComp η (NormalExpr.leftUnitorInv g)
- let ⟨η'', pf_η''⟩ ← evalComp (NormalExpr.leftUnitor f) η'
- return ⟨η'', ← mkAppM ``evalWhiskerLeft_id #[pf_η', pf_η'']⟩
-
-/-- Evaluate the expression `η ▷ f` into a normalized form. -/
-partial def evalWhiskerRightExpr : NormalExpr → Mor₁ → MonoidalM Result
- | .nil α, h => do
- return ⟨.nil (.whiskerRight α h), ← mkAppM ``evalWhiskerRight_nil #[← α.e, ← h.e]⟩
- | .cons α (.of η) ηs, .of f => do
- let ⟨θ, pf_θ⟩ ← evalWhiskerRightExpr ηs (.of f)
- let η' := .cons (.whiskerRight α (.of f)) (.of (.whisker η f)) θ
- return ⟨η', ← mkAppM ``evalWhiskerRight_cons_of_of #[← α.e, ← η.e, pf_θ]⟩
- | .cons α (.whisker f η) ηs, h => do
- let g ← η.src
- let g' ← η.tgt
- let ⟨η₁, pf_η₁⟩ ← evalWhiskerRightExpr (.cons (.id g) η (.nil (.id g'))) h
- let ⟨η₂, pf_η₂⟩ ← evalWhiskerLeftExpr (.of f) η₁
- let ⟨ηs₁, pf_ηs₁⟩ ← evalWhiskerRightExpr ηs h
- let α' := .whiskerRight α h
- let ⟨ηs₂, pf_ηs₂⟩ ← evalComp (.associatorInv (.of f) g' h) ηs₁
- let ⟨η₃, pf_η₃⟩ ← evalComp η₂ ηs₂
- let ⟨η₄, pf_η₄⟩ ← evalComp (.associator (.of f) g h) η₃
- let ⟨η₅, pf_η₅⟩ ← evalComp (.nil α') η₄
- return ⟨η₅, ← mkAppM ``evalWhiskerRight_cons_whisker
- #[pf_η₁, pf_η₂, pf_ηs₁, pf_ηs₂, pf_η₃, pf_η₄, pf_η₅]⟩
- | η, .comp g h => do
- let ⟨η₁, pf_η₁⟩ ← evalWhiskerRightExpr η g
- let ⟨η₂, pf_η₂⟩ ← evalWhiskerRightExpr η₁ h
- let f := η.src
- let f' := η.tgt
- let ⟨η₃, pf_η₃⟩ ← evalComp η₂ (.associator f' g h)
- let ⟨η₄, pf_η₄⟩ ← evalComp (.associatorInv f g h) η₃
- return ⟨η₄, ← mkAppM ``evalWhiskerRight_comp #[pf_η₁, pf_η₂, pf_η₃, pf_η₄]⟩
- | η, .id => do
- let f := η.src
- let g := η.tgt
- let ⟨η₁, pf_η₁⟩ ← evalComp η (.rightUnitorInv g)
- let ⟨η₂, pf_η₂⟩ ← evalComp (.rightUnitor f) η₁
- return ⟨η₂, ← mkAppM ``evalWhiskerRight_id #[pf_η₁, pf_η₂]⟩
-
-/-- Evaluate the expression of a 2-morphism into a normalized form. -/
-partial def eval (e : Expr) : MonoidalM Result := do
- if let .some α ← structuralAtom? e then
- return ⟨.nil <| .atom α, ← mkEqRefl (← α.e)⟩
- else
- match e.getAppFnArgs with
- | (``CategoryStruct.id, #[_, _, f]) =>
- return ⟨.nil (.id (← toMor₁ f)), ← mkEqRefl (← mkAppM ``CategoryStruct.id #[f])⟩
- | (``CategoryStruct.comp, #[_, _, _, _, _, η, θ]) =>
- let ⟨η_e, pf_η⟩ ← eval η
- let ⟨θ_e, pf_θ⟩ ← eval θ
- let ⟨ηθ, pf⟩ ← evalComp η_e θ_e
- return ⟨ηθ, ← mkAppM ``eval_comp #[pf_η, pf_θ, pf]⟩
- | (``MonoidalCategoryStruct.whiskerLeft, #[_, _, _, f, _, _, η]) =>
- let ⟨η_e, pf_η⟩ ← eval η
- let ⟨θ, pf_θ⟩ ← evalWhiskerLeftExpr (← toMor₁ f) η_e
- return ⟨θ, ← mkAppM ``eval_whiskerLeft #[pf_η, pf_θ]⟩
- | (``MonoidalCategoryStruct.whiskerRight, #[_, _, _, _, _, η, h]) =>
- let ⟨η_e, pf_η⟩ ← eval η
- let ⟨θ, pf_θ⟩ ← evalWhiskerRightExpr η_e (← toMor₁ h)
- return ⟨θ, ← mkAppM ``eval_whiskerRight #[pf_η, pf_θ]⟩
- | (``monoidalComp, #[C, _, _, _, _, _, _, η, θ]) =>
- let ⟨η_e, pf_η⟩ ← eval η
- let α₀ ← structuralOfMonoidalComp C e
- let α := NormalExpr.nil α₀
- let ⟨θ_e, pf_θ⟩ ← eval θ
- let ⟨αθ, pf_θα⟩ ← evalComp α θ_e
- let ⟨ηαθ, pf_ηαθ⟩ ← evalComp η_e αθ
- return ⟨ηαθ, ← mkAppM ``eval_monoidalComp #[pf_η, pf_θ, pf_θα, pf_ηαθ]⟩
- | _ =>
- return ⟨← NormalExpr.ofExpr e, ← mkAppM ``eval_of #[e]⟩
-
-/-- Convert a `NormalExpr` expression into a list of `WhiskerLeftExpr` expressions. -/
-def NormalExpr.toList : NormalExpr → List WhiskerLeftExpr
- | NormalExpr.nil _ => []
- | NormalExpr.cons _ η ηs => η :: NormalExpr.toList ηs
-
-end Mathlib.Tactic.Monoidal
-
-open Mathlib.Tactic.Monoidal
-
-/-- `normalize% η` is the normalization of the 2-morphism `η`.
-1. The normalized 2-morphism is of the form `α₀ ≫ η₀ ≫ α₁ ≫ η₁ ≫ ... αₘ ≫ ηₘ ≫ αₘ₊₁` where
- each `αᵢ` is a structural 2-morphism (consisting of associators and unitors),
-2. each `ηᵢ` is a non-structural 2-morphism of the form `f₁ ◁ ... ◁ fₘ ◁ θ`, and
-3. `θ` is of the form `ι ▷ g₁ ▷ ... ▷ gₗ`
--/
-elab "normalize% " t:term:51 : term => do
- let e ← Lean.Elab.Term.elabTerm t none
- let some ctx ← mkContext? e
- | throwError "{← ppExpr e} is not a morphism"
- MonoidalM.run ctx do (← eval e).expr.e
-
-theorem mk_eq {α : Type _} (a b a' b' : α) (ha : a = a') (hb : b = b') (h : a' = b') : a = b := by
- simp [h, ha, hb]
-
-open Lean Elab Meta Tactic in
-/-- Transform an equality between 2-morphisms into the equality between their normalizations. -/
-def mkEq (e : Expr) : MetaM Expr := do
- let some (_, e₁, e₂) := (← whnfR <| e).eq?
- | throwError "monoidal_nf requires an equality goal"
- let some ctx ← mkContext? e₁
- | throwError "the lhs and rhs must be morphisms"
- MonoidalM.run ctx do
- let ⟨e₁', p₁⟩ ← eval e₁
- let ⟨e₂', p₂⟩ ← eval e₂
- mkAppM ``mk_eq #[e₁, e₂, ← e₁'.e, ← e₂'.e, p₁, p₂]
-
-open Lean Elab Tactic in
-/-- Normalize the both sides of an equality. -/
-elab "monoidal_nf" : tactic => withMainContext do
- let t ← getMainTarget
- let mvarIds ← (← getMainGoal).apply (← mkEq t)
- replaceMainGoal mvarIds
diff --git a/Mathlib/Tactic/CategoryTheory/Monoidal/Basic.lean b/Mathlib/Tactic/CategoryTheory/Monoidal/Basic.lean
new file mode 100644
index 0000000000000..6158728b44231
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Monoidal/Basic.lean
@@ -0,0 +1,55 @@
+/-
+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.Tactic.CategoryTheory.Coherence.Basic
+import Mathlib.Tactic.CategoryTheory.Monoidal.Normalize
+import Mathlib.Tactic.CategoryTheory.Monoidal.PureCoherence
+
+/-!
+# `monoidal` tactic
+
+This file provides `monoidal` tactic, which solves equations in a monoidal category, where
+the two sides only differ by replacing strings of monoidal structural morphisms (that is,
+associators, unitors, and identities) with different strings of structural morphisms with the same
+source and target. In other words, `monoidal` solves equalities where both sides have the same
+string diagrams.
+
+The core function for the `monoidal` tactic is provided in
+`Mathlib.Tactic.CategoryTheory.Coherence.Basic`. See this file for more details about the
+implementation.
+
+-/
+
+open Lean Meta Elab Tactic
+open CategoryTheory Mathlib.Tactic.BicategoryLike
+
+namespace Mathlib.Tactic.Monoidal
+
+/-- Normalize the both sides of an equality. -/
+def monoidalNf (mvarId : MVarId) : MetaM (List MVarId) := do
+ BicategoryLike.normalForm Monoidal.Context `monoidal mvarId
+
+@[inherit_doc monoidalNf]
+elab "monoidal_nf" : tactic => withMainContext do
+ replaceMainGoal (← monoidalNf (← getMainGoal))
+
+/--
+Use the coherence theorem for monoidal categories to solve equations in a monoidal category,
+where the two sides only differ by replacing strings of monoidal structural morphisms
+(that is, associators, unitors, and identities)
+with different strings of structural morphisms with the same source and target.
+
+That is, `monoidal` can handle goals of the form
+`a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'`
+where `a = a'`, `b = b'`, and `c = c'` can be proved using `monoidal_coherence`.
+-/
+def monoidal (mvarId : MVarId) : MetaM (List MVarId) :=
+ BicategoryLike.main Monoidal.Context `monoidal mvarId
+
+@[inherit_doc monoidal]
+elab "monoidal" : tactic => withMainContext do
+ replaceMainGoal <| ← monoidal <| ← getMainGoal
+
+end Mathlib.Tactic.Monoidal
diff --git a/Mathlib/Tactic/CategoryTheory/Monoidal/Datatypes.lean b/Mathlib/Tactic/CategoryTheory/Monoidal/Datatypes.lean
new file mode 100644
index 0000000000000..43c3ef94fc6cc
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Monoidal/Datatypes.lean
@@ -0,0 +1,505 @@
+/-
+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.Tactic.CategoryTheory.Coherence.Datatypes
+import Mathlib.Tactic.CategoryTheory.MonoidalComp
+
+/-!
+# Expressions for monoidal categories
+
+This file converts lean expressions representing morphisms in monoidal categories into `Mor₂Iso`
+or `Mor` terms. The converted expressions are used in the coherence tactics and the string diagram
+widgets.
+
+-/
+
+open Lean Meta Elab Qq
+open CategoryTheory Mathlib.Tactic.BicategoryLike MonoidalCategory
+
+namespace Mathlib.Tactic.Monoidal
+
+/-- The domain of a morphism. -/
+def srcExpr (η : Expr) : MetaM Expr := do
+ match (← whnfR (← inferType η)).getAppFnArgs with
+ | (``Quiver.Hom, #[_, _, f, _]) => return f
+ | _ => throwError m!"{η} is not a morphism"
+
+/-- The codomain of a morphism. -/
+def tgtExpr (η : Expr) : MetaM Expr := do
+ match (← whnfR (← inferType η)).getAppFnArgs with
+ | (``Quiver.Hom, #[_, _, _, g]) => return g
+ | _ => throwError m!"{η} is not a morphism"
+
+/-- The domain of an isomorphism. -/
+def srcExprOfIso (η : Expr) : MetaM Expr := do
+ match (← whnfR (← inferType η)).getAppFnArgs with
+ | (``Iso, #[_, _, f, _]) => return f
+ | _ => throwError m!"{η} is not a morphism"
+
+/-- The codomain of an isomorphism. -/
+def tgtExprOfIso (η : Expr) : MetaM Expr := do
+ match (← whnfR (← inferType η)).getAppFnArgs with
+ | (``Iso, #[_, _, _, g]) => return g
+ | _ => throwError m!"{η} is not a morphism"
+
+initialize registerTraceClass `monoidal
+
+/-- The context for evaluating expressions. -/
+structure Context where
+ /-- The level for morphisms. -/
+ level₂ : Level
+ /-- The level for objects. -/
+ level₁ : Level
+ /-- The expression for the underlying category. -/
+ C : Q(Type level₁)
+ /-- The category instance. -/
+ instCat : Q(Category.{level₂, level₁} $C)
+ /-- The monoidal category instance. -/
+ instMonoidal? : Option Q(MonoidalCategory.{level₂, level₁} $C)
+
+/-- Populate a `context` object for evaluating `e`. -/
+def mkContext? (e : Expr) : MetaM (Option Context) := do
+ let e ← instantiateMVars e
+ let type ← instantiateMVars <| ← inferType e
+ match (← whnfR type).getAppFnArgs with
+ | (``Quiver.Hom, #[_, _, f, _]) =>
+ let C ← instantiateMVars <| ← inferType f
+ let .succ level₁ ← getLevel C | return none
+ let .succ level₂ ← getLevel type | return none
+ let .some instCat ← synthInstance?
+ (mkAppN (.const ``Category [level₂, level₁]) #[C]) | return none
+ let instMonoidal? ← synthInstance?
+ (mkAppN (.const ``MonoidalCategory [level₂, level₁]) #[C, instCat])
+ return some ⟨level₂, level₁, C, instCat, instMonoidal?⟩
+ | _ => return none
+
+instance : BicategoryLike.Context Monoidal.Context where
+ mkContext? := Monoidal.mkContext?
+
+/-- The monad for the normalization of 2-morphisms. -/
+abbrev MonoidalM := CoherenceM Context
+
+/-- Throw an error if the monoidal category instance is not found. -/
+def synthMonoidalError {α : Type} : MetaM α := do
+ throwError "failed to find monoidal category instance"
+
+instance : MonadMor₁ MonoidalM where
+ id₁M a := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ return .id (q(MonoidalCategory.tensorUnit) : Q($ctx.C)) a
+ comp₁M f g := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f_e : Q($ctx.C) := f.e
+ let g_e : Q($ctx.C) := g.e
+ return .comp (q($f_e ⊗ $g_e)) f g
+
+section
+
+universe v u
+variable {C : Type u} [Category.{v} C]
+
+theorem structuralIsoOfExpr_comp {f g h : C}
+ (η : f ⟶ g) (η' : f ≅ g) (ih_η : η'.hom = η)
+ (θ : g ⟶ h) (θ' : g ≅ h) (ih_θ : θ'.hom = θ) :
+ (η' ≪≫ θ').hom = η ≫ θ := by
+ simp [ih_η, ih_θ]
+
+theorem StructuralOfExpr_monoidalComp {f g h i : C} [MonoidalCoherence g h]
+ (η : f ⟶ g) (η' : f ≅ g) (ih_η : η'.hom = η) (θ : h ⟶ i) (θ' : h ≅ i) (ih_θ : θ'.hom = θ) :
+ (η' ≪⊗≫ θ').hom = η ⊗≫ θ := by
+ simp [ih_η, ih_θ, monoidalIsoComp, monoidalComp, MonoidalCoherence.iso]
+
+variable [MonoidalCategory C]
+
+theorem structuralIsoOfExpr_whiskerLeft (f : C) {g h : C}
+ (η : g ⟶ h) (η' : g ≅ h) (ih_η : η'.hom = η) :
+ (whiskerLeftIso f η').hom = f ◁ η := by
+ simp [ih_η]
+
+theorem structuralIsoOfExpr_whiskerRight {f g : C} (h : C)
+ (η : f ⟶ g) (η' : f ≅ g) (ih_η : η'.hom = η) :
+ (whiskerRightIso η' h).hom = η ▷ h := by
+ simp [ih_η]
+
+theorem structuralIsoOfExpr_horizontalComp {f₁ g₁ f₂ g₂ : C}
+ (η : f₁ ⟶ g₁) (η' : f₁ ≅ g₁) (ih_η : η'.hom = η)
+ (θ : f₂ ⟶ g₂) (θ' : f₂ ≅ g₂) (ih_θ : θ'.hom = θ) :
+ (η' ⊗ θ').hom = η ⊗ θ := by
+ simp [ih_η, ih_θ]
+
+end
+
+open MonadMor₁
+
+instance : MonadMor₂Iso MonoidalM where
+ associatorM f g h := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f_e : Q($ctx.C) := f.e
+ let g_e : Q($ctx.C) := g.e
+ let h_e : Q($ctx.C) := h.e
+ return .associator q(α_ $f_e $g_e $h_e) f g h
+ leftUnitorM f := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f_e : Q($ctx.C) := f.e
+ return .leftUnitor q(λ_ $f_e) f
+ rightUnitorM f := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f_e : Q($ctx.C) := f.e
+ return .rightUnitor q(ρ_ $f_e) f
+ id₂M f := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ have f_e : Q($ctx.C) := f.e
+ return .id q(Iso.refl $f_e) f
+ coherenceHomM f g inst := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have inst : Q(MonoidalCoherence $f_e $g_e) := inst
+ match (← whnfI inst).getAppFnArgs with
+ | (``MonoidalCoherence.mk, #[_, _, _, _, α]) =>
+ let e : Q($f_e ≅ $g_e) := q(MonoidalCoherence.iso)
+ return ⟨e, f, g, inst, α⟩
+ | _ => throwError m!"failed to unfold {inst}"
+ comp₂M η θ := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← η.srcM
+ let g ← η.tgtM
+ let h ← θ.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have h_e : Q($ctx.C) := h.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ have θ_e : Q($g_e ≅ $h_e) := θ.e
+ return .comp q($η_e ≪≫ $θ_e) f g h η θ
+ whiskerLeftM f η := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let g ← η.srcM
+ let h ← η.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have h_e : Q($ctx.C) := h.e
+ have η_e : Q($g_e ≅ $h_e) := η.e
+ return .whiskerLeft q(whiskerLeftIso $f_e $η_e) f g h η
+ whiskerRightM η h := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η.srcM
+ let g ← η.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have h_e : Q($ctx.C) := h.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ return .whiskerRight q(whiskerRightIso $η_e $h_e) f g η h
+ horizontalCompM η θ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f₁ ← η.srcM
+ let g₁ ← η.tgtM
+ let f₂ ← θ.srcM
+ let g₂ ← θ.tgtM
+ have f₁_e : Q($ctx.C) := f₁.e
+ have g₁_e : Q($ctx.C) := g₁.e
+ have f₂_e : Q($ctx.C) := f₂.e
+ have g₂_e : Q($ctx.C) := g₂.e
+ have η_e : Q($f₁_e ≅ $g₁_e) := η.e
+ have θ_e : Q($f₂_e ≅ $g₂_e) := θ.e
+ return .horizontalComp q(tensorIso $η_e $θ_e) f₁ g₁ f₂ g₂ η θ
+ symmM η := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← η.srcM
+ let g ← η.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ return .inv q(Iso.symm $η_e) f g η
+ coherenceCompM α η θ := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← η.srcM
+ let g ← η.tgtM
+ let h ← θ.srcM
+ let i ← θ.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have h_e : Q($ctx.C) := h.e
+ have i_e : Q($ctx.C) := i.e
+ have _inst : Q(MonoidalCoherence $g_e $h_e) := α.inst
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ have θ_e : Q($h_e ≅ $i_e) := θ.e
+ return .coherenceComp q($η_e ≪⊗≫ $θ_e) f g h i α η θ
+
+open MonadMor₂Iso
+
+instance : MonadMor₂ MonoidalM where
+ homM η := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← η.srcM
+ let g ← η.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ let e : Q($f_e ⟶ $g_e) := q(Iso.hom $η_e)
+ have eq : Q(Iso.hom $η_e = $e) := q(rfl)
+ return .isoHom e ⟨η, eq⟩ η
+ atomHomM η := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f := η.src
+ let g := η.tgt
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ return .mk q(Iso.hom $η_e) f g
+ invM η := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← η.srcM
+ let g ← η.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ let e : Q($g_e ⟶ $f_e) := q(Iso.inv $η_e)
+ let η_inv ← symmM η
+ let eq : Q(Iso.inv $η_e = $e) := q(Iso.symm_hom $η_e)
+ return .isoInv e ⟨η_inv, eq⟩ η
+ atomInvM η := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f := η.src
+ let g := η.tgt
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have η_e : Q($f_e ≅ $g_e) := η.e
+ return .mk q(Iso.inv $η_e) g f
+ id₂M f := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ have f_e : Q($ctx.C) := f.e
+ let e : Q($f_e ⟶ $f_e) := q(𝟙 $f_e)
+ let eq : Q(𝟙 $f_e = $e) := q(Iso.refl_hom $f_e)
+ return .id e ⟨.structuralAtom <| ← id₂M f, eq⟩ f
+ comp₂M η θ := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← η.srcM
+ let g ← η.tgtM
+ let h ← θ.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have h_e : Q($ctx.C) := h.e
+ have η_e : Q($f_e ⟶ $g_e) := η.e
+ have θ_e : Q($g_e ⟶ $h_e) := θ.e
+ let iso_lift? ← (match (η.isoLift?, θ.isoLift?) with
+ | (some η_iso, some θ_iso) =>
+ have η_iso_e : Q($f_e ≅ $g_e) := η_iso.e.e
+ have θ_iso_e : Q($g_e ≅ $h_e) := θ_iso.e.e
+ have η_iso_eq : Q(Iso.hom $η_iso_e = $η_e) := η_iso.eq
+ have θ_iso_eq : Q(Iso.hom $θ_iso_e = $θ_e) := θ_iso.eq
+ let eq := q(structuralIsoOfExpr_comp _ _ $η_iso_eq _ _ $θ_iso_eq)
+ return .some ⟨← comp₂M η_iso.e θ_iso.e, eq⟩
+ | _ => return none)
+ let e : Q($f_e ⟶ $h_e) := q($η_e ≫ $θ_e)
+ return .comp e iso_lift? f g h η θ
+ whiskerLeftM f η := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let g ← η.srcM
+ let h ← η.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have h_e : Q($ctx.C) := h.e
+ have η_e : Q($g_e ⟶ $h_e) := η.e
+ let iso_lift? ← (match η.isoLift? with
+ | some η_iso => do
+ have η_iso_e : Q($g_e ≅ $h_e) := η_iso.e.e
+ have η_iso_eq : Q(Iso.hom $η_iso_e = $η_e) := η_iso.eq
+ let eq := q(structuralIsoOfExpr_whiskerLeft $f_e _ _ $η_iso_eq)
+ return .some ⟨← whiskerLeftM f η_iso.e, eq⟩
+ | _ => return none)
+ let e : Q($f_e ⊗ $g_e ⟶ $f_e ⊗ $h_e) := q($f_e ◁ $η_e)
+ return .whiskerLeft e iso_lift? f g h η
+ whiskerRightM η h := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η.srcM
+ let g ← η.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have h_e : Q($ctx.C) := h.e
+ have η_e : Q($f_e ⟶ $g_e) := η.e
+ let iso_lift? ← (match η.isoLift? with
+ | some η_iso => do
+ have η_iso_e : Q($f_e ≅ $g_e) := η_iso.e.e
+ have η_iso_eq : Q(Iso.hom $η_iso_e = $η_e) := η_iso.eq
+ let eq := q(structuralIsoOfExpr_whiskerRight $h_e _ _ $η_iso_eq)
+ return .some ⟨← whiskerRightM η_iso.e h, eq⟩
+ | _ => return none)
+ let e : Q($f_e ⊗ $h_e ⟶ $g_e ⊗ $h_e) := q($η_e ▷ $h_e)
+ return .whiskerRight e iso_lift? f g η h
+ horizontalCompM η θ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f₁ ← η.srcM
+ let g₁ ← η.tgtM
+ let f₂ ← θ.srcM
+ let g₂ ← θ.tgtM
+ have f₁_e : Q($ctx.C) := f₁.e
+ have g₁_e : Q($ctx.C) := g₁.e
+ have f₂_e : Q($ctx.C) := f₂.e
+ have g₂_e : Q($ctx.C) := g₂.e
+ have η_e : Q($f₁_e ⟶ $g₁_e) := η.e
+ have θ_e : Q($f₂_e ⟶ $g₂_e) := θ.e
+ let iso_lift? ← (match (η.isoLift?, θ.isoLift?) with
+ | (some η_iso, some θ_iso) => do
+ have η_iso_e : Q($f₁_e ≅ $g₁_e) := η_iso.e.e
+ have θ_iso_e : Q($f₂_e ≅ $g₂_e) := θ_iso.e.e
+ have η_iso_eq : Q(Iso.hom $η_iso_e = $η_e) := η_iso.eq
+ have θ_iso_eq : Q(Iso.hom $θ_iso_e = $θ_e) := θ_iso.eq
+ let eq := q(structuralIsoOfExpr_horizontalComp _ _ $η_iso_eq _ _ $θ_iso_eq)
+ return .some ⟨← horizontalCompM η_iso.e θ_iso.e, eq⟩
+ | _ => return none)
+ let e : Q($f₁_e ⊗ $f₂_e ⟶ $g₁_e ⊗ $g₂_e) := q($η_e ⊗ $θ_e)
+ return .horizontalComp e iso_lift? f₁ g₁ f₂ g₂ η θ
+ coherenceCompM α η θ := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← η.srcM
+ let g ← η.tgtM
+ let h ← θ.srcM
+ let i ← θ.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have h_e : Q($ctx.C) := h.e
+ have i_e : Q($ctx.C) := i.e
+ have _inst : Q(MonoidalCoherence $g_e $h_e) := α.inst
+ have η_e : Q($f_e ⟶ $g_e) := η.e
+ have θ_e : Q($h_e ⟶ $i_e) := θ.e
+ let iso_lift? ← (match (η.isoLift?, θ.isoLift?) with
+ | (some η_iso, some θ_iso) => do
+ have η_iso_e : Q($f_e ≅ $g_e) := η_iso.e.e
+ have θ_iso_e : Q($h_e ≅ $i_e) := θ_iso.e.e
+ have η_iso_eq : Q(Iso.hom $η_iso_e = $η_e) := η_iso.eq
+ have θ_iso_eq : Q(Iso.hom $θ_iso_e = $θ_e) := θ_iso.eq
+ let eq := q(StructuralOfExpr_monoidalComp _ _ $η_iso_eq _ _ $θ_iso_eq)
+ return .some ⟨← coherenceCompM α η_iso.e θ_iso.e, eq⟩
+ | _ => return none)
+ let e : Q($f_e ⟶ $i_e) := q($η_e ⊗≫ $θ_e)
+ return .coherenceComp e iso_lift? f g h i α η θ
+
+/-- Check that `e` is definitionally equal to `𝟙_ C`. -/
+def id₁? (e : Expr) : MonoidalM (Option Obj) := do
+ let ctx ← read
+ match ctx.instMonoidal? with
+ | .some _monoidal => do
+ if ← withDefault <| isDefEq e (q(MonoidalCategory.tensorUnit) : Q($ctx.C)) then
+ return some ⟨none⟩
+ else
+ return none
+ | _ => return none
+
+/-- Return `(f, g)` if `e` is definitionally equal to `f ⊗ g`. -/
+def comp? (e : Expr) : MonoidalM (Option (Mor₁ × Mor₁)) := do
+ let ctx ← read
+ let f ← mkFreshExprMVarQ ctx.C
+ let g ← mkFreshExprMVarQ ctx.C
+ match ctx.instMonoidal? with
+ | .some _monoidal => do
+ if ← withDefault <| isDefEq e q($f ⊗ $g) then
+ let f ← instantiateMVars f
+ let g ← instantiateMVars g
+ return some ((.of ⟨f, ⟨none⟩, ⟨none⟩⟩ : Mor₁), (.of ⟨g, ⟨none⟩, ⟨none⟩⟩ : Mor₁))
+ else
+ return none
+ | _ => return none
+
+/-- Construct a `Mor₁` expression from a Lean expression. -/
+partial def mor₁OfExpr (e : Expr) : MonoidalM Mor₁ := do
+ if let some f := (← get).cache.find? e then
+ return f
+ let f ←
+ if let some a ← id₁? e then
+ MonadMor₁.id₁M a
+ else if let some (f, g) ← comp? e then
+ MonadMor₁.comp₁M (← mor₁OfExpr f.e) (← mor₁OfExpr g.e)
+ else
+ return Mor₁.of ⟨e, ⟨none⟩, ⟨none⟩⟩
+ modify fun s => { s with cache := s.cache.insert e f }
+ return f
+
+instance : MkMor₁ MonoidalM where
+ ofExpr := mor₁OfExpr
+
+/-- Construct a `Mor₂Iso` term from a Lean expression. -/
+partial def Mor₂IsoOfExpr (e : Expr) : MonoidalM Mor₂Iso := do
+ match (← whnfR e).getAppFnArgs with
+ | (``MonoidalCategoryStruct.associator, #[_, _, _, f, g, h]) =>
+ associatorM' (← MkMor₁.ofExpr f) (← MkMor₁.ofExpr g) (← MkMor₁.ofExpr h)
+ | (``MonoidalCategoryStruct.leftUnitor, #[_, _, _, f]) =>
+ leftUnitorM' (← MkMor₁.ofExpr f)
+ | (``MonoidalCategoryStruct.rightUnitor, #[_, _, _, f]) =>
+ rightUnitorM' (← MkMor₁.ofExpr f)
+ | (``Iso.refl, #[_, _, f]) =>
+ id₂M' (← MkMor₁.ofExpr f)
+ | (``Iso.symm, #[_, _, _, _, η]) =>
+ symmM (← Mor₂IsoOfExpr η)
+ | (``Iso.trans, #[_, _, _, _, _, η, θ]) =>
+ comp₂M (← Mor₂IsoOfExpr η) (← Mor₂IsoOfExpr θ)
+ | (``MonoidalCategory.whiskerLeftIso, #[_, _, _, f, _, _, η]) =>
+ whiskerLeftM (← MkMor₁.ofExpr f) (← Mor₂IsoOfExpr η)
+ | (``MonoidalCategory.whiskerRightIso, #[_, _, _, _, _, η, h]) =>
+ whiskerRightM (← Mor₂IsoOfExpr η) (← MkMor₁.ofExpr h)
+ | (``tensorIso, #[_, _, _, _, _, _, _, η, θ]) =>
+ horizontalCompM (← Mor₂IsoOfExpr η) (← Mor₂IsoOfExpr θ)
+ | (``monoidalIsoComp, #[_, _, _, g, h, _, inst, η, θ]) =>
+ let α ← coherenceHomM (← MkMor₁.ofExpr g) (← MkMor₁.ofExpr h) inst
+ coherenceCompM α (← Mor₂IsoOfExpr η) (← Mor₂IsoOfExpr θ)
+ | (``MonoidalCoherence.iso, #[_, _, f, g, inst]) =>
+ coherenceHomM' (← MkMor₁.ofExpr f) (← MkMor₁.ofExpr g) inst
+ | _ =>
+ return .of ⟨e, ← MkMor₁.ofExpr (← srcExprOfIso e), ← MkMor₁.ofExpr (← tgtExprOfIso e)⟩
+
+open MonadMor₂ in
+/-- Construct a `Mor₂` term from a Lean expression. -/
+partial def Mor₂OfExpr (e : Expr) : MonoidalM Mor₂ := do
+ match ← whnfR e with
+ -- whnfR version of `Iso.hom η`
+ | .proj ``Iso 0 η => homM (← Mor₂IsoOfExpr η)
+ -- whnfR version of `Iso.inv η`
+ | .proj ``Iso 1 η => invM (← Mor₂IsoOfExpr η)
+ | .app .. => match (← whnfR e).getAppFnArgs with
+ | (``CategoryStruct.id, #[_, _, f]) => id₂M (← MkMor₁.ofExpr f)
+ | (``CategoryStruct.comp, #[_, _, _, _, _, η, θ]) =>
+ comp₂M (← Mor₂OfExpr η) (← Mor₂OfExpr θ)
+ | (``MonoidalCategoryStruct.whiskerLeft, #[_, _, _, f, _, _, η]) =>
+ whiskerLeftM (← MkMor₁.ofExpr f) (← Mor₂OfExpr η)
+ | (``MonoidalCategoryStruct.whiskerRight, #[_, _, _, _, _, η, h]) =>
+ whiskerRightM (← Mor₂OfExpr η) (← MkMor₁.ofExpr h)
+ | (``MonoidalCategoryStruct.tensorHom, #[_, _, _, _, _, _, _, η, θ]) =>
+ horizontalCompM (← Mor₂OfExpr η) (← Mor₂OfExpr θ)
+ | (``monoidalComp, #[_, _, _, g, h, _, inst, η, θ]) =>
+ let α ← coherenceHomM (← MkMor₁.ofExpr g) (← MkMor₁.ofExpr h) inst
+ coherenceCompM α (← Mor₂OfExpr η) (← Mor₂OfExpr θ)
+ | _ => return .of ⟨e, ← MkMor₁.ofExpr (← srcExpr e), ← MkMor₁.ofExpr (← tgtExpr e)⟩
+ | _ =>
+ return .of ⟨e, ← MkMor₁.ofExpr (← srcExpr e), ← MkMor₁.ofExpr (← tgtExpr e)⟩
+
+instance : BicategoryLike.MkMor₂ MonoidalM where
+ ofExpr := Mor₂OfExpr
+
+instance : MonadCoherehnceHom MonoidalM where
+ unfoldM α := Mor₂IsoOfExpr α.unfold
+
+end Mathlib.Tactic.Monoidal
diff --git a/Mathlib/Tactic/CategoryTheory/Monoidal/Normalize.lean b/Mathlib/Tactic/CategoryTheory/Monoidal/Normalize.lean
new file mode 100644
index 0000000000000..f55e98f5088b0
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Monoidal/Normalize.lean
@@ -0,0 +1,787 @@
+/-
+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.Tactic.CategoryTheory.Coherence.Normalize
+import Mathlib.Tactic.CategoryTheory.Monoidal.Datatypes
+
+/-!
+# Normalization of morphisms in monoidal categories
+
+This file provides the implementation of the normalization given in
+`Mathlib.Tactic.CategoryTheory.Coherence.Normalize`. See this file for more details.
+
+-/
+
+open Lean Meta Elab Qq
+open CategoryTheory Mathlib.Tactic.BicategoryLike MonoidalCategory
+
+namespace Mathlib.Tactic.Monoidal
+
+section
+
+universe v u
+
+variable {C : Type u} [Category.{v} C]
+
+variable {f f' g g' h h' i i' j : C}
+
+@[nolint synTaut]
+theorem evalComp_nil_nil {f g h : C} (α : f ≅ g) (β : g ≅ h) :
+ (α ≪≫ β).hom = (α ≪≫ β).hom := by
+ simp
+
+theorem evalComp_nil_cons {f g h i j : C} (α : f ≅ g) (β : g ≅ h) (η : h ⟶ i) (ηs : i ⟶ j) :
+ α.hom ≫ (β.hom ≫ η ≫ ηs) = (α ≪≫ β).hom ≫ η ≫ ηs := by
+ simp
+
+theorem evalComp_cons {f g h i j : C} (α : f ≅ g) (η : g ⟶ h) {ηs : h ⟶ i} {θ : i ⟶ j} {ι : h ⟶ j}
+ (e_ι : ηs ≫ θ = ι) :
+ (α.hom ≫ η ≫ ηs) ≫ θ = α.hom ≫ η ≫ ι := by
+ simp [e_ι]
+
+theorem eval_comp
+ {η η' : f ⟶ g} {θ θ' : g ⟶ h} {ι : f ⟶ h}
+ (e_η : η = η') (e_θ : θ = θ') (e_ηθ : η' ≫ θ' = ι) :
+ η ≫ θ = ι := by
+ simp [e_η, e_θ, e_ηθ]
+
+theorem eval_of (η : f ⟶ g) :
+ η = (Iso.refl _).hom ≫ η ≫ (Iso.refl _).hom := by
+ simp
+
+theorem eval_monoidalComp
+ {η η' : f ⟶ g} {α : g ≅ h} {θ θ' : h ⟶ i} {αθ : g ⟶ i} {ηαθ : f ⟶ i}
+ (e_η : η = η') (e_θ : θ = θ') (e_αθ : α.hom ≫ θ' = αθ) (e_ηαθ : η' ≫ αθ = ηαθ) :
+ η ≫ α.hom ≫ θ = ηαθ := by
+ simp [e_η, e_θ, e_αθ, e_ηαθ]
+
+variable [MonoidalCategory C]
+
+@[nolint synTaut]
+theorem evalWhiskerLeft_nil (f : C) {g h : C} (α : g ≅ h) :
+ (whiskerLeftIso f α).hom = (whiskerLeftIso f α).hom := by
+ simp
+
+theorem evalWhiskerLeft_of_cons {f g h i j : C}
+ (α : g ≅ h) (η : h ⟶ i) {ηs : i ⟶ j} {θ : f ⊗ i ⟶ f ⊗ j} (e_θ : f ◁ ηs = θ) :
+ f ◁ (α.hom ≫ η ≫ ηs) = (whiskerLeftIso f α).hom ≫ f ◁ η ≫ θ := by
+ simp [e_θ]
+
+theorem evalWhiskerLeft_comp {f g h i : C}
+ {η : h ⟶ i} {η₁ : g ⊗ h ⟶ g ⊗ i} {η₂ : f ⊗ g ⊗ h ⟶ f ⊗ g ⊗ i}
+ {η₃ : f ⊗ g ⊗ h ⟶ (f ⊗ g) ⊗ i} {η₄ : (f ⊗ g) ⊗ h ⟶ (f ⊗ g) ⊗ i}
+ (e_η₁ : g ◁ η = η₁) (e_η₂ : f ◁ η₁ = η₂)
+ (e_η₃ : η₂ ≫ (α_ _ _ _).inv = η₃) (e_η₄ : (α_ _ _ _).hom ≫ η₃ = η₄) :
+ (f ⊗ g) ◁ η = η₄ := by
+ simp [e_η₁, e_η₂, e_η₃, e_η₄]
+
+theorem evalWhiskerLeft_id {f g : C} {η : f ⟶ g}
+ {η₁ : f ⟶ 𝟙_ C ⊗ g} {η₂ : 𝟙_ C ⊗ f ⟶ 𝟙_ C ⊗ g}
+ (e_η₁ : η ≫ (λ_ _).inv = η₁) (e_η₂ : (λ_ _).hom ≫ η₁ = η₂) :
+ 𝟙_ C ◁ η = η₂ := by
+ simp [e_η₁, e_η₂]
+
+theorem eval_whiskerLeft {f g h : C}
+ {η η' : g ⟶ h} {θ : f ⊗ g ⟶ f ⊗ h}
+ (e_η : η = η') (e_θ : f ◁ η' = θ) :
+ f ◁ η = θ := by
+ simp [e_η, e_θ]
+
+theorem eval_whiskerRight {f g h : C}
+ {η η' : f ⟶ g} {θ : f ⊗ h ⟶ g ⊗ h}
+ (e_η : η = η') (e_θ : η' ▷ h = θ) :
+ η ▷ h = θ := by
+ simp [e_η, e_θ]
+
+theorem eval_tensorHom {f g h i : C}
+ {η η' : f ⟶ g} {θ θ' : h ⟶ i} {ι : f ⊗ h ⟶ g ⊗ i}
+ (e_η : η = η') (e_θ : θ = θ') (e_ι : η' ⊗ θ' = ι) :
+ η ⊗ θ = ι := by
+ simp [e_η, e_θ, e_ι]
+
+@[nolint synTaut]
+theorem evalWhiskerRight_nil {f g : C} (α : f ≅ g) (h : C) :
+ (whiskerRightIso α h).hom = (whiskerRightIso α h).hom := by
+ simp
+
+theorem evalWhiskerRight_cons_of_of {f g h i j : C}
+ {α : f ≅ g} {η : g ⟶ h} {ηs : h ⟶ i} {ηs₁ : h ⊗ j ⟶ i ⊗ j}
+ {η₁ : g ⊗ j ⟶ h ⊗ j} {η₂ : g ⊗ j ⟶ i ⊗ j} {η₃ : f ⊗ j ⟶ i ⊗ j}
+ (e_ηs₁ : ηs ▷ j = ηs₁) (e_η₁ : η ▷ j = η₁)
+ (e_η₂ : η₁ ≫ ηs₁ = η₂) (e_η₃ : (whiskerRightIso α j).hom ≫ η₂ = η₃) :
+ (α.hom ≫ η ≫ ηs) ▷ j = η₃ := by
+ simp_all
+
+theorem evalWhiskerRight_cons_whisker {f g h i j k : C}
+ {α : g ≅ f ⊗ h} {η : h ⟶ i} {ηs : f ⊗ i ⟶ j}
+ {η₁ : h ⊗ k ⟶ i ⊗ k} {η₂ : f ⊗ (h ⊗ k) ⟶ f ⊗ (i ⊗ k)} {ηs₁ : (f ⊗ i) ⊗ k ⟶ j ⊗ k}
+ {ηs₂ : f ⊗ (i ⊗ k) ⟶ j ⊗ k} {η₃ : f ⊗ (h ⊗ k) ⟶ j ⊗ k} {η₄ : (f ⊗ h) ⊗ k ⟶ j ⊗ k}
+ {η₅ : g ⊗ k ⟶ j ⊗ k}
+ (e_η₁ : ((Iso.refl _).hom ≫ η ≫ (Iso.refl _).hom) ▷ k = η₁) (e_η₂ : f ◁ η₁ = η₂)
+ (e_ηs₁ : ηs ▷ k = ηs₁) (e_ηs₂ : (α_ _ _ _).inv ≫ ηs₁ = ηs₂)
+ (e_η₃ : η₂ ≫ ηs₂ = η₃) (e_η₄ : (α_ _ _ _).hom ≫ η₃ = η₄)
+ (e_η₅ : (whiskerRightIso α k).hom ≫ η₄ = η₅) :
+ (α.hom ≫ (f ◁ η) ≫ ηs) ▷ k = η₅ := by
+ simp at e_η₁ e_η₅
+ simp [e_η₁, e_η₂, e_ηs₁, e_ηs₂, e_η₃, e_η₄, e_η₅]
+
+theorem evalWhiskerRight_comp {f f' g h : C}
+ {η : f ⟶ f'} {η₁ : f ⊗ g ⟶ f' ⊗ g} {η₂ : (f ⊗ g) ⊗ h ⟶ (f' ⊗ g) ⊗ h}
+ {η₃ : (f ⊗ g) ⊗ h ⟶ f' ⊗ (g ⊗ h)} {η₄ : f ⊗ (g ⊗ h) ⟶ f' ⊗ (g ⊗ h)}
+ (e_η₁ : η ▷ g = η₁) (e_η₂ : η₁ ▷ h = η₂)
+ (e_η₃ : η₂ ≫ (α_ _ _ _).hom = η₃) (e_η₄ : (α_ _ _ _).inv ≫ η₃ = η₄) :
+ η ▷ (g ⊗ h) = η₄ := by
+ simp [e_η₁, e_η₂, e_η₃, e_η₄]
+
+theorem evalWhiskerRight_id {f g : C}
+ {η : f ⟶ g} {η₁ : f ⟶ g ⊗ 𝟙_ C} {η₂ : f ⊗ 𝟙_ C ⟶ g ⊗ 𝟙_ C}
+ (e_η₁ : η ≫ (ρ_ _).inv = η₁) (e_η₂ : (ρ_ _).hom ≫ η₁ = η₂) :
+ η ▷ 𝟙_ C = η₂ := by
+ simp [e_η₁, e_η₂]
+
+theorem evalWhiskerRightAux_of {f g : C} (η : f ⟶ g) (h : C) :
+ η ▷ h = (Iso.refl _).hom ≫ η ▷ h ≫ (Iso.refl _).hom := by
+ simp
+
+theorem evalWhiskerRightAux_cons {f g h i j : C} {η : g ⟶ h} {ηs : i ⟶ j}
+ {ηs' : i ⊗ f ⟶ j ⊗ f} {η₁ : g ⊗ (i ⊗ f) ⟶ h ⊗ (j ⊗ f)}
+ {η₂ : g ⊗ (i ⊗ f) ⟶ (h ⊗ j) ⊗ f} {η₃ : (g ⊗ i) ⊗ f ⟶ (h ⊗ j) ⊗ f}
+ (e_ηs' : ηs ▷ f = ηs') (e_η₁ : ((Iso.refl _).hom ≫ η ≫ (Iso.refl _).hom) ⊗ ηs' = η₁)
+ (e_η₂ : η₁ ≫ (α_ _ _ _).inv = η₂) (e_η₃ : (α_ _ _ _).hom ≫ η₂ = η₃) :
+ (η ⊗ ηs) ▷ f = η₃ := by
+ simp [← e_ηs', ← e_η₁, ← e_η₂, ← e_η₃, MonoidalCategory.tensorHom_def]
+
+theorem evalWhiskerRight_cons_of {f f' g h i : C} {α : f' ≅ g} {η : g ⟶ h} {ηs : h ⟶ i}
+ {ηs₁ : h ⊗ f ⟶ i ⊗ f} {η₁ : g ⊗ f ⟶ h ⊗ f} {η₂ : g ⊗ f ⟶ i ⊗ f}
+ {η₃ : f' ⊗ f ⟶ i ⊗ f}
+ (e_ηs₁ : ηs ▷ f = ηs₁) (e_η₁ : η ▷ f = η₁)
+ (e_η₂ : η₁ ≫ ηs₁ = η₂) (e_η₃ : (whiskerRightIso α f).hom ≫ η₂ = η₃) :
+ (α.hom ≫ η ≫ ηs) ▷ f = η₃ := by
+ simp_all
+
+theorem evalHorizontalCompAux_of {f g h i : C} (η : f ⟶ g) (θ : h ⟶ i) :
+ η ⊗ θ = (Iso.refl _).hom ≫ (η ⊗ θ) ≫ (Iso.refl _).hom := by
+ simp
+
+theorem evalHorizontalCompAux_cons {f f' g g' h i : C} {η : f ⟶ g} {ηs : f' ⟶ g'} {θ : h ⟶ i}
+ {ηθ : f' ⊗ h ⟶ g' ⊗ i} {η₁ : f ⊗ (f' ⊗ h) ⟶ g ⊗ (g' ⊗ i)}
+ {ηθ₁ : f ⊗ (f' ⊗ h) ⟶ (g ⊗ g') ⊗ i} {ηθ₂ : (f ⊗ f') ⊗ h ⟶ (g ⊗ g') ⊗ i}
+ (e_ηθ : ηs ⊗ θ = ηθ) (e_η₁ : ((Iso.refl _).hom ≫ η ≫ (Iso.refl _).hom) ⊗ ηθ = η₁)
+ (e_ηθ₁ : η₁ ≫ (α_ _ _ _).inv = ηθ₁) (e_ηθ₂ : (α_ _ _ _).hom ≫ ηθ₁ = ηθ₂) :
+ (η ⊗ ηs) ⊗ θ = ηθ₂ := by
+ simp_all
+
+theorem evalHorizontalCompAux'_whisker {f f' g g' h : C} {η : g ⟶ h} {θ : f' ⟶ g'}
+ {ηθ : g ⊗ f' ⟶ h ⊗ g'} {η₁ : f ⊗ (g ⊗ f') ⟶ f ⊗ (h ⊗ g')}
+ {η₂ : f ⊗ (g ⊗ f') ⟶ (f ⊗ h) ⊗ g'} {η₃ : (f ⊗ g) ⊗ f' ⟶ (f ⊗ h) ⊗ g'}
+ (e_ηθ : η ⊗ θ = ηθ) (e_η₁ : f ◁ ηθ = η₁)
+ (e_η₂ : η₁ ≫ (α_ _ _ _).inv = η₂) (e_η₃ : (α_ _ _ _).hom ≫ η₂ = η₃) :
+ (f ◁ η) ⊗ θ = η₃ := by
+ simp only [← e_ηθ, ← e_η₁, ← e_η₂, ← e_η₃]
+ simp [MonoidalCategory.tensorHom_def]
+
+theorem evalHorizontalCompAux'_of_whisker {f f' g g' h : C} {η : g ⟶ h} {θ : f' ⟶ g'}
+ {η₁ : g ⊗ f ⟶ h ⊗ f} {ηθ : (g ⊗ f) ⊗ f' ⟶ (h ⊗ f) ⊗ g'}
+ {ηθ₁ : (g ⊗ f) ⊗ f' ⟶ h ⊗ (f ⊗ g')}
+ {ηθ₂ : g ⊗ (f ⊗ f') ⟶ h ⊗ (f ⊗ g')}
+ (e_η₁ : η ▷ f = η₁) (e_ηθ : η₁ ⊗ ((Iso.refl _).hom ≫ θ ≫ (Iso.refl _).hom) = ηθ)
+ (e_ηθ₁ : ηθ ≫ (α_ _ _ _).hom = ηθ₁) (e_ηθ₂ : (α_ _ _ _).inv ≫ ηθ₁ = ηθ₂) :
+ η ⊗ (f ◁ θ) = ηθ₂ := by
+ simp only [← e_η₁, ← e_ηθ, ← e_ηθ₁, ← e_ηθ₂]
+ simp [MonoidalCategory.tensorHom_def]
+
+@[nolint synTaut]
+theorem evalHorizontalComp_nil_nil {f g h i : C} (α : f ≅ g) (β : h ≅ i) :
+ (α ⊗ β).hom = (α ⊗ β).hom := by
+ simp
+
+theorem evalHorizontalComp_nil_cons {f f' g g' h i : C}
+ {α : f ≅ g} {β : f' ≅ g'} {η : g' ⟶ h} {ηs : h ⟶ i}
+ {η₁ : g ⊗ g' ⟶ g ⊗ h} {ηs₁ : g ⊗ h ⟶ g ⊗ i}
+ {η₂ : g ⊗ g' ⟶ g ⊗ i} {η₃ : f ⊗ f' ⟶ g ⊗ i}
+ (e_η₁ : g ◁ ((Iso.refl _).hom ≫ η ≫ (Iso.refl _).hom) = η₁)
+ (e_ηs₁ : g ◁ ηs = ηs₁) (e_η₂ : η₁ ≫ ηs₁ = η₂)
+ (e_η₃ : (α ⊗ β).hom ≫ η₂ = η₃) :
+ α.hom ⊗ (β.hom ≫ η ≫ ηs) = η₃ := by
+ simp_all [MonoidalCategory.tensorHom_def]
+
+theorem evalHorizontalComp_cons_nil {f f' g g' h i : C}
+ {α : f ≅ g} {η : g ⟶ h} {ηs : h ⟶ i} {β : f' ≅ g'}
+ {η₁ : g ⊗ g' ⟶ h ⊗ g'} {ηs₁ : h ⊗ g' ⟶ i ⊗ g'} {η₂ : g ⊗ g' ⟶ i ⊗ g'} {η₃ : f ⊗ f' ⟶ i ⊗ g'}
+ (e_η₁ : ((Iso.refl _).hom ≫ η ≫ (Iso.refl _).hom) ▷ g' = η₁) (e_ηs₁ : ηs ▷ g' = ηs₁)
+ (e_η₂ : η₁ ≫ ηs₁ = η₂) (e_η₃ : (α ⊗ β).hom ≫ η₂ = η₃) :
+ (α.hom ≫ η ≫ ηs) ⊗ β.hom = η₃ := by
+ simp_all [MonoidalCategory.tensorHom_def']
+
+theorem evalHorizontalComp_cons_cons {f f' g g' h h' i i' : C}
+ {α : f ≅ g} {η : g ⟶ h} {ηs : h ⟶ i}
+ {β : f' ≅ g'} {θ : g' ⟶ h'} {θs : h' ⟶ i'}
+ {ηθ : g ⊗ g' ⟶ h ⊗ h'} {ηθs : h ⊗ h' ⟶ i ⊗ i'}
+ {ηθ₁ : g ⊗ g' ⟶ i ⊗ i'} {ηθ₂ : f ⊗ f' ⟶ i ⊗ i'}
+ (e_ηθ : η ⊗ θ = ηθ) (e_ηθs : ηs ⊗ θs = ηθs)
+ (e_ηθ₁ : ηθ ≫ ηθs = ηθ₁) (e_ηθ₂ : (α ⊗ β).hom ≫ ηθ₁ = ηθ₂) :
+ (α.hom ≫ η ≫ ηs) ⊗ (β.hom ≫ θ ≫ θs) = ηθ₂ := by
+ simp [← e_ηθ , ← e_ηθs , ← e_ηθ₁, ← e_ηθ₂]
+
+end
+
+open Mor₂Iso
+
+instance : MkEvalComp MonoidalM where
+ mkEvalCompNilNil α β := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← β.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have α : Q($f ≅ $g) := α.e
+ have β : Q($g ≅ $h) := β.e
+ return q(evalComp_nil_nil $α $β)
+ mkEvalCompNilCons α β η ηs := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← β.tgtM
+ let i ← η.tgtM
+ let j ← ηs.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have j : Q($ctx.C) := j.e
+ have α : Q($f ≅ $g) := α.e
+ have β : Q($g ≅ $h) := β.e
+ have η : Q($h ⟶ $i) := η.e.e
+ have ηs : Q($i ⟶ $j) := ηs.e.e
+ return q(evalComp_nil_cons $α $β $η $ηs)
+ mkEvalCompCons α η ηs θ ι e_ι := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← η.tgtM
+ let i ← ηs.tgtM
+ let j ← θ.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have j : Q($ctx.C) := j.e
+ have α : Q($f ≅ $g) := α.e
+ have η : Q($g ⟶ $h) := η.e.e
+ have ηs : Q($h ⟶ $i) := ηs.e.e
+ have θ : Q($i ⟶ $j) := θ.e.e
+ have ι : Q($h ⟶ $j) := ι.e.e
+ have e_ι : Q($ηs ≫ $θ = $ι) := e_ι
+ return q(evalComp_cons $α $η $e_ι)
+
+instance : MkEvalWhiskerLeft MonoidalM where
+ mkEvalWhiskerLeftNil f α := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let g ← α.srcM
+ let h ← α.tgtM
+ have f_e : Q($ctx.C) := f.e
+ have g_e : Q($ctx.C) := g.e
+ have h_e : Q($ctx.C) := h.e
+ have α_e : Q($g_e ≅ $h_e) := α.e
+ return q(evalWhiskerLeft_nil $f_e $α_e)
+ mkEvalWhiskerLeftOfCons f α η ηs θ e_θ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let g ← α.srcM
+ let h ← α.tgtM
+ let i ← η.tgtM
+ let j ← ηs.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have j : Q($ctx.C) := j.e
+ have α : Q($g ≅ $h) := α.e
+ have η : Q($h ⟶ $i) := η.e.e
+ have ηs : Q($i ⟶ $j) := ηs.e.e
+ have θ : Q($f ⊗ $i ⟶ $f ⊗ $j) := θ.e.e
+ have e_θ : Q($f ◁ $ηs = $θ) := e_θ
+ return q(evalWhiskerLeft_of_cons $α $η $e_θ)
+ mkEvalWhiskerLeftComp f g η η₁ η₂ η₃ η₄ e_η₁ e_η₂ e_η₃ e_η₄ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let h ← η.srcM
+ let i ← η.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have η : Q($h ⟶ $i) := η.e.e
+ have η₁ : Q($g ⊗ $h ⟶ $g ⊗ $i) := η₁.e.e
+ have η₂ : Q($f ⊗ $g ⊗ $h ⟶ $f ⊗ $g ⊗ $i) := η₂.e.e
+ have η₃ : Q($f ⊗ $g ⊗ $h ⟶ ($f ⊗ $g) ⊗ $i) := η₃.e.e
+ have η₄ : Q(($f ⊗ $g) ⊗ $h ⟶ ($f ⊗ $g) ⊗ $i) := η₄.e.e
+ have e_η₁ : Q($g ◁ $η = $η₁) := e_η₁
+ have e_η₂ : Q($f ◁ $η₁ = $η₂) := e_η₂
+ have e_η₃ : Q($η₂ ≫ (α_ _ _ _).inv = $η₃) := e_η₃
+ have e_η₄ : Q((α_ _ _ _).hom ≫ $η₃ = $η₄) := e_η₄
+ return q(evalWhiskerLeft_comp $e_η₁ $e_η₂ $e_η₃ $e_η₄)
+ mkEvalWhiskerLeftId η η₁ η₂ e_η₁ e_η₂ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η.srcM
+ let g ← η.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have η : Q($f ⟶ $g) := η.e.e
+ have η₁ : Q($f ⟶ 𝟙_ _ ⊗ $g) := η₁.e.e
+ have η₂ : Q(𝟙_ _ ⊗ $f ⟶ 𝟙_ _ ⊗ $g) := η₂.e.e
+ have e_η₁ : Q($η ≫ (λ_ _).inv = $η₁) := e_η₁
+ have e_η₂ : Q((λ_ _).hom ≫ $η₁ = $η₂) := e_η₂
+ return q(evalWhiskerLeft_id $e_η₁ $e_η₂)
+
+instance : MkEvalWhiskerRight MonoidalM where
+ mkEvalWhiskerRightAuxOf η h := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η.srcM
+ let g ← η.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have η : Q($f ⟶ $g) := η.e.e
+ have h : Q($ctx.C) := h.e
+ return q(evalWhiskerRightAux_of $η $h)
+ mkEvalWhiskerRightAuxCons f η ηs ηs' η₁ η₂ η₃ e_ηs' e_η₁ e_η₂ e_η₃ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let g ← η.srcM
+ let h ← η.tgtM
+ let i ← ηs.srcM
+ let j ← ηs.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have j : Q($ctx.C) := j.e
+ have η : Q($g ⟶ $h) := η.e.e
+ have ηs : Q($i ⟶ $j) := ηs.e.e
+ have ηs' : Q($i ⊗ $f ⟶ $j ⊗ $f) := ηs'.e.e
+ have η₁ : Q($g ⊗ ($i ⊗ $f) ⟶ $h ⊗ ($j ⊗ $f)) := η₁.e.e
+ have η₂ : Q($g ⊗ ($i ⊗ $f) ⟶ ($h ⊗ $j) ⊗ $f) := η₂.e.e
+ have η₃ : Q(($g ⊗ $i) ⊗ $f ⟶ ($h ⊗ $j) ⊗ $f) := η₃.e.e
+ have e_ηs' : Q($ηs ▷ $f = $ηs') := e_ηs'
+ have e_η₁ : Q(((Iso.refl _).hom ≫ $η ≫ (Iso.refl _).hom) ⊗ $ηs' = $η₁) := e_η₁
+ have e_η₂ : Q($η₁ ≫ (α_ _ _ _).inv = $η₂) := e_η₂
+ have e_η₃ : Q((α_ _ _ _).hom ≫ $η₂ = $η₃) := e_η₃
+ return q(evalWhiskerRightAux_cons $e_ηs' $e_η₁ $e_η₂ $e_η₃)
+ mkEvalWhiskerRightNil α h := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← α.srcM
+ let g ← α.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have α : Q($f ≅ $g) := α.e
+ return q(evalWhiskerRight_nil $α $h)
+ mkEvalWhiskerRightConsOfOf j α η ηs ηs₁ η₁ η₂ η₃ e_ηs₁ e_η₁ e_η₂ e_η₃ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← η.tgtM
+ let i ← ηs.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have j : Q($ctx.C) := j.e
+ have α : Q($f ≅ $g) := α.e
+ have η : Q($g ⟶ $h) := η.e.e
+ have ηs : Q($h ⟶ $i) := ηs.e.e
+ have ηs₁ : Q($h ⊗ $j ⟶ $i ⊗ $j) := ηs₁.e.e
+ have η₁ : Q($g ⊗ $j ⟶ $h ⊗ $j) := η₁.e.e
+ have η₂ : Q($g ⊗ $j ⟶ $i ⊗ $j) := η₂.e.e
+ have η₃ : Q($f ⊗ $j ⟶ $i ⊗ $j) := η₃.e.e
+ have e_ηs₁ : Q($ηs ▷ $j = $ηs₁) := e_ηs₁
+ have e_η₁ : Q($η ▷ $j = $η₁) := e_η₁
+ have e_η₂ : Q($η₁ ≫ $ηs₁ = $η₂) := e_η₂
+ have e_η₃ : Q((whiskerRightIso $α $j).hom ≫ $η₂ = $η₃) := e_η₃
+ return q(evalWhiskerRight_cons_of_of $e_ηs₁ $e_η₁ $e_η₂ $e_η₃)
+ mkEvalWhiskerRightConsWhisker f k α η ηs η₁ η₂ ηs₁ ηs₂ η₃ η₄ η₅
+ e_η₁ e_η₂ e_ηs₁ e_ηs₂ e_η₃ e_η₄ e_η₅ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let g ← α.srcM
+ let h ← η.srcM
+ let i ← η.tgtM
+ let j ← ηs.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have j : Q($ctx.C) := j.e
+ have k : Q($ctx.C) := k.e
+ have α : Q($g ≅ $f ⊗ $h) := α.e
+ have η : Q($h ⟶ $i) := η.e.e
+ have ηs : Q($f ⊗ $i ⟶ $j) := ηs.e.e
+ have η₁ : Q($h ⊗ $k ⟶ $i ⊗ $k) := η₁.e.e
+ have η₂ : Q($f ⊗ ($h ⊗ $k) ⟶ $f ⊗ ($i ⊗ $k)) := η₂.e.e
+ have ηs₁ : Q(($f ⊗ $i) ⊗ $k ⟶ $j ⊗ $k) := ηs₁.e.e
+ have ηs₂ : Q($f ⊗ ($i ⊗ $k) ⟶ $j ⊗ $k) := ηs₂.e.e
+ have η₃ : Q($f ⊗ ($h ⊗ $k) ⟶ $j ⊗ $k) := η₃.e.e
+ have η₄ : Q(($f ⊗ $h) ⊗ $k ⟶ $j ⊗ $k) := η₄.e.e
+ have η₅ : Q($g ⊗ $k ⟶ $j ⊗ $k) := η₅.e.e
+ have e_η₁ : Q(((Iso.refl _).hom ≫ $η ≫ (Iso.refl _).hom) ▷ $k = $η₁) := e_η₁
+ have e_η₂ : Q($f ◁ $η₁ = $η₂) := e_η₂
+ have e_ηs₁ : Q($ηs ▷ $k = $ηs₁) := e_ηs₁
+ have e_ηs₂ : Q((α_ _ _ _).inv ≫ $ηs₁ = $ηs₂) := e_ηs₂
+ have e_η₃ : Q($η₂ ≫ $ηs₂ = $η₃) := e_η₃
+ have e_η₄ : Q((α_ _ _ _).hom ≫ $η₃ = $η₄) := e_η₄
+ have e_η₅ : Q((whiskerRightIso $α $k).hom ≫ $η₄ = $η₅) := e_η₅
+ return q(evalWhiskerRight_cons_whisker $e_η₁ $e_η₂ $e_ηs₁ $e_ηs₂ $e_η₃ $e_η₄ $e_η₅)
+ mkEvalWhiskerRightComp g h η η₁ η₂ η₃ η₄ e_η₁ e_η₂ e_η₃ e_η₄ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η.srcM
+ let f' ← η.tgtM
+ have f : Q($ctx.C) := f.e
+ have f' : Q($ctx.C) := f'.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have η : Q($f ⟶ $f') := η.e.e
+ have η₁ : Q($f ⊗ $g ⟶ $f' ⊗ $g) := η₁.e.e
+ have η₂ : Q(($f ⊗ $g) ⊗ $h ⟶ ($f' ⊗ $g) ⊗ $h) := η₂.e.e
+ have η₃ : Q(($f ⊗ $g) ⊗ $h ⟶ $f' ⊗ ($g ⊗ $h)) := η₃.e.e
+ have η₄ : Q($f ⊗ ($g ⊗ $h) ⟶ $f' ⊗ ($g ⊗ $h)) := η₄.e.e
+ have e_η₁ : Q($η ▷ $g = $η₁) := e_η₁
+ have e_η₂ : Q($η₁ ▷ $h = $η₂) := e_η₂
+ have e_η₃ : Q($η₂ ≫ (α_ _ _ _).hom = $η₃) := e_η₃
+ have e_η₄ : Q((α_ _ _ _).inv ≫ $η₃ = $η₄) := e_η₄
+ return q(evalWhiskerRight_comp $e_η₁ $e_η₂ $e_η₃ $e_η₄)
+ mkEvalWhiskerRightId η η₁ η₂ e_η₁ e_η₂ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η.srcM
+ let g ← η.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have η : Q($f ⟶ $g) := η.e.e
+ have η₁ : Q($f ⟶ $g ⊗ 𝟙_ _) := η₁.e.e
+ have η₂ : Q($f ⊗ 𝟙_ _ ⟶ $g ⊗ 𝟙_ _) := η₂.e.e
+ have e_η₁ : Q($η ≫ (ρ_ _).inv = $η₁) := e_η₁
+ have e_η₂ : Q((ρ_ _).hom ≫ $η₁ = $η₂) := e_η₂
+ return q(evalWhiskerRight_id $e_η₁ $e_η₂)
+
+instance : MkEvalHorizontalComp MonoidalM where
+ mkEvalHorizontalCompAuxOf η θ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η.srcM
+ let g ← η.tgtM
+ let h ← θ.srcM
+ let i ← θ.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have η : Q($f ⟶ $g) := η.e.e
+ have θ : Q($h ⟶ $i) := θ.e.e
+ return q(evalHorizontalCompAux_of $η $θ)
+ mkEvalHorizontalCompAuxCons η ηs θ ηθ η₁ ηθ₁ ηθ₂ e_ηθ e_η₁ e_ηθ₁ e_ηθ₂ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η.srcM
+ let g ← η.tgtM
+ let f' ← ηs.srcM
+ let g' ← ηs.tgtM
+ let h ← θ.srcM
+ let i ← θ.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have f' : Q($ctx.C) := f'.e
+ have g' : Q($ctx.C) := g'.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have η : Q($f ⟶ $g) := η.e.e
+ have ηs : Q($f' ⟶ $g') := ηs.e.e
+ have θ : Q($h ⟶ $i) := θ.e.e
+ have ηθ : Q($f' ⊗ $h ⟶ $g' ⊗ $i) := ηθ.e.e
+ have η₁ : Q($f ⊗ ($f' ⊗ $h) ⟶ $g ⊗ ($g' ⊗ $i)) := η₁.e.e
+ have ηθ₁ : Q($f ⊗ ($f' ⊗ $h) ⟶ ($g ⊗ $g') ⊗ $i) := ηθ₁.e.e
+ have ηθ₂ : Q(($f ⊗ $f') ⊗ $h ⟶ ($g ⊗ $g') ⊗ $i) := ηθ₂.e.e
+ have e_ηθ : Q($ηs ⊗ $θ = $ηθ) := e_ηθ
+ have e_η₁ : Q(((Iso.refl _).hom ≫ $η ≫ (Iso.refl _).hom) ⊗ $ηθ = $η₁) := e_η₁
+ have e_ηθ₁ : Q($η₁ ≫ (α_ _ _ _).inv = $ηθ₁) := e_ηθ₁
+ have e_ηθ₂ : Q((α_ _ _ _).hom ≫ $ηθ₁ = $ηθ₂) := e_ηθ₂
+ return q(evalHorizontalCompAux_cons $e_ηθ $e_η₁ $e_ηθ₁ $e_ηθ₂)
+ mkEvalHorizontalCompAux'Whisker f η θ ηθ η₁ η₂ η₃ e_ηθ e_η₁ e_η₂ e_η₃ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let g ← η.srcM
+ let h ← η.tgtM
+ let f' ← θ.srcM
+ let g' ← θ.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have f' : Q($ctx.C) := f'.e
+ have g' : Q($ctx.C) := g'.e
+ have η : Q($g ⟶ $h) := η.e.e
+ have θ : Q($f' ⟶ $g') := θ.e.e
+ have ηθ : Q($g ⊗ $f' ⟶ $h ⊗ $g') := ηθ.e.e
+ have η₁ : Q($f ⊗ ($g ⊗ $f') ⟶ $f ⊗ ($h ⊗ $g')) := η₁.e.e
+ have η₂ : Q($f ⊗ ($g ⊗ $f') ⟶ ($f ⊗ $h) ⊗ $g') := η₂.e.e
+ have η₃ : Q(($f ⊗ $g) ⊗ $f' ⟶ ($f ⊗ $h) ⊗ $g') := η₃.e.e
+ have e_ηθ : Q($η ⊗ $θ = $ηθ) := e_ηθ
+ have e_η₁ : Q($f ◁ $ηθ = $η₁) := e_η₁
+ have e_η₂ : Q($η₁ ≫ (α_ _ _ _).inv = $η₂) := e_η₂
+ have e_η₃ : Q((α_ _ _ _).hom ≫ $η₂ = $η₃) := e_η₃
+ return q(evalHorizontalCompAux'_whisker $e_ηθ $e_η₁ $e_η₂ $e_η₃)
+ mkEvalHorizontalCompAux'OfWhisker f η θ η₁ ηθ ηθ₁ ηθ₂ e_η₁ e_ηθ e_ηθ₁ e_ηθ₂ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let g ← η.srcM
+ let h ← η.tgtM
+ let f' ← θ.srcM
+ let g' ← θ.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have f' : Q($ctx.C) := f'.e
+ have g' : Q($ctx.C) := g'.e
+ have η : Q($g ⟶ $h) := η.e.e
+ have θ : Q($f' ⟶ $g') := θ.e.e
+ have η₁ : Q($g ⊗ $f ⟶ $h ⊗ $f) := η₁.e.e
+ have ηθ : Q(($g ⊗ $f) ⊗ $f' ⟶ ($h ⊗ $f) ⊗ $g') := ηθ.e.e
+ have ηθ₁ : Q(($g ⊗ $f) ⊗ $f' ⟶ $h ⊗ ($f ⊗ $g')) := ηθ₁.e.e
+ have ηθ₂ : Q($g ⊗ ($f ⊗ $f') ⟶ $h ⊗ ($f ⊗ $g')) := ηθ₂.e.e
+ have e_η₁ : Q($η ▷ $f = $η₁) := e_η₁
+ have e_ηθ : Q($η₁ ⊗ ((Iso.refl _).hom ≫ $θ ≫ (Iso.refl _).hom) = $ηθ) := e_ηθ
+ have e_ηθ₁ : Q($ηθ ≫ (α_ _ _ _).hom = $ηθ₁) := e_ηθ₁
+ have e_ηθ₂ : Q((α_ _ _ _).inv ≫ $ηθ₁ = $ηθ₂) := e_ηθ₂
+ return q(evalHorizontalCompAux'_of_whisker $e_η₁ $e_ηθ $e_ηθ₁ $e_ηθ₂)
+ mkEvalHorizontalCompNilNil α β := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← β.srcM
+ let i ← β.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have α : Q($f ≅ $g) := α.e
+ have β : Q($h ≅ $i) := β.e
+ return q(evalHorizontalComp_nil_nil $α $β)
+ mkEvalHorizontalCompNilCons α β η ηs η₁ ηs₁ η₂ η₃ e_η₁ e_ηs₁ e_η₂ e_η₃ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← α.srcM
+ let g ← α.tgtM
+ let f' ← β.srcM
+ let g' ← β.tgtM
+ let h ← η.tgtM
+ let i ← ηs.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have f' : Q($ctx.C) := f'.e
+ have g' : Q($ctx.C) := g'.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have α : Q($f ≅ $g) := α.e
+ have β : Q($f' ≅ $g') := β.e
+ have η : Q($g' ⟶ $h) := η.e.e
+ have ηs : Q($h ⟶ $i) := ηs.e.e
+ have η₁ : Q($g ⊗ $g' ⟶ $g ⊗ $h) := η₁.e.e
+ have ηs₁ : Q($g ⊗ $h ⟶ $g ⊗ $i) := ηs₁.e.e
+ have η₂ : Q($g ⊗ $g' ⟶ $g ⊗ $i) := η₂.e.e
+ have η₃ : Q($f ⊗ $f' ⟶ $g ⊗ $i) := η₃.e.e
+ have e_η₁ : Q($g ◁ ((Iso.refl _).hom ≫ $η ≫ (Iso.refl _).hom) = $η₁) := e_η₁
+ have e_ηs₁ : Q($g ◁ $ηs = $ηs₁) := e_ηs₁
+ have e_η₂ : Q($η₁ ≫ $ηs₁ = $η₂) := e_η₂
+ have e_η₃ : Q(($α ⊗ $β).hom ≫ $η₂ = $η₃) := e_η₃
+ return q(evalHorizontalComp_nil_cons $e_η₁ $e_ηs₁ $e_η₂ $e_η₃)
+ mkEvalHorizontalCompConsNil α β η ηs η₁ ηs₁ η₂ η₃ e_η₁ e_ηs₁ e_η₂ e_η₃ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← η.tgtM
+ let i ← ηs.tgtM
+ let f' ← β.srcM
+ let g' ← β.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have f' : Q($ctx.C) := f'.e
+ have g' : Q($ctx.C) := g'.e
+ have α : Q($f ≅ $g) := α.e
+ have η : Q($g ⟶ $h) := η.e.e
+ have ηs : Q($h ⟶ $i) := ηs.e.e
+ have β : Q($f' ≅ $g') := β.e
+ have η₁ : Q($g ⊗ $g' ⟶ $h ⊗ $g') := η₁.e.e
+ have ηs₁ : Q($h ⊗ $g' ⟶ $i ⊗ $g') := ηs₁.e.e
+ have η₂ : Q($g ⊗ $g' ⟶ $i ⊗ $g') := η₂.e.e
+ have η₃ : Q($f ⊗ $f' ⟶ $i ⊗ $g') := η₃.e.e
+ have e_η₁ : Q(((Iso.refl _).hom ≫ $η ≫ (Iso.refl _).hom) ▷ $g' = $η₁) := e_η₁
+ have e_ηs₁ : Q($ηs ▷ $g' = $ηs₁) := e_ηs₁
+ have e_η₂ : Q($η₁ ≫ $ηs₁ = $η₂) := e_η₂
+ have e_η₃ : Q(($α ⊗ $β).hom ≫ $η₂ = $η₃) := e_η₃
+ return q(evalHorizontalComp_cons_nil $e_η₁ $e_ηs₁ $e_η₂ $e_η₃)
+ mkEvalHorizontalCompConsCons α β η θ ηs θs ηθ ηθs ηθ₁ ηθ₂ e_ηθ e_ηθs e_ηθ₁ e_ηθ₂ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← α.srcM
+ let g ← α.tgtM
+ let h ← η.tgtM
+ let i ← ηs.tgtM
+ let f' ← β.srcM
+ let g' ← β.tgtM
+ let h' ← θ.tgtM
+ let i' ← θs.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have f' : Q($ctx.C) := f'.e
+ have g' : Q($ctx.C) := g'.e
+ have h' : Q($ctx.C) := h'.e
+ have i' : Q($ctx.C) := i'.e
+ have α : Q($f ≅ $g) := α.e
+ have η : Q($g ⟶ $h) := η.e.e
+ have ηs : Q($h ⟶ $i) := ηs.e.e
+ have β : Q($f' ≅ $g') := β.e
+ have θ : Q($g' ⟶ $h') := θ.e.e
+ have θs : Q($h' ⟶ $i') := θs.e.e
+ have ηθ : Q($g ⊗ $g' ⟶ $h ⊗ $h') := ηθ.e.e
+ have ηθs : Q($h ⊗ $h' ⟶ $i ⊗ $i') := ηθs.e.e
+ have ηθ₁ : Q($g ⊗ $g' ⟶ $i ⊗ $i') := ηθ₁.e.e
+ have ηθ₂ : Q($f ⊗ $f' ⟶ $i ⊗ $i') := ηθ₂.e.e
+ have e_ηθ : Q($η ⊗ $θ = $ηθ) := e_ηθ
+ have e_ηθs : Q($ηs ⊗ $θs = $ηθs) := e_ηθs
+ have e_ηθ₁ : Q($ηθ ≫ $ηθs = $ηθ₁) := e_ηθ₁
+ have e_ηθ₂ : Q(($α ⊗ $β).hom ≫ $ηθ₁ = $ηθ₂) := e_ηθ₂
+ return q(evalHorizontalComp_cons_cons $e_ηθ $e_ηθs $e_ηθ₁ $e_ηθ₂)
+
+instance : MkEval MonoidalM where
+ mkEvalComp η θ η' θ' ι e_η e_θ e_ηθ := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← η'.srcM
+ let g ← η'.tgtM
+ let h ← θ'.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have η : Q($f ⟶ $g) := η.e
+ have η' : Q($f ⟶ $g) := η'.e.e
+ have θ : Q($g ⟶ $h) := θ.e
+ have θ' : Q($g ⟶ $h) := θ'.e.e
+ have ι : Q($f ⟶ $h) := ι.e.e
+ have e_η : Q($η = $η') := e_η
+ have e_θ : Q($θ = $θ') := e_θ
+ have e_ηθ : Q($η' ≫ $θ' = $ι) := e_ηθ
+ return q(eval_comp $e_η $e_θ $e_ηθ)
+ mkEvalWhiskerLeft f η η' θ e_η e_θ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let g ← η'.srcM
+ let h ← η'.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have η : Q($g ⟶ $h) := η.e
+ have η' : Q($g ⟶ $h) := η'.e.e
+ have θ : Q($f ⊗ $g ⟶ $f ⊗ $h) := θ.e.e
+ have e_η : Q($η = $η') := e_η
+ have e_θ : Q($f ◁ $η' = $θ) := e_θ
+ return q(eval_whiskerLeft $e_η $e_θ)
+ mkEvalWhiskerRight η h η' θ e_η e_θ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η'.srcM
+ let g ← η'.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have η : Q($f ⟶ $g) := η.e
+ have η' : Q($f ⟶ $g) := η'.e.e
+ have θ : Q($f ⊗ $h ⟶ $g ⊗ $h) := θ.e.e
+ have e_η : Q($η = $η') := e_η
+ have e_θ : Q($η' ▷ $h = $θ) := e_θ
+ return q(eval_whiskerRight $e_η $e_θ)
+ mkEvalHorizontalComp η θ η' θ' ι e_η e_θ e_ι := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let f ← η'.srcM
+ let g ← η'.tgtM
+ let h ← θ'.srcM
+ let i ← θ'.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have η : Q($f ⟶ $g) := η.e
+ have η' : Q($f ⟶ $g) := η'.e.e
+ have θ : Q($h ⟶ $i) := θ.e
+ have θ' : Q($h ⟶ $i) := θ'.e.e
+ have ι : Q($f ⊗ $h ⟶ $g ⊗ $i) := ι.e.e
+ have e_η : Q($η = $η') := e_η
+ have e_θ : Q($θ = $θ') := e_θ
+ have e_ι : Q($η' ⊗ $θ' = $ι) := e_ι
+ return q(eval_tensorHom $e_η $e_θ $e_ι)
+ mkEvalOf η := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f := η.src
+ let g := η.tgt
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have η : Q($f ⟶ $g) := η.e
+ return q(eval_of $η)
+ mkEvalMonoidalComp η θ α η' θ' αθ ηαθ e_η e_θ e_αθ e_ηαθ := do
+ let ctx ← read
+ let _cat := ctx.instCat
+ let f ← η'.srcM
+ let g ← η'.tgtM
+ let h ← α.tgtM
+ let i ← θ'.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have i : Q($ctx.C) := i.e
+ have η : Q($f ⟶ $g) := η.e
+ have η' : Q($f ⟶ $g) := η'.e.e
+ have α : Q($g ≅ $h) := α.e
+ have θ : Q($h ⟶ $i) := θ.e
+ have θ' : Q($h ⟶ $i) := θ'.e.e
+ have αθ : Q($g ⟶ $i) := αθ.e.e
+ have ηαθ : Q($f ⟶ $i) := ηαθ.e.e
+ have e_η : Q($η = $η') := e_η
+ have e_θ : Q($θ = $θ') := e_θ
+ have e_αθ : Q(Iso.hom $α ≫ $θ' = $αθ) := e_αθ
+ have e_ηαθ : Q($η' ≫ $αθ = $ηαθ) := e_ηαθ
+ return q(eval_monoidalComp $e_η $e_θ $e_αθ $e_ηαθ)
+
+instance : MonadNormalExpr MonoidalM where
+ whiskerRightM η h := do
+ return .whisker (← MonadMor₂.whiskerRightM η.e (.of h)) η h
+ hConsM η θ := do
+ return .cons (← MonadMor₂.horizontalCompM η.e θ.e) η θ
+ whiskerLeftM f η := do
+ return .whisker (← MonadMor₂.whiskerLeftM (.of f) η.e) f η
+ nilM α := do
+ return .nil (← MonadMor₂.homM α) α
+ consM α η ηs := do
+ return .cons (← MonadMor₂.comp₂M (← MonadMor₂.homM α) (← MonadMor₂.comp₂M η.e ηs.e)) α η ηs
+
+instance : MkMor₂ MonoidalM where
+ ofExpr := Mor₂OfExpr
+
+end Mathlib.Tactic.Monoidal
diff --git a/Mathlib/Tactic/CategoryTheory/Monoidal/PureCoherence.lean b/Mathlib/Tactic/CategoryTheory/Monoidal/PureCoherence.lean
new file mode 100644
index 0000000000000..56c83c25a1459
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/Monoidal/PureCoherence.lean
@@ -0,0 +1,277 @@
+/-
+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.Tactic.CategoryTheory.Coherence.PureCoherence
+import Mathlib.Tactic.CategoryTheory.Monoidal.Datatypes
+
+/-!
+# Coherence tactic for monoidal categories
+
+We provide a `monoidal_coherence` tactic,
+which proves that any two morphisms (with the same source and target)
+in a monoidal category which are built out of associators and unitors
+are equal.
+
+-/
+
+open Lean Meta Elab Qq
+open CategoryTheory Mathlib.Tactic.BicategoryLike MonoidalCategory
+
+namespace Mathlib.Tactic.Monoidal
+
+section
+
+universe v u
+
+variable {C : Type u} [Category.{v} C] [MonoidalCategory C]
+
+local infixr:81 " ◁ " => MonoidalCategory.whiskerLeftIso
+local infixl:81 " ▷ " => MonoidalCategory.whiskerRightIso
+
+/-- The composition of the normalizing isomorphisms `η_f : p ⊗ f ≅ pf` and `η_g : pf ⊗ g ≅ pfg`. -/
+abbrev normalizeIsoComp {p f g pf pfg : C} (η_f : p ⊗ f ≅ pf) (η_g : pf ⊗ g ≅ pfg) :=
+ (α_ _ _ _).symm ≪≫ whiskerRightIso η_f g ≪≫ η_g
+
+theorem naturality_associator {p f g h pf pfg pfgh : C}
+ (η_f : p ⊗ f ≅ pf) (η_g : pf ⊗ g ≅ pfg) (η_h : pfg ⊗ h ≅ pfgh) :
+ p ◁ (α_ f g h) ≪≫ normalizeIsoComp η_f (normalizeIsoComp η_g η_h) =
+ normalizeIsoComp (normalizeIsoComp η_f η_g) η_h :=
+ Iso.ext (by simp)
+
+theorem naturality_leftUnitor {p f pf : C} (η_f : p ⊗ f ≅ pf) :
+ p ◁ (λ_ f) ≪≫ η_f = normalizeIsoComp (ρ_ p) η_f :=
+ Iso.ext (by simp)
+
+theorem naturality_rightUnitor {p f pf : C} (η_f : p ⊗ f ≅ pf) :
+ p ◁ (ρ_ f) ≪≫ η_f = normalizeIsoComp η_f (ρ_ pf) :=
+ Iso.ext (by simp)
+
+theorem naturality_id {p f pf : C} (η_f : p ⊗ f ≅ pf) :
+ p ◁ Iso.refl f ≪≫ η_f = η_f := by
+ simp
+
+theorem naturality_comp {p f g h pf : C} {η : f ≅ g} {θ : g ≅ h}
+ (η_f : p ⊗ f ≅ pf) (η_g : p ⊗ g ≅ pf) (η_h : p ⊗ h ≅ pf)
+ (ih_η : p ◁ η ≪≫ η_g = η_f) (ih_θ : p ◁ θ ≪≫ η_h = η_g) :
+ p ◁ (η ≪≫ θ) ≪≫ η_h = η_f := by
+ simp_all
+
+theorem naturality_whiskerLeft {p f g h pf pfg : C} {η : g ≅ h}
+ (η_f : p ⊗ f ≅ pf) (η_fg : pf ⊗ g ≅ pfg) (η_fh : (pf ⊗ h) ≅ pfg)
+ (ih_η : pf ◁ η ≪≫ η_fh = η_fg) :
+ p ◁ (f ◁ η) ≪≫ normalizeIsoComp η_f η_fh = normalizeIsoComp η_f η_fg := by
+ rw [← ih_η]
+ apply Iso.ext
+ simp [← whisker_exchange_assoc]
+
+theorem naturality_whiskerRight {p f g h pf pfh : C} {η : f ≅ g}
+ (η_f : p ⊗ f ≅ pf) (η_g : p ⊗ g ≅ pf) (η_fh : (pf ⊗ h) ≅ pfh)
+ (ih_η : p ◁ η ≪≫ η_g = η_f) :
+ p ◁ (η ▷ h) ≪≫ normalizeIsoComp η_g η_fh = normalizeIsoComp η_f η_fh := by
+ rw [← ih_η]
+ apply Iso.ext
+ simp
+
+theorem naturality_tensorHom {p f₁ g₁ f₂ g₂ pf₁ pf₁f₂ : C} {η : f₁ ≅ g₁} {θ : f₂ ≅ g₂}
+ (η_f₁ : p ⊗ f₁ ≅ pf₁) (η_g₁ : p ⊗ g₁ ≅ pf₁) (η_f₂ : pf₁ ⊗ f₂ ≅ pf₁f₂) (η_g₂ : pf₁ ⊗ g₂ ≅ pf₁f₂)
+ (ih_η : p ◁ η ≪≫ η_g₁ = η_f₁)
+ (ih_θ : pf₁ ◁ θ ≪≫ η_g₂ = η_f₂) :
+ p ◁ (η ⊗ θ) ≪≫ normalizeIsoComp η_g₁ η_g₂ = normalizeIsoComp η_f₁ η_f₂ := by
+ rw [tensorIso_def]
+ apply naturality_comp
+ · apply naturality_whiskerRight _ _ _ ih_η
+ · apply naturality_whiskerLeft _ _ _ ih_θ
+
+theorem naturality_inv {p f g pf : C} {η : f ≅ g}
+ (η_f : p ⊗ f ≅ pf) (η_g : p ⊗ g ≅ pf) (ih : p ◁ η ≪≫ η_g = η_f) :
+ p ◁ η.symm ≪≫ η_f = η_g := by
+ rw [← ih]
+ apply Iso.ext
+ simp
+
+instance : MonadNormalizeNaturality MonoidalM where
+ mkNaturalityAssociator p pf pfg pfgh f g h η_f η_g η_h := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have p : Q($ctx.C) := p.e.e
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have pf : Q($ctx.C) := pf.e.e
+ have pfg : Q($ctx.C) := pfg.e.e
+ have pfgh : Q($ctx.C) := pfgh.e.e
+ have η_f : Q($p ⊗ $f ≅ $pf) := η_f.e
+ have η_g : Q($pf ⊗ $g ≅ $pfg) := η_g.e
+ have η_h : Q($pfg ⊗ $h ≅ $pfgh) := η_h.e
+ return q(naturality_associator $η_f $η_g $η_h)
+ mkNaturalityLeftUnitor p pf f η_f := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have p : Q($ctx.C) := p.e.e
+ have f : Q($ctx.C) := f.e
+ have pf : Q($ctx.C) := pf.e.e
+ have η_f : Q($p ⊗ $f ≅ $pf) := η_f.e
+ return q(naturality_leftUnitor $η_f)
+ mkNaturalityRightUnitor p pf f η_f := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have p : Q($ctx.C) := p.e.e
+ have f : Q($ctx.C) := f.e
+ have pf : Q($ctx.C) := pf.e.e
+ have η_f : Q($p ⊗ $f ≅ $pf) := η_f.e
+ return q(naturality_rightUnitor $η_f)
+ mkNaturalityId p pf f η_f := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have p : Q($ctx.C) := p.e.e
+ have f : Q($ctx.C) := f.e
+ have pf : Q($ctx.C) := pf.e.e
+ have η_f : Q($p ⊗ $f ≅ $pf) := η_f.e
+ return q(naturality_id $η_f)
+ mkNaturalityComp p pf f g h η θ η_f η_g η_h ih_η ih_θ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have p : Q($ctx.C) := p.e.e
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have pf : Q($ctx.C) := pf.e.e
+ have η : Q($f ≅ $g) := η.e
+ have θ : Q($g ≅ $h) := θ.e
+ have η_f : Q($p ⊗ $f ≅ $pf) := η_f.e
+ have η_g : Q($p ⊗ $g ≅ $pf) := η_g.e
+ have η_h : Q($p ⊗ $h ≅ $pf) := η_h.e
+ have ih_η : Q($p ◁ $η ≪≫ $η_g = $η_f) := ih_η
+ have ih_θ : Q($p ◁ $θ ≪≫ $η_h = $η_g) := ih_θ
+ return q(naturality_comp $η_f $η_g $η_h $ih_η $ih_θ)
+ mkNaturalityWhiskerLeft p pf pfg f g h η η_f η_fg η_fh ih_η := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have p : Q($ctx.C) := p.e.e
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have pf : Q($ctx.C) := pf.e.e
+ have pfg : Q($ctx.C) := pfg.e.e
+ have η : Q($g ≅ $h) := η.e
+ have η_f : Q($p ⊗ $f ≅ $pf) := η_f.e
+ have η_fg : Q($pf ⊗ $g ≅ $pfg) := η_fg.e
+ have η_fh : Q($pf ⊗ $h ≅ $pfg) := η_fh.e
+ have ih_η : Q($pf ◁ $η ≪≫ $η_fh = $η_fg) := ih_η
+ return q(naturality_whiskerLeft $η_f $η_fg $η_fh $ih_η)
+ mkNaturalityWhiskerRight p pf pfh f g h η η_f η_g η_fh ih_η := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have p : Q($ctx.C) := p.e.e
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have h : Q($ctx.C) := h.e
+ have pf : Q($ctx.C) := pf.e.e
+ have pfh : Q($ctx.C) := pfh.e.e
+ have η : Q($f ≅ $g) := η.e
+ have η_f : Q($p ⊗ $f ≅ $pf) := η_f.e
+ have η_g : Q($p ⊗ $g ≅ $pf) := η_g.e
+ have η_fh : Q($pf ⊗ $h ≅ $pfh) := η_fh.e
+ have ih_η : Q($p ◁ $η ≪≫ $η_g = $η_f) := ih_η
+ return q(naturality_whiskerRight $η_f $η_g $η_fh $ih_η)
+ mkNaturalityHorizontalComp p pf₁ pf₁f₂ f₁ g₁ f₂ g₂ η θ η_f₁ η_g₁ η_f₂ η_g₂ ih_η ih_θ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have p : Q($ctx.C) := p.e.e
+ have f₁ : Q($ctx.C) := f₁.e
+ have g₁ : Q($ctx.C) := g₁.e
+ have f₂ : Q($ctx.C) := f₂.e
+ have g₂ : Q($ctx.C) := g₂.e
+ have pf₁ : Q($ctx.C) := pf₁.e.e
+ have pf₁f₂ : Q($ctx.C) := pf₁f₂.e.e
+ have η : Q($f₁ ≅ $g₁) := η.e
+ have θ : Q($f₂ ≅ $g₂) := θ.e
+ have η_f₁ : Q($p ⊗ $f₁ ≅ $pf₁) := η_f₁.e
+ have η_g₁ : Q($p ⊗ $g₁ ≅ $pf₁) := η_g₁.e
+ have η_f₂ : Q($pf₁ ⊗ $f₂ ≅ $pf₁f₂) := η_f₂.e
+ have η_g₂ : Q($pf₁ ⊗ $g₂ ≅ $pf₁f₂) := η_g₂.e
+ have ih_η : Q($p ◁ $η ≪≫ $η_g₁ = $η_f₁) := ih_η
+ have ih_θ : Q($pf₁ ◁ $θ ≪≫ $η_g₂ = $η_f₂) := ih_θ
+ return q(naturality_tensorHom $η_f₁ $η_g₁ $η_f₂ $η_g₂ $ih_η $ih_θ)
+ mkNaturalityInv p pf f g η η_f η_g ih := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ have p : Q($ctx.C) := p.e.e
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have pf : Q($ctx.C) := pf.e.e
+ have η : Q($f ≅ $g) := η.e
+ have η_f : Q($p ⊗ $f ≅ $pf) := η_f.e
+ have η_g : Q($p ⊗ $g ≅ $pf) := η_g.e
+ have ih : Q($p ◁ $η ≪≫ $η_g = $η_f) := ih
+ return q(naturality_inv $η_f $η_g $ih)
+
+theorem of_normalize_eq {f g f' : C} {η θ : f ≅ g} (η_f : 𝟙_ C ⊗ f ≅ f') (η_g : 𝟙_ C ⊗ g ≅ f')
+ (h_η : 𝟙_ C ◁ η ≪≫ η_g = η_f)
+ (h_θ : 𝟙_ C ◁ θ ≪≫ η_g = η_f) : η = θ := by
+ apply Iso.ext
+ calc
+ η.hom = (λ_ f).inv ≫ η_f.hom ≫ η_g.inv ≫ (λ_ g).hom := by
+ simp [← reassoc_of% (congrArg Iso.hom h_η)]
+ _ = θ.hom := by
+ simp [← reassoc_of% (congrArg Iso.hom h_θ)]
+
+theorem mk_eq_of_naturality {f g f' : C} {η θ : f ⟶ g} {η' θ' : f ≅ g}
+ (η_f : 𝟙_ C ⊗ f ≅ f') (η_g : 𝟙_ C ⊗ g ≅ f')
+ (η_hom : η'.hom = η) (Θ_hom : θ'.hom = θ)
+ (Hη : whiskerLeftIso (𝟙_ C) η' ≪≫ η_g = η_f)
+ (Hθ : whiskerLeftIso (𝟙_ C) θ' ≪≫ η_g = η_f) : η = θ :=
+ calc
+ η = η'.hom := η_hom.symm
+ _ = (λ_ f).inv ≫ η_f.hom ≫ η_g.inv ≫ (λ_ g).hom := by
+ simp [← reassoc_of% (congrArg Iso.hom Hη)]
+ _ = θ'.hom := by
+ simp [← reassoc_of% (congrArg Iso.hom Hθ)]
+ _ = θ := Θ_hom
+
+end
+
+instance : MkEqOfNaturality MonoidalM where
+ mkEqOfNaturality η θ ηIso θIso η_f η_g Hη Hθ := do
+ let ctx ← read
+ let .some _monoidal := ctx.instMonoidal? | synthMonoidalError
+ let η' := ηIso.e
+ let θ' := θIso.e
+ let f ← η'.srcM
+ let g ← η'.tgtM
+ let f' ← η_f.tgtM
+ have f : Q($ctx.C) := f.e
+ have g : Q($ctx.C) := g.e
+ have f' : Q($ctx.C) := f'.e
+ have η : Q($f ⟶ $g) := η
+ have θ : Q($f ⟶ $g) := θ
+ have η'_e : Q($f ≅ $g) := η'.e
+ have θ'_e : Q($f ≅ $g) := θ'.e
+ have η_f : Q(tensorUnit ⊗ $f ≅ $f') := η_f.e
+ have η_g : Q(tensorUnit ⊗ $g ≅ $f') := η_g.e
+ have η_hom : Q(Iso.hom $η'_e = $η) := ηIso.eq
+ have Θ_hom : Q(Iso.hom $θ'_e = $θ) := θIso.eq
+ have Hη : Q(whiskerLeftIso tensorUnit $η'_e ≪≫ $η_g = $η_f) := Hη
+ have Hθ : Q(whiskerLeftIso tensorUnit $θ'_e ≪≫ $η_g = $η_f) := Hθ
+ return q(mk_eq_of_naturality $η_f $η_g $η_hom $Θ_hom $Hη $Hθ)
+
+open Elab.Tactic
+
+/-- Close the goal of the form `η = θ`, where `η` and `θ` are 2-isomorphisms made up only of
+associators, unitors, and identities.
+```lean
+example {C : Type} [Category C] [MonoidalCategory C] :
+ (λ_ (𝟙_ C)).hom = (ρ_ (𝟙_ C)).hom := by
+ monoidal_coherence
+```
+-/
+def pureCoherence (mvarId : MVarId) : MetaM (List MVarId) :=
+ BicategoryLike.pureCoherence Monoidal.Context `monoidal mvarId
+
+@[inherit_doc pureCoherence]
+elab "monoidal_coherence" : tactic => withMainContext do
+ replaceMainGoal <| ← Monoidal.pureCoherence <| ← getMainGoal
+
+end Mathlib.Tactic.Monoidal
diff --git a/Mathlib/Tactic/CategoryTheory/MonoidalComp.lean b/Mathlib/Tactic/CategoryTheory/MonoidalComp.lean
index e62ef8538919e..316faec90eedf 100644
--- a/Mathlib/Tactic/CategoryTheory/MonoidalComp.lean
+++ b/Mathlib/Tactic/CategoryTheory/MonoidalComp.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2022. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Yuma Mizuno, Oleksandr Manzyuk
+Authors: Kim Morrison, Yuma Mizuno, Oleksandr Manzyuk
-/
import Mathlib.CategoryTheory.Monoidal.Category
@@ -47,25 +47,20 @@ Used by the `⊗≫` monoidal composition operator, and the `coherence` tactic.
-- We could likely turn this into a `Prop` valued existential if that proves useful.
class MonoidalCoherence (X Y : C) where
/-- A monoidal structural isomorphism between two objects. -/
- hom : X ⟶ Y
- [isIso : IsIso hom]
+ iso : X ≅ Y
/-- Notation for identities up to unitors and associators. -/
scoped[CategoryTheory.MonoidalCategory] notation " ⊗𝟙 " =>
- MonoidalCoherence.hom -- type as \ot 𝟙
-
-attribute [instance] MonoidalCoherence.isIso
-
-noncomputable section
+ MonoidalCoherence.iso -- type as \ot 𝟙
/-- Construct an isomorphism between two objects in a monoidal category
out of unitors and associators. -/
-def monoidalIso (X Y : C) [MonoidalCoherence X Y] : X ≅ Y := asIso ⊗𝟙
+abbrev monoidalIso (X Y : C) [MonoidalCoherence X Y] : X ≅ Y := MonoidalCoherence.iso
/-- Compose two morphisms in a monoidal category,
inserting unitors and associators between as necessary. -/
def monoidalComp {W X Y Z : C} [MonoidalCoherence X Y] (f : W ⟶ X) (g : Y ⟶ Z) : W ⟶ Z :=
- f ≫ ⊗𝟙 ≫ g
+ f ≫ ⊗𝟙.hom ≫ g
@[inherit_doc monoidalComp]
scoped[CategoryTheory.MonoidalCategory] infixr:80 " ⊗≫ " =>
@@ -74,70 +69,68 @@ scoped[CategoryTheory.MonoidalCategory] infixr:80 " ⊗≫ " =>
/-- Compose two isomorphisms in a monoidal category,
inserting unitors and associators between as necessary. -/
def monoidalIsoComp {W X Y Z : C} [MonoidalCoherence X Y] (f : W ≅ X) (g : Y ≅ Z) : W ≅ Z :=
- f ≪≫ asIso ⊗𝟙 ≪≫ g
+ f ≪≫ ⊗𝟙 ≪≫ g
@[inherit_doc monoidalIsoComp]
scoped[CategoryTheory.MonoidalCategory] infixr:80 " ≪⊗≫ " =>
monoidalIsoComp -- type as \ll \ot \gg
-end
-
namespace MonoidalCoherence
variable [MonoidalCategory C]
@[simps]
-instance refl (X : C) : MonoidalCoherence X X := ⟨𝟙 _⟩
+instance refl (X : C) : MonoidalCoherence X X := ⟨Iso.refl _⟩
@[simps]
instance whiskerLeft (X Y Z : C) [MonoidalCoherence Y Z] :
MonoidalCoherence (X ⊗ Y) (X ⊗ Z) :=
- ⟨X ◁ ⊗𝟙⟩
+ ⟨whiskerLeftIso X ⊗𝟙⟩
@[simps]
instance whiskerRight (X Y Z : C) [MonoidalCoherence X Y] :
MonoidalCoherence (X ⊗ Z) (Y ⊗ Z) :=
- ⟨⊗𝟙 ▷ Z⟩
+ ⟨whiskerRightIso ⊗𝟙 Z⟩
@[simps]
instance tensor_right (X Y : C) [MonoidalCoherence (𝟙_ C) Y] :
MonoidalCoherence X (X ⊗ Y) :=
- ⟨(ρ_ X).inv ≫ X ◁ ⊗𝟙⟩
+ ⟨(ρ_ X).symm ≪≫ (whiskerLeftIso X ⊗𝟙)⟩
@[simps]
instance tensor_right' (X Y : C) [MonoidalCoherence Y (𝟙_ C)] :
MonoidalCoherence (X ⊗ Y) X :=
- ⟨X ◁ ⊗𝟙 ≫ (ρ_ X).hom⟩
+ ⟨whiskerLeftIso X ⊗𝟙 ≪≫ (ρ_ X)⟩
@[simps]
instance left (X Y : C) [MonoidalCoherence X Y] :
MonoidalCoherence (𝟙_ C ⊗ X) Y :=
- ⟨(λ_ X).hom ≫ ⊗𝟙⟩
+ ⟨λ_ X ≪≫ ⊗𝟙⟩
@[simps]
instance left' (X Y : C) [MonoidalCoherence X Y] :
MonoidalCoherence X (𝟙_ C ⊗ Y) :=
- ⟨⊗𝟙 ≫ (λ_ Y).inv⟩
+ ⟨⊗𝟙 ≪≫ (λ_ Y).symm⟩
@[simps]
instance right (X Y : C) [MonoidalCoherence X Y] :
MonoidalCoherence (X ⊗ 𝟙_ C) Y :=
- ⟨(ρ_ X).hom ≫ ⊗𝟙⟩
+ ⟨ρ_ X ≪≫ ⊗𝟙⟩
@[simps]
instance right' (X Y : C) [MonoidalCoherence X Y] :
MonoidalCoherence X (Y ⊗ 𝟙_ C) :=
- ⟨⊗𝟙 ≫ (ρ_ Y).inv⟩
+ ⟨⊗𝟙 ≪≫ (ρ_ Y).symm⟩
@[simps]
instance assoc (X Y Z W : C) [MonoidalCoherence (X ⊗ (Y ⊗ Z)) W] :
MonoidalCoherence ((X ⊗ Y) ⊗ Z) W :=
- ⟨(α_ X Y Z).hom ≫ ⊗𝟙⟩
+ ⟨α_ X Y Z ≪≫ ⊗𝟙⟩
@[simps]
instance assoc' (W X Y Z : C) [MonoidalCoherence W (X ⊗ (Y ⊗ Z))] :
MonoidalCoherence W ((X ⊗ Y) ⊗ Z) :=
- ⟨⊗𝟙 ≫ (α_ X Y Z).inv⟩
+ ⟨⊗𝟙 ≪≫ (α_ X Y Z).symm⟩
end MonoidalCoherence
diff --git a/Mathlib/Tactic/CategoryTheory/Reassoc.lean b/Mathlib/Tactic/CategoryTheory/Reassoc.lean
index eedc010454f06..7861b38db0151 100644
--- a/Mathlib/Tactic/CategoryTheory/Reassoc.lean
+++ b/Mathlib/Tactic/CategoryTheory/Reassoc.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Functor.Basic
import Mathlib.Util.AddRelatedDecl
@@ -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 60a77786bac0a..d0c2105619b6e 100644
--- a/Mathlib/Tactic/CategoryTheory/Slice.lean
+++ b/Mathlib/Tactic/CategoryTheory/Slice.lean
@@ -1,8 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
-
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Category.Basic
import Mathlib.Tactic.Conv
diff --git a/Mathlib/Tactic/CategoryTheory/ToApp.lean b/Mathlib/Tactic/CategoryTheory/ToApp.lean
new file mode 100644
index 0000000000000..93a6aebb3170d
--- /dev/null
+++ b/Mathlib/Tactic/CategoryTheory/ToApp.lean
@@ -0,0 +1,142 @@
+/-
+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.Category.Cat
+import Mathlib.Util.AddRelatedDecl
+
+/-!
+# The `to_app` attribute
+
+Adding `@[to_app]` to a lemma named `F` of shape `∀ .., η = θ`, where `η θ : f ⟶ g` are 2-morphisms
+in some bicategory, create a new lemma named `F_app`. This lemma is obtained by first specializing
+the bicategory in which the equality is taking place to `Cat`, then applying `NatTrans.congr_app`
+to obtain a proof of `∀ ... (X : Cat), η.app X = θ.app X`, and finally simplifying the conclusion
+using some basic lemmas in the bicategory `Cat`:
+`Cat.whiskerLeft_app`, `Cat.whiskerRight_app`, `Cat.id_app`, `Cat.comp_app` and `Cat.eqToHom_app`
+
+So, for example, if the conclusion of `F` is `f ◁ η = θ` then the conclusion of `F_app` will be
+`η.app (f.obj X) = θ.app X`.
+
+This is useful for automatically generating lemmas that can be applied to expressions of 1-morphisms
+in `Cat` which contain components of 2-morphisms.
+
+There is also a term elaborator `to_app_of% t` for use within proofs.
+-/
+
+open Lean Meta Elab Tactic
+open Mathlib.Tactic
+
+namespace CategoryTheory
+
+/-- Simplify an expression in `Cat` using basic properties of `NatTrans.app`. -/
+def catAppSimp (e : Expr) : MetaM Simp.Result :=
+ simpOnlyNames [
+ ``Cat.whiskerLeft_app, ``Cat.whiskerRight_app, ``Cat.id_app, ``Cat.comp_app,
+ ``Cat.eqToHom_app] e
+ (config := { decide := false })
+
+/--
+Given a term of type `∀ ..., η = θ`, where `η θ : f ⟶ g` are 2-morphisms in some bicategory
+`B`, which is bound by the `∀` binder, get the corresponding equation in the bicategory `Cat`.
+
+It is important here that the levels in the term are level metavariables, as otherwise these will
+not be reassignable to the corresponding levels of `Cat`. -/
+def toCatExpr (e : Expr) : MetaM Expr := do
+ let (args, binderInfos, conclusion) ← forallMetaTelescope (← inferType e)
+ -- Find the expression corresponding to the bicategory, by anylizing `η = θ` (i.e. conclusion)
+ let B ←
+ match conclusion.getAppFnArgs with
+ | (`Eq, #[_, η, _]) =>
+ match (← inferType η).getAppFnArgs with
+ | (`Quiver.Hom, #[_, _, f, _]) =>
+ match (← inferType f).getAppFnArgs with
+ | (`Quiver.Hom, #[_, _, a, _]) => inferType a
+ | _ => throwError "The conclusion {conclusion} is not an equality of 2-morphisms!"
+ | _ => throwError "The conclusion {conclusion} is not an equality of 2-morphisms!"
+ | _ => throwError "The conclusion {conclusion} is not an equality!"
+ -- Create level metavariables to be used for `Cat.{v, u}`
+ let u ← mkFreshLevelMVar
+ let v ← mkFreshLevelMVar
+ -- Assign `B` to `Cat.{v, u}`
+ let _ ← isDefEq B (.const ``Cat [v, u])
+ -- Assign the right bicategory instance to `Cat.{v, u}`
+ let some inst ← args.findM? fun x => do
+ return (← inferType x).getAppFnArgs == (`CategoryTheory.Bicategory, #[B])
+ | throwError "Can not find the argument for the bicategory instance of the bicategory in which \
+ the equality is taking place."
+ let _ ← isDefEq inst (.const ``CategoryTheory.Cat.bicategory [v, u])
+ -- Construct the new expression
+ let value := mkAppN e args
+ let rec
+ /-- Recursive function which applies `mkLambdaFVars` stepwise
+ (so that each step can have different binderinfos) -/
+ apprec (i : Nat) (e : Expr) : MetaM Expr := do
+ if i < args.size then
+ let arg := args[i]!
+ let bi := binderInfos[i]!
+ let e' ← apprec (i + 1) e
+ unless arg != B && arg != inst do return e'
+ mkLambdaFVars #[arg] e' (binderInfoForMVars := bi)
+ else
+ return e
+ let value ← apprec 0 value
+ return value
+
+/--
+Given morphisms `f g : C ⟶ D` in the bicategory `Cat`, and an equation `η = θ` between 2-morphisms
+(possibly after a `∀` binder), produce the equation `∀ (X : C), f.app X = g.app X`, and simplify
+it using basic lemmas about `NatTrans.app`. -/
+def toAppExpr (e : Expr) : MetaM Expr := do
+ mapForallTelescope (fun e => do simpType catAppSimp (← mkAppM ``NatTrans.congr_app #[e])) e
+
+/--
+Adding `@[to_app]` to a lemma named `F` of shape `∀ .., η = θ`, where `η θ : f ⟶ g` are 2-morphisms
+in some bicategory, create a new lemma named `F_app`. This lemma is obtained by first specializing
+the bicategory in which the equality is taking place to `Cat`, then applying `NatTrans.congr_app`
+to obtain a proof of `∀ ... (X : Cat), η.app X = θ.app X`, and finally simplifying the conclusion
+using some basic lemmas in the bicategory `Cat`:
+`Cat.whiskerLeft_app`, `Cat.whiskerRight_app`, `Cat.id_app`, `Cat.comp_app` and `Cat.eqToHom_app`
+
+So, for example, if the conclusion of `F` is `f ◁ η = θ` then the conclusion of `F_app` will be
+`η.app (f.obj X) = θ.app X`.
+
+This is useful for automatically generating lemmas that can be applied to expressions of 1-morphisms
+in `Cat` which contain components of 2-morphisms.
+
+Note that if you want both the lemma and the new lemma to be `simp` lemmas, you should tag the lemma
+`@[to_app (attr := simp)]`. The variant `@[simp, to_app]` on a lemma `F` will tag `F` with
+`@[simp]`, but not `F_app` (this is sometimes useful).
+-/
+syntax (name := to_app) "to_app" (" (" &"attr" ":=" Parser.Term.attrInstance,* ")")? : attr
+
+initialize registerBuiltinAttribute {
+ name := `to_app
+ descr := ""
+ applicationTime := .afterCompilation
+ add := fun src ref kind => match ref with
+ | `(attr| to_app $[(attr := $stx?,*)]?) => MetaM.run' do
+ if (kind != AttributeKind.global) then
+ throwError "`to_app` can only be used as a global attribute"
+ addRelatedDecl src "_app" ref stx? fun type value levels => do
+ let levelMVars ← levels.mapM fun _ => mkFreshLevelMVar
+ let value ← mkExpectedTypeHint value type
+ let value := value.instantiateLevelParams levels levelMVars
+ let newValue ← toAppExpr (← toCatExpr value)
+ let r := (← getMCtx).levelMVarToParam (fun _ => false) (fun _ => false) newValue
+ let output := (r.expr, r.newParamNames.toList)
+ pure output
+ | _ => throwUnsupportedSyntax }
+
+open Term in
+/--
+Given an equation `t` of the form `η = θ` between 2-morphisms `f ⟶ g` with `f g : C ⟶ D` in the
+bicategory `Cat` (possibly after a `∀` binder), `to_app_of% t` produces the equation
+`∀ (X : C), η.app X = θ.app X` (where `X` is an object in the domain of `f` and `g`), and simplifies
+it suitably using basic lemmas about `NatTrans.app`.
+-/
+elab "to_app_of% " t:term : term => do
+ toAppExpr (← elabTerm t none)
+
+end CategoryTheory
diff --git a/Mathlib/Tactic/Common.lean b/Mathlib/Tactic/Common.lean
index eb2b980c73313..c864e4fc60f26 100644
--- a/Mathlib/Tactic/Common.lean
+++ b/Mathlib/Tactic/Common.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
-- First import Aesop and Qq
@@ -15,6 +15,9 @@ import ImportGraph.Imports
import Batteries.Tactic.Where
import Batteries.Tactic.Basic
+-- Import syntax for leansearch
+import LeanSearchClient
+
-- Import Mathlib-specific linters.
import Mathlib.Tactic.Linter.Lint
@@ -76,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/Constructor.lean b/Mathlib/Tactic/Constructor.lean
index 6ba7e4aee3325..64adccae545b7 100644
--- a/Mathlib/Tactic/Constructor.lean
+++ b/Mathlib/Tactic/Constructor.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Newell Jensen
+Authors: Kim Morrison, Newell Jensen
-/
import Mathlib.Init
import Lean.Elab.SyntheticMVars
diff --git a/Mathlib/Tactic/Convert.lean b/Mathlib/Tactic/Convert.lean
index aa2d570e1a2a9..c0dcc20b97221 100644
--- a/Mathlib/Tactic/Convert.lean
+++ b/Mathlib/Tactic/Convert.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Kyle Miller
+Authors: Kim Morrison, Kyle Miller
-/
import Mathlib.Tactic.CongrExclamation
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/FinCases.lean b/Mathlib/Tactic/FinCases.lean
index 493404b8844af..5a59db53e67bd 100644
--- a/Mathlib/Tactic/FinCases.lean
+++ b/Mathlib/Tactic/FinCases.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2022 Hanting Zhang. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Hanting Zhang
+Authors: Kim Morrison, Hanting Zhang
-/
import Mathlib.Tactic.Core
import Mathlib.Lean.Expr.Basic
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 5e20116dd53ac..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 :=
@@ -104,7 +103,6 @@ attribute [fun_prop]
Differentiable.mul
Differentiable.smul
Differentiable.div
- Differentiable.inv'
Differentiable.inv
DifferentiableAt.add
@@ -113,7 +111,6 @@ attribute [fun_prop]
DifferentiableAt.mul
DifferentiableAt.smul
DifferentiableAt.div
- DifferentiableAt.inv'
DifferentiableAt.inv
DifferentiableOn.add
@@ -122,7 +119,6 @@ attribute [fun_prop]
DifferentiableOn.mul
DifferentiableOn.smul
DifferentiableOn.div
- DifferentiableOn.inv'
DifferentiableOn.inv
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.lean b/Mathlib/Tactic/GCongr.lean
index dbee7afe65acd..ddb08c8e3e2dc 100644
--- a/Mathlib/Tactic/GCongr.lean
+++ b/Mathlib/Tactic/GCongr.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Heather Macbeth
-/
import Mathlib.Tactic.Positivity.Core
-import Mathlib.Tactic.GCongr.Core
+import Mathlib.Tactic.GCongr.CoreAttrs
/-! # Setup for the `gcongr` tactic
diff --git a/Mathlib/Tactic/GCongr/Core.lean b/Mathlib/Tactic/GCongr/Core.lean
index eeafb8d0cd02b..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
```
@@ -406,8 +407,13 @@ partial def _root_.Lean.MVarId.gcongr
-- by the `apply`.
for g in gs do
if !(← g.isAssigned) && !subgoals.contains g then
- try sideGoalDischarger g
- catch _ => out := out.push g
+ let s ← saveState
+ try
+ let (_, g') ← g.intros
+ sideGoalDischarger g'
+ catch _ =>
+ s.restore
+ out := out.push g
-- Return all unresolved subgoals, "main" or "side"
return (true, names, out ++ subgoals)
-- A. If there is no template, and there was no `@[gcongr]` lemma which matched the goal,
diff --git a/Mathlib/Tactic/GCongr/CoreAttrs.lean b/Mathlib/Tactic/GCongr/CoreAttrs.lean
new file mode 100644
index 0000000000000..423dbda223088
--- /dev/null
+++ b/Mathlib/Tactic/GCongr/CoreAttrs.lean
@@ -0,0 +1,16 @@
+/-
+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.Tactic.GCongr.Core
+
+/-!
+# gcongr attributes for lemmas up in the import chain
+
+In this file we add `gcongr` attribute to lemmas in `Lean.Init`.
+We may add lemmas from other files imported by `Mathlib/Tactic/GCongr/Core` later.
+-/
+
+attribute [gcongr] List.Sublist.append List.Sublist.append_left List.Sublist.append_right
+ List.Sublist.reverse List.drop_sublist_drop_left List.Sublist.drop Nat.succ_le_succ
diff --git a/Mathlib/Tactic/Generalize.lean b/Mathlib/Tactic/Generalize.lean
index bcd97b1c34af3..20250ad5f6e41 100644
--- a/Mathlib/Tactic/Generalize.lean
+++ b/Mathlib/Tactic/Generalize.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Lean.Elab.Binders
diff --git a/Mathlib/Tactic/GeneralizeProofs.lean b/Mathlib/Tactic/GeneralizeProofs.lean
index 7acd8bef29e3e..645637ae46a0f 100644
--- a/Mathlib/Tactic/GeneralizeProofs.lean
+++ b/Mathlib/Tactic/GeneralizeProofs.lean
@@ -341,7 +341,7 @@ This continuation `k` is passed
The `propToFVar` map is updated with the new proposition fvars.
-/
-partial def withGeneralizedProofs {α : Type} [Inhabited α] (e : Expr) (ty? : Option Expr)
+partial def withGeneralizedProofs {α : Type} [Nonempty α] (e : Expr) (ty? : Option Expr)
(k : Array Expr → Array Expr → Expr → MGen α) :
MGen α := do
let propToFVar := (← get).propToFVar
@@ -351,7 +351,7 @@ partial def withGeneralizedProofs {α : Type} [Inhabited α] (e : Expr) (ty? : O
post-abstracted{indentD e}\nnew generalizations: {generalizations}"
let rec
/-- Core loop for `withGeneralizedProofs`, adds generalizations one at a time. -/
- go [Inhabited α] (i : Nat) (fvars pfs : Array Expr)
+ go [Nonempty α] (i : Nat) (fvars pfs : Array Expr)
(proofToFVar propToFVar : ExprMap Expr) : MGen α := do
if h : i < generalizations.size then
let (ty, pf) := generalizations[i]
diff --git a/Mathlib/Tactic/Hint.lean b/Mathlib/Tactic/Hint.lean
index 6194f2cbaaabb..8df08cd79a07e 100644
--- a/Mathlib/Tactic/Hint.lean
+++ b/Mathlib/Tactic/Hint.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Lean.Meta.Tactic.TryThis
import Batteries.Linter.UnreachableTactic
diff --git a/Mathlib/Tactic/ITauto.lean b/Mathlib/Tactic/ITauto.lean
index 11fea885b2ddf..f0449d9828b14 100644
--- a/Mathlib/Tactic/ITauto.lean
+++ b/Mathlib/Tactic/ITauto.lean
@@ -3,13 +3,11 @@ Copyright (c) 2021 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
-import Batteries.Logic
import Batteries.Tactic.Exact
import Batteries.Tactic.Init
-import Mathlib.Tactic.Hint
+import Mathlib.Logic.Basic
import Mathlib.Tactic.DeriveToExpr
import Mathlib.Util.AtomM
-import Mathlib.Init.Logic
import Qq
/-!
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/IntervalCases.lean b/Mathlib/Tactic/IntervalCases.lean
index 621a718ffea2c..37e90dfc742f4 100644
--- a/Mathlib/Tactic/IntervalCases.lean
+++ b/Mathlib/Tactic/IntervalCases.lean
@@ -1,10 +1,11 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Mario Carneiro
+Authors: Kim Morrison, Mario Carneiro
-/
import Mathlib.Tactic.NormNum
import Mathlib.Tactic.FinCases
+import Mathlib.Control.Basic
/-!
# Case bash on variables in finite intervals
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/Linarith/Datatypes.lean b/Mathlib/Tactic/Linarith/Datatypes.lean
index d34b1f949f653..4b939583e90ec 100644
--- a/Mathlib/Tactic/Linarith/Datatypes.lean
+++ b/Mathlib/Tactic/Linarith/Datatypes.lean
@@ -6,7 +6,6 @@ Authors: Robert Y. Lewis
import Mathlib.Tactic.Linarith.Lemmas
import Mathlib.Tactic.Ring.Basic
import Mathlib.Util.SynthesizeUsing
-import Batteries.Data.HashMap.Basic
/-!
# Datatypes for `linarith`
@@ -312,7 +311,7 @@ structure CertificateOracle : Type where
`hyps` by eliminating all variables ≤ `max_var`.
If successful, it returns a map `coeff : Nat → Nat` as a certificate.
This map represents that we can find a contradiction by taking the sum `∑ (coeff i) * hyps[i]`. -/
- produceCertificate (hyps : List Comp) (max_var : Nat) : MetaM (Batteries.HashMap Nat Nat)
+ produceCertificate (hyps : List Comp) (max_var : Nat) : MetaM (Std.HashMap Nat Nat)
/-!
### Auxiliary functions
diff --git a/Mathlib/Tactic/Linarith/Frontend.lean b/Mathlib/Tactic/Linarith/Frontend.lean
index 2143364d3f3ea..f23bfb3fa0d6e 100644
--- a/Mathlib/Tactic/Linarith/Frontend.lean
+++ b/Mathlib/Tactic/Linarith/Frontend.lean
@@ -92,7 +92,7 @@ disequality hypotheses, since this would lead to a number of runs exponential in
disequalities in the context.
The oracle is very modular. It can easily be replaced with another function of type
-`List Comp → ℕ → MetaM ((Batteries.HashMap ℕ ℕ))`,
+`List Comp → ℕ → MetaM ((Std.HashMap ℕ ℕ))`,
which takes a list of comparisons and the largest variable
index appearing in those comparisons, and returns a map from comparison indices to coefficients.
An alternate oracle can be specified in the `LinarithConfig` object.
diff --git a/Mathlib/Tactic/Linarith/Oracle/FourierMotzkin.lean b/Mathlib/Tactic/Linarith/Oracle/FourierMotzkin.lean
index e65a8f3eba4cd..d1b3479c6c896 100644
--- a/Mathlib/Tactic/Linarith/Oracle/FourierMotzkin.lean
+++ b/Mathlib/Tactic/Linarith/Oracle/FourierMotzkin.lean
@@ -3,8 +3,9 @@ Copyright (c) 2020 Robert Y. Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Robert Y. Lewis
-/
+import Mathlib.Std.Data.HashMap
+import Batteries.Lean.HashMap
import Mathlib.Tactic.Linarith.Datatypes
-import Batteries.Data.HashMap.WF
/-!
# The Fourier-Motzkin elimination procedure
@@ -61,8 +62,8 @@ For example, suppose `cs` is produced by scaling assumption 2 by 5,
and adding to that the sum of assumptions 1 and 2.
`cs.flatten` maps `1 ↦ 1, 2 ↦ 6`.
-/
-def CompSource.flatten : CompSource → HashMap Nat Nat
- | (CompSource.assump n) => HashMap.empty.insert n 1
+def CompSource.flatten : CompSource → Std.HashMap Nat Nat
+ | (CompSource.assump n) => Std.HashMap.empty.insert n 1
| (CompSource.add c1 c2) =>
(CompSource.flatten c1).mergeWith (fun _ b b' => b + b') (CompSource.flatten c2)
| (CompSource.scale n c) => (CompSource.flatten c).mapVal (fun _ v => v * n)
@@ -258,7 +259,7 @@ The linarith monad extends an exceptional monad with a `LinarithData` state.
An exception produces a contradictory `PComp`.
-/
abbrev LinarithM : Type → Type :=
- StateT LinarithData (ExceptT PComp Id)
+ StateT LinarithData (ExceptT PComp Lean.Core.CoreM)
/-- Returns the current max variable. -/
def getMaxVar : LinarithM ℕ :=
@@ -272,7 +273,7 @@ def getPCompSet : LinarithM PCompSet :=
def validate : LinarithM Unit := do
match (← getPCompSet).toList.find? (fun p : PComp => p.isContr) with
| none => return ()
- | some c => throw c
+ | some c => throwThe _ c
/--
Updates the current state with a new max variable and comparisons,
@@ -304,9 +305,12 @@ from the `linarith` state.
-/
def elimVarM (a : ℕ) : LinarithM Unit := do
let vs ← getMaxVar
- if (a ≤ vs) then (do
+ if (a ≤ vs) then
+ Lean.Core.checkSystem decl_name%.toString
let ⟨pos, neg, notPresent⟩ := splitSetByVarSign a (← getPCompSet)
- update (vs - 1) (pos.foldl (fun s p => s.union (elimWithSet a p neg)) notPresent))
+ update (vs - 1) (← pos.foldlM (fun s p => do
+ Lean.Core.checkSystem decl_name%.toString
+ pure (s.union (elimWithSet a p neg))) notPresent)
else
pure ()
@@ -327,9 +331,12 @@ def mkLinarithData (hyps : List Comp) (maxVar : ℕ) : LinarithData :=
/-- An oracle that uses Fourier-Motzkin elimination. -/
def CertificateOracle.fourierMotzkin : CertificateOracle where
- produceCertificate hyps maxVar := match ExceptT.run
- (StateT.run (do validate; elimAllVarsM : LinarithM Unit) (mkLinarithData hyps maxVar)) with
- | (Except.ok _) => failure
- | (Except.error contr) => return contr.src.flatten
+ produceCertificate hyps maxVar := do
+ let linarithData := mkLinarithData hyps maxVar
+ let result ←
+ (ExceptT.run (StateT.run (do validate; elimAllVarsM : LinarithM Unit) linarithData) : _)
+ match result with
+ | (Except.ok _) => failure
+ | (Except.error contr) => return contr.src.flatten
end Linarith
diff --git a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm.lean b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm.lean
index e582844d49f0a..daeddd75376e8 100644
--- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm.lean
+++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm.lean
@@ -14,8 +14,6 @@ The algorithm's entry point is the function `Linarith.SimplexAlgorithm.findPosit
See the file `PositiveVector.lean` for details of how the procedure works.
-/
-open Batteries
-
namespace Linarith.SimplexAlgorithm
/-- Preprocess the goal to pass it to `Linarith.SimplexAlgorithm.findPositiveVector`. -/
@@ -30,11 +28,10 @@ def preprocess (matType : ℕ → ℕ → Type) [UsableInSimplexAlgorithm matTyp
/--
Extract the certificate from the `vec` found by `Linarith.SimplexAlgorithm.findPositiveVector`.
-/
-def postprocess (vec : Array ℚ) : HashMap ℕ ℕ :=
+def postprocess (vec : Array ℚ) : Std.HashMap ℕ ℕ :=
let common_den : ℕ := vec.foldl (fun acc item => acc.lcm item.den) 1
let vecNat : Array ℕ := vec.map (fun x : ℚ => (x * common_den).floor.toNat)
- HashMap.ofList <| vecNat.toList.enum.filter (fun ⟨_, item⟩ => item != 0)
-
+ Std.HashMap.empty.insertMany <| vecNat.toList.enum.filter (fun ⟨_, item⟩ => item != 0)
end SimplexAlgorithm
diff --git a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Gauss.lean b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Gauss.lean
index ab46c5726b44f..93cad0a43aa77 100644
--- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Gauss.lean
+++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Gauss.lean
@@ -15,7 +15,7 @@ solution which is done by standard Gaussian Elimination algorithm implemented in
namespace Linarith.SimplexAlgorithm.Gauss
/-- The monad for the Gaussian Elimination algorithm. -/
-abbrev GaussM (n m : Nat) (matType : Nat → Nat → Type) := StateM <| matType n m
+abbrev GaussM (n m : Nat) (matType : Nat → Nat → Type) := StateT (matType n m) Lean.CoreM
variable {n m : Nat} {matType : Nat → Nat → Type} [UsableInSimplexAlgorithm matType]
@@ -35,6 +35,7 @@ def getTableauImp : GaussM n m matType <| Tableau matType := do
let mut col : Nat := 0
while row < n && col < m do
+ Lean.Core.checkSystem decl_name%.toString
match ← findNonzeroRow row col with
| .none =>
free := free.push col
@@ -74,7 +75,7 @@ Given matrix `A`, solves the linear equation `A x = 0` and returns the solution
some variables are free and others (basic) variable are expressed as linear combinations of the free
ones.
-/
-def getTableau (A : matType n m) : Tableau matType := Id.run do
+def getTableau (A : matType n m) : Lean.CoreM (Tableau matType) := do
return (← getTableauImp.run A).fst
end Linarith.SimplexAlgorithm.Gauss
diff --git a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/PositiveVector.lean b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/PositiveVector.lean
index c93e2e33f9b24..97f8d6d475622 100644
--- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/PositiveVector.lean
+++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/PositiveVector.lean
@@ -90,10 +90,10 @@ def findPositiveVector {n m : Nat} {matType : Nat → Nat → Type} [UsableInSim
/- Using Gaussian elimination split variable into free and basic forming the tableau that will be
operated by the Simplex Algorithm. -/
- let initTableau := Gauss.getTableau B
+ let initTableau ← Gauss.getTableau B
/- Run the Simplex Algorithm and extract the solution. -/
- let res := runSimplexAlgorithm.run initTableau
+ let res ← runSimplexAlgorithm.run initTableau
if res.fst.isOk then
return extractSolution res.snd
else
diff --git a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/SimplexAlgorithm.lean b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/SimplexAlgorithm.lean
index 924814fa69fce..9858e94c23f14 100644
--- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/SimplexAlgorithm.lean
+++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/SimplexAlgorithm.lean
@@ -21,7 +21,7 @@ inductive SimplexAlgorithmException
/-- The monad for the Simplex Algorithm. -/
abbrev SimplexAlgorithmM (matType : Nat → Nat → Type) [UsableInSimplexAlgorithm matType] :=
- ExceptT SimplexAlgorithmException <| StateM (Tableau matType)
+ ExceptT SimplexAlgorithmException <| StateT (Tableau matType) Lean.CoreM
variable {matType : Nat → Nat → Type} [UsableInSimplexAlgorithm matType]
@@ -77,7 +77,7 @@ def chooseEnteringVar : SimplexAlgorithmM matType Nat := do
/- If there is no such variable the solution does not exist for sure. -/
match enterIdxOpt with
- | .none => throw SimplexAlgorithmException.infeasible
+ | .none => throwThe SimplexAlgorithmException SimplexAlgorithmException.infeasible
| .some enterIdx => return enterIdx
/--
@@ -116,6 +116,7 @@ such exists.
-/
def runSimplexAlgorithm : SimplexAlgorithmM matType Unit := do
while !(← checkSuccess) do
+ Lean.Core.checkSystem decl_name%.toString
let ⟨exitIdx, enterIdx⟩ ← choosePivots
doPivotOperation exitIdx enterIdx
diff --git a/Mathlib/Tactic/Linarith/Verification.lean b/Mathlib/Tactic/Linarith/Verification.lean
index 2439b1d8def02..b8702e24fc4f5 100644
--- a/Mathlib/Tactic/Linarith/Verification.lean
+++ b/Mathlib/Tactic/Linarith/Verification.lean
@@ -191,6 +191,7 @@ def proveFalseByLinarith (transparency : TransparencyMode) (oracle : Certificate
| _, [] => throwError "no args to linarith"
| g, l@(h::_) => do
trace[linarith.detail] "Beginning work in `proveFalseByLinarith`."
+ Lean.Core.checkSystem decl_name%.toString
-- for the elimination to work properly, we must add a proof of `-1 < 0` to the list,
-- along with negated equality proofs.
let l' ← addNegEqProofs l
@@ -202,7 +203,7 @@ def proveFalseByLinarith (transparency : TransparencyMode) (oracle : Certificate
trace[linarith.detail] "... finished `linearFormsAndMaxVar`."
trace[linarith.detail] "{comps}"
-- perform the elimination and fail if no contradiction is found.
- let certificate : Batteries.HashMap Nat Nat ← try
+ let certificate : Std.HashMap Nat Nat ← try
oracle.produceCertificate comps max_var
catch e =>
trace[linarith] e.toMessageData
@@ -210,7 +211,7 @@ def proveFalseByLinarith (transparency : TransparencyMode) (oracle : Certificate
trace[linarith] "linarith has found a contradiction: {certificate.toList}"
let enum_inputs := inputs.enum
-- construct a list pairing nonzero coeffs with the proof of their corresponding comparison
- let zip := enum_inputs.filterMap fun ⟨n, e⟩ => (certificate.find? n).map (e, ·)
+ let zip := enum_inputs.filterMap fun ⟨n, e⟩ => (certificate[n]?).map (e, ·)
let mls ← zip.mapM fun ⟨e, n⟩ => do mulExpr n (← leftOfIneqProof e)
-- `sm` is the sum of input terms, scaled to cancel out all variables.
let sm ← addExprs mls
diff --git a/Mathlib/Tactic/LinearCombination'.lean b/Mathlib/Tactic/LinearCombination'.lean
index e42ba57d7608c..c7965a7998ee9 100644
--- a/Mathlib/Tactic/LinearCombination'.lean
+++ b/Mathlib/Tactic/LinearCombination'.lean
@@ -174,12 +174,17 @@ syntax expStx := atomic(" (" &"exp" " := ") withoutPosition(num) ")"
of a list of equalities and subtracting it from the target.
The tactic will create a linear
combination by adding the equalities together from left to right, so the order
- of the input hypotheses does matter. If the `normalize` field of the
- configuration is set to false, then the tactic will simply set the user up to
+ of the input hypotheses does matter. If the `norm` field of the
+ tactic is set to `skip`, then the tactic will simply set the user up to
prove their target using the linear combination instead of normalizing the subtraction.
Note: There is also a similar tactic `linear_combination` (no prime); this version is
-provided for backward compatibility.
+provided for backward compatibility. Compared to this tactic, `linear_combination`:
+* drops the `←` syntax for reversing an equation, instead offering this operation using the `-`
+ syntax
+* does not support multiplication of two hypotheses (`h1 * h2`), division by a hypothesis (`3 / h`),
+ or inversion of a hypothesis (`h⁻¹`)
+* produces noisy output when the user adds or subtracts a constant to a hypothesis (`h + 3`)
Note: The left and right sides of all the equalities should have the same
type, and the coefficients should also have this type. There must be
diff --git a/Mathlib/Tactic/LinearCombination.lean b/Mathlib/Tactic/LinearCombination.lean
index a0942a5645645..ae81750d27b27 100644
--- a/Mathlib/Tactic/LinearCombination.lean
+++ b/Mathlib/Tactic/LinearCombination.lean
@@ -3,6 +3,7 @@ Copyright (c) 2022 Abby J. Goldberg. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Abby J. Goldberg, Mario Carneiro
-/
+import Mathlib.Tactic.LinearCombination.Lemmas
import Mathlib.Tactic.Ring
/-!
@@ -33,21 +34,6 @@ namespace Mathlib.Tactic.LinearCombination
open Lean hiding Rat
open Elab Meta Term
-variable {α : Type*} {a a' a₁ a₂ b b' b₁ b₂ c : α}
-
-theorem pf_add_c [Add α] (p : a = b) (c : α) : a + c = b + c := p ▸ rfl
-theorem c_add_pf [Add α] (p : b = c) (a : α) : a + b = a + c := p ▸ rfl
-theorem add_pf [Add α] (p₁ : (a₁:α) = b₁) (p₂ : a₂ = b₂) : a₁ + a₂ = b₁ + b₂ := p₁ ▸ p₂ ▸ rfl
-theorem pf_sub_c [Sub α] (p : a = b) (c : α) : a - c = b - c := p ▸ rfl
-theorem c_sub_pf [Sub α] (p : b = c) (a : α) : a - b = a - c := p ▸ rfl
-theorem pf_mul_c [Mul α] (p : a = b) (c : α) : a * c = b * c := p ▸ rfl
-theorem c_mul_pf [Mul α] (p : b = c) (a : α) : a * b = a * c := p ▸ rfl
-theorem mul_pf [Mul α] (p₁ : (a₁:α) = b₁) (p₂ : a₂ = b₂) : a₁ * a₂ = b₁ * b₂ := p₁ ▸ p₂ ▸ rfl
-theorem inv_pf [Inv α] (p : (a:α) = b) : a⁻¹ = b⁻¹ := p ▸ rfl
-theorem pf_div_c [Div α] (p : a = b) (c : α) : a / c = b / c := p ▸ rfl
-theorem c_div_pf [Div α] (p : b = c) (a : α) : a / b = a / c := p ▸ rfl
-theorem div_pf [Div α] (p₁ : (a₁:α) = b₁) (p₂ : a₂ = b₂) : a₁ / a₂ = b₁ / b₂ := p₁ ▸ p₂ ▸ rfl
-
/-- Result of `expandLinearCombo`, either an equality proof or a value. -/
inductive Expanded
/-- A proof of `a = b`. -/
@@ -69,35 +55,40 @@ partial def expandLinearCombo (ty : Expr) (stx : Syntax.Term) : TermElabM Expand
| `($e₁ + $e₂) => do
match ← expandLinearCombo ty e₁, ← expandLinearCombo ty e₂ with
| .const c₁, .const c₂ => .const <$> ``($c₁ + $c₂)
- | .proof p₁, .const c₂ => .proof <$> ``(pf_add_c $p₁ $c₂)
- | .const c₁, .proof p₂ => .proof <$> ``(c_add_pf $p₂ $c₁)
| .proof p₁, .proof p₂ => .proof <$> ``(add_pf $p₁ $p₂)
+ | .proof p, .const c | .const c, .proof p =>
+ logWarningAt c "this constant has no effect on the linear combination; it can be dropped \
+ from the term"
+ pure (.proof p)
| `($e₁ - $e₂) => do
match ← expandLinearCombo ty e₁, ← expandLinearCombo ty e₂ with
| .const c₁, .const c₂ => .const <$> ``($c₁ - $c₂)
- | .proof p₁, .const c₂ => .proof <$> ``(pf_sub_c $p₁ $c₂)
- | .const c₁, .proof p₂ => .proof <$> ``(c_sub_pf $p₂ $c₁)
+ | .proof p, .const c =>
+ logWarningAt c "this constant has no effect on the linear combination; it can be dropped \
+ from the term"
+ pure (.proof p)
+ | .const c, .proof p =>
+ logWarningAt c "this constant has no effect on the linear combination; it can be dropped \
+ from the term"
+ .proof <$> ``(Eq.symm $p)
| .proof p₁, .proof p₂ => .proof <$> ``(add_pf $p₁ (Eq.symm $p₂))
| `(-$e) => do
match ← expandLinearCombo ty e with
| .const c => .const <$> `(-$c)
| .proof p => .proof <$> ``(Eq.symm $p)
- | `($e₁ * $e₂) => do
+ | `($e₁ *%$tk $e₂) => do
match ← expandLinearCombo ty e₁, ← expandLinearCombo ty e₂ with
| .const c₁, .const c₂ => .const <$> ``($c₁ * $c₂)
| .proof p₁, .const c₂ => .proof <$> ``(pf_mul_c $p₁ $c₂)
| .const c₁, .proof p₂ => .proof <$> ``(c_mul_pf $p₂ $c₁)
- | .proof p₁, .proof p₂ => .proof <$> ``(mul_pf $p₁ $p₂)
- | `($e⁻¹) => do
- match ← expandLinearCombo ty e with
- | .const c => .const <$> `($c⁻¹)
- | .proof p => .proof <$> ``(inv_pf $p)
- | `($e₁ / $e₂) => do
+ | .proof _, .proof _ =>
+ throwErrorAt tk "'linear_combination' supports only linear operations"
+ | `($e₁ /%$tk $e₂) => do
match ← expandLinearCombo ty e₁, ← expandLinearCombo ty e₂ with
| .const c₁, .const c₂ => .const <$> ``($c₁ / $c₂)
| .proof p₁, .const c₂ => .proof <$> ``(pf_div_c $p₁ $c₂)
- | .const c₁, .proof p₂ => .proof <$> ``(c_div_pf $p₂ $c₁)
- | .proof p₁, .proof p₂ => .proof <$> ``(div_pf $p₁ $p₂)
+ | _, .proof _ =>
+ throwErrorAt tk "'linear_combination' supports only linear operations"
| e =>
-- We have the expected type from the goal, so we can fully synthesize this leaf node.
withSynthesize do
@@ -109,17 +100,6 @@ partial def expandLinearCombo (ty : Expr) (stx : Syntax.Term) : TermElabM Expand
else
.const <$> c.toSyntax
-theorem eq_of_sub [AddGroup α] (p : (a:α) = b) (H : (a' - b') - (a - b) = 0) : a' = b' := by
- rw [← sub_eq_zero] at p ⊢; rwa [sub_eq_zero, p] at H
-
-theorem eq_of_add [Add α] [IsRightCancelAdd α] (p : (a:α) = b) (H : a' + b = b' + a) : a' = b' := by
- rw [p] at H
- exact add_right_cancel H
-
-theorem eq_of_add_pow [Ring α] [NoZeroDivisors α] (n : ℕ) (p : (a:α) = b)
- (H : (a' - b')^n - (a - b) = 0) : a' = b' := by
- rw [← sub_eq_zero] at p ⊢; apply pow_eq_zero (n := n); rwa [sub_eq_zero, p] at H
-
/-- Implementation of `linear_combination`. -/
def elabLinearCombination (tk : Syntax)
(norm? : Option Syntax.Tactic) (exp? : Option Syntax.NumLit) (input : Option Syntax.Term) :
@@ -130,7 +110,10 @@ def elabLinearCombination (tk : Syntax)
| none => `(Eq.refl 0)
| some e =>
match ← expandLinearCombo ty e with
- | .const _ => throwError "To run 'linear_combination' without hypotheses, call it without input"
+ | .const c =>
+ logWarningAt c "this constant has no effect on the linear combination; it can be dropped \
+ from the term"
+ `(Eq.refl 0)
| .proof p => pure p
let norm := norm?.getD (Unhygienic.run <| withRef tk `(tactic| ring1))
let lem : Ident ← mkIdent <$> do
@@ -169,8 +152,8 @@ syntax expStx := atomic(" (" &"exp" " := ") withoutPosition(num) ")"
of a list of equalities and subtracting it from the target.
The tactic will create a linear
combination by adding the equalities together from left to right, so the order
- of the input hypotheses does matter. If the `normalize` field of the
- configuration is set to false, then the tactic will simply set the user up to
+ of the input hypotheses does matter. If the `norm` field of the
+ tactic is set to `skip`, then the tactic will simply set the user up to
prove their target using the linear combination instead of normalizing the subtraction.
Note: The left and right sides of all the equalities should have the same type `α`, and the
diff --git a/Mathlib/Tactic/LinearCombination/Lemmas.lean b/Mathlib/Tactic/LinearCombination/Lemmas.lean
new file mode 100644
index 0000000000000..912fa19ffe828
--- /dev/null
+++ b/Mathlib/Tactic/LinearCombination/Lemmas.lean
@@ -0,0 +1,36 @@
+/-
+Copyright (c) 2022 Abby J. Goldberg. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Abby J. Goldberg, Mario Carneiro
+-/
+import Mathlib.Algebra.GroupWithZero.Basic
+import Mathlib.Algebra.Ring.Defs
+
+/-!
+# Lemmas for the linear_combination tactic
+
+These should not be used directly in user code.
+-/
+
+namespace Mathlib.Tactic.LinearCombination
+open Lean
+
+variable {α : Type*} {a a' a₁ a₂ b b' b₁ b₂ c : α}
+
+theorem add_pf [Add α] (p₁ : (a₁:α) = b₁) (p₂ : a₂ = b₂) : a₁ + a₂ = b₁ + b₂ := p₁ ▸ p₂ ▸ rfl
+theorem pf_mul_c [Mul α] (p : a = b) (c : α) : a * c = b * c := p ▸ rfl
+theorem c_mul_pf [Mul α] (p : b = c) (a : α) : a * b = a * c := p ▸ rfl
+theorem pf_div_c [Div α] (p : a = b) (c : α) : a / c = b / c := p ▸ rfl
+
+theorem eq_of_sub [AddGroup α] (p : (a:α) = b) (H : (a' - b') - (a - b) = 0) : a' = b' := by
+ rw [← sub_eq_zero] at p ⊢; rwa [sub_eq_zero, p] at H
+
+theorem eq_of_add [Add α] [IsRightCancelAdd α] (p : (a:α) = b) (H : a' + b = b' + a) : a' = b' := by
+ rw [p] at H
+ exact add_right_cancel H
+
+theorem eq_of_add_pow [Ring α] [NoZeroDivisors α] (n : ℕ) (p : (a:α) = b)
+ (H : (a' - b')^n - (a - b) = 0) : a' = b' := by
+ rw [← sub_eq_zero] at p ⊢; apply pow_eq_zero (n := n); rwa [sub_eq_zero, p] at H
+
+end Mathlib.Tactic.LinearCombination
diff --git a/Mathlib/Tactic/Linter.lean b/Mathlib/Tactic/Linter.lean
index e40a62f821d5a..2f67da1bea192 100644
--- a/Mathlib/Tactic/Linter.lean
+++ b/Mathlib/Tactic/Linter.lean
@@ -11,4 +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.TextBased
+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/DocPrime.lean b/Mathlib/Tactic/Linter/DocPrime.lean
new file mode 100644
index 0000000000000..79a08666bae3f
--- /dev/null
+++ b/Mathlib/Tactic/Linter/DocPrime.lean
@@ -0,0 +1,75 @@
+/-
+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 "docPrime" linter
+
+The "docPrime" linter emits a warning on declarations that have no doc-string and whose
+name ends with a `'`. Such declarations are expected to have a documented explanation
+for the presence of a `'` in their name. This may consist of discussion of the difference relative
+to an unprimed version of that declaration, or an explanation as to why no better naming scheme
+is possible.
+-/
+
+open Lean Elab
+
+namespace Mathlib.Linter
+
+/--
+The "docPrime" linter emits a warning on declarations that have no doc-string and whose
+name ends with a `'`.
+
+The file `scripts/no_lints_prime_decls.txt` contains a list of temporary exceptions to this linter.
+This list should not be appended to, and become emptied over time.
+-/
+register_option linter.docPrime : Bool := {
+ defValue := false
+ descr := "enable the docPrime linter"
+}
+
+namespace DocPrime
+
+@[inherit_doc Mathlib.Linter.linter.docPrime]
+def docPrimeLinter : Linter where run := withSetOptionIn fun stx ↦ do
+ unless Linter.getLinterValue linter.docPrime (← getOptions) do
+ return
+ if (← get).messages.hasErrors then
+ return
+ unless [``Lean.Parser.Command.declaration, `lemma].contains stx.getKind do return
+ -- ignore private declarations
+ if (stx.find? (·.isOfKind ``Lean.Parser.Command.private)).isSome then return
+ let docstring := stx[0][0]
+ -- The current declaration's id, possibly followed by a list of universe names.
+ let declId :=
+ if stx[1].isOfKind ``Lean.Parser.Command.instance then
+ stx[1][3][0]
+ else
+ stx[1][1]
+ -- The name of the current declaration, with namespaces resolved.
+ let declName :=
+ if let `_root_ :: rest := declId[0].getId.components then
+ rest.foldl (· ++ ·) default
+ else (← getCurrNamespace) ++ declId[0].getId
+ let msg := m!"`{declName}` is missing a doc-string, please add one.\n\
+ Declarations whose name ends with a `'` are expected to contain an explanation for the \
+ presence of a `'` in their doc-string. This may consist of discussion of the difference \
+ relative to the unprimed version, or an explanation as to why no better naming scheme \
+ is possible."
+ if docstring[0][1].getAtomVal.isEmpty && declName.toString.back == '\'' then
+ if ← System.FilePath.pathExists "scripts/no_lints_prime_decls.txt" then
+ if (← IO.FS.lines "scripts/no_lints_prime_decls.txt").contains declName.toString then
+ return
+ else
+ Linter.logLint linter.docPrime declId msg
+ else
+ Linter.logLint linter.docPrime declId msg
+
+initialize addLinter docPrimeLinter
+
+end DocPrime
+
+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 7bf25054c4a86..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
@@ -13,7 +14,7 @@ In this file we define additional linters for mathlib.
Perhaps these should be moved to Batteries in the future.
-/
-namespace Std.Tactic.Lint
+namespace Batteries.Tactic.Lint
open Lean Meta
/--
@@ -45,7 +46,7 @@ Linter that checks whether a structure should be in Prop.
| some _ => return none -- TODO: enforce `YYYY-MM-DD` format
| none => return m!"`deprecated` attribute without `since` date"
-end Std.Tactic.Lint
+end Batteries.Tactic.Lint
namespace Mathlib.Linter
@@ -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.
-/
@@ -320,6 +312,12 @@ register_option linter.style.longFile : Nat := {
descr := "enable the longFile linter"
}
+/-- The number of lines that the `longFile` linter considers the default. -/
+register_option linter.style.longFileDefValue : Nat := {
+ defValue := 1500
+ descr := "a soft upper bound on the number of lines of each file"
+}
+
namespace Style.longFile
@[inherit_doc Mathlib.Linter.linter.style.longFile]
@@ -327,7 +325,7 @@ def longFileLinter : Linter where run := withSetOptionIn fun stx ↦ do
let linterBound := linter.style.longFile.get (← getOptions)
if linterBound == 0 then
return
- let defValue := 1500
+ let defValue := linter.style.longFileDefValue.get (← getOptions)
let smallOption := match stx with
| `(set_option linter.style.longFile $x) => TSyntax.getNat ⟨x.raw⟩ ≤ defValue
| _ => false
@@ -348,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\
@@ -359,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
@@ -406,9 +416,13 @@ def longLineLinter : Linter where run := withSetOptionIn fun stx ↦ do
(100 < (fm.toPosition line.stopPos).column)
for line in longLines 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 \
+ line, removing all intervening whitespace."
+ else ""
Linter.logLint linter.style.longLine (.ofRange ⟨line.startPos, line.stopPos⟩)
- m!"This line exceeds the 100 character limit, please shorten it!"
-
+ m!"This line exceeds the 100 character limit, please shorten it!{stringMsg}"
initialize addLinter longLineLinter
end Style.longLine
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 dbe70677fbc6b..81ddc7216b380 100644
--- a/Mathlib/Tactic/Linter/TextBased.lean
+++ b/Mathlib/Tactic/Linter/TextBased.lean
@@ -6,6 +6,7 @@ Authors: Michael Rothgang
import Batteries.Data.String.Matcher
import Mathlib.Data.Nat.Notation
+import Std.Data.HashMap.Basic
/-!
## Text-based linters
@@ -64,6 +65,7 @@ inductive StyleError where
| broadImport (module : BroadImports)
/-- A line ends with windows line endings (\r\n) instead of unix ones (\n). -/
| windowsLineEnding
+ | duplicateImport (importStatement: String) (alreadyImportedLine: ℕ)
deriving BEq
/-- How to format style errors -/
@@ -94,6 +96,8 @@ def StyleError.errorMessage (err : StyleError) : String := match err with
benchmark it. If this is fine, feel free to allow this linter."
| windowsLineEnding => "This line ends with a windows line ending (\r\n): please use Unix line\
endings (\n) instead"
+ | StyleError.duplicateImport (importStatement) (alreadyImportedLine) =>
+ s!"Duplicate imports: {importStatement} (already imported on line {alreadyImportedLine})"
/-- The error code for a given style error. Keep this in sync with `parse?_errorContext` below! -/
-- FUTURE: we're matching the old codes in `lint-style.py` for compatibility;
@@ -104,6 +108,7 @@ def StyleError.errorCode (err : StyleError) : String := match err with
| StyleError.adaptationNote => "ERR_ADN"
| StyleError.broadImport _ => "ERR_IMP"
| StyleError.windowsLineEnding => "ERR_WIN"
+ | StyleError.duplicateImport _ _ => "ERR_DIMP"
/-- Context for a style error: the actual error, the line number in the file we're reading
and the path to the file. -/
@@ -142,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
@@ -190,6 +197,7 @@ def parse?_errorContext (line : String) : Option ErrorContext := Id.run do
| "ERR_AUT" => some (StyleError.authors)
| "ERR_ADN" => some (StyleError.adaptationNote)
| "ERR_WIN" => some (StyleError.windowsLineEnding)
+ | "ERR_DIMP" => some (StyleError.duplicateImport "" 0)
| "ERR_IMP" =>
-- XXX tweak exceptions messages to ease parsing?
if (errorMessage.get! 0).containsSubstr "tactic" then
@@ -285,6 +293,26 @@ def adaptationNoteLinter : TextbasedLinter := fun lines ↦ Id.run do
lineNumber := lineNumber + 1
return (errors, none)
+/-- Lint on a collection of input strings if one of the is a duplicate import statement. -/
+def duplicateImportsLinter : TextbasedLinter := fun lines ↦ Id.run do
+ let mut lineNumber := 1
+ let mut errors := Array.mkEmpty 0
+ let mut importStatements : Std.HashMap String ℕ := {}
+ for line in lines do
+ if line.startsWith "import " then
+ let lineWithoutComment := (line.splitOn "--")[0]!
+ let importStatement := lineWithoutComment.trim
+ if importStatements.contains importStatement then
+ let alreadyImportedLine := importStatements[importStatement]!
+ errors := errors.push (
+ (StyleError.duplicateImport importStatement alreadyImportedLine),
+ lineNumber
+ )
+ else
+ importStatements := importStatements.insert importStatement lineNumber
+ lineNumber := lineNumber + 1
+ return (errors, none)
+
/-- Lint a collection of input strings if one of them contains an unnecessarily broad import. -/
def broadImportsLinter : TextbasedLinter := fun lines ↦ Id.run do
let mut errors := Array.mkEmpty 0
@@ -325,7 +353,7 @@ end
/-- All text-based linters registered in this file. -/
def allLinters : Array TextbasedLinter := #[
- copyrightHeaderLinter, adaptationNoteLinter, broadImportsLinter
+ copyrightHeaderLinter, adaptationNoteLinter, broadImportsLinter, duplicateImportsLinter
]
@@ -398,13 +426,17 @@ def lintModules (moduleNames : Array String) (style : ErrorFormat) (fix : Bool)
-- If this poses an issue, I can either filter the output
-- or wait until lint-style.py is fully rewritten in Lean.
let args := if fix then #["--fix"] else #[]
- let pythonOutput ← IO.Process.run { cmd := "./scripts/print-style-errors.sh", args := args }
- if pythonOutput != "" then
+ let output ← IO.Process.output { cmd := "./scripts/print-style-errors.sh", args := args }
+ if output.exitCode != 0 then
+ numberErrorFiles := numberErrorFiles + 1
+ IO.eprintln s!"error: `print-style-error.sh` exited with code {output.exitCode}"
+ IO.eprint output.stderr
+ else if output.stdout != "" then
numberErrorFiles := numberErrorFiles + 1
- IO.print pythonOutput
+ IO.eprint output.stdout
formatErrors allUnexpectedErrors style
if allUnexpectedErrors.size > 0 then
- IO.println s!"error: found {allUnexpectedErrors.size} new style error(s)"
+ IO.eprintln s!"error: found {allUnexpectedErrors.size} new style error(s)"
return numberErrorFiles
end Mathlib.Linter.TextBased
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/ModCases.lean b/Mathlib/Tactic/ModCases.lean
index 9846cca299457..fd1a5afdd358f 100644
--- a/Mathlib/Tactic/ModCases.lean
+++ b/Mathlib/Tactic/ModCases.lean
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Heather Macbeth
-/
import Mathlib.Data.Int.ModEq
+import Mathlib.Tactic.HaveI
/-! # `mod_cases` tactic
diff --git a/Mathlib/Tactic/Module.lean b/Mathlib/Tactic/Module.lean
new file mode 100644
index 0000000000000..fd9b22fd82518
--- /dev/null
+++ b/Mathlib/Tactic/Module.lean
@@ -0,0 +1,657 @@
+/-
+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.Algebra.Tower
+import Mathlib.Algebra.BigOperators.GroupWithZero.Action
+import Mathlib.Tactic.Ring
+import Mathlib.Util.AtomM
+
+/-! # A tactic for normalization over modules
+
+This file provides the two tactics `match_scalars` and `module`. Given a goal which is an equality
+in a type `M` (with `M` an `AddCommMonoid`), the `match_scalars` tactic parses the LHS and RHS of
+the goal as linear combinations of `M`-atoms over some semiring `R`, and reduces the goal to
+the respective equalities of the `R`-coefficients of each atom. The `module` tactic does this and
+then runs the `ring` tactic on each of these coefficient-wise equalities, failing if this does not
+resolve them.
+
+The scalar type `R` is not pre-determined: instead it starts as `ℕ` (when each atom is initially
+given a scalar `(1:ℕ)`) and gets bumped up into bigger semirings when such semirings are
+encountered. However, to permit this, it is assumed that there is a "linear order" on all the
+semirings which appear in the expression: for any two semirings `R` and `S` which occur, we have
+either `Algebra R S` or `Algebra S R`).
+-/
+
+open Lean hiding Module
+open Meta Elab Qq Mathlib.Tactic List
+
+namespace Mathlib.Tactic.Module
+
+/-! ### Theory of lists of pairs (scalar, vector)
+
+This section contains the lemmas which are orchestrated by the `match_scalars` and `module` tactics
+to prove goals in modules. The basic object which these lemmas concern is `NF R M`, a type synonym
+for a list of ordered pairs in `R × M`, where typically `M` is an `R`-module.
+-/
+
+/-- Basic theoretical "normal form" object of the `match_scalars` and `module` tactics: a type
+synonym for a list of ordered pairs in `R × M`, where typically `M` is an `R`-module. This is the
+form to which the tactics reduce module expressions.
+
+(It is not a full "normal form" because the scalars, i.e. `R` components, are not themselves
+ring-normalized. But this partial normal form is more convenient for our purposes.) -/
+def NF (R : Type*) (M : Type*) := List (R × M)
+
+namespace NF
+variable {S : Type*} {R : Type*} {M : Type*}
+
+/-- Augment a `Module.NF R M` object `l`, i.e. a list of pairs in `R × M`, by prepending another
+pair `p : R × M`. -/
+@[match_pattern]
+def cons (p : R × M) (l : NF R M) : NF R M := p :: l
+
+@[inherit_doc cons] infixl:100 " ::ᵣ " => cons
+
+/-- Evaluate a `Module.NF R M` object `l`, i.e. a list of pairs in `R × M`, to an element of `M`, by
+forming the "linear combination" it specifies: scalar-multiply each `R` term to the corresponding
+`M` term, then add them all up. -/
+def eval [Add M] [Zero M] [SMul R M] (l : NF R M) : M := (l.map (fun (⟨r, x⟩ : R × M) ↦ r • x)).sum
+
+@[simp] theorem eval_cons [AddMonoid M] [SMul R M] (p : R × M) (l : NF R M) :
+ (p ::ᵣ l).eval = p.1 • p.2 + l.eval := by
+ unfold eval cons
+ rw [List.map_cons]
+ rw [List.sum_cons]
+
+theorem atom_eq_eval [AddMonoid M] (x : M) : x = NF.eval [(1, x)] := by simp [eval]
+
+variable (M) in
+theorem zero_eq_eval [AddMonoid M] : (0:M) = NF.eval (R := ℕ) (M := M) [] := rfl
+
+theorem add_eq_eval₁ [AddMonoid M] [SMul R M] (a₁ : R × M) {a₂ : R × M} {l₁ l₂ l : NF R M}
+ (h : l₁.eval + (a₂ ::ᵣ l₂).eval = l.eval) :
+ (a₁ ::ᵣ l₁).eval + (a₂ ::ᵣ l₂).eval = (a₁ ::ᵣ l).eval := by
+ simp only [eval_cons, ← h, add_assoc]
+
+theorem add_eq_eval₂ [Semiring R] [AddCommMonoid M] [Module R M] (r₁ r₂ : R) (x : M)
+ {l₁ l₂ l : NF R M} (h : l₁.eval + l₂.eval = l.eval) :
+ ((r₁, x) ::ᵣ l₁).eval + ((r₂, x) ::ᵣ l₂).eval = ((r₁ + r₂, x) ::ᵣ l).eval := by
+ simp only [← h, eval_cons, add_smul, add_assoc]
+ congr! 1
+ simp only [← add_assoc]
+ congr! 1
+ rw [add_comm]
+
+theorem add_eq_eval₃ [Semiring R] [AddCommMonoid M] [Module R M] {a₁ : R × M} (a₂ : R × M)
+ {l₁ l₂ l : NF R M} (h : (a₁ ::ᵣ l₁).eval + l₂.eval = l.eval) :
+ (a₁ ::ᵣ l₁).eval + (a₂ ::ᵣ l₂).eval = (a₂ ::ᵣ l).eval := by
+ simp only [eval_cons, ← h]
+ nth_rw 4 [add_comm]
+ simp only [add_assoc]
+ congr! 2
+ rw [add_comm]
+
+theorem add_eq_eval {R₁ R₂ : Type*} [AddCommMonoid M] [Semiring R] [Module R M] [Semiring R₁]
+ [Module R₁ M] [Semiring R₂] [Module R₂ M] {l₁ l₂ l : NF R M} {l₁' : NF R₁ M} {l₂' : NF R₂ M}
+ {x₁ x₂ : M} (hx₁ : x₁ = l₁'.eval) (hx₂ : x₂ = l₂'.eval) (h₁ : l₁.eval = l₁'.eval)
+ (h₂ : l₂.eval = l₂'.eval) (h : l₁.eval + l₂.eval = l.eval) :
+ x₁ + x₂ = l.eval := by
+ rw [hx₁, hx₂, ← h₁, ← h₂, h]
+
+theorem sub_eq_eval₁ [SMul R M] [AddGroup M] (a₁ : R × M) {a₂ : R × M} {l₁ l₂ l : NF R M}
+ (h : l₁.eval - (a₂ ::ᵣ l₂).eval = l.eval) :
+ (a₁ ::ᵣ l₁).eval - (a₂ ::ᵣ l₂).eval = (a₁ ::ᵣ l).eval := by
+ simp only [eval_cons, ← h, sub_eq_add_neg, add_assoc]
+
+theorem sub_eq_eval₂ [Ring R] [AddCommGroup M] [Module R M] (r₁ r₂ : R) (x : M) {l₁ l₂ l : NF R M}
+ (h : l₁.eval - l₂.eval = l.eval) :
+ ((r₁, x) ::ᵣ l₁).eval - ((r₂, x) ::ᵣ l₂).eval = ((r₁ - r₂, x) ::ᵣ l).eval := by
+ simp only [← h, eval_cons, sub_smul, sub_eq_add_neg, neg_add, add_smul, neg_smul, add_assoc]
+ congr! 1
+ simp only [← add_assoc]
+ congr! 1
+ rw [add_comm]
+
+theorem sub_eq_eval₃ [Ring R] [AddCommGroup M] [Module R M] {a₁ : R × M} (a₂ : R × M)
+ {l₁ l₂ l : NF R M} (h : (a₁ ::ᵣ l₁).eval - l₂.eval = l.eval) :
+ (a₁ ::ᵣ l₁).eval - (a₂ ::ᵣ l₂).eval = ((-a₂.1, a₂.2) ::ᵣ l).eval := by
+ simp only [eval_cons, neg_smul, neg_add, sub_eq_add_neg, ← h, ← add_assoc]
+ congr! 1
+ rw [add_comm, add_assoc]
+
+theorem sub_eq_eval {R₁ R₂ S₁ S₂ : Type*} [AddCommGroup M] [Ring R] [Module R M] [Semiring R₁]
+ [Module R₁ M] [Semiring R₂] [Module R₂ M] [Semiring S₁] [Module S₁ M] [Semiring S₂]
+ [Module S₂ M] {l₁ l₂ l : NF R M} {l₁' : NF R₁ M} {l₂' : NF R₂ M} {l₁'' : NF S₁ M}
+ {l₂'' : NF S₂ M} {x₁ x₂ : M} (hx₁ : x₁ = l₁''.eval) (hx₂ : x₂ = l₂''.eval)
+ (h₁' : l₁'.eval = l₁''.eval) (h₂' : l₂'.eval = l₂''.eval) (h₁ : l₁.eval = l₁'.eval)
+ (h₂ : l₂.eval = l₂'.eval) (h : l₁.eval - l₂.eval = l.eval) :
+ x₁ - x₂ = l.eval := by
+ rw [hx₁, hx₂, ← h₁', ← h₂', ← h₁, ← h₂, h]
+
+instance [Neg R] : Neg (NF R M) where
+ neg l := l.map fun (a, x) ↦ (-a, x)
+
+theorem eval_neg [AddCommGroup M] [Ring R] [Module R M] (l : NF R M) : (-l).eval = - l.eval := by
+ simp only [NF.eval, List.map_map, List.sum_neg, NF.instNeg]
+ congr
+ ext p
+ simp
+
+theorem zero_sub_eq_eval [AddCommGroup M] [Ring R] [Module R M] (l : NF R M) :
+ 0 - l.eval = (-l).eval := by
+ simp [eval_neg]
+
+theorem neg_eq_eval [AddCommGroup M] [Semiring S] [Module S M] [Ring R] [Module R M] {l : NF R M}
+ {l₀ : NF S M} (hl : l.eval = l₀.eval) {x : M} (h : x = l₀.eval) :
+ - x = (-l).eval := by
+ rw [h, ← hl, eval_neg]
+
+instance [Mul R] : SMul R (NF R M) where
+ smul r l := l.map fun (a, x) ↦ (r * a, x)
+
+@[simp] theorem smul_apply [Mul R] (r : R) (l : NF R M) : r • l = l.map fun (a, x) ↦ (r * a, x) :=
+ rfl
+
+theorem eval_smul [AddCommMonoid M] [Semiring R] [Module R M] {l : NF R M} {x : M} (h : x = l.eval)
+ (r : R) : (r • l).eval = r • x := by
+ unfold NF.eval at h ⊢
+ simp only [h, smul_sum, map_map, NF.smul_apply]
+ congr
+ ext p
+ simp [mul_smul]
+
+theorem smul_eq_eval {R₀ : Type*} [AddCommMonoid M] [Semiring R] [Module R M] [Semiring R₀]
+ [Module R₀ M] [Semiring S] [Module S M] {l : NF R M} {l₀ : NF R₀ M} {s : S} {r : R}
+ {x : M} (hx : x = l₀.eval) (hl : l.eval = l₀.eval) (hs : r • x = s • x) :
+ s • x = (r • l).eval := by
+ rw [← hs, hx, ← hl, eval_smul]
+ rfl
+
+theorem eq_cons_cons [AddMonoid M] [SMul R M] {r₁ r₂ : R} (m : M) {l₁ l₂ : NF R M} (h1 : r₁ = r₂)
+ (h2 : l₁.eval = l₂.eval) :
+ ((r₁, m) ::ᵣ l₁).eval = ((r₂, m) ::ᵣ l₂).eval := by
+ simp only [NF.eval, NF.cons] at *
+ simp [h1, h2]
+
+theorem eq_cons_const [AddCommMonoid M] [Semiring R] [Module R M] {r : R} (m : M) {n : M}
+ {l : NF R M} (h1 : r = 0) (h2 : l.eval = n) :
+ ((r, m) ::ᵣ l).eval = n := by
+ simp only [NF.eval, NF.cons] at *
+ simp [h1, h2]
+
+theorem eq_const_cons [AddCommMonoid M] [Semiring R] [Module R M] {r : R} (m : M) {n : M}
+ {l : NF R M} (h1 : 0 = r) (h2 : n = l.eval) :
+ n = ((r, m) ::ᵣ l).eval := by
+ simp only [NF.eval, NF.cons] at *
+ simp [← h1, h2]
+
+theorem eq_of_eval_eq_eval {R₁ R₂ : Type*} [AddCommMonoid M] [Semiring R] [Module R M] [Semiring R₁]
+ [Module R₁ M] [Semiring R₂] [Module R₂ M] {l₁ l₂ : NF R M} {l₁' : NF R₁ M} {l₂' : NF R₂ M}
+ {x₁ x₂ : M} (hx₁ : x₁ = l₁'.eval) (hx₂ : x₂ = l₂'.eval) (h₁ : l₁.eval = l₁'.eval)
+ (h₂ : l₂.eval = l₂'.eval) (h : l₁.eval = l₂.eval) :
+ x₁ = x₂ := by
+ rw [hx₁, hx₂, ← h₁, ← h₂, h]
+
+variable (R)
+
+/-- Operate on a `Module.NF S M` object `l`, i.e. a list of pairs in `S × M`, where `S` is some
+commutative semiring, by applying to each `S`-component the algebra-map from `S` into a specified
+`S`-algebra `R`. -/
+def algebraMap [CommSemiring S] [Semiring R] [Algebra S R] (l : NF S M) : NF R M :=
+ l.map (fun ⟨s, x⟩ ↦ (_root_.algebraMap S R s, x))
+
+theorem eval_algebraMap [CommSemiring S] [Semiring R] [Algebra S R] [AddMonoid M] [SMul S M]
+ [MulAction R M] [IsScalarTower S R M] (l : NF S M) :
+ (l.algebraMap R).eval = l.eval := by
+ simp only [NF.eval, algebraMap, map_map]
+ congr
+ ext
+ simp [IsScalarTower.algebraMap_smul]
+
+end NF
+
+variable {u v : Level}
+
+/-! ### Lists of expressions representing scalars and vectors, and operations on such lists -/
+
+/-- Basic meta-code "normal form" object of the `match_scalars` and `module` tactics: a type synonym
+for a list of ordered triples comprising expressions representing terms of two types `R` and `M`
+(where typically `M` is an `R`-module), together with a natural number "index".
+
+The natural number represents the index of the `M` term in the `AtomM` monad: this is not enforced,
+but is sometimes assumed in operations. Thus when items `((a₁, x₁), k)` and `((a₂, x₂), k)`
+appear in two different `Module.qNF` objects (i.e. with the same `ℕ`-index `k`), it is expected that
+the expressions `x₁` and `x₂` are the same. It is also expected that the items in a `Module.qNF`
+list are in strictly increasing order by natural-number index.
+
+By forgetting the natural number indices, an expression representing a `Mathlib.Tactic.Module.NF`
+object can be built from a `Module.qNF` object; this construction is provided as
+`Mathlib.Tactic.Module.qNF.toNF`. -/
+abbrev qNF (R : Q(Type u)) (M : Q(Type v)) := List ((Q($R) × Q($M)) × ℕ)
+
+namespace qNF
+
+variable {M : Q(Type v)} {R : Q(Type u)}
+
+/-- Given `l` of type `qNF R M`, i.e. a list of `(Q($R) × Q($M)) × ℕ`s (two `Expr`s and a natural
+number), build an `Expr` representing an object of type `NF R M` (i.e. `List (R × M)`) in the
+in the obvious way: by forgetting the natural numbers and gluing together the `Expr`s. -/
+def toNF (l : qNF R M) : Q(NF $R $M) :=
+ let l' : List Q($R × $M) := (l.map Prod.fst).map (fun (a, x) ↦ q(($a, $x)))
+ let qt : List Q($R × $M) → Q(List ($R × $M)) := List.rec q([]) (fun e _ l ↦ q($e ::ᵣ $l))
+ qt l'
+
+/-- Given `l` of type `qNF R₁ M`, i.e. a list of `(Q($R₁) × Q($M)) × ℕ`s (two `Expr`s and a natural
+number), apply an expression representing a function with domain `R₁` to each of the `Q($R₁)`
+components. -/
+def onScalar {u₁ u₂ : Level} {R₁ : Q(Type u₁)} {R₂ : Q(Type u₂)} (l : qNF R₁ M) (f : Q($R₁ → $R₂)) :
+ qNF R₂ M :=
+ l.map fun ((a, x), k) ↦ ((q($f $a), x), k)
+
+/-- Given two terms `l₁`, `l₂` of type `qNF R M`, i.e. lists of `(Q($R) × Q($M)) × ℕ`s (two `Expr`s
+and a natural number), construct another such term `l`, which will have the property that in the
+`$R`-module `$M`, the sum of the "linear combinations" represented by `l₁` and `l₂` is the linear
+combination represented by `l`.
+
+The construction assumes, to be valid, that the lists `l₁` and `l₂` are in strictly increasing order
+by `ℕ`-component, and that if pairs `(a₁, x₁)` and `(a₂, x₂)` appear in `l₁`, `l₂` respectively with
+the same `ℕ`-component `k`, then the expressions `x₁` and `x₂` are equal.
+
+The construction is as follows: merge the two lists, except that if pairs `(a₁, x₁)` and `(a₂, x₂)`
+appear in `l₁`, `l₂` respectively with the same `ℕ`-component `k`, then contribute a term
+`(a₁ + a₂, x₁)` to the output list with `ℕ`-component `k`. -/
+def add (iR : Q(Semiring $R)) : qNF R M → qNF R M → qNF R M
+ | [], l => l
+ | l, [] => l
+ | ((a₁, x₁), k₁) ::ᵣ t₁, ((a₂, x₂), k₂) ::ᵣ t₂ =>
+ if k₁ < k₂ then
+ ((a₁, x₁), k₁) ::ᵣ add iR t₁ (((a₂, x₂), k₂) ::ᵣ t₂)
+ else if k₁ = k₂ then
+ ((q($a₁ + $a₂), x₁), k₁) ::ᵣ add iR t₁ t₂
+ else
+ ((a₂, x₂), k₂) ::ᵣ add iR (((a₁, x₁), k₁) ::ᵣ t₁) t₂
+
+/-- Given two terms `l₁`, `l₂` of type `qNF R M`, i.e. lists of `(Q($R) × Q($M)) × ℕ`s (two `Expr`s
+and a natural number), recursively construct a proof that in the `$R`-module `$M`, the sum of the
+"linear combinations" represented by `l₁` and `l₂` is the linear combination represented by
+`Module.qNF.add iR l₁ l₁`.-/
+def mkAddProof {iR : Q(Semiring $R)} {iM : Q(AddCommMonoid $M)} (iRM : Q(Module $R $M))
+ (l₁ l₂ : qNF R M) :
+ Q(NF.eval $(l₁.toNF) + NF.eval $(l₂.toNF) = NF.eval $((qNF.add iR l₁ l₂).toNF)) :=
+ match l₁, l₂ with
+ | [], l => (q(zero_add (NF.eval $(l.toNF))):)
+ | l, [] => (q(add_zero (NF.eval $(l.toNF))):)
+ | ((a₁, x₁), k₁) ::ᵣ t₁, ((a₂, x₂), k₂) ::ᵣ t₂ =>
+ if k₁ < k₂ then
+ let pf := mkAddProof iRM t₁ (((a₂, x₂), k₂) ::ᵣ t₂)
+ (q(NF.add_eq_eval₁ ($a₁, $x₁) $pf):)
+ else if k₁ = k₂ then
+ let pf := mkAddProof iRM t₁ t₂
+ (q(NF.add_eq_eval₂ $a₁ $a₂ $x₁ $pf):)
+ else
+ let pf := mkAddProof iRM (((a₁, x₁), k₁) ::ᵣ t₁) t₂
+ (q(NF.add_eq_eval₃ ($a₂, $x₂) $pf):)
+
+/-- Given two terms `l₁`, `l₂` of type `qNF R M`, i.e. lists of `(Q($R) × Q($M)) × ℕ`s (two `Expr`s
+and a natural number), construct another such term `l`, which will have the property that in the
+`$R`-module `$M`, the difference of the "linear combinations" represented by `l₁` and `l₂` is the
+linear combination represented by `l`.
+
+The construction assumes, to be valid, that the lists `l₁` and `l₂` are in strictly increasing order
+by `ℕ`-component, and that if pairs `(a₁, x₁)` and `(a₂, x₂)` appear in `l₁`, `l₂` respectively with
+the same `ℕ`-component `k`, then the expressions `x₁` and `x₂` are equal.
+
+The construction is as follows: merge the first list and the negation of the second list, except
+that if pairs `(a₁, x₁)` and `(a₂, x₂)` appear in `l₁`, `l₂` respectively with the same
+`ℕ`-component `k`, then contribute a term `(a₁ - a₂, x₁)` to the output list with `ℕ`-component `k`.
+-/
+def sub (iR : Q(Ring $R)) : qNF R M → qNF R M → qNF R M
+ | [], l => l.onScalar q(Neg.neg)
+ | l, [] => l
+ | ((a₁, x₁), k₁) ::ᵣ t₁, ((a₂, x₂), k₂) ::ᵣ t₂ =>
+ if k₁ < k₂ then
+ ((a₁, x₁), k₁) ::ᵣ sub iR t₁ (((a₂, x₂), k₂) ::ᵣ t₂)
+ else if k₁ = k₂ then
+ ((q($a₁ - $a₂), x₁), k₁) ::ᵣ sub iR t₁ t₂
+ else
+ ((q(-$a₂), x₂), k₂) ::ᵣ sub iR (((a₁, x₁), k₁) ::ᵣ t₁) t₂
+
+/-- Given two terms `l₁`, `l₂` of type `qNF R M`, i.e. lists of `(Q($R) × Q($M)) × ℕ`s (two `Expr`s
+and a natural number), recursively construct a proof that in the `$R`-module `$M`, the difference
+of the "linear combinations" represented by `l₁` and `l₂` is the linear combination represented by
+`Module.qNF.sub iR l₁ l₁`.-/
+def mkSubProof (iR : Q(Ring $R)) (iM : Q(AddCommGroup $M)) (iRM : Q(Module $R $M))
+ (l₁ l₂ : qNF R M) :
+ Q(NF.eval $(l₁.toNF) - NF.eval $(l₂.toNF) = NF.eval $((qNF.sub iR l₁ l₂).toNF)) :=
+ match l₁, l₂ with
+ | [], l => (q(NF.zero_sub_eq_eval $(l.toNF)):)
+ | l, [] => (q(sub_zero (NF.eval $(l.toNF))):)
+ | ((a₁, x₁), k₁) ::ᵣ t₁, ((a₂, x₂), k₂) ::ᵣ t₂ =>
+ if k₁ < k₂ then
+ let pf := mkSubProof iR iM iRM t₁ (((a₂, x₂), k₂) ::ᵣ t₂)
+ (q(NF.sub_eq_eval₁ ($a₁, $x₁) $pf):)
+ else if k₁ = k₂ then
+ let pf := mkSubProof iR iM iRM t₁ t₂
+ (q(NF.sub_eq_eval₂ $a₁ $a₂ $x₁ $pf):)
+ else
+ let pf := mkSubProof iR iM iRM (((a₁, x₁), k₁) ::ᵣ t₁) t₂
+ (q(NF.sub_eq_eval₃ ($a₂, $x₂) $pf):)
+
+variable {iM : Q(AddCommMonoid $M)}
+ {u₁ : Level} {R₁ : Q(Type u₁)} {iR₁ : Q(Semiring $R₁)} (iRM₁ : Q(@Module $R₁ $M $iR₁ $iM))
+ {u₂ : Level} {R₂ : Q(Type u₂)} (iR₂ : Q(Semiring $R₂)) (iRM₂ : Q(@Module $R₂ $M $iR₂ $iM))
+
+/-- Given an expression `M` representing a type which is an `AddCommMonoid` and a module over *two*
+semirings `R₁` and `R₂`, find the "bigger" of the two semirings. That is, we assume that it will
+turn out to be the case that either (1) `R₁` is an `R₂`-algebra and the `R₂` scalar action on `M` is
+induced from `R₁`'s scalar action on `M`, or (2) vice versa; we return the semiring `R₁` in the
+first case and `R₂` in the second case.
+
+Moreover, given expressions representing particular scalar multiplications of `R₁` and/or `R₂` on
+`M` (a `List (R₁ × M)`, a `List (R₂ × M)`, a pair `(r, x) : R₂ × M`), bump these up to the "big"
+ring by applying the algebra-map where needed. -/
+def matchRings (l₁ : qNF R₁ M) (l₂ : qNF R₂ M) (r : Q($R₂)) (x : Q($M)) :
+ MetaM <| Σ u : Level, Σ R : Q(Type u), Σ iR : Q(Semiring $R), Σ _ : Q(@Module $R $M $iR $iM),
+ (Σ l₁' : qNF R M, Q(NF.eval $(l₁'.toNF) = NF.eval $(l₁.toNF)))
+ × (Σ l₂' : qNF R M, Q(NF.eval $(l₂'.toNF) = NF.eval $(l₂.toNF)))
+ × (Σ r' : Q($R), Q($r' • $x = $r • $x)) := do
+ if ← withReducible <| isDefEq R₁ R₂ then
+ -- the case when `R₁ = R₂` is handled separately, so as not to require commutativity of that ring
+ pure ⟨u₁, R₁, iR₁, iRM₁, ⟨l₁, q(rfl)⟩, ⟨l₂, (q(@rfl _ (NF.eval $(l₂.toNF))):)⟩,
+ r, (q(@rfl _ ($r • $x)):)⟩
+ -- otherwise the "smaller" of the two rings must be commutative
+ else try
+ -- first try to exhibit `R₂` as an `R₁`-algebra
+ let _i₁ ← synthInstanceQ q(CommSemiring $R₁)
+ let _i₃ ← synthInstanceQ q(Algebra $R₁ $R₂)
+ let _i₄ ← synthInstanceQ q(IsScalarTower $R₁ $R₂ $M)
+ assumeInstancesCommute
+ let l₁' : qNF R₂ M := l₁.onScalar q(algebraMap $R₁ $R₂)
+ pure ⟨u₂, R₂, iR₂, iRM₂, ⟨l₁', (q(NF.eval_algebraMap $R₂ $(l₁.toNF)):)⟩, ⟨l₂, q(rfl)⟩,
+ r, q(rfl)⟩
+ catch _ => try
+ -- then if that fails, try to exhibit `R₁` as an `R₂`-algebra
+ let _i₁ ← synthInstanceQ q(CommSemiring $R₂)
+ let _i₃ ← synthInstanceQ q(Algebra $R₂ $R₁)
+ let _i₄ ← synthInstanceQ q(IsScalarTower $R₂ $R₁ $M)
+ assumeInstancesCommute
+ let l₂' : qNF R₁ M := l₂.onScalar q(algebraMap $R₂ $R₁)
+ let r' : Q($R₁) := q(algebraMap $R₂ $R₁ $r)
+ pure ⟨u₁, R₁, iR₁, iRM₁, ⟨l₁, q(rfl)⟩, ⟨l₂', (q(NF.eval_algebraMap $R₁ $(l₂.toNF)):)⟩,
+ r', (q(IsScalarTower.algebraMap_smul $R₁ $r $x):)⟩
+ catch _ =>
+ throwError "match_scalars failed: {R₁} is not an {R₂}-algebra and {R₂} is not an {R₁}-algebra"
+
+end qNF
+
+/-! ### Core of the `module` tactic -/
+
+variable {M : Q(Type v)}
+
+/-- The main algorithm behind the `match_scalars` and `module` tactics: partially-normalizing an
+expression in an additive commutative monoid `M` into the form c1 • x1 + c2 • x2 + ... c_k • x_k,
+where x1, x2, ... are distinct atoms in `M`, and c1, c2, ... are scalars. The scalar type of the
+expression is not pre-determined: instead it starts as `ℕ` (when each atom is initially given a
+scalar `(1:ℕ)`) and gets bumped up into bigger semirings when such semirings are encountered.
+
+It is assumed that there is a "linear order" on all the semirings which appear in the expression:
+for any two semirings `R` and `S` which occur, we have either `Algebra R S` or `Algebra S R`).
+
+TODO: implement a variant in which a semiring `R` is provided by the user, and the assumption is
+instead that for any semiring `S` which occurs, we have `Algebra S R`. The PR #16984 provides a
+proof-of-concept implementation of this variant, but it would need some polishing before joining
+Mathlib.
+
+Possible TODO, if poor performance on large problems is witnessed: switch the implementation from
+`AtomM` to `CanonM`, per the discussion
+https://github.com/leanprover-community/mathlib4/pull/16593/files#r1749623191 -/
+partial def parse (iM : Q(AddCommMonoid $M)) (x : Q($M)) :
+ AtomM (Σ u : Level, Σ R : Q(Type u), Σ iR : Q(Semiring $R), Σ _ : Q(@Module $R $M $iR $iM),
+ Σ l : qNF R M, Q($x = NF.eval $(l.toNF))) := do
+ match x with
+ /- parse an addition: `x₁ + x₂` -/
+ | ~q($x₁ + $x₂) =>
+ let ⟨_, _, _, iRM₁, l₁', pf₁'⟩ ← parse iM x₁
+ let ⟨_, _, _, iRM₂, l₂', pf₂'⟩ ← parse iM x₂
+ -- lift from the semirings of scalars parsed from `x₁`, `x₂` (say `R₁`, `R₂`) to `R₁ ⊗ R₂`
+ let ⟨u, R, iR, iRM, ⟨l₁, pf₁⟩, ⟨l₂, pf₂⟩, _⟩ ← qNF.matchRings iRM₁ _ iRM₂ l₁' l₂' q(0) q(0)
+ -- build the new list and proof
+ let pf := qNF.mkAddProof iRM l₁ l₂
+ pure ⟨u, R, iR, iRM, qNF.add iR l₁ l₂, (q(NF.add_eq_eval $pf₁' $pf₂' $pf₁ $pf₂ $pf):)⟩
+ /- parse a subtraction: `x₁ - x₂` -/
+ | ~q(@HSub.hSub _ _ _ (@instHSub _ $iM') $x₁ $x₂) =>
+ let ⟨_, _, _, iRM₁, l₁'', pf₁''⟩ ← parse iM x₁
+ let ⟨_, _, _, iRM₂, l₂'', pf₂''⟩ ← parse iM x₂
+ -- lift from the semirings of scalars parsed from `x₁`, `x₂` (say `R₁`, `R₂`) to `R₁ ⊗ R₂ ⊗ ℤ`
+ let iZ := q(Int.instSemiring)
+ let iMZ ← synthInstanceQ q(Module ℤ $M)
+ let ⟨_, _, _, iRM₁', ⟨l₁', pf₁'⟩, _, _⟩ ← qNF.matchRings iRM₁ iZ iMZ l₁'' [] q(0) q(0)
+ let ⟨_, _, _, iRM₂', ⟨l₂', pf₂'⟩, _, _⟩ ← qNF.matchRings iRM₂ iZ iMZ l₂'' [] q(0) q(0)
+ let ⟨u, R, iR, iRM, ⟨l₁, pf₁⟩, ⟨l₂, pf₂⟩, _⟩ ← qNF.matchRings iRM₁' _ iRM₂' l₁' l₂' q(0) q(0)
+ let iR' ← synthInstanceQ q(Ring $R)
+ let iM' ← synthInstanceQ q(AddCommGroup $M)
+ assumeInstancesCommute
+ -- build the new list and proof
+ let pf := qNF.mkSubProof iR' iM' iRM l₁ l₂
+ pure ⟨u, R, iR, iRM, qNF.sub iR' l₁ l₂,
+ q(NF.sub_eq_eval $pf₁'' $pf₂'' $pf₁' $pf₂' $pf₁ $pf₂ $pf)⟩
+ /- parse a negation: `-y` -/
+ | ~q(@Neg.neg _ $iM' $y) =>
+ let ⟨u₀, _, _, iRM₀, l₀, pf₀⟩ ← parse iM y
+ -- lift from original semiring of scalars (say `R₀`) to `R₀ ⊗ ℤ`
+ let _i ← synthInstanceQ q(AddCommGroup $M)
+ let iZ := q(Int.instSemiring)
+ let iMZ ← synthInstanceQ q(Module ℤ $M)
+ let ⟨u, R, iR, iRM, ⟨l, pf⟩, _, _⟩ ← qNF.matchRings iRM₀ iZ iMZ l₀ [] q(0) q(0)
+ let _i' ← synthInstanceQ q(Ring $R)
+ assumeInstancesCommute
+ -- build the new list and proof
+ pure ⟨u, R, iR, iRM, l.onScalar q(Neg.neg), (q(NF.neg_eq_eval $pf $pf₀):)⟩
+ /- parse a scalar multiplication: `(s₀ : S) • y` -/
+ | ~q(@HSMul.hSMul _ _ _ (@instHSMul $S _ $iS) $s₀ $y) =>
+ let ⟨_, _, _, iRM₀, l₀, pf₀⟩ ← parse iM y
+ let i₁ ← synthInstanceQ q(Semiring $S)
+ let i₂ ← synthInstanceQ q(Module $S $M)
+ assumeInstancesCommute
+ -- lift from original semiring of scalars (say `R₀`) to `R₀ ⊗ S`
+ let ⟨u, R, iR, iRM, ⟨l, pf_l⟩, _, ⟨s, pf_r⟩⟩ ← qNF.matchRings iRM₀ i₁ i₂ l₀ [] s₀ y
+ -- build the new list and proof
+ pure ⟨u, R, iR, iRM, l.onScalar q(HMul.hMul $s), (q(NF.smul_eq_eval $pf₀ $pf_l $pf_r):)⟩
+ /- parse a `(0:M)` -/
+ | ~q(0) =>
+ pure ⟨0, q(Nat), q(Nat.instSemiring), q(AddCommGroup.toNatModule), [], q(NF.zero_eq_eval $M)⟩
+ /- anything else should be treated as an atom -/
+ | _ =>
+ let k : ℕ ← AtomM.addAtom x
+ pure ⟨0, q(Nat), q(Nat.instSemiring), q(AddCommGroup.toNatModule), [((q(1), x), k)],
+ q(NF.atom_eq_eval $x)⟩
+
+/-- Given expressions `R` and `M` representing types such that `M`'s is a module over `R`'s, and
+given two terms `l₁`, `l₂` of type `qNF R M`, i.e. lists of `(Q($R) × Q($M)) × ℕ`s (two `Expr`s
+and a natural number), construct a list of new goals: that the `R`-coefficient of an `M`-atom which
+appears in only one list is zero, and that the `R`-coefficients of an `M`-atom which appears in both
+lists are equal. Also construct (dependent on these new goals) a proof that the "linear
+combinations" represented by `l₁` and `l₂` are equal in `M`. -/
+partial def reduceCoefficientwise {R : Q(Type u)} {_ : Q(AddCommMonoid $M)} {_ : Q(Semiring $R)}
+ (iRM : Q(Module $R $M)) (l₁ l₂ : qNF R M) :
+ MetaM (List MVarId × Q(NF.eval $(l₁.toNF) = NF.eval $(l₂.toNF))) := do
+ match l₁, l₂ with
+ /- if both empty, return a `rfl` proof that `(0:M) = 0` -/
+ | [], [] =>
+ 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 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
+ pure (mvar.mvarId! :: mvars, (q(NF.eq_const_cons $x $mvar $pf):))
+ | ((a, x), _) ::ᵣ L, [] =>
+ let mvar : Q($a = (0:$R)) ← mkFreshExprMVar q($a = (0:$R))
+ let (mvars, pf) ← reduceCoefficientwise iRM L []
+ pure (mvar.mvarId! :: mvars, (q(NF.eq_cons_const $x $mvar $pf):))
+ /- if both lists are nonempty, then deal with the numerically-smallest term in either list,
+ forming a goal that it is equal to zero (if it appears in only one list) or that its
+ coefficients in the two lists are the same (if it appears in both lists); then recurse -/
+ | ((a₁, x₁), k₁) ::ᵣ L₁, ((a₂, x₂), k₂) ::ᵣ L₂ =>
+ if k₁ < k₂ then
+ let mvar : Q($a₁ = (0:$R)) ← mkFreshExprMVar q($a₁ = (0:$R))
+ let (mvars, pf) ← reduceCoefficientwise iRM L₁ l₂
+ pure (mvar.mvarId! :: mvars, (q(NF.eq_cons_const $x₁ $mvar $pf):))
+ else if k₁ = k₂ then
+ let mvar : Q($a₁ = $a₂) ← mkFreshExprMVar q($a₁ = $a₂)
+ let (mvars, pf) ← reduceCoefficientwise iRM L₁ L₂
+ pure (mvar.mvarId! :: mvars, (q(NF.eq_cons_cons $x₁ $mvar $pf):))
+ else
+ let mvar : Q((0:$R) = $a₂) ← mkFreshExprMVar q((0:$R) = $a₂)
+ let (mvars, pf) ← reduceCoefficientwise iRM l₁ L₂
+ pure (mvar.mvarId! :: mvars, (q(NF.eq_const_cons $x₂ $mvar $pf):))
+
+/-- Given a goal which is an equality in a type `M` (with `M` an `AddCommMonoid`), parse the LHS and
+RHS of the goal as linear combinations of `M`-atoms over some semiring `R`, and reduce the goal to
+the respective equalities of the `R`-coefficients of each atom.
+
+This is an auxiliary function which produces slightly awkward goals in `R`; they are later cleaned
+up by the function `Mathlib.Tactic.Module.postprocess`. -/
+def matchScalarsAux (g : MVarId) : AtomM (List MVarId) := do
+ /- Parse the goal as an equality in a type `M` of two expressions `lhs` and `rhs`, with `M`
+ carrying an `AddCommMonoid` instance. -/
+ let eqData ← do
+ match (← g.getType').eq? with
+ | some e => pure e
+ | none => throwError "goal {← g.getType} is not an equality"
+ let .sort v₀ ← whnf (← inferType eqData.1) | unreachable!
+ let some v := v₀.dec | unreachable!
+ let ((M : Q(Type v)), (lhs : Q($M)), (rhs :Q($M))) := eqData
+ let iM ← synthInstanceQ q(AddCommMonoid.{v} $M)
+ /- Construct from the `lhs` expression a term `l₁` of type `qNF R₁ M` for some semiring `R₁` --
+ that is, a list of `(Q($R₁) × Q($M)) × ℕ`s (two `Expr`s and a natural number) -- together with a
+ proof that `lhs` is equal to the `R₁`-linear combination in `M` this represents. -/
+ let e₁ ← parse iM lhs
+ have u₁ : Level := e₁.fst
+ have R₁ : Q(Type u₁) := e₁.snd.fst
+ have _iR₁ : Q(Semiring.{u₁} $R₁) := e₁.snd.snd.fst
+ let iRM₁ ← synthInstanceQ q(Module $R₁ $M)
+ assumeInstancesCommute
+ have l₁ : qNF R₁ M := e₁.snd.snd.snd.snd.fst
+ let pf₁ : Q($lhs = NF.eval $(l₁.toNF)) := e₁.snd.snd.snd.snd.snd
+ /- Do the same for the `rhs` expression, obtaining a term `l₂` of type `qNF R₂ M` for some
+ semiring `R₂`. -/
+ let e₂ ← parse iM rhs
+ have u₂ : Level := e₂.fst
+ have R₂ : Q(Type u₂) := e₂.snd.fst
+ have _iR₂ : Q(Semiring.{u₂} $R₂) := e₂.snd.snd.fst
+ let iRM₂ ← synthInstanceQ q(Module $R₂ $M)
+ have l₂ : qNF R₂ M := e₂.snd.snd.snd.snd.fst
+ let pf₂ : Q($rhs = NF.eval $(l₂.toNF)) := e₂.snd.snd.snd.snd.snd
+ /- Lift everything to the same scalar ring, `R`. -/
+ let ⟨_, _, _, iRM, ⟨l₁', pf₁'⟩, ⟨l₂', pf₂'⟩, _⟩ ← qNF.matchRings iRM₁ _ iRM₂ l₁ l₂ q(0) q(0)
+ /- Construct a list of goals for the coefficientwise equality of these formal linear combinations,
+ and resolve our original goal (modulo these new goals). -/
+ let (mvars, pf) ← reduceCoefficientwise iRM l₁' l₂'
+ g.assign q(NF.eq_of_eval_eq_eval $pf₁ $pf₂ $pf₁' $pf₂' $pf)
+ return mvars
+
+/-- Lemmas used to post-process the result of the `match_scalars` and `module` tactics by converting
+the `algebraMap` operations which (which proliferate in the constructed scalar goals) to more
+familiar forms: `ℕ`, `ℤ` and `ℚ` casts. -/
+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 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
+ -- augment this list with the `algebraMapThms` lemmas, which handle `algebraMap` operations
+ for thm in algebraMapThms do
+ let ⟨levelParams, _, proof⟩ ← abstractMVars (mkConst thm)
+ thms ← thms.add (.stx (← mkFreshId) Syntax.missing) levelParams proof
+ -- now run `simp` with these lemmas, and (importantly) *no* simprocs
+ let ctx : Simp.Context := {
+ config := { failIfUnchanged := false }
+ simpTheorems := #[thms]
+ }
+ let (some r, _) ← simpTarget mvarId ctx (simprocs := #[]) |
+ throwError "internal error in match_scalars tactic: postprocessing should not close goals"
+ return r
+
+/-- Given a goal which is an equality in a type `M` (with `M` an `AddCommMonoid`), parse the LHS and
+RHS of the goal as linear combinations of `M`-atoms over some semiring `R`, and reduce the goal to
+the respective equalities of the `R`-coefficients of each atom. -/
+def matchScalars (g : MVarId) : MetaM (List MVarId) := do
+ let mvars ← AtomM.run .instances (matchScalarsAux g)
+ mvars.mapM postprocess
+
+/-- Given a goal which is an equality in a type `M` (with `M` an `AddCommMonoid`), parse the LHS and
+RHS of the goal as linear combinations of `M`-atoms over some semiring `R`, and reduce the goal to
+the respective equalities of the `R`-coefficients of each atom.
+
+For example, this produces the goal `⊢ a * 1 + b * 1 = (b + a) * 1`:
+```
+example [AddCommMonoid M] [Semiring R] [Module R M] (a b : R) (x : M) :
+ a • x + b • x = (b + a) • x := by
+ match_scalars
+```
+This produces the two goals `⊢ a * (a * 1) + b * (b * 1) = 1` (from the `x` atom) and
+`⊢ a * -(b * 1) + b * (a * 1) = 0` (from the `y` atom):
+```
+example [AddCommGroup M] [Ring R] [Module R M] (a b : R) (x : M) :
+ a • (a • x - b • y) + (b • a • y + b • b • x) = x := by
+ match_scalars
+```
+This produces the goal `⊢ -2 * (a * 1) = a * (-2 * 1)`:
+```
+example [AddCommGroup M] [Ring R] [Module R M] (a : R) (x : M) :
+ -(2:R) • a • x = a • (-2:ℤ) • x := by
+ match_scalars
+```
+The scalar type for the goals produced by the `match_scalars` tactic is the largest scalar type
+encountered; for example, if `ℕ`, `ℚ` and a characteristic-zero field `K` all occur as scalars, then
+the goals produced are equalities in `K`. A variant of `push_cast` is used internally in
+`match_scalars` to interpret scalars from the other types in this largest type.
+
+If the set of scalar types encountered is not totally ordered (in the sense that for all rings `R`,
+`S` encountered, it holds that either `Algebra R S` or `Algebra S R`), then the `match_scalars`
+tactic fails.
+-/
+elab "match_scalars" : tactic => Tactic.liftMetaTactic matchScalars
+
+/-- Given a goal which is an equality in a type `M` (with `M` an `AddCommMonoid`), parse the LHS and
+RHS of the goal as linear combinations of `M`-atoms over some commutative semiring `R`, and prove
+the goal by checking that the LHS- and RHS-coefficients of each atom are the same up to
+ring-normalization in `R`.
+
+(If the proofs of coefficient-wise equality will require more reasoning than just
+ring-normalization, use the tactic `match_scalars` instead, and then prove coefficient-wise equality
+by hand.)
+
+Example uses of the `module` tactic:
+```
+example [AddCommMonoid M] [CommSemiring R] [Module R M] (a b : R) (x : M) :
+ a • x + b • x = (b + a) • x := by
+ module
+
+example [AddCommMonoid M] [Field K] [CharZero K] [Module K M] (x : M) :
+ (2:K)⁻¹ • x + (3:K)⁻¹ • x + (6:K)⁻¹ • x = x := by
+ module
+
+example [AddCommGroup M] [CommRing R] [Module R M] (a : R) (v w : M) :
+ (1 + a ^ 2) • (v + w) - a • (a • v - w) = v + (1 + a + a ^ 2) • w := by
+ module
+
+example [AddCommGroup M] [CommRing R] [Module R M] (a b μ ν : R) (x y : M) :
+ (μ - ν) • a • x = (a • μ • x + b • ν • y) - ν • (a • x + b • y) := by
+ module
+```
+-/
+elab "module" : tactic => Tactic.liftMetaFinishingTactic fun g ↦ do
+ let l ← matchScalars g
+ discard <| l.mapM fun mvar ↦ AtomM.run .instances (Ring.proveEq mvar)
+
+end Mathlib.Tactic.Module
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/NoncommRing.lean b/Mathlib/Tactic/NoncommRing.lean
index 46fd98f60bca4..f7c338b2c3b82 100644
--- a/Mathlib/Tactic/NoncommRing.lean
+++ b/Mathlib/Tactic/NoncommRing.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Oliver Nash. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Jireh Loreaux, Scott Morrison, Oliver Nash
+Authors: Jireh Loreaux, Kim Morrison, Oliver Nash
-/
import Mathlib.Algebra.Group.Action.Defs
import Mathlib.Tactic.Abel
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 3037be0ca7da7..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
@@ -147,8 +155,8 @@ theorem isInt_dvd_true : {a b : ℤ} → {a' b' c : ℤ} →
| _, _, _, _, _, ⟨rfl⟩, ⟨rfl⟩, rfl => ⟨_, rfl⟩
theorem isInt_dvd_false : {a b : ℤ} → {a' b' : ℤ} →
- IsInt a a' → IsInt b b' → Int.mod b' a' != 0 → ¬a ∣ b
- | _, _, _, _, ⟨rfl⟩, ⟨rfl⟩, e => mt Int.mod_eq_zero_of_dvd (by simpa using e)
+ IsInt a a' → IsInt b b' → Int.emod b' a' != 0 → ¬a ∣ b
+ | _, _, _, _, ⟨rfl⟩, ⟨rfl⟩, e => mt Int.emod_eq_zero_of_dvd (by simpa using e)
/-- The `norm_num` extension which identifies expressions of the form `(a : ℤ) ∣ b`,
such that `norm_num` successfully recognises both `a` and `b`. -/
@@ -167,7 +175,7 @@ such that `norm_num` successfully recognises both `a` and `b`. -/
haveI' : Int.mul $na $c =Q $nb := ⟨⟩
return .isTrue q(isInt_dvd_true $pa $pb (.refl $nb))
else
- have : Q(Int.mod $nb $na != 0) := (q(Eq.refl true) : Expr)
+ have : Q(Int.emod $nb $na != 0) := (q(Eq.refl true) : Expr)
return .isFalse q(isInt_dvd_false $pa $pb $this)
end Mathlib.Meta.NormNum
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/Core.lean b/Mathlib/Tactic/Positivity/Core.lean
index a03631e11fca8..5ea9541b1909c 100644
--- a/Mathlib/Tactic/Positivity/Core.lean
+++ b/Mathlib/Tactic/Positivity/Core.lean
@@ -122,7 +122,7 @@ variable {A : Type*} {e : A}
lemma lt_of_le_of_ne' {a b : A} [PartialOrder A] :
(a : A) ≤ b → b ≠ a → a < b := fun h₁ h₂ => lt_of_le_of_ne h₁ h₂.symm
-lemma pos_of_isNat {n : ℕ} [StrictOrderedSemiring A]
+lemma pos_of_isNat {n : ℕ} [OrderedSemiring A] [Nontrivial A]
(h : NormNum.IsNat e n) (w : Nat.ble 1 n = true) : 0 < (e : A) := by
rw [NormNum.IsNat.to_eq h rfl]
apply Nat.cast_pos.2
@@ -184,11 +184,12 @@ def normNumPositivity (e : Q($α)) : MetaM (Strictness zα pα e) := catchNone d
| .isBool .. => failure
| .isNat _ lit p =>
if 0 < lit.natLit! then
- let _a ← synthInstanceQ q(StrictOrderedSemiring $α)
+ let _a ← synthInstanceQ q(OrderedSemiring $α)
+ let _a ← synthInstanceQ q(Nontrivial $α)
assumeInstancesCommute
have p : Q(NormNum.IsNat $e $lit) := p
haveI' p' : Nat.ble 1 $lit =Q true := ⟨⟩
- pure (.positive q(@pos_of_isNat $α _ _ _ $p $p'))
+ pure (.positive q(@pos_of_isNat $α _ _ _ _ $p $p'))
else
let _a ← synthInstanceQ q(OrderedSemiring $α)
assumeInstancesCommute
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/Propose.lean b/Mathlib/Tactic/Propose.lean
index 9ca99b07d8d03..4169210c6c5ce 100644
--- a/Mathlib/Tactic/Propose.lean
+++ b/Mathlib/Tactic/Propose.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Lean.Meta.Tactic.TryThis
import Lean.Meta.Tactic.SolveByElim
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/RSuffices.lean b/Mathlib/Tactic/RSuffices.lean
index 22ca30eec31d5..ef0156c6581e3 100644
--- a/Mathlib/Tactic/RSuffices.lean
+++ b/Mathlib/Tactic/RSuffices.lean
@@ -13,6 +13,8 @@ of any syntax that would be valid in an `obtain` block. This tactic just calls `
on the expression, and then `rotate_left`.
-/
+namespace Mathlib.Tactic
+
/--
The `rsuffices` tactic is an alternative version of `suffices`, that allows the usage
of any syntax that would be valid in an `obtain` block. This tactic just calls `obtain`
@@ -24,3 +26,5 @@ syntax (name := rsuffices) "rsuffices"
macro_rules
| `(tactic| rsuffices $[$pred]? $[: $foo]? $[:= $bar]?) =>
`(tactic | (obtain $[$pred]? $[: $foo]? $[:= $bar]?; rotate_left))
+
+end Mathlib.Tactic
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/Symm.lean b/Mathlib/Tactic/Relation/Symm.lean
index 6057927cfb8b5..8d33854268714 100644
--- a/Mathlib/Tactic/Relation/Symm.lean
+++ b/Mathlib/Tactic/Relation/Symm.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Lean.Meta.Tactic.Symm
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/RewriteSearch.lean b/Mathlib/Tactic/RewriteSearch.lean
index befd4ab7e0ee1..f91c389946783 100644
--- a/Mathlib/Tactic/RewriteSearch.lean
+++ b/Mathlib/Tactic/RewriteSearch.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Lean.Meta.Tactic.Rewrites
import Mathlib.Algebra.Order.Group.Nat
diff --git a/Mathlib/Tactic/Ring/Basic.lean b/Mathlib/Tactic/Ring/Basic.lean
index bda62f7eef640..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
@@ -134,26 +135,28 @@ inductive ExSum : ∀ {u : Lean.Level} {α : Q(Type u)}, Q(CommSemiring $α) →
ExProd sα a → ExSum sα b → ExSum sα q($a + $b)
end
-
--- In this file, we would like to use multi-character auto-implicits.
-set_option autoImplicit true
-
mutual -- partial only to speed up compilation
/-- Equality test for expressions. This is not a `BEq` instance because it is heterogeneous. -/
-partial def ExBase.eq : ExBase sα a → ExBase sα b → Bool
+partial def ExBase.eq
+ {u : Lean.Level} {α : Q(Type u)} {sα : Q(CommSemiring $α)} {a b : Q($α)} :
+ ExBase sα a → ExBase sα b → Bool
| .atom i, .atom j => i == j
| .sum a, .sum b => a.eq b
| _, _ => false
@[inherit_doc ExBase.eq]
-partial def ExProd.eq : ExProd sα a → ExProd sα b → Bool
+partial def ExProd.eq
+ {u : Lean.Level} {α : Q(Type u)} {sα : Q(CommSemiring $α)} {a b : Q($α)} :
+ ExProd sα a → ExProd sα b → Bool
| .const i _, .const j _ => i == j
| .mul a₁ a₂ a₃, .mul b₁ b₂ b₃ => a₁.eq b₁ && a₂.eq b₂ && a₃.eq b₃
| _, _ => false
@[inherit_doc ExBase.eq]
-partial def ExSum.eq : ExSum sα a → ExSum sα b → Bool
+partial def ExSum.eq
+ {u : Lean.Level} {α : Q(Type u)} {sα : Q(CommSemiring $α)} {a b : Q($α)} :
+ ExSum sα a → ExSum sα b → Bool
| .zero, .zero => true
| .add a₁ a₂, .add b₁ b₂ => a₁.eq b₁ && a₂.eq b₂
| _, _ => false
@@ -164,28 +167,34 @@ mutual -- partial only to speed up compilation
A total order on normalized expressions.
This is not an `Ord` instance because it is heterogeneous.
-/
-partial def ExBase.cmp : ExBase sα a → ExBase sα b → Ordering
+partial def ExBase.cmp
+ {u : Lean.Level} {α : Q(Type u)} {sα : Q(CommSemiring $α)} {a b : Q($α)} :
+ ExBase sα a → ExBase sα b → Ordering
| .atom i, .atom j => compare i j
| .sum a, .sum b => a.cmp b
| .atom .., .sum .. => .lt
| .sum .., .atom .. => .gt
@[inherit_doc ExBase.cmp]
-partial def ExProd.cmp : ExProd sα a → ExProd sα b → Ordering
+partial def ExProd.cmp
+ {u : Lean.Level} {α : Q(Type u)} {sα : Q(CommSemiring $α)} {a b : Q($α)} :
+ ExProd sα a → ExProd sα b → Ordering
| .const i _, .const j _ => compare i j
| .mul a₁ a₂ a₃, .mul b₁ b₂ b₃ => (a₁.cmp b₁).then (a₂.cmp b₂) |>.then (a₃.cmp b₃)
| .const _ _, .mul .. => .lt
| .mul .., .const _ _ => .gt
@[inherit_doc ExBase.cmp]
-partial def ExSum.cmp : ExSum sα a → ExSum sα b → Ordering
+partial def ExSum.cmp
+ {u : Lean.Level} {α : Q(Type u)} {sα : Q(CommSemiring $α)} {a b : Q($α)} :
+ ExSum sα a → ExSum sα b → Ordering
| .zero, .zero => .eq
| .add a₁ a₂, .add b₁ b₂ => (a₁.cmp b₁).then (a₂.cmp b₂)
| .zero, .add .. => .lt
| .add .., .zero => .gt
end
-variable {u : Lean.Level} {arg : Q(Type u)} {sα : Q(CommSemiring $arg)}
+variable {u : Lean.Level} {α : Q(Type u)} {sα : Q(CommSemiring $α)}
instance : Inhabited (Σ e, (ExBase sα) e) := ⟨default, .atom 0⟩
instance : Inhabited (Σ e, (ExSum sα) e) := ⟨_, .zero⟩
@@ -194,24 +203,28 @@ instance : Inhabited (Σ e, (ExProd sα) e) := ⟨default, .const 0 none⟩
mutual
/-- Converts `ExBase sα` to `ExBase sβ`, assuming `sα` and `sβ` are defeq. -/
-partial def ExBase.cast {a : Q($arg)} : ExBase sα a → Σ a, ExBase sβ a
+partial def ExBase.cast
+ {v : Lean.Level} {β : Q(Type v)} {sβ : Q(CommSemiring $β)} {a : Q($α)} :
+ ExBase sα a → Σ a, ExBase sβ a
| .atom i => ⟨a, .atom i⟩
| .sum a => let ⟨_, vb⟩ := a.cast; ⟨_, .sum vb⟩
/-- Converts `ExProd sα` to `ExProd sβ`, assuming `sα` and `sβ` are defeq. -/
-partial def ExProd.cast {a : Q($arg)} : ExProd sα a → Σ a, ExProd sβ a
+partial def ExProd.cast
+ {v : Lean.Level} {β : Q(Type v)} {sβ : Q(CommSemiring $β)} {a : Q($α)} :
+ ExProd sα a → Σ a, ExProd sβ a
| .const i h => ⟨a, .const i h⟩
| .mul a₁ a₂ a₃ => ⟨_, .mul a₁.cast.2 a₂ a₃.cast.2⟩
/-- Converts `ExSum sα` to `ExSum sβ`, assuming `sα` and `sβ` are defeq. -/
-partial def ExSum.cast {a : Q($arg)} : ExSum sα a → Σ a, ExSum sβ a
+partial def ExSum.cast
+ {v : Lean.Level} {β : Q(Type v)} {sβ : Q(CommSemiring $β)} {a : Q($α)} :
+ ExSum sα a → Σ a, ExSum sβ a
| .zero => ⟨_, .zero⟩
| .add a₁ a₂ => ⟨_, .add a₁.cast.2 a₂.cast.2⟩
end
-set_option autoImplicit false
-
variable {u : Lean.Level}
/--
@@ -295,6 +308,11 @@ theorem add_overlap_pf_zero (x : R) (e) :
IsNat (a + b) (nat_lit 0) → IsNat (x ^ e * a + x ^ e * b) (nat_lit 0)
| ⟨h⟩ => ⟨by simp [h, ← mul_add]⟩
+-- TODO: decide if this is a good idea globally in
+-- https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/.60MonadLift.20Option.20.28OptionT.20m.29.60/near/469097834
+private local instance {m} [Pure m] : MonadLift Option (OptionT m) where
+ monadLift f := .mk <| pure f
+
/--
Given monomials `va, vb`, attempts to add them together to get another monomial.
If the monomials are not compatible, returns `none`.
@@ -302,7 +320,8 @@ For example, `xy + 2xy = 3xy` is a `.nonzero` overlap, while `xy + xz` returns `
and `xy + -xy = 0` is a `.zero` overlap.
-/
def evalAddOverlap {a b : Q($α)} (va : ExProd sα a) (vb : ExProd sα b) :
- Option (Overlap sα q($a + $b)) :=
+ OptionT Lean.Core.CoreM (Overlap sα q($a + $b)) := do
+ Lean.Core.checkSystem decl_name%.toString
match va, vb with
| .const za ha, .const zb hb => do
let ra := Result.ofRawRat za a ha; let rb := Result.ofRawRat zb b hb
@@ -319,7 +338,7 @@ def evalAddOverlap {a b : Q($α)} (va : ExProd sα a) (vb : ExProd sα b) :
| .zero p => pure <| .zero (q(add_overlap_pf_zero $a₁ $a₂ $p) : Expr)
| .nonzero ⟨_, vc, p⟩ =>
pure <| .nonzero ⟨_, .mul va₁ va₂ vc, (q(add_overlap_pf $a₁ $a₂ $p) : Expr)⟩
- | _, _ => none
+ | _, _ => OptionT.fail
theorem add_pf_zero_add (b : R) : 0 + b = b := by simp
@@ -347,25 +366,26 @@ theorem add_pf_add_gt (b₁ : R) (_ : a + b₂ = c) : a + (b₁ + b₂) = b₁ +
* `(a₁ + a₂) + (b₁ + b₂) = b₁ + ((a₁ + a₂) + b₂)` (if not `a₁.lt b₁`)
-/
partial def evalAdd {a b : Q($α)} (va : ExSum sα a) (vb : ExSum sα b) :
- Result (ExSum sα) q($a + $b) :=
+ Lean.Core.CoreM <| Result (ExSum sα) q($a + $b) := do
+ Lean.Core.checkSystem decl_name%.toString
match va, vb with
- | .zero, vb => ⟨b, vb, q(add_pf_zero_add $b)⟩
- | va, .zero => ⟨a, va, q(add_pf_add_zero $a)⟩
+ | .zero, vb => return ⟨b, vb, q(add_pf_zero_add $b)⟩
+ | va, .zero => return ⟨a, va, q(add_pf_add_zero $a)⟩
| .add (a := a₁) (b := _a₂) va₁ va₂, .add (a := b₁) (b := _b₂) vb₁ vb₂ =>
- match evalAddOverlap sα va₁ vb₁ with
+ match ← (evalAddOverlap sα va₁ vb₁).run with
| some (.nonzero ⟨_, vc₁, pc₁⟩) =>
- let ⟨_, vc₂, pc₂⟩ := evalAdd va₂ vb₂
- ⟨_, .add vc₁ vc₂, q(add_pf_add_overlap $pc₁ $pc₂)⟩
+ let ⟨_, vc₂, pc₂⟩ ← evalAdd va₂ vb₂
+ return ⟨_, .add vc₁ vc₂, q(add_pf_add_overlap $pc₁ $pc₂)⟩
| some (.zero pc₁) =>
- let ⟨c₂, vc₂, pc₂⟩ := evalAdd va₂ vb₂
- ⟨c₂, vc₂, q(add_pf_add_overlap_zero $pc₁ $pc₂)⟩
+ let ⟨c₂, vc₂, pc₂⟩ ← evalAdd va₂ vb₂
+ return ⟨c₂, vc₂, q(add_pf_add_overlap_zero $pc₁ $pc₂)⟩
| none =>
if let .lt := va₁.cmp vb₁ then
- let ⟨_c, vc, (pc : Q($_a₂ + ($b₁ + $_b₂) = $_c))⟩ := evalAdd va₂ vb
- ⟨_, .add va₁ vc, q(add_pf_add_lt $a₁ $pc)⟩
+ let ⟨_c, vc, (pc : Q($_a₂ + ($b₁ + $_b₂) = $_c))⟩ ← evalAdd va₂ vb
+ return ⟨_, .add va₁ vc, q(add_pf_add_lt $a₁ $pc)⟩
else
- let ⟨_c, vc, (pc : Q($a₁ + $_a₂ + $_b₂ = $_c))⟩ := evalAdd va vb₂
- ⟨_, .add vb₁ vc, q(add_pf_add_gt $b₁ $pc)⟩
+ let ⟨_c, vc, (pc : Q($a₁ + $_a₂ + $_b₂ = $_c))⟩ ← evalAdd va vb₂
+ return ⟨_, .add vb₁ vc, q(add_pf_add_gt $b₁ $pc)⟩
theorem one_mul (a : R) : (nat_lit 1).rawCast * a = a := by simp [Nat.rawCast]
@@ -394,37 +414,38 @@ theorem mul_pp_pf_overlap {ea eb e : ℕ} (x : R) (_ : ea + eb = e) (_ : a₂ *
* `(a₁ * a₂) * (b₁ * b₂) = b₁ * ((a₁ * a₂) * b₂)` (if not `a₁.lt b₁`)
-/
partial def evalMulProd {a b : Q($α)} (va : ExProd sα a) (vb : ExProd sα b) :
- Result (ExProd sα) q($a * $b) :=
+ Lean.Core.CoreM <| Result (ExProd sα) q($a * $b) := do
+ Lean.Core.checkSystem decl_name%.toString
match va, vb with
| .const za ha, .const zb hb =>
if za = 1 then
- ⟨b, .const zb hb, (q(one_mul $b) : Expr)⟩
+ return ⟨b, .const zb hb, (q(one_mul $b) : Expr)⟩
else if zb = 1 then
- ⟨a, .const za ha, (q(mul_one $a) : Expr)⟩
+ return ⟨a, .const za ha, (q(mul_one $a) : Expr)⟩
else
let ra := Result.ofRawRat za a ha; let rb := Result.ofRawRat zb b hb
let rc := (NormNum.evalMul.core q($a * $b) q(HMul.hMul) _ _
q(CommSemiring.toSemiring) ra rb).get!
let ⟨zc, hc⟩ := rc.toRatNZ.get!
let ⟨c, pc⟩ := rc.toRawEq
- ⟨c, .const zc hc, pc⟩
+ return ⟨c, .const zc hc, pc⟩
| .mul (x := a₁) (e := a₂) va₁ va₂ va₃, .const _ _ =>
- let ⟨_, vc, pc⟩ := evalMulProd va₃ vb
- ⟨_, .mul va₁ va₂ vc, (q(mul_pf_left $a₁ $a₂ $pc) : Expr)⟩
+ let ⟨_, vc, pc⟩ ← evalMulProd va₃ vb
+ return ⟨_, .mul va₁ va₂ vc, (q(mul_pf_left $a₁ $a₂ $pc) : Expr)⟩
| .const _ _, .mul (x := b₁) (e := b₂) vb₁ vb₂ vb₃ =>
- let ⟨_, vc, pc⟩ := evalMulProd va vb₃
- ⟨_, .mul vb₁ vb₂ vc, (q(mul_pf_right $b₁ $b₂ $pc) : Expr)⟩
- | .mul (x := xa) (e := ea) vxa vea va₂, .mul (x := xb) (e := eb) vxb veb vb₂ => Id.run do
+ let ⟨_, vc, pc⟩ ← evalMulProd va vb₃
+ return ⟨_, .mul vb₁ vb₂ vc, (q(mul_pf_right $b₁ $b₂ $pc) : Expr)⟩
+ | .mul (x := xa) (e := ea) vxa vea va₂, .mul (x := xb) (e := eb) vxb veb vb₂ => do
if vxa.eq vxb then
- if let some (.nonzero ⟨_, ve, pe⟩) := evalAddOverlap sℕ vea veb then
- let ⟨_, vc, pc⟩ := evalMulProd va₂ vb₂
+ if let some (.nonzero ⟨_, ve, pe⟩) ← (evalAddOverlap sℕ vea veb).run then
+ let ⟨_, vc, pc⟩ ← evalMulProd va₂ vb₂
return ⟨_, .mul vxa ve vc, (q(mul_pp_pf_overlap $xa $pe $pc) : Expr)⟩
if let .lt := (vxa.cmp vxb).then (vea.cmp veb) then
- let ⟨_, vc, pc⟩ := evalMulProd va₂ vb
- ⟨_, .mul vxa vea vc, (q(mul_pf_left $xa $ea $pc) : Expr)⟩
+ let ⟨_, vc, pc⟩ ← evalMulProd va₂ vb
+ return ⟨_, .mul vxa vea vc, (q(mul_pf_left $xa $ea $pc) : Expr)⟩
else
- let ⟨_, vc, pc⟩ := evalMulProd va vb₂
- ⟨_, .mul vxb veb vc, (q(mul_pf_right $xb $eb $pc) : Expr)⟩
+ let ⟨_, vc, pc⟩ ← evalMulProd va vb₂
+ return ⟨_, .mul vxb veb vc, (q(mul_pf_right $xb $eb $pc) : Expr)⟩
theorem mul_zero (a : R) : a * 0 = 0 := by simp
@@ -437,14 +458,15 @@ theorem mul_add {d : R} (_ : (a : R) * b₁ = c₁) (_ : a * b₂ = c₂) (_ : c
* `a * 0 = 0`
* `a * (b₁ + b₂) = (a * b₁) + (a * b₂)`
-/
-def evalMul₁ {a b : Q($α)} (va : ExProd sα a) (vb : ExSum sα b) : Result (ExSum sα) q($a * $b) :=
+def evalMul₁ {a b : Q($α)} (va : ExProd sα a) (vb : ExSum sα b) :
+ Lean.Core.CoreM <| Result (ExSum sα) q($a * $b) := do
match vb with
- | .zero => ⟨_, .zero, q(mul_zero $a)⟩
+ | .zero => return ⟨_, .zero, q(mul_zero $a)⟩
| .add vb₁ vb₂ =>
- let ⟨_, vc₁, pc₁⟩ := evalMulProd sα va vb₁
- let ⟨_, vc₂, pc₂⟩ := evalMul₁ va vb₂
- let ⟨_, vd, pd⟩ := evalAdd sα vc₁.toSum vc₂
- ⟨_, vd, q(mul_add $pc₁ $pc₂ $pd)⟩
+ let ⟨_, vc₁, pc₁⟩ ← evalMulProd sα va vb₁
+ let ⟨_, vc₂, pc₂⟩ ← evalMul₁ va vb₂
+ let ⟨_, vd, pd⟩ ← evalAdd sα vc₁.toSum vc₂
+ return ⟨_, vd, q(mul_add $pc₁ $pc₂ $pd)⟩
theorem zero_mul (b : R) : 0 * b = 0 := by simp
@@ -456,14 +478,15 @@ theorem add_mul {d : R} (_ : (a₁ : R) * b = c₁) (_ : a₂ * b = c₂) (_ : c
* `0 * b = 0`
* `(a₁ + a₂) * b = (a₁ * b) + (a₂ * b)`
-/
-def evalMul {a b : Q($α)} (va : ExSum sα a) (vb : ExSum sα b) : Result (ExSum sα) q($a * $b) :=
+def evalMul {a b : Q($α)} (va : ExSum sα a) (vb : ExSum sα b) :
+ Lean.Core.CoreM <| Result (ExSum sα) q($a * $b) := do
match va with
- | .zero => ⟨_, .zero, q(zero_mul $b)⟩
+ | .zero => return ⟨_, .zero, q(zero_mul $b)⟩
| .add va₁ va₂ =>
- let ⟨_, vc₁, pc₁⟩ := evalMul₁ sα va₁ vb
- let ⟨_, vc₂, pc₂⟩ := evalMul va₂ vb
- let ⟨_, vd, pd⟩ := evalAdd sα vc₁ vc₂
- ⟨_, vd, q(add_mul $pc₁ $pc₂ $pd)⟩
+ let ⟨_, vc₁, pc₁⟩ ← evalMul₁ sα va₁ vb
+ let ⟨_, vc₂, pc₂⟩ ← evalMul va₂ vb
+ let ⟨_, vd, pd⟩ ← evalAdd sα vc₁ vc₂
+ return ⟨_, vd, q(add_mul $pc₁ $pc₂ $pd)⟩
theorem natCast_nat (n) : ((Nat.rawCast n : ℕ) : R) = Nat.rawCast n := by simp
@@ -540,11 +563,11 @@ def evalNSMul {a : Q(ℕ)} {b : Q($α)} (va : ExSum sℕ a) (vb : ExSum sα b) :
if ← isDefEq sα sℕ then
let ⟨_, va'⟩ := va.cast
have _b : Q(ℕ) := b
- let ⟨(_c : Q(ℕ)), vc, (pc : Q($a * $_b = $_c))⟩ := evalMul sα va' vb
+ let ⟨(_c : Q(ℕ)), vc, (pc : Q($a * $_b = $_c))⟩ ← evalMul sα va' vb
pure ⟨_, vc, (q(smul_nat $pc) : Expr)⟩
else
let ⟨_, va', pa'⟩ ← va.evalNatCast sα
- let ⟨_, vc, pc⟩ := evalMul sα va' vb
+ let ⟨_, vc, pc⟩ ← evalMul sα va' vb
pure ⟨_, vc, (q(smul_eq_cast $pa' $pc) : Expr)⟩
theorem neg_one_mul {R} [Ring R] {a b : R} (_ : (Int.negOfNat (nat_lit 1)).rawCast * a = b) :
@@ -558,7 +581,9 @@ theorem neg_mul {R} [Ring R] (a₁ : R) (a₂) {a₃ b : R}
* `-c = (-c)` (for `c` coefficient)
* `-(a₁ * a₂) = a₁ * -a₂`
-/
-def evalNegProd {a : Q($α)} (rα : Q(Ring $α)) (va : ExProd sα a) : Result (ExProd sα) q(-$a) :=
+def evalNegProd {a : Q($α)} (rα : Q(Ring $α)) (va : ExProd sα a) :
+ Lean.Core.CoreM <| Result (ExProd sα) q(-$a) := do
+ Lean.Core.checkSystem decl_name%.toString
match va with
| .const za ha =>
let lit : Q(ℕ) := mkRawNatLit 1
@@ -569,10 +594,10 @@ def evalNegProd {a : Q($α)} (rα : Q(Ring $α)) (va : ExProd sα a) : Result (E
q(CommSemiring.toSemiring) rm ra).get!
let ⟨zb, hb⟩ := rb.toRatNZ.get!
let ⟨b, (pb : Q((Int.negOfNat (nat_lit 1)).rawCast * $a = $b))⟩ := rb.toRawEq
- ⟨b, .const zb hb, (q(neg_one_mul (R := $α) $pb) : Expr)⟩
+ return ⟨b, .const zb hb, (q(neg_one_mul (R := $α) $pb) : Expr)⟩
| .mul (x := a₁) (e := a₂) va₁ va₂ va₃ =>
- let ⟨_, vb, pb⟩ := evalNegProd rα va₃
- ⟨_, .mul va₁ va₂ vb, (q(neg_mul $a₁ $a₂ $pb) : Expr)⟩
+ let ⟨_, vb, pb⟩ ← evalNegProd rα va₃
+ return ⟨_, .mul va₁ va₂ vb, (q(neg_mul $a₁ $a₂ $pb) : Expr)⟩
theorem neg_zero {R} [Ring R] : -(0 : R) = 0 := by simp
@@ -585,13 +610,14 @@ theorem neg_add {R} [Ring R] {a₁ a₂ b₁ b₂ : R}
* `-0 = 0` (for `c` coefficient)
* `-(a₁ + a₂) = -a₁ + -a₂`
-/
-def evalNeg {a : Q($α)} (rα : Q(Ring $α)) (va : ExSum sα a) : Result (ExSum sα) q(-$a) :=
+def evalNeg {a : Q($α)} (rα : Q(Ring $α)) (va : ExSum sα a) :
+ Lean.Core.CoreM <| Result (ExSum sα) q(-$a) := do
match va with
- | .zero => ⟨_, .zero, (q(neg_zero (R := $α)) : Expr)⟩
+ | .zero => return ⟨_, .zero, (q(neg_zero (R := $α)) : Expr)⟩
| .add va₁ va₂ =>
- let ⟨_, vb₁, pb₁⟩ := evalNegProd sα rα va₁
- let ⟨_, vb₂, pb₂⟩ := evalNeg rα va₂
- ⟨_, .add vb₁ vb₂, (q(neg_add $pb₁ $pb₂) : Expr)⟩
+ let ⟨_, vb₁, pb₁⟩ ← evalNegProd sα rα va₁
+ let ⟨_, vb₂, pb₂⟩ ← evalNeg rα va₂
+ return ⟨_, .add vb₁ vb₂, (q(neg_add $pb₁ $pb₂) : Expr)⟩
theorem sub_pf {R} [Ring R] {a b c d : R}
(_ : -b = c) (_ : a + c = d) : a - b = d := by subst_vars; simp [sub_eq_add_neg]
@@ -601,10 +627,11 @@ theorem sub_pf {R} [Ring R] {a b c d : R}
* `a - b = a + -b`
-/
def evalSub {α : Q(Type u)} (sα : Q(CommSemiring $α)) {a b : Q($α)}
- (rα : Q(Ring $α)) (va : ExSum sα a) (vb : ExSum sα b) : Result (ExSum sα) q($a - $b) :=
- let ⟨_c, vc, pc⟩ := evalNeg sα rα vb
- let ⟨d, vd, (pd : Q($a + $_c = $d))⟩ := evalAdd sα va vc
- ⟨d, vd, (q(sub_pf $pc $pd) : Expr)⟩
+ (rα : Q(Ring $α)) (va : ExSum sα a) (vb : ExSum sα b) :
+ Lean.Core.CoreM <| Result (ExSum sα) q($a - $b) := do
+ let ⟨_c, vc, pc⟩ ← evalNeg sα rα vb
+ let ⟨d, vd, (pd : Q($a + $_c = $d))⟩ ← evalAdd sα va vc
+ return ⟨d, vd, (q(sub_pf $pc $pd) : Expr)⟩
theorem pow_prod_atom (a : R) (b) : a ^ b = (a + 0) ^ b * (nat_lit 1).rawCast := by simp
@@ -706,22 +733,23 @@ into a sum of monomials.
* `x ^ (2*n) = x ^ n * x ^ n`
* `x ^ (2*n+1) = x ^ n * x ^ n * x`
-/
-partial def evalPowNat {a : Q($α)} (va : ExSum sα a) (n : Q(ℕ)) : Result (ExSum sα) q($a ^ $n) :=
+partial def evalPowNat {a : Q($α)} (va : ExSum sα a) (n : Q(ℕ)) :
+ Lean.Core.CoreM <| Result (ExSum sα) q($a ^ $n) := do
let nn := n.natLit!
if nn = 1 then
- ⟨_, va, (q(pow_one $a) : Expr)⟩
+ return ⟨_, va, (q(pow_one $a) : Expr)⟩
else
let nm := nn >>> 1
have m : Q(ℕ) := mkRawNatLit nm
if nn &&& 1 = 0 then
- let ⟨_, vb, pb⟩ := evalPowNat va m
- let ⟨_, vc, pc⟩ := evalMul sα vb vb
- ⟨_, vc, (q(pow_bit0 $pb $pc) : Expr)⟩
+ let ⟨_, vb, pb⟩ ← evalPowNat va m
+ let ⟨_, vc, pc⟩ ← evalMul sα vb vb
+ return ⟨_, vc, (q(pow_bit0 $pb $pc) : Expr)⟩
else
- let ⟨_, vb, pb⟩ := evalPowNat va m
- let ⟨_, vc, pc⟩ := evalMul sα vb vb
- let ⟨_, vd, pd⟩ := evalMul sα vc va
- ⟨_, vd, (q(pow_bit1 $pb $pc $pd) : Expr)⟩
+ let ⟨_, vb, pb⟩ ← evalPowNat va m
+ let ⟨_, vc, pc⟩ ← evalMul sα vb vb
+ let ⟨_, vd, pd⟩ ← evalMul sα vc va
+ return ⟨_, vd, (q(pow_bit1 $pb $pc $pd) : Expr)⟩
theorem one_pow (b : ℕ) : ((nat_lit 1).rawCast : R) ^ b = (nat_lit 1).rawCast := by simp
@@ -738,10 +766,11 @@ theorem mul_pow {ea₁ b c₁ : ℕ} {xa₁ : R}
In all other cases we use `evalPowProdAtom`.
-/
def evalPowProd {a : Q($α)} {b : Q(ℕ)} (va : ExProd sα a) (vb : ExProd sℕ b) :
- Result (ExProd sα) q($a ^ $b) :=
- let res : Option (Result (ExProd sα) q($a ^ $b)) := do
+ Lean.Core.CoreM <| Result (ExProd sα) q($a ^ $b) := do
+ Lean.Core.checkSystem decl_name%.toString
+ let res : OptionT Lean.Core.CoreM (Result (ExProd sα) q($a ^ $b)) := do
match va, vb with
- | .const 1, _ => some ⟨_, va, (q(one_pow (R := $α) $b) : Expr)⟩
+ | .const 1, _ => return ⟨_, va, (q(one_pow (R := $α) $b) : Expr)⟩
| .const za ha, .const zb hb =>
assert! 0 ≤ zb
let ra := Result.ofRawRat za a ha
@@ -751,13 +780,13 @@ def evalPowProd {a : Q($α)} {b : Q(ℕ)} (va : ExProd sα a) (vb : ExProd sℕ
q(CommSemiring.toSemiring) ra
let ⟨zc, hc⟩ ← rc.toRatNZ
let ⟨c, pc⟩ := rc.toRawEq
- some ⟨c, .const zc hc, pc⟩
- | .mul vxa₁ vea₁ va₂, vb => do
- let ⟨_, vc₁, pc₁⟩ := evalMulProd sℕ vea₁ vb
- let ⟨_, vc₂, pc₂⟩ := evalPowProd va₂ vb
- some ⟨_, .mul vxa₁ vc₁ vc₂, q(mul_pow $pc₁ $pc₂)⟩
- | _, _ => none
- res.getD (evalPowProdAtom sα va vb)
+ return ⟨c, .const zc hc, pc⟩
+ | .mul vxa₁ vea₁ va₂, vb =>
+ let ⟨_, vc₁, pc₁⟩ ← evalMulProd sℕ vea₁ vb
+ let ⟨_, vc₂, pc₂⟩ ← evalPowProd va₂ vb
+ return ⟨_, .mul vxa₁ vc₁ vc₂, q(mul_pow $pc₁ $pc₂)⟩
+ | _, _ => OptionT.fail
+ return (← res.run).getD (evalPowProdAtom sα va vb)
/--
The result of `extractCoeff` is a numeral and a proof that the original expression
@@ -815,24 +844,25 @@ theorem pow_nat {b c k : ℕ} {d e : R} (_ : b = c * k) (_ : a ^ c = d) (_ : d ^
Otherwise `a ^ b` is just encoded as `a ^ b * 1 + 0` using `evalPowAtom`.
-/
partial def evalPow₁ {a : Q($α)} {b : Q(ℕ)} (va : ExSum sα a) (vb : ExProd sℕ b) :
- Result (ExSum sα) q($a ^ $b) :=
+ Lean.Core.CoreM <| Result (ExSum sα) q($a ^ $b) := do
match va, vb with
| va, .const 1 =>
haveI : $b =Q Nat.rawCast (nat_lit 1) := ⟨⟩
- ⟨_, va, q(pow_one_cast $a)⟩
+ return ⟨_, va, q(pow_one_cast $a)⟩
| .zero, vb => match vb.evalPos with
- | some p => ⟨_, .zero, q(zero_pow (R := $α) $p)⟩
- | none => evalPowAtom sα (.sum .zero) vb
+ | some p => return ⟨_, .zero, q(zero_pow (R := $α) $p)⟩
+ | none => return evalPowAtom sα (.sum .zero) vb
| ExSum.add va .zero, vb => -- TODO: using `.add` here takes a while to compile?
- let ⟨_, vc, pc⟩ := evalPowProd sα va vb
- ⟨_, vc.toSum, q(single_pow $pc)⟩
+ let ⟨_, vc, pc⟩ ← evalPowProd sα va vb
+ return ⟨_, vc.toSum, q(single_pow $pc)⟩
| va, vb =>
if vb.coeff > 1 then
let ⟨k, _, vc, pc⟩ := extractCoeff vb
- let ⟨_, vd, pd⟩ := evalPow₁ va vc
- let ⟨_, ve, pe⟩ := evalPowNat sα vd k
- ⟨_, ve, q(pow_nat $pc $pd $pe)⟩
- else evalPowAtom sα (.sum va) vb
+ let ⟨_, vd, pd⟩ ← evalPow₁ va vc
+ let ⟨_, ve, pe⟩ ← evalPowNat sα vd k
+ return ⟨_, ve, q(pow_nat $pc $pd $pe)⟩
+ else
+ return evalPowAtom sα (.sum va) vb
theorem pow_zero (a : R) : a ^ 0 = (nat_lit 1).rawCast + 0 := by simp
@@ -846,17 +876,17 @@ theorem pow_add {b₁ b₂ : ℕ} {d : R}
* `a ^ (b₁ + b₂) = a ^ b₁ * a ^ b₂`
-/
def evalPow {a : Q($α)} {b : Q(ℕ)} (va : ExSum sα a) (vb : ExSum sℕ b) :
- Result (ExSum sα) q($a ^ $b) :=
+ Lean.Core.CoreM <| Result (ExSum sα) q($a ^ $b) := do
match vb with
- | .zero => ⟨_, (ExProd.mkNat sα 1).2.toSum, q(pow_zero $a)⟩
+ | .zero => return ⟨_, (ExProd.mkNat sα 1).2.toSum, q(pow_zero $a)⟩
| .add vb₁ vb₂ =>
- let ⟨_, vc₁, pc₁⟩ := evalPow₁ sα va vb₁
- let ⟨_, vc₂, pc₂⟩ := evalPow va vb₂
- let ⟨_, vd, pd⟩ := evalMul sα vc₁ vc₂
- ⟨_, vd, q(pow_add $pc₁ $pc₂ $pd)⟩
+ let ⟨_, vc₁, pc₁⟩ ← evalPow₁ sα va vb₁
+ let ⟨_, vc₂, pc₂⟩ ← evalPow va vb₂
+ let ⟨_, vd, pd⟩ ← evalMul sα vc₁ vc₂
+ 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. -/
@@ -956,6 +986,7 @@ def evalInvAtom (a : Q($α)) : AtomM (Result (ExBase sα) q($a⁻¹)) := do
-/
def ExProd.evalInv {a : Q($α)} (czα : Option Q(CharZero $α)) (va : ExProd sα a) :
AtomM (Result (ExProd sα) q($a⁻¹)) := do
+ Lean.Core.checkSystem decl_name%.toString
match va with
| .const c hc =>
let ra := Result.ofRawRat c a hc
@@ -970,7 +1001,7 @@ def ExProd.evalInv {a : Q($α)} (czα : Option Q(CharZero $α)) (va : ExProd sα
| .mul (x := a₁) (e := _a₂) _va₁ va₂ va₃ => do
let ⟨_b₁, vb₁, pb₁⟩ ← evalInvAtom sα dα a₁
let ⟨_b₃, vb₃, pb₃⟩ ← va₃.evalInv czα
- let ⟨c, vc, (pc : Q($_b₃ * ($_b₁ ^ $_a₂ * Nat.rawCast 1) = $c))⟩ :=
+ let ⟨c, vc, (pc : Q($_b₃ * ($_b₁ ^ $_a₂ * Nat.rawCast 1) = $c))⟩ ←
evalMulProd sα vb₃ (vb₁.toProd va₂)
pure ⟨c, vc, (q(inv_mul $pb₁ $pb₃ $pc) : Expr)⟩
@@ -984,7 +1015,7 @@ def ExSum.evalInv {a : Q($α)} (czα : Option Q(CharZero $α)) (va : ExSum sα a
match va with
| ExSum.zero => pure ⟨_, .zero, (q(inv_zero (R := $α)) : Expr)⟩
| ExSum.add va ExSum.zero => do
- let ⟨_, vb, pb⟩ ← va.evalInv dα czα
+ let ⟨_, vb, pb⟩ ← va.evalInv sα dα czα
pure ⟨_, vb.toSum, (q(inv_single $pb) : Expr)⟩
| va => do
let ⟨_, vb, pb⟩ ← evalInvAtom sα dα a
@@ -1002,7 +1033,7 @@ theorem div_pf {R} [DivisionRing R] {a b c d : R} (_ : b⁻¹ = c) (_ : a * c =
def evalDiv {a b : Q($α)} (rα : Q(DivisionRing $α)) (czα : Option Q(CharZero $α)) (va : ExSum sα a)
(vb : ExSum sα b) : AtomM (Result (ExSum sα) q($a / $b)) := do
let ⟨_c, vc, pc⟩ ← vb.evalInv sα rα czα
- let ⟨d, vd, (pd : Q($a * $_c = $d))⟩ := evalMul sα va vc
+ let ⟨d, vd, (pd : Q($a * $_c = $d))⟩ ← evalMul sα va vc
pure ⟨d, vd, (q(div_pf $pc $pd) : Expr)⟩
theorem add_congr (_ : a = a') (_ : b = b') (_ : a' + b' = c) : (a + b : R) = c := by
@@ -1077,14 +1108,14 @@ partial def eval {u : Lean.Level} {α : Q(Type u)} (sα : Q(CommSemiring $α))
| ~q($a + $b) =>
let ⟨_, va, pa⟩ ← eval sα c a
let ⟨_, vb, pb⟩ ← eval sα c b
- let ⟨c, vc, p⟩ := evalAdd sα va vb
+ let ⟨c, vc, p⟩ ← evalAdd sα va vb
pure ⟨c, vc, (q(add_congr $pa $pb $p) : Expr)⟩
| _ => els
| ``HMul.hMul, _, _ | ``Mul.mul, _, _ => match e with
| ~q($a * $b) =>
let ⟨_, va, pa⟩ ← eval sα c a
let ⟨_, vb, pb⟩ ← eval sα c b
- let ⟨c, vc, p⟩ := evalMul sα va vb
+ let ⟨c, vc, p⟩ ← evalMul sα va vb
pure ⟨c, vc, (q(mul_congr $pa $pb $p) : Expr)⟩
| _ => els
| ``HSMul.hSMul, _, _ => match e with
@@ -1098,19 +1129,20 @@ partial def eval {u : Lean.Level} {α : Q(Type u)} (sα : Q(CommSemiring $α))
| ~q($a ^ $b) =>
let ⟨_, va, pa⟩ ← eval sα c a
let ⟨_, vb, pb⟩ ← eval sℕ .nat b
- let ⟨c, vc, p⟩ := evalPow sα va vb
+ let ⟨c, vc, p⟩ ← evalPow sα va vb
pure ⟨c, vc, (q(pow_congr $pa $pb $p) : Expr)⟩
| _ => els
| ``Neg.neg, some rα, _ => match e with
| ~q(-$a) =>
let ⟨_, va, pa⟩ ← eval sα c a
- let ⟨b, vb, p⟩ := evalNeg sα rα va
+ let ⟨b, vb, p⟩ ← evalNeg sα rα va
pure ⟨b, vb, (q(neg_congr $pa $p) : Expr)⟩
+ | _ => els
| ``HSub.hSub, some rα, _ | ``Sub.sub, some rα, _ => match e with
| ~q($a - $b) => do
let ⟨_, va, pa⟩ ← eval sα c a
let ⟨_, vb, pb⟩ ← eval sα c b
- let ⟨c, vc, p⟩ := evalSub sα rα va vb
+ let ⟨c, vc, p⟩ ← evalSub sα rα va vb
pure ⟨c, vc, (q(sub_congr $pa $pb $p) : Expr)⟩
| _ => els
| ``Inv.inv, _, some dα => match e with
@@ -1118,6 +1150,7 @@ partial def eval {u : Lean.Level} {α : Q(Type u)} (sα : Q(CommSemiring $α))
let ⟨_, va, pa⟩ ← eval sα c a
let ⟨b, vb, p⟩ ← va.evalInv sα dα c.czα
pure ⟨b, vb, (q(inv_congr $pa $p) : Expr)⟩
+ | _ => els
| ``HDiv.hDiv, _, some dα | ``Div.div, _, some dα => match e with
| ~q($a / $b) => do
let ⟨_, va, pa⟩ ← eval sα c a
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/Ring/RingNF.lean b/Mathlib/Tactic/Ring/RingNF.lean
index 4ac168ff6ec41..c538ee4c12311 100644
--- a/Mathlib/Tactic/Ring/RingNF.lean
+++ b/Mathlib/Tactic/Ring/RingNF.lean
@@ -147,7 +147,7 @@ partial def M.run
``rat_rawCast_neg, ``rat_rawCast_pos].foldlM (·.addConst · (post := false)) thms
let ctx' := { ctx with simpTheorems := #[thms] }
pure fun r' : Simp.Result ↦ do
- r'.mkEqTrans (← Simp.main r'.expr ctx' (methods := ← Lean.Meta.Simp.mkDefaultMethods)).1
+ r'.mkEqTrans (← Simp.main r'.expr ctx' (methods := Lean.Meta.Simp.mkDefaultMethodsCore {})).1
let nctx := { ctx, simp }
let rec
/-- The recursive context. -/
diff --git a/Mathlib/Tactic/Says.lean b/Mathlib/Tactic/Says.lean
index 72b195ef15967..29bd33ed183cf 100644
--- a/Mathlib/Tactic/Says.lean
+++ b/Mathlib/Tactic/Says.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Kim Liesinger. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Kim Liesinger
+Authors: Kim Morrison
-/
import Mathlib.Init
import Batteries.Data.String.Basic
@@ -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 9d7dfe3ba1c6e..3b28a506c4d61 100644
--- a/Mathlib/Tactic/Simps/Basic.lean
+++ b/Mathlib/Tactic/Simps/Basic.lean
@@ -8,7 +8,6 @@ import Lean.Elab.App
import Mathlib.Tactic.Simps.NotationClass
import Batteries.Data.String.Basic
import Mathlib.Lean.Expr.Basic
-import Batteries.Data.List.Basic
/-!
# Simps attribute
@@ -318,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
```
@@ -1180,7 +1178,7 @@ def simpsTac (ref : Syntax) (nm : Name) (cfg : Config := {})
let env ← getEnv
let some d := env.find? nm | throwError "Declaration {nm} doesn't exist."
let lhs : Expr := mkConst d.name <| d.levelParams.map Level.param
- let todo := todo.pwFilter (·.1 ≠ ·.1) |>.map fun (proj, stx) ↦ (proj ++ "_", stx)
+ let todo := todo.eraseDups |>.map fun (proj, stx) ↦ (proj ++ "_", stx)
let mut cfg := cfg
MetaM.run' <| addProjections ref d.levelParams
nm d.type lhs (d.value?.getD default) #[] (mustBeStr := true) cfg todo []
diff --git a/Mathlib/Tactic/SlimCheck.lean b/Mathlib/Tactic/SlimCheck.lean
index 66c0e52fbbb68..d30b24c1f4eb5 100644
--- a/Mathlib/Tactic/SlimCheck.lean
+++ b/Mathlib/Tactic/SlimCheck.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Simon Hudon. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Simon Hudon, Scott Morrison
+Authors: Simon Hudon, Kim Morrison
-/
import Mathlib.Testing.SlimCheck.Testable
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 b370a472ffc45..54b458ff6ba3d 100644
--- a/Mathlib/Tactic/StacksAttribute.lean
+++ b/Mathlib/Tactic/StacksAttribute.lean
@@ -4,24 +4,37 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Damiano Testa
-/
import Lean.Elab.Command
+import Mathlib.Init
/-!
-# The `stacks` attribute
+# The `stacks` and `kerodon` attributes
-This allows tagging of mathlib lemmas with the corresponding
-[Tags](https://stacks.math.columbia.edu/tags) from the Stacks Project.
+This allows tagging of mathlib results with the corresponding
+tags from the [Stacks Project](https://stacks.math.columbia.edu/tags) and
+[Kerodon](https://kerodon.net/tag/).
+
+While the Stacks Project is the main focus, because the tag format at Kerodon is
+compatible, the attribute can be used to tag results with Kerodon tags as well.
-/
open Lean Elab
-namespace Mathlib.Stacks
+namespace Mathlib.StacksTag
+
+/-- Web database users of projects tags -/
+inductive Database where
+ | kerodon
+ | stacks
+ deriving BEq, Hashable
-/-- `Tag` is the structure that carries the data of a Stacks Projects tag and a corresponding
+/-- `Tag` is the structure that carries the data of a project tag and a corresponding
Mathlib declaration. -/
structure Tag where
/-- The name of the declaration with the given tag. -/
declName : Name
- /-- The Stacks Project tag. -/
+ /-- The online database where the tag is found. -/
+ database : Database
+ /-- The database tag. -/
tag : String
/-- The (optional) comment that comes with the given tag. -/
comment : String
@@ -40,8 +53,10 @@ initialize tagExt : SimplePersistentEnvExtension Tag (Std.HashSet Tag) ←
the `String`s `tag` and `comment` of the `stacks` attribute.
It extends the `Tag` environment extension with the data `declName, tag, comment`.
-/
-def addTagEntry {m : Type → Type} [MonadEnv m] (declName : Name) (tag comment : String) : m Unit :=
- modifyEnv (tagExt.addEntry · { declName := declName, tag := tag, comment := comment })
+def addTagEntry {m : Type → Type} [MonadEnv m]
+ (declName : Name) (db : Database) (tag comment : String) : m Unit :=
+ modifyEnv (tagExt.addEntry ·
+ { declName := declName, database := db, tag := tag, comment := comment })
open Parser
@@ -75,12 +90,12 @@ def stacksTagNoAntiquot : Parser := {
}
@[inherit_doc stacksTagFn]
-def stacksTag : Parser :=
+def stacksTagParser : Parser :=
withAntiquot (mkAntiquot "stacksTag" stacksTagKind) stacksTagNoAntiquot
-end Mathlib.Stacks
+end Mathlib.StacksTag
-open Mathlib.Stacks
+open Mathlib.StacksTag
/-- Extract the underlying tag as a string from a `stacksTag` node. -/
def Lean.TSyntax.getStacksTag (stx : TSyntax stacksTagKind) : CoreM String := do
@@ -104,54 +119,70 @@ namespace Parenthesizer
end Lean.PrettyPrinter.Parenthesizer
-namespace Mathlib.Stacks
+namespace Mathlib.StacksTag
+
+/-- The syntax category for the database name. -/
+declare_syntax_cat stacksTagDB
+
+/-- The syntax for a "kerodon" database identifier in a `@[kerodon]` attribute. -/
+syntax "kerodon" : stacksTagDB
+/-- The syntax for a "stacks" database identifier in a `@[stacks]` attribute. -/
+syntax "stacks" : stacksTagDB
+
+/-- The `stacksTag` attribute.
+Use it as `@[kerodon TAG "Optional comment"]` or `@[stacks TAG "Optional comment"]`
+depending on the database you are referencing.
-/-- The `stacks` attribute.
-Use it as `@[stacks TAG "Optional comment"]`.
The `TAG` is mandatory and should be a sequence of 4 digits or uppercase letters.
-See the [Tags page](https://stacks.math.columbia.edu/tags) in the Stacks project for more details.
+See the [Tags page](https://stacks.math.columbia.edu/tags) in the Stacks project or
+[Tags page](https://kerodon.net/tag/) in the Kerodon project for more details.
-/
-syntax (name := stacks) "stacks " stacksTag (ppSpace str)? : attr
+syntax (name := stacksTag) stacksTagDB stacksTagParser (ppSpace str)? : attr
initialize Lean.registerBuiltinAttribute {
- name := `stacks
- descr := "Apply a Stacks project tag to a theorem."
+ name := `stacksTag
+ descr := "Apply a Stacks or Kerodon project tag to a theorem."
add := fun decl stx _attrKind => match stx with
| `(attr| stacks $tag $[$comment]?) => do
- addTagEntry decl (← tag.getStacksTag) <| (comment.map (·.getString)).getD ""
+ addTagEntry decl .stacks (← tag.getStacksTag) <| (comment.map (·.getString)).getD ""
+ | `(attr| kerodon $tag $[$comment]?) => do
+ addTagEntry decl .kerodon (← tag.getStacksTag) <| (comment.map (·.getString)).getD ""
| _ => throwUnsupportedSyntax
}
-end Mathlib.Stacks
+end Mathlib.StacksTag
/--
`getSortedStackProjectTags env` returns the array of `Tags`, sorted by alphabetical order of tag.
-/
-def Lean.Environment.getSortedStackProjectTags (env : Environment) : Array Tag :=
+private def Lean.Environment.getSortedStackProjectTags (env : Environment) : Array Tag :=
tagExt.getState env |>.toArray.qsort (·.tag < ·.tag)
/--
`getSortedStackProjectDeclNames env tag` returns the array of declaration names of results
with Stacks Project tag equal to `tag`.
-/
-def Lean.Environment.getSortedStackProjectDeclNames (env : Environment) (tag : String) :
+private def Lean.Environment.getSortedStackProjectDeclNames (env : Environment) (tag : String) :
Array Name :=
let tags := env.getSortedStackProjectTags
tags.filterMap fun d => if d.tag == tag then some d.declName else none
-/--
-`#stacks_tags` retrieves all declarations that have the `stacks` attribute.
+namespace Mathlib.StacksTag
-For each found declaration, it prints a line
-```
-'declaration_name' corresponds to tag 'declaration_tag'.
-```
-The variant `#stacks_tags!` also adds the theorem statement after each summary line.
+private def databaseURL (db : Database) : String :=
+ match db with
+ | .kerodon => "https://kerodon.net/tag/"
+ | .stacks => "https://stacks.math.columbia.edu/tag/"
+
+/--
+`traceStacksTags db verbose` prints the tags of the database `db` to the user and
+inlines the theorem statements if `verbose` is `true`.
-/
-elab (name := Mathlib.Stacks.stacksTags) "#stacks_tags" tk:("!")?: command => do
+def traceStacksTags (db : Database) (verbose : Bool := false) :
+ Command.CommandElabM Unit := do
let env ← getEnv
- let entries := env.getSortedStackProjectTags
+ let entries := env.getSortedStackProjectTags |>.filter (·.database == db)
if entries.isEmpty then logInfo "No tags found." else
let mut msgs := #[m!""]
for d in entries do
@@ -159,10 +190,35 @@ elab (name := Mathlib.Stacks.stacksTags) "#stacks_tags" tk:("!")?: command => do
let (parL, parR) := if d.comment.isEmpty then ("", "") else (" (", ")")
let cmt := parL ++ d.comment ++ parR
msgs := msgs.push
- m!"[Stacks Tag {d.tag}](https://stacks.math.columbia.edu/tag/{d.tag}) \
+ m!"[Stacks Tag {d.tag}]({databaseURL db ++ d.tag}) \
corresponds to declaration '{dname}'.{cmt}"
- if tk.isSome then
+ if verbose then
let dType := ((env.find? dname).getD default).type
msgs := (msgs.push m!"{dType}").push ""
let msg := MessageData.joinSep msgs.toList "\n"
logInfo msg
+
+/--
+`#stacks_tags` retrieves all declarations that have the `stacks` attribute.
+
+For each found declaration, it prints a line
+```
+'declaration_name' corresponds to tag 'declaration_tag'.
+```
+The variant `#stacks_tags!` also adds the theorem statement after each summary line.
+-/
+elab (name := stacksTags) "#stacks_tags" tk:("!")?: command =>
+ traceStacksTags .stacks (tk.isSome)
+
+/-- The `#kerodon_tags` command retrieves all declarations that have the `kerodon` attribute.
+
+For each found declaration, it prints a line
+```
+'declaration_name' corresponds to tag 'declaration_tag'.
+```
+The variant `#kerodon_tags!` also adds the theorem statement after each summary line.
+-/
+elab (name := kerodonTags) "#kerodon_tags" tk:("!")?: command =>
+ traceStacksTags .kerodon (tk.isSome)
+
+end Mathlib.StacksTag
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 9d80c1c15e17a..3881cd09cfd2c 100644
--- a/Mathlib/Tactic/SuccessIfFailWithMsg.lean
+++ b/Mathlib/Tactic/SuccessIfFailWithMsg.lean
@@ -1,10 +1,11 @@
/-
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, Scott Morrison, Thomas Murrills
+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/TFAE.lean b/Mathlib/Tactic/TFAE.lean
index 6eaad297bad50..2a4ec7918e278 100644
--- a/Mathlib/Tactic/TFAE.lean
+++ b/Mathlib/Tactic/TFAE.lean
@@ -15,48 +15,108 @@ This file provides the tactics `tfae_have` and `tfae_finish` for proving goals o
`TFAE [P₁, P₂, ...]`.
-/
-open List Lean Meta Expr Elab.Term Elab.Tactic Mathlib.Tactic Qq
-
namespace Mathlib.Tactic.TFAE
-/-- An arrow of the form `←`, `→`, or `↔`. -/
-syntax impArrow := " → " <|> " ↔ " <|> " ← "
+/-! # Parsing and syntax
+
+We implement `tfae_have` in terms of a syntactic `have`. To support as much of the same syntax as
+possible, we recreate the parsers for `have`, except with the changes necessary for `tfae_have`.
+-/
+
+open Lean.Parser Term
+
+namespace Parser
+
+/- An arrow of the form `←`, `→`, or `↔`. -/
+private def impTo : Parser := leading_parser unicodeSymbol " → " " -> "
+private def impFrom : Parser := leading_parser unicodeSymbol " ← " " <- "
+private def impIff : Parser := leading_parser unicodeSymbol " ↔ " " <-> "
+private def impArrow : Parser := leading_parser impTo <|> impFrom <|> impIff
+
+/-- A `tfae_have` type specification, e.g. `1 ↔ 3` The numbers refer to the proposition at the
+corresponding position in the `TFAE` goal (starting at 1). -/
+private def tfaeType := leading_parser num >> impArrow >> num
+
+/-!
+The following parsers are similar to those for `have` in `Lean.Parser.Term`, but
+instead of `optType`, we use `tfaeType := num >> impArrow >> num` (as a `tfae_have` invocation must
+always include this specification). Also, we disallow including extra binders, as that makes no
+sense in this context; we also include `" : "` after the binder to avoid breaking `tfae_have 1 → 2`
+syntax (which, unlike `have`, omits `" : "`).
+-/
+
+/- See `haveIdLhs`.
+
+We omit `many (ppSpace >> letIdBinder)`, as it makes no sense to add extra arguments to a
+`tfae_have` decl. -/
+private def tfaeHaveIdLhs := leading_parser
+ ((ppSpace >> binderIdent >> " : ") <|> hygieneInfo) >> tfaeType
+/- See `haveIdDecl`. E.g. `h : 1 → 3 := term`. -/
+private def tfaeHaveIdDecl := leading_parser (withAnonymousAntiquot := false)
+ atomic (tfaeHaveIdLhs >> " := ") >> termParser
+/- See `haveEqnsDecl`. E.g. `h : 1 → 3 | p => f p`. -/
+private def tfaeHaveEqnsDecl := leading_parser (withAnonymousAntiquot := false)
+ tfaeHaveIdLhs >> matchAlts
+/- See `letPatDecl`. E.g. `⟨mp, mpr⟩ : 1 ↔ 3 := term`. -/
+private def tfaeHavePatDecl := leading_parser (withAnonymousAntiquot := false)
+ atomic (termParser >> pushNone >> " : " >> tfaeType >> " := ") >> termParser
+/- See `haveDecl`. Any of `tfaeHaveIdDecl`, `tfaeHavePatDecl`, or `tfaeHaveEqnsDecl`. -/
+private def tfaeHaveDecl := leading_parser (withAnonymousAntiquot := false)
+ tfaeHaveIdDecl <|> (ppSpace >> tfaeHavePatDecl) <|> tfaeHaveEqnsDecl
+
+end Parser
+
+open Parser
/--
`tfae_have` introduces hypotheses for proving goals of the form `TFAE [P₁, P₂, ...]`. Specifically,
-`tfae_have i arrow j` introduces a hypothesis of type `Pᵢ arrow Pⱼ` to the local context,
-where `arrow` can be `→`, `←`, or `↔`. Note that `i` and `j` are natural number indices (beginning
-at 1) used to specify the propositions `P₁, P₂, ...` that appear in the `TFAE` goal list. A proof
-is required afterward, typically via a tactic block.
+`tfae_have i j := ...` introduces a hypothesis of type `Pᵢ Pⱼ` to the local
+context, where `` can be `→`, `←`, or `↔`. Note that `i` and `j` are natural number indices
+(beginning at 1) used to specify the propositions `P₁, P₂, ...` that appear in the goal.
```lean
example (h : P → R) : TFAE [P, Q, R] := by
- tfae_have 1 → 3
- · exact h
+ tfae_have 1 → 3 := h
...
```
The resulting context now includes `tfae_1_to_3 : P → R`.
-The introduced hypothesis can be given a custom name, in analogy to `have` syntax:
+Once sufficient hypotheses have been introduced by `tfae_have`, `tfae_finish` can be used to close
+the goal. For example,
+
```lean
-tfae_have h : 2 ↔ 3
+example : TFAE [P, Q, R] := by
+ tfae_have 1 → 2 := sorry /- proof of P → Q -/
+ tfae_have 2 → 1 := sorry /- proof of Q → P -/
+ tfae_have 2 ↔ 3 := sorry /- proof of Q ↔ R -/
+ tfae_finish
```
-Once sufficient hypotheses have been introduced by `tfae_have`, `tfae_finish` can be used to close
-the goal.
+All relevant features of `have` are supported by `tfae_have`, including naming, destructuring, goal
+creation, and matching. These are demonstrated below.
```lean
-example : TFAE [P, Q, R] := by
+example : TFAE [P, Q] := by
+ -- `tfae_1_to_2 : P → Q`:
+ tfae_have 1 → 2 := sorry
+ -- `hpq : P → Q`:
+ tfae_have hpq : 1 → 2 := sorry
+ -- inaccessible `h✝ : P → Q`:
+ tfae_have _ : 1 → 2 := sorry
+ -- `tfae_1_to_2 : P → Q`, and `?a` is a new goal:
+ tfae_have 1 → 2 := f ?a
+ -- create a goal of type `P → Q`:
tfae_have 1 → 2
- · /- proof of P → Q -/
- tfae_have 2 → 1
- · /- proof of Q → P -/
- tfae_have 2 ↔ 3
- · /- proof of Q ↔ R -/
- tfae_finish
+ · exact (sorry : P → Q)
+ -- match on `p : P` and prove `Q`:
+ tfae_have 1 → 2
+ | p => f p
+ -- introduces `pq : P → Q`, `qp : Q → P`:
+ tfae_have ⟨pq, qp⟩ : 1 ↔ 2 := sorry
+ ...
```
-/
-syntax (name := tfaeHave) "tfae_have " (ident " : ")? num impArrow num : tactic
+syntax (name := tfaeHave) "tfae_have " tfaeHaveDecl : tactic
/--
`tfae_finish` is used to close goals of the form `TFAE [P₁, P₂, ...]` once a sufficient collection
@@ -67,19 +127,19 @@ of hypotheses of the form `Pᵢ → Pⱼ` or `Pᵢ ↔ Pⱼ` have been introduce
Example:
```lean
example : TFAE [P, Q, R] := by
- tfae_have 1 → 2
- · /- proof of P → Q -/
- tfae_have 2 → 1
- · /- proof of Q → P -/
- tfae_have 2 ↔ 3
- · /- proof of Q ↔ R -/
+ tfae_have 1 → 2 := sorry /- proof of P → Q -/
+ tfae_have 2 → 1 := sorry /- proof of Q → P -/
+ tfae_have 2 ↔ 3 := sorry /- proof of Q ↔ R -/
tfae_finish
```
-/
syntax (name := tfaeFinish) "tfae_finish" : tactic
+
/-! # Setup -/
+open List Lean Meta Expr Elab Tactic Mathlib.Tactic Qq
+
/-- Extract a list of `Prop` expressions from an expression of the form `TFAE [P₁, P₂, ...]` as
long as `[P₁, P₂, ...]` is an explicit list. -/
partial def getTFAEList (t : Expr) : MetaM (Q(List Prop) × List Q(Prop)) := do
@@ -159,62 +219,72 @@ def proveTFAE (is : List ℕ) (l : Q(List Prop)) : MetaM Q(TFAE $l) := do
/-! # `tfae_have` components -/
/-- Construct a name for a hypothesis introduced by `tfae_have`. -/
-def mkTFAEHypName (i j : TSyntax `num) (arr : TSyntax ``impArrow) : MetaM Name := do
- let arr ← match arr with
- | `(impArrow| ← ) => pure "from"
- | `(impArrow| → ) => pure "to"
- | `(impArrow| ↔ ) => pure "iff"
- | _ => throwErrorAt arr "expected '←', '→', or '↔'"
- return .mkSimple <| String.intercalate "_" ["tfae", s!"{i.getNat}", arr, s!"{j.getNat}"]
-
-open Elab in
-/-- The core of `tfae_have`, which behaves like `haveLetCore` in `Mathlib.Tactic.Have`. -/
-def tfaeHaveCore (goal : MVarId) (name : Option (TSyntax `ident)) (i j : TSyntax `num)
- (arrow : TSyntax ``impArrow) (t : Expr) : TermElabM (MVarId × MVarId) :=
- goal.withContext do
- let n := (Syntax.getId <$> name).getD <|← mkTFAEHypName i j arrow
- let (goal1, t, p) ← do
- let p ← mkFreshExprMVar t MetavarKind.syntheticOpaque n
- pure (p.mvarId!, t, p)
- let (fv, goal2) ← (← MVarId.assert goal n t p).intro1P
- if let some stx := name then
- goal2.withContext do
- Term.addTermInfo' (isBinder := true) stx (mkFVar fv)
- pure (goal1, goal2)
+def mkTFAEId : TSyntax ``tfaeType → MacroM Name
+ | `(tfaeType|$i:num $arr:impArrow $j:num) => do
+ let arr ← match arr with
+ | `(impArrow| ← ) => pure "from"
+ | `(impArrow| → ) => pure "to"
+ | `(impArrow| ↔ ) => pure "iff"
+ | _ => Macro.throwUnsupported
+ return .mkSimple <| String.intercalate "_" ["tfae", s!"{i.getNat}", arr, s!"{j.getNat}"]
+ | _ => Macro.throwUnsupported
/-- Turn syntax for a given index into a natural number, as long as it lies between `1` and
`maxIndex`. -/
-def elabIndex (i : TSyntax `num) (maxIndex : ℕ) : TacticM ℕ := do
+def elabIndex (i : TSyntax `num) (maxIndex : ℕ) : MetaM ℕ := do
let i' := i.getNat
- unless Nat.ble 1 i' && Nat.ble i' maxIndex do
- throwError "{i} must be between 1 and {maxIndex}"
+ unless 1 ≤ i' && i' ≤ maxIndex do
+ throwErrorAt i "{i} must be between 1 and {maxIndex}"
return i'
-/-- Construct an expression for the type `Pj → Pi`, `Pi → Pj`, or `Pi ↔ Pj` given expressions
-`Pi Pj : Q(Prop)` and `impArrow` syntax `arr`, depending on whether `arr` is `←`, `→`, or `↔`
-respectively. -/
-def mkImplType (Pi : Q(Prop)) (arr : TSyntax ``impArrow) (Pj : Q(Prop)) : MetaM Q(Prop) := do
- match arr with
- | `(impArrow| ← ) => pure q($Pj → $Pi)
- | `(impArrow| → ) => pure q($Pi → $Pj)
- | `(impArrow| ↔ ) => pure q($Pi ↔ $Pj)
- | _ => throwErrorAt arr "expected '←', '→', or '↔'"
-
/-! # Tactic implementation -/
-elab_rules : tactic
-| `(tactic| tfae_have $[$h:ident : ]? $i:num $arr:impArrow $j:num) => do
- let goal ← getMainGoal
- goal.withContext do
- let (_, tfaeList) ← getTFAEList (← goal.getType)
- let l₀ := tfaeList.length
- let i' ← elabIndex i l₀
- let j' ← elabIndex j l₀
+/-- Accesses the propositions at indices `i` and `j` of `tfaeList`, and constructs the expression
+`Pi Pj`, which will be the type of our `tfae_have` hypothesis -/
+def elabTFAEType (tfaeList : List Q(Prop)) : TSyntax ``tfaeType → TermElabM Expr
+ | stx@`(tfaeType|$i:num $arr:impArrow $j:num) => do
+ let l := tfaeList.length
+ let i' ← elabIndex i l
+ let j' ← elabIndex j l
let Pi := tfaeList.get! (i'-1)
let Pj := tfaeList.get! (j'-1)
- let type ← mkImplType Pi arr Pj
- let (goal1, goal2) ← tfaeHaveCore goal h i j arr type
- replaceMainGoal [goal1, goal2]
+ Term.addTermInfo' i Pi q(Prop)
+ Term.addTermInfo' j Pj q(Prop)
+ match arr with
+ | `(impArrow| ← ) => Term.addTermInfo stx q($Pj → $Pi) q(Prop)
+ | `(impArrow| → ) => Term.addTermInfo stx q($Pi → $Pj) q(Prop)
+ | `(impArrow| ↔ ) => Term.addTermInfo stx q($Pi ↔ $Pj) q(Prop)
+ | _ => throwUnsupportedSyntax
+ | _ => throwUnsupportedSyntax
+
+/- Convert `tfae_have i j ...` to `tfae_have tfae_i_arr_j : i j ...`. See
+`expandHave`, which is responsible for inserting `this` in `have : A := ...`. -/
+macro_rules
+| `(tfaeHave|tfae_have $hy:hygieneInfo $t:tfaeType := $val) => do
+ let id := HygieneInfo.mkIdent hy (← mkTFAEId t) (canonical := true)
+ `(tfaeHave|tfae_have $id : $t := $val)
+| `(tfaeHave|tfae_have $hy:hygieneInfo $t:tfaeType $alts:matchAlts) => do
+ let id := HygieneInfo.mkIdent hy (← mkTFAEId t) (canonical := true)
+ `(tfaeHave|tfae_have $id : $t $alts)
+
+open Term
+
+elab_rules : tactic
+| `(tfaeHave|tfae_have $d:tfaeHaveDecl) => withMainContext do
+ let goal ← getMainGoal
+ let (_, tfaeList) ← getTFAEList (← goal.getType)
+ withRef d do
+ match d with
+ | `(tfaeHaveDecl| $b : $t:tfaeType := $pf:term) =>
+ let type ← elabTFAEType tfaeList t
+ evalTactic <|← `(tactic|have $b : $(← exprToSyntax type) := $pf)
+ | `(tfaeHaveDecl| $b : $t:tfaeType $alts:matchAlts) =>
+ let type ← elabTFAEType tfaeList t
+ evalTactic <|← `(tactic|have $b : $(← exprToSyntax type) $alts:matchAlts)
+ | `(tfaeHaveDecl| $pat:term : $t:tfaeType := $pf:term) =>
+ let type ← elabTFAEType tfaeList t
+ evalTactic <|← `(tactic|have $pat:term : $(← exprToSyntax type) := $pf)
+ | _ => throwUnsupportedSyntax
elab_rules : tactic
| `(tactic| tfae_finish) => do
@@ -225,7 +295,7 @@ elab_rules : tactic
let is ← tfaeList.mapM AtomM.addAtom
let mut hyps := #[]
for hyp in ← getLocalHyps do
- let ty ← inferType hyp
+ let ty ← whnfR <|← instantiateMVars <|← inferType hyp
if let (``Iff, #[p1, p2]) := ty.getAppFnArgs then
let q1 ← AtomM.addAtom p1
let q2 ← AtomM.addAtom p2
@@ -237,6 +307,39 @@ elab_rules : tactic
hyps := hyps.push (q1, q2, hyp)
proveTFAE hyps (← get).atoms is tfaeListQ
+/-!
+
+# "Old-style" `tfae_have`
+
+We preserve the "old-style" `tfae_have` (which behaves like Mathlib `have`) for compatibility
+purposes.
+
+-/
+
+@[inherit_doc tfaeHave]
+syntax (name := tfaeHave') "tfae_have " tfaeHaveIdLhs : tactic
+
+macro_rules
+| `(tfaeHave'|tfae_have $hy:hygieneInfo $t:tfaeType) => do
+ let id := HygieneInfo.mkIdent hy (← mkTFAEId t) (canonical := true)
+ `(tfaeHave'|tfae_have $id : $t)
+
+elab_rules : tactic
+| `(tfaeHave'|tfae_have $d:tfaeHaveIdLhs) => withMainContext do
+ let goal ← getMainGoal
+ let (_, tfaeList) ← getTFAEList (← goal.getType)
+ -- Note that due to the macro above, the following match is exhaustive.
+ match d with
+ | `(tfaeHaveIdLhs| $b:ident : $t:tfaeType) =>
+ let n := b.getId
+ let type ← elabTFAEType tfaeList t
+ let p ← mkFreshExprMVar type MetavarKind.syntheticOpaque n
+ let (fv, mainGoal) ← (← MVarId.assert goal n type p).intro1P
+ mainGoal.withContext do
+ Term.addTermInfo' (isBinder := true) b (mkFVar fv)
+ replaceMainGoal [p.mvarId!, mainGoal]
+ | _ => throwUnsupportedSyntax
+
end TFAE
end 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 3c57fb543a3b6..8997800729532 100644
--- a/Mathlib/Tactic/ToExpr.lean
+++ b/Mathlib/Tactic/ToExpr.lean
@@ -16,7 +16,7 @@ that come from core Lean 4 that do not handle universe polymorphism.
In addition, we provide some additional `ToExpr` instances for core definitions.
-/
-section override
+section override -- Note: this section uses `autoImplicit` pervasively
namespace Lean
attribute [-instance] Lean.instToExprOption
@@ -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/WLOG.lean b/Mathlib/Tactic/WLOG.lean
index c996e5552b6df..461949d04ab7b 100644
--- a/Mathlib/Tactic/WLOG.lean
+++ b/Mathlib/Tactic/WLOG.lean
@@ -86,7 +86,8 @@ def _root_.Lean.MVarId.wlog (goal : MVarId) (h : Option Name) (P : Expr)
let hGoal := HExpr.mvarId!
/- Begin the "reduction goal" which will contain hypotheses `H` and `¬h`. For now, it only
contains `H`. Keep track of that hypothesis' FVarId. -/
- let (HFVarId, reductionGoal) ← goal.assertHypotheses #[⟨H, HType, HExpr⟩]
+ let (HFVarId, reductionGoal) ←
+ goal.assertHypotheses #[{ userName := H, type := HType, value := HExpr }]
let HFVarId := HFVarId[0]!
/- Clear the reverted fvars from the branch that will contain `h` as a hypothesis. -/
let hGoal ← hGoal.tryClearMany revertedFVars
diff --git a/Mathlib/Tactic/Widget/Calc.lean b/Mathlib/Tactic/Widget/Calc.lean
index bbcba1e9996ae..5e39f560b44b2 100644
--- a/Mathlib/Tactic/Widget/Calc.lean
+++ b/Mathlib/Tactic/Widget/Calc.lean
@@ -17,7 +17,7 @@ new calc steps with holes specified by selected sub-expressions in the goal.
-/
section code_action
-open Std CodeAction
+open Batteries.CodeAction
open Lean Server RequestM
/-- Code action to create a `calc` tactic from the current goal. -/
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 2f784b24ccc24..c2745df6eff9a 100644
--- a/Mathlib/Tactic/Widget/StringDiagram.lean
+++ b/Mathlib/Tactic/Widget/StringDiagram.lean
@@ -6,7 +6,9 @@ Authors: Yuma Mizuno
import ProofWidgets.Component.PenroseDiagram
import ProofWidgets.Component.Panel.Basic
import ProofWidgets.Presentation.Expr
-import Mathlib.Tactic.CategoryTheory.Monoidal
+import ProofWidgets.Component.HtmlDisplay
+import Mathlib.Tactic.CategoryTheory.Bicategory.Normalize
+import Mathlib.Tactic.CategoryTheory.Monoidal.Normalize
/-!
# String Diagram Widget
@@ -21,6 +23,12 @@ show_panel_widgets [local StringDiagram]
```
to enable the string diagram widget in the current section.
+We also have the `#string_diagram` command. For example,
+```lean
+#string_diagram MonoidalCategory.whisker_exchange
+```
+displays the string diagram for the exchange law of the left and right whiskerings.
+
String diagrams are graphical representations of morphisms in monoidal categories, which are
useful for rewriting computations. More precisely, objects in a monoidal category is represented
by strings, and morphisms between two objects is represented by nodes connecting two strings
@@ -55,10 +63,12 @@ namespace Mathlib.Tactic
open Lean Meta Elab
open CategoryTheory
-open Mathlib.Tactic.Monoidal
+open BicategoryLike
namespace Widget.StringDiagram
+initialize registerTraceClass `string_diagram
+
/-! ## Objects in string diagrams -/
/-- Nodes for 2-morphisms in a string diagram. -/
@@ -95,15 +105,15 @@ def Node.e : Node → Expr
/-- The domain of the 2-morphism associated with a node as a list
(the first component is the node itself). -/
-def Node.srcList : Node → MetaM (List (Node × Atom₁))
- | Node.atom n => return (← n.atom.src).toList.map (fun f ↦ (.atom n, f))
- | Node.id n => return [(.id n, n.id)]
+def Node.srcList : Node → List (Node × Atom₁)
+ | Node.atom n => n.atom.src.toList.map (fun f ↦ (.atom n, f))
+ | Node.id n => [(.id n, n.id)]
/-- The codomain of the 2-morphism associated with a node as a list
(the first component is the node itself). -/
-def Node.tarList : Node → MetaM (List (Node × Atom₁))
- | Node.atom n => return (← n.atom.tgt).toList.map (fun f ↦ (.atom n, f))
- | Node.id n => return [(.id n, n.id)]
+def Node.tarList : Node → List (Node × Atom₁)
+ | Node.atom n => n.atom.tgt.toList.map (fun f ↦ (.atom n, f))
+ | Node.id n => [(.id n, n.id)]
/-- The vertical position of a node in a string diagram. -/
def Node.vPos : Node → ℕ
@@ -120,10 +130,6 @@ def Node.hPosTar : Node → ℕ
| Node.atom n => n.hPosTar
| Node.id n => n.hPosTar
-/-- The list of nodes at the top of a string diagram. -/
-def topNodes (η : WhiskerLeftExpr) : MetaM (List Node) := do
- return (← η.src).toList.enum.map (fun (i, f) => .id ⟨0, i, i, f⟩)
-
/-- Strings in a string diagram. -/
structure Strand : Type where
/-- The horizontal position of the strand in the string diagram. -/
@@ -141,62 +147,79 @@ def Strand.vPos (s : Strand) : ℕ :=
end Widget.StringDiagram
-namespace Monoidal
+namespace BicategoryLike
open Widget.StringDiagram
/-- The list of nodes associated with a 2-morphism. The position is counted from the
specified natural numbers. -/
-def WhiskerRightExpr.nodes (v h₁ h₂ : ℕ) : WhiskerRightExpr → MetaM (List Node)
- | WhiskerRightExpr.of η => do
- return [.atom ⟨v, h₁, h₂, η⟩]
- | WhiskerRightExpr.whisker η f => do
- let ηs ← η.nodes v h₁ h₂
- let k₁ := (← ηs.mapM (fun n ↦ n.srcList)).join.length
- let k₂ := (← ηs.mapM (fun n ↦ n.tarList)).join.length
+def WhiskerRight.nodes (v h₁ h₂ : ℕ) : WhiskerRight → List Node
+ | WhiskerRight.of η => [.atom ⟨v, h₁, h₂, η⟩]
+ | WhiskerRight.whisker _ η f =>
+ let ηs := η.nodes v h₁ h₂
+ let k₁ := (ηs.map (fun n ↦ n.srcList)).join.length
+ let k₂ := (ηs.map (fun n ↦ n.tarList)).join.length
let s : Node := .id ⟨v, h₁ + k₁, h₂ + k₂, f⟩
- return ηs ++ [s]
+ ηs ++ [s]
/-- The list of nodes associated with a 2-morphism. The position is counted from the
specified natural numbers. -/
-def WhiskerLeftExpr.nodes (v h₁ h₂ : ℕ) : WhiskerLeftExpr → MetaM (List Node)
- | WhiskerLeftExpr.of η => η.nodes v h₁ h₂
- | WhiskerLeftExpr.whisker f η => do
+def HorizontalComp.nodes (v h₁ h₂ : ℕ) : HorizontalComp → List Node
+ | HorizontalComp.of η => η.nodes v h₁ h₂
+ | HorizontalComp.cons _ η ηs =>
+ let s₁ := η.nodes v h₁ h₂
+ let k₁ := (s₁.map (fun n ↦ n.srcList)).join.length
+ let k₂ := (s₁.map (fun n ↦ n.tarList)).join.length
+ let s₂ := ηs.nodes v (h₁ + k₁) (h₂ + k₂)
+ s₁ ++ s₂
+
+/-- The list of nodes associated with a 2-morphism. The position is counted from the
+specified natural numbers. -/
+def WhiskerLeft.nodes (v h₁ h₂ : ℕ) : WhiskerLeft → List Node
+ | WhiskerLeft.of η => η.nodes v h₁ h₂
+ | WhiskerLeft.whisker _ f η =>
let s : Node := .id ⟨v, h₁, h₂, f⟩
- let ss ← η.nodes v (h₁ + 1) (h₂ + 1)
- return s :: ss
+ let ss := η.nodes v (h₁ + 1) (h₂ + 1)
+ s :: ss
+
+variable {ρ : Type} [MonadMor₁ (CoherenceM ρ)]
+
+/-- The list of nodes at the top of a string diagram. -/
+def topNodes (η : WhiskerLeft) : CoherenceM ρ (List Node) := do
+ return (← η.srcM).toList.enum.map (fun (i, f) => .id ⟨0, i, i, f⟩)
/-- The list of nodes at the top of a string diagram. The position is counted from the
specified natural number. -/
-def NormalExpr.nodesAux (v : ℕ) : NormalExpr → MetaM (List (List Node))
- | NormalExpr.nil α => return [(α.src).toList.enum.map (fun (i, f) => .id ⟨v, i, i, f⟩)]
- | NormalExpr.cons _ η ηs => do
- let s₁ ← η.nodes v 0 0
+def NormalExpr.nodesAux (v : ℕ) : NormalExpr → CoherenceM ρ (List (List Node))
+ | NormalExpr.nil _ α => return [(← α.srcM).toList.enum.map (fun (i, f) => .id ⟨v, i, i, f⟩)]
+ | NormalExpr.cons _ _ η ηs => do
+ let s₁ := η.nodes v 0 0
let s₂ ← ηs.nodesAux (v + 1)
return s₁ :: s₂
/-- The list of nodes associated with a 2-morphism. -/
-def NormalExpr.nodes (e : NormalExpr) : MetaM (List (List Node)) := do
+def NormalExpr.nodes (e : NormalExpr) : CoherenceM ρ (List (List Node)) :=
match e with
- | NormalExpr.nil _ => return []
- | NormalExpr.cons _ η _ => return (← topNodes η) :: (← e.nodesAux 1)
+ | NormalExpr.nil _ _ => return []
+ | NormalExpr.cons _ _ η _ => return (← topNodes η) :: (← e.nodesAux 1)
/-- `pairs [a, b, c, d]` is `[(a, b), (b, c), (c, d)]`. -/
def pairs {α : Type} : List α → List (α × α) :=
fun l => l.zip (l.drop 1)
/-- The list of strands associated with a 2-morphism. -/
-def NormalExpr.strands (e : NormalExpr) : MetaM (List (List Strand)) := do
+def NormalExpr.strands (e : NormalExpr) : CoherenceM ρ (List (List Strand)) := do
let l ← e.nodes
(pairs l).mapM fun (x, y) ↦ do
- let xs := (← x.mapM (fun n ↦ n.tarList)).join
- let ys := (← y.mapM (fun n ↦ n.srcList)).join
+ let xs := (x.map (fun n ↦ n.tarList)).join
+ let ys := (y.map (fun n ↦ n.srcList)).join
+ -- sanity check
if xs.length ≠ ys.length then
throwError "The number of the start and end points of a string does not match."
(xs.zip ys).enum.mapM fun (k, (n₁, f₁), (n₂, _)) => do
return ⟨n₁.hPosTar + k, n₁, n₂, f₁⟩
-end Monoidal
+end BicategoryLike
namespace Widget.StringDiagram
@@ -240,9 +263,8 @@ def addConstructor (tp : String) (v : PenroseVar) (nm : String) (vs : List Penro
open scoped Jsx in
/-- Construct a string diagram from a Penrose `sub`stance program and expressions `embeds` to
display as labels in the diagram. -/
-def mkStringDiagram (e : NormalExpr) : DiagramBuilderM PUnit := do
- let nodes ← e.nodes
- let strands ← e.strands
+def mkStringDiagram (nodes : List (List Node)) (strands : List (List Strand)) :
+ DiagramBuilderM PUnit := do
/- Add 2-morphisms. -/
for x in nodes.join do
match x with
@@ -271,21 +293,59 @@ def dsl :=
def sty :=
include_str ".."/".."/".."/"widget"/"src"/"penrose"/"monoidal.sty"
-open scoped Jsx in
-/-- Construct a string diagram from the expression of a 2-morphism. -/
-def fromExpr (e : Expr) : MonoidalM Html := do
- let e' := (← eval e).expr
- DiagramBuilderM.run do
- mkStringDiagram e'
- match ← DiagramBuilderM.buildDiagram dsl sty with
- | some html => return html
- | none => return No non-structural morphisms found.
+/-- The kind of the context. -/
+inductive Kind where
+ | monoidal : Kind
+ | bicategory : Kind
+ | none : Kind
+
+/-- The name of the context. -/
+def Kind.name : Kind → Name
+ | Kind.monoidal => `monoidal
+ | Kind.bicategory => `bicategory
+ | Kind.none => default
+
+/-- Given an expression, return the kind of the context. -/
+def mkKind (e : Expr) : MetaM Kind := do
+ let e ← instantiateMVars e
+ let e ← (match (← whnfR e).eq? with
+ | some (_, lhs, _) => return lhs
+ | none => return e)
+ let ctx? ← BicategoryLike.mkContext? (ρ := Bicategory.Context) e
+ match ctx? with
+ | .some _ => return .bicategory
+ | .none =>
+ let ctx? ← BicategoryLike.mkContext? (ρ := Monoidal.Context) e
+ match ctx? with
+ | .some _ => return .monoidal
+ | .none => return .none
+open scoped Jsx in
/-- Given a 2-morphism, return a string diagram. Otherwise `none`. -/
def stringM? (e : Expr) : MetaM (Option Html) := do
let e ← instantiateMVars e
- let some ctx ← mkContext? e | return none
- return some <| ← MonoidalM.run ctx <| fromExpr e
+ let k ← mkKind e
+ let x : Option (List (List Node) × List (List Strand)) ← (match k with
+ | .monoidal => do
+ let .some ctx ← BicategoryLike.mkContext? (ρ := Monoidal.Context) e | return .none
+ CoherenceM.run (ctx := ctx) do
+ let e' := (← BicategoryLike.eval k.name (← MkMor₂.ofExpr e)).expr
+ return .some (← e'.nodes, ← e'.strands)
+ | .bicategory => do
+ let .some ctx ← BicategoryLike.mkContext? (ρ := Bicategory.Context) e | return .none
+ CoherenceM.run (ctx := ctx) do
+ let e' := (← BicategoryLike.eval k.name (← MkMor₂.ofExpr e)).expr
+ return .some (← e'.nodes, ← e'.strands)
+ | .none => return .none)
+ match x with
+ | .none => return none
+ | .some (nodes, strands) => do
+ DiagramBuilderM.run do
+ mkStringDiagram nodes strands
+ trace[string_diagram] "Penrose substance: \n{(← get).sub}"
+ match ← DiagramBuilderM.buildDiagram dsl sty with
+ | some html => return html
+ | none => return No non-structural morphisms found.
open scoped Jsx in
/-- Help function for displaying two string diagrams in an equality. -/
@@ -315,12 +375,13 @@ def stringEqM? (e : Expr) : MetaM (Option Html) := do
/-- Given an 2-morphism or equality between 2-morphisms, return a string diagram.
Otherwise `none`. -/
def stringMorOrEqM? (e : Expr) : MetaM (Option Html) := do
- if let some html ← stringM? e then
- return some html
- else if let some html ← stringEqM? e then
- return some html
- else
- return none
+ forallTelescopeReducing (← inferType e) fun xs a => do
+ if let some html ← stringM? (mkAppN e xs) then
+ return some html
+ else if let some html ← stringEqM? a then
+ return some html
+ else
+ return none
/-- The `Expr` presenter for displaying string diagrams. -/
@[expr_presenter]
@@ -358,4 +419,36 @@ open ProofWidgets
def StringDiagram : Component PanelWidgetProps :=
mk_rpc_widget% StringDiagram.rpc
+open Command
+
+/--
+Display the string diagram for a given term.
+
+Example usage:
+```
+/- String diagram for the equality theorem. -/
+#string_diagram MonoidalCategory.whisker_exchange
+
+/- String diagram for the morphism. -/
+variable {C : Type u} [Category.{v} C] [MonoidalCategory C] {X Y : C} (f : 𝟙_ C ⟶ X ⊗ Y) in
+#string_diagram f
+```
+-/
+syntax (name := stringDiagram) "#string_diagram " term : command
+
+@[command_elab stringDiagram, inherit_doc stringDiagram]
+def elabStringDiagramCmd : CommandElab := fun
+ | stx@`(#string_diagram $t:term) => do
+ let html ← runTermElabM fun _ => do
+ let e ← try mkConstWithFreshMVarLevels (← realizeGlobalConstNoOverloadWithInfo t)
+ catch _ => Term.levelMVarToParam (← instantiateMVars (← Term.elabTerm t none))
+ match ← StringDiagram.stringMorOrEqM? e with
+ | .some html => return html
+ | .none => throwError "could not find a morphism or equality: {e}"
+ liftCoreM <| Widget.savePanelWidgetInfo
+ (hash HtmlDisplay.javascript)
+ (return json% { html: $(← Server.RpcEncodable.rpcEncode html) })
+ stx
+ | stx => throwError "Unexpected syntax {stx}."
+
end Mathlib.Tactic.Widget
diff --git a/Mathlib/Testing/SlimCheck/Functions.lean b/Mathlib/Testing/SlimCheck/Functions.lean
index ddc576d88d833..7b73daf4bdbcb 100644
--- a/Mathlib/Testing/SlimCheck/Functions.lean
+++ b/Mathlib/Testing/SlimCheck/Functions.lean
@@ -177,8 +177,7 @@ def applyFinsupp (tf : TotalFunction α β) : α →₀ β where
· intro h
use (A.dlookup a).getD (0 : β)
rw [← List.dlookup_dedupKeys] at h ⊢
- simp only [h, ← List.mem_dlookup_iff A.nodupKeys_dedupKeys, and_true_iff, not_false_iff,
- Option.mem_def]
+ simp only [h, ← List.mem_dlookup_iff A.nodupKeys_dedupKeys, not_false_iff, Option.mem_def]
cases haA : List.dlookup a A.dedupKeys
· simp [haA] at h
· simp
@@ -290,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
@@ -324,14 +323,14 @@ theorem applyId_mem_iff [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs
dsimp [List.dlookup] at h₃; split_ifs at h₃ with h
· rw [Option.some_inj] at h₃
subst x'; subst val
- simp only [List.mem_cons, true_or_iff, eq_self_iff_true]
+ simp only [List.mem_cons, true_or, eq_self_iff_true]
· cases' h₀ with _ _ h₀ h₅
cases' h₂ with _ _ h₂ h₄
have h₆ := Nat.succ.inj h₁
specialize xs_ih h₅ h₃ h₄ h₆
- simp only [Ne.symm h, xs_ih, List.mem_cons, false_or_iff]
+ 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
@@ -364,7 +363,7 @@ theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup
· symm; rw [h]
rw [← List.applyId_zip_eq] <;> assumption
· rw [← h₁.length_eq]
- rw [List.getElem?_eq_some] at hx
+ rw [List.getElem?_eq_some_iff] at hx
cases' hx with hx hx'
exact hx
· rw [← applyId_mem_iff h₀ h₁] at hx hy
@@ -424,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)
@@ -454,7 +453,7 @@ protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Inject
induction xs with
| nil => simp only [List.zip_nil_right, List.map_nil]
| cons xs_hd xs_tl xs_ih =>
- simp only [true_and_iff, Prod.toSigma, eq_self_iff_true, Sigma.eta, List.zip_cons_cons,
+ simp only [Prod.toSigma, eq_self_iff_true, Sigma.eta, List.zip_cons_cons,
List.map, List.cons_inj_right]
exact xs_ih
revert hperm hnodup
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 a754e4fc9b10d..aceac53facf2d 100644
--- a/Mathlib/Topology/AlexandrovDiscrete.lean
+++ b/Mathlib/Topology/AlexandrovDiscrete.lean
@@ -6,7 +6,7 @@ Authors: Yaël Dillies
import Mathlib.Data.Set.Image
import Mathlib.Topology.Bases
import Mathlib.Topology.Inseparable
-import Mathlib.Topology.Compactness.Compact
+import Mathlib.Topology.Compactness.Exterior
/-!
# Alexandrov-discrete topological spaces
@@ -20,8 +20,6 @@ minimal neighborhood, which we call the *exterior* of the set.
## Main declarations
* `AlexandrovDiscrete`: Prop-valued typeclass for a topological space to be Alexandrov-discrete
-* `exterior`: Intersection of all neighborhoods of a set. When the space is Alexandrov-discrete,
- this is the minimal neighborhood of the set.
## Notes
@@ -116,46 +114,7 @@ lemma closure_sUnion (S : Set (Set α)) : closure (⋃₀ S) = ⋃ s ∈ S, clos
end AlexandrovDiscrete
-variable {s t : Set α} {a x y : α}
-
-/-- The *exterior* of a set is the intersection of all its neighborhoods. In an Alexandrov-discrete
-space, this is the smallest neighborhood of the set.
-
-Note that this construction is unnamed in the literature. We choose the name in analogy to
-`interior`. -/
-def exterior (s : Set α) : Set α := (𝓝ˢ s).ker
-
-lemma exterior_singleton_eq_ker_nhds (a : α) : exterior {a} = (𝓝 a).ker := by simp [exterior]
-
-lemma exterior_def (s : Set α) : exterior s = ⋂₀ {t : Set α | IsOpen t ∧ s ⊆ t} :=
- (hasBasis_nhdsSet _).ker.trans sInter_eq_biInter.symm
-
-lemma mem_exterior : a ∈ exterior s ↔ ∀ U, IsOpen U → s ⊆ U → a ∈ U := by simp [exterior_def]
-
-lemma subset_exterior_iff : s ⊆ exterior t ↔ ∀ U, IsOpen U → t ⊆ U → s ⊆ U := by
- simp [exterior_def]
-
-lemma subset_exterior : s ⊆ exterior s := subset_exterior_iff.2 fun _ _ ↦ id
-
-lemma exterior_minimal (h₁ : s ⊆ t) (h₂ : IsOpen t) : exterior s ⊆ t := by
- rw [exterior_def]; exact sInter_subset_of_mem ⟨h₂, h₁⟩
-
-lemma IsOpen.exterior_eq (h : IsOpen s) : exterior s = s :=
- (exterior_minimal Subset.rfl h).antisymm subset_exterior
-
-lemma IsOpen.exterior_subset_iff (ht : IsOpen t) : exterior s ⊆ t ↔ s ⊆ t :=
- ⟨subset_exterior.trans, fun h ↦ exterior_minimal h ht⟩
-
-@[mono] lemma exterior_mono : Monotone (exterior : Set α → Set α) :=
- fun _s _t h ↦ ker_mono <| nhdsSet_mono h
-
-@[simp] lemma exterior_empty : exterior (∅ : Set α) = ∅ := isOpen_empty.exterior_eq
-@[simp] lemma exterior_univ : exterior (univ : Set α) = univ := isOpen_univ.exterior_eq
-
-@[simp] lemma exterior_eq_empty : exterior s = ∅ ↔ s = ∅ :=
- ⟨eq_bot_mono subset_exterior, by rintro rfl; exact exterior_empty⟩
-
-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 ⊢
@@ -163,20 +122,9 @@ lemma Inducing.alexandrovDiscrete [AlexandrovDiscrete α] {f : β → α} (h : I
refine ⟨_, isOpen_iInter₂ hU, ?_⟩
simp_rw [preimage_iInter, htU, sInter_eq_biInter]
-lemma IsOpen.exterior_subset (ht : IsOpen t) : exterior s ⊆ t ↔ s ⊆ t :=
- ⟨subset_exterior.trans, fun h ↦ exterior_minimal h ht⟩
-
-lemma Set.Finite.isCompact_exterior (hs : s.Finite) : IsCompact (exterior s) := by
- classical
- refine isCompact_of_finite_subcover fun f hf hsf ↦ ?_
- choose g hg using fun a (ha : a ∈ exterior s) ↦ mem_iUnion.1 (hsf ha)
- refine ⟨hs.toFinset.attach.image fun a ↦
- g a.1 <| subset_exterior <| (Finite.mem_toFinset _).1 a.2,
- (isOpen_iUnion fun i ↦ isOpen_iUnion ?_).exterior_subset.2 ?_⟩
- · exact fun _ ↦ hf _
- refine fun a ha ↦ mem_iUnion₂.2 ⟨_, ?_, hg _ <| subset_exterior ha⟩
- simp only [Finset.mem_image, Finset.mem_attach, true_and, Subtype.exists, Finite.mem_toFinset]
- exact ⟨a, ha, rfl⟩
+@[deprecated (since := "2024-10-28")]
+alias Inducing.alexandrovDiscrete := IsInducing.alexandrovDiscrete
+
end
lemma AlexandrovDiscrete.sup {t₁ t₂ : TopologicalSpace α} (_ : @AlexandrovDiscrete α t₁)
@@ -194,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
@@ -220,50 +168,28 @@ lemma exterior_singleton_subset_iff_mem_nhds : exterior {a} ⊆ t ↔ t ∈ 𝓝
lemma gc_exterior_interior : GaloisConnection (exterior : Set α → Set α) interior :=
fun s t ↦ by simp [exterior_subset_iff, subset_interior_iff]
-@[simp] lemma exterior_exterior (s : Set α) : exterior (exterior s) = exterior s :=
- isOpen_exterior.exterior_eq
-
-@[simp] lemma exterior_union (s t : Set α) : exterior (s ∪ t) = exterior s ∪ exterior t :=
- gc_exterior_interior.l_sup
-
-@[simp] lemma nhdsSet_exterior (s : Set α) : 𝓝ˢ (exterior s) = 𝓝ˢ s := by
- ext t; simp_rw [← exterior_subset_iff_mem_nhdsSet, exterior_exterior]
-
@[simp] lemma principal_exterior (s : Set α) : 𝓟 (exterior s) = 𝓝ˢ s := by
rw [← nhdsSet_exterior, isOpen_exterior.nhdsSet_eq]
-@[simp] lemma exterior_subset_exterior : exterior s ⊆ exterior t ↔ 𝓝ˢ s ≤ 𝓝ˢ t := by
- refine ⟨?_, fun h ↦ ker_mono h⟩
- simp_rw [le_def, ← exterior_subset_iff_mem_nhdsSet]
- exact fun h u ↦ h.trans
-
-lemma specializes_iff_exterior_subset : x ⤳ y ↔ exterior {x} ⊆ exterior {y} := by
- simp [Specializes]
-
lemma isOpen_iff_forall_specializes : IsOpen s ↔ ∀ x y, x ⤳ y → y ∈ s → x ∈ s := by
- refine ⟨fun hs x y hxy ↦ hxy.mem_open hs, fun hs ↦ ?_⟩
- simp_rw [specializes_iff_exterior_subset] at hs
- simp_rw [isOpen_iff_mem_nhds, mem_nhds_iff]
- rintro a ha
- refine ⟨_, fun b hb ↦ hs _ _ ?_ ha, isOpen_exterior, subset_exterior <| mem_singleton _⟩
- rwa [isOpen_exterior.exterior_subset, singleton_subset_iff]
+ simp only [← exterior_subset_iff_isOpen, Set.subset_def, mem_exterior_iff_specializes, exists_imp,
+ and_imp, @forall_swap (_ ⤳ _)]
lemma alexandrovDiscrete_coinduced {β : Type*} {f : α → β} :
@AlexandrovDiscrete β (coinduced f ‹_›) :=
@AlexandrovDiscrete.mk β (coinduced f ‹_›) fun S hS ↦ by
rw [isOpen_coinduced, preimage_sInter]; exact isOpen_iInter₂ hS
-
instance AlexandrovDiscrete.toFirstCountable : FirstCountableTopology α where
nhds_generated_countable a := ⟨{exterior {a}}, countable_singleton _, by simp⟩
instance AlexandrovDiscrete.toLocallyCompactSpace : LocallyCompactSpace α where
local_compact_nhds a _U hU := ⟨exterior {a},
isOpen_exterior.mem_nhds <| subset_exterior <| mem_singleton _,
- exterior_singleton_subset_iff_mem_nhds.2 hU, (finite_singleton _).isCompact_exterior⟩
+ 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/Algebra.lean b/Mathlib/Topology/Algebra/Algebra.lean
index bcc728324280b..367ba0a65e42e 100644
--- a/Mathlib/Topology/Algebra/Algebra.lean
+++ b/Mathlib/Topology/Algebra/Algebra.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Antoine Chambert-Loir, María Inés de Frutos-Fernández
+Authors: Kim Morrison, Antoine Chambert-Loir, María Inés de Frutos-Fernández
-/
import Mathlib.Algebra.Algebra.Subalgebra.Basic
import Mathlib.Topology.Algebra.Module.Basic
diff --git a/Mathlib/Topology/Algebra/Algebra/Rat.lean b/Mathlib/Topology/Algebra/Algebra/Rat.lean
index d63250277c31e..212c43adc23f5 100644
--- a/Mathlib/Topology/Algebra/Algebra/Rat.lean
+++ b/Mathlib/Topology/Algebra/Algebra/Rat.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Algebra.Rat
import Mathlib.Topology.Algebra.Monoid
diff --git a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean
new file mode 100644
index 0000000000000..803016fe59879
--- /dev/null
+++ b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean
@@ -0,0 +1,261 @@
+/-
+Copyright (c) 2024 Jujian Zhang. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Jujian Zhang, Nailin Guan, Yuyang Zhao
+-/
+import Mathlib.Algebra.Category.Grp.FiniteGrp
+import Mathlib.Topology.Algebra.ClosedSubgroup
+import Mathlib.Topology.Algebra.ContinuousMonoidHom
+import Mathlib.Topology.Category.Profinite.Basic
+/-!
+
+# Category of Profinite Groups
+
+We say `G` is a profinite group if it is a topological group which is compact and totally
+disconnected.
+
+## Main definitions and results
+
+* `ProfiniteGrp` is the category of profinite groups.
+
+* `ProfiniteGrp.pi` : The pi-type of profinite groups is also a profinite group.
+
+* `ofFiniteGrp` : A `FiniteGrp` when given the discrete topology can be considered as a
+ profinite group.
+
+* `ofClosedSubgroup` : A closed subgroup of a profinite group is profinite.
+
+-/
+
+universe u v
+
+open CategoryTheory Topology
+
+/--
+The category of profinite groups. A term of this type consists of a profinite
+set with a topological group structure.
+-/
+@[pp_with_univ]
+structure ProfiniteGrp where
+ /-- The underlying profinite topological space. -/
+ toProfinite : Profinite
+ /-- The group structure. -/
+ [group : Group toProfinite]
+ /-- The above data together form a topological group. -/
+ [topologicalGroup : TopologicalGroup toProfinite]
+
+/--
+The category of profinite additive groups. A term of this type consists of a profinite
+set with a topological additive group structure.
+-/
+@[pp_with_univ]
+structure ProfiniteAddGrp where
+ /-- The underlying profinite topological space. -/
+ toProfinite : Profinite
+ /-- The additive group structure. -/
+ [addGroup : AddGroup toProfinite]
+ /-- The above data together form a topological additive group. -/
+ [topologicalAddGroup : TopologicalAddGroup toProfinite]
+
+attribute [to_additive] ProfiniteGrp
+
+namespace ProfiniteGrp
+
+@[to_additive]
+instance : CoeSort ProfiniteGrp (Type u) where
+ coe G := G.toProfinite
+
+attribute [instance] group topologicalGroup
+ ProfiniteAddGrp.addGroup ProfiniteAddGrp.topologicalAddGroup
+
+@[to_additive]
+instance : Category ProfiniteGrp where
+ Hom A B := ContinuousMonoidHom A B
+ id A := ContinuousMonoidHom.id A
+ comp f g := ContinuousMonoidHom.comp g f
+
+@[to_additive]
+instance (G H : ProfiniteGrp) : FunLike (G ⟶ H) G H :=
+ inferInstanceAs <| FunLike (ContinuousMonoidHom G H) G H
+
+@[to_additive]
+instance (G H : ProfiniteGrp) : MonoidHomClass (G ⟶ H) G H :=
+ inferInstanceAs <| MonoidHomClass (ContinuousMonoidHom G H) G H
+
+@[to_additive]
+instance (G H : ProfiniteGrp) : ContinuousMapClass (G ⟶ H) G H :=
+ inferInstanceAs <| ContinuousMapClass (ContinuousMonoidHom G H) G H
+
+@[to_additive]
+instance : ConcreteCategory ProfiniteGrp where
+ forget :=
+ { obj := fun G => G
+ map := fun f => f }
+ forget_faithful :=
+ { map_injective := by
+ intro G H f g h
+ exact DFunLike.ext _ _ <| fun x => congr_fun h x }
+
+/-- Construct a term of `ProfiniteGrp` from a type endowed with the structure of a
+compact and totally disconnected topological group.
+(The condition of being Hausdorff can be omitted here because totally disconnected implies that {1}
+is a closed set, thus implying Hausdorff in a topological group.)-/
+@[to_additive "Construct a term of `ProfiniteAddGrp` from a type endowed with the structure of a
+compact and totally disconnected topological additive group.
+(The condition of being Hausdorff can be omitted here because totally disconnected implies that {0}
+is a closed set, thus implying Hausdorff in a topological additive group.)"]
+def of (G : Type u) [Group G] [TopologicalSpace G] [TopologicalGroup G]
+ [CompactSpace G] [TotallyDisconnectedSpace G] : ProfiniteGrp where
+ toProfinite := .of G
+ group := ‹_›
+ topologicalGroup := ‹_›
+
+@[to_additive (attr := simp)]
+theorem coe_of (X : ProfiniteGrp) : (of X : Type _) = X :=
+ rfl
+
+@[to_additive (attr := simp)]
+theorem coe_id (X : ProfiniteGrp) : (𝟙 ((forget ProfiniteGrp).obj X)) = id :=
+ rfl
+
+@[to_additive (attr := simp)]
+theorem coe_comp {X Y Z : ProfiniteGrp} (f : X ⟶ Y) (g : Y ⟶ Z) :
+ ((forget ProfiniteGrp).map f ≫ (forget ProfiniteGrp).map g) = g ∘ f :=
+ rfl
+
+/-- Construct a term of `ProfiniteGrp` from a type endowed with the structure of a
+profinite topological group. -/
+@[to_additive "Construct a term of `ProfiniteAddGrp` from a type endowed with the structure of a
+profinite topological additive group."]
+abbrev ofProfinite (G : Profinite) [Group G] [TopologicalGroup G] :
+ ProfiniteGrp := of G
+
+/-- The pi-type of profinite groups is a profinite group. -/
+@[to_additive "The pi-type of profinite additive groups is a
+profinite additive group."]
+def pi {α : Type u} (β : α → ProfiniteGrp) : ProfiniteGrp :=
+ let pitype := Profinite.pi fun (a : α) => (β a).toProfinite
+ letI (a : α): Group (β a).toProfinite := (β a).group
+ letI : Group pitype := Pi.group
+ letI : TopologicalGroup pitype := Pi.topologicalGroup
+ ofProfinite pitype
+
+/-- A `FiniteGrp` when given the discrete topology can be considered as a profinite group. -/
+@[to_additive "A `FiniteAddGrp` when given the discrete topology can be considered as a
+profinite additive group."]
+def ofFiniteGrp (G : FiniteGrp) : ProfiniteGrp :=
+ letI : TopologicalSpace G := ⊥
+ letI : DiscreteTopology G := ⟨rfl⟩
+ letI : TopologicalGroup G := {}
+ of G
+
+@[to_additive]
+instance : HasForget₂ FiniteGrp ProfiniteGrp where
+ forget₂ :=
+ { obj := ofFiniteGrp
+ map := fun f => ⟨f, by continuity⟩ }
+
+@[to_additive]
+instance : HasForget₂ ProfiniteGrp Grp where
+ forget₂ := {
+ obj := fun P => ⟨P, P.group⟩
+ map := fun f => f.toMonoidHom
+ }
+
+/-- A closed subgroup of a profinite group is profinite. -/
+def ofClosedSubgroup {G : ProfiniteGrp} (H : ClosedSubgroup G) : ProfiniteGrp :=
+ letI : CompactSpace H := inferInstance
+ of H.1
+
+/-- The functor mapping a profinite group to its underlying profinite space. -/
+def profiniteGrpToProfinite : ProfiniteGrp ⥤ Profinite where
+ obj G := G.toProfinite
+ map f := ⟨f, by continuity⟩
+
+instance : profiniteGrpToProfinite.Faithful := {
+ map_injective := fun {_ _} _ _ h =>
+ ConcreteCategory.hom_ext_iff.mpr (congrFun (congrArg ContinuousMap.toFun h)) }
+
+end ProfiniteGrp
+
+/-!
+# Limits in the category of profinite groups
+
+In this section, we construct limits in the category of profinite groups.
+
+* `ProfiniteGrp.limitCone` : The explicit limit cone in `ProfiniteGrp`.
+
+* `ProfiniteGrp.limitConeIsLimit`: `ProfiniteGrp.limitCone` is a limit cone.
+
+-/
+
+section Limits
+
+namespace ProfiniteGrp
+
+section
+
+variable {J : Type v} [SmallCategory J] (F : J ⥤ ProfiniteGrp.{max v u})
+
+/-- Auxiliary construction to obtain the group structure on the limit of profinite groups. -/
+def limitConePtAux : Subgroup (Π j : J, F.obj j) where
+ carrier := {x | ∀ ⦃i j : J⦄ (π : i ⟶ j), F.map π (x i) = x j}
+ mul_mem' hx hy _ _ π := by simp only [Pi.mul_apply, map_mul, hx π, hy π]
+ one_mem' := by simp only [Set.mem_setOf_eq, Pi.one_apply, map_one, implies_true]
+ inv_mem' h _ _ π := by simp only [Pi.inv_apply, map_inv, h π]
+
+instance : Group (Profinite.limitCone (F ⋙ profiniteGrpToProfinite.{max v u})).pt :=
+ inferInstanceAs (Group (limitConePtAux F))
+
+instance : TopologicalGroup (Profinite.limitCone (F ⋙ profiniteGrpToProfinite.{max v u})).pt :=
+ inferInstanceAs (TopologicalGroup (limitConePtAux F))
+
+/-- The explicit limit cone in `ProfiniteGrp`. -/
+abbrev limitCone : Limits.Cone F where
+ pt := ofProfinite (Profinite.limitCone (F ⋙ profiniteGrpToProfinite.{max v u})).pt
+ π :=
+ { app := fun j => {
+ toFun := fun x => x.1 j
+ map_one' := rfl
+ map_mul' := fun x y => rfl
+ continuous_toFun := by
+ exact (continuous_apply j).comp (continuous_iff_le_induced.mpr fun U a => a) }
+ naturality := fun i j f => by
+ simp only [Functor.const_obj_obj, Functor.comp_obj,
+ Functor.const_obj_map, Category.id_comp, Functor.comp_map]
+ congr
+ exact funext fun x => (x.2 f).symm }
+
+/-- `ProfiniteGrp.limitCone` is a limit cone. -/
+def limitConeIsLimit : Limits.IsLimit (limitCone F) where
+ lift cone := {
+ ((Profinite.limitConeIsLimit (F ⋙ profiniteGrpToProfinite)).lift
+ (profiniteGrpToProfinite.mapCone cone)) with
+ map_one' := Subtype.ext (funext fun j ↦ map_one (cone.π.app j))
+ -- TODO: investigate whether it's possible to set up `ext` lemmas for the `TopCat`-related
+ -- categories so that `by ext j; exact map_one (cone.π.app j)` works here, similarly below.
+ map_mul' := fun _ _ ↦ Subtype.ext (funext fun j ↦ map_mul (cone.π.app j) _ _) }
+ uniq cone m h := by
+ apply profiniteGrpToProfinite.map_injective
+ simpa using (Profinite.limitConeIsLimit (F ⋙ profiniteGrpToProfinite)).uniq
+ (profiniteGrpToProfinite.mapCone cone) (profiniteGrpToProfinite.map m)
+ (fun j ↦ congrArg profiniteGrpToProfinite.map (h j))
+
+instance : Limits.HasLimit F where
+ exists_limit := Nonempty.intro
+ { cone := limitCone F
+ isLimit := limitConeIsLimit F }
+
+/-- The abbreviation for the limit of `ProfiniteGrp`s. -/
+abbrev limit : ProfiniteGrp := (ProfiniteGrp.limitCone F).pt
+
+end
+
+instance : Limits.PreservesLimits profiniteGrpToProfinite.{u} where
+ preservesLimitsOfShape := {
+ preservesLimit := fun {F} ↦ CategoryTheory.Limits.preservesLimitOfPreservesLimitCone
+ (limitConeIsLimit F) (Profinite.limitConeIsLimit (F ⋙ profiniteGrpToProfinite)) }
+
+end ProfiniteGrp
+
+end Limits
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/ClosedSubgroup.lean b/Mathlib/Topology/Algebra/ClosedSubgroup.lean
new file mode 100644
index 0000000000000..302f09738270a
--- /dev/null
+++ b/Mathlib/Topology/Algebra/ClosedSubgroup.lean
@@ -0,0 +1,128 @@
+/-
+Copyright (c) 2024 Nailin Guan. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Nailin Guan
+-/
+
+import Mathlib.Topology.Algebra.Group.Basic
+import Mathlib.Algebra.Group.Subgroup.Basic
+import Mathlib.GroupTheory.Index
+
+/-!
+# Closed subgroups of a topological group
+
+This files builds the SemilatticeInf `ClosedSubgroup G` of closed subgroups in a
+topological group `G`, and its additive version `ClosedAddSubgroup`.
+
+# Main definitions and results
+
+* `normalCore_isClosed` : The `normalCore` of a closed subgroup is closed.
+
+* `finindex_closedSubgroup_isOpen` : A closed subgroup with finite index is open.
+
+-/
+
+section
+
+universe u v
+
+/-- The type of closed subgroups of a topological group. -/
+@[ext]
+structure ClosedSubgroup (G : Type u) [Group G] [TopologicalSpace G] extends Subgroup G where
+ isClosed' : IsClosed carrier
+
+/-- The type of closed subgroups of an additive topological group. -/
+@[ext]
+structure ClosedAddSubgroup (G : Type u) [AddGroup G] [TopologicalSpace G] extends
+ AddSubgroup G where
+ isClosed' : IsClosed carrier
+
+attribute [to_additive] ClosedSubgroup
+
+attribute [coe] ClosedSubgroup.toSubgroup ClosedAddSubgroup.toAddSubgroup
+
+namespace ClosedSubgroup
+
+variable (G : Type u) [Group G] [TopologicalSpace G]
+
+variable {G} in
+@[to_additive]
+theorem toSubgroup_injective : Function.Injective
+ (ClosedSubgroup.toSubgroup : ClosedSubgroup G → Subgroup G) :=
+ fun A B h ↦ by
+ ext
+ rw [h]
+
+@[to_additive]
+instance : SetLike (ClosedSubgroup G) G where
+ coe U := U.1
+ coe_injective' _ _ h := toSubgroup_injective <| SetLike.ext' h
+
+@[to_additive]
+instance : SubgroupClass (ClosedSubgroup G) G where
+ mul_mem := Subsemigroup.mul_mem' _
+ one_mem U := U.one_mem'
+ inv_mem := Subgroup.inv_mem' _
+
+@[to_additive]
+instance : Coe (ClosedSubgroup G) (Subgroup G) where
+ coe := toSubgroup
+
+@[to_additive]
+instance instInfClosedSubgroup : Inf (ClosedSubgroup G) :=
+ ⟨fun U V ↦ ⟨U ⊓ V, U.isClosed'.inter V.isClosed'⟩⟩
+
+@[to_additive]
+instance instSemilatticeInfClosedSubgroup : SemilatticeInf (ClosedSubgroup G) :=
+ SetLike.coe_injective.semilatticeInf ((↑) : ClosedSubgroup G → Set G) fun _ _ ↦ rfl
+
+@[to_additive]
+instance [CompactSpace G] (H : ClosedSubgroup G) : CompactSpace H :=
+ isCompact_iff_compactSpace.mp (IsClosed.isCompact H.isClosed')
+
+end ClosedSubgroup
+
+open scoped Pointwise
+
+namespace Subgroup
+
+variable {G : Type u} [Group G] [TopologicalSpace G] [ContinuousMul G]
+
+lemma normalCore_isClosed (H : Subgroup G) (h : IsClosed (H : Set G)) :
+ IsClosed (H.normalCore : Set G) := by
+ rw [normalCore_eq_iInf_conjAct]
+ push_cast
+ apply isClosed_iInter
+ intro g
+ convert IsClosed.preimage (TopologicalGroup.continuous_conj (ConjAct.ofConjAct g⁻¹)) h
+ exact Set.ext (fun t ↦ Set.mem_smul_set_iff_inv_smul_mem)
+
+@[to_additive]
+lemma isOpen_of_isClosed_of_finiteIndex (H : Subgroup G) [H.FiniteIndex]
+ (h : IsClosed (H : Set G)) : IsOpen (H : Set G) := by
+ apply isClosed_compl_iff.mp
+ convert isClosed_iUnion_of_finite <| fun (x : {x : (G ⧸ H) // x ≠ QuotientGroup.mk 1})
+ ↦ IsClosed.smul h (Quotient.out' x.1)
+ ext x
+ refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩
+ · have : QuotientGroup.mk 1 ≠ QuotientGroup.mk (s := H) x := by
+ apply QuotientGroup.eq.not.mpr
+ simpa only [inv_one, one_mul, ne_eq]
+ simp only [ne_eq, Set.mem_iUnion]
+ use ⟨QuotientGroup.mk (s := H) x, this.symm⟩,
+ (Quotient.out' (QuotientGroup.mk (s := H) x))⁻¹ * x
+ simp only [SetLike.mem_coe, smul_eq_mul, mul_inv_cancel_left, and_true]
+ exact QuotientGroup.eq.mp <| QuotientGroup.out_eq' (QuotientGroup.mk (s := H) x)
+ · rcases h with ⟨S,⟨y,hS⟩,mem⟩
+ simp only [← hS] at mem
+ rcases mem with ⟨h,hh,eq⟩
+ simp only [Set.mem_compl_iff, SetLike.mem_coe]
+ by_contra mH
+ simp only [← eq, ne_eq, smul_eq_mul] at mH
+ absurd y.2.symm
+ rw [← QuotientGroup.out_eq' y.1, QuotientGroup.eq]
+ simp only [inv_one, ne_eq, one_mul, (Subgroup.mul_mem_cancel_right H hh).mp mH]
+
+end Subgroup
+
+end
diff --git a/Mathlib/Topology/Algebra/ConstMulAction.lean b/Mathlib/Topology/Algebra/ConstMulAction.lean
index 482927bb1d468..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
@@ -451,6 +455,11 @@ theorem isOpenMap_quotient_mk'_mul [ContinuousConstSMul Γ T] :
rw [isOpen_coinduced, MulAction.quotient_preimage_image_eq_union_mul U]
exact isOpen_iUnion fun γ => isOpenMap_smul γ U hU
+@[to_additive]
+theorem MulAction.isOpenQuotientMap_quotientMk [ContinuousConstSMul Γ T] :
+ IsOpenQuotientMap (Quotient.mk (MulAction.orbitRel Γ T)) :=
+ ⟨surjective_quot_mk _, continuous_quot_mk, isOpenMap_quotient_mk'_mul⟩
+
/-- The quotient by a discontinuous group action of a locally compact t2 space is t2. -/
@[to_additive "The quotient by a discontinuous group action of a locally compact t2
space is t2."]
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 39cb34e5d4264..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.ContinuousFunction.Basic
import Mathlib.Topology.Algebra.Module.Basic
/-!
diff --git a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean
index de9f0789c24cb..f2d88910ccaaa 100644
--- a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean
+++ b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean
@@ -5,7 +5,7 @@ Authors: Thomas Browning
-/
import Mathlib.Topology.Algebra.Equicontinuity
import Mathlib.Topology.Algebra.Group.Compact
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.Topology.ContinuousMap.Algebra
import Mathlib.Topology.UniformSpace.Ascoli
/-!
@@ -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,53 +97,61 @@ 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!) "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!) "Product of two continuous homomorphisms on different spaces."]
-def prod_map (f : ContinuousMonoidHom A C) (g : ContinuousMonoidHom B D) :
+@[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.prod_map 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")]
+alias _root_.ContinuousAddMonoidHom.sum_map := ContinuousAddMonoidHom.prodMap
+
+set_option linter.existingAttributeWarning false in
+attribute [to_additive existing] prod_map
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) :=
@@ -156,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!)
@@ -195,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}
@@ -208,7 +212,7 @@ variable {A B C D E}
@[to_additive (attr := simps!) "Coproduct of two continuous homomorphisms to the same space."]
def coprod (f : ContinuousMonoidHom A E) (g : ContinuousMonoidHom B E) :
ContinuousMonoidHom (A × B) E :=
- (mul E).comp (f.prod_map g)
+ (mul E).comp (f.prodMap g)
@[to_additive]
instance : CommGroup (ContinuousMonoidHom A E) where
@@ -228,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 :
@@ -245,54 +263,57 @@ 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.prod_map hc hc))
+ { continuous_mul := hi.continuous_iff.mpr (continuous_mul.comp (Continuous.prodMap hc hc))
continuous_inv := hi.continuous_iff.mpr (continuous_inv.comp hc) }
@[to_additive]
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).prod_map (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)
@@ -357,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 6a6d37b9907fc..c897f0bb8fa18 100644
--- a/Mathlib/Topology/Algebra/Field.lean
+++ b/Mathlib/Topology/Algebra/Field.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2021 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Scott Morrison
+Authors: Patrick Massot, Kim Morrison
-/
import Mathlib.Algebra.Field.Subfield
import Mathlib.Algebra.GroupWithZero.Divisibility
@@ -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
@@ -132,7 +132,7 @@ theorem IsPreconnected.eq_or_eq_neg_of_sq_eq [Field 𝕜] [HasContinuousInv₀
(hsq : EqOn (f ^ 2) (g ^ 2) S) (hg_ne : ∀ {x : α}, x ∈ S → g x ≠ 0) :
EqOn f g S ∨ EqOn f (-g) S := by
have hsq : EqOn ((f / g) ^ 2) 1 S := fun x hx => by
- simpa [div_eq_one_iff_eq (pow_ne_zero _ (hg_ne hx))] using hsq hx
+ simpa [div_eq_one_iff_eq (pow_ne_zero _ (hg_ne hx)), div_pow] using hsq hx
simpa (config := { contextual := true }) [EqOn, div_eq_iff (hg_ne _)]
using hS.eq_one_or_eq_neg_one_of_sq_eq (hf.div hg fun z => hg_ne) hsq
@@ -146,6 +146,6 @@ theorem IsPreconnected.eq_of_sq_eq [Field 𝕜] [HasContinuousInv₀ 𝕜] [Cont
rcases hS.eq_or_eq_neg_of_sq_eq hf hg @hsq @hg_ne with (h | h)
· exact h hx
· rw [h _, Pi.neg_apply, neg_eq_iff_add_eq_zero, ← two_mul, mul_eq_zero,
- iff_false_iff.2 (hg_ne _)] at hy' ⊢ <;> assumption
+ (iff_of_eq (iff_false _)).2 (hg_ne _)] at hy' ⊢ <;> assumption
end Preconnected
diff --git a/Mathlib/Topology/Algebra/Group/Basic.lean b/Mathlib/Topology/Algebra/Group/Basic.lean
index ad1294ce4d9e6..cc7be69cbeef0 100644
--- a/Mathlib/Topology/Algebra/Group/Basic.lean
+++ b/Mathlib/Topology/Algebra/Group/Basic.lean
@@ -3,12 +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.Algebra.Group.Subgroup.Pointwise
import Mathlib.Algebra.Order.Archimedean.Basic
-import Mathlib.GroupTheory.QuotientGroup.Basic
+import Mathlib.Topology.Algebra.Monoid
/-!
# Topological groups
@@ -377,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
/-!
@@ -535,7 +534,7 @@ end OrderedCommGroup
@[to_additive]
instance [TopologicalSpace H] [Group H] [TopologicalGroup H] : TopologicalGroup (G × H) where
- continuous_inv := continuous_inv.prod_map continuous_inv
+ continuous_inv := continuous_inv.prodMap continuous_inv
@[to_additive]
instance Pi.topologicalGroup {C : β → Type*} [∀ b, TopologicalSpace (C b)] [∀ b, Group (C b)]
@@ -546,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 `αᵃᵒᵖ`."]
@@ -586,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
@@ -846,69 +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]
-theorem quotientMap_mk (N : Subgroup G) : QuotientMap (mk : G → G ⧸ N) :=
- quotientMap_quot_mk
-
-variable [TopologicalGroup G] (N : Subgroup G)
-
-@[to_additive]
-theorem isOpenMap_coe : IsOpenMap ((↑) : G → G ⧸ N) :=
- isOpenMap_quotient_mk'_mul
-
-@[to_additive (attr := simp)]
-theorem dense_preimage_mk {s : Set (G ⧸ N)} : Dense ((↑) ⁻¹' s : Set G) ↔ Dense s :=
- letI := leftRel N -- `Dense.quotient` assumes `[Setoid G]`
- ⟨fun h ↦ h.quotient.mono <| image_preimage_subset _ _, fun h ↦ h.preimage <| isOpenMap_coe _⟩
-
-@[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 instTopologicalGroup [N.Normal] : TopologicalGroup (G ⧸ N) where
- continuous_mul := by
- have cont : Continuous (((↑) : G → G ⧸ N) ∘ fun p : G × G ↦ p.fst * p.snd) :=
- continuous_quot_mk.comp continuous_mul
- have quot : QuotientMap fun p : G × G ↦ ((p.1 : G ⧸ N), (p.2 : G ⧸ N)) := by
- apply IsOpenMap.to_quotientMap
- · exact (QuotientGroup.isOpenMap_coe N).prod (QuotientGroup.isOpenMap_coe N)
- · exact continuous_quot_mk.prod_map continuous_quot_mk
- · exact (surjective_quot_mk _).prodMap (surjective_quot_mk _)
- exact quot.continuous_iff.2 cont
- 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
-
-/-- 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) :=
- le_antisymm ((QuotientGroup.isOpenMap_coe N).nhds_le x) continuous_quot_mk.continuousAt
-
-@[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 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
@@ -1113,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
@@ -1231,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
@@ -1329,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]
@@ -1363,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`.) -/
@@ -1407,7 +1331,7 @@ theorem Subgroup.properlyDiscontinuousSMul_opposite_of_tendsto_cofinite (S : Sub
(hS : Tendsto S.subtype cofinite (cocompact G)) : ProperlyDiscontinuousSMul S.op G :=
{ finite_disjoint_inter_image := by
intro K L hK hL
- have : Continuous fun p : G × G => (p.1⁻¹, p.2) := continuous_inv.prod_map continuous_id
+ have : Continuous fun p : G × G => (p.1⁻¹, p.2) := continuous_inv.prodMap continuous_id
have H : Set.Finite _ :=
hS ((hK.prod hL).image (continuous_mul.comp this)).compl_mem_cocompact
simp only [preimage_compl, compl_compl, coeSubtype, comp_apply] at H
@@ -1599,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 N).image_mem_nhds s_mem, mapsTo'.mp hs,
- s_comp.image C⟩
-
end
section
@@ -1646,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."]
@@ -1678,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
@@ -1892,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
@@ -1925,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/Compact.lean b/Mathlib/Topology/Algebra/Group/Compact.lean
index 57b0155e2e6a8..b479c867ca91f 100644
--- a/Mathlib/Topology/Algebra/Group/Compact.lean
+++ b/Mathlib/Topology/Algebra/Group/Compact.lean
@@ -4,24 +4,18 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot
-/
import Mathlib.Topology.Algebra.Group.Basic
-import Mathlib.Topology.CompactOpen
import Mathlib.Topology.Sets.Compacts
/-!
# Additional results on topological groups
-Two results on topological groups that have been separated out as they require more substantial
-imports developing either positive compacts or the compact open topology.
-
+A result on topological groups that has been separated out
+as it requires more substantial imports developing positive compacts.
-/
-universe u v w x
-
-variable {α : Type u} {β : Type v} {G : Type w} {H : Type x}
-section
-
-variable [TopologicalSpace G] [Group G] [TopologicalGroup G]
+universe u
+variable {G : Type u} [TopologicalSpace G] [Group G] [TopologicalGroup G]
/-- Every topological group in which there exists a compact set with nonempty interior
is locally compact. -/
@@ -32,21 +26,3 @@ theorem TopologicalSpace.PositiveCompacts.locallyCompactSpace_of_group
(K : PositiveCompacts G) : LocallyCompactSpace G :=
let ⟨_x, hx⟩ := K.interior_nonempty
K.isCompact.locallyCompactSpace_of_mem_nhds_of_group (mem_interior_iff_mem_nhds.1 hx)
-
-end
-
-section Quotient
-
-variable [Group G] [TopologicalSpace G] [TopologicalGroup G] {Γ : Subgroup G}
-
-@[to_additive]
-instance QuotientGroup.continuousSMul [LocallyCompactSpace G] : ContinuousSMul G (G ⧸ Γ) where
- continuous_smul := by
- let F : G × G ⧸ Γ → G ⧸ Γ := fun p => p.1 • p.2
- change Continuous F
- have H : Continuous (F ∘ fun p : G × G => (p.1, QuotientGroup.mk p.2)) := by
- change Continuous fun p : G × G => QuotientGroup.mk (p.1 * p.2)
- exact continuous_coinduced_rng.comp continuous_mul
- exact QuotientMap.continuous_lift_prod_right quotientMap_quotient_mk' H
-
-end Quotient
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/Group/SubmonoidClosure.lean b/Mathlib/Topology/Algebra/Group/SubmonoidClosure.lean
new file mode 100644
index 0000000000000..ae23b4d9c3b9b
--- /dev/null
+++ b/Mathlib/Topology/Algebra/Group/SubmonoidClosure.lean
@@ -0,0 +1,118 @@
+/-
+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.Order.Filter.AtTopBot.Group
+import Mathlib.Topology.Algebra.Group.Basic
+
+/-!
+# Topological closure of the submonoid closure
+
+In this file we prove several versions of the following statement:
+if `G` is a compact topological group and `s : Set G`,
+then the topological closures of `Submonoid.closure s` and `Subgroup.closure s` are equal.
+
+The proof is based on the following observation, see `mapClusterPt_self_zpow_atTop_pow`:
+each `x^m`, `m : ℤ` is a limit point (`MapClusterPt`) of the sequence `x^n`, `n : ℕ`, as `n → ∞`.
+-/
+
+open Filter Function Set
+open scoped Topology
+
+variable {G : Type*}
+
+@[to_additive]
+theorem mapClusterPt_atTop_zpow_iff_pow [DivInvMonoid G] [TopologicalSpace G] {x y : G} :
+ MapClusterPt x atTop (y ^ · : ℤ → G) ↔ MapClusterPt x atTop (y ^ · : ℕ → G) := by
+ simp_rw [MapClusterPt, ← Nat.map_cast_int_atTop, map_map, comp_def, zpow_natCast]
+
+variable [Group G] [TopologicalSpace G] [CompactSpace G] [TopologicalGroup G]
+
+@[to_additive]
+theorem mapClusterPt_self_zpow_atTop_pow (x : G) (m : ℤ) :
+ MapClusterPt (x ^ m) atTop (x ^ · : ℕ → G) := by
+ obtain ⟨y, hy⟩ : ∃ y, MapClusterPt y atTop (x ^ · : ℤ → G) :=
+ exists_clusterPt_of_compactSpace _
+ rw [← mapClusterPt_atTop_zpow_iff_pow]
+ have H : MapClusterPt (x ^ m) (atTop.curry atTop) ↿(fun a b ↦ x ^ (m + b - a)) := by
+ have : ContinuousAt (fun yz ↦ x ^ m * yz.2 / yz.1) (y, y) := by fun_prop
+ simpa only [comp_def, ← zpow_sub, ← zpow_add, div_eq_mul_inv, Prod.map, mul_inv_cancel_right]
+ using (hy.curry_prodMap hy).continuousAt_comp this
+ suffices Tendsto ↿(fun a b ↦ m + b - a) (atTop.curry atTop) atTop from H.of_comp this
+ refine Tendsto.curry <| .of_forall fun a ↦ ?_
+ simp only [sub_eq_add_neg] -- TODO: add `Tendsto.atTop_sub_const` etc
+ exact tendsto_atTop_add_const_right _ _ (tendsto_atTop_add_const_left atTop m tendsto_id)
+
+@[to_additive]
+theorem mapClusterPt_one_atTop_pow (x : G) : MapClusterPt 1 atTop (x ^ · : ℕ → G) := by
+ simpa using mapClusterPt_self_zpow_atTop_pow x 0
+
+@[to_additive]
+theorem mapClusterPt_self_atTop_pow (x : G) : MapClusterPt x atTop (x ^ · : ℕ → G) := by
+ simpa using mapClusterPt_self_zpow_atTop_pow x 1
+
+@[to_additive]
+theorem mapClusterPt_atTop_pow_tfae (x y : G) :
+ List.TFAE [
+ MapClusterPt x atTop (y ^ · : ℕ → G),
+ MapClusterPt x atTop (y ^ · : ℤ → G),
+ x ∈ closure (range (y ^ · : ℕ → G)),
+ x ∈ closure (range (y ^ · : ℤ → G)),
+ ] := by
+ tfae_have 2 ↔ 1 := mapClusterPt_atTop_zpow_iff_pow
+ tfae_have 3 → 4 := by
+ refine fun h ↦ closure_mono (range_subset_iff.2 fun n ↦ ?_) h
+ exact ⟨n, zpow_natCast _ _⟩
+ tfae_have 4 → 1 := by
+ refine fun h ↦ closure_minimal ?_ isClosed_setOf_clusterPt h
+ exact range_subset_iff.2 (mapClusterPt_self_zpow_atTop_pow _)
+ tfae_have 1 → 3 := by
+ rw [mem_closure_iff_clusterPt]
+ exact (ClusterPt.mono · (le_principal_iff.2 range_mem_map))
+ tfae_finish
+
+@[to_additive]
+theorem mapClusterPt_atTop_pow_iff_mem_topologicalClosure_zpowers {x y : G} :
+ MapClusterPt x atTop (y ^ · : ℕ → G) ↔ x ∈ (Subgroup.zpowers y).topologicalClosure :=
+ (mapClusterPt_atTop_pow_tfae x y).out 0 3
+
+@[to_additive (attr := simp)]
+theorem mapClusterPt_inv_atTop_pow {x y : G} :
+ MapClusterPt x⁻¹ atTop (y ^ · : ℕ → G) ↔ MapClusterPt x atTop (y ^ · : ℕ → G) := by
+ simp only [mapClusterPt_atTop_pow_iff_mem_topologicalClosure_zpowers, inv_mem_iff]
+
+@[to_additive]
+theorem closure_range_zpow_eq_pow (x : G) :
+ closure (range (x ^ · : ℤ → G)) = closure (range (x ^ · : ℕ → G)) := by
+ ext y
+ exact (mapClusterPt_atTop_pow_tfae y x).out 3 2
+
+@[to_additive]
+theorem denseRange_zpow_iff_pow {x : G} :
+ DenseRange (x ^ · : ℤ → G) ↔ DenseRange (x ^ · : ℕ → G) := by
+ simp only [DenseRange, dense_iff_closure_eq, closure_range_zpow_eq_pow]
+
+@[to_additive]
+theorem topologicalClosure_subgroupClosure_toSubmonoid (s : Set G) :
+ (Subgroup.closure s).toSubmonoid.topologicalClosure =
+ (Submonoid.closure s).topologicalClosure := by
+ refine le_antisymm ?_ (closure_mono <| Subgroup.le_closure_toSubmonoid _)
+ refine Submonoid.topologicalClosure_minimal _ ?_ isClosed_closure
+ rw [Subgroup.closure_toSubmonoid, Submonoid.closure_le]
+ refine union_subset (Submonoid.subset_closure.trans subset_closure) fun x hx ↦ ?_
+ refine closure_mono (Submonoid.powers_le.2 (Submonoid.subset_closure <| Set.mem_inv.1 hx)) ?_
+ rw [Submonoid.coe_powers, ← closure_range_zpow_eq_pow, ← Subgroup.coe_zpowers,
+ ← Subgroup.topologicalClosure_coe, SetLike.mem_coe, ← inv_mem_iff]
+ exact subset_closure <| Subgroup.mem_zpowers _
+
+@[to_additive]
+theorem closure_submonoidClosure_eq_closure_subgroupClosure (s : Set G) :
+ closure (Submonoid.closure s : Set G) = closure (Subgroup.closure s) :=
+ congrArg SetLike.coe (topologicalClosure_subgroupClosure_toSubmonoid s).symm
+
+@[to_additive]
+theorem dense_submonoidClosure_iff_subgroupClosure {s : Set G} :
+ Dense (Submonoid.closure s : Set G) ↔ Dense (Subgroup.closure s : Set G) := by
+ simp only [dense_iff_closure_eq, closure_submonoidClosure_eq_closure_subgroupClosure]
diff --git a/Mathlib/Topology/Algebra/GroupCompletion.lean b/Mathlib/Topology/Algebra/GroupCompletion.lean
index 234486fbb1753..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
@@ -181,8 +180,8 @@ theorem continuous_toCompl : Continuous (toCompl : α → Completion α) :=
variable (α)
-theorem denseInducing_toCompl : DenseInducing (toCompl : α → Completion α) :=
- denseInducing_coe
+theorem isDenseInducing_toCompl : IsDenseInducing (toCompl : α → Completion α) :=
+ isDenseInducing_coe
variable {α}
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 9642c81b12ef4..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) :=
@@ -204,7 +206,7 @@ protected theorem Multipliable.map_iff_of_leftInverse [CommMonoid γ] [Topologic
Multipliable (g ∘ f) ↔ Multipliable f :=
⟨fun h ↦ by
have := h.map _ hg'
- rwa [← Function.comp.assoc, hinv.id] at this, fun h ↦ h.map _ hg⟩
+ rwa [← Function.comp_assoc, hinv.id] at this, fun h ↦ h.map _ hg⟩
@[to_additive]
theorem Multipliable.map_tprod [CommMonoid γ] [TopologicalSpace γ] [T2Space γ] (hf : Multipliable 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 c68372a5f2ce0..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 _ ↦ ?_
@@ -146,7 +146,35 @@ end ContinuousMul
section CompleteSpace
-variable [CommGroup α] [UniformSpace α] [UniformGroup α] [CompleteSpace α]
+variable [CommGroup α] [UniformSpace α] [UniformGroup α]
+
+@[to_additive]
+theorem HasProd.of_sigma {γ : β → Type*} {f : (Σ b : β, γ b) → α} {g : β → α} {a : α}
+ (hf : ∀ b, HasProd (fun c ↦ f ⟨b, c⟩) (g b)) (hg : HasProd g a)
+ (h : CauchySeq (fun (s : Finset (Σ b : β, γ b)) ↦ ∏ i ∈ s, f i)) :
+ HasProd f a := by
+ classical
+ apply le_nhds_of_cauchy_adhp h
+ simp only [← mapClusterPt_def, mapClusterPt_iff, frequently_atTop, ge_iff_le, le_eq_subset]
+ intro u hu s
+ rcases mem_nhds_iff.1 hu with ⟨v, vu, v_open, hv⟩
+ 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 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 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 ⟨{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 α]
@[to_additive]
theorem Multipliable.sigma_factor {γ : β → Type*} {f : (Σb : β, γ b) → α}
diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean b/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean
index b4e52d99ca80c..2bf685cd201e1 100644
--- a/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean
+++ b/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean
@@ -3,8 +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
-/
-import Mathlib.Topology.Separation
import Mathlib.Algebra.BigOperators.Finprod
+import Mathlib.Order.Filter.AtTopBot.BigOperators
+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/GroupCompletion.lean b/Mathlib/Topology/Algebra/InfiniteSum/GroupCompletion.lean
index 52b2b087f1a48..078edbe10ffe4 100644
--- a/Mathlib/Topology/Algebra/InfiniteSum/GroupCompletion.lean
+++ b/Mathlib/Topology/Algebra/InfiniteSum/GroupCompletion.lean
@@ -17,13 +17,13 @@ variable {α β : Type*} [AddCommGroup α] [UniformSpace α] [UniformAddGroup α
/-- A function `f` has a sum in an uniform additive group `α` if and only if it has that sum in the
completion of `α`. -/
theorem hasSum_iff_hasSum_compl (f : β → α) (a : α) :
- HasSum (toCompl ∘ f) a ↔ HasSum f a := (denseInducing_toCompl α).hasSum_iff f a
+ HasSum (toCompl ∘ f) a ↔ HasSum f a := (isDenseInducing_toCompl α).hasSum_iff f a
/-- A function `f` is summable in a uniform additive group `α` if and only if it is summable in
`Completion α` and its sum in `Completion α` lies in the range of `toCompl : α →+ Completion α`. -/
theorem summable_iff_summable_compl_and_tsum_mem (f : β → α) :
Summable f ↔ Summable (toCompl ∘ f) ∧ ∑' i, toCompl (f i) ∈ Set.range toCompl :=
- (denseInducing_toCompl α).summable_iff_tsum_comp_mem_range f
+ (isDenseInducing_toCompl α).summable_iff_tsum_comp_mem_range f
/-- A function `f` is summable in a uniform additive group `α` if and only if the net of its partial
sums is Cauchy and its sum in `Completion α` lies in the range of `toCompl : α →+ Completion α`.
diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Order.lean b/Mathlib/Topology/Algebra/InfiniteSum/Order.lean
index 53773dace6081..612e335b22582 100644
--- a/Mathlib/Topology/Algebra/InfiniteSum/Order.lean
+++ b/Mathlib/Topology/Algebra/InfiniteSum/Order.lean
@@ -40,7 +40,7 @@ variable [OrderedCommMonoid α] [TopologicalSpace α] [OrderClosedTopology α] {
theorem hasProd_le (h : ∀ i, f i ≤ g i) (hf : HasProd f a₁) (hg : HasProd g a₂) : a₁ ≤ a₂ :=
le_of_tendsto_of_tendsto' hf hg fun _ ↦ prod_le_prod' fun i _ ↦ h i
-@[to_additive (attr := mono)]
+@[to_additive]
theorem hasProd_mono (hf : HasProd f a₁) (hg : HasProd g a₂) (h : f ≤ g) : a₁ ≤ a₂ :=
hasProd_le h hf hg
@@ -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 10923f5231954..0ec905dcba11e 100644
--- a/Mathlib/Topology/Algebra/Module/Alternating/Topology.lean
+++ b/Mathlib/Topology/Algebra/Module/Alternating/Topology.lean
@@ -24,6 +24,22 @@ namespace ContinuousAlternatingMap
variable {𝕜 E F ι : Type*} [NormedField 𝕜]
[AddCommGroup E] [Module 𝕜 E] [TopologicalSpace E] [AddCommGroup F] [Module 𝕜 F]
+section IsClosedRange
+
+variable [TopologicalSpace F] [TopologicalAddGroup F]
+
+instance instTopologicalSpace : TopologicalSpace (E [⋀^ι]→L[𝕜] F) :=
+ .induced toContinuousMultilinearMap inferInstance
+
+lemma isClosed_range_toContinuousMultilinearMap [ContinuousSMul 𝕜 E] [T2Space F] :
+ IsClosed (Set.range (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F) →
+ ContinuousMultilinearMap 𝕜 (fun _ : ι ↦ E) F)) := by
+ simp only [range_toContinuousMultilinearMap, setOf_forall]
+ repeat refine isClosed_iInter fun _ ↦ ?_
+ exact isClosed_singleton.preimage (continuous_eval_const _)
+
+end IsClosedRange
+
section UniformAddGroup
variable [UniformSpace F] [UniformAddGroup F]
@@ -31,14 +47,17 @@ variable [UniformSpace F] [UniformAddGroup F]
instance instUniformSpace : UniformSpace (E [⋀^ι]→L[𝕜] F) :=
.comap toContinuousMultilinearMap inferInstance
-lemma uniformEmbedding_toContinuousMultilinearMap :
- UniformEmbedding (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F) → _) where
+lemma isUniformEmbedding_toContinuousMultilinearMap :
+ IsUniformEmbedding (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F) → _) where
inj := toContinuousMultilinearMap_injective
comap_uniformity := rfl
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_toContinuousMultilinearMap := isUniformEmbedding_toContinuousMultilinearMap
+
lemma uniformContinuous_toContinuousMultilinearMap :
UniformContinuous (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F) → _) :=
- uniformEmbedding_toContinuousMultilinearMap.uniformContinuous
+ isUniformEmbedding_toContinuousMultilinearMap.uniformContinuous
theorem uniformContinuous_coe_fun [ContinuousSMul 𝕜 E] :
UniformContinuous (DFunLike.coe : (E [⋀^ι]→L[𝕜] F) → (ι → E) → F) :=
@@ -50,28 +69,40 @@ theorem uniformContinuous_eval_const [ContinuousSMul 𝕜 E] (x : ι → E) :
uniformContinuous_pi.1 uniformContinuous_coe_fun x
instance instUniformAddGroup : UniformAddGroup (E [⋀^ι]→L[𝕜] F) :=
- uniformEmbedding_toContinuousMultilinearMap.uniformAddGroup
+ isUniformEmbedding_toContinuousMultilinearMap.uniformAddGroup
(toContinuousMultilinearMapLinear (R := ℕ))
instance instUniformContinuousConstSMul {M : Type*}
[Monoid M] [DistribMulAction M F] [SMulCommClass 𝕜 M F] [ContinuousConstSMul M F] :
UniformContinuousConstSMul M (E [⋀^ι]→L[𝕜] F) :=
- uniformEmbedding_toContinuousMultilinearMap.uniformContinuousConstSMul fun _ _ ↦ rfl
+ 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
- uniformEmbedding_toContinuousMultilinearMap.toUniformInducing, range_toContinuousMultilinearMap]
- simp only [setOf_forall]
- apply IsClosed.isComplete
- repeat refine isClosed_iInter fun _ ↦ ?_
- exact isClosed_singleton.preimage (ContinuousMultilinearMap.continuous_eval_const _)
+ isUniformEmbedding_toContinuousMultilinearMap.isUniformInducing]
+ apply isClosed_range_toContinuousMultilinearMap.isComplete
instance instCompleteSpace [TopologicalAddGroup E] [SequentialSpace (ι → E)] :
CompleteSpace (E [⋀^ι]→L[𝕜] F) :=
@@ -84,15 +115,18 @@ section RestrictScalars
variable (𝕜' : Type*) [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜' 𝕜]
[Module 𝕜' E] [IsScalarTower 𝕜' 𝕜 E] [Module 𝕜' F] [IsScalarTower 𝕜' 𝕜 F] [ContinuousSMul 𝕜 E]
-theorem uniformEmbedding_restrictScalars :
- UniformEmbedding (restrictScalars 𝕜' : E [⋀^ι]→L[𝕜] F → E [⋀^ι]→L[𝕜'] F) := by
- rw [← uniformEmbedding_toContinuousMultilinearMap.of_comp_iff]
- exact (ContinuousMultilinearMap.uniformEmbedding_restrictScalars 𝕜').comp
- uniformEmbedding_toContinuousMultilinearMap
+theorem isUniformEmbedding_restrictScalars :
+ IsUniformEmbedding (restrictScalars 𝕜' : E [⋀^ι]→L[𝕜] F → E [⋀^ι]→L[𝕜'] F) := by
+ rw [← isUniformEmbedding_toContinuousMultilinearMap.of_comp_iff]
+ exact (ContinuousMultilinearMap.isUniformEmbedding_restrictScalars 𝕜').comp
+ isUniformEmbedding_toContinuousMultilinearMap
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_restrictScalars := isUniformEmbedding_restrictScalars
theorem uniformContinuous_restrictScalars :
UniformContinuous (restrictScalars 𝕜' : E [⋀^ι]→L[𝕜] F → E [⋀^ι]→L[𝕜'] F) :=
- (uniformEmbedding_restrictScalars 𝕜').uniformContinuous
+ (isUniformEmbedding_restrictScalars 𝕜').uniformContinuous
end RestrictScalars
@@ -100,27 +134,31 @@ end UniformAddGroup
variable [TopologicalSpace F] [TopologicalAddGroup F]
-instance instTopologicalSpace : TopologicalSpace (E [⋀^ι]→L[𝕜] F) :=
- .induced toContinuousMultilinearMap inferInstance
-
-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)
- uniformEmbedding_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) :
@@ -138,21 +176,27 @@ theorem hasBasis_nhds_zero :
variable [ContinuousSMul 𝕜 E]
-@[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
+lemma isClosedEmbedding_toContinuousMultilinearMap [T2Space F] :
+ IsClosedEmbedding (toContinuousMultilinearMap :
+ (E [⋀^ι]→L[𝕜] F) → ContinuousMultilinearMap 𝕜 (fun _ : ι ↦ E) F) :=
+ ⟨isEmbedding_toContinuousMultilinearMap, isClosed_range_toContinuousMultilinearMap⟩
-theorem continuous_coe_fun :
- Continuous (DFunLike.coe : E [⋀^ι]→L[𝕜] F → (ι → E) → F) :=
- continuous_pi continuous_eval_const
+@[deprecated (since := "2024-10-20")]
+alias closedEmbedding_toContinuousMultilinearMap := isClosedEmbedding_toContinuousMultilinearMap
+
+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
@@ -160,17 +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
- (uniformEmbedding_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
+ Continuous (restrictScalars 𝕜' : E [⋀^ι]→L[𝕜] F → E [⋀^ι]→L[𝕜'] F) :=
+ 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 def18b6123639..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.ContinuousFunction.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
@@ -727,6 +719,18 @@ theorem add_comp [ContinuousAdd M₃] (g₁ g₂ : M₂ →SL[σ₂₃] M₃) (f
ext
simp
+theorem comp_finset_sum {ι : Type*} {s : Finset ι}
+ [ContinuousAdd M₂] [ContinuousAdd M₃] (g : M₂ →SL[σ₂₃] M₃)
+ (f : ι → M₁ →SL[σ₁₂] M₂) : g.comp (∑ i ∈ s, f i) = ∑ i ∈ s, g.comp (f i) := by
+ ext
+ simp
+
+theorem finset_sum_comp {ι : Type*} {s : Finset ι}
+ [ContinuousAdd M₃] (g : ι → M₂ →SL[σ₂₃] M₃)
+ (f : M₁ →SL[σ₁₂] M₂) : (∑ i ∈ s, g i).comp f = ∑ i ∈ s, (g i).comp f := by
+ ext
+ simp only [coe_comp', coe_sum', Function.comp_apply, Finset.sum_apply]
+
theorem comp_assoc {R₄ : Type*} [Semiring R₄] [Module R₄ M₄] {σ₁₄ : R₁ →+* R₄} {σ₂₄ : R₂ →+* R₄}
{σ₃₄ : R₃ →+* R₄} [RingHomCompTriple σ₁₃ σ₃₄ σ₁₄] [RingHomCompTriple σ₂₃ σ₃₄ σ₂₄]
[RingHomCompTriple σ₁₂ σ₂₄ σ₁₄] (h : M₃ →SL[σ₃₄] M₄) (g : M₂ →SL[σ₂₃] M₃) (f : M₁ →SL[σ₁₂] M₂) :
@@ -1127,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 :=
@@ -1172,20 +1176,14 @@ def iInfKerProjEquiv {I J : Set ι} [DecidablePred fun i => i ∈ I] (hd : Disjo
Submodule R (∀ i, φ i)) ≃L[R] ∀ i : I, φ i where
toLinearEquiv := LinearMap.iInfKerProjEquiv R φ hd hu
continuous_toFun :=
- continuous_pi fun i => by
- have :=
+ continuous_pi fun i =>
+ Continuous.comp (continuous_apply (π := φ) i) <|
@continuous_subtype_val _ _ fun x =>
x ∈ (⨅ i ∈ J, ker (proj i : (∀ i, φ i) →L[R] φ i) : Submodule R (∀ i, φ i))
- have := Continuous.comp (continuous_apply (π := φ) i) this
- exact this
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])
_
@@ -1421,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]
@@ -1508,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₂]
@@ -1599,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]
@@ -1633,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
@@ -1690,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
@@ -1750,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]
@@ -1807,8 +1800,8 @@ theorem trans_toLinearEquiv (e₁ : M₁ ≃SL[σ₁₂] M₂) (e₂ : M₂ ≃S
def prod [Module R₁ M₂] [Module R₁ M₃] [Module R₁ M₄] (e : M₁ ≃L[R₁] M₂) (e' : M₃ ≃L[R₁] M₄) :
(M₁ × M₃) ≃L[R₁] M₂ × M₄ :=
{ e.toLinearEquiv.prod e'.toLinearEquiv with
- continuous_toFun := e.continuous_toFun.prod_map e'.continuous_toFun
- continuous_invFun := e.continuous_invFun.prod_map e'.continuous_invFun }
+ continuous_toFun := e.continuous_toFun.prodMap e'.continuous_toFun
+ continuous_invFun := e.continuous_invFun.prodMap e'.continuous_invFun }
@[simp, norm_cast]
theorem prod_apply [Module R₁ M₂] [Module R₁ M₃] [Module R₁ M₄] (e : M₁ ≃L[R₁] M₂)
@@ -1932,22 +1925,27 @@ protected theorem preimage_symm_preimage (e : M₁ ≃SL[σ₁₂] M₂) (s : Se
e ⁻¹' (e.symm ⁻¹' s) = s :=
e.symm.symm_preimage_preimage s
-protected theorem uniformEmbedding {E₁ E₂ : Type*} [UniformSpace E₁] [UniformSpace E₂]
+lemma isUniformEmbedding {E₁ E₂ : Type*} [UniformSpace E₁] [UniformSpace E₂]
[AddCommGroup E₁] [AddCommGroup E₂] [Module R₁ E₁] [Module R₂ E₂] [UniformAddGroup E₁]
- [UniformAddGroup E₂] (e : E₁ ≃SL[σ₁₂] E₂) : UniformEmbedding e :=
- e.toLinearEquiv.toEquiv.uniformEmbedding e.toContinuousLinearMap.uniformContinuous
+ [UniformAddGroup E₂] (e : E₁ ≃SL[σ₁₂] E₂) : IsUniformEmbedding e :=
+ e.toLinearEquiv.toEquiv.isUniformEmbedding e.toContinuousLinearMap.uniformContinuous
e.symm.toContinuousLinearMap.uniformContinuous
-protected theorem _root_.LinearEquiv.uniformEmbedding {E₁ E₂ : Type*} [UniformSpace E₁]
+@[deprecated (since := "2024-10-01")] alias uniformEmbedding := isUniformEmbedding
+
+protected theorem _root_.LinearEquiv.isUniformEmbedding {E₁ E₂ : Type*} [UniformSpace E₁]
[UniformSpace E₂] [AddCommGroup E₁] [AddCommGroup E₂] [Module R₁ E₁] [Module R₂ E₂]
[UniformAddGroup E₁] [UniformAddGroup E₂] (e : E₁ ≃ₛₗ[σ₁₂] E₂)
- (h₁ : Continuous e) (h₂ : Continuous e.symm) : UniformEmbedding e :=
- ContinuousLinearEquiv.uniformEmbedding
+ (h₁ : Continuous e) (h₂ : Continuous e.symm) : IsUniformEmbedding e :=
+ ContinuousLinearEquiv.isUniformEmbedding
({ e with
continuous_toFun := h₁
continuous_invFun := h₂ } :
E₁ ≃SL[σ₁₂] E₂)
+@[deprecated (since := "2024-10-01")]
+alias _root_.LinearEquiv.uniformEmbedding := _root_.LinearEquiv.isUniformEmbedding
+
/-- Create a `ContinuousLinearEquiv` from two `ContinuousLinearMap`s that are
inverse of each other. -/
def equivOfInverse (f₁ : M₁ →SL[σ₁₂] M₂) (f₂ : M₂ →SL[σ₂₁] M₁) (h₁ : Function.LeftInverse f₂ f₁)
@@ -2015,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
@@ -2050,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
@@ -2059,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
@@ -2305,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
@@ -2365,29 +2405,40 @@ variable {R M : Type*} [Ring R] [AddCommGroup M] [Module R M] [TopologicalSpace
instance _root_.QuotientModule.Quotient.topologicalSpace : TopologicalSpace (M ⧸ S) :=
inferInstanceAs (TopologicalSpace (Quotient S.quotientRel))
-theorem isOpenMap_mkQ [TopologicalAddGroup M] : IsOpenMap S.mkQ :=
- QuotientAddGroup.isOpenMap_coe S.toAddSubgroup
+theorem isOpenMap_mkQ [ContinuousAdd M] : IsOpenMap S.mkQ :=
+ QuotientAddGroup.isOpenMap_coe
+
+theorem isOpenQuotientMap_mkQ [ContinuousAdd M] : IsOpenQuotientMap S.mkQ :=
+ QuotientAddGroup.isOpenQuotientMap_mk
instance topologicalAddGroup_quotient [TopologicalAddGroup M] : TopologicalAddGroup (M ⧸ S) :=
inferInstanceAs <| TopologicalAddGroup (M ⧸ S.toAddSubgroup)
instance continuousSMul_quotient [TopologicalSpace R] [TopologicalAddGroup M] [ContinuousSMul R M] :
- ContinuousSMul R (M ⧸ S) := by
- constructor
- have quot : QuotientMap fun au : R × M => (au.1, S.mkQ au.2) :=
- IsOpenMap.to_quotientMap (IsOpenMap.id.prod S.isOpenMap_mkQ)
- (continuous_id.prod_map continuous_quot_mk)
- (Function.surjective_id.prodMap <| surjective_quot_mk _)
- rw [quot.continuous_iff]
- exact continuous_quot_mk.comp continuous_smul
+ ContinuousSMul R (M ⧸ S) where
+ continuous_smul := by
+ rw [← (IsOpenQuotientMap.id.prodMap S.isOpenQuotientMap_mkQ).continuous_comp_iff]
+ exact continuous_quot_mk.comp continuous_smul
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/CharacterSpace.lean b/Mathlib/Topology/Algebra/Module/CharacterSpace.lean
index aa4aeffcdfcb1..39d280cac3ba7 100644
--- a/Mathlib/Topology/Algebra/Module/CharacterSpace.lean
+++ b/Mathlib/Topology/Algebra/Module/CharacterSpace.lean
@@ -5,7 +5,7 @@ Authors: Frédéric Dupuis
-/
import Mathlib.Topology.Algebra.Module.WeakDual
import Mathlib.Algebra.Algebra.Spectrum
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.Topology.ContinuousMap.Algebra
import Mathlib.Data.Set.Lattice
/-!
diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean
index 8b1c1ca19d66a..bdab9d7a3ba36 100644
--- a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean
+++ b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean
@@ -47,7 +47,7 @@ universe u v w x
noncomputable section
-open Set FiniteDimensional TopologicalSpace Filter
+open Filter Module Set TopologicalSpace
section Field
@@ -106,7 +106,7 @@ theorem unique_topology_of_t2 {t : TopologicalSpace 𝕜} (h₁ : @TopologicalAd
-- For that, we use that `𝓑` is balanced : since `‖ξ₀‖ < ε < ‖ξ‖`, we have `‖ξ₀ / ξ‖ ≤ 1`,
-- hence `ξ₀ = (ξ₀ / ξ) • ξ ∈ 𝓑` because `ξ ∈ 𝓑`.
refine (balancedCore_balanced _).smul_mem ?_ hξ
- rw [norm_mul, norm_inv, mul_inv_le_iff (norm_pos_iff.mpr hξ0), mul_one]
+ rw [norm_mul, norm_inv, mul_inv_le_iff₀ (norm_pos_iff.mpr hξ0), one_mul]
exact (hξ₀ε.trans h).le
· -- Finally, to show `𝓣₀ ≤ 𝓣`, we simply argue that `id = (fun x ↦ x • 1)` is continuous from
-- `(𝕜, 𝓣₀)` to `(𝕜, 𝓣)` because `(•) : (𝕜, 𝓣₀) × (𝕜, 𝓣) → (𝕜, 𝓣)` is continuous.
@@ -197,22 +197,22 @@ private theorem continuous_equivFun_basis_aux [T2Space E] {ι : Type v} [Fintype
induction' hn : Fintype.card ι with n IH generalizing ι E
· rw [Fintype.card_eq_zero_iff] at hn
exact continuous_of_const fun x y => funext hn.elim
- · haveI : FiniteDimensional 𝕜 E := of_fintype_basis ξ
+ · haveI : FiniteDimensional 𝕜 E := .of_fintype_basis ξ
-- first step: thanks to the induction hypothesis, any n-dimensional subspace is equivalent
-- to a standard space of dimension n, hence it is complete and therefore closed.
have H₁ : ∀ s : Submodule 𝕜 E, finrank 𝕜 s = n → IsClosed (s : Set E) := by
intro s s_dim
letI : UniformAddGroup s := s.toAddSubgroup.uniformAddGroup
let b := Basis.ofVectorSpace 𝕜 s
- have U : UniformEmbedding b.equivFun.symm.toEquiv := by
+ have U : IsUniformEmbedding b.equivFun.symm.toEquiv := by
have : Fintype.card (Basis.ofVectorSpaceIndex 𝕜 s) = n := by
rw [← s_dim]
exact (finrank_eq_card_basis b).symm
have : Continuous b.equivFun := IH b this
exact
- b.equivFun.symm.uniformEmbedding b.equivFun.symm.toLinearMap.continuous_on_pi this
+ b.equivFun.symm.isUniformEmbedding b.equivFun.symm.toLinearMap.continuous_on_pi this
have : IsComplete (s : Set E) :=
- completeSpace_coe_iff_isComplete.1 ((completeSpace_congr U).1 (by infer_instance))
+ completeSpace_coe_iff_isComplete.1 ((completeSpace_congr U).1 inferInstance)
exact this.isClosed
-- second step: any linear form is continuous, as its kernel is closed by the first step
have H₂ : ∀ f : E →ₗ[𝕜] 𝕜, Continuous f := by
@@ -264,7 +264,7 @@ continuous (see `LinearMap.continuous_of_finiteDimensional`), which in turn impl
norms are equivalent in finite dimensions. -/
theorem continuous_equivFun_basis [T2Space E] {ι : Type*} [Finite ι] (ξ : Basis ι 𝕜 E) :
Continuous ξ.equivFun :=
- haveI : FiniteDimensional 𝕜 E := of_fintype_basis ξ
+ haveI : FiniteDimensional 𝕜 E := .of_fintype_basis ξ
ξ.equivFun.toLinearMap.continuous_of_finiteDimensional
namespace LinearMap
@@ -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
@@ -490,8 +489,8 @@ variable (𝕜 E : Type*) [NontriviallyNormedField 𝕜]
include 𝕜 in
theorem FiniteDimensional.complete [FiniteDimensional 𝕜 E] : CompleteSpace E := by
set e := ContinuousLinearEquiv.ofFinrankEq (@finrank_fin_fun 𝕜 _ _ (finrank 𝕜 E)).symm
- have : UniformEmbedding e.toLinearEquiv.toEquiv.symm := e.symm.uniformEmbedding
- exact (completeSpace_congr this).1 (by infer_instance)
+ have : IsUniformEmbedding e.toEquiv.symm := e.symm.isUniformEmbedding
+ exact (completeSpace_congr this).1 inferInstance
variable {𝕜 E}
@@ -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 c4849ddb17994..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₂ :=
@@ -202,7 +199,7 @@ end ContinuousAdd
/-- If `f` is a continuous multilinear map, then `f.toContinuousLinearMap m i` is the continuous
linear map obtained by fixing all coordinates but `i` equal to those of `m`, and varying the
`i`-th coordinate. -/
-def toContinuousLinearMap [DecidableEq ι] (m : ∀ i, M₁ i) (i : ι) : M₁ i →L[R] M₂ :=
+@[simps!] def toContinuousLinearMap [DecidableEq ι] (m : ∀ i, M₁ i) (i : ι) : M₁ i →L[R] M₂ :=
{ f.toMultilinearMap.toLinearMap m i with
cont := f.cont.comp (continuous_const.update i continuous_id) }
diff --git a/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean b/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean
index a403ef7dca6bd..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,18 +67,29 @@ section UniformAddGroup
variable [UniformSpace F] [UniformAddGroup F]
-lemma uniformEmbedding_toUniformOnFun :
- UniformEmbedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → _) where
- inj := DFunLike.coe_injective
- comap_uniformity := rfl
+lemma isUniformInducing_toUniformOnFun :
+ IsUniformInducing (toUniformOnFun :
+ ContinuousMultilinearMap 𝕜 E F → ((Π i, E i) →ᵤ[{s | IsVonNBounded 𝕜 s}] F)) := ⟨rfl⟩
-lemma embedding_toUniformOnFun : Embedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → _) :=
- uniformEmbedding_toUniformOnFun.embedding
+lemma isUniformEmbedding_toUniformOnFun :
+ IsUniformEmbedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → _) :=
+ ⟨isUniformInducing_toUniformOnFun, DFunLike.coe_injective⟩
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_toUniformOnFun := isUniformEmbedding_toUniformOnFun
+
+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) :=
(UniformOnFun.uniformContinuous_toFun isVonNBounded_covers).comp
- uniformEmbedding_toUniformOnFun.uniformContinuous
+ isUniformEmbedding_toUniformOnFun.uniformContinuous
theorem uniformContinuous_eval_const [∀ i, ContinuousSMul 𝕜 (E i)] (x : Π i, E i) :
UniformContinuous fun f : ContinuousMultilinearMap 𝕜 E F ↦ f x :=
@@ -85,27 +98,41 @@ theorem uniformContinuous_eval_const [∀ i, ContinuousSMul 𝕜 (E i)] (x : Π
instance instUniformAddGroup : UniformAddGroup (ContinuousMultilinearMap 𝕜 E F) :=
let φ : ContinuousMultilinearMap 𝕜 E F →+ (Π i, E i) →ᵤ[{s | IsVonNBounded 𝕜 s}] F :=
{ toFun := toUniformOnFun, map_add' := fun _ _ ↦ rfl, map_zero' := rfl }
- uniformEmbedding_toUniformOnFun.uniformAddGroup φ
+ isUniformEmbedding_toUniformOnFun.uniformAddGroup φ
instance instUniformContinuousConstSMul {M : Type*}
[Monoid M] [DistribMulAction M F] [SMulCommClass 𝕜 M F] [ContinuousConstSMul M F] :
UniformContinuousConstSMul M (ContinuousMultilinearMap 𝕜 E F) :=
haveI := uniformContinuousConstSMul_of_continuousConstSMul M F
- uniformEmbedding_toUniformOnFun.uniformContinuousConstSMul fun _ _ ↦ rfl
+ 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 uniformEmbedding_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
@@ -126,19 +153,22 @@ variable (𝕜' : Type*) [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜'
[∀ i, Module 𝕜' (E i)] [∀ i, IsScalarTower 𝕜' 𝕜 (E i)] [Module 𝕜' F] [IsScalarTower 𝕜' 𝕜 F]
[∀ i, ContinuousSMul 𝕜 (E i)]
-theorem uniformEmbedding_restrictScalars :
- UniformEmbedding
+theorem isUniformEmbedding_restrictScalars :
+ IsUniformEmbedding
(restrictScalars 𝕜' : ContinuousMultilinearMap 𝕜 E F → ContinuousMultilinearMap 𝕜' E F) := by
letI : NontriviallyNormedField 𝕜 :=
⟨let ⟨x, hx⟩ := @NontriviallyNormedField.non_trivial 𝕜' _; ⟨algebraMap 𝕜' 𝕜 x, by simpa⟩⟩
- rw [← uniformEmbedding_toUniformOnFun.of_comp_iff]
- convert uniformEmbedding_toUniformOnFun using 4 with s
+ rw [← isUniformEmbedding_toUniformOnFun.of_comp_iff]
+ convert isUniformEmbedding_toUniformOnFun using 4 with s
exact ⟨fun h ↦ h.extend_scalars _, fun h ↦ h.restrict_scalars _⟩
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_restrictScalars := isUniformEmbedding_restrictScalars
+
theorem uniformContinuous_restrictScalars :
UniformContinuous
(restrictScalars 𝕜' : ContinuousMultilinearMap 𝕜 E F → ContinuousMultilinearMap 𝕜' E F) :=
- (uniformEmbedding_restrictScalars 𝕜').uniformContinuous
+ (isUniformEmbedding_restrictScalars 𝕜').uniformContinuous
end RestrictScalars
@@ -146,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
@@ -160,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) :
@@ -182,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
- (uniformEmbedding_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 437453ea31e0d..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,8 +56,8 @@ sets).
uniform convergence, bounded convergence
-/
-
-open scoped Topology UniformConvergence
+open scoped Topology UniformConvergence Uniformity
+open Filter Set Function Bornology
section General
@@ -73,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)) :
@@ -92,7 +93,7 @@ instance instTopologicalSpace [TopologicalSpace F] [TopologicalAddGroup F] (𝔖
(DFunLike.coe : (UniformConvergenceCLM σ F 𝔖) → (E →ᵤ[𝔖] F))
theorem topologicalSpace_eq [UniformSpace F] [UniformAddGroup F] (𝔖 : Set (Set E)) :
- instTopologicalSpace σ F 𝔖 = TopologicalSpace.induced DFunLike.coe
+ instTopologicalSpace σ F 𝔖 = TopologicalSpace.induced (UniformOnFun.ofFun 𝔖 ∘ DFunLike.coe)
(UniformOnFun.topologicalSpace E F 𝔖) := by
rw [instTopologicalSpace]
congr
@@ -103,12 +104,13 @@ that this has nice definitional properties. -/
instance instUniformSpace [UniformSpace F] [UniformAddGroup F]
(𝔖 : Set (Set E)) : UniformSpace (UniformConvergenceCLM σ F 𝔖) :=
UniformSpace.replaceTopology
- ((UniformOnFun.uniformSpace E F 𝔖).comap
- (DFunLike.coe : (UniformConvergenceCLM σ F 𝔖) → (E →ᵤ[𝔖] F)))
+ ((UniformOnFun.uniformSpace E F 𝔖).comap (UniformOnFun.ofFun 𝔖 ∘ DFunLike.coe))
(by rw [UniformConvergenceCLM.instTopologicalSpace, UniformAddGroup.toUniformSpace_eq]; rfl)
theorem uniformSpace_eq [UniformSpace F] [UniformAddGroup F] (𝔖 : Set (Set E)) :
- instUniformSpace σ F 𝔖 = UniformSpace.comap DFunLike.coe (UniformOnFun.uniformSpace E F 𝔖) := by
+ instUniformSpace σ F 𝔖 =
+ UniformSpace.comap (UniformOnFun.ofFun 𝔖 ∘ DFunLike.coe)
+ (UniformOnFun.uniformSpace E F 𝔖) := by
rw [instUniformSpace, UniformSpace.replaceTopology_eq]
@[simp]
@@ -117,23 +119,38 @@ theorem uniformity_toTopologicalSpace_eq [UniformSpace F] [UniformAddGroup F] (
UniformConvergenceCLM.instTopologicalSpace σ F 𝔖 :=
rfl
-theorem uniformEmbedding_coeFn [UniformSpace F] [UniformAddGroup F] (𝔖 : Set (Set E)) :
- UniformEmbedding (α := UniformConvergenceCLM σ F 𝔖) (β := E →ᵤ[𝔖] F) DFunLike.coe :=
- ⟨⟨rfl⟩, DFunLike.coe_injective⟩
+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) :=
+ ⟨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) :=
- UniformEmbedding.embedding (uniformEmbedding_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
+@[simp]
+theorem coe_zero [TopologicalSpace F] [TopologicalAddGroup F] (𝔖 : Set (Set E)) :
+ ⇑(0 : UniformConvergenceCLM σ F 𝔖) = 0 :=
+ rfl
+
instance instUniformAddGroup [UniformSpace F] [UniformAddGroup F] (𝔖 : Set (Set E)) :
UniformAddGroup (UniformConvergenceCLM σ F 𝔖) := by
let φ : (UniformConvergenceCLM σ F 𝔖) →+ E →ᵤ[𝔖] F :=
⟨⟨(DFunLike.coe : (UniformConvergenceCLM σ F 𝔖) → E →ᵤ[𝔖] F), rfl⟩, fun _ _ => rfl⟩
- exact (uniformEmbedding_coeFn _ _ _).uniformAddGroup φ
+ exact (isUniformEmbedding_coeFn _ _ _).uniformAddGroup φ
instance instTopologicalAddGroup [TopologicalSpace F] [TopologicalAddGroup F]
(𝔖 : Set (Set E)) : TopologicalAddGroup (UniformConvergenceCLM σ F 𝔖) := by
@@ -141,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𝔖 : ⋃₀ 𝔖 = Set.univ) : T2Space (UniformConvergenceCLM σ F 𝔖) := by
+ (𝔖 : 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)) :
@@ -158,7 +184,7 @@ instance instModule (R : Type*) [Semiring R] [Module R F] [SMulCommClass 𝕜₂
theorem continuousSMul [RingHomSurjective σ] [RingHomIsometric σ]
[TopologicalSpace F] [TopologicalAddGroup F] [ContinuousSMul 𝕜₂ F] (𝔖 : Set (Set E))
- (h𝔖₃ : ∀ S ∈ 𝔖, Bornology.IsVonNBounded 𝕜₁ S) :
+ (h𝔖₃ : ∀ S ∈ 𝔖, IsVonNBounded 𝕜₁ S) :
ContinuousSMul 𝕜₂ (UniformConvergenceCLM σ F 𝔖) := by
letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F
haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform
@@ -175,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]
@@ -185,11 +211,66 @@ theorem hasBasis_nhds_zero [TopologicalSpace F] [TopologicalAddGroup F]
{ f : UniformConvergenceCLM σ F 𝔖 | ∀ x ∈ SV.1, f x ∈ SV.2 } :=
hasBasis_nhds_zero_of_basis σ F 𝔖 h𝔖₁ h𝔖₂ (𝓝 0).basis_sets
+theorem nhds_zero_eq_of_basis [TopologicalSpace F] [TopologicalAddGroup F] (𝔖 : Set (Set E))
+ {ι : Type*} {p : ι → Prop} {b : ι → Set F} (h : (𝓝 0 : Filter F).HasBasis p b) :
+ 𝓝 (0 : UniformConvergenceCLM σ F 𝔖) =
+ ⨅ (s : Set E) (_ : s ∈ 𝔖) (i : ι) (_ : p i),
+ 𝓟 {f : UniformConvergenceCLM σ F 𝔖 | MapsTo f s (b i)} := by
+ letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F
+ haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform
+ rw [(isEmbedding_coeFn σ F 𝔖).isInducing.nhds_eq_comap,
+ UniformOnFun.nhds_eq_of_basis _ _ h.uniformity_of_nhds_zero]
+ simp [MapsTo]
+
+theorem nhds_zero_eq [TopologicalSpace F] [TopologicalAddGroup F] (𝔖 : Set (Set E)) :
+ 𝓝 (0 : UniformConvergenceCLM σ F 𝔖) =
+ ⨅ s ∈ 𝔖, ⨅ t ∈ 𝓝 (0 : F),
+ 𝓟 {f : UniformConvergenceCLM σ F 𝔖 | MapsTo f s t} :=
+ nhds_zero_eq_of_basis _ _ _ (𝓝 0).basis_sets
+
+variable {F} in
+theorem eventually_nhds_zero_mapsTo [TopologicalSpace F] [TopologicalAddGroup F]
+ {𝔖 : Set (Set E)} {s : Set E} (hs : s ∈ 𝔖) {U : Set F} (hu : U ∈ 𝓝 0) :
+ ∀ᶠ f : UniformConvergenceCLM σ F 𝔖 in 𝓝 0, MapsTo f s U := by
+ rw [nhds_zero_eq]
+ apply_rules [mem_iInf_of_mem, mem_principal_self]
+
+variable {σ F} in
+theorem isVonNBounded_image2_apply {R : Type*} [SeminormedRing R]
+ [TopologicalSpace F] [TopologicalAddGroup F]
+ [Module R F] [ContinuousConstSMul R F] [SMulCommClass 𝕜₂ R F]
+ {𝔖 : Set (Set E)} {S : Set (UniformConvergenceCLM σ F 𝔖)} (hS : IsVonNBounded R S)
+ {s : Set E} (hs : s ∈ 𝔖) : IsVonNBounded R (Set.image2 (fun f x ↦ f x) S s) := by
+ intro U hU
+ filter_upwards [hS (eventually_nhds_zero_mapsTo σ hs hU)] with c hc
+ rw [image2_subset_iff]
+ intro f hf x hx
+ rcases hc hf with ⟨g, hg, rfl⟩
+ exact smul_mem_smul_set (hg hx)
+
+variable {σ F} in
+/-- A set `S` of continuous linear maps with topology of uniform convergence on sets `s ∈ 𝔖`
+is von Neumann bounded iff for any `s ∈ 𝔖`,
+the set `{f x | (f ∈ S) (x ∈ s)}` is von Neumann bounded. -/
+theorem isVonNBounded_iff {R : Type*} [NormedDivisionRing R]
+ [TopologicalSpace F] [TopologicalAddGroup F]
+ [Module R F] [ContinuousConstSMul R F] [SMulCommClass 𝕜₂ R F]
+ {𝔖 : Set (Set E)} {S : Set (UniformConvergenceCLM σ F 𝔖)} :
+ IsVonNBounded R S ↔ ∀ s ∈ 𝔖, IsVonNBounded R (Set.image2 (fun f x ↦ f x) S s) := by
+ refine ⟨fun hS s hs ↦ isVonNBounded_image2_apply hS hs, fun h ↦ ?_⟩
+ simp_rw [isVonNBounded_iff_absorbing_le, nhds_zero_eq, le_iInf_iff, le_principal_iff]
+ intro s hs U hU
+ rw [Filter.mem_absorbing, Absorbs]
+ filter_upwards [h s hs hU, eventually_ne_cobounded 0] with c hc hc₀ f hf
+ rw [mem_smul_set_iff_inv_smul_mem₀ hc₀]
+ intro x hx
+ simpa only [mem_smul_set_iff_inv_smul_mem₀ hc₀] using hc (mem_image2_of_mem hf hx)
+
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 𝔖) :=
- (uniformEmbedding_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]
@@ -204,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 : 𝔖₂ ⊆ 𝔖₁) :
@@ -240,7 +347,7 @@ variable {𝕜₁ 𝕜₂ 𝕜₃ : Type*} [NormedField 𝕜₁] [NormedField
the operator norm when `E` and `F` are normed spaces. -/
instance topologicalSpace [TopologicalSpace F] [TopologicalAddGroup F] :
TopologicalSpace (E →SL[σ] F) :=
- UniformConvergenceCLM.instTopologicalSpace σ F { S | Bornology.IsVonNBounded 𝕜₁ S }
+ UniformConvergenceCLM.instTopologicalSpace σ F { S | IsVonNBounded 𝕜₁ S }
instance topologicalAddGroup [TopologicalSpace F] [TopologicalAddGroup F] :
TopologicalAddGroup (E →SL[σ] F) :=
@@ -248,37 +355,43 @@ instance topologicalAddGroup [TopologicalSpace F] [TopologicalAddGroup F] :
instance continuousSMul [RingHomSurjective σ] [RingHomIsometric σ] [TopologicalSpace F]
[TopologicalAddGroup F] [ContinuousSMul 𝕜₂ F] : ContinuousSMul 𝕜₂ (E →SL[σ] F) :=
- UniformConvergenceCLM.continuousSMul σ F { S | Bornology.IsVonNBounded 𝕜₁ S } fun _ hs => hs
+ UniformConvergenceCLM.continuousSMul σ F { S | IsVonNBounded 𝕜₁ S } fun _ hs => hs
instance uniformSpace [UniformSpace F] [UniformAddGroup F] : UniformSpace (E →SL[σ] F) :=
- UniformConvergenceCLM.instUniformSpace σ F { S | Bornology.IsVonNBounded 𝕜₁ S }
+ UniformConvergenceCLM.instUniformSpace σ F { S | IsVonNBounded 𝕜₁ S }
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) (Bornology.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) :
- (𝓝 (0 : E →SL[σ] F)).HasBasis (fun Si : Set E × ι => Bornology.IsVonNBounded 𝕜₁ Si.1 ∧ p Si.2)
+ (𝓝 (0 : E →SL[σ] F)).HasBasis (fun Si : Set E × ι => IsVonNBounded 𝕜₁ Si.1 ∧ p Si.2)
fun Si => { f : E →SL[σ] F | ∀ x ∈ Si.1, f x ∈ b Si.2 } :=
- UniformConvergenceCLM.hasBasis_nhds_zero_of_basis σ F { S | Bornology.IsVonNBounded 𝕜₁ S }
- ⟨∅, Bornology.isVonNBounded_empty 𝕜₁ E⟩
- (directedOn_of_sup_mem fun _ _ => Bornology.IsVonNBounded.union) h
+ UniformConvergenceCLM.hasBasis_nhds_zero_of_basis σ F { S | IsVonNBounded 𝕜₁ S }
+ ⟨∅, isVonNBounded_empty 𝕜₁ E⟩
+ (directedOn_of_sup_mem fun _ _ => IsVonNBounded.union) h
protected theorem hasBasis_nhds_zero [TopologicalSpace F] [TopologicalAddGroup F] :
(𝓝 (0 : E →SL[σ] F)).HasBasis
- (fun SV : Set E × Set F => Bornology.IsVonNBounded 𝕜₁ SV.1 ∧ SV.2 ∈ (𝓝 0 : Filter F))
+ (fun SV : Set E × Set F => IsVonNBounded 𝕜₁ SV.1 ∧ SV.2 ∈ (𝓝 0 : Filter F))
fun SV => { f : E →SL[σ] F | ∀ x ∈ SV.1, f x ∈ SV.2 } :=
ContinuousLinearMap.hasBasis_nhds_zero_of_basis (𝓝 0).basis_sets
-theorem uniformEmbedding_toUniformOnFun [UniformSpace F] [UniformAddGroup F] :
- UniformEmbedding fun f : E →SL[σ] F ↦ UniformOnFun.ofFun {s | Bornology.IsVonNBounded 𝕜₁ s} f :=
- UniformConvergenceCLM.uniformEmbedding_coeFn ..
+theorem isUniformEmbedding_toUniformOnFun [UniformSpace F] [UniformAddGroup F] :
+ IsUniformEmbedding
+ fun f : E →SL[σ] F ↦ UniformOnFun.ofFun {s | Bornology.IsVonNBounded 𝕜₁ s} f :=
+ UniformConvergenceCLM.isUniformEmbedding_coeFn ..
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_toUniformOnFun := isUniformEmbedding_toUniformOnFun
instance uniformContinuousConstSMul
{M : Type*} [Monoid M] [DistribMulAction M F] [SMulCommClass 𝕜₂ M F]
@@ -291,6 +404,61 @@ instance continuousConstSMul {M : Type*} [Monoid M] [DistribMulAction M F] [SMul
ContinuousConstSMul M (E →SL[σ] F) :=
UniformConvergenceCLM.instContinuousConstSMul σ F _ _
+protected theorem nhds_zero_eq_of_basis [TopologicalSpace F] [TopologicalAddGroup F]
+ {ι : Type*} {p : ι → Prop} {b : ι → Set F} (h : (𝓝 0 : Filter F).HasBasis p b) :
+ 𝓝 (0 : E →SL[σ] F) =
+ ⨅ (s : Set E) (_ : IsVonNBounded 𝕜₁ s) (i : ι) (_ : p i),
+ 𝓟 {f : E →SL[σ] F | MapsTo f s (b i)} :=
+ UniformConvergenceCLM.nhds_zero_eq_of_basis _ _ _ h
+
+protected theorem nhds_zero_eq [TopologicalSpace F] [TopologicalAddGroup F] :
+ 𝓝 (0 : E →SL[σ] F) =
+ ⨅ (s : Set E) (_ : IsVonNBounded 𝕜₁ s) (U : Set F) (_ : U ∈ 𝓝 0),
+ 𝓟 {f : E →SL[σ] F | MapsTo f s U} :=
+ UniformConvergenceCLM.nhds_zero_eq ..
+
+/-- If `s` is a von Neumann bounded set and `U` is a neighbourhood of zero,
+then sufficiently small continuous linear maps map `s` to `U`. -/
+theorem eventually_nhds_zero_mapsTo [TopologicalSpace F] [TopologicalAddGroup F]
+ {s : Set E} (hs : IsVonNBounded 𝕜₁ s) {U : Set F} (hu : U ∈ 𝓝 0) :
+ ∀ᶠ f : E →SL[σ] F in 𝓝 0, MapsTo f s U :=
+ UniformConvergenceCLM.eventually_nhds_zero_mapsTo _ hs hu
+
+/-- If `S` is a von Neumann bounded set of continuous linear maps `f : E →SL[σ] F`
+and `s` is a von Neumann bounded set in the domain,
+then the set `{f x | (f ∈ S) (x ∈ s)}` is von Neumann bounded.
+
+See also `isVonNBounded_iff` for an `Iff` version with stronger typeclass assumptions. -/
+theorem isVonNBounded_image2_apply {R : Type*} [SeminormedRing R]
+ [TopologicalSpace F] [TopologicalAddGroup F]
+ [Module R F] [ContinuousConstSMul R F] [SMulCommClass 𝕜₂ R F]
+ {S : Set (E →SL[σ] F)} (hS : IsVonNBounded R S) {s : Set E} (hs : IsVonNBounded 𝕜₁ s) :
+ IsVonNBounded R (Set.image2 (fun f x ↦ f x) S s) :=
+ UniformConvergenceCLM.isVonNBounded_image2_apply hS hs
+
+/-- A set `S` of continuous linear maps is von Neumann bounded
+iff for any von Neumann bounded set `s`,
+the set `{f x | (f ∈ S) (x ∈ s)}` is von Neumann bounded.
+
+For the forward implication with weaker typeclass assumptions, see `isVonNBounded_image2_apply`. -/
+theorem isVonNBounded_iff {R : Type*} [NormedDivisionRing R]
+ [TopologicalSpace F] [TopologicalAddGroup F]
+ [Module R F] [ContinuousConstSMul R F] [SMulCommClass 𝕜₂ R F]
+ {S : Set (E →SL[σ] F)} :
+ IsVonNBounded R S ↔
+ ∀ 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.
@@ -305,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}
@@ -327,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
@@ -362,15 +530,18 @@ variable [UniformSpace F] [UniformAddGroup F] [Module 𝕜 F]
(𝕜' : Type*) [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜' 𝕜]
[Module 𝕜' E] [IsScalarTower 𝕜' 𝕜 E] [Module 𝕜' F] [IsScalarTower 𝕜' 𝕜 F]
-theorem uniformEmbedding_restrictScalars :
- UniformEmbedding (restrictScalars 𝕜' : (E →L[𝕜] F) → (E →L[𝕜'] F)) := by
- rw [← uniformEmbedding_toUniformOnFun.of_comp_iff]
- convert uniformEmbedding_toUniformOnFun using 4 with s
+theorem isUniformEmbedding_restrictScalars :
+ IsUniformEmbedding (restrictScalars 𝕜' : (E →L[𝕜] F) → (E →L[𝕜'] F)) := by
+ rw [← isUniformEmbedding_toUniformOnFun.of_comp_iff]
+ convert isUniformEmbedding_toUniformOnFun using 4 with s
exact ⟨fun h ↦ h.extend_scalars _, fun h ↦ h.restrict_scalars _⟩
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_restrictScalars := isUniformEmbedding_restrictScalars
+
theorem uniformContinuous_restrictScalars :
UniformContinuous (restrictScalars 𝕜' : (E →L[𝕜] F) → (E →L[𝕜'] F)) :=
- (uniformEmbedding_restrictScalars 𝕜').uniformContinuous
+ (isUniformEmbedding_restrictScalars 𝕜').uniformContinuous
end UniformSpace
@@ -378,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
- (uniformEmbedding_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
new file mode 100644
index 0000000000000..256a8a929210a
--- /dev/null
+++ b/Mathlib/Topology/Algebra/Module/WeakBilin.lean
@@ -0,0 +1,164 @@
+/-
+Copyright (c) 2021 Kalle Kytölä. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Kalle Kytölä, Moritz Doll
+-/
+import Mathlib.Algebra.Algebra.Defs
+import Mathlib.Topology.Algebra.Group.Basic
+
+/-!
+# Weak dual topology
+
+This file defines the weak topology given two vector spaces `E` and `F` over a commutative semiring
+`𝕜` and a bilinear form `B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜`. The weak topology on `E` is the coarsest topology
+such that for all `y : F` every map `fun x => B x y` is continuous.
+
+## Main definitions
+
+The main definition is the type `WeakBilin B`.
+
+* Given `B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜`, the type `WeakBilin B` is a type synonym for `E`.
+* The instance `WeakBilin.instTopologicalSpace` is the weak topology induced by the bilinear form
+ `B`.
+
+## Main results
+
+We establish that `WeakBilin B` has the following structure:
+* `WeakBilin.instContinuousAdd`: The addition in `WeakBilin B` is continuous.
+* `WeakBilin.instContinuousSMul`: The scalar multiplication in `WeakBilin B` is continuous.
+
+We prove the following results characterizing the weak topology:
+* `eval_continuous`: For any `y : F`, the evaluation mapping `fun x => B x y` is continuous.
+* `continuous_of_continuous_eval`: For a mapping to `WeakBilin B` to be continuous,
+ it suffices that its compositions with pairing with `B` at all points `y : F` is continuous.
+* `tendsto_iff_forall_eval_tendsto`: Convergence in `WeakBilin B` can be characterized
+ in terms of convergence of the evaluations at all points `y : F`.
+
+## Notations
+
+No new notation is introduced.
+
+## References
+
+* [H. H. Schaefer, *Topological Vector Spaces*][schaefer1966]
+
+## Tags
+
+weak-star, weak dual, duality
+
+-/
+
+
+noncomputable section
+
+open Filter
+
+open Topology
+
+variable {α 𝕜 𝕝 E F : Type*}
+
+section WeakTopology
+
+/-- The space `E` equipped with the weak topology induced by the bilinear form `B`. -/
+@[nolint unusedArguments]
+def WeakBilin [CommSemiring 𝕜] [AddCommMonoid E] [Module 𝕜 E] [AddCommMonoid F] [Module 𝕜 F]
+ (_ : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) := E
+
+namespace WeakBilin
+
+-- Porting note: the next two instances should be derived from the definition
+instance instAddCommMonoid [CommSemiring 𝕜] [a : AddCommMonoid E] [Module 𝕜 E] [AddCommMonoid F]
+ [Module 𝕜 F] (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : AddCommMonoid (WeakBilin B) := a
+
+instance instModule [CommSemiring 𝕜] [AddCommMonoid E] [m : Module 𝕜 E] [AddCommMonoid F]
+ [Module 𝕜 F] (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : Module 𝕜 (WeakBilin B) := m
+
+instance instAddCommGroup [CommSemiring 𝕜] [a : AddCommGroup E] [Module 𝕜 E] [AddCommMonoid F]
+ [Module 𝕜 F] (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : AddCommGroup (WeakBilin B) := a
+
+instance (priority := 100) instModule' [CommSemiring 𝕜] [CommSemiring 𝕝] [AddCommMonoid E]
+ [Module 𝕜 E] [AddCommMonoid F] [Module 𝕜 F] [m : Module 𝕝 E] (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) :
+ Module 𝕝 (WeakBilin B) := m
+
+instance instIsScalarTower [CommSemiring 𝕜] [CommSemiring 𝕝] [AddCommMonoid E] [Module 𝕜 E]
+ [AddCommMonoid F] [Module 𝕜 F] [SMul 𝕝 𝕜] [Module 𝕝 E] [s : IsScalarTower 𝕝 𝕜 E]
+ (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : IsScalarTower 𝕝 𝕜 (WeakBilin B) := s
+
+section Semiring
+
+variable [TopologicalSpace 𝕜] [CommSemiring 𝕜]
+variable [AddCommMonoid E] [Module 𝕜 E]
+variable [AddCommMonoid F] [Module 𝕜 F]
+variable (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜)
+
+instance instTopologicalSpace : TopologicalSpace (WeakBilin B) :=
+ TopologicalSpace.induced (fun x y => B x y) Pi.topologicalSpace
+
+/-- The coercion `(fun x y => B x y) : E → (F → 𝕜)` is continuous. -/
+theorem coeFn_continuous : Continuous fun (x : WeakBilin B) y => B x y :=
+ continuous_induced_dom
+
+theorem eval_continuous (y : F) : Continuous fun x : WeakBilin B => B x y :=
+ (continuous_pi_iff.mp (coeFn_continuous B)) y
+
+theorem continuous_of_continuous_eval [TopologicalSpace α] {g : α → WeakBilin B}
+ (h : ∀ y, Continuous fun a => B (g a) y) : Continuous g :=
+ continuous_induced_rng.2 (continuous_pi_iff.mpr h)
+
+/-- The coercion `(fun x y => B x y) : E → (F → 𝕜)` is an embedding. -/
+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, (isEmbedding hB).tendsto_nhds_iff]
+ rfl
+
+/-- Addition in `WeakBilin B` is continuous. -/
+instance instContinuousAdd [ContinuousAdd 𝕜] : ContinuousAdd (WeakBilin B) := by
+ refine ⟨continuous_induced_rng.2 ?_⟩
+ refine
+ cast (congr_arg _ ?_)
+ (((coeFn_continuous B).comp continuous_fst).add ((coeFn_continuous B).comp continuous_snd))
+ ext
+ simp only [Function.comp_apply, Pi.add_apply, map_add, LinearMap.add_apply]
+
+/-- Scalar multiplication by `𝕜` on `WeakBilin B` is continuous. -/
+instance instContinuousSMul [ContinuousSMul 𝕜 𝕜] : ContinuousSMul 𝕜 (WeakBilin B) := by
+ refine ⟨continuous_induced_rng.2 ?_⟩
+ refine cast (congr_arg _ ?_) (continuous_fst.smul ((coeFn_continuous B).comp continuous_snd))
+ ext
+ simp only [Function.comp_apply, Pi.smul_apply, LinearMap.map_smulₛₗ, RingHom.id_apply,
+ LinearMap.smul_apply]
+
+end Semiring
+
+section Ring
+
+variable [TopologicalSpace 𝕜] [CommRing 𝕜]
+variable [AddCommGroup E] [Module 𝕜 E]
+variable [AddCommGroup F] [Module 𝕜 F]
+
+
+variable (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜)
+
+/-- `WeakBilin B` is a `TopologicalAddGroup`, meaning that addition and negation are
+continuous. -/
+instance instTopologicalAddGroup [ContinuousAdd 𝕜] : TopologicalAddGroup (WeakBilin B) where
+ toContinuousAdd := by infer_instance
+ continuous_neg := by
+ refine continuous_induced_rng.2 (continuous_pi_iff.mpr fun y => ?_)
+ refine cast (congr_arg _ ?_) (eval_continuous B (-y))
+ ext x
+ simp only [map_neg, Function.comp_apply, LinearMap.neg_apply]
+
+end Ring
+
+end WeakBilin
+
+end WeakTopology
diff --git a/Mathlib/Topology/Algebra/Module/WeakDual.lean b/Mathlib/Topology/Algebra/Module/WeakDual.lean
index 8bc7353b3fce3..d2bdbb2408760 100644
--- a/Mathlib/Topology/Algebra/Module/WeakDual.lean
+++ b/Mathlib/Topology/Algebra/Module/WeakDual.lean
@@ -3,28 +3,28 @@ Copyright (c) 2021 Kalle Kytölä. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kalle Kytölä, Moritz Doll
-/
-import Mathlib.Topology.Algebra.Module.Basic
import Mathlib.LinearAlgebra.BilinearMap
+import Mathlib.Topology.Algebra.Module.Basic
+import Mathlib.Topology.Algebra.Module.WeakBilin
/-!
# Weak dual topology
-This file defines the weak topology given two vector spaces `E` and `F` over a commutative semiring
+We continue in the setting of `Mathlib.Topology.Algebra.Module.WeakBilin`,
+which defines the weak topology given two vector spaces `E` and `F` over a commutative semiring
`𝕜` and a bilinear form `B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜`. The weak topology on `E` is the coarsest topology
such that for all `y : F` every map `fun x => B x y` is continuous.
+In this file, we consider two special cases.
In the case that `F = E →L[𝕜] 𝕜` and `B` being the canonical pairing, we obtain the weak-* topology,
`WeakDual 𝕜 E := (E →L[𝕜] 𝕜)`. Interchanging the arguments in the bilinear form yields the
weak topology `WeakSpace 𝕜 E := E`.
## Main definitions
-The main definitions are the types `WeakBilin B` for the general case and the two special cases
-`WeakDual 𝕜 E` and `WeakSpace 𝕜 E` with the respective topology instances on it.
+The main definitions are the types `WeakDual 𝕜 E` and `WeakSpace 𝕜 E`,
+with the respective topology instances on it.
-* Given `B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜`, the type `WeakBilin B` is a type synonym for `E`.
-* The instance `WeakBilin.instTopologicalSpace` is the weak topology induced by the bilinear form
- `B`.
* `WeakDual 𝕜 E` is a type synonym for `Dual 𝕜 E` (when the latter is defined): both are equal to
the type `E →L[𝕜] 𝕜` of continuous linear maps from a module `E` over `𝕜` to the ring `𝕜`.
* The instance `WeakDual.instTopologicalSpace` is the weak-* topology on `WeakDual 𝕜 E`, i.e., the
@@ -33,19 +33,6 @@ The main definitions are the types `WeakBilin B` for the general case and the tw
* The instance `WeakSpace.instTopologicalSpace` is the weak topology on `E`, i.e., the
coarsest topology such that all `v : dual 𝕜 E` remain continuous.
-## Main results
-
-We establish that `WeakBilin B` has the following structure:
-* `WeakBilin.instContinuousAdd`: The addition in `WeakBilin B` is continuous.
-* `WeakBilin.instContinuousSMul`: The scalar multiplication in `WeakBilin B` is continuous.
-
-We prove the following results characterizing the weak topology:
-* `eval_continuous`: For any `y : F`, the evaluation mapping `fun x => B x y` is continuous.
-* `continuous_of_continuous_eval`: For a mapping to `WeakBilin B` to be continuous,
- it suffices that its compositions with pairing with `B` at all points `y : F` is continuous.
-* `tendsto_iff_forall_eval_tendsto`: Convergence in `WeakBilin B` can be characterized
- in terms of convergence of the evaluations at all points `y : F`.
-
## Notations
No new notation is introduced.
@@ -67,123 +54,16 @@ open Filter
open Topology
-variable {α 𝕜 𝕝 R E F M : Type*}
-
-section WeakTopology
-
-/-- The space `E` equipped with the weak topology induced by the bilinear form `B`. -/
-@[nolint unusedArguments]
-def WeakBilin [CommSemiring 𝕜] [AddCommMonoid E] [Module 𝕜 E] [AddCommMonoid F] [Module 𝕜 F]
- (_ : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) := E
-
-namespace WeakBilin
-
--- Porting note: the next two instances should be derived from the definition
-instance instAddCommMonoid [CommSemiring 𝕜] [a : AddCommMonoid E] [Module 𝕜 E] [AddCommMonoid F]
- [Module 𝕜 F] (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : AddCommMonoid (WeakBilin B) := a
-
-instance instModule [CommSemiring 𝕜] [AddCommMonoid E] [m : Module 𝕜 E] [AddCommMonoid F]
- [Module 𝕜 F] (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : Module 𝕜 (WeakBilin B) := m
-
-instance instAddCommGroup [CommSemiring 𝕜] [a : AddCommGroup E] [Module 𝕜 E] [AddCommMonoid F]
- [Module 𝕜 F] (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : AddCommGroup (WeakBilin B) := a
-
-instance (priority := 100) instModule' [CommSemiring 𝕜] [CommSemiring 𝕝] [AddCommGroup E]
- [Module 𝕜 E] [AddCommGroup F] [Module 𝕜 F] [m : Module 𝕝 E] (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) :
- Module 𝕝 (WeakBilin B) := m
-
-instance instIsScalarTower [CommSemiring 𝕜] [CommSemiring 𝕝] [AddCommGroup E] [Module 𝕜 E]
- [AddCommGroup F] [Module 𝕜 F] [SMul 𝕝 𝕜] [Module 𝕝 E] [s : IsScalarTower 𝕝 𝕜 E]
- (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : IsScalarTower 𝕝 𝕜 (WeakBilin B) := s
-
-section Semiring
-
-variable [TopologicalSpace 𝕜] [CommSemiring 𝕜]
-variable [AddCommMonoid E] [Module 𝕜 E]
-variable [AddCommMonoid F] [Module 𝕜 F]
-variable (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜)
-
-instance instTopologicalSpace : TopologicalSpace (WeakBilin B) :=
- TopologicalSpace.induced (fun x y => B x y) Pi.topologicalSpace
-
-/-- The coercion `(fun x y => B x y) : E → (F → 𝕜)` is continuous. -/
-theorem coeFn_continuous : Continuous fun (x : WeakBilin B) y => B x y :=
- continuous_induced_dom
-
-theorem eval_continuous (y : F) : Continuous fun x : WeakBilin B => B x y :=
- (continuous_pi_iff.mp (coeFn_continuous B)) y
-
-theorem continuous_of_continuous_eval [TopologicalSpace α] {g : α → WeakBilin B}
- (h : ∀ y, Continuous fun a => B (g a) y) : Continuous g :=
- 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 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)]
- rfl
-
-/-- Addition in `WeakBilin B` is continuous. -/
-instance instContinuousAdd [ContinuousAdd 𝕜] : ContinuousAdd (WeakBilin B) := by
- refine ⟨continuous_induced_rng.2 ?_⟩
- refine
- cast (congr_arg _ ?_)
- (((coeFn_continuous B).comp continuous_fst).add ((coeFn_continuous B).comp continuous_snd))
- ext
- simp only [Function.comp_apply, Pi.add_apply, map_add, LinearMap.add_apply]
-
-/-- Scalar multiplication by `𝕜` on `WeakBilin B` is continuous. -/
-instance instContinuousSMul [ContinuousSMul 𝕜 𝕜] : ContinuousSMul 𝕜 (WeakBilin B) := by
- refine ⟨continuous_induced_rng.2 ?_⟩
- refine cast (congr_arg _ ?_) (continuous_fst.smul ((coeFn_continuous B).comp continuous_snd))
- ext
- simp only [Function.comp_apply, Pi.smul_apply, LinearMap.map_smulₛₗ, RingHom.id_apply,
- LinearMap.smul_apply]
-
-end Semiring
-
-section Ring
-
-variable [TopologicalSpace 𝕜] [CommRing 𝕜]
-variable [AddCommGroup E] [Module 𝕜 E]
-variable [AddCommGroup F] [Module 𝕜 F]
-
-
-variable (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜)
-
-/-- `WeakBilin B` is a `TopologicalAddGroup`, meaning that addition and negation are
-continuous. -/
-instance instTopologicalAddGroup [ContinuousAdd 𝕜] : TopologicalAddGroup (WeakBilin B) where
- toContinuousAdd := by infer_instance
- continuous_neg := by
- refine continuous_induced_rng.2 (continuous_pi_iff.mpr fun y => ?_)
- refine cast (congr_arg _ ?_) (eval_continuous B (-y))
- ext x
- simp only [map_neg, Function.comp_apply, LinearMap.neg_apply]
-
-end Ring
-
-end WeakBilin
-
-end WeakTopology
-
-section WeakStarTopology
+variable {α 𝕜 𝕝 E F : Type*}
/-- The canonical pairing of a vector space and its topological dual. -/
def topDualPairing (𝕜 E) [CommSemiring 𝕜] [TopologicalSpace 𝕜] [ContinuousAdd 𝕜] [AddCommMonoid E]
[Module 𝕜 E] [TopologicalSpace E] [ContinuousConstSMul 𝕜 𝕜] : (E →L[𝕜] 𝕜) →ₗ[𝕜] E →ₗ[𝕜] 𝕜 :=
ContinuousLinearMap.coeLM 𝕜
-variable [CommSemiring 𝕜] [TopologicalSpace 𝕜] [ContinuousAdd 𝕜]
-variable [ContinuousConstSMul 𝕜 𝕜]
-variable [AddCommMonoid E] [Module 𝕜 E] [TopologicalSpace E]
-
-theorem topDualPairing_apply (v : E →L[𝕜] 𝕜) (x : E) : topDualPairing 𝕜 E v x = v x :=
+theorem topDualPairing_apply [CommSemiring 𝕜] [TopologicalSpace 𝕜] [ContinuousAdd 𝕜]
+ [AddCommMonoid E] [Module 𝕜 E] [TopologicalSpace E] [ContinuousConstSMul 𝕜 𝕜] (v : E →L[𝕜] 𝕜)
+ (x : E) : topDualPairing 𝕜 E v x = v x :=
rfl
/-- The weak star topology is the topology coarsest topology on `E →L[𝕜] 𝕜` such that all
@@ -194,6 +74,12 @@ def WeakDual (𝕜 E : Type*) [CommSemiring 𝕜] [TopologicalSpace 𝕜] [Conti
namespace WeakDual
+section Semiring
+
+variable [CommSemiring 𝕜] [TopologicalSpace 𝕜] [ContinuousAdd 𝕜]
+variable [ContinuousConstSMul 𝕜 𝕜]
+variable [AddCommMonoid E] [Module 𝕜 E] [TopologicalSpace E]
+
-- Porting note: the next four instances should be derived from the definition
instance instAddCommMonoid : AddCommMonoid (WeakDual 𝕜 E) :=
WeakBilin.instAddCommMonoid (topDualPairing 𝕜 E)
@@ -216,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 𝕜]
@@ -262,9 +143,22 @@ 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
+
+section Ring
+
+variable [CommRing 𝕜] [TopologicalSpace 𝕜] [TopologicalAddGroup 𝕜] [ContinuousConstSMul 𝕜 𝕜]
+variable [AddCommGroup E] [Module 𝕜 E] [TopologicalSpace E] [TopologicalAddGroup E]
+
+instance instAddCommGroup : AddCommGroup (WeakDual 𝕜 E) :=
+ WeakBilin.instAddCommGroup (topDualPairing 𝕜 E)
+
+instance instTopologicalAddGroup : TopologicalAddGroup (WeakDual 𝕜 E) :=
+ WeakBilin.instTopologicalAddGroup (topDualPairing 𝕜 E)
+
+end Ring
end WeakDual
@@ -274,6 +168,12 @@ def WeakSpace (𝕜 E) [CommSemiring 𝕜] [TopologicalSpace 𝕜] [ContinuousAd
[ContinuousConstSMul 𝕜 𝕜] [AddCommMonoid E] [Module 𝕜 E] [TopologicalSpace E] :=
WeakBilin (topDualPairing 𝕜 E).flip
+section Semiring
+
+variable [CommSemiring 𝕜] [TopologicalSpace 𝕜] [ContinuousAdd 𝕜]
+variable [ContinuousConstSMul 𝕜 𝕜]
+variable [AddCommMonoid E] [Module 𝕜 E] [TopologicalSpace E]
+
namespace WeakSpace
-- Porting note: the next four instances should be derived from the definition
@@ -289,6 +189,13 @@ instance instTopologicalSpace : TopologicalSpace (WeakSpace 𝕜 E) :=
instance instContinuousAdd : ContinuousAdd (WeakSpace 𝕜 E) :=
WeakBilin.instContinuousAdd (topDualPairing 𝕜 E).flip
+instance instModule' [CommSemiring 𝕝] [Module 𝕝 E] : Module 𝕝 (WeakSpace 𝕜 E) :=
+ WeakBilin.instModule' (topDualPairing 𝕜 E).flip
+
+instance instIsScalarTower [CommSemiring 𝕝] [Module 𝕝 𝕜] [Module 𝕝 E] [IsScalarTower 𝕝 𝕜 E] :
+ IsScalarTower 𝕝 𝕜 (WeakSpace 𝕜 E) :=
+ WeakBilin.instIsScalarTower (topDualPairing 𝕜 E).flip
+
variable [AddCommMonoid F] [Module 𝕜 F] [TopologicalSpace F]
/-- A continuous linear map from `E` to `F` is still continuous when `E` and `F` are equipped with
@@ -315,7 +222,7 @@ def toWeakSpace : E ≃ₗ[𝕜] WeakSpace 𝕜 E := LinearEquiv.refl 𝕜 E
variable (𝕜 E) in
/-- For a topological vector space `E`, "identity mapping" `E → WeakSpace 𝕜 E` is continuous.
This definition implements it as a continuous linear map. -/
-def continuousLinearMapToWeakSpace : E →L[𝕜] WeakSpace 𝕜 E where
+def toWeakSpaceCLM : E →L[𝕜] WeakSpace 𝕜 E where
__ := toWeakSpace 𝕜 E
cont := by
apply WeakBilin.continuous_of_continuous_eval
@@ -323,21 +230,21 @@ def continuousLinearMapToWeakSpace : E →L[𝕜] WeakSpace 𝕜 E where
variable (𝕜 E) in
@[simp]
-theorem continuousLinearMapToWeakSpace_eq_toWeakSpace (x : E) :
- continuousLinearMapToWeakSpace 𝕜 E x = toWeakSpace 𝕜 E x := by rfl
+theorem toWeakSpaceCLM_eq_toWeakSpace (x : E) :
+ toWeakSpaceCLM 𝕜 E x = toWeakSpace 𝕜 E x := by rfl
-theorem continuousLinearMapToWeakSpace_bijective :
- Function.Bijective (continuousLinearMapToWeakSpace 𝕜 E) :=
+theorem toWeakSpaceCLM_bijective :
+ Function.Bijective (toWeakSpaceCLM 𝕜 E) :=
(toWeakSpace 𝕜 E).bijective
/-- The canonical map from `WeakSpace 𝕜 E` to `E` is an open map. -/
theorem isOpenMap_toWeakSpace_symm : IsOpenMap (toWeakSpace 𝕜 E).symm :=
- IsOpenMap.of_inverse (continuousLinearMapToWeakSpace 𝕜 E).cont
+ IsOpenMap.of_inverse (toWeakSpaceCLM 𝕜 E).cont
(toWeakSpace 𝕜 E).left_inv (toWeakSpace 𝕜 E).right_inv
/-- A set in `E` which is open in the weak topology is open. -/
theorem WeakSpace.isOpen_of_isOpen (V : Set E)
- (hV : IsOpen ((continuousLinearMapToWeakSpace 𝕜 E) '' V : Set (WeakSpace 𝕜 E))) : IsOpen V := by
+ (hV : IsOpen ((toWeakSpaceCLM 𝕜 E) '' V : Set (WeakSpace 𝕜 E))) : IsOpen V := by
simpa [Set.image_image] using isOpenMap_toWeakSpace_symm _ hV
theorem tendsto_iff_forall_eval_tendsto_topDualPairing {l : Filter α} {f : α → WeakDual 𝕜 E}
@@ -346,4 +253,21 @@ theorem tendsto_iff_forall_eval_tendsto_topDualPairing {l : Filter α} {f : α
∀ y, Tendsto (fun i => topDualPairing 𝕜 E (f i) y) l (𝓝 (topDualPairing 𝕜 E x y)) :=
WeakBilin.tendsto_iff_forall_eval_tendsto _ ContinuousLinearMap.coe_injective
-end WeakStarTopology
+end Semiring
+
+section Ring
+
+namespace WeakSpace
+
+variable [CommRing 𝕜] [TopologicalSpace 𝕜] [TopologicalAddGroup 𝕜] [ContinuousConstSMul 𝕜 𝕜]
+variable [AddCommGroup E] [Module 𝕜 E] [TopologicalSpace E] [TopologicalAddGroup E]
+
+instance instAddCommGroup : AddCommGroup (WeakSpace 𝕜 E) :=
+ WeakBilin.instAddCommGroup (topDualPairing 𝕜 E).flip
+
+instance instTopologicalAddGroup : TopologicalAddGroup (WeakSpace 𝕜 E) :=
+ WeakBilin.instTopologicalAddGroup (topDualPairing 𝕜 E).flip
+
+end WeakSpace
+
+end Ring
diff --git a/Mathlib/Topology/Algebra/Monoid.lean b/Mathlib/Topology/Algebra/Monoid.lean
index c2bebad5ed312..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.ContinuousFunction.Basic
import Mathlib.Algebra.Group.ULift
+import Mathlib.Topology.ContinuousMap.Defs
/-!
# Theory of topological monoids
@@ -75,7 +75,7 @@ instance ContinuousMul.to_continuousSMul : ContinuousSMul M M :=
instance ContinuousMul.to_continuousSMul_op : ContinuousSMul Mᵐᵒᵖ M :=
⟨show Continuous ((fun p : M × M => p.1 * p.2) ∘ Prod.swap ∘ Prod.map MulOpposite.unop id) from
continuous_mul.comp <|
- continuous_swap.comp <| Continuous.prod_map MulOpposite.continuous_unop continuous_id⟩
+ continuous_swap.comp <| Continuous.prodMap MulOpposite.continuous_unop continuous_id⟩
@[to_additive]
theorem ContinuousMul.induced {α : Type*} {β : Type*} {F : Type*} [FunLike F α β] [MulOneClass α]
@@ -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 92b5c88ea7ba5..39f700ad8f4b0 100644
--- a/Mathlib/Topology/Algebra/MulAction.lean
+++ b/Mathlib/Topology/Algebra/MulAction.lean
@@ -71,6 +71,13 @@ section SMul
variable [SMul M X] [ContinuousSMul M X]
+lemma IsScalarTower.continuousSMul {M : Type*} (N : Type*) {α : Type*} [Monoid N] [SMul M N]
+ [MulAction N α] [SMul M α] [IsScalarTower M N α] [TopologicalSpace M] [TopologicalSpace N]
+ [TopologicalSpace α] [ContinuousSMul M N] [ContinuousSMul N α] : ContinuousSMul M α :=
+ { continuous_smul := by
+ suffices Continuous (fun p : M × α ↦ (p.1 • (1 : N)) • p.2) by simpa
+ fun_prop }
+
@[to_additive]
instance : ContinuousSMul (ULift M) X :=
⟨(continuous_smul (M := M)).comp₂ (continuous_uLift_down.comp continuous_fst) continuous_snd⟩
@@ -125,13 +132,13 @@ action is."]
instance ContinuousSMul.op [SMul Mᵐᵒᵖ X] [IsCentralScalar M X] : ContinuousSMul Mᵐᵒᵖ X :=
⟨by
suffices Continuous fun p : M × X => MulOpposite.op p.fst • p.snd from
- this.comp (MulOpposite.continuous_unop.prod_map continuous_id)
+ this.comp (MulOpposite.continuous_unop.prodMap continuous_id)
simpa only [op_smul_eq_smul] using (continuous_smul : Continuous fun p : M × X => _)⟩
@[to_additive]
instance MulOpposite.continuousSMul : ContinuousSMul M Xᵐᵒᵖ :=
⟨MulOpposite.continuous_op.comp <|
- continuous_smul.comp <| continuous_id.prod_map MulOpposite.continuous_unop⟩
+ continuous_smul.comp <| continuous_id.prodMap MulOpposite.continuous_unop⟩
@[to_additive]
protected theorem Specializes.smul {a b : M} {x y : X} (h₁ : a ⤳ b) (h₂ : x ⤳ y) :
@@ -170,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
@@ -190,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. -/
@@ -204,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
@@ -216,6 +225,12 @@ variable [Group M] [MulAction M X] [ContinuousSMul M X]
instance Subgroup.continuousSMul {S : Subgroup M} : ContinuousSMul S X :=
S.toSubmonoid.continuousSMul
+variable (M)
+
+/-- The stabilizer of a continuous group action on a discrete space is an open subgroup. -/
+lemma stabilizer_isOpen [DiscreteTopology X] (x : X) : IsOpen (MulAction.stabilizer M x : Set M) :=
+ IsOpen.preimage (f := fun g ↦ g • x) (by fun_prop) (isOpen_discrete {x})
+
end Group
@[to_additive]
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/Completion.lean b/Mathlib/Topology/Algebra/Nonarchimedean/Completion.lean
index 8d88cf4ee0a0a..c5dd61852fecd 100644
--- a/Mathlib/Topology/Algebra/Nonarchimedean/Completion.lean
+++ b/Mathlib/Topology/Algebra/Nonarchimedean/Completion.lean
@@ -51,7 +51,7 @@ instance {G : Type*} [AddGroup G] [UniformSpace G] [UniformAddGroup G] [Nonarchi
`0` in `Completion G`. This follows from the fact that `toCompl : G → Completion G` is dense
inducing and `W` is a neighborhood of `0` in `G`. -/
apply isOpen_of_mem_nhds (g := 0)
- apply (denseInducing_toCompl _).closure_image_mem_nhds
+ apply (isDenseInducing_toCompl _).closure_image_mem_nhds
exact mem_nhds_zero W
use ⟨_, this⟩
/- Finally, it remains to show that `V ⊆ U`. It suffices to show that `V ⊆ C`, which
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 5512c7f43dcb2..e604312216e17 100644
--- a/Mathlib/Topology/Algebra/OpenSubgroup.lean
+++ b/Mathlib/Topology/Algebra/OpenSubgroup.lean
@@ -1,9 +1,12 @@
/-
Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin
+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
@@ -135,8 +138,8 @@ instance : Inhabited (OpenSubgroup G) :=
@[to_additive]
theorem isClosed [ContinuousMul G] (U : OpenSubgroup G) : IsClosed (U : Set G) := by
apply isOpen_compl_iff.1
- refine isOpen_iff_forall_mem_open.2 fun x hx => ⟨(fun y => y * x⁻¹) ⁻¹' U, ?_, ?_, ?_⟩
- · refine fun u hux hu => hx ?_
+ refine isOpen_iff_forall_mem_open.2 fun x hx ↦ ⟨(fun y ↦ y * x⁻¹) ⁻¹' U, ?_, ?_, ?_⟩
+ · refine fun u hux hu ↦ hx ?_
simp only [Set.mem_preimage, SetLike.mem_coe] at hux hu ⊢
convert U.mul_mem (U.inv_mem hux) hu
simp
@@ -170,7 +173,7 @@ end
@[to_additive]
instance instInfOpenSubgroup : Inf (OpenSubgroup G) :=
- ⟨fun U V => ⟨U ⊓ V, U.isOpen.inter V.isOpen⟩⟩
+ ⟨fun U V ↦ ⟨U ⊓ V, U.isOpen.inter V.isOpen⟩⟩
@[to_additive (attr := simp, norm_cast)]
theorem coe_inf : (↑(U ⊓ V) : Set G) = (U : Set G) ∩ V :=
@@ -194,7 +197,7 @@ instance instPartialOrderOpenSubgroup : PartialOrder (OpenSubgroup G) := inferIn
-- Porting note: we override `toPartialorder` to get better `le`
@[to_additive]
instance instSemilatticeInfOpenSubgroup : SemilatticeInf (OpenSubgroup G) :=
- { SetLike.coe_injective.semilatticeInf ((↑) : OpenSubgroup G → Set G) fun _ _ => rfl with
+ { SetLike.coe_injective.semilatticeInf ((↑) : OpenSubgroup G → Set G) fun _ _ ↦ rfl with
toInf := instInfOpenSubgroup
toPartialOrder := instPartialOrderOpenSubgroup }
@@ -245,9 +248,9 @@ variable {G : Type*} [Group G] [TopologicalSpace G]
@[to_additive]
theorem isOpen_of_mem_nhds [ContinuousMul G] (H : Subgroup G) {g : G} (hg : (H : Set G) ∈ 𝓝 g) :
IsOpen (H : Set G) := by
- refine isOpen_iff_mem_nhds.2 fun x hx => ?_
+ refine isOpen_iff_mem_nhds.2 fun x hx ↦ ?_
have hg' : g ∈ H := SetLike.mem_coe.1 (mem_of_mem_nhds hg)
- have : Filter.Tendsto (fun y => y * (x⁻¹ * g)) (𝓝 x) (𝓝 g) :=
+ have : Filter.Tendsto (fun y ↦ y * (x⁻¹ * g)) (𝓝 x) (𝓝 g) :=
(continuous_id.mul continuous_const).tendsto' _ _ (mul_inv_cancel_left _ _)
simpa only [SetLike.mem_coe, Filter.mem_map',
H.mul_mem_cancel_right (H.mul_mem (H.inv_mem hx) hg')] using this hg
@@ -269,6 +272,56 @@ theorem isOpen_of_one_mem_interior [ContinuousMul G] (H: Subgroup G)
(h_1_int : (1 : G) ∈ interior (H : Set G)) : IsOpen (H : Set G) :=
isOpen_of_mem_nhds H <| mem_interior_iff_mem_nhds.1 h_1_int
+@[to_additive]
+lemma isClosed_of_isOpen [ContinuousMul G] (U : Subgroup G) (h : IsOpen (U : Set G)) :
+ IsClosed (U : Set G) :=
+ OpenSubgroup.isClosed ⟨U, h⟩
+
+@[to_additive]
+lemma subgroupOf_isOpen (U K : Subgroup G) (h : IsOpen (K : Set G)) :
+ IsOpen (K.subgroupOf U : Set U) :=
+ Continuous.isOpen_preimage (continuous_iff_le_induced.mpr fun _ ↦ id) _ h
+
+@[to_additive]
+lemma discreteTopology [ContinuousMul G] (U : Subgroup G) (h : IsOpen (U : Set G)) :
+ DiscreteTopology (G ⧸ U) := by
+ refine singletons_open_iff_discrete.mp (fun g ↦ ?_)
+ induction' g using Quotient.inductionOn with g
+ show IsOpen (QuotientGroup.mk ⁻¹' {QuotientGroup.mk g})
+ convert_to IsOpen ((g * ·) '' U)
+ · ext g'
+ simp only [Set.mem_preimage, Set.mem_singleton_iff, QuotientGroup.eq, Set.image_mul_left]
+ rw [← U.inv_mem_iff]
+ simp
+ · exact Homeomorph.mulLeft g |>.isOpen_image |>.mpr h
+
+@[to_additive]
+instance [ContinuousMul G] (U : OpenSubgroup G) : DiscreteTopology (G ⧸ U.toSubgroup) :=
+ discreteTopology U.toSubgroup U.isOpen
+
+@[to_additive]
+lemma quotient_finite_of_isOpen [ContinuousMul G] [CompactSpace G] (U : Subgroup G)
+ (h : IsOpen (U : Set G)) : Finite (G ⧸ U) :=
+ have : DiscreteTopology (G ⧸ U) := U.discreteTopology h
+ finite_of_compact_of_discrete
+
+@[to_additive]
+instance [ContinuousMul G] [CompactSpace G] (U : OpenSubgroup G) : Finite (G ⧸ U.toSubgroup) :=
+ quotient_finite_of_isOpen U.toSubgroup U.isOpen
+
+@[to_additive]
+lemma quotient_finite_of_isOpen' [TopologicalGroup G] [CompactSpace G] (U : Subgroup G)
+ (K : Subgroup U) (hUopen : IsOpen (U : Set G)) (hKopen : IsOpen (K : Set U)) :
+ Finite (U ⧸ K) :=
+ have : CompactSpace U := isCompact_iff_compactSpace.mp <| IsClosed.isCompact <|
+ U.isClosed_of_isOpen hUopen
+ K.quotient_finite_of_isOpen hKopen
+
+@[to_additive]
+instance [TopologicalGroup G] [CompactSpace G] (U : OpenSubgroup G) (K : OpenSubgroup U) :
+ Finite (U ⧸ K.toSubgroup) :=
+ quotient_finite_of_isOpen' U.toSubgroup K.toSubgroup U.isOpen K.isOpen
+
end Subgroup
namespace OpenSubgroup
@@ -277,7 +330,7 @@ variable {G : Type*} [Group G] [TopologicalSpace G] [ContinuousMul G]
@[to_additive]
instance : Sup (OpenSubgroup G) :=
- ⟨fun U V => ⟨U ⊔ V, Subgroup.isOpen_mono (le_sup_left : U.1 ≤ U.1 ⊔ V.1) U.isOpen⟩⟩
+ ⟨fun U V ↦ ⟨U ⊔ V, Subgroup.isOpen_mono (le_sup_left : U.1 ≤ U.1 ⊔ V.1) U.isOpen⟩⟩
@[to_additive (attr := simp, norm_cast)]
theorem toSubgroup_sup (U V : OpenSubgroup G) : (↑(U ⊔ V) : Subgroup G) = ↑U ⊔ ↑V := rfl
@@ -286,7 +339,7 @@ theorem toSubgroup_sup (U V : OpenSubgroup G) : (↑(U ⊔ V) : Subgroup G) =
@[to_additive]
instance : Lattice (OpenSubgroup G) :=
{ instSemilatticeInfOpenSubgroup,
- toSubgroup_injective.semilatticeSup ((↑) : OpenSubgroup G → Subgroup G) fun _ _ => rfl with
+ toSubgroup_injective.semilatticeSup ((↑) : OpenSubgroup G → Subgroup G) fun _ _ ↦ rfl with
toPartialOrder := instPartialOrderOpenSubgroup }
end OpenSubgroup
@@ -314,3 +367,199 @@ theorem isOpen_of_isOpen_subideal {U I : Ideal R} (h : U ≤ I) (hU : IsOpen (U
@Submodule.isOpen_mono R R _ _ _ _ Semiring.toModule _ _ h hU
end Ideal
+
+/-!
+# Open normal subgroups of a topological group
+
+This section builds the lattice `OpenNormalSubgroup G` of open subgroups in a topological group `G`,
+and its additive version `OpenNormalAddSubgroup`.
+
+-/
+
+section
+
+universe u
+
+/-- The type of open normal subgroups of a topological group. -/
+@[ext]
+structure OpenNormalSubgroup (G : Type u) [Group G] [TopologicalSpace G]
+ extends OpenSubgroup G where
+ isNormal' : toSubgroup.Normal := by infer_instance
+
+/-- The type of open normal subgroups of a topological additive group. -/
+@[ext]
+structure OpenNormalAddSubgroup (G : Type u) [AddGroup G] [TopologicalSpace G]
+ extends OpenAddSubgroup G where
+ isNormal' : toAddSubgroup.Normal := by infer_instance
+
+attribute [to_additive] OpenNormalSubgroup
+
+namespace OpenNormalSubgroup
+
+variable {G : Type u} [Group G] [TopologicalSpace G]
+
+@[to_additive]
+instance (H : OpenNormalSubgroup G) : H.toSubgroup.Normal := H.isNormal'
+
+@[to_additive]
+theorem toSubgroup_injective : Function.Injective
+ (fun H ↦ H.toOpenSubgroup.toSubgroup : OpenNormalSubgroup G → Subgroup G) :=
+ fun A B h ↦ by
+ ext
+ dsimp at h
+ rw [h]
+
+@[to_additive]
+instance : SetLike (OpenNormalSubgroup G) G where
+ coe U := U.1
+ coe_injective' _ _ h := toSubgroup_injective <| SetLike.ext' h
+
+@[to_additive]
+instance : SubgroupClass (OpenNormalSubgroup G) G where
+ mul_mem := Subsemigroup.mul_mem' _
+ one_mem U := U.one_mem'
+ inv_mem := Subgroup.inv_mem' _
+
+@[to_additive]
+instance : Coe (OpenNormalSubgroup G) (Subgroup G) where
+ coe H := H.toOpenSubgroup.toSubgroup
+
+@[to_additive]
+instance instPartialOrderOpenNormalSubgroup : PartialOrder (OpenNormalSubgroup G) := inferInstance
+
+@[to_additive]
+instance instInfOpenNormalSubgroup : Inf (OpenNormalSubgroup G) :=
+ ⟨fun U V ↦ ⟨U.toOpenSubgroup ⊓ V.toOpenSubgroup,
+ Subgroup.normal_inf_normal U.toSubgroup V.toSubgroup⟩⟩
+
+@[to_additive]
+instance instSemilatticeInfOpenNormalSubgroup : SemilatticeInf (OpenNormalSubgroup G) :=
+ SetLike.coe_injective.semilatticeInf ((↑) : OpenNormalSubgroup G → Set G) fun _ _ ↦ rfl
+
+@[to_additive]
+instance [ContinuousMul G] : Sup (OpenNormalSubgroup G) :=
+ ⟨fun U V ↦ ⟨U.toOpenSubgroup ⊔ V.toOpenSubgroup,
+ Subgroup.sup_normal U.toOpenSubgroup.1 V.toOpenSubgroup.1⟩⟩
+
+@[to_additive]
+instance instSemilatticeSupOpenNormalSubgroup [ContinuousMul G] :
+ SemilatticeSup (OpenNormalSubgroup G) :=
+ toSubgroup_injective.semilatticeSup
+ (fun (H : OpenNormalSubgroup G) ↦ ↑H.toOpenSubgroup) (fun _ _ ↦ rfl)
+
+@[to_additive]
+instance [ContinuousMul G] : Lattice (OpenNormalSubgroup G) :=
+ { instSemilatticeInfOpenNormalSubgroup,
+ instSemilatticeSupOpenNormalSubgroup with
+ toPartialOrder := instPartialOrderOpenNormalSubgroup}
+
+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 210984070446a..8e6a51ab5faed 100644
--- a/Mathlib/Topology/Algebra/Order/Field.lean
+++ b/Mathlib/Topology/Algebra/Order/Field.lean
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Benjamin Davidson, Devon Tuma, Eric Rodriguez, Oliver Nash
-/
import Mathlib.Data.Set.Pointwise.Interval
+import Mathlib.Order.Filter.AtTopBot.Field
import Mathlib.Topology.Algebra.Field
import Mathlib.Topology.Algebra.Order.Group
@@ -140,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) :
@@ -194,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/Floor.lean b/Mathlib/Topology/Algebra/Order/Floor.lean
index 3877c5331e7bf..bde8ae91b5715 100644
--- a/Mathlib/Topology/Algebra/Order/Floor.lean
+++ b/Mathlib/Topology/Algebra/Order/Floor.lean
@@ -3,9 +3,8 @@ Copyright (c) 2020 Anatole Dedecker. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Anatole Dedecker
-/
-import Mathlib.Algebra.Order.Floor
+import Mathlib.Order.Filter.AtTopBot.Floor
import Mathlib.Topology.Algebra.Order.Group
-import Mathlib.Topology.Order.Basic
/-!
# Topological facts about `Int.floor`, `Int.ceil` and `Int.fract`
@@ -27,8 +26,36 @@ This file proves statements about limits and continuity of functions involving `
open Filter Function Int Set Topology
+namespace FloorSemiring
+
+open scoped Nat
+
+variable {K : Type*} [LinearOrderedField K] [FloorSemiring K] [TopologicalSpace K] [OrderTopology K]
+
+theorem tendsto_mul_pow_div_factorial_sub_atTop (a c : K) (d : ℕ) :
+ Tendsto (fun n ↦ a * c ^ n / (n - d)!) atTop (𝓝 0) := by
+ rw [tendsto_order]
+ constructor
+ all_goals
+ intro ε hε
+ filter_upwards [eventually_mul_pow_lt_factorial_sub (a * ε⁻¹) c d] with n h
+ rw [mul_right_comm, ← div_eq_mul_inv] at h
+ · rw [div_lt_iff_of_neg hε] at h
+ rwa [lt_div_iff₀' (Nat.cast_pos.mpr (Nat.factorial_pos _))]
+ · rw [div_lt_iff₀ hε] at h
+ rwa [div_lt_iff₀' (Nat.cast_pos.mpr (Nat.factorial_pos _))]
+
+theorem tendsto_pow_div_factorial_atTop (c : K) :
+ Tendsto (fun n ↦ c ^ n / n !) atTop (𝓝 0) := by
+ convert tendsto_mul_pow_div_factorial_sub_atTop 1 c 0
+ rw [one_mul]
+
+end FloorSemiring
+
variable {α β γ : Type*} [LinearOrderedRing α] [FloorRing α]
+-- TODO: move to `Mathlib.Order.Filter.AtTopBot.Floor`
+
theorem tendsto_floor_atTop : Tendsto (floor : α → ℤ) atTop atTop :=
floor_mono.tendsto_atTop_atTop fun b =>
⟨(b + 1 : ℤ), by rw [floor_intCast]; exact (lt_add_one _).le⟩
@@ -179,7 +206,7 @@ theorem ContinuousOn.comp_fract' {f : β → α → γ} (h : ContinuousOn (uncur
(tendsto_id.prod_map (tendsto_fract_right _))).mono_right (le_of_eq ?_) <;>
simp [nhdsWithin_prod_eq, nhdsWithin_univ]
· replace ht : t ≠ ⌊t⌋ := fun ht' => ht ⟨_, ht'⟩
- refine (h.continuousAt ?_).comp (continuousAt_id.prod_map (continuousAt_fract ht))
+ refine (h.continuousAt ?_).comp (continuousAt_id.prodMap (continuousAt_fract ht))
exact prod_mem_nhds univ_mem (Icc_mem_nhds (fract_pos.2 ht) (fract_lt_one _))
theorem ContinuousOn.comp_fract {s : β → α} {f : β → α → γ}
diff --git a/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean b/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean
index 43ef0e855d0da..18a175654b3dd 100644
--- a/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean
+++ b/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean
@@ -7,7 +7,7 @@ import Mathlib.Algebra.BigOperators.Intervals
import Mathlib.Algebra.BigOperators.Ring
import Mathlib.Algebra.Order.Group.Indicator
import Mathlib.Order.LiminfLimsup
-import Mathlib.Order.Filter.Archimedean
+import Mathlib.Order.Filter.AtTopBot.Archimedean
import Mathlib.Order.Filter.CountableInter
import Mathlib.Topology.Algebra.Group.Basic
import Mathlib.Data.Set.Lattice
@@ -167,8 +167,8 @@ theorem limsSup_nhds (a : α) : limsSup (𝓝 a) = a :=
| Or.inl ⟨c, hac, hcb⟩ => ⟨c, ge_mem_nhds hac, hcb⟩
| Or.inr ⟨_, h⟩ => ⟨a, (𝓝 a).sets_of_superset (gt_mem_nhds hba) h, hba⟩
-theorem limsInf_nhds : ∀ a : α, limsInf (𝓝 a) = a :=
- limsSup_nhds (α := αᵒᵈ)
+theorem limsInf_nhds (a : α) : limsInf (𝓝 a) = a :=
+ limsSup_nhds (α := αᵒᵈ) a
/-- If a filter is converging, its limsup coincides with its limit. -/
theorem limsInf_eq_of_le_nhds {f : Filter α} {a : α} [NeBot f] (h : f ≤ 𝓝 a) : f.limsInf = a :=
@@ -184,8 +184,8 @@ theorem limsInf_eq_of_le_nhds {f : Filter α} {a : α} [NeBot f] (h : f ≤ 𝓝
_ ≤ f.limsInf := limsInf_le_limsInf_of_le h (isBounded_ge_nhds a) hb_le.isCobounded_flip)
/-- If a filter is converging, its liminf coincides with its limit. -/
-theorem limsSup_eq_of_le_nhds : ∀ {f : Filter α} {a : α} [NeBot f], f ≤ 𝓝 a → f.limsSup = a :=
- limsInf_eq_of_le_nhds (α := αᵒᵈ)
+theorem limsSup_eq_of_le_nhds {f : Filter α} {a : α} [NeBot f] (h : f ≤ 𝓝 a) : f.limsSup = a :=
+ limsInf_eq_of_le_nhds (α := αᵒᵈ) h
/-- If a function has a limit, then its limsup coincides with its limit. -/
theorem Filter.Tendsto.limsup_eq {f : Filter β} {u : β → α} {a : α} [NeBot f]
@@ -209,12 +209,9 @@ and is greater than or equal to the `limsup` of `f`, then `f` tends to `a` along
theorem tendsto_of_le_liminf_of_limsup_le {f : Filter β} {u : β → α} {a : α} (hinf : a ≤ liminf u f)
(hsup : limsup u f ≤ a) (h : f.IsBoundedUnder (· ≤ ·) u := by isBoundedDefault)
(h' : f.IsBoundedUnder (· ≥ ·) u := by isBoundedDefault) : Tendsto u f (𝓝 a) := by
- classical
- by_cases hf : f = ⊥
- · rw [hf]
- exact tendsto_bot
- · haveI : NeBot f := ⟨hf⟩
- exact tendsto_of_liminf_eq_limsup (le_antisymm (le_trans (liminf_le_limsup h h') hsup) hinf)
+ rcases f.eq_or_neBot with rfl | _
+ · exact tendsto_bot
+ · exact tendsto_of_liminf_eq_limsup (le_antisymm (le_trans (liminf_le_limsup h h') hsup) hinf)
(le_antisymm hsup (le_trans hinf (liminf_le_limsup h h'))) h h'
/-- Assume that, for any `a < b`, a sequence can not be infinitely many times below `a` and
@@ -274,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]
@@ -528,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)
@@ -536,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)
@@ -544,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)
@@ -552,31 +549,52 @@ 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)
(fun _ _ h ↦ add_le_add_right h c) (continuous_add_right c).continuousAt cobdd bdd_below).symm
/-- `limsup (c - xᵢ) = c - liminf xᵢ`. -/
-lemma limsup_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)
+lemma limsup_const_sub (F : Filter ι) [AddCommSemigroup R] [Sub R] [ContinuousSub R] [OrderedSub 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 :=
- (Antitone.map_limsInf_of_continuousAt (F := F.map f) (f := fun (x : R) ↦ c - x)
+ Filter.limsup (fun i ↦ c - f i) F = c - Filter.liminf f F := by
+ rcases F.eq_or_neBot with rfl | _
+ · simp only [liminf, limsInf, limsup, limsSup, map_bot, eventually_bot, Set.setOf_true]
+ simp only [IsCoboundedUnder, IsCobounded, map_bot, eventually_bot, true_implies] at cobdd
+ rcases cobdd with ⟨x, hx⟩
+ refine (csInf_le ?_ (Set.mem_univ _)).antisymm
+ (tsub_le_iff_tsub_le.1 (le_csSup ?_ (Set.mem_univ _)))
+ · refine ⟨x - x, mem_lowerBounds.2 fun y ↦ ?_⟩
+ simp only [Set.mem_univ, true_implies]
+ exact tsub_le_iff_tsub_le.1 (hx (x - y))
+ · refine ⟨x, mem_upperBounds.2 fun y ↦ ?_⟩
+ simp only [Set.mem_univ, hx y, implies_true]
+ · exact (Antitone.map_limsInf_of_continuousAt (F := F.map f) (f := fun (x : R) ↦ c - x)
(fun _ _ h ↦ tsub_le_tsub_left h c) (continuous_sub_left c).continuousAt cobdd bdd_below).symm
/-- `limsup (xᵢ - c) = (limsup xᵢ) - c`. -/
-lemma limsup_sub_const (F : Filter ι) [NeBot F] [AddCommSemigroup R] [Sub R] [ContinuousSub R]
- [OrderedSub R] (f : ι → R) (c : R)
+lemma limsup_sub_const (F : Filter ι) [AddCommSemigroup R] [Sub R] [ContinuousSub R] [OrderedSub 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)
- (fun _ _ h ↦ tsub_le_tsub_right h c) (continuous_sub_right c).continuousAt bdd_above cobdd).symm
+ Filter.limsup (fun i ↦ f i - c) F = Filter.limsup f F - c := by
+ rcases F.eq_or_neBot with rfl | _
+ · have {a : R} : sInf Set.univ ≤ a := by
+ apply csInf_le _ (Set.mem_univ a)
+ simp only [IsCoboundedUnder, IsCobounded, map_bot, eventually_bot, true_implies] at cobdd
+ rcases cobdd with ⟨x, hx⟩
+ refine ⟨x, mem_lowerBounds.2 fun y ↦ ?_⟩
+ simp only [Set.mem_univ, hx y, implies_true]
+ simp only [limsup, limsSup, map_bot, eventually_bot, Set.setOf_true]
+ exact this.antisymm (tsub_le_iff_right.2 this)
+ · apply (Monotone.map_limsSup_of_continuousAt (F := F.map f) (f := fun (x : R) ↦ x - c) _ _).symm
+ · exact fun _ _ h ↦ tsub_le_tsub_right h c
+ · exact (continuous_sub_right c).continuousAt
/-- `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/Polynomial.lean b/Mathlib/Topology/Algebra/Polynomial.lean
index fb827c4965390..663b8bd81dc20 100644
--- a/Mathlib/Topology/Algebra/Polynomial.lean
+++ b/Mathlib/Topology/Algebra/Polynomial.lean
@@ -191,8 +191,7 @@ theorem coeff_bdd_of_roots_le {B : ℝ} {d : ℕ} (f : F →+* K) {p : F[X]} (h1
_ ≤ max B 1 ^ d * d.choose (d / 2) := by
gcongr; exact (i.choose_mono h3).trans (i.choose_le_middle d)
· rw [eq_one_of_roots_le hB h1 h2 h4, Polynomial.map_one, coeff_one]
- refine _root_.trans ?_
- (one_le_mul_of_one_le_of_one_le (one_le_pow_of_one_le (le_max_right B 1) d) ?_)
+ refine le_trans ?_ (one_le_mul_of_one_le_of_one_le (one_le_pow₀ (le_max_right B 1)) ?_)
· split_ifs <;> norm_num
· exact mod_cast Nat.succ_le_iff.mpr (Nat.choose_pos (d.div_le_self 2))
diff --git a/Mathlib/Topology/Algebra/PontryaginDual.lean b/Mathlib/Topology/Algebra/PontryaginDual.lean
index 80aa1eef70921..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,23 +48,23 @@ 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
refine fun n x ↦ ⟨?_, fun hx ↦ ⟨Complex.arg x, hx, Circle.exp_arg x⟩⟩
rintro ⟨t, ht : |t| < _, rfl⟩
- have ht' := ht.trans_le (div_le_self Real.pi_nonneg (one_le_pow_of_one_le one_le_two (n + 1)))
+ have ht' := ht.trans_le (div_le_self Real.pi_nonneg (one_le_pow₀ one_le_two))
rwa [Circle.arg_exp (neg_lt_of_abs_lt ht') (lt_of_abs_lt ht').le]
refine ContinuousMonoidHom.locallyCompactSpace_of_hasBasis Vn ?_ ?_
· intro n x h1 h2
rw [hVn] at h1 h2 ⊢
rwa [Circle.coe_mul, Complex.arg_mul x.coe_ne_zero x.coe_ne_zero,
- ← two_mul, abs_mul, abs_two, ← lt_div_iff' two_pos, div_div, ← pow_succ] at h2
+ ← two_mul, abs_mul, abs_two, ← lt_div_iff₀' two_pos, div_div, ← pow_succ] at h2
apply Set.Ioo_subset_Ioc_self
- rw [← two_mul, Set.mem_Ioo, ← abs_lt, abs_mul, abs_two, ← lt_div_iff' two_pos]
+ rw [← two_mul, Set.mem_Ioo, ← abs_lt, abs_mul, abs_two, ← lt_div_iff₀' two_pos]
exact h1.trans_le
- (div_le_div_of_nonneg_left Real.pi_nonneg two_pos (le_self_pow one_le_two n.succ_ne_zero))
+ (div_le_div_of_nonneg_left Real.pi_nonneg two_pos (le_self_pow₀ one_le_two n.succ_ne_zero))
· rw [← Circle.exp_zero, ← isLocalHomeomorph_circleExp.map_nhds_eq 0]
refine ((nhds_basis_zero_abs_sub_lt ℝ).to_hasBasis
(fun x hx ↦ ⟨Nat.ceil (Real.pi / x), trivial, fun t ht ↦ ?_⟩)
@@ -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.lean
deleted file mode 100644
index 2c645d7ab198d..0000000000000
--- a/Mathlib/Topology/Algebra/ProperAction.lean
+++ /dev/null
@@ -1,278 +0,0 @@
-/-
-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
-
-/-!
-# Proper group action
-
-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
-
-* `ProperSMul` : a group `G` acts properly on a topological space `X`
- if the map `(g, x) ↦ (g • x, x)` is proper, in the sense of `IsProperMap`.
-
-## Main statements
-
-* `t2Space_quotient_mulAction_of_properSMul`: If a group `G` acts properly
- 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
-
-* [N. Bourbaki, *General Topology*][bourbaki1966]
-
-## Tags
-
-Hausdorff, group action, proper action
--/
-
-open Filter Topology Set Prod
-
-/-- Proper group action in the sense of Bourbaki:
-the map `G × X → X × X` is a proper map (see `IsProperMap`). -/
-class ProperVAdd (G X : Type*) [TopologicalSpace G] [TopologicalSpace X] [AddGroup G]
- [AddAction G X] : Prop where
- /-- Proper group action in the sense of Bourbaki:
- the map `G × X → X × X` is a proper map (see `IsProperMap`). -/
- isProperMap_vadd_pair : IsProperMap (fun gx ↦ (gx.1 +ᵥ gx.2, gx.2) : G × X → X × X)
-
-/-- Proper group action in the sense of Bourbaki:
-the map `G × X → X × X` is a proper map (see `IsProperMap`). -/
-@[to_additive existing (attr := mk_iff)]
-class ProperSMul (G X : Type*) [TopologicalSpace G] [TopologicalSpace X] [Group G]
- [MulAction G X] : Prop where
- /-- Proper group action in the sense of Bourbaki:
- the map `G × X → X × X` is a proper map (see `IsProperMap`). -/
- isProperMap_smul_pair : IsProperMap (fun gx ↦ (gx.1 • gx.2, gx.2) : G × X → X × X)
-
-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]
-
-/-- If a group acts properly then in particular it acts continuously. -/
-@[to_additive "If a group acts properly then in particular it acts continuously."]
--- See note [lower instance property]
-instance (priority := 100) ProperSMul.toContinuousSMul [ProperSMul G X] : ContinuousSMul G X where
- continuous_smul := isProperMap_smul_pair.continuous.fst
-
-/-- A group `G` acts properly on a topological space `X` if and only if for all ultrafilters
-`𝒰` on `X × G`, if `𝒰` converges to `(x₁, x₂)` along the map `(g, x) ↦ (g • x, x)`,
-then there exists `g : G` such that `g • x₂ = x₁` and `𝒰.fst` converges to `g`. -/
-@[to_additive "A group acts `G` properly on a topological space `X` if and only if
-for all ultrafilters `𝒰` on `X`, if `𝒰` converges to `(x₁, x₂)`
-along the map `(g, x) ↦ (g • x, x)`, then there exists `g : G` such that `g • x₂ = x₁`
-and `𝒰.fst` converges to `g`."]
-theorem properSMul_iff_continuousSMul_ultrafilter_tendsto :
- ProperSMul G X ↔ ContinuousSMul G X ∧
- (∀ 𝒰 : Ultrafilter (G × X), ∀ x₁ x₂ : X,
- Tendsto (fun gx : G × X ↦ (gx.1 • gx.2, gx.2)) 𝒰 (𝓝 (x₁, x₂)) →
- ∃ g : G, g • x₂ = x₁ ∧ Tendsto (Prod.fst : G × X → G) 𝒰 (𝓝 g)) := by
- refine ⟨fun h ↦ ⟨inferInstance, fun 𝒰 x₁ x₂ h' ↦ ?_⟩, fun ⟨cont, h⟩ ↦ ?_⟩
- · rw [properSMul_iff, isProperMap_iff_ultrafilter] at h
- rcases h.2 h' with ⟨gx, hgx1, hgx2⟩
- refine ⟨gx.1, ?_, (continuous_fst.tendsto gx).mono_left hgx2⟩
- simp only [Prod.mk.injEq] at hgx1
- rw [← hgx1.2, hgx1.1]
- · rw [properSMul_iff, isProperMap_iff_ultrafilter]
- refine ⟨by fun_prop, fun 𝒰 (x₁, x₂) hxx ↦ ?_⟩
- rcases h 𝒰 x₁ x₂ hxx with ⟨g, hg1, hg2⟩
- refine ⟨(g, x₂), by simp_rw [hg1], ?_⟩
- rw [nhds_prod_eq, 𝒰.le_prod]
- exact ⟨hg2, (continuous_snd.tendsto _).comp hxx⟩
-
-/-- A group `G` acts properly on a T2 topological space `X` if and only if for all ultrafilters
-`𝒰` on `X × G`, if `𝒰` converges to `(x₁, x₂)` along the map `(g, x) ↦ (g • x, x)`,
-then there exists `g : G` such that `𝒰.fst` converges to `g`. -/
-theorem properSMul_iff_continuousSMul_ultrafilter_tendsto_t2 [T2Space X] :
- ProperSMul G X ↔ ContinuousSMul G X ∧
- (∀ 𝒰 : Ultrafilter (G × X), ∀ x₁ x₂ : X,
- Tendsto (fun gx : G × X ↦ (gx.1 • gx.2, gx.2)) 𝒰 (𝓝 (x₁, x₂)) →
- ∃ g : G, Tendsto (Prod.fst : G × X → G) 𝒰 (𝓝 g)) := by
- rw [properSMul_iff_continuousSMul_ultrafilter_tendsto]
- refine and_congr_right fun hc ↦ ?_
- congrm ∀ 𝒰 x₁ x₂ hxx, ∃ g, ?_
- exact and_iff_right_of_imp fun hg ↦ tendsto_nhds_unique
- (hg.smul ((continuous_snd.tendsto _).comp hxx)) ((continuous_fst.tendsto _).comp hxx)
-
-/-- If `G` acts properly on `X`, then the quotient space is Hausdorff (T2). -/
-@[to_additive "If `G` acts properly on `X`, then the quotient space is Hausdorff (T2)."]
-theorem t2Space_quotient_mulAction_of_properSMul [ProperSMul G X] :
- T2Space (Quotient (MulAction.orbitRel G X)) := by
- rw [t2_iff_isClosed_diagonal]
- set R := MulAction.orbitRel G X
- let π : X → Quotient R := Quotient.mk'
- have : QuotientMap (Prod.map π π) :=
- (isOpenMap_quotient_mk'_mul.prod isOpenMap_quotient_mk'_mul).to_quotientMap
- (continuous_quotient_mk'.prod_map continuous_quotient_mk')
- ((surjective_quotient_mk' _).prodMap (surjective_quotient_mk' _))
- rw [← this.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]
- all_goals infer_instance
-
-/-- If a T2 group acts properly on a topological space, then this topological space is T2. -/
-@[to_additive "If a T2 group acts properly on a topological space,
-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
- · 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)
- · have : range f = ({1} ×ˢ univ) := by simp
- rw [this]
- exact isClosed_singleton.prod isClosed_univ
- rw [t2_iff_isClosed_diagonal]
- let g := fun gx : G × X ↦ (gx.1 • gx.2, gx.2)
- have proper_g : IsProperMap g := (properSMul_iff G X).1 h_proper
- have : g ∘ f = fun x ↦ (x, x) := by ext x <;> simp
- have range_gf : range (g ∘ f) = diagonal X := by simp [this]
- rw [← range_gf]
- exact (proper_f.comp proper_g).isClosed_range
-
-/-- 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`. -/
-@[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)
- (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)) := IsProperMap.prod_map this 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
-
-/-- 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.prod_map (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)
diff --git a/Mathlib/Topology/Algebra/ProperAction/Basic.lean b/Mathlib/Topology/Algebra/ProperAction/Basic.lean
new file mode 100644
index 0000000000000..5b68b2d2d0d6f
--- /dev/null
+++ b/Mathlib/Topology/Algebra/ProperAction/Basic.lean
@@ -0,0 +1,167 @@
+/-
+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.MulAction
+import Mathlib.Topology.Maps.Proper.Basic
+import Mathlib.Topology.Maps.OpenQuotient
+
+/-!
+# Proper group action
+
+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.
+
+## Main definitions
+
+* `ProperSMul` : a group `G` acts properly on a topological space `X`
+ if the map `(g, x) ↦ (g • x, x)` is proper, in the sense of `IsProperMap`.
+
+## Main statements
+
+* `t2Space_quotient_mulAction_of_properSMul`: If a group `G` acts properly
+ 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.
+
+## References
+
+* [N. Bourbaki, *General Topology*][bourbaki1966]
+
+## Tags
+
+Hausdorff, group action, proper action
+-/
+
+open Filter Topology Set Prod
+
+/-- Proper group action in the sense of Bourbaki:
+the map `G × X → X × X` is a proper map (see `IsProperMap`). -/
+class ProperVAdd (G X : Type*) [TopologicalSpace G] [TopologicalSpace X] [AddGroup G]
+ [AddAction G X] : Prop where
+ /-- Proper group action in the sense of Bourbaki:
+ the map `G × X → X × X` is a proper map (see `IsProperMap`). -/
+ isProperMap_vadd_pair : IsProperMap (fun gx ↦ (gx.1 +ᵥ gx.2, gx.2) : G × X → X × X)
+
+/-- Proper group action in the sense of Bourbaki:
+the map `G × X → X × X` is a proper map (see `IsProperMap`). -/
+@[to_additive existing (attr := mk_iff)]
+class ProperSMul (G X : Type*) [TopologicalSpace G] [TopologicalSpace X] [Group G]
+ [MulAction G X] : Prop where
+ /-- Proper group action in the sense of Bourbaki:
+ the map `G × X → X × X` is a proper map (see `IsProperMap`). -/
+ isProperMap_smul_pair : IsProperMap (fun gx ↦ (gx.1 • gx.2, gx.2) : G × X → X × X)
+
+attribute [to_additive existing] properSMul_iff
+
+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."]
+-- See note [lower instance property]
+instance (priority := 100) ProperSMul.toContinuousSMul [ProperSMul G X] : ContinuousSMul G X where
+ continuous_smul := isProperMap_smul_pair.continuous.fst
+
+/-- A group `G` acts properly on a topological space `X` if and only if for all ultrafilters
+`𝒰` on `X × G`, if `𝒰` converges to `(x₁, x₂)` along the map `(g, x) ↦ (g • x, x)`,
+then there exists `g : G` such that `g • x₂ = x₁` and `𝒰.fst` converges to `g`. -/
+@[to_additive "A group `G` acts properly on a topological space `X` if and only if
+for all ultrafilters `𝒰` on `X`, if `𝒰` converges to `(x₁, x₂)`
+along the map `(g, x) ↦ (g • x, x)`, then there exists `g : G` such that `g • x₂ = x₁`
+and `𝒰.fst` converges to `g`."]
+theorem properSMul_iff_continuousSMul_ultrafilter_tendsto :
+ ProperSMul G X ↔ ContinuousSMul G X ∧
+ (∀ 𝒰 : Ultrafilter (G × X), ∀ x₁ x₂ : X,
+ Tendsto (fun gx : G × X ↦ (gx.1 • gx.2, gx.2)) 𝒰 (𝓝 (x₁, x₂)) →
+ ∃ g : G, g • x₂ = x₁ ∧ Tendsto (Prod.fst : G × X → G) 𝒰 (𝓝 g)) := by
+ refine ⟨fun h ↦ ⟨inferInstance, fun 𝒰 x₁ x₂ h' ↦ ?_⟩, fun ⟨cont, h⟩ ↦ ?_⟩
+ · rw [properSMul_iff, isProperMap_iff_ultrafilter] at h
+ rcases h.2 h' with ⟨gx, hgx1, hgx2⟩
+ refine ⟨gx.1, ?_, (continuous_fst.tendsto gx).mono_left hgx2⟩
+ simp only [Prod.mk.injEq] at hgx1
+ rw [← hgx1.2, hgx1.1]
+ · rw [properSMul_iff, isProperMap_iff_ultrafilter]
+ refine ⟨by fun_prop, fun 𝒰 (x₁, x₂) hxx ↦ ?_⟩
+ rcases h 𝒰 x₁ x₂ hxx with ⟨g, hg1, hg2⟩
+ refine ⟨(g, x₂), by simp_rw [hg1], ?_⟩
+ rw [nhds_prod_eq, 𝒰.le_prod]
+ exact ⟨hg2, (continuous_snd.tendsto _).comp hxx⟩
+
+/-- A group `G` acts properly on a T2 topological space `X` if and only if for all ultrafilters
+`𝒰` on `X × G`, if `𝒰` converges to `(x₁, x₂)` along the map `(g, x) ↦ (g • x, x)`,
+then there exists `g : G` such that `𝒰.fst` converges to `g`. -/
+theorem properSMul_iff_continuousSMul_ultrafilter_tendsto_t2 [T2Space X] :
+ ProperSMul G X ↔ ContinuousSMul G X ∧
+ (∀ 𝒰 : Ultrafilter (G × X), ∀ x₁ x₂ : X,
+ Tendsto (fun gx : G × X ↦ (gx.1 • gx.2, gx.2)) 𝒰 (𝓝 (x₁, x₂)) →
+ ∃ g : G, Tendsto (Prod.fst : G × X → G) 𝒰 (𝓝 g)) := by
+ rw [properSMul_iff_continuousSMul_ultrafilter_tendsto]
+ refine and_congr_right fun hc ↦ ?_
+ congrm ∀ 𝒰 x₁ x₂ hxx, ∃ g, ?_
+ exact and_iff_right_of_imp fun hg ↦ tendsto_nhds_unique
+ (hg.smul ((continuous_snd.tendsto _).comp hxx)) ((continuous_fst.tendsto _).comp hxx)
+
+/-- If `G` acts properly on `X`, then the quotient space is Hausdorff (T2). -/
+@[to_additive "If `G` acts properly on `X`, then the quotient space is Hausdorff (T2)."]
+theorem t2Space_quotient_mulAction_of_properSMul [ProperSMul G X] :
+ T2Space (Quotient (MulAction.orbitRel G X)) := by
+ rw [t2_iff_isClosed_diagonal]
+ set R := MulAction.orbitRel G X
+ let π : X → Quotient R := Quotient.mk'
+ have : IsOpenQuotientMap (Prod.map π π) :=
+ MulAction.isOpenQuotientMap_quotientMk.prodMap MulAction.isOpenQuotientMap_quotientMk
+ 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', 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. -/
+@[to_additive "If a T2 group acts properly on a topological space,
+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
+ refine IsClosedEmbedding.isProperMap ⟨?_, ?_⟩
+ · let g := fun gx : G × X ↦ gx.2
+ have : Function.LeftInverse g f := fun x ↦ by simp
+ exact this.isEmbedding (by fun_prop) (by fun_prop)
+ · have : range f = ({1} ×ˢ univ) := by simp
+ rw [this]
+ exact isClosed_singleton.prod isClosed_univ
+ rw [t2_iff_isClosed_diagonal]
+ let g := fun gx : G × X ↦ (gx.1 • gx.2, gx.2)
+ have proper_g : IsProperMap g := (properSMul_iff G X).1 h_proper
+ have : g ∘ f = fun x ↦ (x, x) := by ext x <;> simp
+ have range_gf : range (g ∘ f) = diagonal X := by simp [this]
+ rw [← range_gf]
+ exact (proper_f.comp proper_g).isClosed_range
+
+/-- 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`. -/
+@[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_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 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_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/ProperConstSMul.lean b/Mathlib/Topology/Algebra/ProperConstSMul.lean
index 30fbbb4b83bf7..7e3167890f5ee 100644
--- a/Mathlib/Topology/Algebra/ProperConstSMul.lean
+++ b/Mathlib/Topology/Algebra/ProperConstSMul.lean
@@ -61,7 +61,7 @@ instance {M X Y : Type*}
[SMul M X] [TopologicalSpace X] [ProperConstSMul M X]
[SMul M Y] [TopologicalSpace Y] [ProperConstSMul M Y] :
ProperConstSMul M (X × Y) :=
- ⟨fun c ↦ (isProperMap_smul c X).prod_map (isProperMap_smul c Y)⟩
+ ⟨fun c ↦ (isProperMap_smul c X).prodMap (isProperMap_smul c Y)⟩
instance {M ι : Type*} {X : ι → Type*}
[∀ i, SMul M (X i)] [∀ i, TopologicalSpace (X i)] [∀ i, ProperConstSMul M (X i)] :
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 bd45ee761f821..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
@@ -51,26 +52,21 @@ instance topologicalRingQuotientTopology : TopologicalSpace (R ⧸ N) :=
-- note for the reader: in the following, `mk` is `Ideal.Quotient.mk`, the canonical map `R → R/I`.
variable [TopologicalRing R]
-theorem QuotientRing.isOpenMap_coe : IsOpenMap (mk N) := by
- intro s s_op
- change IsOpen (mk N ⁻¹' (mk N '' s))
- rw [quotient_ring_saturate]
- exact isOpen_iUnion fun ⟨n, _⟩ => isOpenMap_add_left n s s_op
-
-theorem QuotientRing.quotientMap_coe_coe : QuotientMap fun p : R × R => (mk N p.1, mk N p.2) :=
- IsOpenMap.to_quotientMap ((QuotientRing.isOpenMap_coe N).prod (QuotientRing.isOpenMap_coe N))
- ((continuous_quot_mk.comp continuous_fst).prod_mk (continuous_quot_mk.comp continuous_snd))
- (by rintro ⟨⟨x⟩, ⟨y⟩⟩; exact ⟨(x, y), rfl⟩)
-
-instance topologicalRing_quotient : TopologicalRing (R ⧸ N) :=
- TopologicalSemiring.toTopologicalRing
- { continuous_add :=
- have cont : Continuous (mk N ∘ fun p : R × R => p.fst + p.snd) :=
- continuous_quot_mk.comp continuous_add
- (QuotientMap.continuous_iff (QuotientRing.quotientMap_coe_coe N)).mpr cont
- continuous_mul :=
- have cont : Continuous (mk N ∘ fun p : R × R => p.fst * p.snd) :=
- continuous_quot_mk.comp continuous_mul
- (QuotientMap.continuous_iff (QuotientRing.quotientMap_coe_coe N)).mpr cont }
+theorem QuotientRing.isOpenMap_coe : IsOpenMap (mk N) :=
+ QuotientAddGroup.isOpenMap_coe
+
+theorem QuotientRing.isOpenQuotientMap_mk : IsOpenQuotientMap (mk N) :=
+ QuotientAddGroup.isOpenQuotientMap_mk
+
+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.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 83%
rename from Mathlib/Topology/Algebra/SeparationQuotient.lean
rename to Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean
index 140e089dc9563..1f2427e29b56f 100644
--- a/Mathlib/Topology/Algebra/SeparationQuotient.lean
+++ b/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
import Mathlib.Topology.Algebra.Module.Basic
-import Mathlib.LinearAlgebra.Basis.VectorSpace
/-!
# Algebraic operations on `SeparationQuotient`
@@ -20,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
@@ -35,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]
@@ -63,6 +64,12 @@ instance instIsScalarTower [SMul M N] [ContinuousConstSMul N X] [IsScalarTower M
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).isQuotientMap.continuous_iff]
+ exact continuous_mk.comp continuous_smul
+
instance instSMulZeroClass {M X : Type*} [Zero X] [SMulZeroClass M X] [TopologicalSpace X]
[ContinuousConstSMul M X] : SMulZeroClass M (SeparationQuotient X) :=
ZeroHom.smulZeroClass ⟨mk, mk_zero⟩ mk_smul
@@ -86,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) :=
@@ -147,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] :
@@ -168,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
@@ -190,6 +197,17 @@ instance instCommGroup [CommGroup G] [TopologicalGroup G] : CommGroup (Separatio
end Group
+section UniformGroup
+
+@[to_additive]
+instance instUniformGroup {G : Type*} [Group G] [UniformSpace G] [UniformGroup G] :
+ UniformGroup (SeparationQuotient G) where
+ uniformContinuous_div := by
+ rw [uniformContinuous_dom₂]
+ exact uniformContinuous_mk.comp uniformContinuous_div
+
+end UniformGroup
+
section MonoidWithZero
variable {M₀ : Type*} [TopologicalSpace M₀]
@@ -315,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
@@ -357,65 +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]
+section Algebra
+variable {R A : Type*} [CommSemiring R] [Semiring A] [Algebra R A]
+ [TopologicalSpace A] [TopologicalSemiring A] [ContinuousConstSMul R A]
-/-- 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, 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
+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 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)
-
-/-- 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_uniformEmbedding : UniformEmbedding (outCLM K E) where
- inj := outCLM_injective K E
- toUniformInducing := outCLM_uniformInducing K E
-
-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 deb57a790041b..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.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Defs
/-!
# Continuity of `star`
diff --git a/Mathlib/Topology/Algebra/StarSubalgebra.lean b/Mathlib/Topology/Algebra/StarSubalgebra.lean
index c535323f3084f..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
@@ -146,7 +153,7 @@ theorem _root_.StarAlgHom.ext_topologicalClosure [T2Space B] {S : StarSubalgebra
theorem _root_.StarAlgHomClass.ext_topologicalClosure [T2Space B] {F : Type*}
{S : StarSubalgebra R A} [FunLike F S.topologicalClosure B]
- [AlgHomClass F R S.topologicalClosure B] [StarAlgHomClass F R S.topologicalClosure B] {φ ψ : F}
+ [AlgHomClass F R S.topologicalClosure B] [StarHomClass F S.topologicalClosure B] {φ ψ : F}
(hφ : Continuous φ) (hψ : Continuous ψ) (h : ∀ x : S,
φ (inclusion (le_topologicalClosure S) x) = ψ ((inclusion (le_topologicalClosure S)) x)) :
φ = ψ := by
@@ -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] [StarAlgHomClass F R _ B]
+ [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 : StarAlgHomClass F R (↥(topologicalClosure (adjoin R {a}))) B :=
- inferInstanceAs (StarAlgHomClass F R (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 adf3afef18aff..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
@@ -252,8 +253,8 @@ protected theorem UniformOnFun.hasBasis_nhds_one_of_basis (𝔖 : Set <| Set α)
(h : (𝓝 1 : Filter G).HasBasis p b) :
(𝓝 1 : Filter (α →ᵤ[𝔖] G)).HasBasis (fun Si : Set α × ι => Si.1 ∈ 𝔖 ∧ p Si.2) fun Si =>
{ f : α →ᵤ[𝔖] G | ∀ x ∈ Si.1, toFun 𝔖 f x ∈ b Si.2 } := by
- have := h.uniformity_of_nhds_one_swapped
- convert UniformOnFun.hasBasis_nhds_of_basis α _ 𝔖 (1 : α →ᵤ[𝔖] G) h𝔖₁ h𝔖₂ this
+ convert UniformOnFun.hasBasis_nhds_of_basis α _ 𝔖 (1 : α →ᵤ[𝔖] G) h𝔖₁ h𝔖₂ <|
+ h.uniformity_of_nhds_one_swapped
simp [UniformOnFun.gen]
@[to_additive]
diff --git a/Mathlib/Topology/Algebra/UniformField.lean b/Mathlib/Topology/Algebra/UniformField.lean
index 059b0ae0cacfb..b0532ff29f706 100644
--- a/Mathlib/Topology/Algebra/UniformField.lean
+++ b/Mathlib/Topology/Algebra/UniformField.lean
@@ -55,17 +55,17 @@ namespace UniformSpace
namespace Completion
instance (priority := 100) [T0Space K] : Nontrivial (hat K) :=
- ⟨⟨0, 1, fun h => zero_ne_one <| (uniformEmbedding_coe K).inj h⟩⟩
+ ⟨⟨0, 1, fun h => zero_ne_one <| (isUniformEmbedding_coe K).inj h⟩⟩
variable {K}
/-- extension of inversion to the completion of a field. -/
def hatInv : hat K → hat K :=
- denseInducing_coe.extend fun x : K => (↑x⁻¹ : hat K)
+ isDenseInducing_coe.extend fun x : K => (↑x⁻¹ : hat K)
theorem continuous_hatInv [CompletableTopField K] {x : hat K} (h : x ≠ 0) :
ContinuousAt hatInv x := by
- refine denseInducing_coe.continuousAt_extend ?_
+ refine isDenseInducing_coe.continuousAt_extend ?_
apply mem_of_superset (compl_singleton_mem_nhds h)
intro y y_ne
rw [mem_compl_singleton_iff] at y_ne
@@ -77,13 +77,13 @@ theorem continuous_hatInv [CompletableTopField K] {x : hat K} (h : x ≠ 0) :
rw [this, ← Filter.map_map]
apply Cauchy.map _ (Completion.uniformContinuous_coe K)
apply CompletableTopField.nice
- · haveI := denseInducing_coe.comap_nhds_neBot y
+ · haveI := isDenseInducing_coe.comap_nhds_neBot y
apply cauchy_nhds.comap
rw [Completion.comap_coe_eq_uniformity]
· have eq_bot : 𝓝 (0 : hat K) ⊓ 𝓝 y = ⊥ := by
by_contra h
exact y_ne (eq_of_nhds_neBot <| neBot_iff.mpr h).symm
- erw [denseInducing_coe.nhds_eq_comap (0 : K), ← Filter.comap_inf, eq_bot]
+ erw [isDenseInducing_coe.nhds_eq_comap (0 : K), ← Filter.comap_inf, eq_bot]
exact comap_bot
open Classical in
@@ -97,7 +97,7 @@ instance instInvCompletion : Inv (hat K) :=
variable [TopologicalDivisionRing K]
theorem hatInv_extends {x : K} (h : x ≠ 0) : hatInv (x : hat K) = ↑(x⁻¹ : K) :=
- denseInducing_coe.extend_eq_at ((continuous_coe K).continuousAt.comp (continuousAt_inv₀ h))
+ isDenseInducing_coe.extend_eq_at ((continuous_coe K).continuousAt.comp (continuousAt_inv₀ h))
variable [CompletableTopField K]
@@ -111,7 +111,7 @@ theorem coe_inv (x : K) : (x : hat K)⁻¹ = ((x⁻¹ : K) : hat K) := by
· conv_lhs => dsimp [Inv.inv]
rw [if_neg]
· exact hatInv_extends h
- · exact fun H => h (denseEmbedding_coe.inj H)
+ · exact fun H => h (isDenseEmbedding_coe.inj H)
variable [UniformAddGroup K]
@@ -126,7 +126,7 @@ theorem mul_hatInv_cancel {x : hat K} (x_ne : x ≠ 0) : x * hatInv x = 1 := by
continuous_id.continuousAt.prod (continuous_hatInv x_ne)
exact (_root_.continuous_mul.continuousAt.comp this : _)
have clo : x ∈ closure (c '' {0}ᶜ) := by
- have := denseInducing_coe.dense x
+ have := isDenseInducing_coe.dense x
rw [← image_univ, show (univ : Set K) = {0} ∪ {0}ᶜ from (union_compl_self _).symm,
image_union] at this
apply mem_closure_of_mem_closure_union this
@@ -145,14 +145,14 @@ theorem mul_hatInv_cancel {x : hat K} (x_ne : x ≠ 0) : x * hatInv x = 1 := by
rwa [closure_singleton, mem_singleton_iff] at fxclo
instance instField : Field (hat K) where
- exists_pair_ne := ⟨0, 1, fun h => zero_ne_one ((uniformEmbedding_coe K).inj h)⟩
+ exists_pair_ne := ⟨0, 1, fun h => zero_ne_one ((isUniformEmbedding_coe K).inj h)⟩
mul_inv_cancel := fun x x_ne => by simp only [Inv.inv, if_neg x_ne, mul_hatInv_cancel x_ne]
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 := uniformEmbedding_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 b160ebca22eed..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,95 +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 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
@@ -141,72 +44,36 @@ instance Pi.instUniformGroup {ι : Type*} {G : ι → Type*} [∀ i, UniformSpac
(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 uniformEmbedding_translate_mul (a : α) : UniformEmbedding fun x : α => x * a :=
+theorem isUniformEmbedding_translate_mul (a : α) : IsUniformEmbedding fun x : α => x * a :=
{ comap_uniformity := by
nth_rw 1 [← uniformity_translate_mul a, comap_map]
rintro ⟨p₁, p₂⟩ ⟨q₁, q₂⟩
simp only [Prod.mk.injEq, mul_left_inj, imp_self]
inj := mul_left_injective a }
-namespace MulOpposite
-
-@[to_additive]
-instance : UniformGroup αᵐᵒᵖ :=
- ⟨uniformContinuous_op.comp
- ((uniformContinuous_unop.comp uniformContinuous_snd).inv.mul <|
- uniformContinuous_unop.comp uniformContinuous_fst)⟩
-
-end MulOpposite
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_translate_mul := isUniformEmbedding_translate_mul
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.prod_map hf.uniformContinuous)
+ 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
@@ -217,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) :=
@@ -384,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 β}
@@ -440,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
@@ -542,76 +243,9 @@ 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 : DenseInducing 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 DenseInducing
+namespace IsDenseInducing
variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*}
variable {G : Type*}
@@ -623,8 +257,8 @@ variable [TopologicalSpace β] [AddCommGroup β]
variable [TopologicalSpace γ] [AddCommGroup γ] [TopologicalAddGroup γ]
variable [TopologicalSpace δ] [AddCommGroup δ]
variable [UniformSpace G] [AddCommGroup G]
-variable {e : β →+ α} (de : DenseInducing e)
-variable {f : δ →+ γ} (df : DenseInducing f)
+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))
@@ -698,21 +332,21 @@ private theorem extend_Z_bilin_key (x₀ : α) (y₀ : γ) : ∃ U ∈ comap e (
have h₄ := H x₁ x₁_in x xU₁ y yV₁ y' y'V₁
exact W4 h₁ h₂ h₃ h₄
-open DenseInducing
+open IsDenseInducing
variable [T0Space G] [CompleteSpace G]
/-- Bourbaki GT III.6.5 Theorem I:
ℤ-bilinear continuous maps from dense images into a complete Hausdorff group extend by continuity.
Note: Bourbaki assumes that α and β are also complete Hausdorff, but this is not necessary. -/
-theorem extend_Z_bilin : Continuous (extend (de.prod df) (fun p : β × δ => φ p.1 p.2)) := by
+theorem extend_Z_bilin : Continuous (extend (de.prodMap df) (fun p : β × δ => φ p.1 p.2)) := by
refine continuous_extend_of_cauchy _ ?_
rintro ⟨x₀, y₀⟩
constructor
· apply NeBot.map
apply comap_neBot
intro U h
- rcases mem_closure_iff_nhds.1 ((de.prod df).dense (x₀, y₀)) U h with ⟨x, x_in, ⟨z, z_x⟩⟩
+ rcases mem_closure_iff_nhds.1 ((de.prodMap df).dense (x₀, y₀)) U h with ⟨x, x_in, ⟨z, z_x⟩⟩
exists z
aesop
· suffices map (fun p : (β × δ) × β × δ => (fun p : β × δ => φ p.1 p.2) p.2 -
@@ -740,7 +374,7 @@ theorem extend_Z_bilin : Continuous (extend (de.prod df) (fun p : β × δ => φ
rcases p with ⟨⟨x, y⟩, ⟨x', y'⟩⟩
apply h <;> tauto
-end DenseInducing
+end IsDenseInducing
section CompleteQuotient
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 4c23eda8c9359..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
@@ -116,6 +120,39 @@ instance UniformGroup.to_uniformContinuousConstSMul {G : Type u} [Group G] [Unif
[UniformGroup G] : UniformContinuousConstSMul G G :=
⟨fun _ => uniformContinuous_const.mul uniformContinuous_id⟩
+section Ring
+
+variable {R β : Type*} [Ring R] [UniformSpace R] [UniformSpace β]
+
+theorem UniformContinuous.const_mul' [UniformContinuousConstSMul R R] {f : β → R}
+ (hf : UniformContinuous f) (a : R) : UniformContinuous fun x ↦ a * f x :=
+ hf.const_smul a
+
+theorem UniformContinuous.mul_const' [UniformContinuousConstSMul Rᵐᵒᵖ R] {f : β → R}
+ (hf : UniformContinuous f) (a : R) : UniformContinuous fun x ↦ f x * a :=
+ hf.const_smul (MulOpposite.op a)
+
+theorem uniformContinuous_mul_left' [UniformContinuousConstSMul R R] (a : R) :
+ UniformContinuous fun b : R => a * b :=
+ uniformContinuous_id.const_mul' _
+
+theorem uniformContinuous_mul_right' [UniformContinuousConstSMul Rᵐᵒᵖ R] (a : R) :
+ UniformContinuous fun b : R => b * a :=
+ uniformContinuous_id.mul_const' _
+
+theorem UniformContinuous.div_const' {R β : Type*} [DivisionRing R] [UniformSpace R]
+ [UniformContinuousConstSMul Rᵐᵒᵖ R] [UniformSpace β] {f : β → R}
+ (hf : UniformContinuous f) (a : R) :
+ UniformContinuous fun x ↦ f x / a := by
+ simpa [div_eq_mul_inv] using hf.mul_const' a⁻¹
+
+theorem uniformContinuous_div_const' {R : Type*} [DivisionRing R] [UniformSpace R]
+ [UniformContinuousConstSMul Rᵐᵒᵖ R] (a : R) :
+ UniformContinuous fun b : R => b / a :=
+ uniformContinuous_id.div_const' _
+
+end Ring
+
namespace UniformSpace
namespace Completion
diff --git a/Mathlib/Topology/Algebra/UniformRing.lean b/Mathlib/Topology/Algebra/UniformRing.lean
index d5096b53d82a7..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:
@@ -38,7 +39,7 @@ noncomputable section
universe u
namespace UniformSpace.Completion
-open DenseInducing UniformSpace Function
+open IsDenseInducing UniformSpace Function
section one_and_mul
variable (α : Type*) [Ring α] [UniformSpace α]
@@ -47,7 +48,7 @@ instance one : One (Completion α) :=
⟨(1 : α)⟩
instance mul : Mul (Completion α) :=
- ⟨curry <| (denseInducing_coe.prod denseInducing_coe).extend ((↑) ∘ uncurry (· * ·))⟩
+ ⟨curry <| (isDenseInducing_coe.prodMap isDenseInducing_coe).extend ((↑) ∘ uncurry (· * ·))⟩
@[norm_cast]
theorem coe_one : ((1 : α) : Completion α) = 1 :=
@@ -59,7 +60,7 @@ variable {α : Type*} [Ring α] [UniformSpace α] [TopologicalRing α]
@[norm_cast]
theorem coe_mul (a b : α) : ((a * b : α) : Completion α) = a * b :=
- ((denseInducing_coe.prod denseInducing_coe).extend_eq
+ ((isDenseInducing_coe.prodMap isDenseInducing_coe).extend_eq
((continuous_coe α).comp (@continuous_mul α _ _ _)) (a, b)).symm
variable [UniformAddGroup α]
@@ -70,7 +71,7 @@ theorem continuous_mul : Continuous fun p : Completion α × Completion α => p.
apply (continuous_coe α).comp _
simp only [AddMonoidHom.coe_mul, AddMonoidHom.coe_mulLeft]
exact _root_.continuous_mul
- have di : DenseInducing (toCompl : α → Completion α) := denseInducing_coe
+ have di : IsDenseInducing (toCompl : α → Completion α) := isDenseInducing_coe
convert di.extend_Z_bilin di this
theorem Continuous.mul {β : Type*} [TopologicalSpace β] {f g : β → Completion α}
@@ -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,28 +277,28 @@ variable {γ : Type*} [UniformSpace γ] [Semiring γ] [TopologicalSemiring γ]
variable [T2Space γ] [CompleteSpace γ]
/-- The dense inducing extension as a ring homomorphism. -/
-noncomputable def DenseInducing.extendRingHom {i : α →+* β} {f : α →+* γ} (ue : UniformInducing i)
- (dr : DenseRange i) (hf : UniformContinuous f) : β →+* γ where
- toFun := (ue.denseInducing dr).extend f
+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 DenseInducing.extend_eq (ue.denseInducing dr) hf.continuous 1
+ convert IsDenseInducing.extend_eq (ue.isDenseInducing dr) hf.continuous 1
exacts [i.map_one.symm, f.map_one.symm]
map_zero' := by
- convert DenseInducing.extend_eq (ue.denseInducing dr) hf.continuous 0 <;>
+ convert IsDenseInducing.extend_eq (ue.isDenseInducing dr) hf.continuous 0 <;>
simp only [map_zero]
map_add' := by
have h := (uniformContinuous_uniformly_extend ue dr hf).continuous
refine fun x y => DenseRange.induction_on₂ dr ?_ (fun a b => ?_) x y
· exact isClosed_eq (Continuous.comp h continuous_add)
((h.comp continuous_fst).add (h.comp continuous_snd))
- · simp_rw [← i.map_add, DenseInducing.extend_eq (ue.denseInducing dr) hf.continuous _,
+ · simp_rw [← i.map_add, IsDenseInducing.extend_eq (ue.isDenseInducing dr) hf.continuous _,
← f.map_add]
map_mul' := by
have h := (uniformContinuous_uniformly_extend ue dr hf).continuous
refine fun x y => DenseRange.induction_on₂ dr ?_ (fun a b => ?_) x y
· exact isClosed_eq (Continuous.comp h continuous_mul)
((h.comp continuous_fst).mul (h.comp continuous_snd))
- · simp_rw [← i.map_mul, DenseInducing.extend_eq (ue.denseInducing dr) hf.continuous _,
+ · simp_rw [← i.map_mul, IsDenseInducing.extend_eq (ue.isDenseInducing dr) hf.continuous _,
← f.map_mul]
end UniformExtension
diff --git a/Mathlib/Topology/Algebra/Valued/NormedValued.lean b/Mathlib/Topology/Algebra/Valued/NormedValued.lean
index 7ce1d9f1fee9d..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 Γ₀]
@@ -97,12 +110,12 @@ def toNormedField : NormedField L :=
haveI : Nonempty { ε : ℝ // ε > 0 } := nonempty_Ioi_subtype
ext U
rw [hasBasis_iff.mp (Valued.hasBasis_uniformity L Γ₀), iInf_subtype', mem_iInf_of_directed]
- · simp only [true_and_iff, mem_principal, Subtype.exists, gt_iff_lt, exists_prop]
+ · simp only [true_and, mem_principal, Subtype.exists, gt_iff_lt, exists_prop]
refine ⟨fun ⟨ε, hε⟩ => ?_, fun ⟨r, hr_pos, hr⟩ => ?_⟩
· set δ : ℝ≥0 := hv.hom ε with hδ
have hδ_pos : 0 < δ := by
rw [hδ, ← _root_.map_zero hv.hom]
- exact hv.strictMono (Units.zero_lt ε)
+ exact hv.strictMono _ (Units.zero_lt ε)
use δ, hδ_pos
apply subset_trans _ hε
intro x hx
@@ -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 2d7836874a275..1ea189adaa60b 100644
--- a/Mathlib/Topology/Algebra/Valued/ValuedField.lean
+++ b/Mathlib/Topology/Algebra/Valued/ValuedField.lean
@@ -187,14 +187,14 @@ open WithZeroTopology
/-- The extension of the valuation of a valued field to the completion of the field. -/
noncomputable def extension : hat K → Γ₀ :=
- Completion.denseInducing_coe.extend (v : K → Γ₀)
+ Completion.isDenseInducing_coe.extend (v : K → Γ₀)
theorem continuous_extension : Continuous (Valued.extension : hat K → Γ₀) := by
- refine Completion.denseInducing_coe.continuous_extend ?_
+ refine Completion.isDenseInducing_coe.continuous_extend ?_
intro x₀
rcases eq_or_ne x₀ 0 with (rfl | h)
· refine ⟨0, ?_⟩
- erw [← Completion.denseInducing_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
@@ -204,7 +204,7 @@ theorem continuous_extension : Continuous (Valued.extension : hat K → Γ₀) :
ext x
rw [Valuation.map_one, mem_preimage, mem_singleton_iff, mem_setOf_eq]
obtain ⟨V, V_in, hV⟩ : ∃ V ∈ 𝓝 (1 : hat K), ∀ x : K, (x : hat K) ∈ V → (v x : Γ₀) = 1 := by
- rwa [Completion.denseInducing_coe.nhds_eq_comap, mem_comap] at preimage_one
+ rwa [Completion.isDenseInducing_coe.nhds_eq_comap, mem_comap] at preimage_one
have : ∃ V' ∈ 𝓝 (1 : hat K), (0 : hat K) ∉ V' ∧ ∀ (x) (_ : x ∈ V') (y) (_ : y ∈ V'),
x * y⁻¹ ∈ V := by
have : Tendsto (fun p : hat K × hat K => p.1 * p.2⁻¹) ((𝓝 1) ×ˢ (𝓝 1)) (𝓝 1) := by
@@ -265,8 +265,8 @@ theorem continuous_extension : Continuous (Valued.extension : hat K → Γ₀) :
@[simp, norm_cast]
theorem extension_extends (x : K) : extension (x : hat K) = v x := by
- refine Completion.denseInducing_coe.extend_eq_of_tendsto ?_
- rw [← Completion.denseInducing_coe.nhds_eq_comap]
+ refine Completion.isDenseInducing_coe.extend_eq_of_tendsto ?_
+ rw [← Completion.isDenseInducing_coe.nhds_eq_comap]
exact Valued.continuous_valuation.continuousAt
/-- the extension of a valuation on a division ring to its completion. -/
@@ -313,9 +313,9 @@ theorem closure_coe_completion_v_lt {γ : Γ₀ˣ} :
suffices γ₀ ≠ 0 → (x ∈ closure ((↑) '' { x : K | v x < (γ : Γ₀) }) ↔ γ₀ < (γ : Γ₀)) by
rcases eq_or_ne γ₀ 0 with h | h
· simp only [h, (Valuation.zero_iff _).mp h, mem_setOf_eq, Valuation.map_zero, Units.zero_lt,
- iff_true_iff]
+ iff_true]
apply subset_closure
- exact ⟨0, by simp only [mem_setOf_eq, Valuation.map_zero, Units.zero_lt, true_and_iff]; rfl⟩
+ exact ⟨0, by simp only [mem_setOf_eq, Valuation.map_zero, Units.zero_lt, true_and]; rfl⟩
· exact this h
intro h
have hγ₀ : extension ⁻¹' {γ₀} ∈ 𝓝 x :=
@@ -339,7 +339,7 @@ noncomputable instance valuedCompletion : Valued (hat K) Γ₀ where
rw [this.mem_iff]
exact exists_congr fun γ => by simp
simp_rw [← closure_coe_completion_v_lt]
- exact (hasBasis_nhds_zero K Γ₀).hasBasis_of_denseInducing Completion.denseInducing_coe
+ exact (hasBasis_nhds_zero K Γ₀).hasBasis_of_isDenseInducing Completion.isDenseInducing_coe
-- Porting note: removed @[norm_cast] attribute due to error:
-- norm_cast: badly shaped lemma, rhs can't start with coe
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 033576301698e..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₂) :
@@ -286,11 +289,6 @@ protected theorem IsTopologicalBasis.continuous_iff {β : Type*} [TopologicalSpa
Continuous f ↔ ∀ s ∈ B, IsOpen (f ⁻¹' s) := by
rw [hB.eq_generateFrom, continuous_generateFrom_iff]
-@[deprecated (since := "2023-12-24")]
-protected theorem IsTopologicalBasis.continuous {β : Type*} [TopologicalSpace β] {B : Set (Set β)}
- (hB : IsTopologicalBasis B) (f : α → β) (hf : ∀ s ∈ B, IsOpen (f ⁻¹' s)) : Continuous f :=
- hB.continuous_iff.2 hf
-
variable (α)
/-- A separable space is one with a countable dense subset, available through
@@ -357,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⟩
@@ -387,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
@@ -578,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)]
@@ -661,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
@@ -892,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
@@ -922,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)
@@ -936,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}
@@ -950,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
@@ -965,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 bd76d56aee901..9961f73158dbd 100644
--- a/Mathlib/Topology/Basic.lean
+++ b/Mathlib/Topology/Basic.lean
@@ -3,6 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Mario Carneiro, Jeremy Avigad
-/
+import Mathlib.Algebra.Group.Support
import Mathlib.Order.Filter.Lift
import Mathlib.Topology.Defs.Filter
@@ -89,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
@@ -308,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₂⟩
@@ -798,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
@@ -845,18 +848,18 @@ theorem tendsto_nhds {f : α → X} {l : Filter α} :
theorem tendsto_atTop_nhds [Nonempty α] [SemilatticeSup α] {f : α → X} :
Tendsto f atTop (𝓝 x) ↔ ∀ U : Set X, x ∈ U → IsOpen U → ∃ N, ∀ n, N ≤ n → f n ∈ U :=
(atTop_basis.tendsto_iff (nhds_basis_opens x)).trans <| by
- simp only [and_imp, exists_prop, true_and_iff, mem_Ici]
+ simp only [and_imp, exists_prop, true_and, mem_Ici]
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
@@ -1028,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
-/
@@ -1059,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
@@ -1141,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
@@ -1399,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/Bornology/Absorbs.lean b/Mathlib/Topology/Bornology/Absorbs.lean
index 186c664199d67..4afc9483a389f 100644
--- a/Mathlib/Topology/Bornology/Absorbs.lean
+++ b/Mathlib/Topology/Bornology/Absorbs.lean
@@ -22,6 +22,9 @@ We formulate it in a more general settings for two reasons:
- some proofs look nicer with this definition than with something like
`∃ r : ℝ, ∀ a : R, r ≤ ‖a‖ → B ⊆ a • A`.
+If `M` is a `GroupWithZero` (e.g., a division ring),
+the sets absorbing a given set form a filter, see `Filter.absorbing`.
+
## Implementation notes
For now, all theorems assume that we deal with (a generalization of) a module over a division ring.
@@ -133,58 +136,70 @@ protected lemma zero [Zero E] [SMulZeroClass M E] {s : Set E} (hs : 0 ∈ s) : A
end AddZero
+end Absorbs
+
section GroupWithZero
variable {G₀ α : Type*} [GroupWithZero G₀] [Bornology G₀] [MulAction G₀ α]
{s t u : Set α} {S : Set (Set α)}
@[simp]
-protected lemma univ : Absorbs G₀ univ s :=
+protected lemma Absorbs.univ : Absorbs G₀ univ s :=
(eventually_ne_cobounded 0).mono fun a ha ↦ by rw [smul_set_univ₀ ha]; apply subset_univ
-lemma _root_.absorbs_iff_eventually_cobounded_mapsTo :
+lemma absorbs_iff_eventually_cobounded_mapsTo :
Absorbs G₀ s t ↔ ∀ᶠ c in cobounded G₀, MapsTo (c⁻¹ • ·) t s :=
eventually_congr <| (eventually_ne_cobounded 0).mono fun c hc ↦ by
rw [← preimage_smul_inv₀ hc]; rfl
alias ⟨eventually_cobounded_mapsTo, _⟩ := absorbs_iff_eventually_cobounded_mapsTo
-lemma _root_.Set.Finite.absorbs_sInter (hS : S.Finite) :
- Absorbs G₀ (⋂₀ S) t ↔ ∀ s ∈ S, Absorbs G₀ s t := by
- simp only [absorbs_iff_eventually_cobounded_mapsTo, mapsTo_sInter, hS.eventually_all]
+@[simp]
+lemma absorbs_inter : Absorbs G₀ (s ∩ t) u ↔ Absorbs G₀ s u ∧ Absorbs G₀ t u := by
+ simp only [absorbs_iff_eventually_cobounded_mapsTo, mapsTo_inter, eventually_and]
+
+protected lemma Absorbs.inter (hs : Absorbs G₀ s u) (ht : Absorbs G₀ t u) : Absorbs G₀ (s ∩ t) u :=
+ absorbs_inter.2 ⟨hs, ht⟩
-protected alias ⟨_, sInter⟩ := Set.Finite.absorbs_sInter
+variable (G₀ u) in
+/-- The filter of sets that absorb `u`. -/
+def Filter.absorbing : Filter α where
+ sets := {s | Absorbs G₀ s u}
+ univ_sets := .univ
+ sets_of_superset h := h.mono_left
+ inter_sets := .inter
@[simp]
-lemma _root_.absorbs_inter : Absorbs G₀ (s ∩ t) u ↔ Absorbs G₀ s u ∧ Absorbs G₀ t u := by
- simpa using ((finite_singleton t).insert s).absorbs_sInter
+lemma Filter.mem_absorbing : s ∈ absorbing G₀ u ↔ Absorbs G₀ s u := .rfl
-protected lemma inter (hs : Absorbs G₀ s u) (ht : Absorbs G₀ t u) : Absorbs G₀ (s ∩ t) u :=
- absorbs_inter.2 ⟨hs, ht⟩
+lemma Set.Finite.absorbs_sInter (hS : S.Finite) :
+ Absorbs G₀ (⋂₀ S) t ↔ ∀ s ∈ S, Absorbs G₀ s t :=
+ sInter_mem (f := absorbing G₀ t) hS
+
+protected alias ⟨_, Absorbs.sInter⟩ := Set.Finite.absorbs_sInter
@[simp]
-lemma _root_.absorbs_iInter {ι : Sort*} [Finite ι] {s : ι → Set α} :
+lemma absorbs_iInter {ι : Sort*} [Finite ι] {s : ι → Set α} :
Absorbs G₀ (⋂ i, s i) t ↔ ∀ i, Absorbs G₀ (s i) t :=
- (finite_range s).absorbs_sInter.trans forall_mem_range
+ iInter_mem (f := absorbing G₀ t)
-protected alias ⟨_, iInter⟩ := absorbs_iInter
+protected alias ⟨_, Absorbs.iInter⟩ := absorbs_iInter
-lemma _root_.Set.Finite.absorbs_biInter {ι : Type*} {I : Set ι} (hI : I.Finite) {s : ι → Set α} :
- Absorbs G₀ (⋂ i ∈ I, s i) t ↔ ∀ i ∈ I, Absorbs G₀ (s i) t := by
- simpa only [sInter_image, forall_mem_image] using (hI.image s).absorbs_sInter
+lemma Set.Finite.absorbs_biInter {ι : Type*} {I : Set ι} (hI : I.Finite) {s : ι → Set α} :
+ Absorbs G₀ (⋂ i ∈ I, s i) t ↔ ∀ i ∈ I, Absorbs G₀ (s i) t :=
+ biInter_mem (f := absorbing G₀ t) hI
-protected alias ⟨_, biInter⟩ := Set.Finite.absorbs_biInter
+protected alias ⟨_, Absorbs.biInter⟩ := Set.Finite.absorbs_biInter
@[simp]
-lemma _root_.absorbs_zero_iff [NeBot (cobounded G₀)] {E : Type*} [AddMonoid E]
- [DistribMulAction G₀ E] {s : Set E} : Absorbs G₀ s 0 ↔ 0 ∈ s := by
+lemma absorbs_zero_iff [NeBot (cobounded G₀)]
+ {E : Type*} [AddMonoid E] [DistribMulAction G₀ E] {s : Set E} :
+ Absorbs G₀ s 0 ↔ 0 ∈ s := by
simp only [absorbs_iff_eventually_cobounded_mapsTo, ← singleton_zero,
mapsTo_singleton, smul_zero, eventually_const]
end GroupWithZero
-end Absorbs
-
section AddGroup
variable {M E : Type*} [Monoid M] [AddGroup E] [DistribMulAction M E] [Bornology M]
diff --git a/Mathlib/Topology/Bornology/Constructions.lean b/Mathlib/Topology/Bornology/Constructions.lean
index e53a16415f67c..c38d27051cf5b 100644
--- a/Mathlib/Topology/Bornology/Constructions.lean
+++ b/Mathlib/Topology/Bornology/Constructions.lean
@@ -77,7 +77,7 @@ theorem isBounded_prod_of_nonempty (hne : Set.Nonempty (s ×ˢ t)) :
theorem isBounded_prod : IsBounded (s ×ˢ t) ↔ s = ∅ ∨ t = ∅ ∨ IsBounded s ∧ IsBounded t := by
rcases s.eq_empty_or_nonempty with (rfl | hs); · simp
rcases t.eq_empty_or_nonempty with (rfl | ht); · simp
- simp only [hs.ne_empty, ht.ne_empty, isBounded_prod_of_nonempty (hs.prod ht), false_or_iff]
+ simp only [hs.ne_empty, ht.ne_empty, isBounded_prod_of_nonempty (hs.prod ht), false_or]
theorem isBounded_prod_self : IsBounded (s ×ˢ s) ↔ IsBounded s := by
rcases s.eq_empty_or_nonempty with (rfl | hs); · simp
@@ -109,7 +109,7 @@ theorem isBounded_pi_of_nonempty (hne : (pi univ S).Nonempty) :
theorem isBounded_pi : IsBounded (pi univ S) ↔ (∃ i, S i = ∅) ∨ ∀ i, IsBounded (S i) := by
by_cases hne : ∃ i, S i = ∅
· simp [hne, univ_pi_eq_empty_iff.2 hne]
- · simp only [hne, false_or_iff]
+ · simp only [hne, false_or]
simp only [not_exists, ← Ne.eq_def, ← nonempty_iff_ne_empty, ← univ_pi_nonempty_iff] at hne
exact isBounded_pi_of_nonempty hne
diff --git a/Mathlib/Topology/CWComplex.lean b/Mathlib/Topology/CWComplex.lean
new file mode 100644
index 0000000000000..8dae230580f73
--- /dev/null
+++ b/Mathlib/Topology/CWComplex.lean
@@ -0,0 +1,100 @@
+/-
+Copyright (c) 2024 Elliot Dean Young and Jiazhen Xia. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Jiazhen Xia, Elliot Dean Young
+-/
+import Mathlib.Topology.Category.TopCat.Limits.Basic
+import Mathlib.Topology.Category.TopCat.Sphere
+import Mathlib.CategoryTheory.Limits.Shapes.Products
+import Mathlib.CategoryTheory.Functor.OfSequence
+
+/-!
+# CW-complexes
+
+This file defines (relative) CW-complexes.
+
+## Main definitions
+
+* `RelativeCWComplex`: A relative CW-complex is the colimit of an expanding sequence of subspaces
+ `sk i` (called the $(i-1)$-skeleton) for `i ≥ 0`, where `sk 0` (i.e., the $(-1)$-skeleton) is an
+ arbitrary topological space, and each `sk (n + 1)` (i.e., the $n$-skeleton) is obtained from
+ `sk n` (i.e., the $(n-1)$-skeleton) by attaching `n`-disks.
+
+* `CWComplex`: A CW-complex is a relative CW-complex whose `sk 0` (i.e., $(-1)$-skeleton) is empty.
+
+## References
+
+* [R. Fritsch and R. Piccinini, *Cellular Structures in Topology*][fritsch-piccinini1990]
+* The definition of CW-complexes follows David Wärn's suggestion on
+ [Zulip](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Do.20we.20have.20CW.20complexes.3F/near/231769080).
+-/
+
+open CategoryTheory TopCat
+
+universe u
+
+namespace RelativeCWComplex
+
+/-- The inclusion map from the `n`-sphere to the `(n + 1)`-disk. (For `n = -1`, this
+involves the empty space `𝕊 (-1)`. This is the reason why `sphere` takes `n : ℤ` as
+an input rather than `n : ℕ`.) -/
+def sphereInclusion (n : ℤ) : 𝕊 n ⟶ 𝔻 (n + 1) where
+ toFun := fun ⟨p, hp⟩ ↦ ⟨p, le_of_eq hp⟩
+ continuous_toFun := ⟨fun t ⟨s, ⟨r, hro, hrs⟩, hst⟩ ↦ by
+ rw [isOpen_induced_iff, ← hst, ← hrs]
+ tauto⟩
+
+/-- A type witnessing that `X'` is obtained from `X` by attaching generalized cells `f : S ⟶ D` -/
+structure AttachGeneralizedCells {S D : TopCat.{u}} (f : S ⟶ D) (X X' : TopCat.{u}) where
+ /-- The index type over the generalized cells -/
+ cells : Type u
+ /-- An attaching map for each generalized cell -/
+ attachMaps : cells → (S ⟶ X)
+ /-- `X'` is the pushout of `∐ S ⟶ X` and `∐ S ⟶ ∐ D`. -/
+ iso_pushout : X' ≅ Limits.pushout (Limits.Sigma.desc attachMaps) (Limits.Sigma.map fun _ ↦ f)
+
+/-- A type witnessing that `X'` is obtained from `X` by attaching `(n + 1)`-disks -/
+def AttachCells (n : ℤ) := AttachGeneralizedCells (sphereInclusion n)
+
+end RelativeCWComplex
+
+/-- A relative CW-complex consists of an expanding sequence of subspaces `sk i` (called the
+$(i-1)$-skeleton) for `i ≥ 0`, where `sk 0` (i.e., the $(-1)$-skeleton) is an arbitrary topological
+space, and each `sk (n + 1)` (i.e., the `n`-skeleton) is obtained from `sk n` (i.e., the
+$(n-1)$-skeleton) by attaching `n`-disks. -/
+structure RelativeCWComplex where
+ /-- The skeletons. Note: `sk i` is usually called the $(i-1)$-skeleton in the math literature. -/
+ sk : ℕ → TopCat.{u}
+ /-- Each `sk (n + 1)` (i.e., the $n$-skeleton) is obtained from `sk n`
+ (i.e., the $(n-1)$-skeleton) by attaching `n`-disks. -/
+ attachCells (n : ℕ) : RelativeCWComplex.AttachCells ((n : ℤ) - 1) (sk n) (sk (n + 1))
+
+/-- A CW-complex is a relative CW-complex whose `sk 0` (i.e., $(-1)$-skeleton) is empty. -/
+structure CWComplex extends RelativeCWComplex.{u} where
+ /-- `sk 0` (i.e., the $(-1)$-skeleton) is empty. -/
+ isEmpty_sk_zero : IsEmpty (sk 0)
+
+namespace RelativeCWComplex
+
+noncomputable section Topology
+
+/-- The inclusion map from `X` to `X'`, when `X'` is obtained from `X`
+by attaching generalized cells `f : S ⟶ D`. -/
+def AttachGeneralizedCells.inclusion {S D : TopCat.{u}} {f : S ⟶ D} {X X' : TopCat.{u}}
+ (att : AttachGeneralizedCells f X X') : X ⟶ X' :=
+ Limits.pushout.inl _ _ ≫ att.iso_pushout.inv
+
+/-- The inclusion map from `sk n` (i.e., the $(n-1)$-skeleton) to `sk (n + 1)` (i.e., the
+$n$-skeleton) of a relative CW-complex -/
+def skInclusion (X : RelativeCWComplex.{u}) (n : ℕ) : X.sk n ⟶ X.sk (n + 1) :=
+ (X.attachCells n).inclusion
+
+/-- The topology on a relative CW-complex -/
+def toTopCat (X : RelativeCWComplex.{u}) : TopCat.{u} :=
+ Limits.colimit (Functor.ofSequence X.skInclusion)
+
+instance : Coe RelativeCWComplex TopCat where coe X := toTopCat X
+
+end Topology
+
+end RelativeCWComplex
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/EffectiveEpi.lean b/Mathlib/Topology/Category/CompHaus/EffectiveEpi.lean
index c6517bf9f086a..11338ba0c53d7 100644
--- a/Mathlib/Topology/Category/CompHaus/EffectiveEpi.lean
+++ b/Mathlib/Topology/Category/CompHaus/EffectiveEpi.lean
@@ -41,12 +41,9 @@ theorem effectiveEpi_tfae
, Epi π
, Function.Surjective π
] := by
- tfae_have 1 → 2
- · intro; infer_instance
- tfae_have 2 ↔ 3
- · exact epi_iff_surjective π
- tfae_have 3 → 1
- · exact fun hπ ↦ ⟨⟨effectiveEpiStruct π hπ⟩⟩
+ tfae_have 1 → 2 := fun _ ↦ inferInstance
+ tfae_have 2 ↔ 3 := epi_iff_surjective π
+ tfae_have 3 → 1 := fun hπ ↦ ⟨⟨effectiveEpiStruct π hπ⟩⟩
tfae_finish
instance : Preregular CompHaus :=
@@ -65,12 +62,12 @@ theorem effectiveEpiFamily_tfae
, ∀ b : B, ∃ (a : α) (x : X a), π a x = b
] := by
tfae_have 2 → 1
- · intro
+ | _ => by
simpa [← effectiveEpi_desc_iff_effectiveEpiFamily, (effectiveEpi_tfae (Sigma.desc π)).out 0 1]
tfae_have 1 → 2
- · intro; infer_instance
+ | _ => inferInstance
tfae_have 3 → 2
- · intro e
+ | e => by
rw [epi_iff_surjective]
intro b
obtain ⟨t, x, h⟩ := e b
@@ -78,7 +75,8 @@ theorem effectiveEpiFamily_tfae
change (Sigma.ι X t ≫ Sigma.desc π) x = _
simpa using h
tfae_have 2 → 3
- · intro e; rw [epi_iff_surjective] at e
+ | e => by
+ rw [epi_iff_surjective] at e
let i : ∐ X ≅ finiteCoproduct X :=
(colimit.isColimit _).coconePointUniqueUpToIso (finiteCoproduct.isColimit _)
intro b
diff --git a/Mathlib/Topology/Category/CompHaus/Projective.lean b/Mathlib/Topology/Category/CompHaus/Projective.lean
index 17bdb7ef5c926..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/Basic.lean b/Mathlib/Topology/Category/CompHausLike/Basic.lean
index 62495d9004dfa..ca9de369a082e 100644
--- a/Mathlib/Topology/Category/CompHausLike/Basic.lean
+++ b/Mathlib/Topology/Category/CompHausLike/Basic.lean
@@ -13,21 +13,21 @@ We construct the category of compact Hausdorff spaces satisfying an additional p
## Implementation
-We define a structure `CompHausLike` which takes as an argument a predicate `P` on topological
+We define a structure `CompHausLike` which takes as an argument a predicate `P` on topological
spaces. It consists of the data of a topological space, satisfying the additional properties of
being compact and Hausdorff, and satisfying `P`. We give a category structure to `CompHausLike P`
induced by the forgetful functor to topological spaces.
It used to be the case (before #12930 was merged) that several different categories of compact
Hausdorff spaces, possibly satisfying some extra property, were defined from scratch in this way.
-For example, one would define a structure `CompHaus` as follows:
+For example, one would define a structure `CompHaus` as follows:
```lean
structure CompHaus where
toTop : TopCat
[is_compact : CompactSpace toTop]
[is_hausdorff : T2Space toTop]
-```
+```
and give it the category structure induced from topological spaces. Then the category of profinite
spaces was defined as follows:
@@ -39,7 +39,7 @@ structure Profinite where
```
The categories `Stonean` consisting of extremally disconnected compact Hausdorff spaces and
-`LightProfinite` consisting of totally disconnected, second countable compact Hausdorff spaces were
+`LightProfinite` consisting of totally disconnected, second countable compact Hausdorff spaces were
defined in a similar way. This resulted in code duplication, and reducing this duplication was part
of the motivation for introducing `CompHausLike`.
@@ -52,11 +52,11 @@ Using `CompHausLike`, we can now define
These four categories are important building blocks of condensed objects (see the files
`Condensed.Basic` and `Condensed.Light.Basic`). These categories share many properties and often,
one wants to argue about several of them simultaneously. This is the other part of the motivation
-for introducing `CompHausLike`. On paper, one would say "let `C` be on of the categories `CompHaus`
+for introducing `CompHausLike`. On paper, one would say "let `C` be on of the categories `CompHaus`
or `Profinite`, then the following holds: ...". This was not possible in Lean using the old
definitions. Using the new definitions, this becomes a matter of identifying what common property
-of `CompHaus` and `Profinite` is used in the proof in question, and then proving the theorem for
-`CompHausLike P` satisfying that property, and it will automatically apply to both `CompHaus` and
+of `CompHaus` and `Profinite` is used in the proof in question, and then proving the theorem for
+`CompHausLike P` satisfying that property, and it will automatically apply to both `CompHaus` and
`Profinite`.
-/
@@ -255,4 +255,13 @@ def isoEquivHomeo {X Y : CompHausLike.{u} P} : (X ≅ Y) ≃ (X ≃ₜ Y) where
left_inv _ := rfl
right_inv _ := rfl
+/-- A constant map as a morphism in `CompHausLike` -/
+def const {P : TopCat.{u} → Prop}
+ (T : CompHausLike.{u} P) {S : CompHausLike.{u} P} (s : S) : T ⟶ S :=
+ ContinuousMap.const _ s
+
+lemma const_comp {P : TopCat.{u} → Prop} {S T U : CompHausLike.{u} P}
+ (s : S) (g : S ⟶ U) : T.const s ≫ g = T.const (g s) :=
+ rfl
+
end CompHausLike
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/CompHausLike/SigmaComparison.lean b/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean
index ae1412b6a3d0d..fc574ef66ea35 100644
--- a/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean
+++ b/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean
@@ -8,11 +8,11 @@ import Mathlib.Topology.Category.CompHausLike.Limits
# The sigma-comparison map
-This file defines the map `CompHausLike.sigmaComparison` associated to a presheaf `X` on
+This file defines the map `CompHausLike.sigmaComparison` associated to a presheaf `X` on
`CompHausLike P`, and a finite family `S₁,...,Sₙ` of spaces in `CompHausLike P`, where `P` is
stable under taking finite disjoint unions.
-The map `sigmaComparison` is the canonical map `X(S₁ ⊔ ... ⊔ Sₙ) ⟶ X(S₁) × ... × X(Sₙ)` induced by
+The map `sigmaComparison` is the canonical map `X(S₁ ⊔ ... ⊔ Sₙ) ⟶ X(S₁) × ... × X(Sₙ)` induced by
the inclusion maps `Sᵢ ⟶ S₁ ⊔ ... ⊔ Sₙ`, and it is an isomorphism when `X` preserves finite
products.
-/
@@ -38,10 +38,6 @@ values on the components.
def sigmaComparison : X.obj ⟨(of P ((a : α) × σ a))⟩ ⟶ ((a : α) → X.obj ⟨of P (σ a)⟩) :=
fun x a ↦ X.map ⟨Sigma.mk a, continuous_sigmaMk⟩ x
-noncomputable instance : PreservesLimitsOfShape (Discrete α) X :=
- letI : Fintype α := Fintype.ofFinite _
- preservesFiniteProductsOfPreservesBinaryAndTerminal X α
-
theorem sigmaComparison_eq_comp_isos : sigmaComparison X σ =
(X.mapIso (opCoproductIsoProduct'
(finiteCoproduct.isColimit.{u, u} (fun a ↦ of P (σ a)))
diff --git a/Mathlib/Topology/Category/Compactum.lean b/Mathlib/Topology/Category/Compactum.lean
index 7cd821aa6d9d6..d8ccb28743f15 100644
--- a/Mathlib/Topology/Category/Compactum.lean
+++ b/Mathlib/Topology/Category/Compactum.lean
@@ -211,7 +211,7 @@ private theorem cl_cl {X : Compactum} (A : Set X) : cl (cl A) ⊆ cl A := by
have claim1 : ∀ (B) (_ : B ∈ C0) (C) (_ : C ∈ C0), B ∩ C ∈ C0 := by
rintro B ⟨Q, hQ, rfl⟩ C ⟨R, hR, rfl⟩
use Q ∩ R
- simp only [and_true_iff, eq_self_iff_true, Set.preimage_inter]
+ simp only [and_true, eq_self_iff_true, Set.preimage_inter]
exact inter_sets _ hQ hR
-- All sets in C0 are nonempty.
have claim2 : ∀ B ∈ C0, Set.Nonempty B := by
@@ -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 40d42567504e8..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⟩
@@ -119,6 +119,11 @@ instance : FintypeCat.toLightProfinite.Faithful :=
instance : FintypeCat.toLightProfinite.Full :=
FintypeCat.toLightProfiniteFullyFaithful.full
+instance (X : FintypeCat.{u}) : Fintype (FintypeCat.toLightProfinite.obj X) :=
+ inferInstanceAs (Fintype X)
+
+instance (X : FintypeCat.{u}) : Fintype (LightProfinite.of X) := inferInstanceAs (Fintype X)
+
end DiscreteTopology
namespace LightProfinite
@@ -140,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
@@ -155,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
@@ -333,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/Extend.lean b/Mathlib/Topology/Category/LightProfinite/Extend.lean
index 55d6645661ad5..4f7e5eb315b90 100644
--- a/Mathlib/Topology/Category/LightProfinite/Extend.lean
+++ b/Mathlib/Topology/Category/LightProfinite/Extend.lean
@@ -10,9 +10,9 @@ import Mathlib.Topology.Category.Profinite.Extend
# Extending cones in `LightProfinite`
-Let `(Sₙ)_{n : ℕᵒᵖ}` be a sequential inverse system of finite sets and let `S` be
-its limit in `Profinite`. Let `G` be a functor from `LightProfinite` to a category `C` and suppose
-that `G` preserves the limit described above. Suppose further that the projection maps `S ⟶ Sₙ` are
+Let `(Sₙ)_{n : ℕᵒᵖ}` be a sequential inverse system of finite sets and let `S` be
+its limit in `Profinite`. Let `G` be a functor from `LightProfinite` to a category `C` and suppose
+that `G` preserves the limit described above. Suppose further that the projection maps `S ⟶ Sₙ` are
epimorphic for all `n`. Then `G.obj S` is isomorphic to a limit indexed by
`StructuredArrow S toLightProfinite` (see `LightProfinite.Extend.isLimitCone`).
@@ -21,7 +21,7 @@ We also provide the dual result for a functor of the form `G : LightProfiniteᵒ
We apply this to define `LightProfinite.diagram'`, `LightProfinite.asLimitCone'`, and
`LightProfinite.asLimit'`, analogues to their unprimed versions in
`Mathlib.Topology.Category.LightProfinite.AsLimit`, in which the
-indexing category is `StructuredArrow S toLightProfinite` instead of `ℕᵒᵖ`.
+indexing category is `StructuredArrow S toLightProfinite` instead of `ℕᵒᵖ`.
-/
universe u
@@ -37,7 +37,7 @@ variable {F : ℕᵒᵖ ⥤ FintypeCat.{u}} (c : Cone <| F ⋙ toLightProfinite)
namespace Extend
/--
-Given a sequential cone in `LightProfinite` consisting of finite sets,
+Given a sequential cone in `LightProfinite` consisting of finite sets,
we obtain a functor from the indexing category to `StructuredArrow c.pt toLightProfinite`.
-/
@[simps]
@@ -49,7 +49,7 @@ def functor : ℕᵒᵖ ⥤ StructuredArrow c.pt toLightProfinite where
example : functor c ⋙ StructuredArrow.proj c.pt toLightProfinite ≅ F := Iso.refl _
/--
-Given a sequential cone in `LightProfinite` consisting of finite sets,
+Given a sequential cone in `LightProfinite` consisting of finite sets,
we obtain a functor from the opposite of the indexing category to
`CostructuredArrow toProfinite.op ⟨c.pt⟩`.
-/
@@ -113,12 +113,12 @@ def cone (S : LightProfinite) :
example : G.mapCone c = (cone G c.pt).whisker (functor c) := rfl
/--
-If `c` and `G.mapCone c` are limit cones and the projection maps in `c` are epimorphic,
+If `c` and `G.mapCone c` are limit cones and the projection maps in `c` are epimorphic,
then `cone G c.pt` is a limit cone.
-/
noncomputable
def isLimitCone (hc : IsLimit c) [∀ i, Epi (c.π.app i)] (hc' : IsLimit <| G.mapCone c) :
- IsLimit (cone G c.pt) := (functor_initial c hc).isLimitWhiskerEquiv _ hc'
+ IsLimit (cone G c.pt) := (functor_initial c hc).isLimitWhiskerEquiv _ _ hc'
end Limit
@@ -158,7 +158,7 @@ noncomputable
def isColimitCocone (hc : IsLimit c) [∀ i, Epi (c.π.app i)] (hc' : IsColimit <| G.mapCocone c.op) :
IsColimit (cocone G c.pt) :=
haveI := functorOp_final c hc
- (Functor.final_comp (opOpEquivalence ℕ).functor (functorOp c)).isColimitWhiskerEquiv _ hc'
+ (Functor.final_comp (opOpEquivalence ℕ).functor (functorOp c)).isColimitWhiskerEquiv _ _ hc'
end Colimit
@@ -171,7 +171,7 @@ section LightProfiniteAsLimit
variable (S : LightProfinite.{u})
/--
-A functor `StructuredArrow S toLightProfinite ⥤ FintypeCat` whose limit in `LightProfinite` is
+A functor `StructuredArrow S toLightProfinite ⥤ FintypeCat` whose limit in `LightProfinite` is
isomorphic to `S`.
-/
abbrev fintypeDiagram' : StructuredArrow S toLightProfinite ⥤ FintypeCat :=
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 01e03d65b2389..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⟩
@@ -157,6 +157,10 @@ instance : FintypeCat.toProfinite.Faithful := FintypeCat.toProfiniteFullyFaithfu
instance : FintypeCat.toProfinite.Full := FintypeCat.toProfiniteFullyFaithful.full
+instance (X : FintypeCat) : Fintype (FintypeCat.toProfinite.obj X) := inferInstanceAs (Fintype X)
+
+instance (X : FintypeCat) : Fintype (Profinite.of X) := inferInstanceAs (Fintype X)
+
end DiscreteTopology
end Profinite
@@ -185,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 :=
@@ -250,4 +254,7 @@ theorem epi_iff_surjective {X Y : Profinite.{u}} (f : X ⟶ Y) : Epi f ↔ Funct
· rw [← CategoryTheory.epi_iff_surjective]
apply (forget Profinite).epi_of_epi_map
+/-- The pi-type of profinite spaces is profinite. -/
+def pi {α : Type u} (β : α → Profinite) : Profinite := .of (Π (a : α), β a)
+
end Profinite
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/EffectiveEpi.lean b/Mathlib/Topology/Category/Profinite/EffectiveEpi.lean
index 251da0eb75003..f6a2c77737320 100644
--- a/Mathlib/Topology/Category/Profinite/EffectiveEpi.lean
+++ b/Mathlib/Topology/Category/Profinite/EffectiveEpi.lean
@@ -37,12 +37,9 @@ theorem effectiveEpi_tfae
, Epi π
, Function.Surjective π
] := by
- tfae_have 1 → 2
- · intro; infer_instance
- tfae_have 2 ↔ 3
- · exact epi_iff_surjective π
- tfae_have 3 → 1
- · exact fun hπ ↦ ⟨⟨CompHausLike.effectiveEpiStruct π hπ⟩⟩
+ tfae_have 1 → 2 := fun _ ↦ inferInstance
+ tfae_have 2 ↔ 3 := epi_iff_surjective π
+ tfae_have 3 → 1 := fun hπ ↦ ⟨⟨CompHausLike.effectiveEpiStruct π hπ⟩⟩
tfae_finish
instance : profiniteToCompHaus.PreservesEffectiveEpis where
@@ -80,12 +77,11 @@ theorem effectiveEpiFamily_tfae
, ∀ b : B, ∃ (a : α) (x : X a), π a x = b
] := by
tfae_have 2 → 1
- · intro
+ | _ => by
simpa [← effectiveEpi_desc_iff_effectiveEpiFamily, (effectiveEpi_tfae (Sigma.desc π)).out 0 1]
- tfae_have 1 → 2
- · intro; infer_instance
- tfae_have 3 ↔ 1
- · erw [((CompHaus.effectiveEpiFamily_tfae
+ tfae_have 1 → 2 := fun _ ↦ inferInstance
+ tfae_have 3 ↔ 1 := by
+ erw [((CompHaus.effectiveEpiFamily_tfae
(fun a ↦ profiniteToCompHaus.obj (X a)) (fun a ↦ profiniteToCompHaus.map (π a))).out 2 0 : )]
exact ⟨fun h ↦ profiniteToCompHaus.finite_effectiveEpiFamily_of_map _ _ h,
fun _ ↦ inferInstance⟩
diff --git a/Mathlib/Topology/Category/Profinite/Extend.lean b/Mathlib/Topology/Category/Profinite/Extend.lean
index 1ac168134b484..bbdcf1c6b88fc 100644
--- a/Mathlib/Topology/Category/Profinite/Extend.lean
+++ b/Mathlib/Topology/Category/Profinite/Extend.lean
@@ -10,9 +10,9 @@ import Mathlib.CategoryTheory.Filtered.Final
# Extending cones in `Profinite`
-Let `(Sᵢ)_{i : I}` be a family of finite sets indexed by a cofiltered category `I` and let `S` be
-its limit in `Profinite`. Let `G` be a functor from `Profinite` to a category `C` and suppose that
-`G` preserves the limit described above. Suppose further that the projection maps `S ⟶ Sᵢ` are
+Let `(Sᵢ)_{i : I}` be a family of finite sets indexed by a cofiltered category `I` and let `S` be
+its limit in `Profinite`. Let `G` be a functor from `Profinite` to a category `C` and suppose that
+`G` preserves the limit described above. Suppose further that the projection maps `S ⟶ Sᵢ` are
epimorphic for all `i`. Then `G.obj S` is isomorphic to a limit indexed by
`StructuredArrow S toProfinite` (see `Profinite.Extend.isLimitCone`).
@@ -20,7 +20,7 @@ We also provide the dual result for a functor of the form `G : Profiniteᵒᵖ
We apply this to define `Profinite.diagram'`, `Profinite.asLimitCone'`, and `Profinite.asLimit'`,
analogues to their unprimed versions in `Mathlib.Topology.Category.Profinite.AsLimit`, in which the
-indexing category is `StructuredArrow S toProfinite` instead of `DiscreteQuotient S`.
+indexing category is `StructuredArrow S toProfinite` instead of `DiscreteQuotient S`.
-/
universe u w
@@ -52,7 +52,7 @@ lemma exists_hom (hc : IsLimit c) {X : FintypeCat} (f : c.pt ⟶ toProfinite.obj
namespace Extend
/--
-Given a cone in `Profinite`, consisting of finite sets and indexed by a cofiltered category,
+Given a cone in `Profinite`, consisting of finite sets and indexed by a cofiltered category,
we obtain a functor from the indexing category to `StructuredArrow c.pt toProfinite`.
-/
@[simps]
@@ -64,7 +64,7 @@ def functor : I ⥤ StructuredArrow c.pt toProfinite where
example : functor c ⋙ StructuredArrow.proj c.pt toProfinite ≅ F := Iso.refl _
/--
-Given a cone in `Profinite`, consisting of finite sets and indexed by a cofiltered category,
+Given a cone in `Profinite`, consisting of finite sets and indexed by a cofiltered category,
we obtain a functor from the opposite of the indexing category to
`CostructuredArrow toProfinite.op ⟨c.pt⟩`.
-/
@@ -126,22 +126,17 @@ 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
/--
-If `c` and `G.mapCone c` are limit cones and the projection maps in `c` are epimorphic,
+If `c` and `G.mapCone c` are limit cones and the projection maps in `c` are epimorphic,
then `cone G c.pt` is a limit cone.
-/
noncomputable
def isLimitCone (hc : IsLimit c) [∀ i, Epi (c.π.app i)] (hc' : IsLimit <| G.mapCone c) :
- IsLimit (cone G c.pt) := (functor_initial c hc).isLimitWhiskerEquiv _ hc'
+ IsLimit (cone G c.pt) := (functor_initial c hc).isLimitWhiskerEquiv _ _ hc'
end Limit
@@ -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
@@ -177,7 +171,7 @@ are epimorphic, then `cocone G c.pt` is a colimit cone.
-/
noncomputable
def isColimitCocone (hc : IsLimit c) [∀ i, Epi (c.π.app i)] (hc' : IsColimit <| G.mapCocone c.op) :
- IsColimit (cocone G c.pt) := (functorOp_final c hc).isColimitWhiskerEquiv _ hc'
+ IsColimit (cocone G c.pt) := (functorOp_final c hc).isColimitWhiskerEquiv _ _ hc'
end Colimit
@@ -190,7 +184,7 @@ section ProfiniteAsLimit
variable (S : Profinite.{u})
/--
-A functor `StructuredArrow S toProfinite ⥤ FintypeCat` whose limit in `Profinite` is isomorphic
+A functor `StructuredArrow S toProfinite ⥤ FintypeCat` whose limit in `Profinite` is isomorphic
to `S`.
-/
abbrev fintypeDiagram' : StructuredArrow S toProfinite ⥤ FintypeCat :=
diff --git a/Mathlib/Topology/Category/Profinite/Nobeling.lean b/Mathlib/Topology/Category/Profinite/Nobeling.lean
index b666e7f0d9593..d4b021e2620d3 100644
--- a/Mathlib/Topology/Category/Profinite/Nobeling.lean
+++ b/Mathlib/Topology/Category/Profinite/Nobeling.lean
@@ -412,7 +412,7 @@ theorem evalFacProps {l : Products I} (J K : I → Prop)
have : l.eval (π C J) ∘ Homeomorph.setCongr (proj_eq_of_subset C J K hJK) =
l.eval (π (π C K) J) := by
ext; simp [Homeomorph.setCongr, Products.eval_eq]
- rw [ProjRestricts, ← Function.comp.assoc, this, ← evalFacProp (π C K) J h]
+ rw [ProjRestricts, ← Function.comp_assoc, this, ← evalFacProp (π C K) J h]
theorem prop_of_isGood {l : Products I} (J : I → Prop) [∀ j, Decidable (J j)]
(h : l.isGood (π C J)) : ∀ a, a ∈ l.val → J a := by
@@ -1043,7 +1043,7 @@ theorem smaller_mono {o₁ o₂ : Ordinal} (h : o₁ ≤ o₂) : smaller C o₁
ext x
rw [eval, ← Products.eval_πs' _ h (Products.prop_of_isGood C _ gl), eval]
· rw [← LocallyConstant.coe_inj, coe_πs C o₂, ← LocallyConstant.toFun_eq_coe, coe_πs',
- Function.comp.assoc, projRestricts_comp_projRestrict C _, coe_πs]
+ Function.comp_assoc, projRestricts_comp_projRestrict C _, coe_πs]
rfl
end GoodProducts
@@ -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 becda45ececde..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/EffectiveEpi.lean b/Mathlib/Topology/Category/Stonean/EffectiveEpi.lean
index ff4d234dae338..1901963fcc1a9 100644
--- a/Mathlib/Topology/Category/Stonean/EffectiveEpi.lean
+++ b/Mathlib/Topology/Category/Stonean/EffectiveEpi.lean
@@ -36,12 +36,9 @@ theorem effectiveEpi_tfae
, Epi π
, Function.Surjective π
] := by
- tfae_have 1 → 2
- · intro; infer_instance
- tfae_have 2 ↔ 3
- · exact epi_iff_surjective π
- tfae_have 3 → 1
- · exact fun hπ ↦ ⟨⟨effectiveEpiStruct π hπ⟩⟩
+ tfae_have 1 → 2 := fun _ ↦ inferInstance
+ tfae_have 2 ↔ 3 := epi_iff_surjective π
+ tfae_have 3 → 1 := fun hπ ↦ ⟨⟨effectiveEpiStruct π hπ⟩⟩
tfae_finish
instance : Stonean.toCompHaus.PreservesEffectiveEpis where
@@ -81,12 +78,11 @@ theorem effectiveEpiFamily_tfae
, ∀ b : B, ∃ (a : α) (x : X a), π a x = b
] := by
tfae_have 2 → 1
- · intro
+ | _ => by
simpa [← effectiveEpi_desc_iff_effectiveEpiFamily, (effectiveEpi_tfae (Sigma.desc π)).out 0 1]
- tfae_have 1 → 2
- · intro; infer_instance
- tfae_have 3 ↔ 1
- · erw [((CompHaus.effectiveEpiFamily_tfae
+ tfae_have 1 → 2 := fun _ ↦ inferInstance
+ tfae_have 3 ↔ 1 := by
+ erw [((CompHaus.effectiveEpiFamily_tfae
(fun a ↦ Stonean.toCompHaus.obj (X a)) (fun a ↦ Stonean.toCompHaus.map (π a))).out 2 0 : )]
exact ⟨fun h ↦ Stonean.toCompHaus.finite_effectiveEpiFamily_of_map _ _ h,
fun _ ↦ inferInstance⟩
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 db65a15d38f8a..52f1591638bd4 100644
--- a/Mathlib/Topology/Category/TopCat/Adjunctions.lean
+++ b/Mathlib/Topology/Category/TopCat/Adjunctions.lean
@@ -1,5 +1,5 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Patrick Massot, Mario Carneiro
-/
@@ -26,18 +26,16 @@ namespace TopCat
/-- Equipping a type with the discrete topology is left adjoint to the forgetful functor
`Top ⥤ Type`. -/
@[simps! unit counit]
-def adj₁ : discrete ⊣ forget TopCat.{u} :=
- Adjunction.mkOfUnitCounit
- { unit := { app := fun X => id }
- counit := { app := fun X => ⟨id, continuous_bot⟩ } }
+def adj₁ : discrete ⊣ forget TopCat.{u} where
+ 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 :=
- Adjunction.mkOfUnitCounit
- { unit := { app := fun X => ⟨id, continuous_top⟩ }
- counit := { app := fun X => id } }
+def adj₂ : forget TopCat.{u} ⊣ trivial where
+ 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 5d001338b22c2..87760f303fc0e 100644
--- a/Mathlib/Topology/Category/TopCat/Basic.lean
+++ b/Mathlib/Topology/Category/TopCat/Basic.lean
@@ -1,10 +1,10 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Scott Morrison, Mario Carneiro
+Authors: Patrick Massot, Kim Morrison, Mario Carneiro
-/
import Mathlib.CategoryTheory.ConcreteCategory.BundledHom
-import Mathlib.Topology.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Basic
/-!
# Category instance for topological spaces
@@ -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 5510c9abcf4ae..75c863468db2e 100644
--- a/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean
+++ b/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean
@@ -4,13 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Dagur Asgeirsson
-/
import Mathlib.CategoryTheory.EffectiveEpi.RegularEpi
-import Mathlib.CategoryTheory.EffectiveEpi.Comp
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.
-/
@@ -23,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
@@ -46,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
@@ -60,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)
@@ -74,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 2c9ab0122ae91..e7833bab71d89 100644
--- a/Mathlib/Topology/Category/TopCat/Limits/Basic.lean
+++ b/Mathlib/Topology/Category/TopCat/Limits/Basic.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Scott Morrison, Mario Carneiro, Andrew Yang
+Authors: Patrick Massot, Kim Morrison, Mario Carneiro, Andrew Yang
-/
import Mathlib.Topology.Category.TopCat.Basic
import Mathlib.CategoryTheory.Limits.Types
@@ -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
@@ -184,7 +184,7 @@ instance forgetPreservesColimits : PreservesColimits (forget : TopCat.{u} ⥤ Ty
/-- The terminal object of `Top` is `PUnit`. -/
def isTerminalPUnit : IsTerminal (TopCat.of PUnit.{u + 1}) :=
haveI : ∀ X, Unique (X ⟶ TopCat.of PUnit.{u + 1}) := fun X =>
- ⟨⟨⟨fun _ => PUnit.unit, by continuity⟩⟩, fun f => by ext; aesop⟩
+ ⟨⟨⟨fun _ => PUnit.unit, continuous_const⟩⟩, fun f => by ext; aesop⟩
Limits.IsTerminal.ofUnique _
/-- The terminal object of `Top` is `PUnit`. -/
diff --git a/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean b/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean
index a6ef38a679ede..f0d717923cbaa 100644
--- a/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean
+++ b/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Scott Morrison, Mario Carneiro, Andrew Yang
+Authors: Patrick Massot, Kim Morrison, Mario Carneiro, Andrew Yang
-/
import Mathlib.Topology.Category.TopCat.Limits.Basic
import Mathlib.CategoryTheory.Filtered.Basic
@@ -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/Konig.lean b/Mathlib/Topology/Category/TopCat/Limits/Konig.lean
index a8ca567c55146..0d6f7501547f2 100644
--- a/Mathlib/Topology/Category/TopCat/Limits/Konig.lean
+++ b/Mathlib/Topology/Category/TopCat/Limits/Konig.lean
@@ -133,8 +133,8 @@ theorem nonempty_limitCone_of_compact_t2_cofiltered_system (F : J ⥤ TopCat.{ma
intro X Y f
let G : FiniteDiagram J :=
⟨{X, Y},
- {⟨X, Y, by simp only [true_or_iff, eq_self_iff_true, Finset.mem_insert], by
- simp only [eq_self_iff_true, or_true_iff, Finset.mem_insert, Finset.mem_singleton], f⟩}⟩
+ {⟨X, Y, by simp only [true_or, eq_self_iff_true, Finset.mem_insert], by
+ simp only [eq_self_iff_true, or_true, Finset.mem_insert, Finset.mem_singleton], f⟩}⟩
exact hu _ ⟨G, rfl⟩ (Finset.mem_singleton_self _)
end TopologicalKonig
diff --git a/Mathlib/Topology/Category/TopCat/Limits/Products.lean b/Mathlib/Topology/Category/TopCat/Limits/Products.lean
index 20ee2f8395a8d..7036388381771 100644
--- a/Mathlib/Topology/Category/TopCat/Limits/Products.lean
+++ b/Mathlib/Topology/Category/TopCat/Limits/Products.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Scott Morrison, Mario Carneiro, Andrew Yang
+Authors: Patrick Massot, Kim Morrison, Mario Carneiro, Andrew Yang
-/
import Mathlib.Topology.Category.TopCat.EpiMono
import Mathlib.Topology.Category.TopCat.Limits.Basic
@@ -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 80e0708f53c5a..8c8900dc78066 100644
--- a/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean
+++ b/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2017 Scott Morrison. All rights reserved.
+Copyright (c) 2017 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Scott Morrison, Mario Carneiro, Andrew Yang
+Authors: Patrick Massot, Kim Morrison, Mario Carneiro, Andrew Yang
-/
import Mathlib.Topology.Category.TopCat.Limits.Products
@@ -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 cbdaf939b871a..fdfe88f737c64 100644
--- a/Mathlib/Topology/Category/TopCat/OpenNhds.lean
+++ b/Mathlib/Topology/Category/TopCat/OpenNhds.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Topology.Category.TopCat.Opens
import Mathlib.Data.Set.Subsingleton
@@ -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
@@ -144,9 +147,8 @@ def functorNhds (h : IsOpenMap f) (x : X) : OpenNhds x ⥤ OpenNhds (f x) where
map i := h.functor.map i
/-- 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 :=
- Adjunction.mkOfUnitCounit
- { unit := { app := fun U => homOfLE fun x hxU => ⟨x, hxU, rfl⟩ }
- counit := { app := fun V => homOfLE fun y ⟨_, hfxV, hxy⟩ => hxy ▸ hfxV } }
+def adjunctionNhds (h : IsOpenMap f) (x : X) : IsOpenMap.functorNhds h x ⊣ OpenNhds.map f x where
+ 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 1c695024dcbd1..bbb4a6f5369a9 100644
--- a/Mathlib/Topology/Category/TopCat/Opens.lean
+++ b/Mathlib/Topology/Category/TopCat/Opens.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Category.Preorder
import Mathlib.CategoryTheory.EqToHom
@@ -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) :=
@@ -280,10 +281,9 @@ def IsOpenMap.functor {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenMap f) : Opens X
/-- An open map `f : X ⟶ Y` induces an adjunction between `Opens X` and `Opens Y`.
-/
def IsOpenMap.adjunction {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenMap f) :
- Adjunction hf.functor (TopologicalSpace.Opens.map f) :=
- Adjunction.mkOfUnitCounit
- { unit := { app := fun U => homOfLE fun x hxU => ⟨x, hxU, rfl⟩ }
- counit := { app := fun V => homOfLE fun y ⟨_, hfxV, hxy⟩ => hxy ▸ hfxV } }
+ Adjunction hf.functor (TopologicalSpace.Opens.map f) where
+ 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
@@ -295,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
@@ -316,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
@@ -336,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/Sphere.lean b/Mathlib/Topology/Category/TopCat/Sphere.lean
new file mode 100644
index 0000000000000..b8f23e34fc643
--- /dev/null
+++ b/Mathlib/Topology/Category/TopCat/Sphere.lean
@@ -0,0 +1,39 @@
+/-
+Copyright (c) 2024 Elliot Dean Young and Jiazhen Xia. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Jiazhen Xia, Elliot Dean Young
+-/
+
+import Mathlib.Analysis.InnerProductSpace.PiL2
+import Mathlib.Topology.Category.TopCat.Basic
+
+/-!
+# Euclidean spheres
+
+This files defines the `n`-sphere `𝕊 n` and the `n`-disk `𝔻` as objects in `TopCat`.
+The parameter `n` is in `ℤ` so as to facilitate the definition of
+CW-complexes (see the file `Topology.CWComplex`).
+
+-/
+
+universe u
+
+namespace TopCat
+
+/-- The `n`-sphere is the set of points in ℝⁿ⁺¹ whose norm equals `1`,
+endowed with the subspace topology. -/
+noncomputable def sphere (n : ℤ) : TopCat.{u} :=
+ TopCat.of <| ULift <| Metric.sphere (0 : EuclideanSpace ℝ <| Fin <| (n + 1).toNat) 1
+
+/-- The `n`-disk is the set of points in ℝⁿ whose norm is at most `1`,
+endowed with the subspace topology. -/
+noncomputable def disk (n : ℤ) : TopCat.{u} :=
+ TopCat.of <| ULift <| Metric.closedBall (0 : EuclideanSpace ℝ <| Fin <| n.toNat) 1
+
+/-- `𝕊 n` denotes the `n`-sphere. -/
+scoped prefix:arg "𝕊 " => sphere
+
+/-- `𝔻 n` denotes the `n`-disk. -/
+scoped prefix:arg "𝔻 " => disk
+
+end TopCat
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 153f2b41ff795..d8e2fce858d9a 100644
--- a/Mathlib/Topology/Category/TopCommRingCat.lean
+++ b/Mathlib/Topology/Category/TopCommRingCat.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.Ring.Basic
import Mathlib.Topology.Category.TopCat.Basic
@@ -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 ebeee9ca6766e..dc6f68256827c 100644
--- a/Mathlib/Topology/Category/UniformSpace.lean
+++ b/Mathlib/Topology/Category/UniformSpace.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Reid Barton, Patrick Massot, Scott Morrison
+Authors: Reid Barton, Patrick Massot, Kim Morrison
-/
import Mathlib.CategoryTheory.Adjunction.Reflective
import Mathlib.CategoryTheory.ConcreteCategory.UnbundledHom
@@ -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 99e06e4f3aa34..82c9d0719beea 100644
--- a/Mathlib/Topology/CompactOpen.lean
+++ b/Mathlib/Topology/CompactOpen.lean
@@ -3,7 +3,8 @@ 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.ContinuousFunction.Basic
+import Mathlib.Topology.Hom.ContinuousEval
+import Mathlib.Topology.ContinuousMap.Basic
/-!
# The compact-open topology
@@ -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,29 +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
-@[deprecated (since := "2023-12-26")] alias continuous_eval' := continuous_eval
+@[deprecated (since := "2024-10-01")] protected alias continuous_eval := continuous_eval
-/-- Evaluation of a continuous map `f` at a point `x` is continuous in `f`.
+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
-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
+@[deprecated (since := "2024-10-01")] protected alias continuous_eval_const := continuous_eval_const
-/-- Coercion from `C(X, Y)` with compact-open topology to `X → Y` with pointwise convergence
-topology is a continuous map.
-
-Porting note: merged `continuous_coe` with `continuous_coe'` removing unneeded assumptions. -/
+@[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} :=
@@ -194,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)
@@ -204,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
@@ -212,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
@@ -238,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)) ≤
@@ -262,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]
@@ -344,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) :=
@@ -376,7 +403,7 @@ theorem continuous_curry [LocallyCompactSpace (X × Y)] :
/-- The uncurried form of a continuous map `X → C(Y, Z)` is a continuous map `X × Y → Z`. -/
theorem continuous_uncurry_of_continuous [LocallyCompactSpace Y] (f : C(X, C(Y, Z))) :
Continuous (Function.uncurry fun x y => f x y) :=
- continuous_eval.comp <| f.continuous.prod_map continuous_id
+ continuous_eval.comp <| f.continuous.prodMap continuous_id
/-- The uncurried form of a continuous map `X → C(Y, Z)` as a continuous map `X × Y → Z` (if `Y` is
locally compact). If `X` is also locally compact, then this is a homeomorphism between the two
@@ -390,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.prod_map 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)) :=
@@ -444,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
@@ -462,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 0201f2ccbee78..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
@@ -426,16 +440,19 @@ theorem denseRange_coe [NoncompactSpace X] : DenseRange ((↑) : X → OnePoint
rw [DenseRange, ← compl_infty]
exact dense_compl_singleton _
-theorem denseEmbedding_coe [NoncompactSpace X] : DenseEmbedding ((↑) : X → OnePoint X) :=
- { openEmbedding_coe with dense := denseRange_coe }
+theorem isDenseEmbedding_coe [NoncompactSpace X] : IsDenseEmbedding ((↑) : X → OnePoint X) :=
+ { 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)
@@ -507,7 +524,7 @@ example [WeaklyLocallyCompactSpace X] [T2Space X] : T4Space (OnePoint X) := infe
/-- If `X` is not a compact space, then `OnePoint X` is a connected space. -/
instance [PreconnectedSpace X] [NoncompactSpace X] : ConnectedSpace (OnePoint X) where
- toPreconnectedSpace := denseEmbedding_coe.toDenseInducing.preconnectedSpace
+ toPreconnectedSpace := isDenseEmbedding_coe.toIsDenseInducing.preconnectedSpace
toNonempty := inferInstance
/-- If `X` is an infinite type with discrete topology (e.g., `ℕ`), then the identity map from
@@ -535,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 1a468a8d2b236..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,18 +222,18 @@ 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⟩ :=
hs.elim_directed_cover (compl ∘ t) (fun i => (htc i).isOpen_compl)
(by
simpa only [subset_def, not_forall, eq_empty_iff_forall_not_mem, mem_iUnion, exists_prop,
- mem_inter_iff, not_and, iff_self_iff, mem_iInter, mem_compl_iff] using hst)
+ mem_inter_iff, not_and, mem_iInter, mem_compl_iff] using hst)
(hdt.mono_comp _ fun _ _ => compl_subset_compl.mpr)
⟨t, by
simpa only [subset_def, not_forall, eq_empty_iff_forall_not_mem, mem_iUnion, exists_prop,
- mem_inter_iff, not_and, iff_self_iff, mem_iInter, mem_compl_iff] using ht⟩
+ mem_inter_iff, not_and, mem_iInter, mem_compl_iff] using ht⟩
-- Porting note (#11215): TODO: reformulate using `Disjoint`
/-- For every family of closed sets whose intersection avoids a compact set,
@@ -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)
@@ -301,7 +301,7 @@ theorem IsCompact.nonempty_iInter_of_sequence_nonempty_isCompact_isClosed (t :
(htcl : ∀ i, IsClosed (t i)) : (⋂ i, t i).Nonempty :=
have tmono : Antitone t := antitone_nat_of_succ_le htd
have htd : Directed (· ⊇ ·) t := tmono.directed_ge
- have : ∀ i, t i ⊆ t 0 := fun i => tmono <| zero_le i
+ have : ∀ i, t i ⊆ t 0 := fun i => tmono <| Nat.zero_le i
have htc : ∀ i, IsCompact (t i) := fun i => ht0.of_isClosed_subset (htcl i) (this i)
IsCompact.nonempty_iInter_of_directed_nonempty_isCompact_isClosed t htd htn htc htcl
@@ -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/Exterior.lean b/Mathlib/Topology/Compactness/Exterior.lean
new file mode 100644
index 0000000000000..986fcfe09e456
--- /dev/null
+++ b/Mathlib/Topology/Compactness/Exterior.lean
@@ -0,0 +1,30 @@
+/-
+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.Tactic.Peel
+import Mathlib.Topology.Compactness.Compact
+import Mathlib.Topology.Exterior
+
+/-!
+# Compactness of the exterior of a set
+
+In this file we prove that the exterior of a set
+(defined as the intersection of all of its neighborhoods)
+is a compact set if and only if the original set is a compact set.
+-/
+
+variable {X : Type*} [TopologicalSpace X] {s : Set X}
+
+theorem IsCompact.exterior_iff : IsCompact (exterior s) ↔ IsCompact s := by
+ simp only [isCompact_iff_finite_subcover]
+ peel with ι U hUo
+ simp only [(isOpen_iUnion hUo).exterior_subset,
+ (isOpen_iUnion fun i ↦ isOpen_iUnion fun _ ↦ hUo i).exterior_subset]
+
+protected alias ⟨IsCompact.of_exterior, IsCompact.exterior⟩ := IsCompact.exterior_iff
+
+@[deprecated IsCompact.exterior (since := "2024-09-18")]
+lemma Set.Finite.isCompact_exterior (hs : s.Finite) : IsCompact (exterior s) :=
+ hs.isCompact.exterior
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 1881270210e57..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. -/
@@ -76,9 +86,6 @@ theorem LocallyCompactSpace.of_hasBasis {ι : X → Type*} {p : ∀ x, ι x →
let ⟨i, hp, ht⟩ := (h x).mem_iff.1 ht
⟨s x i, (h x).mem_of_mem hp, ht, hc x i hp⟩⟩
-@[deprecated (since := "2023-12-29")]
-alias locallyCompactSpace_of_hasBasis := LocallyCompactSpace.of_hasBasis
-
instance Prod.locallyCompactSpace (X : Type*) (Y : Type*) [TopologicalSpace X]
[TopologicalSpace Y] [LocallyCompactSpace X] [LocallyCompactSpace Y] :
LocallyCompactSpace (X × Y) :=
@@ -169,28 +176,53 @@ 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⟩
-protected theorem ClosedEmbedding.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y}
- (hf : ClosedEmbedding f) : LocallyCompactSpace X :=
- haveI : ∀ x : X, (𝓝 x).HasBasis (fun s => s ∈ 𝓝 (f x) ∧ IsCompact s) (f ⁻¹' ·) := fun x ↦ by
- rw [hf.toInducing.nhds_eq_comap]
- exact (compact_basis_nhds _).comap _
- .of_hasBasis this fun x s hs => hf.isCompact_preimage hs.2
+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 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
+ have H : U ∈ 𝓝 (f x) := hU.mem_nhds (hUZ.subset <| mem_range_self _).1
+ rw [hf.nhds_eq_comap, ← comap_nhdsWithin_range, hUZ,
+ nhdsWithin_inter_of_mem (nhdsWithin_le_nhds H)]
+ exact (nhdsWithin_hasBasis ((compact_basis_nhds (f x)).restrict_subset H) _).comap _
+ refine .of_hasBasis this fun x s ⟨⟨_, hs⟩, hsU⟩ ↦ ?_
+ rw [hf.isCompact_preimage_iff]
+ exacts [hs.inter_right hZ, hUZ ▸ by gcongr]
+
+@[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
+
+@[deprecated (since := "2024-10-18")]
+alias OpenEmbedding.locallyCompactSpace := IsOpenEmbedding.locallyCompactSpace
+
+protected theorem IsLocallyClosed.locallyCompactSpace [LocallyCompactSpace X] {s : Set X}
+ (hs : IsLocallyClosed s) : LocallyCompactSpace s :=
+ IsEmbedding.subtypeVal.locallyCompactSpace <| by rwa [Subtype.range_val]
protected theorem IsClosed.locallyCompactSpace [LocallyCompactSpace X] {s : Set X}
(hs : IsClosed s) : LocallyCompactSpace s :=
- (closedEmbedding_subtype_val hs).locallyCompactSpace
-
-protected theorem OpenEmbedding.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y}
- (hf : OpenEmbedding f) : LocallyCompactSpace X := by
- have : ∀ x : X,
- (𝓝 x).HasBasis (fun s ↦ (s ∈ 𝓝 (f x) ∧ IsCompact s) ∧ s ⊆ range f) (f ⁻¹' ·) := fun x ↦ by
- rw [hf.nhds_eq_comap]
- exact ((compact_basis_nhds _).restrict_subset <| hf.isOpen_range.mem_nhds <|
- mem_range_self _).comap _
- refine .of_hasBasis this fun x s hs => ?_
- rw [hf.toInducing.isCompact_iff, image_preimage_eq_of_subset hs.2]
- exact hs.1.2
+ hs.isLocallyClosed.locallyCompactSpace
protected theorem IsOpen.locallyCompactSpace [LocallyCompactSpace X] {s : Set X} (hs : IsOpen s) :
LocallyCompactSpace s :=
- hs.openEmbedding_subtype_val.locallyCompactSpace
+ hs.isLocallyClosed.locallyCompactSpace
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 8d8d2a542f23d..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) :=
@@ -506,7 +509,7 @@ theorem isConnected_connectedComponent {x : α} : IsConnected (connectedComponen
theorem isConnected_connectedComponentIn_iff {x : α} {F : Set α} :
IsConnected (connectedComponentIn F x) ↔ x ∈ F := by
simp_rw [← connectedComponentIn_nonempty_iff, IsConnected, isPreconnected_connectedComponentIn,
- and_true_iff]
+ and_true]
theorem IsPreconnected.subset_connectedComponent {x : α} {s : Set α} (H1 : IsPreconnected s)
(H2 : x ∈ s) : s ⊆ connectedComponent x := fun _z hz => mem_sUnion_of_mem hz ⟨H1, H2⟩
@@ -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 1cad1a9499c1e..7db33a85e7b36 100644
--- a/Mathlib/Topology/Connected/PathConnected.lean
+++ b/Mathlib/Topology/Connected/PathConnected.lean
@@ -75,8 +75,8 @@ structure Path (x y : X) extends C(I, X) where
target' : toFun 1 = y
instance Path.funLike : FunLike (Path x y) I X where
- coe := fun γ ↦ ⇑γ.toContinuousMap
- coe_injective' := fun γ₁ γ₂ h => by
+ coe γ := ⇑γ.toContinuousMap
+ coe_injective' γ₁ γ₂ h := by
simp only [DFunLike.coe_fn_eq] at h
cases γ₁; cases γ₂; congr
@@ -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)).prod_map 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 :=
@@ -423,17 +417,17 @@ theorem cast_coe (γ : Path x y) {x' y'} (hx : x' = x) (hy : y' = y) : (γ.cast
theorem symm_continuous_family {ι : Type*} [TopologicalSpace ι]
{a b : ι → X} (γ : ∀ t : ι, Path (a t) (b t)) (h : Continuous ↿γ) :
Continuous ↿fun t => (γ t).symm :=
- h.comp (continuous_id.prod_map continuous_symm)
+ h.comp (continuous_id.prodMap continuous_symm)
@[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 ι]
{a b : ι → X} (γ : ∀ t : ι, Path (a t) (b t)) (h : Continuous ↿γ) :
Continuous ↿fun t => (γ t).extend := by
- apply h.comp (continuous_id.prod_map continuous_projIcc)
+ apply h.comp (continuous_id.prodMap continuous_projIcc)
exact zero_le_one
@[continuity]
@@ -447,12 +441,12 @@ theorem trans_continuous_family {ι : Type*} [TopologicalSpace ι]
refine Continuous.if_le ?_ ?_ (continuous_subtype_val.comp continuous_snd) continuous_const ?_
· change
Continuous ((fun p : ι × ℝ => (γ₁ p.1).extend p.2) ∘ Prod.map id (fun x => 2 * x : I → ℝ))
- exact h₁'.comp (continuous_id.prod_map <| continuous_const.mul continuous_subtype_val)
+ exact h₁'.comp (continuous_id.prodMap <| continuous_const.mul continuous_subtype_val)
· change
Continuous ((fun p : ι × ℝ => (γ₂ p.1).extend p.2) ∘ Prod.map id (fun x => 2 * x - 1 : I → ℝ))
exact
h₂'.comp
- (continuous_id.prod_map <|
+ (continuous_id.prodMap <|
(continuous_const.mul continuous_subtype_val).sub continuous_const)
· rintro st hst
simp [hst, mul_inv_cancel₀ (two_ne_zero' ℝ)]
@@ -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 d688f53c39586..4544c981222a1 100644
--- a/Mathlib/Topology/Constructions.lean
+++ b/Mathlib/Topology/Constructions.lean
@@ -3,9 +3,10 @@ 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.Data.Finset.Piecewise
+import Mathlib.Order.Filter.Curry
import Mathlib.Topology.Maps.Basic
import Mathlib.Topology.NhdsSet
-import Mathlib.Order.Filter.Curry
/-!
# Constructions of new topological spaces from old ones
@@ -399,10 +400,12 @@ theorem Continuous.comp₄ {g : X × Y × Z × ζ → ε} (hg : Continuous g) {e
hg.comp₃ he hf <| hk.prod_mk hl
@[continuity]
-theorem Continuous.prod_map {f : Z → X} {g : W → Y} (hf : Continuous f) (hg : Continuous g) :
- Continuous fun p : Z × W => (f p.1, g p.2) :=
+theorem Continuous.prodMap {f : Z → X} {g : W → Y} (hf : Continuous f) (hg : Continuous g) :
+ Continuous (Prod.map f g) :=
hf.fst'.prod_mk hg.snd'
+@[deprecated (since := "2024-10-05")] alias Continuous.prod_map := Continuous.prodMap
+
/-- A version of `continuous_inf_dom_left` for binary functions -/
theorem continuous_inf_dom_left₂ {X Y Z} {f : X → Y → Z} {ta1 ta2 : TopologicalSpace X}
{tb1 tb2 : TopologicalSpace Y} {tc1 : TopologicalSpace Z}
@@ -410,7 +413,7 @@ theorem continuous_inf_dom_left₂ {X Y Z} {f : X → Y → Z} {ta1 ta2 : Topolo
haveI := ta1 ⊓ ta2; haveI := tb1 ⊓ tb2; exact Continuous fun p : X × Y => f p.1 p.2 := by
have ha := @continuous_inf_dom_left _ _ id ta1 ta2 ta1 (@continuous_id _ (id _))
have hb := @continuous_inf_dom_left _ _ id tb1 tb2 tb1 (@continuous_id _ (id _))
- have h_continuous_id := @Continuous.prod_map _ _ _ _ ta1 tb1 (ta1 ⊓ ta2) (tb1 ⊓ tb2) _ _ ha hb
+ have h_continuous_id := @Continuous.prodMap _ _ _ _ ta1 tb1 (ta1 ⊓ ta2) (tb1 ⊓ tb2) _ _ ha hb
exact @Continuous.comp _ _ _ (id _) (id _) _ _ _ h h_continuous_id
/-- A version of `continuous_inf_dom_right` for binary functions -/
@@ -420,7 +423,7 @@ theorem continuous_inf_dom_right₂ {X Y Z} {f : X → Y → Z} {ta1 ta2 : Topol
haveI := ta1 ⊓ ta2; haveI := tb1 ⊓ tb2; exact Continuous fun p : X × Y => f p.1 p.2 := by
have ha := @continuous_inf_dom_right _ _ id ta1 ta2 ta2 (@continuous_id _ (id _))
have hb := @continuous_inf_dom_right _ _ id tb1 tb2 tb2 (@continuous_id _ (id _))
- have h_continuous_id := @Continuous.prod_map _ _ _ _ ta2 tb2 (ta1 ⊓ ta2) (tb1 ⊓ tb2) _ _ ha hb
+ have h_continuous_id := @Continuous.prodMap _ _ _ _ ta2 tb2 (ta1 ⊓ ta2) (tb1 ⊓ tb2) _ _ ha hb
exact @Continuous.comp _ _ _ (id _) (id _) _ _ _ h h_continuous_id
/-- A version of `continuous_sInf_dom` for binary functions -/
@@ -432,7 +435,7 @@ theorem continuous_sInf_dom₂ {X Y Z} {f : X → Y → Z} {tas : Set (Topologic
exact @Continuous _ _ _ tc fun p : X × Y => f p.1 p.2 := by
have hX := continuous_sInf_dom hX continuous_id
have hY := continuous_sInf_dom hY continuous_id
- have h_continuous_id := @Continuous.prod_map _ _ _ _ tX tY (sInf tas) (sInf tbs) _ _ hX hY
+ have h_continuous_id := @Continuous.prodMap _ _ _ _ tX tY (sInf tas) (sInf tbs) _ _ hX hY
exact @Continuous.comp _ _ _ (id _) (id _) _ _ _ hf h_continuous_id
theorem Filter.Eventually.prod_inl_nhds {p : X → Prop} {x : X} (h : ∀ᶠ x in 𝓝 x, p x) (y : Y) :
@@ -581,13 +584,19 @@ theorem ContinuousAt.prod {f : X → Y} {g : X → Z} {x : X} (hf : ContinuousAt
(hg : ContinuousAt g x) : ContinuousAt (fun x => (f x, g x)) x :=
hf.prod_mk_nhds hg
-theorem ContinuousAt.prod_map {f : X → Z} {g : Y → W} {p : X × Y} (hf : ContinuousAt f p.fst)
- (hg : ContinuousAt g p.snd) : ContinuousAt (fun p : X × Y => (f p.1, g p.2)) p :=
+theorem ContinuousAt.prodMap {f : X → Z} {g : Y → W} {p : X × Y} (hf : ContinuousAt f p.fst)
+ (hg : ContinuousAt g p.snd) : ContinuousAt (Prod.map f g) p :=
hf.fst''.prod hg.snd''
-theorem ContinuousAt.prod_map' {f : X → Z} {g : Y → W} {x : X} {y : Y} (hf : ContinuousAt f x)
- (hg : ContinuousAt g y) : ContinuousAt (fun p : X × Y => (f p.1, g p.2)) (x, y) :=
- hf.fst'.prod hg.snd'
+@[deprecated (since := "2024-10-05")] alias ContinuousAt.prod_map := ContinuousAt.prodMap
+
+/-- A version of `ContinuousAt.prodMap` that avoids `Prod.fst`/`Prod.snd`
+by assuming that the point is `(x, y)`. -/
+theorem ContinuousAt.prodMap' {f : X → Z} {g : Y → W} {x : X} {y : Y} (hf : ContinuousAt f x)
+ (hg : ContinuousAt g y) : ContinuousAt (Prod.map f g) (x, y) :=
+ hf.prodMap hg
+
+@[deprecated (since := "2024-10-05")] alias ContinuousAt.prod_map' := ContinuousAt.prodMap'
theorem ContinuousAt.comp₂ {f : Y × Z → W} {g : X → Y} {h : X → Z} {x : X}
(hf : ContinuousAt f (g x, h x)) (hg : ContinuousAt g x) (hh : ContinuousAt h x) :
@@ -619,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))
@@ -647,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⟩)
@@ -727,14 +736,20 @@ theorem isOpen_prod_iff' {s : Set X} {t : Set Y} :
rw [← snd_image_prod st.1 t]
exact isOpenMap_snd _ H
· intro H
- simp only [st.1.ne_empty, st.2.ne_empty, not_false_iff, or_false_iff] at H
+ 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
+
+@[deprecated (since := "2024-10-22")]
+alias quotientMap_fst := isQuotientMap_fst
-theorem quotientMap_snd [Nonempty X] : QuotientMap (Prod.snd : X × Y → Y) :=
- isOpenMap_snd.to_quotientMap continuous_snd Prod.snd_surjective
+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
@@ -775,46 +790,80 @@ theorem Dense.prod {s : Set X} {t : Set Y} (hs : Dense s) (ht : Dense t) : Dense
exact ⟨hs x.1, ht x.2⟩
/-- If `f` and `g` are maps with dense range, then `Prod.map f g` has dense range. -/
-theorem DenseRange.prod_map {ι : Type*} {κ : Type*} {f : ι → Y} {g : κ → Z} (hf : DenseRange f)
+theorem DenseRange.prodMap {ι : Type*} {κ : Type*} {f : ι → Y} {g : κ → Z} (hf : DenseRange f)
(hg : DenseRange g) : DenseRange (Prod.map f g) := by
simpa only [DenseRange, prod_range_range_eq] using hf.prod hg
-theorem Inducing.prod_map {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,
+@[deprecated (since := "2024-10-05")] alias DenseRange.prod_map := DenseRange.prodMap
+
+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-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.prod_map {f : X → Y} {g : Z → W} (hf : Embedding f) (hg : Embedding g) :
- Embedding (Prod.map f g) :=
- { hf.toInducing.prod_map 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
-protected theorem IsOpenMap.prod {f : X → Y} {g : Z → W} (hf : IsOpenMap f) (hg : IsOpenMap g) :
- IsOpenMap fun p : X × Z => (f p.1, g p.2) := by
+@[deprecated (since := "2024-10-26")]
+alias Embedding.prodMap := IsEmbedding.prodMap
+
+@[deprecated (since := "2024-10-05")] alias Embedding.prod_map := Embedding.prodMap
+
+protected theorem IsOpenMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenMap f) (hg : IsOpenMap g) :
+ IsOpenMap (Prod.map f g) := by
rw [isOpenMap_iff_nhds_le]
rintro ⟨a, b⟩
- rw [nhds_prod_eq, nhds_prod_eq, ← Filter.prod_map_map_eq]
+ rw [nhds_prod_eq, nhds_prod_eq, ← Filter.prod_map_map_eq']
exact Filter.prod_mono (hf.nhds_le a) (hg.nhds_le b)
-protected theorem OpenEmbedding.prod {f : X → Y} {g : Z → W} (hf : OpenEmbedding f)
- (hg : OpenEmbedding g) : OpenEmbedding fun x : X × Z => (f x.1, g x.2) :=
- openEmbedding_of_embedding_open (hf.1.prod_map hg.1) (hf.isOpenMap.prod hg.isOpenMap)
+@[deprecated (since := "2024-10-05")] alias IsOpenMap.prod := IsOpenMap.prodMap
+
+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
-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
+@[deprecated (since := "2024-10-05")] alias IsOpenEmbedding.prod := IsOpenEmbedding.prodMap
-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
+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-26")]
+alias embedding_graph := isEmbedding_graph
+
+lemma isEmbedding_prodMk (x : X) : IsEmbedding (Prod.mk x : Y → X × Y) :=
+ .of_comp (Continuous.Prod.mk x) continuous_snd .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) :=
+ ⟨.prodMap hf.1 hg.1, .prodMap hf.2 hg.2, .prodMap hf.3 hg.3⟩
end Prod
@@ -857,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]
@@ -881,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]
@@ -907,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 isClosedEmbedding_inr : IsClosedEmbedding (inr : Y → X ⊕ Y) :=
+ ⟨.inr, isClosed_range_inr⟩
-theorem closedEmbedding_inr : ClosedEmbedding (inr : Y → X ⊕ Y) :=
- ⟨embedding_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) :
@@ -951,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)
@@ -962,20 +1021,29 @@ end Sum
section Subtype
-variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] {p : X → Prop}
+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⟩
-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
+@[deprecated (since := "2024-10-28")] alias inducing_subtype_val := IsInducing.subtypeVal
-theorem embedding_subtype_val : Embedding ((↑) : Subtype p → X) :=
- ⟨inducing_subtype_val, Subtype.coe_injective⟩
+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 closedEmbedding_subtype_val (h : IsClosed { a | p a }) :
- ClosedEmbedding ((↑) : Subtype p → X) :=
- ⟨embedding_subtype_val, by rwa [Subtype.range_coe_subtype]⟩
+@[deprecated (since := "2024-10-28")] alias Inducing.of_codRestrict := IsInducing.of_codRestrict
+
+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) :=
@@ -985,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)) :
@@ -1021,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 :=
@@ -1045,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
@@ -1072,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
-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
+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_inclusion {s t : Set X} (h : s ⊆ t) : Embedding (inclusion h) :=
- embedding_subtype_val.codRestrict _ _
+@[deprecated (since := "2024-10-26")]
+alias Embedding.codRestrict := IsEmbedding.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. -/
@@ -1099,30 +1180,43 @@ 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
-variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z]
+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
@@ -1132,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
@@ -1143,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
@@ -1225,10 +1322,44 @@ lemma Pi.induced_precomp [TopologicalSpace Y] {ι' : Type*} (φ : ι' → ι) :
⨅ i', induced (eval (φ i')) ‹TopologicalSpace Y› :=
induced_precomp' φ
+@[continuity, fun_prop]
lemma Pi.continuous_restrict (S : Set ι) :
Continuous (S.restrict : (∀ i : ι, π i) → (∀ i : S, π i)) :=
Pi.continuous_precomp' ((↑) : S → ι)
+@[continuity, fun_prop]
+lemma Pi.continuous_restrict₂ {s t : Set ι} (hst : s ⊆ t) : Continuous (restrict₂ (π := π) hst) :=
+ continuous_pi fun _ ↦ continuous_apply _
+
+@[continuity, fun_prop]
+theorem Finset.continuous_restrict (s : Finset ι) : Continuous (s.restrict (π := π)) :=
+ continuous_pi fun _ ↦ continuous_apply _
+
+@[continuity, fun_prop]
+theorem Finset.continuous_restrict₂ {s t : Finset ι} (hst : s ⊆ t) :
+ Continuous (Finset.restrict₂ (π := π) hst) :=
+ continuous_pi fun _ ↦ continuous_apply _
+
+variable [TopologicalSpace Z]
+
+@[continuity, fun_prop]
+theorem Pi.continuous_restrict_apply (s : Set X) {f : X → Z} (hf : Continuous f) :
+ Continuous (s.restrict f) := hf.comp continuous_subtype_val
+
+@[continuity, fun_prop]
+theorem Pi.continuous_restrict₂_apply {s t : Set X} (hst : s ⊆ t)
+ {f : t → Z} (hf : Continuous f) :
+ Continuous (restrict₂ (π := fun _ ↦ Z) hst f) := hf.comp (continuous_inclusion hst)
+
+@[continuity, fun_prop]
+theorem Finset.continuous_restrict_apply (s : Finset X) {f : X → Z} (hf : Continuous f) :
+ Continuous (s.restrict f) := hf.comp continuous_subtype_val
+
+@[continuity, fun_prop]
+theorem Finset.continuous_restrict₂_apply {s t : Finset X} (hst : s ⊆ t)
+ {f : t → Z} (hf : Continuous f) :
+ Continuous (restrict₂ (π := fun _ ↦ Z) hst f) := hf.comp (continuous_inclusion hst)
+
lemma Pi.induced_restrict (S : Set ι) :
induced (S.restrict) Pi.topologicalSpace =
⨅ i ∈ S, induced (eval i) (T i) := by
@@ -1379,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
@@ -1411,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)]
@@ -1466,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₂]
@@ -1510,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
@@ -1525,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)) :
@@ -1538,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]
+
+@[deprecated (since := "2024-10-28")] alias inducing_sigma_map := isInducing_sigmaMap
-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]
+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 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]
+@[deprecated (since := "2024-10-26")]
+alias embedding_sigma_map := isEmbedding_sigmaMap
-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,
+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
@@ -1574,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
@@ -1603,8 +1759,8 @@ theorem IsClosed.trans (ht : IsClosed t) (hs : IsClosed s) : IsClosed (t : Set X
end Monad
section NhdsSet
-variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] {f : Filter X}
- {s : Set X} {t : Set Y} {x : X}
+variable [TopologicalSpace X] [TopologicalSpace Y]
+ {s : Set X} {t : Set Y}
/-- The product of a neighborhood of `s` and a neighborhood of `t` is a neighborhood of `s ×ˢ t`,
formulated in terms of a filter inequality. -/
@@ -1626,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/ContinuousFunction/Algebra.lean b/Mathlib/Topology/ContinuousMap/Algebra.lean
similarity index 93%
rename from Mathlib/Topology/ContinuousFunction/Algebra.lean
rename to Mathlib/Topology/ContinuousMap/Algebra.lean
index c3143c043f066..c8e869fee7be1 100644
--- a/Mathlib/Topology/ContinuousFunction/Algebra.lean
+++ b/Mathlib/Topology/ContinuousMap/Algebra.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Nicolò Cavalleri
+Authors: Kim Morrison, Nicolò Cavalleri
-/
import Mathlib.Algebra.Algebra.Pi
import Mathlib.Algebra.Order.Group.Lattice
@@ -13,8 +13,7 @@ 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.ContinuousFunction.Ordered
+import Mathlib.Topology.ContinuousMap.Ordered
import Mathlib.Topology.UniformSpace.CompactConvergence
/-!
@@ -295,9 +294,9 @@ instance [LocallyCompactSpace α] [Mul β] [ContinuousMul β] : ContinuousMul C(
⟨by
refine continuous_of_continuous_uncurry _ ?_
have h1 : Continuous fun x : (C(α, β) × C(α, β)) × α => x.fst.fst x.snd :=
- continuous_eval.comp (continuous_fst.prod_map continuous_id)
+ continuous_eval.comp (continuous_fst.prodMap continuous_id)
have h2 : Continuous fun x : (C(α, β) × C(α, β)) × α => x.fst.snd x.snd :=
- continuous_eval.comp (continuous_snd.prod_map continuous_id)
+ continuous_eval.comp (continuous_snd.prodMap continuous_id)
exact h1.mul h2⟩
/-- Coercion to a function as a `MonoidHom`. Similar to `MonoidHom.coeFn`. -/
@@ -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
@@ -550,7 +551,7 @@ instance [LocallyCompactSpace α] [TopologicalSpace R] [SMul R M] [ContinuousSMu
⟨by
refine continuous_of_continuous_uncurry _ ?_
have h : Continuous fun x : (R × C(α, M)) × α => x.fst.snd x.snd :=
- continuous_eval.comp (continuous_snd.prod_map continuous_id)
+ continuous_eval.comp (continuous_snd.prodMap continuous_id)
exact (continuous_fst.comp continuous_fst).smul h⟩
@[to_additive (attr := simp, norm_cast)]
@@ -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/ContinuousFunction/Basic.lean b/Mathlib/Topology/ContinuousMap/Basic.lean
similarity index 74%
rename from Mathlib/Topology/ContinuousFunction/Basic.lean
rename to Mathlib/Topology/ContinuousMap/Basic.lean
index e77f01dabfc8e..852cf38dfab8f 100644
--- a/Mathlib/Topology/ContinuousFunction/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*) [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
@@ -271,8 +172,6 @@ def prodMk (f : C(α, β₁)) (g : C(α, β₂)) : C(α, β₁ × β₂) where
@[simps]
def prodMap (f : C(α₁, α₂)) (g : C(β₁, β₂)) : C(α₁ × β₁, α₂ × β₂) where
toFun := Prod.map f g
- continuous_toFun := f.continuous.prod_map g.continuous
- -- Porting note: proof was `continuity`
@[simp]
theorem prod_eval (f : C(α, β₁)) (g : C(α, β₂)) (a : α) : (prodMk f g) a = (f a, g a) :=
@@ -380,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
@@ -404,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}
@@ -463,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'
@@ -484,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]
@@ -494,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
@@ -509,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
@@ -520,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
@@ -529,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/ContinuousFunction/Bounded.lean b/Mathlib/Topology/ContinuousMap/Bounded.lean
similarity index 95%
rename from Mathlib/Topology/ContinuousFunction/Bounded.lean
rename to Mathlib/Topology/ContinuousMap/Bounded.lean
index 3c61e9ba6a02d..037cf9103630a 100644
--- a/Mathlib/Topology/ContinuousFunction/Bounded.lean
+++ b/Mathlib/Topology/ContinuousMap/Bounded.lean
@@ -4,12 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel, Mario Carneiro, Yury Kudryashov, Heather Macbeth
-/
import Mathlib.Algebra.Module.MinimalAxioms
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.Topology.ContinuousMap.Algebra
import Mathlib.Analysis.Normed.Order.Lattice
import Mathlib.Analysis.NormedSpace.OperatorNorm.Basic
import Mathlib.Analysis.CStarAlgebra.Basic
-import Mathlib.Analysis.Normed.Operator.ContinuousLinearMap
import Mathlib.Topology.Bornology.BoundedOperation
+import Mathlib.Tactic.Monotonicity
/-!
# Bounded continuous functions
@@ -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 `UniformEmbedding`
-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 [uniformEmbedding_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/BoundedCompactlySupported.lean b/Mathlib/Topology/ContinuousMap/BoundedCompactlySupported.lean
new file mode 100644
index 0000000000000..ff7efe16ef944
--- /dev/null
+++ b/Mathlib/Topology/ContinuousMap/BoundedCompactlySupported.lean
@@ -0,0 +1,104 @@
+/-
+Copyright (c) 2024 Yoh Tanimoto. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Yoh Tanimoto
+-/
+import Mathlib.Topology.ContinuousMap.Bounded
+import Mathlib.RingTheory.TwoSidedIdeal.Lattice
+
+/-!
+# Compactly supported bounded continuous functions
+
+The two-sided ideal of compactly supported bounded continuous functions taking values in a metric
+space, with the uniform distance.
+-/
+
+open Set BoundedContinuousFunction
+
+section CompactlySupported
+
+/-- The two-sided ideal of compactly supported functions. -/
+def compactlySupported (α γ : Type*) [TopologicalSpace α] [NonUnitalNormedRing γ] :
+ TwoSidedIdeal (α →ᵇ γ) :=
+ .mk' {z | HasCompactSupport z} .zero .add .neg' .mul_left .mul_right
+
+variable {α γ : Type*} [TopologicalSpace α] [NonUnitalNormedRing γ]
+
+@[inherit_doc]
+scoped[BoundedContinuousFunction] notation
+ "C_cb(" α ", " γ ")" => compactlySupported α γ
+
+lemma mem_compactlySupported {f : α →ᵇ γ} :
+ f ∈ C_cb(α, γ) ↔ HasCompactSupport f :=
+ TwoSidedIdeal.mem_mk' {z : α →ᵇ γ | HasCompactSupport z} .zero .add .neg' .mul_left .mul_right f
+
+lemma exist_norm_eq [c : Nonempty α] {f : α →ᵇ γ} (h : f ∈ C_cb(α, γ)) : ∃ (x : α),
+ ‖f x‖ = ‖f‖ := by
+ by_cases hs : (tsupport f).Nonempty
+ · obtain ⟨x, _, hmax⟩ := mem_compactlySupported.mp h |>.exists_isMaxOn hs <|
+ (map_continuous f).norm.continuousOn
+ refine ⟨x, le_antisymm (norm_coe_le_norm f x) (norm_le (norm_nonneg _) |>.mpr fun y ↦ ?_)⟩
+ by_cases hy : y ∈ tsupport f
+ · exact hmax hy
+ · simp [image_eq_zero_of_nmem_tsupport hy]
+ · suffices f = 0 by simp [this]
+ rwa [not_nonempty_iff_eq_empty, tsupport_eq_empty_iff, ← coe_zero, ← DFunLike.ext'_iff] at hs
+
+theorem norm_lt_iff_of_compactlySupported {f : α →ᵇ γ} (h : f ∈ C_cb(α, γ)) {M : ℝ}
+ (M0 : 0 < M) : ‖f‖ < M ↔ ∀ (x : α), ‖f x‖ < M := by
+ refine ⟨fun hn x ↦ lt_of_le_of_lt (norm_coe_le_norm f x) hn, ?_⟩
+ · obtain (he | he) := isEmpty_or_nonempty α
+ · simpa
+ · obtain ⟨x, hx⟩ := exist_norm_eq h
+ exact fun h ↦ hx ▸ h x
+
+theorem norm_lt_iff_of_nonempty_compactlySupported [c : Nonempty α] {f : α →ᵇ γ}
+ (h : f ∈ C_cb(α, γ)) {M : ℝ} : ‖f‖ < M ↔ ∀ (x : α), ‖f x‖ < M := by
+ obtain (hM | hM) := lt_or_le 0 M
+ · exact norm_lt_iff_of_compactlySupported h hM
+ · exact ⟨fun h ↦ False.elim <| (h.trans_le hM).not_le (by positivity),
+ fun h ↦ False.elim <| (h (Classical.arbitrary α) |>.trans_le hM).not_le (by positivity)⟩
+
+theorem compactlySupported_eq_top_of_isCompact (h : IsCompact (Set.univ : Set α)) :
+ C_cb(α, γ) = ⊤ :=
+ eq_top_iff.mpr fun _ _ ↦ h.of_isClosed_subset (isClosed_tsupport _) (subset_univ _)
+
+/- This is intentionally not marked `@[simp]` to prevent Lean looking for a `CompactSpace α`
+instance every time it sees `C_cb(α, γ)`. -/
+theorem compactlySupported_eq_top [CompactSpace α] : C_cb(α, γ) = ⊤ :=
+ compactlySupported_eq_top_of_isCompact CompactSpace.isCompact_univ
+
+theorem compactlySupported_eq_top_iff [Nontrivial γ] :
+ C_cb(α, γ) = ⊤ ↔ IsCompact (Set.univ : Set α) := by
+ refine ⟨fun h ↦ ?_, compactlySupported_eq_top_of_isCompact⟩
+ obtain ⟨x, hx⟩ := exists_ne (0 : γ)
+ simpa [tsupport, Function.support_const hx]
+ using (mem_compactlySupported (f := const α x).mp (by simp [h])).isCompact
+
+/-- A compactly supported continuous function is automatically bounded. This constructor gives
+an object of `α →ᵇ γ` from `g : α → γ` and these assumptions. -/
+def ofCompactSupport (g : α → γ) (hg₁ : Continuous g) (hg₂ : HasCompactSupport g) : α →ᵇ γ where
+ toFun := g
+ continuous_toFun := hg₁
+ map_bounded' := by
+ obtain (hs | hs) := (tsupport g).eq_empty_or_nonempty
+ · exact ⟨0, by simp [tsupport_eq_empty_iff.mp hs]⟩
+ · obtain ⟨z, _, hmax⟩ := hg₂.exists_isMaxOn hs <| hg₁.norm.continuousOn
+ refine ⟨2 * ‖g z‖, dist_le_two_norm' fun x ↦ ?_⟩
+ by_cases hx : x ∈ tsupport g
+ · exact isMaxOn_iff.mp hmax x hx
+ · simp [image_eq_zero_of_nmem_tsupport hx]
+
+lemma ofCompactSupport_mem (g : α → γ) (hg₁ : Continuous g) (hg₂ : HasCompactSupport g) :
+ ofCompactSupport g hg₁ hg₂ ∈ C_cb(α, γ) := mem_compactlySupported.mpr hg₂
+
+instance : SMul C(α, γ) C_cb(α, γ) where
+ smul := fun (g : C(α, γ)) => (fun (f : C_cb(α, γ)) =>
+ ⟨ofCompactSupport (g * (f : α →ᵇ γ) : α → γ) (Continuous.mul g.2 f.1.1.2)
+ (HasCompactSupport.mul_left (mem_compactlySupported.mp f.2)), by
+ apply mem_compactlySupported.mpr
+ rw [ofCompactSupport]
+ exact HasCompactSupport.mul_left <| mem_compactlySupported.mp f.2
+ ⟩)
+
+end CompactlySupported
diff --git a/Mathlib/Topology/ContinuousFunction/CocompactMap.lean b/Mathlib/Topology/ContinuousMap/CocompactMap.lean
similarity index 99%
rename from Mathlib/Topology/ContinuousFunction/CocompactMap.lean
rename to Mathlib/Topology/ContinuousMap/CocompactMap.lean
index 8794fe4397f20..d5662c0299843 100644
--- a/Mathlib/Topology/ContinuousFunction/CocompactMap.lean
+++ b/Mathlib/Topology/ContinuousMap/CocompactMap.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.Topology.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Basic
/-!
# Cocompact continuous maps
diff --git a/Mathlib/Topology/ContinuousFunction/Compact.lean b/Mathlib/Topology/ContinuousMap/Compact.lean
similarity index 78%
rename from Mathlib/Topology/ContinuousFunction/Compact.lean
rename to Mathlib/Topology/ContinuousMap/Compact.lean
index 114876977a04d..9400fa18c4860 100644
--- a/Mathlib/Topology/ContinuousFunction/Compact.lean
+++ b/Mathlib/Topology/ContinuousMap/Compact.lean
@@ -1,9 +1,9 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
-import Mathlib.Topology.ContinuousFunction.Bounded
+import Mathlib.Topology.ContinuousMap.Bounded
import Mathlib.Topology.UniformSpace.Compact
import Mathlib.Topology.CompactOpen
import Mathlib.Topology.Sets.Compacts
@@ -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,15 @@ 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)))⟩⟩)
-theorem uniformEmbedding_equivBoundedOfCompact : UniformEmbedding (equivBoundedOfCompact α β) :=
- { uniformInducing_equivBoundedOfCompact α β with inj := (equivBoundedOfCompact α β).injective }
+@[deprecated (since := "2024-10-05")]
+alias uniformInducing_equivBoundedOfCompact := isUniformInducing_equivBoundedOfCompact
+
+theorem isUniformEmbedding_equivBoundedOfCompact : IsUniformEmbedding (equivBoundedOfCompact α β) :=
+ { isUniformInducing_equivBoundedOfCompact α β with
+ inj := (equivBoundedOfCompact α β).injective }
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_equivBoundedOfCompact := isUniformEmbedding_equivBoundedOfCompact
/-- When `α` is compact, the bounded continuous maps `α →ᵇ 𝕜` are
additively equivalent to `C(α, 𝕜)`.
@@ -82,8 +89,13 @@ theorem addEquivBoundedOfCompact_apply [AddMonoid β] [LipschitzAdd β] :
⇑(addEquivBoundedOfCompact α β) = mkOfCompact :=
rfl
-instance metricSpace : MetricSpace C(α, β) :=
- (uniformEmbedding_equivBoundedOfCompact α β).comapMetricSpace _
+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(α, β)`.
@@ -133,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!
@@ -150,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]
@@ -215,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 : NormedRing C(α, R) :=
- { (inferInstance : NormedAddCommGroup C(α, R)), ContinuousMap.instRing with
- norm_mul := fun 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 [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
@@ -228,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
@@ -243,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}
@@ -287,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 }
@@ -301,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.
@@ -335,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
@@ -365,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
@@ -422,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]
@@ -457,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) :=
@@ -473,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/ContinuousFunction/CompactlySupported.lean b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean
similarity index 97%
rename from Mathlib/Topology/ContinuousFunction/CompactlySupported.lean
rename to Mathlib/Topology/ContinuousMap/CompactlySupported.lean
index d8d72123235af..cb59956edbce0 100644
--- a/Mathlib/Topology/ContinuousFunction/CompactlySupported.lean
+++ b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean
@@ -3,8 +3,8 @@ Copyright (c) 2024 Yoh Tanimoto. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yoh Tanimoto
-/
-import Mathlib.Topology.ContinuousFunction.CocompactMap
-import Mathlib.Topology.ContinuousFunction.ZeroAtInfty
+import Mathlib.Topology.ContinuousMap.CocompactMap
+import Mathlib.Topology.ContinuousMap.ZeroAtInfty
import Mathlib.Topology.Support
/-!
@@ -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/ContinuousFunction/ContinuousMapZero.lean b/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean
similarity index 80%
rename from Mathlib/Topology/ContinuousFunction/ContinuousMapZero.lean
rename to Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean
index a0e26115b77b1..ddcc9bd155c7c 100644
--- a/Mathlib/Topology/ContinuousFunction/ContinuousMapZero.lean
+++ b/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean
@@ -3,8 +3,8 @@ 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.ContinuousFunction.Algebra
-import Mathlib.Topology.ContinuousFunction.Compact
+import Mathlib.Topology.ContinuousMap.Algebra
+import Mathlib.Topology.ContinuousMap.Compact
/-!
# Continuous maps sending zero to zero
@@ -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]
@@ -268,35 +284,41 @@ variable [Zero R] [UniformSpace R]
protected instance instUniformSpace : UniformSpace C(X, R)₀ := .comap toContinuousMap inferInstance
-lemma uniformEmbedding_toContinuousMap :
- UniformEmbedding ((↑) : C(X, R)₀ → C(X, R)) where
+lemma isUniformEmbedding_toContinuousMap :
+ IsUniformEmbedding ((↑) : C(X, R)₀ → C(X, R)) where
comap_uniformity := rfl
inj _ _ h := ext fun x ↦ congr($(h) x)
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_toContinuousMap := isUniformEmbedding_toContinuousMap
+
instance [T1Space R] [CompleteSpace C(X, R)] : CompleteSpace C(X, R)₀ :=
- completeSpace_iff_isComplete_range uniformEmbedding_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)₀) :=
+ isUniformEmbedding_toContinuousMap.of_comp_iff.mp <|
+ ContinuousMap.isUniformEmbedding_comp g.toContinuousMap hg |>.comp
+ isUniformEmbedding_toContinuousMap
-lemma uniformEmbedding_comp {Y : Type*} [UniformSpace Y] [Zero Y] (g : C(Y, R)₀)
- (hg : UniformEmbedding g) : UniformEmbedding (g.comp · : C(X, Y)₀ → C(X, R)₀) :=
- uniformEmbedding_toContinuousMap.of_comp_iff.mp <|
- ContinuousMap.uniformEmbedding_comp g.toContinuousMap hg |>.comp
- uniformEmbedding_toContinuousMap
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_comp := isUniformEmbedding_comp
/-- The uniform equivalence `C(X, R)₀ ≃ᵤ C(Y, R)₀` induced by a homeomorphism of the domains
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 := uniformEmbedding_toContinuousMap.uniformContinuous_iff.mpr <|
- ContinuousMap.uniformContinuous_comp_left f.symm.toContinuousMap |>.comp
- uniformEmbedding_toContinuousMap.uniformContinuous
- uniformContinuous_invFun := uniformEmbedding_toContinuousMap.uniformContinuous_iff.mpr <|
- ContinuousMap.uniformContinuous_comp_left f.toContinuousMap |>.comp
- uniformEmbedding_toContinuousMap.uniformContinuous
+ uniformContinuous_toFun := isUniformEmbedding_toContinuousMap.uniformContinuous_iff.mpr <|
+ 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 : C(X, Y)) |>.comp
+ isUniformEmbedding_toContinuousMap.uniformContinuous
end UniformSpace
@@ -340,11 +362,14 @@ section Norm
variable {α : Type*} {𝕜 : Type*} {R : Type*} [TopologicalSpace α] [CompactSpace α] [Zero α]
noncomputable instance [MetricSpace R] [Zero R]: MetricSpace C(α, R)₀ :=
- ContinuousMapZero.uniformEmbedding_toContinuousMap.comapMetricSpace _
+ ContinuousMapZero.isUniformEmbedding_toContinuousMap.comapMetricSpace _
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/ContinuousFunction/Ideals.lean b/Mathlib/Topology/ContinuousMap/Ideals.lean
similarity index 98%
rename from Mathlib/Topology/ContinuousFunction/Ideals.lean
rename to Mathlib/Topology/ContinuousMap/Ideals.lean
index e40d94ca79034..44324eab0595f 100644
--- a/Mathlib/Topology/ContinuousFunction/Ideals.lean
+++ b/Mathlib/Topology/ContinuousMap/Ideals.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jireh Loreaux
-/
import Mathlib.Topology.Algebra.Algebra
-import Mathlib.Topology.ContinuousFunction.Compact
+import Mathlib.Topology.ContinuousMap.Compact
import Mathlib.Topology.UrysohnsLemma
import Mathlib.Analysis.RCLike.Basic
import Mathlib.Analysis.Normed.Ring.Units
@@ -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
@@ -169,7 +169,7 @@ theorem exists_mul_le_one_eqOn_ge (f : C(X, ℝ≥0)) {c : ℝ≥0} (hc : 0 < c)
continuous_toFun :=
((map_continuous f).sup <| map_continuous _).inv₀ fun _ => (hc.trans_le le_sup_right).ne' },
fun x =>
- (inv_mul_le_iff (hc.trans_le le_sup_right)).mpr ((mul_one (f x ⊔ c)).symm ▸ le_sup_left),
+ (inv_mul_le_iff₀ (hc.trans_le le_sup_right)).mpr ((mul_one (f x ⊔ c)).symm ▸ le_sup_left),
fun x hx => by
simpa only [coe_const, mul_apply, coe_mk, Pi.inv_apply, Pi.sup_apply,
Function.const_apply, sup_eq_left.mpr (Set.mem_setOf.mp hx), ne_eq, Pi.one_apply]
@@ -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/ContinuousFunction/LocallyConstant.lean b/Mathlib/Topology/ContinuousMap/LocallyConstant.lean
similarity index 92%
rename from Mathlib/Topology/ContinuousFunction/LocallyConstant.lean
rename to Mathlib/Topology/ContinuousMap/LocallyConstant.lean
index a9858942c825d..bbe26fe3ba211 100644
--- a/Mathlib/Topology/ContinuousFunction/LocallyConstant.lean
+++ b/Mathlib/Topology/ContinuousMap/LocallyConstant.lean
@@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Oliver Nash
-/
import Mathlib.Topology.LocallyConstant.Algebra
-import Mathlib.Topology.ContinuousFunction.Basic
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.Topology.ContinuousMap.Basic
+import Mathlib.Topology.ContinuousMap.Algebra
/-!
# The algebra morphism from locally constant functions to continuous functions.
@@ -15,7 +15,7 @@ import Mathlib.Topology.ContinuousFunction.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/ContinuousFunction/Ordered.lean b/Mathlib/Topology/ContinuousMap/Ordered.lean
similarity index 95%
rename from Mathlib/Topology/ContinuousFunction/Ordered.lean
rename to Mathlib/Topology/ContinuousMap/Ordered.lean
index 7e46c520e70b6..14a4185687a12 100644
--- a/Mathlib/Topology/ContinuousFunction/Ordered.lean
+++ b/Mathlib/Topology/ContinuousMap/Ordered.lean
@@ -1,11 +1,11 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Shing Tak Lam
+Authors: Kim Morrison, Shing Tak Lam
-/
-import Mathlib.Topology.ContinuousFunction.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/ContinuousFunction/Polynomial.lean b/Mathlib/Topology/ContinuousMap/Polynomial.lean
similarity index 97%
rename from Mathlib/Topology/ContinuousFunction/Polynomial.lean
rename to Mathlib/Topology/ContinuousMap/Polynomial.lean
index 3fd434d44adc3..237d38cd410f8 100644
--- a/Mathlib/Topology/ContinuousFunction/Polynomial.lean
+++ b/Mathlib/Topology/ContinuousMap/Polynomial.lean
@@ -1,10 +1,10 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Topology.Algebra.Polynomial
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.Topology.ContinuousMap.Algebra
import Mathlib.Topology.UnitInterval
import Mathlib.Algebra.Star.Subalgebra
@@ -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/ContinuousFunction/Sigma.lean b/Mathlib/Topology/ContinuousMap/Sigma.lean
similarity index 84%
rename from Mathlib/Topology/ContinuousFunction/Sigma.lean
rename to Mathlib/Topology/ContinuousMap/Sigma.lean
index a444781b712f5..1cd4139bd4088 100644
--- a/Mathlib/Topology/ContinuousFunction/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/ContinuousFunction/StarOrdered.lean b/Mathlib/Topology/ContinuousMap/StarOrdered.lean
similarity index 94%
rename from Mathlib/Topology/ContinuousFunction/StarOrdered.lean
rename to Mathlib/Topology/ContinuousMap/StarOrdered.lean
index 18882fe259d74..3b07ebe1a7087 100644
--- a/Mathlib/Topology/ContinuousFunction/StarOrdered.lean
+++ b/Mathlib/Topology/ContinuousMap/StarOrdered.lean
@@ -5,8 +5,8 @@ Authors: Jireh Loreaux
-/
import Mathlib.Analysis.Complex.Basic
import Mathlib.Data.Real.StarOrdered
-import Mathlib.Topology.ContinuousFunction.Algebra
-import Mathlib.Topology.ContinuousFunction.ContinuousMapZero
+import Mathlib.Topology.ContinuousMap.Algebra
+import Mathlib.Topology.ContinuousMap.ContinuousMapZero
/-! # Continuous functions as a star-ordered ring -/
@@ -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/ContinuousFunction/StoneWeierstrass.lean b/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean
similarity index 82%
rename from Mathlib/Topology/ContinuousFunction/StoneWeierstrass.lean
rename to Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean
index 57b51d1724771..18ef947a9a9db 100644
--- a/Mathlib/Topology/ContinuousFunction/StoneWeierstrass.lean
+++ b/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean
@@ -1,13 +1,13 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Heather Macbeth
+Authors: Kim Morrison, Heather Macbeth
-/
import Mathlib.Algebra.Algebra.Subalgebra.Unitization
import Mathlib.Analysis.RCLike.Basic
import Mathlib.Topology.Algebra.StarSubalgebra
-import Mathlib.Topology.ContinuousFunction.ContinuousMapZero
-import Mathlib.Topology.ContinuousFunction.Weierstrass
+import Mathlib.Topology.ContinuousMap.ContinuousMapZero
+import Mathlib.Topology.ContinuousMap.Weierstrass
/-!
# The Stone-Weierstrass theorem
@@ -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/ContinuousFunction/T0Sierpinski.lean b/Mathlib/Topology/ContinuousMap/T0Sierpinski.lean
similarity index 77%
rename from Mathlib/Topology/ContinuousFunction/T0Sierpinski.lean
rename to Mathlib/Topology/ContinuousMap/T0Sierpinski.lean
index 48655f0023ded..1177d31231b59 100644
--- a/Mathlib/Topology/ContinuousFunction/T0Sierpinski.lean
+++ b/Mathlib/Topology/ContinuousMap/T0Sierpinski.lean
@@ -5,7 +5,7 @@ Authors: Ivan Sadofschi Costa
-/
import Mathlib.Topology.Order
import Mathlib.Topology.Sets.Opens
-import Mathlib.Topology.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Basic
/-!
# Any T0 space embeds in a product of copies of the Sierpinski space.
@@ -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/ContinuousFunction/Units.lean b/Mathlib/Topology/ContinuousMap/Units.lean
similarity index 96%
rename from Mathlib/Topology/ContinuousFunction/Units.lean
rename to Mathlib/Topology/ContinuousMap/Units.lean
index a8c880cf3a2bc..b63040d502d1d 100644
--- a/Mathlib/Topology/ContinuousFunction/Units.lean
+++ b/Mathlib/Topology/ContinuousMap/Units.lean
@@ -5,7 +5,7 @@ Authors: Jireh Loreaux
-/
import Mathlib.Analysis.Normed.Ring.Units
import Mathlib.Algebra.Algebra.Spectrum
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.Topology.ContinuousMap.Algebra
/-!
# Units of continuous functions
@@ -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/ContinuousFunction/Weierstrass.lean b/Mathlib/Topology/ContinuousMap/Weierstrass.lean
similarity index 95%
rename from Mathlib/Topology/ContinuousFunction/Weierstrass.lean
rename to Mathlib/Topology/ContinuousMap/Weierstrass.lean
index 90730fc0e1d83..5e1edd95c1dc8 100644
--- a/Mathlib/Topology/ContinuousFunction/Weierstrass.lean
+++ b/Mathlib/Topology/ContinuousMap/Weierstrass.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Analysis.SpecialFunctions.Bernstein
import Mathlib.Topology.Algebra.Algebra
@@ -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/ContinuousFunction/ZeroAtInfty.lean b/Mathlib/Topology/ContinuousMap/ZeroAtInfty.lean
similarity index 99%
rename from Mathlib/Topology/ContinuousFunction/ZeroAtInfty.lean
rename to Mathlib/Topology/ContinuousMap/ZeroAtInfty.lean
index 932426106e17d..c995eda23b8e7 100644
--- a/Mathlib/Topology/ContinuousFunction/ZeroAtInfty.lean
+++ b/Mathlib/Topology/ContinuousMap/ZeroAtInfty.lean
@@ -3,8 +3,8 @@ 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.Topology.ContinuousFunction.Bounded
-import Mathlib.Topology.ContinuousFunction.CocompactMap
+import Mathlib.Topology.ContinuousMap.Bounded
+import Mathlib.Topology.ContinuousMap.CocompactMap
/-!
# Continuous functions vanishing at infinity
@@ -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 e94fe66abd47a..c4d96278ccf4e 100644
--- a/Mathlib/Topology/ContinuousOn.lean
+++ b/Mathlib/Topology/ContinuousOn.lean
@@ -3,18 +3,20 @@ Copyright (c) 2019 Reid Barton. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel
-/
+import Mathlib.Algebra.Group.Indicator
import Mathlib.Topology.Constructions
/-!
# 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.
@@ -28,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
@@ -53,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
@@ -191,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
@@ -290,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
@@ -429,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]
@@ -454,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⟩
@@ -560,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
@@ -589,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
@@ -597,18 +596,14 @@ 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
rw [ContinuousAt, ← nhdsWithin_eq_nhds.2 hi]
exact hf _ _ (mem_of_mem_nhds hi)
-theorem continuousOn_empty (f : α → β) : ContinuousOn f ∅ := fun _ => False.elim
+@[simp] theorem continuousOn_empty (f : α → β) : ContinuousOn f ∅ := fun _ => False.elim
@[simp]
theorem continuousOn_singleton (f : α → β) (a : α) : ContinuousOn f {a} :=
@@ -620,205 +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_iff]
+ simp only [← singleton_union, continuousWithinAt_union, continuousWithinAt_singleton, true_and]
+
+protected alias ⟨_, ContinuousWithinAt.insert⟩ := continuousWithinAt_insert_self
-alias ⟨_, ContinuousWithinAt.insert_self⟩ := 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/Basic.lean b/Mathlib/Topology/Defs/Basic.lean
index 607362753bace..e7526dd6e9024 100644
--- a/Mathlib/Topology/Defs/Basic.lean
+++ b/Mathlib/Topology/Defs/Basic.lean
@@ -151,6 +151,28 @@ def IsOpenMap (f : X → Y) : Prop := ∀ U : Set X, IsOpen U → IsOpen (f '' U
if the image of any closed `U : Set X` is closed in `Y`. -/
def IsClosedMap (f : X → Y) : Prop := ∀ U : Set X, IsClosed U → IsClosed (f '' U)
+/-- An open quotient map is an open map `f : X → Y` which is both an open map and a quotient map.
+Equivalently, it is a surjective continuous open map.
+We use the latter characterization as a definition.
+
+Many important quotient maps are open quotient maps, including
+
+- the quotient map from a topological space to its quotient by the action of a group;
+- the quotient map from a topological group to its quotient by a normal subgroup;
+- the quotient map from a topological spaace to its separation quotient.
+
+Contrary to general quotient maps,
+the category of open quotient maps is closed under `Prod.map`.
+-/
+@[mk_iff]
+structure IsOpenQuotientMap (f : X → Y) : Prop where
+ /-- An open quotient map is surjective. -/
+ surjective : Function.Surjective f
+ /-- An open quotient map is continuous. -/
+ continuous : Continuous f
+ /-- An open quotient map is an open map. -/
+ isOpenMap : IsOpenMap f
+
end Defs
/-! ### Notation for non-standard topologies -/
diff --git a/Mathlib/Topology/Defs/Filter.lean b/Mathlib/Topology/Defs/Filter.lean
index 7266619675e3b..bf9b961755c3a 100644
--- a/Mathlib/Topology/Defs/Filter.lean
+++ b/Mathlib/Topology/Defs/Filter.lean
@@ -29,6 +29,12 @@ as well as other definitions that rely on `Filter`s.
denoted by `𝓝ˢ s` in the `Topology` scope.
A set `t` is called a neighborhood of `s`, if it includes an open set that includes `s`.
+* `exterior s`: The *exterior* of a set is the intersection of all its neighborhoods.
+ In an Alexandrov-discrete space, this is the smallest neighborhood of the set.
+
+ Note that this construction is unnamed in the literature.
+ We choose the name in analogy to `interior`.
+
### Continuity at a point
* `ContinuousAt f x`: a function `f` is continuous at a point `x`,
@@ -146,6 +152,13 @@ def nhdsSet (s : Set X) : Filter X :=
@[inherit_doc] scoped[Topology] notation "𝓝ˢ" => nhdsSet
+/-- The *exterior* of a set is the intersection of all its neighborhoods. In an Alexandrov-discrete
+space, this is the smallest neighborhood of the set.
+
+Note that this construction is unnamed in the literature. We choose the name in analogy to
+`interior`. -/
+def exterior (s : Set X) : Set X := (𝓝ˢ s).ker
+
/-- A function between topological spaces is continuous at a point `x₀`
if `f x` tends to `f x₀` when `x` tends to `x₀`. -/
@[fun_prop]
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 f346261d50bed..aec896b2eef4b 100644
--- a/Mathlib/Topology/DenseEmbedding.lean
+++ b/Mathlib/Topology/DenseEmbedding.lean
@@ -3,22 +3,22 @@ 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
This file defines three properties of functions:
-* `DenseRange f` means `f` has dense image;
-* `DenseInducing i` means `i` is also `Inducing`, namely it induces the topology on its codomain;
-* `DenseEmbedding e` means `e` is further an `Embedding`, namely it is injective and `Inducing`.
+* `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`.
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
`i : X → Y` to a continuous function `g : Y → Z`. Actually `i` only
-has to be `DenseInducing` (not necessarily injective).
+has to be `IsDenseInducing` (not necessarily injective).
-/
@@ -32,30 +32,32 @@ 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 DenseInducing [TopologicalSpace α] [TopologicalSpace β] (i : α → β)
- extends Inducing i : Prop where
+structure IsDenseInducing [TopologicalSpace α] [TopologicalSpace β] (i : α → β)
+ extends IsInducing i : Prop where
/-- The range of a dense inducing map is a dense set. -/
protected dense : DenseRange i
-namespace DenseInducing
+namespace IsDenseInducing
variable [TopologicalSpace α] [TopologicalSpace β]
variable {i : α → β}
-theorem nhds_eq_comap (di : DenseInducing i) : ∀ a : α, 𝓝 a = comap i (𝓝 <| i a) :=
- di.toInducing.nhds_eq_comap
+lemma isInducing (di : IsDenseInducing i) : IsInducing i := di.toIsInducing
-protected theorem continuous (di : DenseInducing i) : Continuous i :=
- di.toInducing.continuous
+theorem nhds_eq_comap (di : IsDenseInducing i) : ∀ a : α, 𝓝 a = comap i (𝓝 <| i a) :=
+ di.isInducing.nhds_eq_comap
-theorem closure_range (di : DenseInducing i) : closure (range i) = univ :=
+protected theorem continuous (di : IsDenseInducing i) : Continuous i :=
+ di.isInducing.continuous
+
+theorem closure_range (di : IsDenseInducing i) : closure (range i) = univ :=
di.dense.closure_range
-protected theorem preconnectedSpace [PreconnectedSpace α] (di : DenseInducing i) :
+protected theorem preconnectedSpace [PreconnectedSpace α] (di : IsDenseInducing i) :
PreconnectedSpace β :=
di.dense.preconnectedSpace di.continuous
-theorem closure_image_mem_nhds {s : Set α} {a : α} (di : DenseInducing i) (hs : s ∈ 𝓝 a) :
+theorem closure_image_mem_nhds {s : Set α} {a : α} (di : IsDenseInducing i) (hs : s ∈ 𝓝 a) :
closure (i '' s) ∈ 𝓝 (i a) := by
rw [di.nhds_eq_comap a, ((nhds_basis_opens _).comap _).mem_iff] at hs
rcases hs with ⟨U, ⟨haU, hUo⟩, sub : i ⁻¹' U ⊆ s⟩
@@ -64,14 +66,14 @@ theorem closure_image_mem_nhds {s : Set α} {a : α} (di : DenseInducing i) (hs
U ⊆ closure (i '' (i ⁻¹' U)) := di.dense.subset_closure_image_preimage_of_isOpen hUo
_ ⊆ closure (i '' s) := closure_mono (image_subset i sub)
-theorem dense_image (di : DenseInducing i) {s : Set α} : Dense (i '' s) ↔ Dense s := by
+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
`α` has empty interior. -/
-theorem interior_compact_eq_empty [T2Space β] (di : DenseInducing i) (hd : Dense (range i)ᶜ)
+theorem interior_compact_eq_empty [T2Space β] (di : IsDenseInducing i) (hd : Dense (range i)ᶜ)
{s : Set α} (hs : IsCompact s) : interior s = ∅ := by
refine eq_empty_iff_forall_not_mem.2 fun x hx => ?_
rw [mem_interior_iff_mem_nhds] at hx
@@ -81,16 +83,19 @@ theorem interior_compact_eq_empty [T2Space β] (di : DenseInducing i) (hd : Dens
exact hyi (image_subset_range _ _ hys)
/-- The product of two dense inducings is a dense inducing -/
-protected theorem prod [TopologicalSpace γ] [TopologicalSpace δ] {e₁ : α → β} {e₂ : γ → δ}
- (de₁ : DenseInducing e₁) (de₂ : DenseInducing e₂) :
- DenseInducing fun p : α × γ => (e₁ p.1, e₂ p.2) where
- toInducing := de₁.toInducing.prod_map de₂.toInducing
- dense := de₁.dense.prod_map de₂.dense
+protected theorem prodMap [TopologicalSpace γ] [TopologicalSpace δ] {e₁ : α → β} {e₂ : γ → δ}
+ (de₁ : IsDenseInducing e₁) (de₂ : IsDenseInducing e₂) :
+ IsDenseInducing (Prod.map e₁ e₂) where
+ toIsInducing := de₁.isInducing.prodMap de₂.isInducing
+ dense := de₁.dense.prodMap de₂.dense
+
+@[deprecated (since := "2024-10-06")]
+protected alias prod := IsDenseInducing.prodMap
open TopologicalSpace
-/-- If the domain of a `DenseInducing` map is a separable space, then so is the codomain. -/
-protected theorem separableSpace [SeparableSpace α] (di : DenseInducing i) : SeparableSpace β :=
+/-- If the domain of a `IsDenseInducing` map is a separable space, then so is the codomain. -/
+protected theorem separableSpace [SeparableSpace α] (di : IsDenseInducing i) : SeparableSpace β :=
di.dense.separableSpace di.continuous
variable [TopologicalSpace δ] {f : γ → α} {g : γ → δ} {h : δ → β}
@@ -102,7 +107,7 @@ g↓ ↓e
δ -h→ β
```
-/
-theorem tendsto_comap_nhds_nhds {d : δ} {a : α} (di : DenseInducing i)
+theorem tendsto_comap_nhds_nhds {d : δ} {a : α} (di : IsDenseInducing i)
(H : Tendsto h (𝓝 d) (𝓝 (i a))) (comm : h ∘ g = i ∘ f) : Tendsto f (comap g (𝓝 d)) (𝓝 a) := by
have lim1 : map g (comap g (𝓝 d)) ≤ 𝓝 d := map_comap_le
replace lim1 : map h (map g (comap g (𝓝 d))) ≤ map h (𝓝 d) := map_mono lim1
@@ -111,10 +116,10 @@ theorem tendsto_comap_nhds_nhds {d : δ} {a : α} (di : DenseInducing i)
rw [← di.nhds_eq_comap] at lim2
exact le_trans lim1 lim2
-protected theorem nhdsWithin_neBot (di : DenseInducing i) (b : β) : NeBot (𝓝[range i] b) :=
+protected theorem nhdsWithin_neBot (di : IsDenseInducing i) (b : β) : NeBot (𝓝[range i] b) :=
di.dense.nhdsWithin_neBot b
-theorem comap_nhds_neBot (di : DenseInducing i) (b : β) : NeBot (comap i (𝓝 b)) :=
+theorem comap_nhds_neBot (di : IsDenseInducing i) (b : β) : NeBot (comap i (𝓝 b)) :=
comap_neBot fun s hs => by
rcases mem_closure_iff_nhds.1 (di.dense b) s hs with ⟨_, ⟨ha, a, rfl⟩⟩
exact ⟨a, ha⟩
@@ -122,38 +127,38 @@ theorem comap_nhds_neBot (di : DenseInducing i) (b : β) : NeBot (comap i (𝓝
variable [TopologicalSpace γ]
/-- If `i : α → β` is a dense inducing, then any function `f : α → γ` "extends" to a function `g =
- DenseInducing.extend di f : β → γ`. If `γ` is Hausdorff and `f` has a continuous extension, then
+ IsDenseInducing.extend di f : β → γ`. If `γ` is Hausdorff and `f` has a continuous extension, then
`g` is the unique such extension. In general, `g` might not be continuous or even extend `f`. -/
-def extend (di : DenseInducing i) (f : α → γ) (b : β) : γ :=
+def extend (di : IsDenseInducing i) (f : α → γ) (b : β) : γ :=
@limUnder _ _ _ ⟨f (di.dense.some b)⟩ (comap i (𝓝 b)) f
-theorem extend_eq_of_tendsto [T2Space γ] (di : DenseInducing i) {b : β} {c : γ} {f : α → γ}
+theorem extend_eq_of_tendsto [T2Space γ] (di : IsDenseInducing i) {b : β} {c : γ} {f : α → γ}
(hf : Tendsto f (comap i (𝓝 b)) (𝓝 c)) : di.extend f b = c :=
haveI := di.comap_nhds_neBot
hf.limUnder_eq
-theorem extend_eq_at [T2Space γ] (di : DenseInducing i) {f : α → γ} {a : α}
+theorem extend_eq_at [T2Space γ] (di : IsDenseInducing i) {f : α → γ} {a : α}
(hf : ContinuousAt f a) : di.extend f (i a) = f a :=
extend_eq_of_tendsto _ <| di.nhds_eq_comap a ▸ hf
-theorem extend_eq_at' [T2Space γ] (di : DenseInducing i) {f : α → γ} {a : α} (c : γ)
+theorem extend_eq_at' [T2Space γ] (di : IsDenseInducing i) {f : α → γ} {a : α} (c : γ)
(hf : Tendsto f (𝓝 a) (𝓝 c)) : di.extend f (i a) = f a :=
di.extend_eq_at (continuousAt_of_tendsto_nhds hf)
-theorem extend_eq [T2Space γ] (di : DenseInducing i) {f : α → γ} (hf : Continuous f) (a : α) :
+theorem extend_eq [T2Space γ] (di : IsDenseInducing i) {f : α → γ} (hf : Continuous f) (a : α) :
di.extend f (i a) = f a :=
di.extend_eq_at hf.continuousAt
/-- Variation of `extend_eq` where we ask that `f` has a limit along `comap i (𝓝 b)` for each
`b : β`. This is a strictly stronger assumption than continuity of `f`, but in a lot of cases
you'd have to prove it anyway to use `continuous_extend`, so this avoids doing the work twice. -/
-theorem extend_eq' [T2Space γ] {f : α → γ} (di : DenseInducing i)
+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 : DenseInducing i)
+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
refine di.extend_eq_of_tendsto fun s hs => mem_map.2 ?_
suffices ∀ᶠ x : α in comap i (𝓝 b), g (i x) ∈ s from
@@ -163,11 +168,11 @@ theorem extend_unique_at [T2Space γ] {b : β} {f : α → γ} {g : β → γ} (
rintro _ hxs x rfl
exact hxs
-theorem extend_unique [T2Space γ] {f : α → γ} {g : β → γ} (di : DenseInducing i)
+theorem extend_unique [T2Space γ] {f : α → γ} {g : β → γ} (di : IsDenseInducing i)
(hf : ∀ x, g (i x) = f x) (hg : Continuous g) : di.extend f = g :=
funext fun _ => extend_unique_at di (Eventually.of_forall hf) hg.continuousAt
-theorem continuousAt_extend [T3Space γ] {b : β} {f : α → γ} (di : DenseInducing i)
+theorem continuousAt_extend [T3Space γ] {b : β} {f : α → γ} (di : IsDenseInducing i)
(hf : ∀ᶠ x in 𝓝 b, ∃ c, Tendsto f (comap i <| 𝓝 x) (𝓝 c)) : ContinuousAt (di.extend f) b := by
set φ := di.extend f
haveI := di.comap_nhds_neBot
@@ -189,83 +194,95 @@ theorem continuousAt_extend [T3Space γ] {b : β} {f : α → γ} (di : DenseInd
use V₂
tauto
-theorem continuous_extend [T3Space γ] {f : α → γ} (di : DenseInducing i)
+theorem continuous_extend [T3Space γ] {f : α → γ} (di : IsDenseInducing i)
(hf : ∀ b, ∃ c, Tendsto f (comap i (𝓝 b)) (𝓝 c)) : Continuous (di.extend f) :=
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) : DenseInducing 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 DenseInducing
+end IsDenseInducing
/-- A dense embedding is an embedding with dense image. -/
-structure DenseEmbedding [TopologicalSpace α] [TopologicalSpace β] (e : α → β) extends
- DenseInducing e : Prop where
+structure IsDenseEmbedding [TopologicalSpace α] [TopologicalSpace β] (e : α → β) extends
+ IsDenseInducing e : Prop where
/-- A dense embedding is injective. -/
inj : Function.Injective e
-theorem DenseEmbedding.mk' [TopologicalSpace α] [TopologicalSpace β] (e : α → β) (c : Continuous e)
+lemma IsDenseEmbedding.mk' [TopologicalSpace α] [TopologicalSpace β] (e : α → β) (c : Continuous e)
(dense : DenseRange e) (inj : Function.Injective e)
- (H : ∀ (a : α), ∀ s ∈ 𝓝 a, ∃ t ∈ 𝓝 (e a), ∀ b, e b ∈ t → b ∈ s) : DenseEmbedding e :=
- { DenseInducing.mk' e c dense H with inj }
+ (H : ∀ (a : α), ∀ s ∈ 𝓝 a, ∃ t ∈ 𝓝 (e a), ∀ b, e b ∈ t → b ∈ s) : IsDenseEmbedding e :=
+ { IsDenseInducing.mk' e c dense H with inj }
-namespace DenseEmbedding
+@[deprecated (since := "2024-09-30")]
+alias DenseEmbedding.mk' := IsDenseEmbedding.mk'
+
+namespace IsDenseEmbedding
open TopologicalSpace
variable [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] [TopologicalSpace δ]
variable {e : α → β}
-theorem inj_iff (de : DenseEmbedding e) {x y} : e x = e y ↔ x = y :=
+theorem inj_iff (de : IsDenseEmbedding e) {x y} : e x = e y ↔ x = y :=
de.inj.eq_iff
-theorem to_embedding (de : DenseEmbedding 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 `DenseEmbedding` is a separable space, then so is its codomain. -/
-protected theorem separableSpace [SeparableSpace α] (de : DenseEmbedding e) : SeparableSpace β :=
- de.toDenseInducing.separableSpace
+/-- If the domain of a `IsDenseEmbedding` is a separable space, then so is its codomain. -/
+protected theorem separableSpace [SeparableSpace α] (de : IsDenseEmbedding e) : SeparableSpace β :=
+ de.toIsDenseInducing.separableSpace
/-- The product of two dense embeddings is a dense embedding. -/
-protected theorem prod {e₁ : α → β} {e₂ : γ → δ} (de₁ : DenseEmbedding e₁)
- (de₂ : DenseEmbedding e₂) : DenseEmbedding fun p : α × γ => (e₁ p.1, e₂ p.2) :=
- { de₁.toDenseInducing.prod de₂.toDenseInducing with
+protected theorem prodMap {e₁ : α → β} {e₂ : γ → δ} (de₁ : IsDenseEmbedding e₁)
+ (de₂ : IsDenseEmbedding e₂) : IsDenseEmbedding fun p : α × γ => (e₁ p.1, e₂ p.2) :=
+ { de₁.toIsDenseInducing.prodMap de₂.toIsDenseInducing with
inj := de₁.inj.prodMap de₂.inj }
+@[deprecated (since := "2024-10-06")] protected alias prod := IsDenseEmbedding.prodMap
+
/-- The dense embedding of a subtype inside its closure. -/
@[simps]
def subtypeEmb {α : Type*} (p : α → Prop) (e : α → β) (x : { x // p x }) :
{ x // x ∈ closure (e '' { x | p x }) } :=
⟨e x, subset_closure <| mem_image_of_mem e x.prop⟩
-protected theorem subtype (de : DenseEmbedding e) (p : α → Prop) :
- DenseEmbedding (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] }
+protected theorem subtype (de : IsDenseEmbedding e) (p : α → Prop) :
+ 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 : α → α) :=
+ { IsEmbedding.id with dense := denseRange_id }
-theorem dense_image (de : DenseEmbedding e) {s : Set α} : Dense (e '' s) ↔ Dense s :=
- de.toDenseInducing.dense_image
+end IsDenseEmbedding
-end DenseEmbedding
+@[deprecated (since := "2024-09-30")]
+alias denseEmbedding_id := IsDenseEmbedding.id
-theorem denseEmbedding_id {α : Type*} [TopologicalSpace α] : DenseEmbedding (id : α → α) :=
- { embedding_id with dense := denseRange_id }
+theorem Dense.isDenseEmbedding_val [TopologicalSpace α] {s : Set α} (hs : Dense s) :
+ IsDenseEmbedding ((↑) : s → α) :=
+ { IsEmbedding.subtypeVal with dense := hs.denseRange_val }
-theorem Dense.denseEmbedding_val [TopologicalSpace α] {s : Set α} (hs : Dense s) :
- DenseEmbedding ((↑) : s → α) :=
- { embedding_subtype_val with dense := hs.denseRange_val }
+@[deprecated (since := "2024-09-30")]
+alias Dense.denseEmbedding_val := Dense.isDenseEmbedding_val
theorem isClosed_property [TopologicalSpace β] {e : α → β} {p : β → Prop} (he : DenseRange e)
(hp : IsClosed { x | p x }) (h : ∀ a, p (e a)) : ∀ b, p b :=
@@ -279,14 +296,14 @@ theorem isClosed_property [TopologicalSpace β] {e : α → β} {p : β → Prop
theorem isClosed_property2 [TopologicalSpace β] {e : α → β} {p : β → β → Prop} (he : DenseRange e)
(hp : IsClosed { q : β × β | p q.1 q.2 }) (h : ∀ a₁ a₂, p (e a₁) (e a₂)) : ∀ b₁ b₂, p b₁ b₂ :=
- have : ∀ q : β × β, p q.1 q.2 := isClosed_property (he.prod_map he) hp fun _ => h _ _
+ have : ∀ q : β × β, p q.1 q.2 := isClosed_property (he.prodMap he) hp fun _ => h _ _
fun b₁ b₂ => this ⟨b₁, b₂⟩
theorem isClosed_property3 [TopologicalSpace β] {e : α → β} {p : β → β → β → Prop}
(he : DenseRange e) (hp : IsClosed { q : β × β × β | p q.1 q.2.1 q.2.2 })
(h : ∀ a₁ a₂ a₃, p (e a₁) (e a₂) (e a₃)) : ∀ b₁ b₂ b₃, p b₁ b₂ b₃ :=
have : ∀ q : β × β × β, p q.1 q.2.1 q.2.2 :=
- isClosed_property (he.prod_map <| he.prod_map he) hp fun _ => h _ _ _
+ isClosed_property (he.prodMap <| he.prodMap he) hp fun _ => h _ _ _
fun b₁ b₂ b₃ => this ⟨b₁, b₂, b₃⟩
@[elab_as_elim]
@@ -319,15 +336,15 @@ theorem DenseRange.equalizer (hfd : DenseRange f) {g h : β → γ} (hg : Contin
end
-- Bourbaki GT III §3 no.4 Proposition 7 (generalised to any dense-inducing map to a T₃ space)
-theorem Filter.HasBasis.hasBasis_of_denseInducing [TopologicalSpace α] [TopologicalSpace β]
+theorem Filter.HasBasis.hasBasis_of_isDenseInducing [TopologicalSpace α] [TopologicalSpace β]
[T3Space β] {ι : Type*} {s : ι → Set α} {p : ι → Prop} {x : α} (h : (𝓝 x).HasBasis p s)
- {f : α → β} (hf : DenseInducing f) : (𝓝 (f x)).HasBasis p fun i => closure <| f '' s i := by
+ {f : α → β} (hf : IsDenseInducing f) : (𝓝 (f x)).HasBasis p fun i => closure <| f '' s i := by
rw [Filter.hasBasis_iff] at h ⊢
intro T
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 6dba286e22d97..0aba00ba4c0d7 100644
--- a/Mathlib/Topology/EMetricSpace/Basic.lean
+++ b/Mathlib/Topology/EMetricSpace/Basic.lean
@@ -58,28 +58,38 @@ 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 uniformEmbedding_iff [PseudoEMetricSpace β] {f : α → β} :
- UniformEmbedding f ↔ Function.Injective f ∧ UniformContinuous f ∧
+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 < δ :=
- (uniformEmbedding_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
/-- 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_uniformEmbedding [PseudoEMetricSpace β] {f : α → β} (h : UniformEmbedding f) :
+theorem controlled_of_isUniformEmbedding [PseudoEMetricSpace β] {f : α → β}
+ (h : 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 < δ :=
- ⟨uniformContinuous_iff.1 h.uniformContinuous, (uniformEmbedding_iff.1 h).2.2⟩
+ ⟨uniformContinuous_iff.1 h.uniformContinuous, (isUniformEmbedding_iff.1 h).2.2⟩
+
+@[deprecated (since := "2024-10-01")]
+alias controlled_of_uniformEmbedding := controlled_of_isUniformEmbedding
/-- ε-δ characterization of Cauchy sequences on pseudoemetric spaces -/
protected theorem cauchy_iff {f : Filter α} :
@@ -144,6 +154,8 @@ variable {x y z : α} {ε ε₁ ε₂ : ℝ≥0∞} {s t : Set α}
theorem inseparable_iff : Inseparable x y ↔ edist x y = 0 := by
simp [inseparable_iff_mem_closure, mem_closure_iff, edist_comm, forall_lt_iff_le']
+alias ⟨_root_.Inseparable.edist_eq_zero, _⟩ := EMetric.inseparable_iff
+
-- see Note [nolint_ge]
/-- In a pseudoemetric space, Cauchy sequences are characterized by the fact that, eventually,
the pseudoedistance between its elements is arbitrarily small -/
@@ -229,11 +241,14 @@ instance (priority := 100) EMetricSpace.instT0Space : T0Space γ where
/-- A map between emetric spaces is a uniform embedding if and only if the edistance between `f x`
and `f y` is controlled in terms of the distance between `x` and `y` and conversely. -/
-theorem EMetric.uniformEmbedding_iff' [EMetricSpace β] {f : γ → β} :
- UniformEmbedding f ↔
+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 [uniformEmbedding_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'
/-- If a `PseudoEMetricSpace` is a T₀ space, then it is an `EMetricSpace`. -/
-- Porting note: made `reducible`;
diff --git a/Mathlib/Topology/EMetricSpace/Defs.lean b/Mathlib/Topology/EMetricSpace/Defs.lean
index 2d530cb9ad131..a75f1b0ea7b64 100644
--- a/Mathlib/Topology/EMetricSpace/Defs.lean
+++ b/Mathlib/Topology/EMetricSpace/Defs.lean
@@ -4,7 +4,7 @@ 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.Inv
-import Mathlib.Topology.UniformSpace.Basic
+import Mathlib.Topology.UniformSpace.OfFun
/-!
# Extended metric spaces
@@ -25,7 +25,7 @@ to `EMetricSpace` at the end.
-/
assert_not_exists Nat.instLocallyFiniteOrder
-assert_not_exists UniformEmbedding
+assert_not_exists IsUniformEmbedding
assert_not_exists TendstoUniformlyOnFilter
open Set Filter
@@ -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
@@ -447,7 +447,7 @@ theorem tendsto_nhdsWithin_nhds {a b} :
Tendsto f (𝓝[s] a) (𝓝 b) ↔
∀ ε > 0, ∃ δ > 0, ∀ {x : α}, x ∈ s → edist x a < δ → edist (f x) b < ε := by
rw [← nhdsWithin_univ b, tendsto_nhdsWithin_nhdsWithin]
- simp only [mem_univ, true_and_iff]
+ simp only [mem_univ, true_and]
theorem tendsto_nhds_nhds {a b} :
Tendsto f (𝓝 a) (𝓝 b) ↔ ∀ ε > 0, ∃ δ > 0, ∀ ⦃x⦄, edist x a < δ → edist (f x) b < ε :=
@@ -491,7 +491,7 @@ theorem tendsto_nhds {f : Filter β} {u : β → α} {a : α} :
theorem tendsto_atTop [Nonempty β] [SemilatticeSup β] {u : β → α} {a : α} :
Tendsto u atTop (𝓝 a) ↔ ∀ ε > 0, ∃ N, ∀ n ≥ N, edist (u n) a < ε :=
(atTop_basis.tendsto_iff nhds_basis_eball).trans <| by
- simp only [exists_prop, true_and_iff, mem_Ici, mem_ball]
+ simp only [exists_prop, true_and, mem_Ici, mem_ball]
section Compact
@@ -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/Diam.lean b/Mathlib/Topology/EMetricSpace/Diam.lean
index 3c3206848162a..18895f5377d0d 100644
--- a/Mathlib/Topology/EMetricSpace/Diam.lean
+++ b/Mathlib/Topology/EMetricSpace/Diam.lean
@@ -4,7 +4,6 @@ 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.EMetricSpace.Pi
-import Mathlib.Data.ENNReal.Real
/-!
# Diameters of sets in extended metric spaces
@@ -74,7 +73,7 @@ theorem diam_iUnion_mem_option {ι : Type*} (o : Option ι) (s : ι → Set α)
theorem diam_insert : diam (insert x s) = max (⨆ y ∈ s, edist x y) (diam s) :=
eq_of_forall_ge_iff fun d => by
simp only [diam_le_iff, forall_mem_insert, edist_self, edist_comm x, max_le_iff, iSup_le_iff,
- zero_le, true_and_iff, forall_and, and_self_iff, ← and_assoc]
+ zero_le, true_and, forall_and, and_self_iff, ← and_assoc]
theorem diam_pair : diam ({x, y} : Set α) = edist x y := by
simp only [iSup_singleton, diam_insert, diam_singleton, ENNReal.max_zero_right]
diff --git a/Mathlib/Topology/EMetricSpace/Paracompact.lean b/Mathlib/Topology/EMetricSpace/Paracompact.lean
index dc2427907aac4..b725de087262c 100644
--- a/Mathlib/Topology/EMetricSpace/Paracompact.lean
+++ b/Mathlib/Topology/EMetricSpace/Paracompact.lean
@@ -3,10 +3,10 @@ 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.Ordinal.Basic
import Mathlib.Tactic.GCongr
import Mathlib.Topology.Compactness.Paracompact
import Mathlib.Topology.EMetricSpace.Basic
+import Mathlib.SetTheory.Cardinal.Basic
/-!
# (Extended) metric spaces are paracompact
@@ -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 e425d7ce55e1a..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
@@ -12,7 +12,7 @@ The main definition of this file is `extendFrom A f` where `f : X → Y`
and `A : Set X`. This defines a new function `g : X → Y` which maps any
`x₀ : X` to the limit of `f` as `x` tends to `x₀`, if such a limit exists.
-This is analogous to the way `DenseInducing.extend` "extends" a function
+This is analogous to the way `IsDenseInducing.extend` "extends" a function
`f : X → Z` to a function `g : Y → Z` along a dense inducing `i : X → Y`.
The main theorem we prove about this definition is `continuousOn_extendFrom`
diff --git a/Mathlib/Topology/Exterior.lean b/Mathlib/Topology/Exterior.lean
new file mode 100644
index 0000000000000..8b46e6e2b00e1
--- /dev/null
+++ b/Mathlib/Topology/Exterior.lean
@@ -0,0 +1,106 @@
+/-
+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, Yury Kudryashov
+-/
+import Mathlib.Topology.NhdsSet
+import Mathlib.Topology.Inseparable
+
+/-!
+# Exterior of a set
+
+We define `exterior s` to be the intersection of all neighborhoods of `s`,
+see `Topology/Defs/Filter`.
+Note that this construction has no standard name in the literature.
+
+In this file we prove basic properties of this operation.
+-/
+
+open Set Filter
+open scoped Topology
+
+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]
+
+@[simp]
+theorem mem_exterior_singleton : x ∈ exterior {y} ↔ x ⤳ y := by
+ rw [exterior_singleton_eq_ker_nhds, ker_nhds_eq_specializes, mem_setOf]
+
+lemma exterior_def (s : Set X) : exterior s = ⋂₀ {t : Set X | IsOpen t ∧ s ⊆ t} :=
+ (hasBasis_nhdsSet _).ker.trans sInter_eq_biInter.symm
+
+lemma mem_exterior : x ∈ exterior s ↔ ∀ U, IsOpen U → s ⊆ U → x ∈ U := by simp [exterior_def]
+
+lemma subset_exterior_iff : s ⊆ exterior t ↔ ∀ U, IsOpen U → t ⊆ U → s ⊆ U := by
+ simp [exterior_def]
+
+lemma subset_exterior : s ⊆ exterior s := subset_exterior_iff.2 fun _ _ ↦ id
+
+lemma exterior_minimal (h₁ : s ⊆ t) (h₂ : IsOpen t) : exterior s ⊆ t := by
+ rw [exterior_def]; exact sInter_subset_of_mem ⟨h₂, h₁⟩
+
+lemma IsOpen.exterior_eq (h : IsOpen s) : exterior s = s :=
+ (exterior_minimal Subset.rfl h).antisymm subset_exterior
+
+lemma IsOpen.exterior_subset (ht : IsOpen t) : exterior s ⊆ t ↔ s ⊆ t :=
+ ⟨subset_exterior.trans, fun h ↦ exterior_minimal h ht⟩
+
+@[deprecated (since := "2024-09-18")] alias IsOpen.exterior_subset_iff := IsOpen.exterior_subset
+
+@[simp]
+theorem exterior_iUnion (s : ι → Set X) : exterior (⋃ i, s i) = ⋃ i, exterior (s i) := by
+ simp only [exterior, nhdsSet_iUnion, ker_iSup]
+
+@[simp]
+theorem exterior_union (s t : Set X) : exterior (s ∪ t) = exterior s ∪ exterior t := by
+ simp only [exterior, nhdsSet_union, ker_sup]
+
+@[simp]
+theorem exterior_sUnion (S : Set (Set X)) : exterior (⋃₀ S) = ⋃ s ∈ S, exterior s := by
+ simp only [sUnion_eq_biUnion, exterior_iUnion]
+
+theorem mem_exterior_iff_specializes : x ∈ exterior s ↔ ∃ y ∈ s, x ⤳ y := calc
+ x ∈ exterior s ↔ x ∈ exterior (⋃ y ∈ s, {y}) := by simp
+ _ ↔ ∃ y ∈ s, x ⤳ y := by
+ simp only [exterior_iUnion, mem_exterior_singleton, mem_iUnion₂, exists_prop]
+
+@[mono] lemma exterior_mono : Monotone (exterior : Set X → Set X) :=
+ fun _s _t h ↦ ker_mono <| nhdsSet_mono h
+
+/-- This name was used to be used for the `Iff` version,
+see `exterior_subset_exterior_iff_nhdsSet`.
+-/
+@[gcongr] lemma exterior_subset_exterior (h : s ⊆ t) : exterior s ⊆ exterior t := exterior_mono h
+
+@[simp] lemma exterior_subset_exterior_iff_nhdsSet : exterior s ⊆ exterior t ↔ 𝓝ˢ s ≤ 𝓝ˢ t := by
+ simp (config := {contextual := true}) only [subset_exterior_iff, (hasBasis_nhdsSet _).ge_iff,
+ and_imp, IsOpen.mem_nhdsSet, IsOpen.exterior_subset]
+
+theorem exterior_eq_exterior_iff_nhdsSet : exterior s = exterior t ↔ 𝓝ˢ s = 𝓝ˢ t := by
+ simp [le_antisymm_iff]
+
+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
+
+@[simp] lemma exterior_eq_empty : exterior s = ∅ ↔ s = ∅ :=
+ ⟨eq_bot_mono subset_exterior, by rintro rfl; exact exterior_empty⟩
+
+@[simp] lemma nhdsSet_exterior (s : Set X) : 𝓝ˢ (exterior s) = 𝓝ˢ s := by
+ refine le_antisymm ((hasBasis_nhdsSet _).ge_iff.2 ?_) (nhdsSet_mono subset_exterior)
+ exact fun U ⟨hUo, hsU⟩ ↦ hUo.mem_nhdsSet.2 <| hUo.exterior_subset.2 hsU
+
+@[simp] lemma exterior_exterior (s : Set X) : exterior (exterior s) = exterior s := by
+ simp only [exterior_eq_exterior_iff_nhdsSet, nhdsSet_exterior]
diff --git a/Mathlib/Topology/ExtremallyDisconnected.lean b/Mathlib/Topology/ExtremallyDisconnected.lean
index a5d3b08560a46..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
@@ -88,7 +88,7 @@ theorem StoneCech.projective [DiscreteTopology X] : CompactT2.Projective (StoneC
let h : StoneCech X → Y := stoneCechExtend ht
have hh : Continuous h := continuous_stoneCechExtend ht
refine ⟨h, hh, denseRange_stoneCechUnit.equalizer (hg.comp hh) hf ?_⟩
- rw [comp.assoc, stoneCechExtend_extends ht, ← comp.assoc, hs, id_comp]
+ rw [comp_assoc, stoneCechExtend_extends ht, ← comp_assoc, hs, id_comp]
protected theorem CompactT2.Projective.extremallyDisconnected [CompactSpace X] [T2Space X]
(h : CompactT2.Projective X) : ExtremallyDisconnected X := by
@@ -271,7 +271,7 @@ protected theorem CompactT2.ExtremallyDisconnected.projective [ExtremallyDisconn
have π₂_cont : Continuous π₂ := continuous_snd.comp continuous_subtype_val
refine ⟨E.restrict π₂ ∘ ρ'.symm, ⟨π₂_cont.continuousOn.restrict.comp ρ'.symm.continuous, ?_⟩⟩
suffices f ∘ E.restrict π₂ = φ ∘ ρ' by
- rw [← comp.assoc, this, comp.assoc, Homeomorph.self_comp_symm, comp_id]
+ rw [← comp_assoc, this, comp_assoc, Homeomorph.self_comp_symm, comp_id]
ext x
exact x.val.mem.symm
diff --git a/Mathlib/Topology/FiberBundle/Basic.lean b/Mathlib/Topology/FiberBundle/Basic.lean
index bb2f8386ba3a3..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_isEmbedding (x : B) : IsEmbedding (@TotalSpace.mk B F E x) :=
+ ⟨totalSpaceMk_isInducing F E x, TotalSpace.mk_injective x⟩
-theorem totalSpaceMk_embedding (x : B) : Embedding (@TotalSpace.mk B F E x) :=
- ⟨totalSpaceMk_inducing F E x, TotalSpace.mk_injective x⟩
+@[deprecated (since := "2024-10-26")]
+alias totalSpaceMk_embedding := totalSpaceMk_isEmbedding
-theorem totalSpaceMk_closedEmbedding [T1Space B] (x : B) :
- ClosedEmbedding (@TotalSpace.mk B F E x) :=
- ⟨totalSpaceMk_embedding F E x, by
+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]
@@ -439,7 +450,7 @@ def trivChange (i j : ι) : PartialHomeomorph (B × F) (B × F) where
exacts [hx.1, ⟨⟨hx.1, hx.2⟩, hx.1⟩]
right_inv' := by
rintro ⟨x, v⟩ hx
- simp only [prod_mk_mem_set_prod_eq, mem_inter_iff, and_true_iff, mem_univ] at hx
+ simp only [prod_mk_mem_set_prod_eq, mem_inter_iff, and_true, mem_univ] at hx
dsimp only
rw [Z.coordChange_comp, Z.coordChange_self]
· exact hx.2
@@ -469,9 +480,9 @@ def localTrivAsPartialEquiv (i : ι) : PartialEquiv Z.TotalSpace (B × F) where
invFun p := ⟨p.1, Z.coordChange i (Z.indexAt p.1) p.1 p.2⟩
toFun p := ⟨p.1, Z.coordChange (Z.indexAt p.1) i p.1 p.2⟩
map_source' p hp := by
- simpa only [Set.mem_preimage, and_true_iff, Set.mem_univ, Set.prod_mk_mem_set_prod_eq] using hp
+ simpa only [Set.mem_preimage, and_true, Set.mem_univ, Set.prod_mk_mem_set_prod_eq] using hp
map_target' p hp := by
- simpa only [Set.mem_preimage, and_true_iff, Set.mem_univ, Set.mem_prod] using hp
+ simpa only [Set.mem_preimage, and_true, Set.mem_univ, Set.mem_prod] using hp
left_inv' := by
rintro ⟨x, v⟩ hx
replace hx : x ∈ Z.baseSet i := hx
@@ -479,7 +490,7 @@ def localTrivAsPartialEquiv (i : ι) : PartialEquiv Z.TotalSpace (B × F) where
rw [Z.coordChange_comp, Z.coordChange_self] <;> apply_rules [mem_baseSet_at, mem_inter]
right_inv' := by
rintro ⟨x, v⟩ hx
- simp only [prod_mk_mem_set_prod_eq, and_true_iff, mem_univ] at hx
+ simp only [prod_mk_mem_set_prod_eq, and_true, mem_univ] at hx
dsimp only
rw [Z.coordChange_comp, Z.coordChange_self]
exacts [hx, ⟨⟨hx, Z.mem_baseSet_at _⟩, hx⟩]
@@ -493,7 +504,7 @@ theorem mem_localTrivAsPartialEquiv_source (p : Z.TotalSpace) :
theorem mem_localTrivAsPartialEquiv_target (p : B × F) :
p ∈ (Z.localTrivAsPartialEquiv i).target ↔ p.1 ∈ Z.baseSet i := by
erw [mem_prod]
- simp only [and_true_iff, mem_univ]
+ simp only [and_true, mem_univ]
theorem localTrivAsPartialEquiv_apply (p : Z.TotalSpace) :
(Z.localTrivAsPartialEquiv i) p = ⟨p.1, Z.coordChange (Z.indexAt p.1) i p.1 p.2⟩ :=
@@ -508,9 +519,9 @@ theorem localTrivAsPartialEquiv_trans (i j : ι) :
simp only [mem_localTrivAsPartialEquiv_target, mfld_simps]
rfl
· rintro ⟨x, v⟩ hx
- simp only [trivChange, localTrivAsPartialEquiv, PartialEquiv.symm, true_and_iff,
+ simp only [trivChange, localTrivAsPartialEquiv, PartialEquiv.symm,
Prod.mk.inj_iff, prod_mk_mem_set_prod_eq, PartialEquiv.trans_source, mem_inter_iff,
- and_true_iff, mem_preimage, proj, mem_univ, eq_self_iff_true, (· ∘ ·),
+ mem_preimage, proj, mem_univ, eq_self_iff_true, (· ∘ ·),
PartialEquiv.coe_trans, TotalSpace.proj] at hx ⊢
simp only [Z.coordChange_comp, hx, mem_inter_iff, and_self_iff, mem_baseSet_at]
@@ -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 222d8ca96b186..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,16 +140,15 @@ 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₃ :=
- (continuous_fst.comp continuous_fst).prod_mk (continuous_snd.prod_map continuous_snd)
+ have hf₃ : Continuous f₃ := by fun_prop
refine ((hf₃.comp_continuousOn hf₂).comp hf₁.continuousOn ?_).congr ?_
· rw [e₁.source_eq, e₂.source_eq]
exact mapsTo_preimage _ _
rintro ⟨b, v₁, v₂⟩ ⟨hb₁, _⟩
- simp only [f₃, Prod.toFun', Prod.mk.inj_iff, Function.comp_apply, and_true_iff]
+ simp only [f₃, Prod.toFun', Prod.mk.inj_iff, Function.comp_apply, and_true]
rw [e₁.coe_fst]
rw [e₁.source_eq, mem_preimage]
exact hb₁
@@ -175,9 +179,8 @@ 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]
- have H₁ : Continuous fun p : B × F₁ × F₂ ↦ ((p.1, p.2.1), (p.1, p.2.2)) :=
- (continuous_id.prod_map continuous_fst).prod_mk (continuous_id.prod_map continuous_snd)
+ 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 _⟩⟩
@@ -191,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
@@ -207,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
@@ -224,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).prod_map (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₂),
@@ -252,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)]
@@ -279,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]
@@ -293,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]
@@ -309,7 +309,7 @@ noncomputable def Trivialization.pullback (e : Trivialization F (π F E)) (f : K
target := (f ⁻¹' e.baseSet) ×ˢ univ
map_source' x h := by
simp_rw [e.source_eq, mem_preimage, Pullback.lift_proj] at h
- simp_rw [prod_mk_mem_set_prod_eq, mem_univ, and_true_iff, mem_preimage, h]
+ simp_rw [prod_mk_mem_set_prod_eq, mem_univ, and_true, mem_preimage, h]
map_target' y h := by
rw [mem_prod, mem_preimage] at h
simp_rw [e.source_eq, mem_preimage, Pullback.lift_proj, h.1]
@@ -317,7 +317,7 @@ noncomputable def Trivialization.pullback (e : Trivialization F (π F E)) (f : K
simp_rw [mem_preimage, e.mem_source, Pullback.lift_proj] at h
simp_rw [Pullback.lift, e.symm_apply_apply_mk h]
right_inv' x h := by
- simp_rw [mem_prod, mem_preimage, mem_univ, and_true_iff] at h
+ simp_rw [mem_prod, mem_preimage, mem_univ, and_true] at h
simp_rw [Pullback.lift_mk, e.apply_mk_symm h]
open_source := by
simp_rw [e.source_eq, ← preimage_comp]
@@ -334,20 +334,20 @@ noncomputable def Trivialization.pullback (e : Trivialization F (π F E)) (f : K
pullbackTotalSpaceEmbedding]
refine
continuousOn_fst.prod
- (e.continuousOn_symm.comp ((map_continuous f).prod_map continuous_id).continuousOn
+ (e.continuousOn_symm.comp ((map_continuous f).prodMap continuous_id).continuousOn
Subset.rfl)
source_eq := by
dsimp only
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 72f78dd20048f..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
@@ -168,7 +168,7 @@ theorem preimage_symm_proj_inter (s : Set B) :
e.toPartialEquiv.symm ⁻¹' (proj ⁻¹' s) ∩ e.baseSet ×ˢ univ = (s ∩ e.baseSet) ×ˢ univ := by
ext ⟨x, y⟩
suffices x ∈ e.baseSet → (proj (e.toPartialEquiv.symm (x, y)) ∈ s ↔ x ∈ s) by
- simpa only [prod_mk_mem_set_prod_eq, mem_inter_iff, and_true_iff, mem_univ, and_congr_left_iff]
+ simpa only [prod_mk_mem_set_prod_eq, mem_inter_iff, and_true, mem_univ, and_congr_left_iff]
intro h
rw [e.proj_symm_apply' h]
@@ -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/FiberPartition.lean b/Mathlib/Topology/FiberPartition.lean
new file mode 100644
index 0000000000000..8e21ee229b9e1
--- /dev/null
+++ b/Mathlib/Topology/FiberPartition.lean
@@ -0,0 +1,69 @@
+/-
+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.LocallyConstant.Basic
+import Mathlib.Logic.Function.FiberPartition
+/-!
+
+This file provides some API surrounding `Function.Fiber` (see
+`Mathlib.Logic.Function.FiberPartition`) in the presence of a topology on the domain of the
+function.
+
+Note: this API is designed to be useful when defining the counit of the adjunction between
+the functor which takes a set to the condensed set corresponding to locally constant maps to that
+set, and the forgetful functor from the category of condensed sets to the category of sets
+(see PR #14027).
+-/
+
+
+open Function
+
+variable {S Y : Type*} (f : S → Y)
+
+namespace TopologicalSpace.Fiber
+
+variable [TopologicalSpace S]
+
+/-- The canonical map from the disjoint union induced by `f` to `S`. -/
+@[simps apply]
+def sigmaIsoHom : C((x : Fiber f) × x.val, S) where
+ toFun | ⟨a, x⟩ => x.val
+
+lemma sigmaIsoHom_inj : Function.Injective (sigmaIsoHom f) := by
+ rintro ⟨⟨_, _, rfl⟩, ⟨_, hx⟩⟩ ⟨⟨_, _, rfl⟩, ⟨_, hy⟩⟩ h
+ refine Sigma.subtype_ext ?_ h
+ simp only [sigmaIsoHom_apply] at h
+ rw [Set.mem_preimage, Set.mem_singleton_iff] at hx hy
+ simp [← hx, ← hy, h]
+
+lemma sigmaIsoHom_surj : Function.Surjective (sigmaIsoHom f) :=
+ fun _ ↦ ⟨⟨⟨_, ⟨⟨_, Set.mem_range_self _⟩, rfl⟩⟩, ⟨_, rfl⟩⟩, rfl⟩
+
+/-- The inclusion map from a component of the disjoint union induced by `f` into `S`. -/
+def sigmaIncl (a : Fiber f) : C(a.val, S) where
+ toFun x := x.val
+
+/-- The inclusion map from a fiber of a composition into the intermediate fiber. -/
+def sigmaInclIncl {X : Type*} (g : Y → X) (a : Fiber (g ∘ f))
+ (b : Fiber (f ∘ (sigmaIncl (g ∘ f) a))) :
+ C(b.val, (Fiber.mk f (b.preimage).val).val) where
+ toFun x := ⟨x.val.val, by
+ have := x.prop
+ simp only [sigmaIncl, ContinuousMap.coe_mk, Fiber.mem_iff_eq_image, comp_apply] at this
+ rw [Fiber.mem_iff_eq_image, Fiber.mk_image, this, ← Fiber.map_preimage_eq_image]
+ simp [sigmaIncl]⟩
+
+variable (l : LocallyConstant S Y) [CompactSpace S]
+
+instance (x : Fiber l) : CompactSpace x.val := by
+ obtain ⟨y, hy⟩ := x.prop
+ rw [← isCompact_iff_compactSpace, ← hy]
+ exact (l.2.isClosed_fiber _).isCompact
+
+instance : Finite (Fiber l) :=
+ have : Finite (Set.range l) := l.range_finite
+ Finite.Set.finite_range _
+
+end TopologicalSpace.Fiber
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/Hom/Open.lean b/Mathlib/Topology/Hom/Open.lean
index bec44e93eff1e..86051435726a8 100644
--- a/Mathlib/Topology/Hom/Open.lean
+++ b/Mathlib/Topology/Hom/Open.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.Topology.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Basic
/-!
# Continuous open maps
diff --git a/Mathlib/Topology/Homeomorph.lean b/Mathlib/Topology/Homeomorph.lean
index 3a5abc02d2bd4..17cbd37091ef9 100644
--- a/Mathlib/Topology/Homeomorph.lean
+++ b/Mathlib/Topology/Homeomorph.lean
@@ -54,13 +54,11 @@ theorem toEquiv_injective : Function.Injective (toEquiv : X ≃ₜ Y → X ≃ Y
| ⟨_, _, _⟩, ⟨_, _, _⟩, rfl => rfl
instance : EquivLike (X ≃ₜ Y) X Y where
- coe := fun h => h.toEquiv
- inv := fun h => h.toEquiv.symm
- left_inv := fun h => h.left_inv
- right_inv := fun h => h.right_inv
- coe_injective' := fun _ _ H _ => toEquiv_injective <| DFunLike.ext' H
-
-instance : CoeFun (X ≃ₜ Y) fun _ ↦ X → Y := ⟨DFunLike.coe⟩
+ coe h := h.toEquiv
+ inv h := h.toEquiv.symm
+ left_inv h := h.left_inv
+ right_inv h := h.right_inv
+ coe_injective' _ _ H _ := toEquiv_injective <| DFunLike.ext' H
@[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,24 +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 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
-protected theorem t2Space [T2Space X] (h : X ≃ₜ Y) : T2Space Y :=
- h.symm.embedding.t2Space
+theorem isDenseEmbedding (h : X ≃ₜ Y) : IsDenseEmbedding h :=
+ { h.isEmbedding with dense := h.surjective.denseRange }
-protected theorem t3Space [T3Space X] (h : X ≃ₜ Y) : T3Space Y :=
- h.symm.embedding.t3Space
-
-protected theorem denseEmbedding (h : X ≃ₜ Y) : DenseEmbedding h :=
- { h.embedding 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
@@ -331,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
+
+@[deprecated (since := "2024-10-18")]
+alias openEmbedding := isOpenEmbedding
-protected theorem closedEmbedding (h : X ≃ₜ Y) : ClosedEmbedding h :=
- closedEmbedding_of_embedding_closed h.embedding h.isClosedMap
+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 _
@@ -364,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
@@ -400,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]
@@ -414,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
@@ -425,40 +444,40 @@ 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
refine ⟨?_, fun hf => h.isOpenMap.comp hf⟩
intro hf
- rw [← Function.id_comp f, ← h.symm_comp_self, Function.comp.assoc]
+ rw [← Function.id_comp f, ← h.symm_comp_self, Function.comp_assoc]
exact h.symm.isOpenMap.comp hf
@[simp]
theorem comp_isOpenMap_iff' (h : X ≃ₜ Y) {f : Y → Z} : IsOpenMap (f ∘ h) ↔ IsOpenMap f := by
refine ⟨?_, fun hf => hf.comp h.isOpenMap⟩
intro hf
- rw [← Function.comp_id f, ← h.self_comp_symm, ← Function.comp.assoc]
+ rw [← Function.comp_id f, ← h.self_comp_symm, ← Function.comp_assoc]
exact hf.comp h.symm.isOpenMap
/-- A homeomorphism `h : X ≃ₜ Y` lifts to a homeomorphism between subtypes corresponding to
@@ -495,8 +514,6 @@ def sumCongr (h₁ : X ≃ₜ X') (h₂ : Y ≃ₜ Y') : X ⊕ Y ≃ₜ X' ⊕ Y
/-- Product of two homeomorphisms. -/
def prodCongr (h₁ : X ≃ₜ X') (h₂ : Y ≃ₜ Y') : X × Y ≃ₜ X' × Y' where
- continuous_toFun := h₁.continuous.prod_map h₂.continuous
- continuous_invFun := h₁.symm.continuous.prod_map h₂.symm.continuous
toEquiv := h₁.toEquiv.prodCongr h₂.toEquiv
@[simp]
@@ -686,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`. -/
@@ -693,9 +753,9 @@ section Distrib
def sumProdDistrib : (X ⊕ Y) × Z ≃ₜ (X × Z) ⊕ (Y × Z) :=
Homeomorph.symm <|
homeomorphOfContinuousOpen (Equiv.sumProdDistrib X Y Z).symm
- ((continuous_inl.prod_map continuous_id).sum_elim
- (continuous_inr.prod_map continuous_id)) <|
- (isOpenMap_inl.prod IsOpenMap.id).sum_elim (isOpenMap_inr.prod IsOpenMap.id)
+ ((continuous_inl.prodMap continuous_id).sum_elim
+ (continuous_inr.prodMap continuous_id)) <|
+ (isOpenMap_inl.prodMap IsOpenMap.id).sum_elim (isOpenMap_inr.prodMap IsOpenMap.id)
/-- `X × (Y ⊕ Z)` is homeomorphic to `X × Y ⊕ X × Z`. -/
def prodSumDistrib : X × (Y ⊕ Z) ≃ₜ (X × Y) ⊕ (X × Z) :=
@@ -709,7 +769,7 @@ def sigmaProdDistrib : (Σ i, X i) × Y ≃ₜ Σ i, X i × Y :=
Homeomorph.symm <|
homeomorphOfContinuousOpen (Equiv.sigmaProdDistrib X Y).symm
(continuous_sigma fun _ => continuous_sigmaMk.fst'.prod_mk continuous_snd)
- (isOpenMap_sigma.2 fun _ => isOpenMap_sigmaMk.prod IsOpenMap.id)
+ (isOpenMap_sigma.2 fun _ => isOpenMap_sigmaMk.prodMap IsOpenMap.id)
end Distrib
@@ -810,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
@@ -828,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
@@ -896,12 +958,27 @@ 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
-protected lemma denseEmbedding : DenseEmbedding f := (hf.homeomorph f).denseEmbedding
+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
end IsHomeomorph
@@ -918,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 :=
@@ -946,14 +1026,14 @@ lemma IsHomeomorph.sumMap {g : Z → W} (hf : IsHomeomorph f) (hg : IsHomeomorph
IsHomeomorph (Sum.map f g) := ⟨hf.1.sum_map hg.1, hf.2.sumMap hg.2, hf.3.sum_map hg.3⟩
lemma IsHomeomorph.prodMap {g : Z → W} (hf : IsHomeomorph f) (hg : IsHomeomorph g) :
- IsHomeomorph (Prod.map f g) := ⟨hf.1.prod_map hg.1, hf.2.prod hg.2, hf.3.prodMap hg.3⟩
+ IsHomeomorph (Prod.map f g) := ⟨hf.1.prodMap hg.1, hf.2.prodMap hg.2, hf.3.prodMap hg.3⟩
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/Basic.lean b/Mathlib/Topology/Homotopy/Basic.lean
index caf0e3a6983a5..e736983bd8031 100644
--- a/Mathlib/Topology/Homotopy/Basic.lean
+++ b/Mathlib/Topology/Homotopy/Basic.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Shing Tak Lam
-/
import Mathlib.Topology.Order.ProjIcc
-import Mathlib.Topology.ContinuousFunction.Ordered
+import Mathlib.Topology.ContinuousMap.Ordered
import Mathlib.Topology.CompactOpen
import Mathlib.Topology.UnitInterval
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 93fad3a1199db..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.prod_map
+ (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 f4f888556c776..c0065281d89e6 100644
--- a/Mathlib/Topology/Inseparable.lean
+++ b/Mathlib/Topology/Inseparable.lean
@@ -5,6 +5,7 @@ Authors: Andrew Yang, Yury Kudryashov
-/
import Mathlib.Tactic.TFAE
import Mathlib.Topology.ContinuousOn
+import Mathlib.Topology.Maps.OpenQuotient
/-!
# Inseparable points in a topological space
@@ -53,20 +54,15 @@ theorem specializes_TFAE (x y : X) :
y ∈ closure ({ x } : Set X),
closure ({ y } : Set X) ⊆ closure { x },
ClusterPt y (pure x)] := by
- tfae_have 1 → 2
- · exact (pure_le_nhds _).trans
- tfae_have 2 → 3
- · exact fun h s hso hy => h (hso.mem_nhds hy)
- tfae_have 3 → 4
- · exact fun h s hsc hx => of_not_not fun hy => h sᶜ hsc.isOpen_compl hy hx
- tfae_have 4 → 5
- · exact fun h => h _ isClosed_closure (subset_closure <| mem_singleton _)
- tfae_have 6 ↔ 5
- · exact isClosed_closure.closure_subset_iff.trans singleton_subset_iff
- tfae_have 5 ↔ 7
- · rw [mem_closure_iff_clusterPt, principal_singleton]
- tfae_have 5 → 1
- · refine fun h => (nhds_basis_opens _).ge_iff.2 ?_
+ tfae_have 1 → 2 := (pure_le_nhds _).trans
+ tfae_have 2 → 3 := fun h s hso hy => h (hso.mem_nhds hy)
+ tfae_have 3 → 4 := fun h s hsc hx => of_not_not fun hy => h sᶜ hsc.isOpen_compl hy hx
+ tfae_have 4 → 5 := fun h => h _ isClosed_closure (subset_closure <| mem_singleton _)
+ tfae_have 6 ↔ 5 := isClosed_closure.closure_subset_iff.trans singleton_subset_iff
+ tfae_have 5 ↔ 7 := by
+ rw [mem_closure_iff_clusterPt, principal_singleton]
+ tfae_have 5 → 1 := by
+ refine fun h => (nhds_basis_opens _).ge_iff.2 ?_
rintro s ⟨hy, ho⟩
rcases mem_closure_iff.1 h s ho hy with ⟨z, hxs, rfl : z = x⟩
exact ho.mem_nhds hxs
@@ -136,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
@@ -150,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
@@ -361,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) :=
@@ -436,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
@@ -514,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) :=
@@ -551,27 +563,32 @@ 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⟩
theorem preimage_image_mk_closed (hs : IsClosed s) : mk ⁻¹' (mk '' s) = s := by
refine Subset.antisymm ?_ (subset_preimage_image _ _)
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]
@@ -604,14 +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 → _) := by
- have hsurj : Surjective (Prod.map mk mk : X × Y → _) := surjective_mk.prodMap surjective_mk
- refine quotientMap_iff.2 ⟨hsurj, fun s ↦ ?_⟩
- refine ⟨fun hs ↦ hs.preimage (continuous_mk.prod_map continuous_mk), fun hs ↦ ?_⟩
- refine isOpen_iff_mem_nhds.2 <| hsurj.forall.2 fun (x, y) h ↦ ?_
- rw [Prod.map_mk, nhds_prod_eq, ← map_mk_nhds, ← map_mk_nhds, Filter.prod_map_map_eq',
- ← nhds_prod_eq, Filter.mem_map]
- exact hs.mem_nhds h
+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 → α`. -/
@@ -713,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 30a63f58660fd..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 𝕜] :
@@ -461,7 +458,7 @@ def setAddOrderOfEquiv {n : ℕ} (hn : 0 < n) :
obtain ⟨m, hm⟩ := h
rw [← mul_div_right_comm, eq_div_iff, mul_comm, ← zsmul_eq_mul, mul_smul_comm, ←
nsmul_eq_mul, ← natCast_zsmul, smul_smul,
- (zsmul_strictMono_left hp.out).injective.eq_iff, mul_comm] at hm
+ zsmul_left_inj hp.out, mul_comm] at hm
swap
· exact Nat.cast_ne_zero.2 hn.ne'
rw [← @Nat.cast_inj ℤ, ← sub_eq_zero]
@@ -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 1bd41163d0387..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
@@ -39,7 +39,7 @@ theorem Complex.subfield_eq_of_closed {K : Subfield ℂ} (hc : IsClosed (K : Set
simp only [Function.comp_apply, ofReal_ratCast, SetLike.mem_coe, SubfieldClass.ratCast_mem]
nth_rw 1 [range_comp]
refine subset_trans ?_ (image_closure_subset_closure_image continuous_ofReal)
- rw [DenseRange.closure_range Rat.denseEmbedding_coe_real.dense]
+ rw [DenseRange.closure_range Rat.isDenseEmbedding_coe_real.dense]
simp only [image_univ]
rfl
@@ -52,32 +52,32 @@ 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.denseInducing (?_ : DenseRange ι)
+ let di := ui.isDenseInducing (?_ : DenseRange ι)
· -- extψ : closure(K) →+* ℂ is the extension of ψ : K →+* ℂ
- let extψ := DenseInducing.extendRingHom ui di.dense hc
+ let extψ := IsDenseInducing.extendRingHom ui di.dense hc
haveI hψ := (uniformContinuous_uniformly_extend ui di.dense hc).continuous
cases' Complex.subfield_eq_of_closed (Subfield.isClosed_topologicalClosure K) with h h
· left
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 (DenseInducing.extend_eq di hc.continuous _).symm
- · rw [← ofReal.coe_rangeRestrict, hr]
+ · exact (IsDenseInducing.extend_eq di hc.continuous _).symm
+ · rw [← ofRealHom.coe_rangeRestrict, hr]
rfl
obtain ⟨r, hr⟩ := SetLike.coe_mem (j (ι x))
exact ⟨r, Subtype.ext hr⟩
@@ -94,11 +94,11 @@ theorem Complex.uniformContinuous_ringHom_eq_id_or_conj (K : Subfield ℂ) {ψ :
· left
ext1 z
convert RingHom.congr_fun h z using 1
- exact (DenseInducing.extend_eq di hc.continuous z).symm
+ exact (IsDenseInducing.extend_eq di hc.continuous z).symm
· right
ext1 z
convert RingHom.congr_fun h z using 1
- exact (DenseInducing.extend_eq di hc.continuous z).symm
+ exact (IsDenseInducing.extend_eq di hc.continuous z).symm
· let j : { x // x ∈ closure (id '' { x | (K : Set ℂ) x }) } → (K.topologicalClosure : Set ℂ) :=
fun x =>
⟨x, by
@@ -106,7 +106,7 @@ theorem Complex.uniformContinuous_ringHom_eq_id_or_conj (K : Subfield ℂ) {ψ :
simp only [id, Set.image_id']
rfl ⟩
convert DenseRange.comp (Function.Surjective.denseRange _)
- (DenseEmbedding.subtype denseEmbedding_id (K : Set ℂ)).dense (by continuity : Continuous j)
+ (IsDenseEmbedding.id.subtype (K : Set ℂ)).dense (by continuity : Continuous j)
rintro ⟨y, hy⟩
use
⟨y, by
diff --git a/Mathlib/Topology/Instances/ENNReal.lean b/Mathlib/Topology/Instances/ENNReal.lean
index 631eda52d1417..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.prod 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 (𝓝 ∞) :=
@@ -390,11 +396,11 @@ protected theorem continuous_pow (n : ℕ) : Continuous fun a : ℝ≥0∞ => a
simp_rw [pow_add, pow_one, continuous_iff_continuousAt]
intro x
refine ENNReal.Tendsto.mul (IH.tendsto _) ?_ tendsto_id ?_ <;> by_cases H : x = 0
- · simp only [H, zero_ne_top, Ne, or_true_iff, not_false_iff]
+ · simp only [H, zero_ne_top, Ne, or_true, not_false_iff]
· exact Or.inl fun h => H (pow_eq_zero h)
- · simp only [H, pow_eq_top_iff, zero_ne_top, false_or_iff, eq_self_iff_true, not_true, Ne,
- not_false_iff, false_and_iff]
- · simp only [H, true_or_iff, Ne, not_false_iff]
+ · simp only [H, pow_eq_top_iff, zero_ne_top, false_or, eq_self_iff_true, not_true, Ne,
+ not_false_iff, false_and]
+ · simp only [H, true_or, Ne, not_false_iff]
theorem continuousOn_sub :
ContinuousOn (fun p : ℝ≥0∞ × ℝ≥0∞ => p.fst - p.snd) { p : ℝ≥0∞ × ℝ≥0∞ | p ≠ ⟨∞, ∞⟩ } := by
@@ -406,7 +412,7 @@ theorem continuousOn_sub :
theorem continuous_sub_left {a : ℝ≥0∞} (a_ne_top : a ≠ ∞) : Continuous (a - ·) := by
change Continuous (Function.uncurry Sub.sub ∘ (a, ·))
refine continuousOn_sub.comp_continuous (Continuous.Prod.mk a) fun x => ?_
- simp only [a_ne_top, Ne, mem_setOf_eq, Prod.mk.inj_iff, false_and_iff, not_false_iff]
+ simp only [a_ne_top, Ne, mem_setOf_eq, Prod.mk.inj_iff, false_and, not_false_iff]
theorem continuous_nnreal_sub {a : ℝ≥0} : Continuous fun x : ℝ≥0∞ => (a : ℝ≥0∞) - x :=
continuous_sub_left coe_ne_top
@@ -419,11 +425,11 @@ 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
- simp only [a_infty, Ne, mem_setOf_eq, Prod.mk.inj_iff, and_false_iff, not_false_iff]
+ simp only [a_infty, Ne, mem_setOf_eq, Prod.mk.inj_iff, and_false, not_false_iff]
protected theorem Tendsto.pow {f : Filter α} {m : α → ℝ≥0∞} {a : ℝ≥0∞} {n : ℕ}
(hm : Tendsto m f (𝓝 a)) : Tendsto (fun x => m x ^ n) f (𝓝 (a ^ n)) :=
@@ -435,34 +441,28 @@ theorem le_of_forall_lt_one_mul_le {x y : ℝ≥0∞} (h : ∀ a < 1, a * x ≤
rw [one_mul] at this
exact le_of_tendsto this (eventually_nhdsWithin_iff.2 <| Eventually.of_forall h)
+@[deprecated mul_iInf' (since := "2024-09-12")]
theorem iInf_mul_left' {ι} {f : ι → ℝ≥0∞} {a : ℝ≥0∞} (h : a = ∞ → ⨅ i, f i = 0 → ∃ i, f i = 0)
- (h0 : a = 0 → Nonempty ι) : ⨅ i, a * f i = a * ⨅ i, f i := by
- by_cases H : a = ∞ ∧ ⨅ i, f i = 0
- · rcases h H.1 H.2 with ⟨i, hi⟩
- rw [H.2, mul_zero, ← bot_eq_zero, iInf_eq_bot]
- exact fun b hb => ⟨i, by rwa [hi, mul_zero, ← bot_eq_zero]⟩
- · rw [not_and_or] at H
- cases isEmpty_or_nonempty ι
- · rw [iInf_of_empty, iInf_of_empty, mul_top]
- exact mt h0 (not_nonempty_iff.2 ‹_›)
- · exact (ENNReal.mul_left_mono.map_ciInf_of_continuousAt
- (ENNReal.continuousAt_const_mul H)).symm
+ (h0 : a = 0 → Nonempty ι) : ⨅ i, a * f i = a * ⨅ i, f i := .symm <| mul_iInf' h h0
+@[deprecated mul_iInf (since := "2024-09-12")]
theorem iInf_mul_left {ι} [Nonempty ι] {f : ι → ℝ≥0∞} {a : ℝ≥0∞}
(h : a = ∞ → ⨅ i, f i = 0 → ∃ i, f i = 0) : ⨅ i, a * f i = a * ⨅ i, f i :=
- iInf_mul_left' h fun _ => ‹Nonempty ι›
+ .symm <| mul_iInf h
+@[deprecated iInf_mul' (since := "2024-09-12")]
theorem iInf_mul_right' {ι} {f : ι → ℝ≥0∞} {a : ℝ≥0∞} (h : a = ∞ → ⨅ i, f i = 0 → ∃ i, f i = 0)
- (h0 : a = 0 → Nonempty ι) : ⨅ i, f i * a = (⨅ i, f i) * a := by
- simpa only [mul_comm a] using iInf_mul_left' h h0
+ (h0 : a = 0 → Nonempty ι) : ⨅ i, f i * a = (⨅ i, f i) * a := .symm <| iInf_mul' h h0
+@[deprecated iInf_mul (since := "2024-09-12")]
theorem iInf_mul_right {ι} [Nonempty ι] {f : ι → ℝ≥0∞} {a : ℝ≥0∞}
- (h : a = ∞ → ⨅ i, f i = 0 → ∃ i, f i = 0) : ⨅ i, f i * a = (⨅ i, f i) * a :=
- iInf_mul_right' h fun _ => ‹Nonempty ι›
+ (h : a = ∞ → ⨅ i, f i = 0 → ∃ i, f i = 0) : ⨅ i, f i * a = (⨅ i, f i) * a := .symm <| iInf_mul h
+@[deprecated inv_iInf (since := "2024-09-12")]
theorem inv_map_iInf {ι : Sort*} {x : ι → ℝ≥0∞} : (iInf x)⁻¹ = ⨆ i, (x i)⁻¹ :=
OrderIso.invENNReal.map_iInf x
+@[deprecated inv_iSup (since := "2024-09-12")]
theorem inv_map_iSup {ι : Sort*} {x : ι → ℝ≥0∞} : (iSup x)⁻¹ = ⨅ i, (x i)⁻¹ :=
OrderIso.invENNReal.map_iSup x
@@ -504,115 +504,10 @@ protected theorem Tendsto.div_const {f : Filter α} {m : α → ℝ≥0∞} {a b
protected theorem tendsto_inv_nat_nhds_zero : Tendsto (fun n : ℕ => (n : ℝ≥0∞)⁻¹) atTop (𝓝 0) :=
ENNReal.inv_top ▸ ENNReal.tendsto_inv_iff.2 tendsto_nat_nhds_top
-theorem iSup_add {ι : Sort*} {s : ι → ℝ≥0∞} [Nonempty ι] : iSup s + a = ⨆ b, s b + a :=
- Monotone.map_ciSup_of_continuousAt (continuousAt_id.add continuousAt_const) <|
- monotone_id.add monotone_const
-
-theorem biSup_add' {ι : Sort*} {p : ι → Prop} (h : ∃ i, p i) {f : ι → ℝ≥0∞} :
- (⨆ (i) (_ : p i), f i) + a = ⨆ (i) (_ : p i), f i + a := by
- haveI : Nonempty { i // p i } := nonempty_subtype.2 h
- simp only [iSup_subtype', iSup_add]
-
-theorem add_biSup' {ι : Sort*} {p : ι → Prop} (h : ∃ i, p i) {f : ι → ℝ≥0∞} :
- (a + ⨆ (i) (_ : p i), f i) = ⨆ (i) (_ : p i), a + f i := by
- simp only [add_comm a, biSup_add' h]
-
-theorem biSup_add {ι} {s : Set ι} (hs : s.Nonempty) {f : ι → ℝ≥0∞} :
- (⨆ i ∈ s, f i) + a = ⨆ i ∈ s, f i + a :=
- biSup_add' hs
-
-theorem add_biSup {ι} {s : Set ι} (hs : s.Nonempty) {f : ι → ℝ≥0∞} :
- (a + ⨆ i ∈ s, f i) = ⨆ i ∈ s, a + f i :=
- add_biSup' hs
-
-theorem sSup_add {s : Set ℝ≥0∞} (hs : s.Nonempty) : sSup s + a = ⨆ b ∈ s, b + a := by
- rw [sSup_eq_iSup, biSup_add hs]
-
-theorem add_iSup {ι : Sort*} {s : ι → ℝ≥0∞} [Nonempty ι] : a + iSup s = ⨆ b, a + s b := by
- rw [add_comm, iSup_add]; simp [add_comm]
-
-theorem iSup_add_iSup_le {ι ι' : Sort*} [Nonempty ι] [Nonempty ι'] {f : ι → ℝ≥0∞} {g : ι' → ℝ≥0∞}
- {a : ℝ≥0∞} (h : ∀ i j, f i + g j ≤ a) : iSup f + iSup g ≤ a := by
- simp_rw [iSup_add, add_iSup]; exact iSup₂_le h
-
-theorem biSup_add_biSup_le' {ι ι'} {p : ι → Prop} {q : ι' → Prop} (hp : ∃ i, p i) (hq : ∃ j, q j)
- {f : ι → ℝ≥0∞} {g : ι' → ℝ≥0∞} {a : ℝ≥0∞} (h : ∀ i, p i → ∀ j, q j → f i + g j ≤ a) :
- ((⨆ (i) (_ : p i), f i) + ⨆ (j) (_ : q j), g j) ≤ a := by
- simp_rw [biSup_add' hp, add_biSup' hq]
- exact iSup₂_le fun i hi => iSup₂_le (h i hi)
-
-theorem biSup_add_biSup_le {ι ι'} {s : Set ι} {t : Set ι'} (hs : s.Nonempty) (ht : t.Nonempty)
- {f : ι → ℝ≥0∞} {g : ι' → ℝ≥0∞} {a : ℝ≥0∞} (h : ∀ i ∈ s, ∀ j ∈ t, f i + g j ≤ a) :
- ((⨆ i ∈ s, f i) + ⨆ j ∈ t, g j) ≤ a :=
- biSup_add_biSup_le' hs ht h
-
-theorem iSup_add_iSup {ι : Sort*} {f g : ι → ℝ≥0∞} (h : ∀ i j, ∃ k, f i + g j ≤ f k + g k) :
- iSup f + iSup g = ⨆ a, f a + g a := by
- cases isEmpty_or_nonempty ι
- · simp only [iSup_of_empty, bot_eq_zero, zero_add]
- · refine le_antisymm ?_ (iSup_le fun a => add_le_add (le_iSup _ _) (le_iSup _ _))
- refine iSup_add_iSup_le fun i j => ?_
- rcases h i j with ⟨k, hk⟩
- exact le_iSup_of_le k hk
-
-theorem iSup_add_iSup_of_monotone {ι : Type*} [Preorder ι] [IsDirected ι (· ≤ ·)]
- {f g : ι → ℝ≥0∞} (hf : Monotone f) (hg : Monotone g) : iSup f + iSup g = ⨆ a, f a + g a :=
- iSup_add_iSup fun i j ↦ (exists_ge_ge i j).imp fun _k ⟨hi, hj⟩ ↦ by gcongr <;> apply_rules
-
-theorem finsetSum_iSup {α ι : Type*} {s : Finset α} {f : α → ι → ℝ≥0∞}
- (hf : ∀ i j, ∃ k, ∀ a, f a i ≤ f a k ∧ f a j ≤ f a k) :
- ∑ a ∈ s, ⨆ i, f a i = ⨆ i, ∑ a ∈ s, f a i := by
- induction s using Finset.cons_induction with
- | empty => simp
- | cons a s ha ihs =>
- simp_rw [Finset.sum_cons, ihs]
- refine iSup_add_iSup fun i j ↦ (hf i j).imp fun k hk ↦ ?_
- gcongr
- exacts [(hk a).1, (hk _).2]
-
-theorem finsetSum_iSup_of_monotone {α} {ι} [Preorder ι] [IsDirected ι (· ≤ ·)]
- {s : Finset α} {f : α → ι → ℝ≥0∞} (hf : ∀ a, Monotone (f a)) :
- (∑ a ∈ s, iSup (f a)) = ⨆ n, ∑ a ∈ s, f a n :=
- finsetSum_iSup fun i j ↦ (exists_ge_ge i j).imp fun _k ⟨hi, hj⟩ a ↦ ⟨hf a hi, hf a hj⟩
-
-@[deprecated (since := "2024-07-14")]
-alias finset_sum_iSup_nat := finsetSum_iSup_of_monotone
-
-theorem mul_iSup {ι : Sort*} {f : ι → ℝ≥0∞} {a : ℝ≥0∞} : a * iSup f = ⨆ i, a * f i := by
- by_cases hf : ∀ i, f i = 0
- · obtain rfl : f = fun _ => 0 := funext hf
- simp only [iSup_zero_eq_zero, mul_zero]
- · refine (monotone_id.const_mul' _).map_iSup_of_continuousAt ?_ (mul_zero a)
- refine ENNReal.Tendsto.const_mul tendsto_id (Or.inl ?_)
- exact mt iSup_eq_zero.1 hf
-
-theorem mul_sSup {s : Set ℝ≥0∞} {a : ℝ≥0∞} : a * sSup s = ⨆ i ∈ s, a * i := by
- simp only [sSup_eq_iSup, mul_iSup]
-
-theorem iSup_mul {ι : Sort*} {f : ι → ℝ≥0∞} {a : ℝ≥0∞} : iSup f * a = ⨆ i, f i * a := by
- rw [mul_comm, mul_iSup]; congr; funext; rw [mul_comm]
-
-theorem smul_iSup {ι : Sort*} {R} [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] (f : ι → ℝ≥0∞)
- (c : R) : (c • ⨆ i, f i) = ⨆ i, c • f i := by
- -- Porting note: replaced `iSup _` with `iSup f`
- simp only [← smul_one_mul c (f _), ← smul_one_mul c (iSup f), ENNReal.mul_iSup]
-
-theorem smul_sSup {R} [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] (s : Set ℝ≥0∞) (c : R) :
- c • sSup s = ⨆ i ∈ s, c • i := by
- -- Porting note: replaced `_` with `s`
- simp_rw [← smul_one_mul c (sSup s), ENNReal.mul_sSup, smul_one_mul]
-
-theorem iSup_div {ι : Sort*} {f : ι → ℝ≥0∞} {a : ℝ≥0∞} : iSup f / a = ⨆ i, f i / a :=
- iSup_mul
-
protected theorem tendsto_coe_sub {b : ℝ≥0∞} :
Tendsto (fun b : ℝ≥0∞ => ↑r - b) (𝓝 b) (𝓝 (↑r - b)) :=
continuous_nnreal_sub.tendsto _
-theorem sub_iSup {ι : Sort*} [Nonempty ι] {b : ι → ℝ≥0∞} (hr : a < ∞) :
- (a - ⨆ i, b i) = ⨅ i, a - b i :=
- antitone_const_tsub.map_ciSup_of_continuousAt (continuous_sub_left hr.ne).continuousAt
-
theorem exists_countable_dense_no_zero_top :
∃ s : Set ℝ≥0∞, s.Countable ∧ Dense s ∧ 0 ∉ s ∧ ∞ ∉ s := by
obtain ⟨s, s_count, s_dense, hs⟩ :
@@ -620,19 +515,7 @@ theorem exists_countable_dense_no_zero_top :
exists_countable_dense_no_bot_top ℝ≥0∞
exact ⟨s, s_count, s_dense, fun h => hs.1 0 (by simp) h, fun h => hs.2 ∞ (by simp) h⟩
-theorem exists_lt_add_of_lt_add {x y z : ℝ≥0∞} (h : x < y + z) (hy : y ≠ 0) (hz : z ≠ 0) :
- ∃ y' z', y' < y ∧ z' < z ∧ x < y' + z' := by
- have : NeZero y := ⟨hy⟩
- have : NeZero z := ⟨hz⟩
- have A : Tendsto (fun p : ℝ≥0∞ × ℝ≥0∞ => p.1 + p.2) (𝓝[<] y ×ˢ 𝓝[<] z) (𝓝 (y + z)) := by
- apply Tendsto.mono_left _ (Filter.prod_mono nhdsWithin_le_nhds nhdsWithin_le_nhds)
- rw [← nhds_prod_eq]
- exact tendsto_add
- rcases ((A.eventually (lt_mem_nhds h)).and
- (Filter.prod_mem_prod self_mem_nhdsWithin self_mem_nhdsWithin)).exists with
- ⟨⟨y', z'⟩, hx, hy', hz'⟩
- exact ⟨y', z', hy', hz', hx⟩
-
+@[deprecated ofReal_iInf (since := "2024-09-12")]
theorem ofReal_cinfi (f : α → ℝ) [Nonempty α] :
ENNReal.ofReal (⨅ i, f i) = ⨅ i, ENNReal.ofReal (f i) := by
by_cases hf : BddBelow (range f)
@@ -805,7 +688,7 @@ theorem tsum_const_eq_top_of_ne_zero {α : Type*} [Infinite α] {c : ℝ≥0∞}
∑' _ : α, c = ∞ := by
have A : Tendsto (fun n : ℕ => (n : ℝ≥0∞) * c) atTop (𝓝 (∞ * c)) := by
apply ENNReal.Tendsto.mul_const tendsto_nat_nhds_top
- simp only [true_or_iff, top_ne_zero, Ne, not_false_iff]
+ simp only [true_or, top_ne_zero, Ne, not_false_iff]
have B : ∀ n : ℕ, (n : ℝ≥0∞) * c ≤ ∑' _ : α, c := fun n => by
rcases Infinite.exists_subset_card_eq α n with ⟨s, hs⟩
simpa [hs] using @ENNReal.sum_le_tsum α (fun _ => c) s
@@ -948,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
@@ -1213,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
@@ -1236,7 +1119,7 @@ open EMetric
theorem tendsto_iff_edist_tendsto_0 {l : Filter β} {f : β → α} {y : α} :
Tendsto f l (𝓝 y) ↔ Tendsto (fun x => edist (f x) y) l (𝓝 0) := by
simp only [EMetric.nhds_basis_eball.tendsto_right_iff, EMetric.mem_ball,
- @tendsto_order ℝ≥0∞ β _ _, forall_prop_of_false ENNReal.not_lt_zero, forall_const, true_and_iff]
+ @tendsto_order ℝ≥0∞ β _ _, forall_prop_of_false ENNReal.not_lt_zero, forall_const, true_and]
/-- Yet another metric characterization of Cauchy sequences on integers. This one is often the
most efficient. -/
@@ -1460,9 +1343,11 @@ section LimsupLiminf
variable {ι : Type*}
-lemma limsup_sub_const (F : Filter ι) [NeBot F] (f : ι → ℝ≥0∞) (c : ℝ≥0∞) :
- 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 : ℝ≥0∞) ↦ x - c)
+lemma limsup_sub_const (F : Filter ι) (f : ι → ℝ≥0∞) (c : ℝ≥0∞) :
+ Filter.limsup (fun i ↦ f i - c) F = Filter.limsup f F - c := by
+ rcases F.eq_or_neBot with rfl | _
+ · simp only [limsup_bot, bot_eq_zero', zero_le, tsub_eq_zero_of_le]
+ · exact (Monotone.map_limsSup_of_continuousAt (F := F.map f) (f := fun (x : ℝ≥0∞) ↦ x - c)
(fun _ _ h ↦ tsub_le_tsub_right h c) (continuous_sub_right c).continuousAt).symm
lemma liminf_sub_const (F : Filter ι) [NeBot F] (f : ι → ℝ≥0∞) (c : ℝ≥0∞) :
@@ -1470,18 +1355,45 @@ lemma liminf_sub_const (F : Filter ι) [NeBot F] (f : ι → ℝ≥0∞) (c :
(Monotone.map_limsInf_of_continuousAt (F := F.map f) (f := fun (x : ℝ≥0∞) ↦ x - c)
(fun _ _ h ↦ tsub_le_tsub_right h c) (continuous_sub_right c).continuousAt).symm
-lemma limsup_const_sub (F : Filter ι) [NeBot F] (f : ι → ℝ≥0∞)
- {c : ℝ≥0∞} (c_ne_top : c ≠ ∞) :
- Filter.limsup (fun i ↦ c - f i) F = c - Filter.liminf f F :=
- (Antitone.map_limsInf_of_continuousAt (F := F.map f) (f := fun (x : ℝ≥0∞) ↦ c - x)
+lemma limsup_const_sub (F : Filter ι) (f : ι → ℝ≥0∞) {c : ℝ≥0∞} (c_ne_top : c ≠ ∞) :
+ Filter.limsup (fun i ↦ c - f i) F = c - Filter.liminf f F := by
+ rcases F.eq_or_neBot with rfl | _
+ · simp only [limsup_bot, bot_eq_zero', liminf_bot, le_top, tsub_eq_zero_of_le]
+ · exact (Antitone.map_limsInf_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 liminf_const_sub (F : Filter ι) [NeBot F] (f : ι → ℝ≥0∞)
- {c : ℝ≥0∞} (c_ne_top : c ≠ ∞) :
+lemma liminf_const_sub (F : Filter ι) [NeBot F] (f : ι → ℝ≥0∞) {c : ℝ≥0∞} (c_ne_top : c ≠ ∞) :
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 : ℝ≥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) :
@@ -1524,5 +1436,3 @@ lemma limsup_toReal_eq {ι : Type*} {F : Filter ι} [NeBot F] {b : ℝ≥0∞} (
end LimsupLiminf
end ENNReal -- namespace
-
-set_option linter.style.longFile 1700
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 5ad8821215f37..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.prod 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 -/
@@ -145,26 +157,50 @@ theorem tendsto_nhds_bot_iff_real {α : Type*} {m : α → EReal} {f : Filter α
Tendsto m f (𝓝 ⊥) ↔ ∀ x : ℝ, ∀ᶠ a in f, m a < x :=
nhds_bot_basis.tendsto_right_iff.trans <| by simp only [true_implies, mem_Iio]
+lemma nhdsWithin_top : 𝓝[≠] (⊤ : EReal) = (atTop).map Real.toEReal := by
+ apply (nhdsWithin_hasBasis nhds_top_basis_Ici _).ext (atTop_basis.map Real.toEReal)
+ · simp only [EReal.image_coe_Ici, true_and]
+ intro x hx
+ by_cases hx_bot : x = ⊥
+ · simp [hx_bot]
+ lift x to ℝ using ⟨hx.ne_top, hx_bot⟩
+ refine ⟨x, fun x ⟨h1, h2⟩ ↦ ?_⟩
+ simp [h1, h2.ne_top]
+ · simp only [EReal.image_coe_Ici, true_implies]
+ refine fun x ↦ ⟨x, ⟨EReal.coe_lt_top x, fun x ⟨(h1 : _ ≤ x), h2⟩ ↦ ?_⟩⟩
+ simp [h1, Ne.lt_top' fun a ↦ h2 a.symm]
+
+lemma nhdsWithin_bot : 𝓝[≠] (⊥ : EReal) = (atBot).map Real.toEReal := by
+ apply (nhdsWithin_hasBasis nhds_bot_basis_Iic _).ext (atBot_basis.map Real.toEReal)
+ · simp only [EReal.image_coe_Iic, Set.subset_compl_singleton_iff, Set.mem_Ioc, lt_self_iff_false,
+ bot_le, and_true, not_false_eq_true, true_and]
+ intro x hx
+ by_cases hx_top : x = ⊤
+ · simp [hx_top]
+ lift x to ℝ using ⟨hx_top, hx.ne_bot⟩
+ refine ⟨x, fun x ⟨h1, h2⟩ ↦ ?_⟩
+ simp [h2, h1.ne_bot]
+ · simp only [EReal.image_coe_Iic, true_implies]
+ refine fun x ↦ ⟨x, ⟨EReal.bot_lt_coe x, fun x ⟨(h1 : x ≤ _), h2⟩ ↦ ?_⟩⟩
+ simp [h1, Ne.bot_lt' fun a ↦ h2 a.symm]
+
+lemma tendsto_toReal_atTop : Tendsto EReal.toReal (𝓝[≠] ⊤) atTop := by
+ rw [nhdsWithin_top, tendsto_map'_iff]
+ exact tendsto_id
+
+lemma tendsto_toReal_atBot : Tendsto EReal.toReal (𝓝[≠] ⊥) atBot := by
+ rw [nhdsWithin_bot, tendsto_map'_iff]
+ exact tendsto_id
+
/-! ### Infs and Sups -/
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 -/
@@ -191,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
@@ -323,7 +359,7 @@ private lemma continuousAt_mul_symm1 {a b : EReal}
simp
rw [this]
apply ContinuousAt.comp (Continuous.continuousAt continuous_neg)
- <| ContinuousAt.comp _ (ContinuousAt.prod_map (Continuous.continuousAt continuous_neg)
+ <| ContinuousAt.comp _ (ContinuousAt.prodMap (Continuous.continuousAt continuous_neg)
(Continuous.continuousAt continuous_id))
simp [h]
diff --git a/Mathlib/Topology/Instances/Int.lean b/Mathlib/Topology/Instances/Int.lean
index eae87217dd5dc..536b95e356e15 100644
--- a/Mathlib/Topology/Instances/Int.lean
+++ b/Mathlib/Topology/Instances/Int.lean
@@ -8,7 +8,7 @@ import Mathlib.Data.Int.SuccPred
import Mathlib.Data.Int.ConditionallyCompleteOrder
import Mathlib.Topology.Instances.Discrete
import Mathlib.Topology.MetricSpace.Bounded
-import Mathlib.Order.Filter.Archimedean
+import Mathlib.Order.Filter.AtTopBot.Archimedean
import Mathlib.Topology.MetricSpace.Basic
/-!
@@ -39,13 +39,19 @@ theorem pairwise_one_le_dist : Pairwise fun m n : ℤ => 1 ≤ dist m n := by
intro m n hne
rw [dist_eq]; norm_cast; rwa [← zero_add (1 : ℤ), Int.add_one_le_iff, abs_pos, sub_ne_zero]
-theorem uniformEmbedding_coe_real : UniformEmbedding ((↑) : ℤ → ℝ) :=
- uniformEmbedding_bot_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist
+theorem isUniformEmbedding_coe_real : IsUniformEmbedding ((↑) : ℤ → ℝ) :=
+ isUniformEmbedding_bot_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist
-theorem closedEmbedding_coe_real : ClosedEmbedding ((↑) : ℤ → ℝ) :=
- closedEmbedding_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_coe_real := isUniformEmbedding_coe_real
-instance : MetricSpace ℤ := Int.uniformEmbedding_coe_real.comapMetricSpace _
+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 _
theorem preimage_ball (x : ℤ) (r : ℝ) : (↑) ⁻¹' ball (x : ℝ) r = ball x r := rfl
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 2e4857faf7c51..c5719cb578fc2 100644
--- a/Mathlib/Topology/Instances/Nat.lean
+++ b/Mathlib/Topology/Instances/Nat.lean
@@ -31,13 +31,19 @@ theorem dist_cast_real (x y : ℕ) : dist (x : ℝ) y = dist x y := rfl
theorem pairwise_one_le_dist : Pairwise fun m n : ℕ => 1 ≤ dist m n := fun _ _ hne =>
Int.pairwise_one_le_dist <| mod_cast hne
-theorem uniformEmbedding_coe_real : UniformEmbedding ((↑) : ℕ → ℝ) :=
- uniformEmbedding_bot_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist
+theorem isUniformEmbedding_coe_real : IsUniformEmbedding ((↑) : ℕ → ℝ) :=
+ isUniformEmbedding_bot_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist
-theorem closedEmbedding_coe_real : ClosedEmbedding ((↑) : ℕ → ℝ) :=
- closedEmbedding_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_coe_real := isUniformEmbedding_coe_real
-instance : MetricSpace ℕ := Nat.uniformEmbedding_coe_real.comapMetricSpace _
+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 _
theorem preimage_ball (x : ℕ) (r : ℝ) : (↑) ⁻¹' ball (x : ℝ) r = ball x r := rfl
diff --git a/Mathlib/Topology/Instances/PNat.lean b/Mathlib/Topology/Instances/PNat.lean
index 3a05c74ac7076..dd79778f35d9b 100644
--- a/Mathlib/Topology/Instances/PNat.lean
+++ b/Mathlib/Topology/Instances/PNat.lean
@@ -24,7 +24,10 @@ theorem dist_eq (x y : ℕ+) : dist x y = |(↑x : ℝ) - ↑y| := rfl
@[simp, norm_cast]
theorem dist_coe (x y : ℕ+) : dist (↑x : ℕ) (↑y : ℕ) = dist x y := rfl
-theorem uniformEmbedding_coe : UniformEmbedding ((↑) : ℕ+ → ℕ) := uniformEmbedding_subtype_val
+theorem isUniformEmbedding_coe : IsUniformEmbedding ((↑) : ℕ+ → ℕ) := isUniformEmbedding_subtype_val
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_coe := isUniformEmbedding_coe
instance : DiscreteTopology ℕ+ := inferInstanceAs (DiscreteTopology { n : ℕ // 0 < n })
diff --git a/Mathlib/Topology/Instances/Rat.lean b/Mathlib/Topology/Instances/Rat.lean
index 1fd5e8eaa6966..a09e2b65750df 100644
--- a/Mathlib/Topology/Instances/Rat.lean
+++ b/Mathlib/Topology/Instances/Rat.lean
@@ -30,14 +30,23 @@ theorem dist_cast (x y : ℚ) : dist (x : ℝ) y = dist x y :=
theorem uniformContinuous_coe_real : UniformContinuous ((↑) : ℚ → ℝ) :=
uniformContinuous_comap
-theorem uniformEmbedding_coe_real : UniformEmbedding ((↑) : ℚ → ℝ) :=
- uniformEmbedding_comap Rat.cast_injective
+theorem isUniformEmbedding_coe_real : IsUniformEmbedding ((↑) : ℚ → ℝ) :=
+ isUniformEmbedding_comap Rat.cast_injective
-theorem denseEmbedding_coe_real : DenseEmbedding ((↑) : ℚ → ℝ) :=
- uniformEmbedding_coe_real.denseEmbedding Rat.denseRange_cast
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_coe_real := isUniformEmbedding_coe_real
-theorem embedding_coe_real : Embedding ((↑) : ℚ → ℝ) :=
- denseEmbedding_coe_real.to_embedding
+theorem isDenseEmbedding_coe_real : IsDenseEmbedding ((↑) : ℚ → ℝ) :=
+ isUniformEmbedding_coe_real.isDenseEmbedding Rat.denseRange_cast
+
+@[deprecated (since := "2024-09-30")]
+alias denseEmbedding_coe_real := isDenseEmbedding_coe_real
+
+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
@@ -48,31 +57,43 @@ end Rat
theorem Nat.dist_cast_rat (x y : ℕ) : dist (x : ℚ) y = dist x y := by
rw [← Nat.dist_cast_real, ← Rat.dist_cast]; congr
-theorem Nat.uniformEmbedding_coe_rat : UniformEmbedding ((↑) : ℕ → ℚ) :=
- uniformEmbedding_bot_of_pairwise_le_dist zero_lt_one <| by simpa using Nat.pairwise_one_le_dist
+theorem Nat.isUniformEmbedding_coe_rat : IsUniformEmbedding ((↑) : ℕ → ℚ) :=
+ isUniformEmbedding_bot_of_pairwise_le_dist zero_lt_one <| by simpa using Nat.pairwise_one_le_dist
+
+@[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
rw [← Int.dist_cast_real, ← Rat.dist_cast]; congr
-theorem Int.uniformEmbedding_coe_rat : UniformEmbedding ((↑) : ℤ → ℚ) :=
- uniformEmbedding_bot_of_pairwise_le_dist zero_lt_one <| by simpa using Int.pairwise_one_le_dist
+theorem Int.isUniformEmbedding_coe_rat : IsUniformEmbedding ((↑) : ℤ → ℚ) :=
+ isUniformEmbedding_bot_of_pairwise_le_dist zero_lt_one <| by simpa using Int.pairwise_one_le_dist
+
+@[deprecated (since := "2024-10-01")]
+alias Int.uniformEmbedding_coe_rat := Int.isUniformEmbedding_coe_rat
+
+theorem Int.isClosedEmbedding_coe_rat : IsClosedEmbedding ((↑) : ℤ → ℚ) :=
+ isClosedEmbedding_of_pairwise_le_dist zero_lt_one <| by simpa using Int.pairwise_one_le_dist
-theorem Int.closedEmbedding_coe_rat : ClosedEmbedding ((↑) : ℤ → ℚ) :=
- closedEmbedding_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.uniformEmbedding_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.prod_map Rat.uniformContinuous_coe_real)
+ (Rat.uniformContinuous_coe_real.prodMap Rat.uniformContinuous_coe_real)
theorem uniformContinuous_neg : UniformContinuous (@Neg.neg ℚ _) :=
Metric.uniformContinuous_iff.2 fun ε ε0 =>
@@ -94,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.uniformEmbedding_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 b94351980b416..1f633201490d0 100644
--- a/Mathlib/Topology/Instances/RatLemmas.lean
+++ b/Mathlib/Topology/Instances/RatLemmas.lean
@@ -36,10 +36,10 @@ 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 = ∅ :=
- denseEmbedding_coe_real.toDenseInducing.interior_compact_eq_empty dense_irrational hs
+ isDenseEmbedding_coe_real.toIsDenseInducing.interior_compact_eq_empty dense_irrational hs
theorem dense_compl_compact (hs : IsCompact s) : Dense sᶜ :=
interior_eq_empty_iff_dense_compl.1 (interior_compact_eq_empty 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 5b895c2cdeb63..38e3de8b03bad 100644
--- a/Mathlib/Topology/Instances/Real.lean
+++ b/Mathlib/Topology/Instances/Real.lean
@@ -3,21 +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
-/
-import Mathlib.Data.Real.Star
-import Mathlib.Algebra.Algebra.Basic
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.UniformMulAction
import Mathlib.Topology.Algebra.Star
+import Mathlib.Topology.Algebra.UniformMulAction
import Mathlib.Topology.Instances.Int
import Mathlib.Topology.Order.Bornology
-import Mathlib.Topology.Metrizable.Basic
+import Mathlib.Topology.Algebra.UniformGroup.Defs
/-!
# Topological properties of ℝ
-/
+assert_not_exists UniformOnFun
+
noncomputable section
open Filter Int Metric Set TopologicalSpace Bornology
@@ -27,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 =>
@@ -60,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]
@@ -141,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'],
@@ -183,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/RealVectorSpace.lean b/Mathlib/Topology/Instances/RealVectorSpace.lean
index a7eaa801c1d9f..5d4327d792021 100644
--- a/Mathlib/Topology/Instances/RealVectorSpace.lean
+++ b/Mathlib/Topology/Instances/RealVectorSpace.lean
@@ -23,7 +23,7 @@ theorem map_real_smul {G} [FunLike G E F] [AddMonoidHomClass G E F] (f : G) (hf
(c : ℝ) (x : E) :
f (c • x) = c • f x :=
suffices (fun c : ℝ => f (c • x)) = fun c : ℝ => c • f x from congr_fun this c
- Rat.denseEmbedding_coe_real.dense.equalizer (hf.comp <| continuous_id.smul continuous_const)
+ Rat.isDenseEmbedding_coe_real.dense.equalizer (hf.comp <| continuous_id.smul continuous_const)
(continuous_id.smul continuous_const) (funext fun r => map_ratCast_smul f ℝ ℝ r x)
namespace AddMonoidHom
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 c76906356f367..9a25326df9e83 100644
--- a/Mathlib/Topology/KrullDimension.lean
+++ b/Mathlib/Topology/KrullDimension.lean
@@ -12,16 +12,55 @@ import Mathlib.Topology.Sets.Closeds
The Krull dimension of a topological space is the order theoretic Krull dimension applied to the
collection of all its subsets that are closed and irreducible. Unfolding this definition, it is
the length of longest series of closed irreducible subsets ordered by inclusion.
-
-TODO: The Krull dimension of `Spec(R)` equals the Krull dimension of `R`, for `R` a commutative
- ring.
-/
-open TopologicalSpace
+open TopologicalSpace Order
/--
The Krull dimension of a topological space is the supremum of lengths of chains of
closed irreducible sets.
-/
noncomputable def topologicalKrullDim (T : Type*) [TopologicalSpace T] : WithBot ℕ∞ :=
- Order.krullDim (IrreducibleCloseds T)
+ krullDim (IrreducibleCloseds T)
+
+variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y]
+
+/--
+Map induced on irreducible closed subsets by a closed continuous map `f`.
+This is just a wrapper around the image of `f` together with proofs that it
+preserves irreducibility (by continuity) and closedness (since `f` is closed).
+-/
+def IrreducibleCloseds.map {f : X → Y} (hf1 : Continuous f) (hf2 : IsClosedMap f)
+ (c : IrreducibleCloseds X) :
+ IrreducibleCloseds Y where
+ carrier := f '' c
+ is_irreducible' := c.is_irreducible'.image f hf1.continuousOn
+ is_closed' := hf2 c c.is_closed'
+
+/--
+Taking images under a closed embedding is strictly monotone on the preorder of irreducible closeds.
+-/
+lemma IrreducibleCloseds.map_strictMono {f : X → Y} (hf : IsClosedEmbedding f) :
+ StrictMono (IrreducibleCloseds.map hf.continuous hf.isClosedMap) :=
+ fun ⦃_ _⦄ UltV ↦ hf.inj.image_strictMono UltV
+
+/--
+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 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 :=
+ IsClosedEmbedding.topologicalKrullDim_le f h.isClosedEmbedding
+ have bwd : topologicalKrullDim Y ≤ topologicalKrullDim X :=
+ 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 2cb3f5399de36..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]
@@ -150,8 +159,8 @@ lemma isLocallyClosed_tfae (s : Set X) :
∀ x ∈ s, ∃ U ∈ 𝓝 x, IsClosed (U ↓∩ s),
∀ x ∈ s, ∃ U, x ∈ U ∧ IsOpen U ∧ U ∩ closure s ⊆ s,
IsOpen (closure s ↓∩ s)] := by
- tfae_have 1 → 2
- · rintro ⟨U, Z, hU, hZ, rfl⟩
+ tfae_have 1 → 2 := by
+ rintro ⟨U, Z, hU, hZ, rfl⟩
have : Z ∪ (frontier (U ∩ Z))ᶜ = univ := by
nth_rw 1 [← hZ.closure_eq]
rw [← compl_subset_iff_union, compl_subset_compl]
@@ -160,24 +169,24 @@ lemma isLocallyClosed_tfae (s : Set X) :
inter_univ]
exact hU.union isClosed_frontier.isOpen_compl
tfae_have 2 → 3
- · exact fun h x ↦ (⟨coborder s, h.mem_nhds <| subset_coborder ·, isClosed_preimage_val_coborder⟩)
+ | h, x => (⟨coborder s, h.mem_nhds <| subset_coborder ·, isClosed_preimage_val_coborder⟩)
tfae_have 3 → 4
- · intro h x hx
+ | h, x, hx => by
obtain ⟨t, ht, ht'⟩ := h x hx
obtain ⟨U, hUt, hU, hxU⟩ := mem_nhds_iff.mp ht
rw [isClosed_preimage_val] at ht'
exact ⟨U, hxU, hU, (subset_inter (inter_subset_left.trans hUt) (hU.inter_closure.trans
(closure_mono <| inter_subset_inter hUt subset_rfl))).trans ht'⟩
tfae_have 4 → 5
- · intro H
+ | H => by
choose U hxU hU e using H
refine ⟨⋃ x ∈ s, U x ‹_›, isOpen_iUnion (isOpen_iUnion <| hU ·), ext fun x ↦ ⟨?_, ?_⟩⟩
· rintro ⟨_, ⟨⟨y, rfl⟩, ⟨_, ⟨hy, rfl⟩, hxU⟩⟩⟩
exact e y hy ⟨hxU, x.2⟩
· exact (subset_iUnion₂ _ _ <| hxU x ·)
tfae_have 5 → 1
- · intro H
- convert H.isLocallyClosed.image inducing_subtype_val
+ | H => by
+ 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 bc918bf4803b5..916e783447b5b 100644
--- a/Mathlib/Topology/LocallyConstant/Basic.lean
+++ b/Mathlib/Topology/LocallyConstant/Basic.lean
@@ -39,18 +39,15 @@ protected theorem tfae (f : X → Y) :
∀ x, IsOpen { x' | f x' = f x },
∀ y, IsOpen (f ⁻¹' {y}),
∀ x, ∃ U : Set X, IsOpen U ∧ x ∈ U ∧ ∀ x' ∈ U, f x' = f x] := by
- tfae_have 1 → 4
- · exact fun h y => h {y}
- tfae_have 4 → 3
- · exact fun h x => h (f x)
- tfae_have 3 → 2
- · exact fun h x => IsOpen.mem_nhds (h x) rfl
+ tfae_have 1 → 4 := fun h y => h {y}
+ tfae_have 4 → 3 := fun h x => h (f x)
+ tfae_have 3 → 2 := fun h x => IsOpen.mem_nhds (h x) rfl
tfae_have 2 → 5
- · intro h x
+ | h, x => by
rcases mem_nhds_iff.1 (h x) with ⟨U, eq, hU, hx⟩
exact ⟨U, hU, hx, eq⟩
tfae_have 5 → 1
- · intro h s
+ | h, s => by
refine isOpen_iff_forall_mem_open.2 fun x hx ↦ ?_
rcases h x with ⟨U, hU, hxU, eq⟩
exact ⟨U, fun x' hx' => mem_preimage.2 <| (eq x' hx').symm ▸ hx, hU, hxU⟩
@@ -361,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 e50f6343087cb..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_iff]
+@[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
new file mode 100644
index 0000000000000..4f593b59638a1
--- /dev/null
+++ b/Mathlib/Topology/Maps/OpenQuotient.lean
@@ -0,0 +1,73 @@
+/-
+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.Maps.Basic
+
+/-!
+# Open quotient maps
+
+An open quotient map is an open map `f : X → Y` which is both an open map and a quotient map.
+Equivalently, it is a surjective continuous open map.
+We use the latter characterization as a definition.
+
+Many important quotient maps are open quotient maps, including
+
+- the quotient map from a topological space to its quotient by the action of a group;
+- the quotient map from a topological group to its quotient by a normal subgroup;
+- the quotient map from a topological spaace to its separation quotient.
+
+Contrary to general quotient maps,
+the category of open quotient maps is closed under `Prod.map`.
+-/
+
+open Function Set Filter
+open scoped Topology
+
+variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] {f : X → Y}
+
+namespace IsOpenQuotientMap
+
+protected theorem id : IsOpenQuotientMap (id : X → X) := ⟨surjective_id, continuous_id, .id⟩
+
+/-- An open quotient map is a quotient map. -/
+theorem isQuotientMap (h : IsOpenQuotientMap f) : IsQuotientMap f :=
+ h.isOpenMap.isQuotientMap h.continuous h.surjective
+
+@[deprecated (since := "2024-10-22")]
+alias quotientMap := isQuotientMap
+
+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_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) :=
+ ⟨.comp hg.1 hf.1, .comp hg.2 hf.2, .comp hg.3 hf.3⟩
+
+theorem map_nhds_eq (h : IsOpenQuotientMap f) (x : X) : map f (𝓝 x) = 𝓝 (f x) :=
+ le_antisymm h.continuous.continuousAt <| h.isOpenMap.nhds_le _
+
+theorem continuous_comp_iff (h : IsOpenQuotientMap f) {g : Y → Z} :
+ Continuous (g ∘ f) ↔ Continuous g :=
+ 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
+ simp only [ContinuousAt, ← h.map_nhds_eq, tendsto_map'_iff, comp_def]
+
+theorem dense_preimage_iff (h : IsOpenQuotientMap f) {s : Set Y} : Dense (f ⁻¹' s) ↔ Dense s :=
+ ⟨fun hs ↦ h.surjective.denseRange.dense_of_mapsTo h.continuous hs (mapsTo_preimage _ _),
+ fun hs ↦ hs.preimage h.isOpenMap⟩
+
+end IsOpenQuotientMap
diff --git a/Mathlib/Topology/Maps/Proper/Basic.lean b/Mathlib/Topology/Maps/Proper/Basic.lean
index 4132dd33262f6..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.
@@ -174,12 +159,12 @@ lemma isProperMap_of_comp_of_t2 [T2Space Y] (hf : Continuous f) (hg : Continuous
exact ⟨x, hx⟩
/-- A binary product of proper maps is proper. -/
-lemma IsProperMap.prod_map {g : Z → W} (hf : IsProperMap f) (hg : IsProperMap g) :
+lemma IsProperMap.prodMap {g : Z → W} (hf : IsProperMap f) (hg : IsProperMap g) :
IsProperMap (Prod.map f g) := by
simp_rw [isProperMap_iff_ultrafilter] at hf hg ⊢
constructor
-- Continuity is clear.
- · exact hf.1.prod_map hg.1
+ · exact hf.1.prodMap hg.1
-- Let `𝒰 : Ultrafilter (X × Z)`, and assume that `f × g` tends to some `(y, w) : Y × W`
-- along `𝒰`.
· intro 𝒰 ⟨y, w⟩ hyw
@@ -197,6 +182,8 @@ lemma IsProperMap.prod_map {g : Z → W} (hf : IsProperMap f) (hg : IsProperMap
rw [nhds_prod_eq, le_prod]
exact ⟨hx, hz⟩
+@[deprecated (since := "2024-10-06")] alias IsProperMap.prod_map := IsProperMap.prodMap
+
/-- Any product of proper maps is proper. -/
lemma IsProperMap.pi_map {X Y : ι → Type*} [∀ i, TopologicalSpace (X i)]
[∀ i, TopologicalSpace (Y i)] {f : (i : ι) → X i → Y i} (h : ∀ i, IsProperMap (f i)) :
@@ -286,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) :=
@@ -320,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
@@ -416,7 +322,7 @@ easier to use because it allows `Z` to live in any universe. -/
theorem IsProperMap.universally_closed (Z) [TopologicalSpace Z] (h : IsProperMap f) :
IsClosedMap (Prod.map f id : X × Z → Y × Z) :=
-- `f × id` is proper as a product of proper maps, hence closed.
- (h.prod_map isProperMap_id).isClosedMap
+ (h.prodMap isProperMap_id).isClosedMap
/-- A map `f : X → Y` is proper if and only if it is continuous and the map
`(Prod.map f id : X × Filter X → Y × Filter X)` is closed. This is stronger than
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 c2d744b24f070..e8a16f85a6d7a 100644
--- a/Mathlib/Topology/MetricSpace/Algebra.lean
+++ b/Mathlib/Topology/MetricSpace/Algebra.lean
@@ -4,6 +4,8 @@ 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
/-!
@@ -143,6 +145,11 @@ instance (priority := 100) BoundedSMul.continuousSMul : ContinuousSMul α β whe
gcongr
_ < ε := hδε
+instance (priority := 100) BoundedSMul.toUniformContinuousConstSMul :
+ UniformContinuousConstSMul α β :=
+ ⟨fun c => ((lipschitzWith_iff_dist_le_mul (K := nndist c 0)).2 fun _ _ =>
+ dist_smul_pair c _ _).uniformContinuous⟩
+
-- this instance could be deduced from `NormedSpace.boundedSMul`, but we prove it separately
-- here so that it is available earlier in the hierarchy
instance Real.boundedSMul : BoundedSMul ℝ ℝ where
@@ -179,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
@@ -207,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 88e3996a46af3..809699925af5d 100644
--- a/Mathlib/Topology/MetricSpace/Antilipschitz.lean
+++ b/Mathlib/Topology/MetricSpace/Antilipschitz.lean
@@ -143,28 +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⟩
-protected theorem uniformEmbedding {α : Type*} {β : Type*} [EMetricSpace α] [PseudoEMetricSpace β]
- {K : ℝ≥0} {f : α → β} (hf : AntilipschitzWith K f) (hfc : UniformContinuous f) :
- UniformEmbedding f :=
- ⟨hf.uniformInducing hfc, hf.injective⟩
+@[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.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.uniformEmbedding 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 f3b2468b6e50b..7ba147f5faf72 100644
--- a/Mathlib/Topology/MetricSpace/Basic.lean
+++ b/Mathlib/Topology/MetricSpace/Basic.lean
@@ -32,11 +32,14 @@ instance (priority := 100) _root_.MetricSpace.instT0Space : T0Space γ where
/-- A map between metric spaces is a uniform embedding if and only if the distance between `f x`
and `f y` is controlled in terms of the distance between `x` and `y` and conversely. -/
-theorem uniformEmbedding_iff' [MetricSpace β] {f : γ → β} :
- UniformEmbedding f ↔
+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 [uniformEmbedding_iff_uniformInducing, uniformInducing_iff, uniformContinuous_iff]
+ rw [isUniformEmbedding_iff_isUniformInducing, isUniformInducing_iff, uniformContinuous_iff]
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_iff' := isUniformEmbedding_iff'
/-- If a `PseudoMetricSpace` is a T₀ space, then it is a `MetricSpace`. -/
abbrev _root_.MetricSpace.ofT0PseudoMetricSpace (α : Type*) [PseudoMetricSpace α] [T0Space α] :
@@ -53,17 +56,23 @@ 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 `β`. -/
-theorem uniformEmbedding_bot_of_pairwise_le_dist {β : Type*} {ε : ℝ} (hε : 0 < ε) {f : β → α}
+theorem isUniformEmbedding_bot_of_pairwise_le_dist {β : Type*} {ε : ℝ} (hε : 0 < ε) {f : β → α}
(hf : Pairwise fun x y => ε ≤ dist (f x) (f y)) :
- @UniformEmbedding _ _ ⊥ (by infer_instance) f :=
- uniformEmbedding_of_spaced_out (dist_mem_uniformity hε) <| by simpa using hf
+ @IsUniformEmbedding _ _ ⊥ (by infer_instance) f :=
+ isUniformEmbedding_of_spaced_out (dist_mem_uniformity hε) <| by simpa using hf
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_bot_of_pairwise_le_dist := isUniformEmbedding_bot_of_pairwise_le_dist
end Metric
@@ -94,15 +103,21 @@ abbrev MetricSpace.induced {γ β} (f : γ → β) (hf : Function.Injective f) (
/-- Pull back a metric space structure by a uniform embedding. This is a version of
`MetricSpace.induced` useful in case if the domain already has a `UniformSpace` structure. -/
-abbrev UniformEmbedding.comapMetricSpace {α β} [UniformSpace α] [m : MetricSpace β] (f : α → β)
- (h : UniformEmbedding f) : MetricSpace α :=
+abbrev IsUniformEmbedding.comapMetricSpace {α β} [UniformSpace α] [m : MetricSpace β] (f : α → β)
+ (h : IsUniformEmbedding f) : MetricSpace α :=
.replaceUniformity (.induced f h.inj m) h.comap_uniformity.symm
+@[deprecated (since := "2024-10-03")]
+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 67b9d4cbf3244..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,17 +224,20 @@ 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
/-- `NonemptyCompacts.toCloseds` is a uniform embedding (as it is an isometry) -/
-theorem NonemptyCompacts.ToCloseds.uniformEmbedding :
- UniformEmbedding (@NonemptyCompacts.toCloseds α _ _) :=
- Isometry.uniformEmbedding fun _ _ => rfl
+theorem NonemptyCompacts.ToCloseds.isUniformEmbedding :
+ IsUniformEmbedding (@NonemptyCompacts.toCloseds α _ _) :=
+ Isometry.isUniformEmbedding fun _ _ => rfl
+
+@[deprecated (since := "2024-10-01")]
+alias NonemptyCompacts.ToCloseds.uniformEmbedding := NonemptyCompacts.ToCloseds.isUniformEmbedding
/-- The range of `NonemptyCompacts.toCloseds` is closed in a complete space -/
theorem NonemptyCompacts.isClosed_in_closeds [CompleteSpace α] :
@@ -278,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.uniformEmbedding.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.uniformEmbedding.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/Completion.lean b/Mathlib/Topology/MetricSpace/Completion.lean
index 8d667f11c999c..97c5f07d31c6e 100644
--- a/Mathlib/Topology/MetricSpace/Completion.lean
+++ b/Mathlib/Topology/MetricSpace/Completion.lean
@@ -6,6 +6,8 @@ Authors: Sébastien Gouëzel
import Mathlib.Topology.UniformSpace.Completion
import Mathlib.Topology.MetricSpace.Isometry
import Mathlib.Topology.MetricSpace.Lipschitz
+import Mathlib.Topology.MetricSpace.Algebra
+import Mathlib.Topology.Algebra.GroupCompletion
import Mathlib.Topology.Instances.Real
/-!
@@ -103,7 +105,7 @@ protected theorem mem_uniformity_dist (s : Set (Completion α × Completion α))
· have Z := hε (not_le.1 h)
simp only [Set.mem_setOf_eq] at Z
exact Or.inr Z
- simp only [not_le.mpr hxy, false_or_iff, not_le] at this
+ simp only [not_le.mpr hxy, false_or, not_le] at this
exact ts this
· /- Start from a set `s` containing an ε-neighborhood of the diagonal in `Completion α`. To show
that it is an entourage, we use the fact that `dist` is uniformly continuous on
@@ -168,6 +170,27 @@ theorem coe_isometry : Isometry ((↑) : α → Completion α) :=
protected theorem edist_eq (x y : α) : edist (x : Completion α) y = edist x y :=
coe_isometry x y
+instance {M} [Zero M] [Zero α] [SMul M α] [PseudoMetricSpace M] [BoundedSMul M α] :
+ BoundedSMul M (Completion α) where
+ dist_smul_pair' c x₁ x₂ := by
+ induction x₁, x₂ using induction_on₂ with
+ | hp =>
+ exact isClosed_le
+ ((continuous_fst.const_smul _).dist (continuous_snd.const_smul _))
+ (continuous_const.mul (continuous_fst.dist continuous_snd))
+ | ih x₁ x₂ =>
+ rw [← coe_smul, ← coe_smul, Completion.dist_eq, Completion.dist_eq]
+ exact dist_smul_pair c x₁ x₂
+ dist_pair_smul' c₁ c₂ x := by
+ induction x using induction_on with
+ | hp =>
+ exact isClosed_le
+ ((continuous_const_smul _).dist (continuous_const_smul _))
+ (continuous_const.mul (continuous_id.dist continuous_const))
+ | ih x =>
+ rw [← coe_smul, ← coe_smul, Completion.dist_eq, ← coe_zero, Completion.dist_eq]
+ exact dist_pair_smul c₁ c₂ x
+
end UniformSpace.Completion
open UniformSpace Completion NNReal
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 c68a245846375..3e66eb3f4f28b 100644
--- a/Mathlib/Topology/MetricSpace/Dilation.lean
+++ b/Mathlib/Topology/MetricSpace/Dilation.lean
@@ -66,7 +66,7 @@ infixl:25 " →ᵈ " => Dilation
/-- `DilationClass F α β r` states that `F` is a type of `r`-dilations.
You should extend this typeclass when you extend `Dilation`. -/
-class DilationClass (F α β : Type*) [PseudoEMetricSpace α] [PseudoEMetricSpace β]
+class DilationClass (F : Type*) (α β : outParam Type*) [PseudoEMetricSpace α] [PseudoEMetricSpace β]
[FunLike F α β] : Prop where
edist_eq' : ∀ f : F, ∃ r : ℝ≥0, r ≠ 0 ∧ ∀ x y : α, edist (f x) (f y) = r * edist x y
@@ -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
@@ -420,19 +420,26 @@ variable [EMetricSpace α]
variable [FunLike F α β]
/-- A dilation from a metric space is a uniform embedding -/
-protected theorem uniformEmbedding [PseudoEMetricSpace β] [DilationClass F α β] (f : F) :
- UniformEmbedding f :=
- (antilipschitz f).uniformEmbedding (lipschitz f).uniformContinuous
+lemma isUniformEmbedding [PseudoEMetricSpace β] [DilationClass F α β] (f : F) :
+ IsUniformEmbedding f :=
+ (antilipschitz f).isUniformEmbedding (lipschitz f).uniformContinuous
+
+@[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.uniformEmbedding 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 acc49b78007c1..7082a492d3c8f 100644
--- a/Mathlib/Topology/MetricSpace/GromovHausdorff.lean
+++ b/Mathlib/Topology/MetricSpace/GromovHausdorff.lean
@@ -282,7 +282,7 @@ theorem hausdorffDist_optimal {X : Type u} [MetricSpace X] [CompactSpace X] [Non
let F : (X ⊕ Y) × (X ⊕ Y) → ℝ := fun p => dist (f p.1) (f p.2)
-- check that the induced "distance" is a candidate
have Fgood : F ∈ candidates X Y := by
- simp only [F, candidates, forall_const, and_true_iff, add_comm, eq_self_iff_true,
+ simp only [F, candidates, forall_const, add_comm, eq_self_iff_true,
dist_eq_zero, and_self_iff, Set.mem_setOf_eq]
repeat' constructor
· exact fun x y =>
@@ -398,7 +398,7 @@ instance : MetricSpace GHSpace where
· exact ⟨0, by rintro b ⟨⟨u, v⟩, -, rfl⟩; exact hausdorffDist_nonneg⟩
· simp only [mem_image, mem_prod, mem_setOf_eq, Prod.exists]
exists y, y
- simpa only [and_self_iff, hausdorffDist_self_zero, eq_self_iff_true, and_true_iff]
+ simpa only [and_self_iff, hausdorffDist_self_zero, eq_self_iff_true, and_true]
· apply le_csInf
· exact Set.Nonempty.image _ <| Set.Nonempty.prod ⟨y, hy⟩ ⟨y, hy⟩
· rintro b ⟨⟨u, v⟩, -, rfl⟩; exact hausdorffDist_nonneg
@@ -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 f343b3d1c3901..1610895150222 100644
--- a/Mathlib/Topology/MetricSpace/GromovHausdorffRealized.lean
+++ b/Mathlib/Topology/MetricSpace/GromovHausdorffRealized.lean
@@ -5,7 +5,7 @@ Authors: Sébastien Gouëzel
-/
import Mathlib.Topology.MetricSpace.Gluing
import Mathlib.Topology.MetricSpace.HausdorffDistance
-import Mathlib.Topology.ContinuousFunction.Bounded
+import Mathlib.Topology.ContinuousMap.Bounded
/-!
# The Gromov-Hausdorff distance is realized
@@ -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 1018155f553a7..eba2e6682959f 100644
--- a/Mathlib/Topology/MetricSpace/HausdorffDimension.lean
+++ b/Mathlib/Topology/MetricSpace/HausdorffDimension.lean
@@ -84,7 +84,7 @@ Hausdorff measure, Hausdorff dimension, dimension
open scoped MeasureTheory ENNReal NNReal Topology
-open MeasureTheory MeasureTheory.Measure Set TopologicalSpace FiniteDimensional Filter
+open MeasureTheory MeasureTheory.Measure Set TopologicalSpace Module Filter
variable {ι X Y : Type*} [EMetricSpace X] [EMetricSpace Y]
@@ -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) :
@@ -441,7 +441,7 @@ theorem dimH_univ_pi_fin (n : ℕ) : dimH (univ : Set (Fin n → ℝ)) = n := by
theorem dimH_of_mem_nhds {x : E} {s : Set E} (h : s ∈ 𝓝 x) : dimH s = finrank ℝ E := by
have e : E ≃L[ℝ] Fin (finrank ℝ E) → ℝ :=
- ContinuousLinearEquiv.ofFinrankEq (FiniteDimensional.finrank_fin_fun ℝ).symm
+ ContinuousLinearEquiv.ofFinrankEq (Module.finrank_fin_fun ℝ).symm
rw [← e.dimH_image]
refine le_antisymm ?_ ?_
· exact (dimH_mono (subset_univ _)).trans_eq (dimH_univ_pi_fin _)
@@ -459,7 +459,7 @@ theorem dimH_univ_eq_finrank : dimH (univ : Set E) = finrank ℝ E :=
dimH_of_mem_nhds (@univ_mem _ (𝓝 0))
theorem dimH_univ : dimH (univ : Set ℝ) = 1 := by
- rw [dimH_univ_eq_finrank ℝ, FiniteDimensional.finrank_self, Nat.cast_one]
+ rw [dimH_univ_eq_finrank ℝ, Module.finrank_self, Nat.cast_one]
variable {E}
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 027a2e3139f9c..c47889bcd8b41 100644
--- a/Mathlib/Topology/MetricSpace/Infsep.lean
+++ b/Mathlib/Topology/MetricSpace/Infsep.lean
@@ -171,7 +171,7 @@ end EDist
section PseudoEMetricSpace
-variable [PseudoEMetricSpace α] {x y z : α} {s t : Set α}
+variable [PseudoEMetricSpace α] {x y z : α} {s : Set α}
theorem einfsep_pair (hxy : x ≠ y) : ({x, y} : Set α).einfsep = edist x y := by
nth_rw 1 [← min_self (edist x y)]
@@ -238,7 +238,7 @@ end PseudoMetricSpace
section EMetricSpace
-variable [EMetricSpace α] {x y z : α} {s t : Set α} {C : ℝ≥0∞} {sC : Set ℝ≥0∞}
+variable [EMetricSpace α] {s : Set α}
theorem einfsep_pos_of_finite [Finite s] : 0 < s.einfsep := by
cases nonempty_fintype s
@@ -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
@@ -312,7 +312,7 @@ end EDist
section PseudoEMetricSpace
-variable [PseudoEMetricSpace α] {x y : α} {s : Set α}
+variable [PseudoEMetricSpace α] {x y : α}
theorem infsep_pair_eq_toReal : ({x, y} : Set α).infsep = (edist x y).toReal := by
by_cases hxy : x = y
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 fc48af3ac67e9..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
@@ -162,17 +168,24 @@ protected theorem injective (h : Isometry f) : Injective f :=
h.antilipschitz.injective
/-- An isometry from an emetric space is a uniform embedding -/
-protected theorem uniformEmbedding (hf : Isometry f) : UniformEmbedding f :=
- hf.antilipschitz.uniformEmbedding hf.lipschitz.uniformContinuous
+lemma isUniformEmbedding (hf : Isometry f) : IsUniformEmbedding f :=
+ hf.antilipschitz.isUniformEmbedding hf.lipschitz.uniformContinuous
+
+@[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.uniformEmbedding.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
@@ -226,18 +239,24 @@ end Isometry
-- namespace
/-- A uniform embedding from a uniform space to a metric space is an isometry with respect to the
induced metric space structure on the source space. -/
-theorem UniformEmbedding.to_isometry {α β} [UniformSpace α] [MetricSpace β] {f : α → β}
- (h : UniformEmbedding f) : (letI := h.comapMetricSpace f; Isometry f) :=
+theorem IsUniformEmbedding.to_isometry {α β} [UniformSpace α] [MetricSpace β] {f : α → β}
+ (h : IsUniformEmbedding f) : (letI := h.comapMetricSpace f; Isometry f) :=
let _ := h.comapMetricSpace f
Isometry.of_dist_eq fun _ _ => rfl
+@[deprecated (since := "2024-10-01")]
+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]
@@ -448,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
@@ -465,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 b001d3c706ab2..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
@@ -786,7 +786,7 @@ theorem min_dist_le_dist_pi (x y : ∀ i, F i) (i : ι) :
theorem dist_le_dist_pi_of_dist_lt {x y : ∀ i, F i} {i : ι} (h : dist x y < (1 / 2) ^ encode i) :
dist (x i) (y i) ≤ dist x y := by
- simpa only [not_le.2 h, false_or_iff] using min_le_iff.1 (min_dist_le_dist_pi x y i)
+ simpa only [not_le.2 h, false_or] using min_le_iff.1 (min_dist_le_dist_pi x y i)
open Topology Filter NNReal
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 5793a4509ed7c..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,26 +59,35 @@ 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]
-nonrec theorem uniformEmbedding_iff [PseudoMetricSpace β] {f : α → β} :
- UniformEmbedding f ↔ Function.Injective f ∧ UniformContinuous f ∧
+@[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 [uniformEmbedding_iff, and_comm, uniformInducing_iff]
+ rw [isUniformEmbedding_iff, and_comm, isUniformInducing_iff]
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_iff := isUniformEmbedding_iff
/-- If a map between pseudometric spaces is a uniform embedding then the distance between `f x`
and `f y` is controlled in terms of the distance between `x` and `y`. -/
-theorem controlled_of_uniformEmbedding [PseudoMetricSpace β] {f : α → β} (h : UniformEmbedding f) :
+theorem controlled_of_isUniformEmbedding [PseudoMetricSpace β] {f : α → β}
+ (h : 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 < δ :=
- ⟨uniformContinuous_iff.1 h.uniformContinuous, (uniformEmbedding_iff.1 h).2.2⟩
+ ⟨uniformContinuous_iff.1 h.uniformContinuous, (isUniformEmbedding_iff.1 h).2.2⟩
+
+@[deprecated (since := "2024-10-01")]
+alias controlled_of_uniformEmbedding := controlled_of_isUniformEmbedding
theorem totallyBounded_iff {s : Set α} :
TotallyBounded s ↔ ∀ ε > 0, ∃ t : Set α, t.Finite ∧ s ⊆ ⋃ y ∈ t, ball y ε :=
@@ -153,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) :
@@ -169,8 +180,20 @@ end Metric
open Metric
+theorem Metric.inseparable_iff_nndist {x y : α} : Inseparable x y ↔ nndist x y = 0 := by
+ rw [EMetric.inseparable_iff, edist_nndist, ENNReal.coe_eq_zero]
+
+alias ⟨Inseparable.nndist_eq_zero, _⟩ := Metric.inseparable_iff_nndist
+
theorem Metric.inseparable_iff {x y : α} : Inseparable x y ↔ dist x y = 0 := by
- rw [EMetric.inseparable_iff, edist_nndist, dist_nndist, ENNReal.coe_eq_zero, NNReal.coe_eq_zero]
+ rw [Metric.inseparable_iff_nndist, dist_nndist, NNReal.coe_eq_zero]
+
+alias ⟨Inseparable.dist_eq_zero, _⟩ := Metric.inseparable_iff
+
+/-- A weaker version of `tendsto_nhds_unique` for `PseudoMetricSpace`. -/
+theorem tendsto_nhds_unique_dist {f : β → α} {l : Filter β} {x y : α} [NeBot l]
+ (ha : Tendsto f l (𝓝 x)) (hb : Tendsto f l (𝓝 y)) : dist x y = 0 :=
+ (tendsto_nhds_unique_inseparable ha hb).dist_eq_zero
section Real
@@ -182,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 cfaf85d8f63ea..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]
@@ -766,7 +775,7 @@ theorem tendsto_nhdsWithin_nhds [PseudoMetricSpace β] {f : α → β} {a b} :
Tendsto f (𝓝[s] a) (𝓝 b) ↔
∀ ε > 0, ∃ δ > 0, ∀ {x : α}, x ∈ s → dist x a < δ → dist (f x) b < ε := by
rw [← nhdsWithin_univ b, tendsto_nhdsWithin_nhdsWithin]
- simp only [mem_univ, true_and_iff]
+ simp only [mem_univ, true_and]
theorem tendsto_nhds_nhds [PseudoMetricSpace β] {f : α → β} {a b} :
Tendsto f (𝓝 a) (𝓝 b) ↔ ∀ ε > 0, ∃ δ > 0, ∀ {x : α}, dist x a < δ → dist (f x) b < ε :=
@@ -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/ShrinkingLemma.lean b/Mathlib/Topology/MetricSpace/ShrinkingLemma.lean
index 058f2115e3541..b7b081e3fb55d 100644
--- a/Mathlib/Topology/MetricSpace/ShrinkingLemma.lean
+++ b/Mathlib/Topology/MetricSpace/ShrinkingLemma.lean
@@ -27,7 +27,7 @@ open Set Metric
open Topology
variable {α : Type u} {ι : Type v} [MetricSpace α] [ProperSpace α] {c : ι → α}
-variable {x : α} {r : ℝ} {s : Set α}
+variable {s : Set α}
/-- **Shrinking lemma** for coverings by open balls in a proper metric space. A point-finite open
cover of a closed subset of a proper metric space by open balls can be shrunk to a new cover by
diff --git a/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean b/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean
index c274fbbc8e376..b3e9cec910f90 100644
--- a/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean
+++ b/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean
@@ -3,8 +3,8 @@ 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.Topology.ContinuousFunction.Bounded
+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/Basic.lean b/Mathlib/Topology/MetricSpace/Ultra/Basic.lean
index 5b00adb8cfda9..ceccb0c003e73 100644
--- a/Mathlib/Topology/MetricSpace/Ultra/Basic.lean
+++ b/Mathlib/Topology/MetricSpace/Ultra/Basic.lean
@@ -50,6 +50,18 @@ lemma dist_triangle_max : dist x z ≤ max (dist x y) (dist y z) :=
namespace IsUltrametricDist
+/-- All triangles are isosceles in an ultrametric space. -/
+lemma dist_eq_max_of_dist_ne_dist (h : dist x y ≠ dist y z) :
+ dist x z = max (dist x y) (dist y z) := by
+ apply le_antisymm (dist_triangle_max x y z)
+ rcases h.lt_or_lt with h | h
+ · rw [max_eq_right h.le]
+ apply (le_max_iff.mp <| dist_triangle_max y x z).resolve_left
+ simpa only [not_le, dist_comm x y] using h
+ · rw [max_eq_left h.le, dist_comm x y, dist_comm x z]
+ apply (le_max_iff.mp <| dist_triangle_max y z x).resolve_left
+ simpa only [not_le, dist_comm x y] using h
+
instance subtype (p : X → Prop) : IsUltrametricDist (Subtype p) :=
⟨fun _ _ _ ↦ by simpa [Subtype.dist_eq] using dist_triangle_max _ _ _⟩
diff --git a/Mathlib/Topology/MetricSpace/Ultra/ContinuousMaps.lean b/Mathlib/Topology/MetricSpace/Ultra/ContinuousMaps.lean
new file mode 100644
index 0000000000000..62dd5bf7c5b27
--- /dev/null
+++ b/Mathlib/Topology/MetricSpace/Ultra/ContinuousMaps.lean
@@ -0,0 +1,22 @@
+/-
+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.Topology.ContinuousMap.Compact
+import Mathlib.Topology.MetricSpace.Ultra.Basic
+
+/-!
+# Ultrametric structure on continuous maps
+-/
+
+/-- Continuous maps from a compact space to an ultrametric space are an ultrametric space. -/
+instance ContinuousMap.isUltrametricDist {X Y : Type*}
+ [TopologicalSpace X] [CompactSpace X] [MetricSpace Y] [IsUltrametricDist Y] :
+ IsUltrametricDist C(X, Y) := by
+ constructor
+ intro f g h
+ rw [ContinuousMap.dist_le (by positivity)]
+ refine fun x ↦ (dist_triangle_max (f x) (g x) (h x)).trans (max_le_max ?_ ?_) <;>
+ exact ContinuousMap.dist_apply_le_dist x
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 51973d61b6486..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) :
@@ -158,8 +158,8 @@ theorem le_two_mul_dist_ofPreNNDist (d : X → X → ℝ≥0) (dist_self : ∀ x
← Option.coe_def, Option.toList_some, take_append_of_le_length hMl.le, getElem_cons_succ]
· exact single_le_sum (fun x _ => zero_le x) _ (mem_iff_get.2 ⟨⟨M, hM_lt⟩, getElem_zipWith⟩)
· rcases hMl.eq_or_lt with (rfl | hMl)
- · simp only [getElem_append_right' le_rfl, sub_self, getElem_singleton, dist_self, zero_le]
- rw [getElem_append _ hMl]
+ · simp only [getElem_append_right le_rfl, sub_self, getElem_singleton, dist_self, zero_le]
+ rw [getElem_append_left hMl]
have hlen : length (drop (M + 1) l) = length l - (M + 1) := length_drop _ _
have hlen_lt : length l - (M + 1) < length l := Nat.sub_lt_of_pos_le M.succ_pos hMl
refine (ihn _ hlen_lt _ y _ hlen).trans ?_
@@ -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. -/
@@ -206,7 +205,7 @@ protected theorem UniformSpace.metrizable_uniformity (X : Type*) [UniformSpace X
split_ifs with h
· rw [← not_forall] at h
simp [h, pow_eq_zero_iff']
- · simpa only [not_exists, Classical.not_not, eq_self_iff_true, true_iff_iff] using h
+ · simpa only [not_exists, Classical.not_not, eq_self_iff_true, true_iff] using h
have hd_symm : ∀ x y, d x y = d y x := by
intro x y
simp only [d, @SymmetricRel.mk_mem_comm _ _ (hU_symm _) x y]
diff --git a/Mathlib/Topology/Metrizable/Urysohn.lean b/Mathlib/Topology/Metrizable/Urysohn.lean
index f136cbf094264..ce5e3289dd04e 100644
--- a/Mathlib/Topology/Metrizable/Urysohn.lean
+++ b/Mathlib/Topology/Metrizable/Urysohn.lean
@@ -5,7 +5,7 @@ Authors: Yury Kudryashov
-/
import Mathlib.Analysis.SpecificLimits.Basic
import Mathlib.Topology.UrysohnsLemma
-import Mathlib.Topology.ContinuousFunction.Bounded
+import Mathlib.Topology.ContinuousMap.Bounded
import Mathlib.Topology.Metrizable.Basic
/-!
# Urysohn's Metrization Theorem
@@ -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 74d4532b5976c..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,32 +62,31 @@ 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
- · refine (noetherianSpace_iff α).trans (Opens.compl_bijective.2.wellFounded_iff ?_)
- exact (@OrderIso.compl (Set α)).lt_iff_lt.symm
- tfae_have 1 ↔ 4
- · exact noetherianSpace_iff_opens α
- tfae_have 1 → 3
- · exact @NoetherianSpace.isCompact α _
- tfae_have 3 → 4
- · exact fun h s => h s
+ tfae_have 1 ↔ 2 := by
+ 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
tfae_finish
variable {α}
@@ -97,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,
@@ -126,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]
@@ -156,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 ddf55f07e81c4..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
@@ -48,7 +57,7 @@ theorem IsOpen.inter (s t : Set α) : IsOpen α s → IsOpen α t → IsOpen α
theorem isOpen_sUnion (s : Set (Set α)) (hs : ∀ t ∈ s, IsOpen α t) : IsOpen α (⋃₀ s) := by
simp only [IsOpen] at hs ⊢
- convert CompleteLattice.ωScottContinuous.sSup hs
+ convert CompleteLattice.ωScottContinuous.sSup hs
aesop
theorem IsOpen.isUpperSet {s : Set α} (hs : IsOpen α s) : IsUpperSet s := hs.monotone
@@ -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 α)
@@ -78,7 +98,7 @@ def notBelow :=
theorem notBelow_isOpen : IsOpen (notBelow y) := by
have h : Monotone (notBelow y) := fun x z hle ↦ mt hle.trans
- change ωScottContinuous fun x ↦ x ∈ notBelow y
+ dsimp only [IsOpen, TopologicalSpace.IsOpen, Scott.IsOpen]
rw [ωScottContinuous_iff_monotone_map_ωSup]
refine ⟨h, fun c ↦ eq_of_forall_ge_iff fun z ↦ ?_⟩
simp only [ωSup_le_iff, notBelow, mem_setOf_eq, le_Prop_eq, OrderHom.coe_mk, Chain.map_coe,
@@ -117,5 +137,6 @@ theorem continuous_of_scottContinuous {α β} [OmegaCompletePartialOrder α]
(hf : ωScottContinuous f) : Continuous f := by
rw [continuous_def]
intro s hs
- change ωScottContinuous (s ∘ f)
+ dsimp only [IsOpen, TopologicalSpace.IsOpen, Scott.IsOpen]
+ simp_rw [mem_preimage, mem_def, ← Function.comp_def]
apply ωScottContinuous.comp hs hf
diff --git a/Mathlib/Topology/Order.lean b/Mathlib/Topology/Order.lean
index 93ab813017221..173ade1245b1d 100644
--- a/Mathlib/Topology/Order.lean
+++ b/Mathlib/Topology/Order.lean
@@ -89,9 +89,6 @@ lemma tendsto_nhds_generateFrom_iff {β : Type*} {m : α → β} {f : Filter α}
simp only [nhds_generateFrom, @forall_swap (b ∈ _), tendsto_iInf, mem_setOf_eq, and_imp,
tendsto_principal]; rfl
-@[deprecated (since := "2023-12-24")]
-alias ⟨_, tendsto_nhds_generateFrom⟩ := tendsto_nhds_generateFrom_iff
-
/-- Construct a topology on α given the filter of neighborhoods of each point of α. -/
protected def mkOfNhds (n : α → Filter α) : TopologicalSpace α where
IsOpen s := ∀ a ∈ s, s ∈ n a
@@ -272,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 _⟩⟩
@@ -396,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
@@ -409,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⟩⟩
@@ -520,6 +527,12 @@ lemma generateFrom_insert_univ {α : Type*} {s : Set (Set α)} :
generateFrom (insert univ s) = generateFrom s :=
generateFrom_insert_of_generateOpen .univ
+@[simp]
+lemma generateFrom_insert_empty {α : Type*} {s : Set (Set α)} :
+ generateFrom (insert ∅ s) = generateFrom s := by
+ rw [← sUnion_empty]
+ exact generateFrom_insert_of_generateOpen (.sUnion ∅ (fun s_1 a ↦ False.elim a))
+
/-- This construction is left adjoint to the operation sending a topology on `α`
to its neighborhood filter at a fixed point `a : α`. -/
def nhdsAdjoint (a : α) (f : Filter α) : TopologicalSpace α where
@@ -615,9 +628,6 @@ lemma continuous_generateFrom_iff {t : TopologicalSpace α} {b : Set (Set β)} :
rw [continuous_iff_coinduced_le, le_generateFrom_iff_subset_isOpen]
simp only [isOpen_coinduced, preimage_id', subset_def, mem_setOf]
-@[deprecated (since := "2023-12-24")]
-alias ⟨_, continuous_generateFrom⟩ := continuous_generateFrom_iff
-
@[continuity, fun_prop]
theorem continuous_induced_dom {t : TopologicalSpace β} : Continuous[induced f t, t] f :=
continuous_iff_le_induced.2 le_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 66dd40b808326..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]
@@ -109,11 +109,10 @@ def counitAppCont : FrameHom L (Opens <| PT L) where
map_sSup' S := by ext; simp
/-- The forgetful functor `topToLocale` is left adjoint to the functor `pt`. -/
-def adjunctionTopToLocalePT : topToLocale ⊣ pt :=
- Adjunction.mkOfUnitCounit
- { unit := { app := fun X ↦ ⟨localePointOfSpacePoint X, continuous_def.2 <|
+def adjunctionTopToLocalePT : topToLocale ⊣ pt where
+ unit := { app := fun X ↦ ⟨localePointOfSpacePoint X, continuous_def.2 <|
by rintro _ ⟨u, rfl⟩; simpa using u.2⟩ }
- counit := { app := fun L ↦ ⟨counitAppCont L⟩ } }
+ counit := { app := fun L ↦ ⟨counitAppCont L⟩ }
end locale_top_adjunction
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 11dc84c396d3c..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.ContinuousFunction.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 06c7281cea152..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)`. -/
@@ -443,7 +441,7 @@ theorem setOf_isPreconnected_eq_of_ordered :
(range Ici ∪ range Ioi ∪ range Iic ∪ range Iio ∪ {univ, ∅}) := by
refine Subset.antisymm setOf_isPreconnected_subset_of_ordered ?_
simp only [subset_def, forall_mem_range, uncurry, or_imp, forall_and, mem_union,
- mem_setOf_eq, insert_eq, mem_singleton_iff, forall_eq, forall_true_iff, and_true_iff,
+ mem_setOf_eq, insert_eq, mem_singleton_iff, forall_eq, forall_true_iff, and_true,
isPreconnected_Icc, isPreconnected_Ico, isPreconnected_Ioc, isPreconnected_Ioo,
isPreconnected_Ioi, isPreconnected_Iio, isPreconnected_Ici, isPreconnected_Iic,
isPreconnected_univ, isPreconnected_empty]
diff --git a/Mathlib/Topology/Order/IsLUB.lean b/Mathlib/Topology/Order/IsLUB.lean
index 85085029dc118..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
@@ -53,8 +52,9 @@ theorem IsLUB.nhdsWithin_neBot {a : α} {s : Set α} (ha : IsLUB s a) (hs : s.No
NeBot (𝓝[s] a) :=
mem_closure_iff_nhdsWithin_neBot.1 (ha.mem_closure hs)
-theorem IsGLB.nhdsWithin_neBot : ∀ {a : α} {s : Set α}, IsGLB s a → s.Nonempty → NeBot (𝓝[s] a) :=
- IsLUB.nhdsWithin_neBot (α := αᵒᵈ)
+theorem IsGLB.nhdsWithin_neBot {a : α} {s : Set α} (ha : IsGLB s a) (hs : s.Nonempty) :
+ NeBot (𝓝[s] a) :=
+ IsLUB.nhdsWithin_neBot (α := αᵒᵈ) ha hs
theorem isLUB_of_mem_nhds {s : Set α} {a : α} {f : Filter α} (hsa : a ∈ upperBounds s) (hsf : s ∈ f)
[NeBot (f ⊓ 𝓝 a)] : IsLUB s a :=
@@ -70,9 +70,10 @@ theorem isLUB_of_mem_closure {s : Set α} {a : α} (hsa : a ∈ upperBounds s) (
rw [mem_closure_iff_clusterPt, ClusterPt, inf_comm] at hsf
exact isLUB_of_mem_nhds hsa (mem_principal_self s)
-theorem isGLB_of_mem_nhds :
- ∀ {s : Set α} {a : α} {f : Filter α}, a ∈ lowerBounds s → s ∈ f → NeBot (f ⊓ 𝓝 a) → IsGLB s a :=
- isLUB_of_mem_nhds (α := αᵒᵈ)
+theorem isGLB_of_mem_nhds {s : Set α} {a : α} {f : Filter α} (hsa : a ∈ lowerBounds s) (hsf : s ∈ f)
+ [NeBot (f ⊓ 𝓝 a)] :
+ IsGLB s a :=
+ isLUB_of_mem_nhds (α := αᵒᵈ) hsa hsf
theorem isGLB_of_mem_closure {s : Set α} {a : α} (hsa : a ∈ lowerBounds s) (hsf : a ∈ closure s) :
IsGLB s a :=
@@ -114,20 +115,20 @@ theorem IsLUB.mem_lowerBounds_of_tendsto [Preorder γ] [TopologicalSpace γ] [Or
(hb : Tendsto f (𝓝[s] a) (𝓝 b)) : b ∈ lowerBounds (f '' s) :=
IsLUB.mem_upperBounds_of_tendsto (γ := γᵒᵈ) hf ha hb
-theorem IsLUB.isGLB_of_tendsto [Preorder γ] [TopologicalSpace γ] [OrderClosedTopology γ] :
- ∀ {f : α → γ} {s : Set α} {a : α} {b : γ},
- AntitoneOn f s → IsLUB s a → s.Nonempty → Tendsto f (𝓝[s] a) (𝓝 b) → IsGLB (f '' s) b :=
- IsLUB.isLUB_of_tendsto (γ := γᵒᵈ)
+theorem IsLUB.isGLB_of_tendsto [Preorder γ] [TopologicalSpace γ] [OrderClosedTopology γ] {f : α → γ}
+ {s : Set α} {a : α} {b : γ} (hf : AntitoneOn f s) (ha : IsLUB s a) (hs : s.Nonempty)
+ (hb : Tendsto f (𝓝[s] a) (𝓝 b)) : IsGLB (f '' s) b :=
+ IsLUB.isLUB_of_tendsto (γ := γᵒᵈ) hf ha hs hb
theorem IsGLB.mem_upperBounds_of_tendsto [Preorder γ] [TopologicalSpace γ] [OrderClosedTopology γ]
{f : α → γ} {s : Set α} {a : α} {b : γ} (hf : AntitoneOn f s) (ha : IsGLB s a)
(hb : Tendsto f (𝓝[s] a) (𝓝 b)) : b ∈ upperBounds (f '' s) :=
IsGLB.mem_lowerBounds_of_tendsto (γ := γᵒᵈ) hf ha hb
-theorem IsGLB.isLUB_of_tendsto [Preorder γ] [TopologicalSpace γ] [OrderClosedTopology γ] :
- ∀ {f : α → γ} {s : Set α} {a : α} {b : γ},
- AntitoneOn f s → IsGLB s a → s.Nonempty → Tendsto f (𝓝[s] a) (𝓝 b) → IsLUB (f '' s) b :=
- IsGLB.isGLB_of_tendsto (γ := γᵒᵈ)
+theorem IsGLB.isLUB_of_tendsto [Preorder γ] [TopologicalSpace γ] [OrderClosedTopology γ] {f : α → γ}
+ {s : Set α} {a : α} {b : γ} (hf : AntitoneOn f s) (ha : IsGLB s a) (hs : s.Nonempty)
+ (hb : Tendsto f (𝓝[s] a) (𝓝 b)) : IsLUB (f '' s) b :=
+ IsGLB.isGLB_of_tendsto (γ := γᵒᵈ) hf ha hs hb
theorem IsLUB.mem_of_isClosed {a : α} {s : Set α} (ha : IsLUB s a) (hs : s.Nonempty)
(sc : IsClosed s) : a ∈ s :=
diff --git a/Mathlib/Topology/Order/LawsonTopology.lean b/Mathlib/Topology/Order/LawsonTopology.lean
index 4c730963736e1..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/LeftRightNhds.lean b/Mathlib/Topology/Order/LeftRightNhds.lean
index 8983e91b3b08f..c6f61ba355838 100644
--- a/Mathlib/Topology/Order/LeftRightNhds.lean
+++ b/Mathlib/Topology/Order/LeftRightNhds.lean
@@ -3,9 +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, Yury Kudryashov
-/
-
-import Mathlib.Topology.Order.Basic
import Mathlib.Algebra.Ring.Pointwise.Set
+import Mathlib.Order.Filter.AtTopBot.Group
+import Mathlib.Topology.Order.Basic
/-!
# Neighborhoods to the left and to the right on an `OrderTopology`
@@ -43,17 +43,15 @@ theorem TFAE_mem_nhdsWithin_Ioi {a b : α} (hab : a < b) (s : Set α) :
s ∈ 𝓝[Ioo a b] a,
∃ u ∈ Ioc a b, Ioo a u ⊆ s,
∃ u ∈ Ioi a, Ioo a u ⊆ s] := by
- tfae_have 1 ↔ 2
- · rw [nhdsWithin_Ioc_eq_nhdsWithin_Ioi hab]
- tfae_have 1 ↔ 3
- · rw [nhdsWithin_Ioo_eq_nhdsWithin_Ioi hab]
- tfae_have 4 → 5
- · exact fun ⟨u, umem, hu⟩ => ⟨u, umem.1, hu⟩
+ tfae_have 1 ↔ 2 := by
+ rw [nhdsWithin_Ioc_eq_nhdsWithin_Ioi hab]
+ tfae_have 1 ↔ 3 := by
+ rw [nhdsWithin_Ioo_eq_nhdsWithin_Ioi hab]
+ tfae_have 4 → 5 := fun ⟨u, umem, hu⟩ => ⟨u, umem.1, hu⟩
tfae_have 5 → 1
- · rintro ⟨u, hau, hu⟩
- exact mem_of_superset (Ioo_mem_nhdsWithin_Ioi ⟨le_refl a, hau⟩) hu
+ | ⟨u, hau, hu⟩ => mem_of_superset (Ioo_mem_nhdsWithin_Ioi ⟨le_refl a, hau⟩) hu
tfae_have 1 → 4
- · intro h
+ | h => by
rcases mem_nhdsWithin_iff_exists_mem_nhds_inter.1 h with ⟨v, va, hv⟩
rcases exists_Ico_subset_of_mem_nhds' va hab with ⟨u, au, hu⟩
exact ⟨u, au, fun x hx => hv ⟨hu ⟨le_of_lt hx.1, hx.2⟩, hx.1⟩⟩
@@ -183,19 +181,15 @@ theorem TFAE_mem_nhdsWithin_Ici {a b : α} (hab : a < b) (s : Set α) :
s ∈ 𝓝[Ico a b] a,
∃ u ∈ Ioc a b, Ico a u ⊆ s,
∃ u ∈ Ioi a , Ico a u ⊆ s] := by
- tfae_have 1 ↔ 2
- · rw [nhdsWithin_Icc_eq_nhdsWithin_Ici hab]
- tfae_have 1 ↔ 3
- · rw [nhdsWithin_Ico_eq_nhdsWithin_Ici hab]
- tfae_have 1 ↔ 5
- · exact (nhdsWithin_Ici_basis' ⟨b, hab⟩).mem_iff
- tfae_have 4 → 5
- · exact fun ⟨u, umem, hu⟩ => ⟨u, umem.1, hu⟩
+ tfae_have 1 ↔ 2 := by
+ rw [nhdsWithin_Icc_eq_nhdsWithin_Ici hab]
+ tfae_have 1 ↔ 3 := by
+ rw [nhdsWithin_Ico_eq_nhdsWithin_Ici hab]
+ tfae_have 1 ↔ 5 := (nhdsWithin_Ici_basis' ⟨b, hab⟩).mem_iff
+ tfae_have 4 → 5 := fun ⟨u, umem, hu⟩ => ⟨u, umem.1, hu⟩
tfae_have 5 → 4
- · rintro ⟨u, hua, hus⟩
- exact
- ⟨min u b, ⟨lt_min hua hab, min_le_right _ _⟩,
- (Ico_subset_Ico_right <| min_le_left _ _).trans hus⟩
+ | ⟨u, hua, hus⟩ => ⟨min u b, ⟨lt_min hua hab, min_le_right _ _⟩,
+ (Ico_subset_Ico_right <| min_le_left _ _).trans hus⟩
tfae_finish
theorem mem_nhdsWithin_Ici_iff_exists_mem_Ioc_Ico_subset {a u' : α} {s : Set α} (hu' : a < u') :
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 efe6bf46b486b..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
@@ -263,10 +263,6 @@ lemma continuous_iff_Ici [TopologicalSpace β] {f : β → α} :
obtain rfl := IsLower.topology_eq α
simp [continuous_generateFrom_iff]
-/-- A function `f : β → α` with lower topology in the codomain is continuous provided that the
-preimage of every interval `Set.Ici a` is a closed set. -/
-@[deprecated (since := "2023-12-24")] alias ⟨_, continuous_of_Ici⟩ := continuous_iff_Ici
-
end Preorder
section PartialOrder
@@ -358,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
@@ -399,13 +395,6 @@ lemma continuous_iff_Iic [TopologicalSpace β] {f : β → α} :
Continuous f ↔ ∀ a, IsClosed (f ⁻¹' (Iic a)) :=
IsLower.continuous_iff_Ici (α := αᵒᵈ)
-/-- A function `f : β → α` with upper topology in the codomain is continuous
-provided that the preimage of every interval `Set.Iic a` is a closed set. -/
-@[deprecated (since := "2023-12-24")]
-lemma continuous_of_Iic [TopologicalSpace β] {f : β → α} (h : ∀ a, IsClosed (f ⁻¹' (Iic a))) :
- Continuous f :=
- continuous_iff_Iic.2 h
-
end Preorder
@@ -509,3 +498,17 @@ lemma isLower_orderDual [Preorder α] [TopologicalSpace α] : IsLower αᵒᵈ
isUpper_orderDual.symm
end Topology
+
+/-- The Sierpiński topology on `Prop` is the upper topology -/
+instance : IsUpper Prop where
+ topology_eq_upperTopology := by
+ rw [Topology.upper, sierpinskiSpace, ← generateFrom_insert_empty]
+ congr
+ exact le_antisymm
+ (fun h hs => by
+ simp only [compl_Iic, mem_setOf_eq]
+ rw [← Ioi_True, ← Ioi_False] at hs
+ rcases hs with (rfl | rfl)
+ · use True
+ · use False)
+ (by rintro _ ⟨a, rfl⟩; by_cases a <;> aesop (add simp [Ioi, lt_iff_le_not_le]))
diff --git a/Mathlib/Topology/Order/Monotone.lean b/Mathlib/Topology/Order/Monotone.lean
index 0493d4d868c9c..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. -/
@@ -52,8 +52,8 @@ supremum to the indexed supremum of the composition. -/
theorem Monotone.map_ciSup_of_continuousAt {ι : Sort*} [Nonempty ι] {f : α → β} {g : ι → α}
(Cf : ContinuousAt f (iSup g)) (Mf : Monotone f)
(bdd : BddAbove (range g) := by bddDefault) : f (⨆ i, g i) = ⨆ i, f (g i) := by
- rw [iSup, Monotone.map_csSup_of_continuousAt Cf Mf (range_nonempty g) bdd, ← range_comp, iSup]
- rfl
+ rw [iSup, Monotone.map_csSup_of_continuousAt Cf Mf (range_nonempty g) bdd, ← range_comp, iSup,
+ comp_def]
@[deprecated (since := "2024-08-26")] alias Monotone.map_iSup_of_continuousAt' :=
Monotone.map_ciSup_of_continuousAt
@@ -81,8 +81,8 @@ infimum to the indexed infimum of the composition. -/
theorem Monotone.map_ciInf_of_continuousAt {ι : Sort*} [Nonempty ι] {f : α → β} {g : ι → α}
(Cf : ContinuousAt f (iInf g)) (Mf : Monotone f)
(bdd : BddBelow (range g) := by bddDefault) : f (⨅ i, g i) = ⨅ i, f (g i) := by
- rw [iInf, Monotone.map_csInf_of_continuousAt Cf Mf (range_nonempty g) bdd, ← range_comp, iInf]
- rfl
+ rw [iInf, Monotone.map_csInf_of_continuousAt Cf Mf (range_nonempty g) bdd, ← range_comp, iInf,
+ comp_def]
@[deprecated (since := "2024-08-26")] alias Monotone.map_iInf_of_continuousAt' :=
Monotone.map_ciInf_of_continuousAt
@@ -110,8 +110,8 @@ infimum to the indexed supremum of the composition. -/
theorem Antitone.map_ciInf_of_continuousAt {ι : Sort*} [Nonempty ι] {f : α → β} {g : ι → α}
(Cf : ContinuousAt f (iInf g)) (Af : Antitone f)
(bdd : BddBelow (range g) := by bddDefault) : f (⨅ i, g i) = ⨆ i, f (g i) := by
- rw [iInf, Antitone.map_csInf_of_continuousAt Cf Af (range_nonempty g) bdd, ← range_comp, iSup]
- rfl
+ rw [iInf, Antitone.map_csInf_of_continuousAt Cf Af (range_nonempty g) bdd, ← range_comp, iSup,
+ comp_def]
@[deprecated (since := "2024-08-26")] alias Antitone.map_iInf_of_continuousAt' :=
Antitone.map_ciInf_of_continuousAt
@@ -139,8 +139,8 @@ indexed supremum to the indexed infimum of the composition. -/
theorem Antitone.map_ciSup_of_continuousAt {ι : Sort*} [Nonempty ι] {f : α → β} {g : ι → α}
(Cf : ContinuousAt f (iSup g)) (Af : Antitone f)
(bdd : BddAbove (range g) := by bddDefault) : f (⨆ i, g i) = ⨅ i, f (g i) := by
- rw [iSup, Antitone.map_csSup_of_continuousAt Cf Af (range_nonempty g) bdd, ← range_comp, iInf]
- rfl
+ rw [iSup, Antitone.map_csSup_of_continuousAt Cf Af (range_nonempty g) bdd, ← range_comp, iInf,
+ comp_def]
@[deprecated (since := "2024-08-26")] alias Antitone.map_iSup_of_continuousAt' :=
Antitone.map_ciSup_of_continuousAt
@@ -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
@@ -184,7 +184,7 @@ a `Sort`, then it sends this indexed supremum to the indexed supremum of the com
theorem Monotone.map_iSup_of_continuousAt {ι : Sort*} {f : α → β} {g : ι → α}
(Cf : ContinuousAt f (iSup g)) (Mf : Monotone f) (fbot : f ⊥ = ⊥) :
f (⨆ i, g i) = ⨆ i, f (g i) := by
- rw [iSup, Mf.map_sSup_of_continuousAt Cf fbot, ← range_comp, iSup]; rfl
+ rw [iSup, Mf.map_sSup_of_continuousAt Cf fbot, ← range_comp, iSup, comp_def]
/-- A monotone function `f` sending `top` to `top` and continuous at the infimum of a set sends
this infimum to the infimum of the image of this set. -/
@@ -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 7a476daeaf513..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
@@ -543,7 +543,7 @@ namespace Subtype
-- todo: add `OrderEmbedding.orderClosedTopology`
instance {p : α → Prop} : OrderClosedTopology (Subtype p) :=
have this : Continuous fun p : Subtype p × Subtype p => ((p.fst : α), (p.snd : α)) :=
- continuous_subtype_val.prod_map continuous_subtype_val
+ continuous_subtype_val.prodMap continuous_subtype_val
OrderClosedTopology.mk (t.isClosed_le'.preimage this)
end Subtype
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 a9b565b1722dc..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,16 +347,27 @@ 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 α 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 α 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
/--
@@ -373,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 5aa350f222cbb..8c2d9de64d0b4 100644
--- a/Mathlib/Topology/Order/UpperLowerSetTopology.lean
+++ b/Mathlib/Topology/Order/UpperLowerSetTopology.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Christopher Hoskin
-/
import Mathlib.Topology.AlexandrovDiscrete
-import Mathlib.Topology.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Basic
import Mathlib.Topology.Order.LowerUpperTopology
/-!
@@ -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 75f77fa794bf8..0f70e094b5f72 100644
--- a/Mathlib/Topology/PartialHomeomorph.lean
+++ b/Mathlib/Topology/PartialHomeomorph.lean
@@ -370,7 +370,7 @@ theorem preimage_eventuallyEq_target_inter_preimage_inter {e : PartialHomeomorph
filter_upwards [e.open_source.mem_nhds hxe,
mem_nhdsWithin_iff_eventually.mp (hf.preimage_mem_nhdsWithin ht)]
intro y hy hyu
- simp_rw [mem_inter_iff, mem_preimage, mem_inter_iff, e.mapsTo hy, true_and_iff, iff_self_and,
+ simp_rw [mem_inter_iff, mem_preimage, mem_inter_iff, e.mapsTo hy, true_and, iff_self_and,
e.left_inv hy, iff_true_intro hyu]
theorem isOpen_inter_preimage {s : Set Y} (hs : IsOpen s) : IsOpen (e.source ∩ e ⁻¹' s) :=
@@ -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 a98ad48c12803..d5fb0185564ef 100644
--- a/Mathlib/Topology/PartitionOfUnity.lean
+++ b/Mathlib/Topology/PartitionOfUnity.lean
@@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
import Mathlib.Algebra.BigOperators.Finprod
-import Mathlib.SetTheory.Ordinal.Basic
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.LinearAlgebra.Basis.VectorSpace
+import Mathlib.Topology.ContinuousMap.Algebra
import Mathlib.Topology.Compactness.Paracompact
import Mathlib.Topology.ShrinkingLemma
import Mathlib.Topology.UrysohnsLemma
@@ -140,7 +140,7 @@ variable {E : Type*} [AddCommMonoid E] [SMulWithZero ℝ E] [TopologicalSpace E]
instance : FunLike (PartitionOfUnity ι X s) ι C(X, ℝ) where
coe := toFun
- coe_injective' := fun f g h ↦ by cases f; cases g; congr
+ coe_injective' f g h := by cases f; cases g; congr
protected theorem locallyFinite : LocallyFinite fun i => support (f i) :=
f.locallyFinite'
@@ -312,7 +312,7 @@ variable {s : Set X} (f : BumpCovering ι X s)
instance : FunLike (BumpCovering ι X s) ι C(X, ℝ) where
coe := toFun
- coe_injective' := fun f g h ↦ by cases f; cases g; congr
+ coe_injective' f g h := by cases f; cases g; congr
protected theorem locallyFinite : LocallyFinite fun i => support (f i) :=
f.locallyFinite'
@@ -340,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]⟩
@@ -507,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/PreorderRestrict.lean b/Mathlib/Topology/PreorderRestrict.lean
new file mode 100644
index 0000000000000..9d833618bfd40
--- /dev/null
+++ b/Mathlib/Topology/PreorderRestrict.lean
@@ -0,0 +1,39 @@
+/-
+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.Order.Restriction
+import Mathlib.Topology.Constructions
+
+/-!
+# Continuity of the restriction function for functions indexed by a preorder
+
+We prove that the map which restricts a function `f : (i : α) → X i` to elements `≤ a` is
+continuous.
+-/
+
+namespace Preorder
+
+variable {α : Type*} [Preorder α] {X : α → Type*} [∀ i, TopologicalSpace (X i)]
+
+@[continuity, fun_prop]
+theorem continuous_restrictLe (a : α) : Continuous (restrictLe (π := X) a) :=
+ Pi.continuous_restrict _
+
+@[continuity, fun_prop]
+theorem continuous_restrictLe₂ {a b : α} (hab : a ≤ b) : Continuous (restrictLe₂ (π := X) hab) :=
+ Pi.continuous_restrict₂ _
+
+variable [LocallyFiniteOrderBot α]
+
+@[continuity, fun_prop]
+theorem continuous_frestrictLe (a : α) : Continuous (frestrictLe (π := X) a) :=
+ Finset.continuous_restrict _
+
+@[continuity, fun_prop]
+theorem continuous_frestrictLe₂ {a b : α} (hab : a ≤ b) :
+ Continuous (frestrictLe₂ (π := X) hab) :=
+ Finset.continuous_restrict₂ _
+
+end Preorder
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/RestrictGenTopology.lean b/Mathlib/Topology/RestrictGen.lean
similarity index 100%
rename from Mathlib/Topology/RestrictGenTopology.lean
rename to Mathlib/Topology/RestrictGen.lean
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 91%
rename from Mathlib/Topology/Separation.lean
rename to Mathlib/Topology/Separation/Basic.lean
index b87d9628b0774..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
@@ -576,30 +587,28 @@ theorem t1Space_TFAE (X : Type u) [TopologicalSpace X] :
∀ ⦃x y : X⦄, x ≠ y → Disjoint (𝓝 x) (pure y),
∀ ⦃x y : X⦄, x ≠ y → Disjoint (pure x) (𝓝 y),
∀ ⦃x y : X⦄, x ⤳ y → x = y] := by
- tfae_have 1 ↔ 2
- · exact ⟨fun h => h.1, fun h => ⟨h⟩⟩
- tfae_have 2 ↔ 3
- · simp only [isOpen_compl_iff]
- tfae_have 5 ↔ 3
- · refine forall_swap.trans ?_
+ tfae_have 1 ↔ 2 := ⟨fun h => h.1, fun h => ⟨h⟩⟩
+ tfae_have 2 ↔ 3 := by
+ simp only [isOpen_compl_iff]
+ tfae_have 5 ↔ 3 := by
+ refine forall_swap.trans ?_
simp only [isOpen_iff_mem_nhds, mem_compl_iff, mem_singleton_iff]
- tfae_have 5 ↔ 6
- · simp only [← subset_compl_singleton_iff, exists_mem_subset_iff]
- tfae_have 5 ↔ 7
- · simp only [(nhds_basis_opens _).mem_iff, subset_compl_singleton_iff, exists_prop, and_assoc,
+ tfae_have 5 ↔ 6 := by
+ simp only [← subset_compl_singleton_iff, exists_mem_subset_iff]
+ tfae_have 5 ↔ 7 := by
+ simp only [(nhds_basis_opens _).mem_iff, subset_compl_singleton_iff, exists_prop, and_assoc,
and_left_comm]
- tfae_have 5 ↔ 8
- · simp only [← principal_singleton, disjoint_principal_right]
- tfae_have 8 ↔ 9
- · exact forall_swap.trans (by simp only [disjoint_comm, ne_comm])
- tfae_have 1 → 4
- · simp only [continuous_def, CofiniteTopology.isOpen_iff']
+ tfae_have 5 ↔ 8 := by
+ simp only [← principal_singleton, disjoint_principal_right]
+ tfae_have 8 ↔ 9 := forall_swap.trans (by simp only [disjoint_comm, ne_comm])
+ tfae_have 1 → 4 := by
+ simp only [continuous_def, CofiniteTopology.isOpen_iff']
rintro H s (rfl | hs)
exacts [isOpen_empty, compl_compl s ▸ (@Set.Finite.isClosed _ _ H _ hs).isOpen_compl]
- tfae_have 4 → 2
- · exact fun h x => (CofiniteTopology.isClosed_iff.2 <| Or.inr (finite_singleton _)).preimage h
- tfae_have 2 ↔ 10
- · simp only [← closure_subset_iff_isClosed, specializes_iff_mem_closure, subset_def,
+ tfae_have 4 → 2 :=
+ fun h x => (CofiniteTopology.isClosed_iff.2 <| Or.inr (finite_singleton _)).preimage h
+ tfae_have 2 ↔ 10 := by
+ simp only [← closure_subset_iff_isClosed, specializes_iff_mem_closure, subset_def,
mem_singleton_iff, eq_comm]
tfae_finish
@@ -677,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
@@ -685,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⟩
@@ -701,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] :
@@ -757,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]
@@ -840,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}
@@ -902,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⟩
@@ -1001,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 -/
@@ -1045,6 +1059,17 @@ theorem r1Space_iff_inseparable_or_disjoint_nhds {X : Type*} [TopologicalSpace X
⟨fun _h x y ↦ (specializes_or_disjoint_nhds x y).imp_left Specializes.inseparable, fun h ↦
⟨fun x y ↦ (h x y).imp_left Inseparable.specializes⟩⟩
+theorem Inseparable.of_nhds_neBot {x y : X} (h : NeBot (𝓝 x ⊓ 𝓝 y)) :
+ Inseparable x y :=
+ (r1Space_iff_inseparable_or_disjoint_nhds.mp ‹_› _ _).resolve_right fun h' => h.ne h'.eq_bot
+
+/-- Limits are unique up to separability.
+
+A weaker version of `tendsto_nhds_unique` for `R1Space`. -/
+theorem tendsto_nhds_unique_inseparable {f : Y → X} {l : Filter Y} {a b : X} [NeBot l]
+ (ha : Tendsto f l (𝓝 a)) (hb : Tendsto f l (𝓝 b)) : Inseparable a b :=
+ .of_nhds_neBot <| neBot_of_le <| le_inf ha hb
+
theorem isClosed_setOf_specializes : IsClosed { p : X × X | p.1 ⤳ p.2 } := by
simp only [← isOpen_compl_iff, compl_setOf, ← disjoint_nhds_nhds_iff_not_specializes,
isOpen_setOf_disjoint_nhds_nhds]
@@ -1160,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 _
@@ -1382,11 +1409,11 @@ theorem isClosed_diagonal [T2Space X] : IsClosed (diagonal X) :=
theorem tendsto_nhds_unique [T2Space X] {f : Y → X} {l : Filter Y} {a b : X} [NeBot l]
(ha : Tendsto f l (𝓝 a)) (hb : Tendsto f l (𝓝 b)) : a = b :=
- eq_of_nhds_neBot <| neBot_of_le <| le_inf ha hb
+ (tendsto_nhds_unique_inseparable ha hb).eq
theorem tendsto_nhds_unique' [T2Space X] {f : Y → X} {l : Filter Y} {a b : X} (_ : NeBot l)
(ha : Tendsto f l (𝓝 a)) (hb : Tendsto f l (𝓝 b)) : a = b :=
- eq_of_nhds_neBot <| neBot_of_le <| le_inf ha hb
+ tendsto_nhds_unique ha hb
theorem tendsto_nhds_unique_of_eventuallyEq [T2Space X] {f g : Y → X} {l : Filter Y} {a b : X}
[NeBot l] (ha : Tendsto f l (𝓝 a)) (hb : Tendsto g l (𝓝 b)) (hfg : f =ᶠ[l] g) : a = b :=
@@ -1442,7 +1469,7 @@ theorem Set.InjOn.exists_mem_nhdsSet {X Y : Type*} [TopologicalSpace X] [Topolog
· rcases loc x hx with ⟨u, hu, hf⟩
exact Filter.mem_of_superset (prod_mem_nhds hu hu) <| forall_prod_set.2 hf
· suffices ∀ᶠ z in 𝓝 (x, y), f z.1 ≠ f z.2 from this.mono fun _ hne h ↦ absurd h hne
- refine (fc x hx).prod_map' (fc y hy) <| isClosed_diagonal.isOpen_compl.mem_nhds ?_
+ refine (fc x hx).prodMap' (fc y hy) <| isClosed_diagonal.isOpen_compl.mem_nhds ?_
exact inj.ne hx hy hne
rw [← eventually_nhdsSet_iff_forall, sc.nhdsSet_prod_eq sc] at this
exact eventually_prod_self_iff.1 this
@@ -1535,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.
-/
@@ -1551,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) :=
@@ -1571,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) :=
@@ -1597,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
@@ -1620,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)
@@ -1715,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))
@@ -1742,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
@@ -1840,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
@@ -1870,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
@@ -1890,30 +1936,28 @@ theorem regularSpace_TFAE (X : Type u) [TopologicalSpace X] :
∀ (x : X) (s : Set X), s ∈ 𝓝 x → ∃ t ∈ 𝓝 x, IsClosed t ∧ t ⊆ s,
∀ x : X, (𝓝 x).lift' closure ≤ 𝓝 x,
∀ x : X , (𝓝 x).lift' closure = 𝓝 x] := by
- tfae_have 1 ↔ 5
- · rw [regularSpace_iff, (@compl_surjective (Set X) _).forall, forall_swap]
+ tfae_have 1 ↔ 5 := by
+ rw [regularSpace_iff, (@compl_surjective (Set X) _).forall, forall_swap]
simp only [isClosed_compl_iff, mem_compl_iff, Classical.not_not, @and_comm (_ ∈ _),
(nhds_basis_opens _).lift'_closure.le_basis_iff (nhds_basis_opens _), and_imp,
(nhds_basis_opens _).disjoint_iff_right, exists_prop, ← subset_interior_iff_mem_nhdsSet,
interior_compl, compl_subset_compl]
- tfae_have 5 → 6
- · exact fun h a => (h a).antisymm (𝓝 _).le_lift'_closure
+ tfae_have 5 → 6 := fun h a => (h a).antisymm (𝓝 _).le_lift'_closure
tfae_have 6 → 4
- · intro H a s hs
+ | H, a, s, hs => by
rw [← H] at hs
rcases (𝓝 a).basis_sets.lift'_closure.mem_iff.mp hs with ⟨U, hU, hUs⟩
exact ⟨closure U, mem_of_superset hU subset_closure, isClosed_closure, hUs⟩
tfae_have 4 → 2
- · intro H s a ha
+ | H, s, a, ha => by
have ha' : sᶜ ∈ 𝓝 a := by rwa [← mem_interior_iff_mem_nhds, interior_compl]
rcases H _ _ ha' with ⟨U, hU, hUc, hUs⟩
refine disjoint_of_disjoint_of_mem disjoint_compl_left ?_ hU
rwa [← subset_interior_iff_mem_nhdsSet, hUc.isOpen_compl.interior_eq, subset_compl_comm]
- tfae_have 2 → 3
- · refine fun H a s => ⟨fun hd has => mem_closure_iff_nhds_ne_bot.mp has ?_, H s a⟩
+ tfae_have 2 → 3 := by
+ refine fun H a s => ⟨fun hd has => mem_closure_iff_nhds_ne_bot.mp has ?_, H s a⟩
exact (hd.symm.mono_right <| @principal_le_nhdsSet _ _ s).eq_bot
- tfae_have 3 → 1
- · exact fun H => ⟨fun hs ha => (H _ _).mpr <| hs.closure_eq.symm ▸ ha⟩
+ tfae_have 3 → 1 := fun H => ⟨fun hs ha => (H _ _).mpr <| hs.closure_eq.symm ▸ ha⟩
tfae_finish
theorem RegularSpace.of_lift'_closure_le (h : ∀ x : X, (𝓝 x).lift' closure ≤ 𝓝 x) :
@@ -2007,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
@@ -2039,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))
@@ -2115,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
@@ -2159,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
@@ -2188,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) := ⟨⟩
@@ -2252,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
@@ -2297,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
@@ -2340,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
@@ -2375,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
@@ -2393,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) :
@@ -2553,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⟩
@@ -2591,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]
@@ -2641,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 1ae5cef54ba68..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] :
@@ -328,7 +334,7 @@ protected theorem IsSeqCompact.totallyBounded (h : IsSeqCompact s) : TotallyBoun
refine ⟨u, u_in, fun x _ φ hφ huφ => ?_⟩
obtain ⟨N, hN⟩ : ∃ N, ∀ p q, p ≥ N → q ≥ N → (u (φ p), u (φ q)) ∈ V :=
huφ.cauchySeq.mem_entourage V_in
- exact hu (φ <| N + 1) (φ N) (hφ <| lt_add_one N) (hN (N + 1) N N.le_succ le_rfl)
+ exact hu (φ <| N + 1) (φ N) (hφ <| Nat.lt_add_one N) (hN (N + 1) N N.le_succ le_rfl)
variable [IsCountablyGenerated (𝓤 X)]
diff --git a/Mathlib/Topology/Sets/Opens.lean b/Mathlib/Topology/Sets/Opens.lean
index 5e2b0453cc80e..8d8d697d4c8f2 100644
--- a/Mathlib/Topology/Sets/Opens.lean
+++ b/Mathlib/Topology/Sets/Opens.lean
@@ -6,7 +6,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Floris van Doorn
import Mathlib.Order.Hom.CompleteLattice
import Mathlib.Topology.Bases
import Mathlib.Topology.Homeomorph
-import Mathlib.Topology.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Basic
import Mathlib.Order.CompactlyGenerated.Basic
import Mathlib.Order.Copy
@@ -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/Forget.lean b/Mathlib/Topology/Sheaves/Forget.lean
index 6783eda87f149..f92a32f660346 100644
--- a/Mathlib/Topology/Sheaves/Forget.lean
+++ b/Mathlib/Topology/Sheaves/Forget.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Category.Ring.Limits
import Mathlib.Topology.Sheaves.Sheaf
diff --git a/Mathlib/Topology/Sheaves/Functors.lean b/Mathlib/Topology/Sheaves/Functors.lean
index ee393d3948d1a..d246fbdbe9fcc 100644
--- a/Mathlib/Topology/Sheaves/Functors.lean
+++ b/Mathlib/Topology/Sheaves/Functors.lean
@@ -34,6 +34,8 @@ open CategoryTheory.Limits
open TopologicalSpace
+open scoped AlgebraicGeometry
+
variable {C : Type u} [Category.{v} C]
variable {X Y : TopCat.{w}} (f : X ⟶ Y)
variable ⦃ι : Type w⦄ {U : ι → Opens Y}
diff --git a/Mathlib/Topology/Sheaves/Limits.lean b/Mathlib/Topology/Sheaves/Limits.lean
index 7309973470775..af880e9d7ae36 100644
--- a/Mathlib/Topology/Sheaves/Limits.lean
+++ b/Mathlib/Topology/Sheaves/Limits.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Topology.Sheaves.Sheaf
import Mathlib.CategoryTheory.Sites.Limits
diff --git a/Mathlib/Topology/Sheaves/LocalPredicate.lean b/Mathlib/Topology/Sheaves/LocalPredicate.lean
index 2c3ef5febbef1..bf6e5eb7f9b01 100644
--- a/Mathlib/Topology/Sheaves/LocalPredicate.lean
+++ b/Mathlib/Topology/Sheaves/LocalPredicate.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison, Adam Topaz
+Authors: Johan Commelin, Kim Morrison, Adam Topaz
-/
import Mathlib.Topology.Sheaves.SheafOfFunctions
import Mathlib.Topology.Sheaves.Stalks
@@ -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 1045f3e96ce28..46dcaa719cd3a 100644
--- a/Mathlib/Topology/Sheaves/Presheaf.lean
+++ b/Mathlib/Topology/Sheaves/Presheaf.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2018 Scott Morrison. All rights reserved.
+Copyright (c) 2018 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Mario Carneiro, Reid Barton, Andrew Yang
+Authors: Kim Morrison, Mario Carneiro, Reid Barton, Andrew Yang
-/
import Mathlib.Topology.Category.TopCat.Opens
import Mathlib.CategoryTheory.Adjunction.Unique
@@ -153,9 +153,9 @@ variable (C)
def pushforward {X Y : TopCat.{w}} (f : X ⟶ Y) : X.Presheaf C ⥤ Y.Presheaf C :=
(whiskeringLeft _ _ _).obj (Opens.map f).op
-set_option quotPrecheck false in
/-- push forward of a presheaf -/
-notation f:80 " _* " P:81 => (pushforward _ f).obj P
+scoped[AlgebraicGeometry] notation f:80 " _* " P:81 =>
+ Prefunctor.obj (Functor.toPrefunctor (TopCat.Presheaf.pushforward _ f)) P
@[simp]
theorem pushforward_map_app' {X Y : TopCat.{w}} (f : X ⟶ Y) {ℱ 𝒢 : X.Presheaf C} (α : ℱ ⟶ 𝒢)
@@ -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 24ed94958851d..4ce4eaa2a3fd1 100644
--- a/Mathlib/Topology/Sheaves/PresheafOfFunctions.lean
+++ b/Mathlib/Topology/Sheaves/PresheafOfFunctions.lean
@@ -1,12 +1,12 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Yoneda
import Mathlib.Topology.Sheaves.Presheaf
import Mathlib.Topology.Category.TopCommRingCat
-import Mathlib.Topology.ContinuousFunction.Algebra
+import Mathlib.Topology.ContinuousMap.Algebra
/-!
# Presheaves of functions
@@ -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/Sheaf.lean b/Mathlib/Topology/Sheaves/Sheaf.lean
index c13307d1eeab1..6345a02e5c3c7 100644
--- a/Mathlib/Topology/Sheaves/Sheaf.lean
+++ b/Mathlib/Topology/Sheaves/Sheaf.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Topology.Sheaves.Presheaf
import Mathlib.CategoryTheory.Sites.Sheaf
diff --git a/Mathlib/Topology/Sheaves/SheafCondition/EqualizerProducts.lean b/Mathlib/Topology/Sheaves/SheafCondition/EqualizerProducts.lean
index 25fd50eb55023..5103d691a3229 100644
--- a/Mathlib/Topology/Sheaves/SheafCondition/EqualizerProducts.lean
+++ b/Mathlib/Topology/Sheaves/SheafCondition/EqualizerProducts.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.CategoryTheory.Limits.Shapes.Equalizers
import Mathlib.CategoryTheory.Limits.Shapes.Products
@@ -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/OpensLeCover.lean b/Mathlib/Topology/Sheaves/SheafCondition/OpensLeCover.lean
index ace2385ed29bd..318e4ad961054 100644
--- a/Mathlib/Topology/Sheaves/SheafCondition/OpensLeCover.lean
+++ b/Mathlib/Topology/Sheaves/SheafCondition/OpensLeCover.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Topology.Sheaves.SheafCondition.Sites
diff --git a/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean b/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean
index 7dcee720fc546..890f87cb37276 100644
--- a/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean
+++ b/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Topology.Sheaves.SheafCondition.OpensLeCover
import Mathlib.CategoryTheory.Limits.Final
@@ -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/SheafOfFunctions.lean b/Mathlib/Topology/Sheaves/SheafOfFunctions.lean
index 4aea0cf255c09..e2c75974e54e3 100644
--- a/Mathlib/Topology/Sheaves/SheafOfFunctions.lean
+++ b/Mathlib/Topology/Sheaves/SheafOfFunctions.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Johan Commelin, Scott Morrison
+Authors: Johan Commelin, Kim Morrison
-/
import Mathlib.Topology.Sheaves.PresheafOfFunctions
import Mathlib.Topology.Sheaves.SheafCondition.UniqueGluing
diff --git a/Mathlib/Topology/Sheaves/Sheafify.lean b/Mathlib/Topology/Sheaves/Sheafify.lean
index 14b6e48ce063c..36740da226f9a 100644
--- a/Mathlib/Topology/Sheaves/Sheafify.lean
+++ b/Mathlib/Topology/Sheaves/Sheafify.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2020 Scott Morrison. All rights reserved.
+Copyright (c) 2020 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Topology.Sheaves.LocalPredicate
import Mathlib.Topology.Sheaves.Stalks
@@ -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 542289c1577d7..5593582768775 100644
--- a/Mathlib/Topology/Sheaves/Skyscraper.lean
+++ b/Mathlib/Topology/Sheaves/Skyscraper.lean
@@ -34,6 +34,7 @@ TODO: generalize universe level when calculating stalks, after generalizing univ
noncomputable section
open TopologicalSpace TopCat CategoryTheory CategoryTheory.Limits Opposite
+open scoped AlgebraicGeometry
universe u v w
@@ -51,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 =>
@@ -160,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]
@@ -246,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
@@ -255,7 +262,7 @@ 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 ..
@@ -265,48 +272,48 @@ def toSkyscraperPresheaf {𝓕 : Presheaf C X} {c : C} (f : 𝓕.stalk p₀ ⟶
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 (op U.unop.1) ≫ eqToHom (if_pos U.unop.2)
+ { app := fun U => f.app ((OpenNhds.inclusion p₀).op.obj U) ≫ eqToHom (if_pos U.unop.2)
naturality := fun U V inc => by
- dsimp
- erw [Category.comp_id, ← Category.assoc, comp_eqToHom_iff, Category.assoc,
+ 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]
- -- Porting note: added this `dsimp` and `rfl` in the end
- dsimp only [skyscraperPresheaf_obj, unop_op, Eq.ndrec]
- have hV : p₀ ∈ (OpenNhds.inclusion p₀).obj V.unop := V.unop.2; split_ifs <;>
- simp only [comp_eqToHom_iff, Category.assoc, eqToHom_trans, eqToHom_refl,
- Category.comp_id] <;> rfl }
+ 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
- · erw [← Category.assoc, colimit.ι_desc, Category.assoc, eqToHom_trans, eqToHom_refl,
+ · 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 :=
- colimit.hom_ext fun U => by
- erw [colimit.ι_desc]; dsimp; rw [dif_pos U.unop.2]
- rw [Category.assoc, Category.assoc, eqToHom_trans, eqToHom_refl, Category.comp_id,
- Presheaf.germ]
- congr 3
+ 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`
@@ -315,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
@@ -334,30 +334,32 @@ open StalkSkyscraperPresheafAdjunctionAuxs
-/
def skyscraperPresheafStalkAdjunction [HasColimits C] :
(Presheaf.stalkFunctor C p₀ : Presheaf C X ⥤ C) ⊣ skyscraperPresheafFunctor p₀ where
- homEquiv c 𝓕 :=
- { toFun := toSkyscraperPresheaf _
- invFun := fromStalk _
- left_inv := fromStalk_to_skyscraper _
- right_inv := to_skyscraper_fromStalk _ }
unit := StalkSkyscraperPresheafAdjunctionAuxs.unit _
counit := StalkSkyscraperPresheafAdjunctionAuxs.counit _
- homEquiv_unit {𝓕} c α := by
- ext U
- -- Porting note: `NatTrans.comp_app` is not picked up by `simp`
- rw [NatTrans.comp_app]
- simp only [Equiv.coe_fn_mk, toSkyscraperPresheaf_app, SkyscraperPresheafFunctor.map'_app,
- skyscraperPresheafFunctor_map, unit_app]
+ left_triangle_components X := by
+ dsimp [Presheaf.stalkFunctor, toSkyscraperPresheaf]
+ ext
+ simp only [Functor.comp_obj, Functor.op_obj, ι_colimMap_assoc, skyscraperPresheaf_obj,
+ whiskerLeft_app, Category.comp_id]
split_ifs with h
- · erw [Category.id_comp, ← Category.assoc, comp_eqToHom_iff, Category.assoc, Category.assoc,
- Category.assoc, Category.assoc, eqToHom_trans, eqToHom_refl, Category.comp_id, ←
- Category.assoc _ _ α, eqToHom_trans, eqToHom_refl, Category.id_comp]
- · apply ((if_neg h).symm.ndrec terminalIsTerminal).hom_ext
- homEquiv_counit {𝓕} c α := by
- -- Porting note: added a `dsimp`
- dsimp; ext U; simp only [Equiv.coe_fn_symm_mk, counit_app]
- erw [colimit.ι_desc, ← Category.assoc, colimit.ι_map, whiskerLeft_app, Category.assoc,
- colimit.ι_desc]
- rfl
+ · simp [skyscraperPresheafStalkOfSpecializes]
+ rfl
+ · simp only [skyscraperPresheafStalkOfSpecializes, colimit.isoColimitCocone_ι_hom,
+ skyscraperPresheafCoconeOfSpecializes_pt, skyscraperPresheafCoconeOfSpecializes_ι_app,
+ Functor.comp_obj, Functor.op_obj, skyscraperPresheaf_obj, Functor.const_obj_obj]
+ rw [comp_eqToHom_iff]
+ apply ((if_neg h).symm.ndrec terminalIsTerminal).hom_ext
+ right_triangle_components Y := by
+ ext
+ simp only [skyscraperPresheafFunctor_obj, Functor.id_obj, skyscraperPresheaf_obj,
+ Functor.comp_obj, Presheaf.stalkFunctor_obj, unit_app, counit_app,
+ skyscraperPresheafStalkOfSpecializes, skyscraperPresheafFunctor_map, Presheaf.comp_app,
+ toSkyscraperPresheaf_app, Category.id_comp, SkyscraperPresheafFunctor.map'_app]
+ split_ifs with h
+ · simp [Presheaf.germ]
+ rfl
+ · simp
+ rfl
instance [HasColimits C] : (skyscraperPresheafFunctor p₀ : C ⥤ Presheaf C X).IsRightAdjoint :=
(skyscraperPresheafStalkAdjunction _).isRightAdjoint
@@ -372,16 +374,15 @@ instance [HasColimits C] : (Presheaf.stalkFunctor C p₀).IsLeftAdjoint :=
def stalkSkyscraperSheafAdjunction [HasColimits C] :
Sheaf.forget C X ⋙ Presheaf.stalkFunctor _ p₀ ⊣ skyscraperSheafFunctor p₀ where
-- Porting note (#11041): `ext1` is changed to `Sheaf.Hom.ext`,
- homEquiv 𝓕 c :=
- ⟨fun f => ⟨toSkyscraperPresheaf p₀ f⟩, fun g => fromStalk p₀ g.1, fromStalk_to_skyscraper p₀,
- fun g => Sheaf.Hom.ext <| to_skyscraper_fromStalk _ _⟩
unit :=
{ app := fun 𝓕 => ⟨(StalkSkyscraperPresheafAdjunctionAuxs.unit p₀).app 𝓕.1⟩
naturality := fun 𝓐 𝓑 f => Sheaf.Hom.ext <| by
apply (StalkSkyscraperPresheafAdjunctionAuxs.unit p₀).naturality }
counit := StalkSkyscraperPresheafAdjunctionAuxs.counit p₀
- homEquiv_unit {𝓐} c f := Sheaf.Hom.ext (skyscraperPresheafStalkAdjunction p₀).homEquiv_unit
- homEquiv_counit {𝓐} c f := (skyscraperPresheafStalkAdjunction p₀).homEquiv_counit
+ left_triangle_components X :=
+ ((skyscraperPresheafStalkAdjunction p₀).left_triangle_components X.val)
+ right_triangle_components _ :=
+ Sheaf.Hom.ext ((skyscraperPresheafStalkAdjunction p₀).right_triangle_components _)
instance [HasColimits C] : (skyscraperSheafFunctor p₀ : C ⥤ Sheaf C X).IsRightAdjoint :=
(stalkSkyscraperSheafAdjunction _).isRightAdjoint
diff --git a/Mathlib/Topology/Sheaves/Stalks.lean b/Mathlib/Topology/Sheaves/Stalks.lean
index 36574cf04a2b3..125a7e70f0fc4 100644
--- a/Mathlib/Topology/Sheaves/Stalks.lean
+++ b/Mathlib/Topology/Sheaves/Stalks.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Justus Springer
+Authors: Kim Morrison, Justus Springer
-/
import Mathlib.Topology.Category.TopCat.OpenNhds
import Mathlib.Topology.Sheaves.Presheaf
@@ -60,6 +60,8 @@ open TopologicalSpace
open Opposite
+open scoped AlgebraicGeometry
+
variable {C : Type u} [Category.{v} C]
variable [HasColimits.{v} C]
variable {X Y Z : TopCat.{v}}
@@ -87,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
--- 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 : 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]
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
+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 : 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)
@@ -141,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
@@ -176,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
@@ -202,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
@@ -215,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]
@@ -246,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,
@@ -267,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) :
@@ -279,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
@@ -290,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⁻¹ℱ)ₓ`. -/
@@ -330,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}
@@ -389,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)]
@@ -399,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
@@ -409,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} _
@@ -421,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]
@@ -435,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₁
@@ -454,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) :
@@ -487,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) :
@@ -499,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`.
@@ -523,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)
@@ -563,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
@@ -597,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 05385bd2df372..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.
-/
@@ -91,7 +91,7 @@ end IsGenericPoint
theorem isGenericPoint_iff_forall_closed (hS : IsClosed S) (hxS : x ∈ S) :
IsGenericPoint x S ↔ ∀ Z : Set α, IsClosed Z → x ∈ Z → S ⊆ Z := by
have : closure {x} ⊆ S := closure_minimal (singleton_subset_iff.2 hxS) hS
- simp_rw [IsGenericPoint, subset_antisymm_iff, this, true_and_iff, closure, subset_sInter_iff,
+ simp_rw [IsGenericPoint, subset_antisymm_iff, this, true_and, closure, subset_sInter_iff,
mem_setOf_eq, and_imp, singleton_subset_iff]
end genericPoint
@@ -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 874083b9a9983..bd57a351804bd 100644
--- a/Mathlib/Topology/Specialization.lean
+++ b/Mathlib/Topology/Specialization.lean
@@ -5,8 +5,7 @@ Authors: Yaël Dillies
-/
import Mathlib.Order.Category.Preord
import Mathlib.Topology.Category.TopCat.Basic
-import Mathlib.Topology.ContinuousFunction.Basic
-import Mathlib.Topology.Separation
+import Mathlib.Topology.ContinuousMap.Basic
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/Spectral/Hom.lean b/Mathlib/Topology/Spectral/Hom.lean
index 078b9875e0dbe..30c704a2d0504 100644
--- a/Mathlib/Topology/Spectral/Hom.lean
+++ b/Mathlib/Topology/Spectral/Hom.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.Topology.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Basic
/-!
# Spectral maps
diff --git a/Mathlib/Topology/StoneCech.lean b/Mathlib/Topology/StoneCech.lean
index ba2b4232abec5..3beed85e1b698 100644
--- a/Mathlib/Topology/StoneCech.lean
+++ b/Mathlib/Topology/StoneCech.lean
@@ -100,7 +100,7 @@ instance Ultrafilter.t2Space : T2Space (Ultrafilter α) :=
instance : TotallyDisconnectedSpace (Ultrafilter α) := by
rw [totallyDisconnectedSpace_iff_connectedComponent_singleton]
intro A
- simp only [Set.eq_singleton_iff_unique_mem, mem_connectedComponent, true_and_iff]
+ simp only [Set.eq_singleton_iff_unique_mem, mem_connectedComponent, true_and]
intro B hB
rw [← Ultrafilter.coe_le_coe]
intro s hs
@@ -148,15 +148,18 @@ theorem induced_topology_pure :
simp
/-- `pure : α → Ultrafilter α` defines a dense inducing of `α` in `Ultrafilter α`. -/
-theorem denseInducing_pure : @DenseInducing _ _ ⊥ _ (pure : α → Ultrafilter α) :=
+theorem isDenseInducing_pure : @IsDenseInducing _ _ ⊥ _ (pure : α → Ultrafilter α) :=
letI : TopologicalSpace α := ⊥
⟨⟨induced_topology_pure.symm⟩, denseRange_pure⟩
-- The following refined version will never be used
/-- `pure : α → Ultrafilter α` defines a dense embedding of `α` in `Ultrafilter α`. -/
-theorem denseEmbedding_pure : @DenseEmbedding _ _ ⊥ _ (pure : α → Ultrafilter α) :=
+theorem isDenseEmbedding_pure : @IsDenseEmbedding _ _ ⊥ _ (pure : α → Ultrafilter α) :=
letI : TopologicalSpace α := ⊥
- { denseInducing_pure with inj := ultrafilter_pure_injective }
+ { isDenseInducing_pure with inj := ultrafilter_pure_injective }
+
+@[deprecated (since := "2024-09-30")]
+alias denseEmbedding_pure := isDenseEmbedding_pure
end Embedding
@@ -166,21 +169,21 @@ section Extension
unique extension to a continuous function `Ultrafilter α → γ`. We
already know it must be unique because `α → Ultrafilter α` is a
dense embedding and `γ` is Hausdorff. For existence, we will invoke
- `DenseInducing.continuous_extend`. -/
+ `IsDenseInducing.continuous_extend`. -/
variable {γ : Type*} [TopologicalSpace γ]
/-- The extension of a function `α → γ` to a function `Ultrafilter α → γ`.
When `γ` is a compact Hausdorff space it will be continuous. -/
def Ultrafilter.extend (f : α → γ) : Ultrafilter α → γ :=
letI : TopologicalSpace α := ⊥
- denseInducing_pure.extend f
+ isDenseInducing_pure.extend f
variable [T2Space γ]
theorem ultrafilter_extend_extends (f : α → γ) : Ultrafilter.extend f ∘ pure = f := by
letI : TopologicalSpace α := ⊥
haveI : DiscreteTopology α := ⟨rfl⟩
- exact funext (denseInducing_pure.extend_eq continuous_of_discreteTopology)
+ exact funext (isDenseInducing_pure.extend_eq continuous_of_discreteTopology)
variable [CompactSpace γ]
@@ -191,7 +194,7 @@ theorem continuous_ultrafilter_extend (f : α → γ) : Continuous (Ultrafilter.
isCompact_univ.ultrafilter_le_nhds (b.map f) (by rw [le_principal_iff]; exact univ_mem)
⟨c, le_trans (map_mono (ultrafilter_comap_pure_nhds _)) h'⟩
let _ : TopologicalSpace α := ⊥
- exact denseInducing_pure.continuous_extend h
+ exact isDenseInducing_pure.continuous_extend h
/-- The value of `Ultrafilter.extend f` on an ultrafilter `b` is the
unique limit of the ultrafilter `b.map f` in `γ`. -/
@@ -210,7 +213,7 @@ theorem ultrafilter_extend_eq_iff {f : α → γ} {b : Ultrafilter α} {c : γ}
exact le_rfl,
fun h ↦
let _ : TopologicalSpace α := ⊥
- denseInducing_pure.extend_eq_of_tendsto
+ isDenseInducing_pure.extend_eq_of_tendsto
(le_trans (map_mono (ultrafilter_comap_pure_nhds _)) h)⟩
end Extension
diff --git a/Mathlib/Topology/Support.lean b/Mathlib/Topology/Support.lean
index 3ddebbe31bfd6..2a3e19012527f 100644
--- a/Mathlib/Topology/Support.lean
+++ b/Mathlib/Topology/Support.lean
@@ -4,8 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
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
@@ -31,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
@@ -97,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
@@ -118,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
@@ -200,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) :
@@ -256,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. -/
@@ -293,18 +297,33 @@ 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') :
HasCompactMulSupport (f * f') := hf.comp₂_left hf' (mul_one 1)
+@[to_additive, simp]
+protected lemma HasCompactMulSupport.one {α β : Type*} [TopologicalSpace α] [One β] :
+ HasCompactMulSupport (1 : α → β) := by
+ simp [HasCompactMulSupport, mulTSupport]
+
end Monoid
+section DivisionMonoid
+
+@[to_additive]
+protected lemma HasCompactMulSupport.inv' {α β : Type*} [TopologicalSpace α] [DivisionMonoid β]
+ {f : α → β} (hf : HasCompactMulSupport f) :
+ HasCompactMulSupport (f⁻¹) := by
+ simpa only [HasCompactMulSupport, mulTSupport, mulSupport_inv'] using hf
+
+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 ⊢
@@ -315,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 ⊢
@@ -329,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 ⊢
@@ -343,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 fb21530f3f80a..b10faf84a84ef 100644
--- a/Mathlib/Topology/UniformSpace/AbsoluteValue.lean
+++ b/Mathlib/Topology/UniformSpace/AbsoluteValue.lean
@@ -5,7 +5,7 @@ Authors: Patrick Massot
-/
import Mathlib.Algebra.Order.AbsoluteValue
import Mathlib.Algebra.Order.Field.Basic
-import Mathlib.Topology.UniformSpace.Basic
+import Mathlib.Topology.UniformSpace.OfFun
/-!
# Uniform structure induced by an absolute value
@@ -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 903552b0c52dd..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 denseInducing : DenseInducing ι :=
- ⟨pkg.uniformInducing.inducing, pkg.dense⟩
+theorem isDenseInducing : IsDenseInducing ι :=
+ ⟨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
@@ -114,23 +116,23 @@ section Extend
/-- Extension of maps to completions -/
protected def extend (f : α → β) : hatα → β :=
- if UniformContinuous f then pkg.denseInducing.extend f else fun x => f (pkg.dense.some x)
+ if UniformContinuous f then pkg.isDenseInducing.extend f else fun x => f (pkg.dense.some x)
variable {f : α → β}
-theorem extend_def (hf : UniformContinuous f) : pkg.extend f = pkg.denseInducing.extend f :=
+theorem extend_def (hf : UniformContinuous f) : pkg.extend f = pkg.isDenseInducing.extend f :=
if_pos hf
theorem extend_coe [T2Space β] (hf : UniformContinuous f) (a : α) : (pkg.extend f) (ι a) = f a := by
rw [pkg.extend_def hf]
- exact pkg.denseInducing.extend_eq hf.continuous a
+ exact pkg.isDenseInducing.extend_eq hf.continuous a
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
@@ -276,17 +278,17 @@ theorem compare_comp_eq_compare (γ : Type*) [TopologicalSpace γ]
letI := pkg.uniformStruct.toTopologicalSpace
letI := pkg'.uniformStruct.toTopologicalSpace
(∀ a : pkg.space,
- Filter.Tendsto f (Filter.comap pkg.coe (𝓝 a)) (𝓝 ((pkg.denseInducing.extend f) a))) →
- pkg.denseInducing.extend f ∘ pkg'.compare pkg = pkg'.denseInducing.extend f := by
+ Filter.Tendsto f (Filter.comap pkg.coe (𝓝 a)) (𝓝 ((pkg.isDenseInducing.extend f) a))) →
+ pkg.isDenseInducing.extend f ∘ pkg'.compare pkg = pkg'.isDenseInducing.extend f := by
let _ := pkg'.uniformStruct
let _ := pkg.uniformStruct
intro h
- have (x : α) : (pkg.denseInducing.extend f ∘ pkg'.compare pkg) (pkg'.coe x) = f x := by
- simp only [Function.comp_apply, compare_coe, DenseInducing.extend_eq _ cont_f, implies_true]
- apply (DenseInducing.extend_unique (AbstractCompletion.denseInducing _) this
+ have (x : α) : (pkg.isDenseInducing.extend f ∘ pkg'.compare pkg) (pkg'.coe x) = f x := by
+ simp only [Function.comp_apply, compare_coe, IsDenseInducing.extend_eq _ cont_f, implies_true]
+ apply (IsDenseInducing.extend_unique (AbstractCompletion.isDenseInducing _) this
(Continuous.comp _ (uniformContinuous_compare pkg' pkg).continuous )).symm
- apply DenseInducing.continuous_extend
- exact fun a ↦ ⟨(pkg.denseInducing.extend f) a, h a⟩
+ apply IsDenseInducing.continuous_extend
+ exact fun a ↦ ⟨(pkg.isDenseInducing.extend f) a, h a⟩
end Compare
@@ -305,8 +307,8 @@ protected def prod : AbstractCompletion (α × β) where
uniformStruct := inferInstance
complete := inferInstance
separation := inferInstance
- uniformInducing := UniformInducing.prod pkg.uniformInducing pkg'.uniformInducing
- dense := DenseRange.prod_map pkg.dense pkg'.dense
+ 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 75e7105788ec2..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,11 +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.uniformEmbedding_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 eca83bcfea729..f720fa95c4ba6 100644
--- a/Mathlib/Topology/UniformSpace/Basic.lean
+++ b/Mathlib/Topology/UniformSpace/Basic.lean
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot
-/
import Mathlib.Order.Filter.SmallSets
-import Mathlib.Tactic.Monotonicity
+import Mathlib.Tactic.Monotonicity.Basic
import Mathlib.Topology.Compactness.Compact
import Mathlib.Topology.NhdsSet
import Mathlib.Algebra.Group.Defs
@@ -17,7 +17,7 @@ generalize to uniform spaces, e.g.
* uniform continuity (in this file)
* completeness (in `Cauchy.lean`)
-* extension of uniform continuous functions to complete spaces (in `UniformEmbedding.lean`)
+* extension of uniform continuous functions to complete spaces (in `IsUniformEmbedding.lean`)
* totally bounded sets (in `Cauchy.lean`)
* totally bounded complete sets are compact (in `Cauchy.lean`)
@@ -136,6 +136,31 @@ theorem mem_idRel {a b : α} : (a, b) ∈ @idRel α ↔ a = b :=
theorem idRel_subset {s : Set (α × α)} : idRel ⊆ s ↔ ∀ a, (a, a) ∈ s := by
simp [subset_def]
+theorem eq_singleton_left_of_prod_subset_idRel {X : Type _} {S T : Set X} (hS : S.Nonempty)
+ (hT : T.Nonempty) (h_diag : S ×ˢ T ⊆ idRel) : ∃ x, S = {x} := by
+ rcases hS, hT with ⟨⟨s, hs⟩, ⟨t, ht⟩⟩
+ refine ⟨s, eq_singleton_iff_nonempty_unique_mem.mpr ⟨⟨s, hs⟩, fun x hx ↦ ?_⟩⟩
+ rw [prod_subset_iff] at h_diag
+ replace hs := h_diag s hs t ht
+ replace hx := h_diag x hx t ht
+ simp only [idRel, mem_setOf_eq] at hx hs
+ rwa [← hs] at hx
+
+theorem eq_singleton_right_prod_subset_idRel {X : Type _} {S T : Set X} (hS : S.Nonempty)
+ (hT : T.Nonempty) (h_diag : S ×ˢ T ⊆ idRel) : ∃ x, T = {x} := by
+ rw [Set.prod_subset_iff] at h_diag
+ replace h_diag := fun x hx y hy => (h_diag y hy x hx).symm
+ exact eq_singleton_left_of_prod_subset_idRel hT hS (prod_subset_iff.mpr h_diag)
+
+theorem eq_singleton_prod_subset_idRel {X : Type _} {S T : Set X} (hS : S.Nonempty)
+ (hT : T.Nonempty) (h_diag : S ×ˢ T ⊆ idRel) : ∃ x, S = {x} ∧ T = {x} := by
+ obtain ⟨⟨x, hx⟩, ⟨y, hy⟩⟩ := eq_singleton_left_of_prod_subset_idRel hS hT h_diag,
+ eq_singleton_right_prod_subset_idRel hS hT h_diag
+ refine ⟨x, ⟨hx, ?_⟩⟩
+ rw [hy, Set.singleton_eq_singleton_iff]
+ exact (Set.prod_subset_iff.mp h_diag x (by simp only [hx, Set.mem_singleton]) y
+ (by simp only [hy, Set.mem_singleton])).symm
+
/-- The composition of relations -/
def compRel (r₁ r₂ : Set (α × α)) :=
{ p : α × α | ∃ z : α, (p.1, z) ∈ r₁ ∧ (z, p.2) ∈ r₂ }
@@ -367,33 +392,6 @@ theorem UniformSpace.replaceTopology_eq {α : Type*} [i : TopologicalSpace α] (
(h : i = u.toTopologicalSpace) : u.replaceTopology h = u :=
UniformSpace.ext rfl
--- Porting note: rfc: use `UniformSpace.Core.mkOfBasis`? This will change defeq here and there
-/-- Define a `UniformSpace` using a "distance" function. The function can be, e.g., the
-distance in a (usual or extended) metric space or an absolute value on a ring. -/
-def UniformSpace.ofFun {α : Type u} {β : Type v} [OrderedAddCommMonoid β]
- (d : α → α → β) (refl : ∀ x, d x x = 0) (symm : ∀ x y, d x y = d y x)
- (triangle : ∀ x y z, d x z ≤ d x y + d y z)
- (half : ∀ ε > (0 : β), ∃ δ > (0 : β), ∀ x < δ, ∀ y < δ, x + y < ε) :
- UniformSpace α :=
- .ofCore
- { uniformity := ⨅ r > 0, 𝓟 { x | d x.1 x.2 < r }
- refl := le_iInf₂ fun r hr => principal_mono.2 <| idRel_subset.2 fun x => by simpa [refl]
- symm := tendsto_iInf_iInf fun r => tendsto_iInf_iInf fun _ => tendsto_principal_principal.2
- fun x hx => by rwa [mem_setOf, symm]
- comp := le_iInf₂ fun r hr => let ⟨δ, h0, hδr⟩ := half r hr; le_principal_iff.2 <|
- mem_of_superset
- (mem_lift' <| mem_iInf_of_mem δ <| mem_iInf_of_mem h0 <| mem_principal_self _)
- fun (x, z) ⟨y, h₁, h₂⟩ => (triangle _ _ _).trans_lt (hδr _ h₁ _ h₂) }
-
-theorem UniformSpace.hasBasis_ofFun {α : Type u} {β : Type v} [LinearOrderedAddCommMonoid β]
- (h₀ : ∃ x : β, 0 < x) (d : α → α → β) (refl : ∀ x, d x x = 0) (symm : ∀ x y, d x y = d y x)
- (triangle : ∀ x y z, d x z ≤ d x y + d y z)
- (half : ∀ ε > (0 : β), ∃ δ > (0 : β), ∀ x < δ, ∀ y < δ, x + y < ε) :
- 𝓤[.ofFun d refl symm triangle half].HasBasis ((0 : β) < ·) (fun ε => { x | d x.1 x.2 < ε }) :=
- hasBasis_biInf_principal'
- (fun ε₁ h₁ ε₂ h₂ => ⟨min ε₁ ε₂, lt_min h₁ h₂, fun _x hx => lt_of_lt_of_le hx (min_le_left _ _),
- fun _x hx => lt_of_lt_of_le hx (min_le_right _ _)⟩) h₀
-
section UniformSpace
variable [UniformSpace α]
@@ -838,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]
@@ -856,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
@@ -894,7 +892,6 @@ lemma DenseRange.iUnion_uniformity_ball {ι : Type*} {xs : ι → α}
### Uniformity bases
-/
-
/-- Open elements of `𝓤 α` form a basis of `𝓤 α`. -/
theorem uniformity_hasBasis_open : HasBasis (𝓤 α) (fun V : Set (α × α) => V ∈ 𝓤 α ∧ IsOpen V) id :=
hasBasis_self.2 fun s hs =>
@@ -1119,6 +1116,11 @@ theorem uniformity_comap {_ : UniformSpace β} (f : α → β) :
𝓤[UniformSpace.comap f ‹_›] = comap (Prod.map f f) (𝓤 β) :=
rfl
+lemma ball_preimage {f : α → β} {U : Set (β × β)} {x : α} :
+ UniformSpace.ball x (Prod.map f f ⁻¹' U) = f ⁻¹' UniformSpace.ball (f x) U := by
+ ext : 1
+ simp only [UniformSpace.ball, mem_preimage, Prod.map_apply]
+
@[simp]
theorem uniformSpace_comap_id {α : Type*} : UniformSpace.comap (id : α → α) = id := by
ext : 2
@@ -1462,10 +1464,12 @@ theorem UniformContinuous.prod_mk_right {f : α × β → γ} (h : UniformContin
UniformContinuous fun b => f (a, b) :=
h.comp (uniformContinuous_const.prod_mk uniformContinuous_id)
-theorem UniformContinuous.prod_map [UniformSpace δ] {f : α → γ} {g : β → δ}
+theorem UniformContinuous.prodMap [UniformSpace δ] {f : α → γ} {g : β → δ}
(hf : UniformContinuous f) (hg : UniformContinuous g) : UniformContinuous (Prod.map f g) :=
(hf.comp uniformContinuous_fst).prod_mk (hg.comp uniformContinuous_snd)
+@[deprecated (since := "2024-10-06")] alias UniformContinuous.prod_map := UniformContinuous.prodMap
+
theorem toTopologicalSpace_prod {α} {β} [u : UniformSpace α] [v : UniformSpace β] :
@UniformSpace.toTopologicalSpace (α × β) instUniformSpaceProd =
@instTopologicalSpaceProd α β u.toTopologicalSpace v.toTopologicalSpace :=
@@ -1481,7 +1485,7 @@ theorem uniformContinuous_inf_dom_left₂ {α β γ} {f : α → β → γ} {ua1
have ha := @UniformContinuous.inf_dom_left _ _ id ua1 ua2 ua1 (@uniformContinuous_id _ (id _))
have hb := @UniformContinuous.inf_dom_left _ _ id ub1 ub2 ub1 (@uniformContinuous_id _ (id _))
have h_unif_cont_id :=
- @UniformContinuous.prod_map _ _ _ _ (ua1 ⊓ ua2) (ub1 ⊓ ub2) ua1 ub1 _ _ ha hb
+ @UniformContinuous.prodMap _ _ _ _ (ua1 ⊓ ua2) (ub1 ⊓ ub2) ua1 ub1 _ _ ha hb
exact @UniformContinuous.comp _ _ _ (id _) (id _) _ _ _ h h_unif_cont_id
/-- A version of `UniformContinuous.inf_dom_right` for binary functions -/
@@ -1494,7 +1498,7 @@ theorem uniformContinuous_inf_dom_right₂ {α β γ} {f : α → β → γ} {ua
have ha := @UniformContinuous.inf_dom_right _ _ id ua1 ua2 ua2 (@uniformContinuous_id _ (id _))
have hb := @UniformContinuous.inf_dom_right _ _ id ub1 ub2 ub2 (@uniformContinuous_id _ (id _))
have h_unif_cont_id :=
- @UniformContinuous.prod_map _ _ _ _ (ua1 ⊓ ua2) (ub1 ⊓ ub2) ua2 ub2 _ _ ha hb
+ @UniformContinuous.prodMap _ _ _ _ (ua1 ⊓ ua2) (ub1 ⊓ ub2) ua2 ub2 _ _ ha hb
exact @UniformContinuous.comp _ _ _ (id _) (id _) _ _ _ h h_unif_cont_id
/-- A version of `uniformContinuous_sInf_dom` for binary functions -/
@@ -1507,7 +1511,7 @@ theorem uniformContinuous_sInf_dom₂ {α β γ} {f : α → β → γ} {uas : S
let _ : UniformSpace (α × β) := instUniformSpaceProd
have ha := uniformContinuous_sInf_dom ha uniformContinuous_id
have hb := uniformContinuous_sInf_dom hb uniformContinuous_id
- have h_unif_cont_id := @UniformContinuous.prod_map _ _ _ _ (sInf uas) (sInf ubs) ua ub _ _ ha hb
+ have h_unif_cont_id := @UniformContinuous.prodMap _ _ _ _ (sInf uas) (sInf ubs) ua ub _ _ ha hb
exact @UniformContinuous.comp _ _ _ (id _) (id _) _ _ _ hf h_unif_cont_id
end Prod
@@ -1543,7 +1547,7 @@ theorem UniformContinuous₂.comp {f : α → β → γ} {g : γ → δ} (hg : U
theorem UniformContinuous₂.bicompl {f : α → β → γ} {ga : δ → α} {gb : δ' → β}
(hf : UniformContinuous₂ f) (hga : UniformContinuous ga) (hgb : UniformContinuous gb) :
UniformContinuous₂ (bicompl f ga gb) :=
- hf.uniformContinuous.comp (hga.prod_map hgb)
+ hf.uniformContinuous.comp (hga.prodMap hgb)
end
@@ -1566,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β⟩
@@ -1735,7 +1739,7 @@ theorem continuousAt_iff'_left [TopologicalSpace β] {f : β → α} {b : β} :
theorem continuousAt_iff_prod [TopologicalSpace β] {f : β → α} {b : β} :
ContinuousAt f b ↔ Tendsto (fun x : β × β => (f x.1, f x.2)) (𝓝 (b, b)) (𝓤 α) :=
- ⟨fun H => le_trans (H.prod_map' H) (nhds_le_uniformity _), fun H =>
+ ⟨fun H => le_trans (H.prodMap' H) (nhds_le_uniformity _), fun H =>
continuousAt_iff'_left.2 <| H.comp <| tendsto_id.prod_mk_nhds tendsto_const_nhds⟩
theorem continuousWithinAt_iff'_right [TopologicalSpace β] {f : β → α} {b : β} {s : Set β} :
diff --git a/Mathlib/Topology/UniformSpace/Cauchy.lean b/Mathlib/Topology/UniformSpace/Cauchy.lean
index bdc078d4dbba6..b2be7ed715fd7 100644
--- a/Mathlib/Topology/UniformSpace/Cauchy.lean
+++ b/Mathlib/Topology/UniformSpace/Cauchy.lean
@@ -6,6 +6,7 @@ Authors: Johannes Hölzl, Mario Carneiro
import Mathlib.Topology.Algebra.Constructions
import Mathlib.Topology.Bases
import Mathlib.Topology.UniformSpace.Basic
+import Mathlib.Algebra.Order.Group.Nat
/-!
# Theory of Cauchy filters in uniform spaces. Complete uniform spaces. Totally bounded subsets.
@@ -249,7 +250,7 @@ theorem CauchySeq.subseq_mem {V : ℕ → Set (α × α)} (hV : ∀ n, V n ∈
exact ⟨N, fun k hk l hl => H _ (le_trans hk hl) _ hk⟩
obtain ⟨φ : ℕ → ℕ, φ_extr : StrictMono φ, hφ : ∀ n, ∀ l ≥ φ n, (u l, u <| φ n) ∈ V n⟩ :=
extraction_forall_of_eventually' this
- exact ⟨φ, φ_extr, fun n => hφ _ _ (φ_extr <| lt_add_one n).le⟩
+ exact ⟨φ, φ_extr, fun n => hφ _ _ (φ_extr <| Nat.lt_add_one n).le⟩
theorem Filter.Tendsto.subseq_mem_entourage {V : ℕ → Set (α × α)} (hV : ∀ n, V n ∈ 𝓤 α) {u : ℕ → α}
{a : α} (hu : Tendsto u atTop (𝓝 a)) : ∃ φ : ℕ → ℕ, StrictMono φ ∧ (u (φ 0), a) ∈ V 0 ∧
@@ -281,7 +282,7 @@ theorem Filter.HasBasis.cauchySeq_iff {γ} [Nonempty β] [SemilatticeSup β] {u
CauchySeq u ↔ ∀ i, p i → ∃ N, ∀ m, N ≤ m → ∀ n, N ≤ n → (u m, u n) ∈ s i := by
rw [cauchySeq_iff_tendsto, ← prod_atTop_atTop_eq]
refine (atTop_basis.prod_self.tendsto_iff h).trans ?_
- simp only [exists_prop, true_and_iff, MapsTo, preimage, subset_def, Prod.forall, mem_prod_eq,
+ simp only [exists_prop, true_and, MapsTo, preimage, subset_def, Prod.forall, mem_prod_eq,
mem_setOf_eq, mem_Ici, and_imp, Prod.map, @forall_swap (_ ≤ _) β]
theorem Filter.HasBasis.cauchySeq_iff' {γ} [Nonempty β] [SemilatticeSup β] {u : β → α}
@@ -562,7 +563,7 @@ theorem TotallyBounded.image [UniformSpace β] {f : α → β} {s : Set α} (hs
simp only [mem_image, iUnion_exists, biUnion_and', iUnion_iUnion_eq_right, image_subset_iff,
preimage_iUnion, preimage_setOf_eq]
simp? [subset_def] at hct says
- simp only [mem_setOf_eq, subset_def, mem_iUnion, exists_prop', nonempty_prop] at hct
+ simp only [mem_setOf_eq, subset_def, mem_iUnion, exists_prop] at hct
intro x hx
simpa using hct x hx⟩
@@ -786,4 +787,29 @@ theorem secondCountable_of_separable [SeparableSpace α] : SecondCountableTopolo
refine ⟨_, ⟨y, hys, k, rfl⟩, (hts k).subset hxy, fun z hz => ?_⟩
exact hUV (ball_subset_of_comp_subset (hk hxy) hUU' (hk hz))
+section DiscreteUniformity
+
+open Filter
+
+/-- A Cauchy filter in a discrete uniform space is contained in a principal filter-/
+theorem DiscreteUnif.cauchy_le_pure {X : Type _} {uX : UniformSpace X}
+ (hX : uX = ⊥) {α : Filter X} (hα : Cauchy α) : ∃ x : X, α = pure x := by
+ rcases hα with ⟨α_ne_bot, α_le⟩
+ rw [hX, bot_uniformity, le_principal_iff, mem_prod_iff] at α_le
+ obtain ⟨S, ⟨hS, ⟨T, ⟨hT, H⟩⟩⟩⟩ := α_le
+ obtain ⟨x, rfl⟩ := eq_singleton_left_of_prod_subset_idRel (α_ne_bot.nonempty_of_mem hS)
+ (Filter.nonempty_of_mem hT) H
+ exact ⟨x, α_ne_bot.le_pure_iff.mp <| le_pure_iff.mpr hS⟩
+
+/-- A constant to which a Cauchy filter in a discrete uniform space converges. -/
+noncomputable def DiscreteUnif.cauchyConst {X : Type _} {uX : UniformSpace X}
+ (hX : uX = ⊥) {α : Filter X} (hα : Cauchy α) : X :=
+ (DiscreteUnif.cauchy_le_pure hX hα).choose
+
+theorem DiscreteUnif.eq_const_of_cauchy {X : Type _} {uX : UniformSpace X} (hX : uX = ⊥)
+ {α : Filter X} (hα : Cauchy α) : α = pure (DiscreteUnif.cauchyConst hX hα) :=
+ (DiscreteUnif.cauchy_le_pure hX hα).choose_spec
+
+end DiscreteUniformity
+
end UniformSpace
diff --git a/Mathlib/Topology/UniformSpace/Compact.lean b/Mathlib/Topology/UniformSpace/Compact.lean
index 8f4de0a668e02..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`.
@@ -151,7 +150,7 @@ theorem CompactSpace.uniformContinuous_of_continuous [CompactSpace α] {f : α
(h : Continuous f) : UniformContinuous f :=
calc map (Prod.map f f) (𝓤 α)
= map (Prod.map f f) (𝓝ˢ (diagonal α)) := by rw [nhdsSet_diagonal_eq_uniformity]
- _ ≤ 𝓝ˢ (diagonal β) := (h.prod_map h).tendsto_nhdsSet mapsTo_prod_map_diagonal
+ _ ≤ 𝓝ˢ (diagonal β) := (h.prodMap h).tendsto_nhdsSet mapsTo_prod_map_diagonal
_ ≤ 𝓤 β := nhdsSet_diagonal_le_uniformity
/-- Heine-Cantor: a continuous function on a compact set of a uniform space is uniformly
diff --git a/Mathlib/Topology/UniformSpace/CompactConvergence.lean b/Mathlib/Topology/UniformSpace/CompactConvergence.lean
index 7f50b07c0cc1d..c70587a4d1137 100644
--- a/Mathlib/Topology/UniformSpace/CompactConvergence.lean
+++ b/Mathlib/Topology/UniformSpace/CompactConvergence.lean
@@ -171,11 +171,14 @@ instance compactConvergenceUniformSpace : UniformSpace C(α, β) :=
nhds_induced, tendsto_comap_iff, UniformOnFun.tendsto_iff_tendstoUniformlyOn]
rfl
-theorem uniformEmbedding_toUniformOnFunIsCompact :
- UniformEmbedding (toUniformOnFunIsCompact : C(α, β) → α →ᵤ[{K | IsCompact K}] β) where
+theorem isUniformEmbedding_toUniformOnFunIsCompact :
+ IsUniformEmbedding (toUniformOnFunIsCompact : C(α, β) → α →ᵤ[{K | IsCompact K}] β) where
comap_uniformity := rfl
inj := DFunLike.coe_injective
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_toUniformOnFunIsCompact := isUniformEmbedding_toUniformOnFunIsCompact
+
-- The following definitions and theorems
-- used to be a part of the construction of the `UniformSpace C(α, β)` structure
-- before it was migrated to `UniformOnFun`
@@ -184,7 +187,7 @@ theorem _root_.Filter.HasBasis.compactConvergenceUniformity {ι : Type*} {pi :
{s : ι → Set (β × β)} (h : (𝓤 β).HasBasis pi s) :
HasBasis (𝓤 C(α, β)) (fun p : Set α × ι => IsCompact p.1 ∧ pi p.2) fun p =>
{ fg : C(α, β) × C(α, β) | ∀ x ∈ p.1, (fg.1 x, fg.2 x) ∈ s p.2 } := by
- rw [← uniformEmbedding_toUniformOnFunIsCompact.comap_uniformity]
+ rw [← isUniformEmbedding_toUniformOnFunIsCompact.comap_uniformity]
exact .comap _ <| UniformOnFun.hasBasis_uniformity_of_basis _ _ {K | IsCompact K}
⟨∅, isCompact_empty⟩ (directedOn_of_sup_mem fun _ _ ↦ IsCompact.union) h
@@ -249,38 +252,39 @@ 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 δ]
theorem uniformContinuous_comp (g : C(β, δ)) (hg : UniformContinuous g) :
UniformContinuous (ContinuousMap.comp g : C(α, β) → C(α, δ)) :=
- uniformEmbedding_toUniformOnFunIsCompact.uniformContinuous_iff.mpr <|
+ isUniformEmbedding_toUniformOnFunIsCompact.uniformContinuous_iff.mpr <|
UniformOnFun.postcomp_uniformContinuous hg |>.comp
- uniformEmbedding_toUniformOnFunIsCompact.uniformContinuous
+ isUniformEmbedding_toUniformOnFunIsCompact.uniformContinuous
+
+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 uniformInducing_comp (g : C(β, δ)) (hg : UniformInducing g) :
- UniformInducing (ContinuousMap.comp g : C(α, β) → C(α, δ)) :=
- uniformEmbedding_toUniformOnFunIsCompact.toUniformInducing.of_comp_iff.mp <|
- UniformOnFun.postcomp_uniformInducing hg |>.comp
- uniformEmbedding_toUniformOnFunIsCompact.toUniformInducing
+theorem isUniformEmbedding_comp (g : C(β, δ)) (hg : IsUniformEmbedding g) :
+ IsUniformEmbedding (ContinuousMap.comp g : C(α, β) → C(α, δ)) :=
+ isUniformEmbedding_toUniformOnFunIsCompact.of_comp_iff.mp <|
+ UniformOnFun.postcomp_isUniformEmbedding hg |>.comp
+ isUniformEmbedding_toUniformOnFunIsCompact
-theorem uniformEmbedding_comp (g : C(β, δ)) (hg : UniformEmbedding g) :
- UniformEmbedding (ContinuousMap.comp g : C(α, β) → C(α, δ)) :=
- uniformEmbedding_toUniformOnFunIsCompact.of_comp_iff.mp <|
- UniformOnFun.postcomp_uniformEmbedding hg |>.comp
- uniformEmbedding_toUniformOnFunIsCompact
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_comp := isUniformEmbedding_comp
theorem uniformContinuous_comp_left (g : C(α, γ)) :
UniformContinuous (fun f ↦ f.comp g : C(γ, β) → C(α, β)) :=
- uniformEmbedding_toUniformOnFunIsCompact.uniformContinuous_iff.mpr <|
+ isUniformEmbedding_toUniformOnFunIsCompact.uniformContinuous_iff.mpr <|
UniformOnFun.precomp_uniformContinuous (fun _ hK ↦ hK.image g.continuous) |>.comp
- uniformEmbedding_toUniformOnFunIsCompact.uniformContinuous
+ isUniformEmbedding_toUniformOnFunIsCompact.uniformContinuous
/-- Any pair of a homeomorphism `X ≃ₜ Z` and an isomorphism `Y ≃ᵤ T` of uniform spaces gives rise
to an isomorphism `C(X, Y) ≃ᵤ C(Z, T)`. -/
@@ -372,7 +376,8 @@ Sufficient conditions on `α` to satisfy this condition are (weak) local compact
`ContinuousMap.instCompleteSpaceOfSequentialSpace`). -/
lemma completeSpace_of_restrictGenTopology (h : RestrictGenTopology {K : Set α | IsCompact K}) :
CompleteSpace C(α, β) := by
- rw [completeSpace_iff_isComplete_range uniformEmbedding_toUniformOnFunIsCompact.toUniformInducing,
+ rw [completeSpace_iff_isComplete_range
+ 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 709fc27902447..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,10 +70,10 @@ 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.uniformEmbedding_coe_real.toUniformInducing)
- (dense := Rat.denseEmbedding_coe_real.dense)
+ 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 79943bfbcdbcf..5c4968e5a26e8 100644
--- a/Mathlib/Topology/UniformSpace/CompleteSeparated.lean
+++ b/Mathlib/Topology/UniformSpace/CompleteSeparated.lean
@@ -27,20 +27,29 @@ 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 UniformEmbedding.toClosedEmbedding [UniformSpace α] [UniformSpace β] [CompleteSpace α]
- [T0Space β] {f : α → β} (hf : UniformEmbedding f) :
- ClosedEmbedding f :=
- ⟨hf.embedding, hf.toUniformInducing.isComplete_range.isClosed⟩
+theorem IsUniformEmbedding.toIsClosedEmbedding [UniformSpace α] [UniformSpace β] [CompleteSpace α]
+ [T0Space β] {f : α → β} (hf : IsUniformEmbedding f) :
+ IsClosedEmbedding f :=
+ ⟨hf.isEmbedding, hf.isUniformInducing.isComplete_range.isClosed⟩
-namespace DenseInducing
+@[deprecated (since := "2024-10-20")]
+alias IsUniformEmbedding.toClosedEmbedding := IsUniformEmbedding.toIsClosedEmbedding
+
+@[deprecated (since := "2024-10-01")]
+alias UniformEmbedding.toIsClosedEmbedding := IsUniformEmbedding.toIsClosedEmbedding
+
+@[deprecated (since := "2024-10-20")]
+alias UniformEmbedding.toClosedEmbedding := UniformEmbedding.toIsClosedEmbedding
+
+namespace IsDenseInducing
open Filter
variable [TopologicalSpace α] {β : Type*} [TopologicalSpace β]
variable {γ : Type*} [UniformSpace γ] [CompleteSpace γ] [T0Space γ]
-theorem continuous_extend_of_cauchy {e : α → β} {f : α → γ} (de : DenseInducing e)
+theorem continuous_extend_of_cauchy {e : α → β} {f : α → γ} (de : IsDenseInducing e)
(h : ∀ b : β, Cauchy (map f (comap e <| 𝓝 b))) : Continuous (de.extend f) :=
de.continuous_extend fun b => CompleteSpace.complete (h b)
-end DenseInducing
+end IsDenseInducing
diff --git a/Mathlib/Topology/UniformSpace/Completion.lean b/Mathlib/Topology/UniformSpace/Completion.lean
index 25ec9b9b1bb0f..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,10 +154,16 @@ theorem uniformInducing_pureCauchy : UniformInducing (pureCauchy : α → Cauchy
_ = 𝓤 α := by simp [this]
⟩
-theorem uniformEmbedding_pureCauchy : UniformEmbedding (pureCauchy : α → CauchyFilter α) :=
- { uniformInducing_pureCauchy with
+@[deprecated (since := "2024-10-05")]
+alias uniformInducing_pureCauchy := isUniformInducing_pureCauchy
+
+theorem isUniformEmbedding_pureCauchy : IsUniformEmbedding (pureCauchy : α → CauchyFilter α) :=
+ { isUniformInducing_pureCauchy with
inj := fun _a₁ _a₂ h => pure_injective <| Subtype.ext_iff_val.1 h }
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_pureCauchy := isUniformEmbedding_pureCauchy
+
theorem denseRange_pureCauchy : DenseRange (pureCauchy : α → CauchyFilter α) := fun f => by
have h_ex : ∀ s ∈ 𝓤 (CauchyFilter α), ∃ y : α, (f, pureCauchy y) ∈ s := fun s hs =>
let ⟨t'', ht''₁, (ht''₂ : gen t'' ⊆ s)⟩ := (mem_lift'_sets monotone_gen).mp hs
@@ -180,15 +186,18 @@ theorem denseRange_pureCauchy : DenseRange (pureCauchy : α → CauchyFilter α)
⟨mem_range_self y, hy⟩
exact ⟨_, this⟩
-theorem denseInducing_pureCauchy : DenseInducing (pureCauchy : α → CauchyFilter α) :=
- uniformInducing_pureCauchy.denseInducing denseRange_pureCauchy
+theorem isDenseInducing_pureCauchy : IsDenseInducing (pureCauchy : α → CauchyFilter α) :=
+ isUniformInducing_pureCauchy.isDenseInducing denseRange_pureCauchy
+
+theorem isDenseEmbedding_pureCauchy : IsDenseEmbedding (pureCauchy : α → CauchyFilter α) :=
+ isUniformEmbedding_pureCauchy.isDenseEmbedding denseRange_pureCauchy
-theorem denseEmbedding_pureCauchy : DenseEmbedding (pureCauchy : α → CauchyFilter α) :=
- uniformEmbedding_pureCauchy.denseEmbedding denseRange_pureCauchy
+@[deprecated (since := "2024-09-30")]
+alias denseEmbedding_pureCauchy := isDenseEmbedding_pureCauchy
theorem nonempty_cauchyFilter_iff : Nonempty (CauchyFilter α) ↔ Nonempty α := by
constructor <;> rintro ⟨c⟩
- · have := eq_univ_iff_forall.1 denseEmbedding_pureCauchy.toDenseInducing.closure_range c
+ · have := eq_univ_iff_forall.1 isDenseEmbedding_pureCauchy.toIsDenseInducing.closure_range c
obtain ⟨_, ⟨_, a, _⟩⟩ := mem_closure_iff.1 this _ isOpen_univ trivial
exact ⟨a⟩
· exact ⟨pureCauchy c⟩
@@ -199,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
@@ -224,7 +233,7 @@ open Classical in
/-- Extend a uniformly continuous function `α → β` to a function `CauchyFilter α → β`.
Outputs junk when `f` is not uniformly continuous. -/
def extend (f : α → β) : CauchyFilter α → β :=
- if UniformContinuous f then denseInducing_pureCauchy.extend f
+ if UniformContinuous f then isDenseInducing_pureCauchy.extend f
else fun x => f (nonempty_cauchyFilter_iff.1 ⟨x⟩).some
section T0Space
@@ -234,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
@@ -243,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
@@ -316,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 {α}
@@ -338,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 α) :=
@@ -356,17 +368,20 @@ theorem uniformContinuous_coe : UniformContinuous ((↑) : α → Completion α)
theorem continuous_coe : Continuous ((↑) : α → Completion α) :=
cPkg.continuous_coe
-theorem uniformEmbedding_coe [T0Space α] : UniformEmbedding ((↑) : α → Completion α) :=
+theorem isUniformEmbedding_coe [T0Space α] : IsUniformEmbedding ((↑) : α → Completion α) :=
{ comap_uniformity := comap_coe_eq_uniformity α
inj := separated_pureCauchy_injective }
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_coe := isUniformEmbedding_coe
+
theorem coe_injective [T0Space α] : Function.Injective ((↑) : α → Completion α) :=
- UniformEmbedding.inj (uniformEmbedding_coe _)
+ IsUniformEmbedding.inj (isUniformEmbedding_coe _)
variable {α}
-theorem denseInducing_coe : DenseInducing ((↑) : α → Completion α) :=
- { (uniformInducing_coe α).inducing with dense := denseRange_coe }
+theorem isDenseInducing_coe : IsDenseInducing ((↑) : α → Completion α) :=
+ { (isUniformInducing_coe α).isInducing with dense := denseRange_coe }
/-- The uniform bijection between a complete space and its uniform completion. -/
def UniformCompletion.completeEquivSelf [CompleteSpace α] [T0Space α] : Completion α ≃ᵤ α :=
@@ -375,19 +390,22 @@ def UniformCompletion.completeEquivSelf [CompleteSpace α] [T0Space α] : Comple
open TopologicalSpace
instance separableSpace_completion [SeparableSpace α] : SeparableSpace (Completion α) :=
- Completion.denseInducing_coe.separableSpace
+ Completion.isDenseInducing_coe.separableSpace
+
+theorem isDenseEmbedding_coe [T0Space α] : IsDenseEmbedding ((↑) : α → Completion α) :=
+ { isDenseInducing_coe with inj := separated_pureCauchy_injective }
-theorem denseEmbedding_coe [T0Space α] : DenseEmbedding ((↑) : α → Completion α) :=
- { denseInducing_coe with inj := separated_pureCauchy_injective }
+@[deprecated (since := "2024-09-30")]
+alias denseEmbedding_coe := isDenseEmbedding_coe
theorem denseRange_coe₂ :
DenseRange fun x : α × β => ((x.1 : Completion α), (x.2 : Completion β)) :=
- denseRange_coe.prod_map denseRange_coe
+ denseRange_coe.prodMap denseRange_coe
theorem denseRange_coe₃ :
DenseRange fun x : α × β × γ =>
((x.1 : Completion α), ((x.2.1 : Completion β), (x.2.2 : Completion γ))) :=
- denseRange_coe.prod_map denseRange_coe₂
+ denseRange_coe.prodMap denseRange_coe₂
@[elab_as_elim]
theorem induction_on {p : Completion α → Prop} (a : Completion α) (hp : IsClosed { a | p a })
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 d4be20cb620ad..e9f383c879b3b 100644
--- a/Mathlib/Topology/UniformSpace/Equiv.lean
+++ b/Mathlib/Topology/UniformSpace/Equiv.lean
@@ -49,11 +49,11 @@ theorem toEquiv_injective : Function.Injective (toEquiv : α ≃ᵤ β → α
| ⟨e, h₁, h₂⟩, ⟨e', h₁', h₂'⟩, h => by simpa only [mk.injEq]
instance : EquivLike (α ≃ᵤ β) α β where
- coe := fun h => h.toEquiv
- inv := fun h => h.toEquiv.symm
- left_inv := fun h => h.left_inv
- right_inv := fun h => h.right_inv
- coe_injective' := fun _ _ H _ => toEquiv_injective <| DFunLike.ext' H
+ coe h := h.toEquiv
+ inv h := h.toEquiv.symm
+ left_inv h := h.left_inv
+ right_inv h := h.right_inv
+ coe_injective' _ _ H _ := toEquiv_injective <| DFunLike.ext' H
@[simp]
theorem uniformEquiv_mk_coe (a : Equiv α β) (b c) : (UniformEquiv.mk a b c : α → β) = a :=
@@ -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,36 +188,43 @@ 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
+
+lemma isUniformEmbedding (h : α ≃ᵤ β) : IsUniformEmbedding h := ⟨h.isUniformInducing, h.injective⟩
-protected theorem uniformEmbedding (h : α ≃ᵤ β) : UniformEmbedding h :=
- ⟨h.uniformInducing, h.injective⟩
+@[deprecated (since := "2024-10-01")] alias uniformEmbedding := isUniformEmbedding
theorem completeSpace_iff (h : α ≃ᵤ β) : CompleteSpace α ↔ CompleteSpace β :=
- completeSpace_congr h.uniformEmbedding
+ completeSpace_congr h.isUniformEmbedding
/-- Uniform equiv given a uniform embedding. -/
-noncomputable def ofUniformEmbedding (f : α → β) (hf : UniformEmbedding f) : α ≃ᵤ Set.range f where
- uniformContinuous_toFun := hf.toUniformInducing.uniformContinuous.subtype_mk _
+noncomputable def ofIsUniformEmbedding (f : α → β) (hf : IsUniformEmbedding f) :
+ α ≃ᵤ Set.range f where
+ 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
+@[deprecated (since := "2024-10-03")] alias ofUniformEmbedding := ofIsUniformEmbedding
+
/-- If two sets are equal, then they are uniformly equivalent. -/
def setCongr {s t : Set α} (h : s = t) : s ≃ᵤ t where
uniformContinuous_toFun := uniformContinuous_subtype_val.subtype_mk _
@@ -327,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 }
@@ -366,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/OfFun.lean b/Mathlib/Topology/UniformSpace/OfFun.lean
new file mode 100644
index 0000000000000..6a1ff605f190e
--- /dev/null
+++ b/Mathlib/Topology/UniformSpace/OfFun.lean
@@ -0,0 +1,52 @@
+/-
+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.UniformSpace.Basic
+import Mathlib.Algebra.Order.Monoid.Defs
+
+/-!
+# Construct a `UniformSpace` from a `dist`-like function
+
+In this file we provide a constructor for `UniformSpace`
+given a `dist`-like function
+
+## TODO
+
+RFC: use `UniformSpace.Core.mkOfBasis`? This will change defeq here and there
+-/
+
+open Filter Set
+open scoped Uniformity
+
+variable {X M : Type*}
+
+namespace UniformSpace
+
+/-- Define a `UniformSpace` using a "distance" function. The function can be, e.g., the
+distance in a (usual or extended) metric space or an absolute value on a ring. -/
+def ofFun [OrderedAddCommMonoid M] (d : X → X → M) (refl : ∀ x, d x x = 0)
+ (symm : ∀ x y, d x y = d y x) (triangle : ∀ x y z, d x z ≤ d x y + d y z)
+ (half : ∀ ε > (0 : M), ∃ δ > (0 : M), ∀ x < δ, ∀ y < δ, x + y < ε) :
+ UniformSpace X :=
+ .ofCore
+ { uniformity := ⨅ r > 0, 𝓟 { x | d x.1 x.2 < r }
+ refl := le_iInf₂ fun r hr => principal_mono.2 <| idRel_subset.2 fun x => by simpa [refl]
+ symm := tendsto_iInf_iInf fun r => tendsto_iInf_iInf fun _ => tendsto_principal_principal.2
+ fun x hx => by rwa [mem_setOf, symm]
+ comp := le_iInf₂ fun r hr => let ⟨δ, h0, hδr⟩ := half r hr; le_principal_iff.2 <|
+ mem_of_superset
+ (mem_lift' <| mem_iInf_of_mem δ <| mem_iInf_of_mem h0 <| mem_principal_self _)
+ fun (x, z) ⟨y, h₁, h₂⟩ => (triangle _ _ _).trans_lt (hδr _ h₁ _ h₂) }
+
+theorem hasBasis_ofFun [LinearOrderedAddCommMonoid M]
+ (h₀ : ∃ x : M, 0 < x) (d : X → X → M) (refl : ∀ x, d x x = 0) (symm : ∀ x y, d x y = d y x)
+ (triangle : ∀ x y z, d x z ≤ d x y + d y z)
+ (half : ∀ ε > (0 : M), ∃ δ > (0 : M), ∀ x < δ, ∀ y < δ, x + y < ε) :
+ 𝓤[.ofFun d refl symm triangle half].HasBasis ((0 : M) < ·) (fun ε => { x | d x.1 x.2 < ε }) :=
+ hasBasis_biInf_principal'
+ (fun ε₁ h₁ ε₂ h₂ => ⟨min ε₁ ε₂, lt_min h₁ h₂, fun _x hx => lt_of_lt_of_le hx (min_le_left _ _),
+ fun _x hx => lt_of_lt_of_le hx (min_le_right _ _)⟩) h₀
+
+end UniformSpace
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 a5dbd62933646..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
@@ -62,7 +61,7 @@ Uniform limit, uniform convergence, tends uniformly to
noncomputable section
-open Topology Uniformity Filter Set
+open Topology Uniformity Filter Set Uniform
universe u v w x
variable {α : Type u} {β : Type v} {γ : Type w} {ι : Type x} [UniformSpace β]
@@ -196,6 +195,12 @@ theorem TendstoUniformlyOn.congr {F' : ι → α → β} (hf : TendstoUniformlyO
simp only [Set.EqOn] at hff'
simp only [mem_prod_principal, hff', mem_setOf_eq]
+lemma tendstoUniformly_congr {F F' : ι → α → β} {f : α → β} (hF : F =ᶠ[p] F') :
+ TendstoUniformly F f p ↔ TendstoUniformly F' f p := by
+ simp_rw [← tendstoUniformlyOn_univ] at *
+ have HF := EventuallyEq.exists_mem hF
+ exact ⟨fun h => h.congr (by aesop), fun h => h.congr (by simp_rw [eqOn_comm]; aesop)⟩
+
theorem TendstoUniformlyOn.congr_right {g : α → β} (hf : TendstoUniformlyOn F f p s)
(hfg : EqOn f g s) : TendstoUniformlyOn F g p s := fun u hu => by
filter_upwards [hf u hu] with i hi a ha using hfg ha ▸ hi a ha
@@ -383,10 +388,12 @@ theorem TendstoUniformlyOn.uniformCauchySeqOn (hF : TendstoUniformlyOn F f p s)
hF.tendstoUniformlyOnFilter.uniformCauchySeqOnFilter
/-- A uniformly Cauchy sequence converges uniformly to its limit -/
-theorem UniformCauchySeqOnFilter.tendstoUniformlyOnFilter_of_tendsto [NeBot p]
+theorem UniformCauchySeqOnFilter.tendstoUniformlyOnFilter_of_tendsto
(hF : UniformCauchySeqOnFilter F p p')
(hF' : ∀ᶠ x : α in p', Tendsto (fun n => F n x) p (𝓝 (f x))) :
TendstoUniformlyOnFilter F f p p' := by
+ rcases p.eq_or_neBot with rfl | _
+ · simp only [TendstoUniformlyOnFilter, bot_prod, eventually_bot, implies_true]
-- Proof idea: |f_n(x) - f(x)| ≤ |f_n(x) - f_m(x)| + |f_m(x) - f(x)|. We choose `n`
-- so that |f_n(x) - f_m(x)| is uniformly small across `s` whenever `m ≥ n`. Then for
-- a fixed `x`, we choose `m` sufficiently large such that |f_m(x) - f(x)| is small.
@@ -412,7 +419,7 @@ theorem UniformCauchySeqOnFilter.tendstoUniformlyOnFilter_of_tendsto [NeBot p]
exact ⟨F m x, ⟨hm.2, htsymm hm.1⟩⟩
/-- A uniformly Cauchy sequence converges uniformly to its limit -/
-theorem UniformCauchySeqOn.tendstoUniformlyOn_of_tendsto [NeBot p] (hF : UniformCauchySeqOn F p s)
+theorem UniformCauchySeqOn.tendstoUniformlyOn_of_tendsto (hF : UniformCauchySeqOn F p s)
(hF' : ∀ x : α, x ∈ s → Tendsto (fun n => F n x) p (𝓝 (f x))) : TendstoUniformlyOn F f p s :=
tendstoUniformlyOn_iff_tendstoUniformlyOnFilter.mpr
(hF.uniformCauchySeqOnFilter.tendstoUniformlyOnFilter_of_tendsto hF')
@@ -481,7 +488,7 @@ theorem UniformCauchySeqOn.prod' {β' : Type*} [UniformSpace β'] {F' : ι →
a Cauchy sequence. -/
theorem UniformCauchySeqOn.cauchy_map [hp : NeBot p] (hf : UniformCauchySeqOn F p s) (hx : x ∈ s) :
Cauchy (map (fun i => F i x) p) := by
- simp only [cauchy_map_iff, hp, true_and_iff]
+ simp only [cauchy_map_iff, hp, true_and]
intro u hu
rw [mem_map]
filter_upwards [hf u hu] with p hp using hp x hx
@@ -523,6 +530,31 @@ theorem tendstoUniformly_iff_seq_tendstoUniformly {l : Filter ι} [l.IsCountably
end SeqTendsto
+section
+
+variable [NeBot p] {L : ι → β} {ℓ : β}
+
+theorem TendstoUniformlyOnFilter.tendsto_of_eventually_tendsto
+ (h1 : TendstoUniformlyOnFilter F f p p') (h2 : ∀ᶠ i in p, Tendsto (F i) p' (𝓝 (L i)))
+ (h3 : Tendsto L p (𝓝 ℓ)) : Tendsto f p' (𝓝 ℓ) := by
+ rw [tendsto_nhds_left]
+ intro s hs
+ rw [mem_map, Set.preimage, ← eventually_iff]
+ obtain ⟨t, ht, hts⟩ := comp3_mem_uniformity hs
+ have p1 : ∀ᶠ i in p, (L i, ℓ) ∈ t := tendsto_nhds_left.mp h3 ht
+ have p2 : ∀ᶠ i in p, ∀ᶠ x in p', (F i x, L i) ∈ t := by
+ filter_upwards [h2] with i h2 using tendsto_nhds_left.mp h2 ht
+ have p3 : ∀ᶠ i in p, ∀ᶠ x in p', (f x, F i x) ∈ t := (h1 t ht).curry
+ obtain ⟨i, p4, p5, p6⟩ := (p1.and (p2.and p3)).exists
+ filter_upwards [p5, p6] with x p5 p6 using hts ⟨F i x, p6, L i, p5, p4⟩
+
+theorem TendstoUniformly.tendsto_of_eventually_tendsto
+ (h1 : TendstoUniformly F f p) (h2 : ∀ᶠ i in p, Tendsto (F i) p' (𝓝 (L i)))
+ (h3 : Tendsto L p (𝓝 ℓ)) : Tendsto f p' (𝓝 ℓ) :=
+ (h1.tendstoUniformlyOnFilter.mono_right le_top).tendsto_of_eventually_tendsto h2 h3
+
+end
+
variable [TopologicalSpace α]
/-- A sequence of functions `Fₙ` converges locally uniformly on a set `s` to a limiting function
@@ -565,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
@@ -653,14 +685,14 @@ theorem tendstoLocallyUniformlyOn_TFAE [LocallyCompactSpace α] (G : ι → α
∀ K, K ⊆ s → IsCompact K → TendstoUniformlyOn G g p K,
∀ x ∈ s, ∃ v ∈ 𝓝[s] x, TendstoUniformlyOn G g p v] := by
tfae_have 1 → 2
- · rintro h K hK1 hK2
- exact (tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hK2).mp (h.mono hK1)
+ | h, K, hK1, hK2 =>
+ (tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hK2).mp (h.mono hK1)
tfae_have 2 → 3
- · rintro h x hx
+ | h, x, hx => by
obtain ⟨K, ⟨hK1, hK2⟩, hK3⟩ := (compact_basis_nhds x).mem_iff.mp (hs.mem_nhds hx)
exact ⟨K, nhdsWithin_le_nhds hK1, h K hK3 hK2⟩
tfae_have 3 → 1
- · rintro h u hu x hx
+ | h, u, hu, x, hx => by
obtain ⟨v, hv1, hv2⟩ := h x hx
exact ⟨v, hv1, hv2 u hu⟩
tfae_finish
diff --git a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean
index 60512c6535c4d..9a7542b8c7d0c 100644
--- a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean
+++ b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean
@@ -6,7 +6,7 @@ Authors: Anatole Dedecker
import Mathlib.Topology.UniformSpace.UniformConvergence
import Mathlib.Topology.UniformSpace.Pi
import Mathlib.Topology.UniformSpace.Equiv
-import Mathlib.Topology.RestrictGenTopology
+import Mathlib.Topology.RestrictGen
/-!
# Topology and uniform structure of uniform convergence
@@ -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,28 +367,35 @@ 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.
More precisely, if `f : γ → β` is a uniform embedding,
then `(f ∘ ·) : (α →ᵤ γ) → (α →ᵤ β)` is a uniform embedding. -/
-protected theorem postcomp_uniformEmbedding [UniformSpace γ] {f : γ → β} (hf : UniformEmbedding f) :
- UniformEmbedding (ofFun ∘ (f ∘ ·) ∘ toFun : (α →ᵤ γ) → α →ᵤ β) where
- toUniformInducing := UniformFun.postcomp_uniformInducing hf.toUniformInducing
+protected theorem postcomp_isUniformEmbedding [UniformSpace γ] {f : γ → β}
+ (hf : IsUniformEmbedding f) :
+ IsUniformEmbedding (ofFun ∘ (f ∘ ·) ∘ toFun : (α →ᵤ γ) → α →ᵤ β) where
+ toIsUniformInducing := UniformFun.postcomp_isUniformInducing hf.isUniformInducing
inj _ _ H := funext fun _ ↦ hf.inj (congrFun H _)
+@[deprecated (since := "2024-10-01")]
+alias postcomp_uniformEmbedding := UniformFun.postcomp_isUniformEmbedding
+
-- Porting note: had to add a type annotation at `((f ∘ ·) : ((α → γ) → (α → β)))`
/-- If `u` is a uniform structures on `β` and `f : γ → β`, then
`𝒰(α, γ, comap f u) = comap (fun g ↦ f ∘ g) 𝒰(α, γ, u₁)`. -/
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 `α →ᵤ β`.
@@ -461,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 _ _ _))
@@ -486,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
@@ -548,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
@@ -861,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
@@ -872,16 +879,22 @@ 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.
More precisely, if `f : γ → β` is a uniform embedding, then
`(fun g ↦ f ∘ g) : (α →ᵤ[𝔖] γ) → (α →ᵤ[𝔖] β)` is a uniform embedding. -/
-protected theorem postcomp_uniformEmbedding [UniformSpace γ] {f : γ → β} (hf : UniformEmbedding f) :
- UniformEmbedding (ofFun 𝔖 ∘ (f ∘ ·) ∘ toFun 𝔖) where
- toUniformInducing := UniformOnFun.postcomp_uniformInducing hf.toUniformInducing
+protected theorem postcomp_isUniformEmbedding [UniformSpace γ] {f : γ → β}
+ (hf : IsUniformEmbedding f) : IsUniformEmbedding (ofFun 𝔖 ∘ (f ∘ ·) ∘ toFun 𝔖) where
+ toIsUniformInducing := UniformOnFun.postcomp_isUniformInducing hf.isUniformInducing
inj _ _ H := funext fun _ ↦ hf.inj (congrFun H _)
+@[deprecated (since := "2024-10-01")]
+alias postcomp_uniformEmbedding := UniformOnFun.postcomp_isUniformEmbedding
+
/-- Turn a uniform isomorphism `γ ≃ᵤ β` into a uniform isomorphism `(α →ᵤ[𝔖] γ) ≃ᵤ (α →ᵤ[𝔖] β)`
by post-composing. -/
protected def congrRight [UniformSpace γ] (e : γ ≃ᵤ β) : (α →ᵤ[𝔖] γ) ≃ᵤ (α →ᵤ[𝔖] β) :=
@@ -1005,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 α (β × γ) 𝔖
@@ -1031,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) _ = _
@@ -1117,3 +1129,41 @@ instance {α β : Type*} [UniformSpace β] [CompleteSpace β] : CompleteSpace (
(UniformOnFun.uniformEquivUniformFun β {univ} (mem_singleton _)).completeSpace_iff.1 inferInstance
end UniformFun
+
+section UniformComposition
+
+variable {α β γ ι : Type*} [UniformSpace β] [UniformSpace γ] {p : Filter ι}
+
+/-- Composing on the left by a uniformly continuous function preserves uniform convergence -/
+theorem UniformContinuousOn.comp_tendstoUniformly (s : Set β) (F : ι → α → β) (f : α → β)
+ (hF : ∀ i x, F i x ∈ s) (hf : ∀ x, f x ∈ s)
+ {g : β → γ} (hg : UniformContinuousOn g s) (h : TendstoUniformly F f p) :
+ TendstoUniformly (fun i x => g (F i x)) (fun x => g (f x)) p := by
+ rw [uniformContinuousOn_iff_restrict] at hg
+ lift F to ι → α → s using hF with F' hF'
+ lift f to α → s using hf with f' hf'
+ rw [tendstoUniformly_iff_tendsto] at h
+ have : Tendsto (fun q : ι × α ↦ (f' q.2, (F' q.1 q.2))) (p ×ˢ ⊤) (𝓤 s) :=
+ h.of_tendsto_comp isUniformEmbedding_subtype_val.comap_uniformity.le
+ apply UniformContinuous.comp_tendstoUniformly hg ?_
+ rwa [← tendstoUniformly_iff_tendsto] at this
+
+theorem UniformContinuousOn.comp_tendstoUniformly_eventually (s : Set β) (F : ι → α → β) (f : α → β)
+ (hF : ∀ᶠ i in p, ∀ x, F i x ∈ s) (hf : ∀ x, f x ∈ s)
+ {g : β → γ} (hg : UniformContinuousOn g s) (h : TendstoUniformly F f p) :
+ TendstoUniformly (fun i => fun x => g (F i x)) (fun x => g (f x)) p := by
+ classical
+ rw [eventually_iff_exists_mem] at hF
+ obtain ⟨s', hs', hs⟩ := hF
+ let F' : ι → α → β := fun (i : ι) x => if i ∈ s' then F i x else f x
+ have hF : F =ᶠ[p] F' := by
+ rw [eventuallyEq_iff_exists_mem]
+ refine ⟨s', hs', fun y hy => by aesop⟩
+ have h' : TendstoUniformly F' f p := by
+ rwa [tendstoUniformly_congr hF] at h
+ apply (tendstoUniformly_congr _).mpr
+ (UniformContinuousOn.comp_tendstoUniformly s F' f (by aesop) hf hg h')
+ rw [eventuallyEq_iff_exists_mem]
+ refine ⟨s', hs', fun i hi => by aesop⟩
+
+end UniformComposition
diff --git a/Mathlib/Topology/UniformSpace/UniformEmbedding.lean b/Mathlib/Topology/UniformSpace/UniformEmbedding.lean
index a543aabffffb7..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
@@ -27,101 +28,169 @@ variable {α : Type u} {β : Type v} {γ : Type w} [UniformSpace α] [UniformSpa
/-- A map `f : α → β` between uniform spaces is called *uniform inducing* if the uniformity filter
on `α` is the pullback of the uniformity filter on `β` under `Prod.map f f`. If `α` is a separated
-space, then this implies that `f` is injective, hence it is a `UniformEmbedding`. -/
+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 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
-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
+@[deprecated (since := "2024-10-05")]
+alias uniformInducing_iff' := isUniformInducing_iff'
-protected lemma Filter.HasBasis.uniformInducing_iff {ι ι'} {p : ι → Prop} {p' : ι' → Prop} {s s'}
+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]
-theorem UniformInducing.mk' {f : α → β}
- (h : ∀ s, s ∈ 𝓤 α ↔ ∃ t ∈ 𝓤 β, ∀ x y : α, (f x, f y) ∈ t → (x, y) ∈ s) : UniformInducing f :=
+@[deprecated (since := "2024-10-05")]
+alias Filter.HasBasis.uniformInducing_iff := Filter.HasBasis.isUniformInducing_iff
+
+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
-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 IsUniformInducing.inducing := IsUniformInducing.isInducing
+
+@[deprecated (since := "2024-10-05")]
+alias UniformInducing.isInducing := IsUniformInducing.isInducing
+
+@[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.denseInducing {f : α → β} (h : UniformInducing f) (hd : DenseRange f) :
- DenseInducing 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
-theorem SeparationQuotient.uniformInducing_mk : UniformInducing (mk : α → SeparationQuotient α) :=
+@[deprecated (since := "2024-10-05")]
+alias UniformInducing.isDenseInducing := IsUniformInducing.isDenseInducing
+
+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,70 +199,118 @@ 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 UniformEmbedding (f : α → β) extends UniformInducing f : Prop where
+structure IsUniformEmbedding (f : α → β) extends IsUniformInducing f : Prop where
/-- A uniform embedding is injective. -/
inj : Function.Injective f
-theorem uniformEmbedding_iff' {f : α → β} :
- UniformEmbedding f ↔ Injective f ∧ UniformContinuous f ∧ comap (Prod.map f f) (𝓤 β) ≤ 𝓤 α := by
- rw [uniformEmbedding_iff, and_comm, uniformInducing_iff']
+lemma IsUniformEmbedding.isUniformInducing (hf : IsUniformEmbedding f) : IsUniformInducing f :=
+ hf.toIsUniformInducing
+
+@[deprecated (since := "2024-10-03")] alias UniformEmbedding := IsUniformEmbedding
-theorem Filter.HasBasis.uniformEmbedding_iff' {ι ι'} {p : ι → Prop} {p' : ι' → Prop} {s s'}
+theorem isUniformEmbedding_iff' {f : α → β} :
+ IsUniformEmbedding f ↔
+ Injective f ∧ UniformContinuous f ∧ comap (Prod.map f f) (𝓤 β) ≤ 𝓤 α := by
+ rw [isUniformEmbedding_iff, and_comm, isUniformInducing_iff']
+
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_iff' := isUniformEmbedding_iff'
+
+theorem Filter.HasBasis.isUniformEmbedding_iff' {ι ι'} {p : ι → Prop} {p' : ι' → Prop} {s s'}
(h : (𝓤 α).HasBasis p s) (h' : (𝓤 β).HasBasis p' s') {f : α → β} :
- UniformEmbedding f ↔ Injective f ∧
+ 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 [uniformEmbedding_iff, and_comm, h.uniformInducing_iff h']
+ rw [isUniformEmbedding_iff, and_comm, h.isUniformInducing_iff h']
-theorem Filter.HasBasis.uniformEmbedding_iff {ι ι'} {p : ι → Prop} {p' : ι' → Prop} {s s'}
+@[deprecated (since := "2024-10-01")]
+alias Filter.HasBasis.uniformEmbedding_iff' := Filter.HasBasis.isUniformEmbedding_iff'
+
+theorem Filter.HasBasis.isUniformEmbedding_iff {ι ι'} {p : ι → Prop} {p' : ι' → Prop} {s s'}
(h : (𝓤 α).HasBasis p s) (h' : (𝓤 β).HasBasis p' s') {f : α → β} :
- UniformEmbedding f ↔ Injective f ∧ UniformContinuous f ∧
+ IsUniformEmbedding f ↔ Injective f ∧ UniformContinuous f ∧
(∀ j, p j → ∃ i, p' i ∧ ∀ x y, (f x, f y) ∈ s' i → (x, y) ∈ s j) := by
- simp only [h.uniformEmbedding_iff' h', h.uniformContinuous_iff h']
+ simp only [h.isUniformEmbedding_iff' h', h.uniformContinuous_iff h']
+
+@[deprecated (since := "2024-10-01")]
+alias Filter.HasBasis.uniformEmbedding_iff := Filter.HasBasis.isUniformEmbedding_iff
-theorem uniformEmbedding_subtype_val {p : α → Prop} :
- UniformEmbedding (Subtype.val : Subtype p → α) :=
+theorem isUniformEmbedding_subtype_val {p : α → Prop} :
+ IsUniformEmbedding (Subtype.val : Subtype p → α) :=
{ comap_uniformity := rfl
inj := Subtype.val_injective }
-theorem uniformEmbedding_set_inclusion {s t : Set α} (hst : s ⊆ t) :
- UniformEmbedding (inclusion hst) where
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_subtype_val := isUniformEmbedding_subtype_val
+
+theorem isUniformEmbedding_set_inclusion {s t : Set α} (hst : s ⊆ t) :
+ IsUniformEmbedding (inclusion hst) where
comap_uniformity := by rw [uniformity_subtype, uniformity_subtype, comap_comap]; rfl
inj := inclusion_injective hst
-theorem UniformEmbedding.comp {g : β → γ} (hg : UniformEmbedding g) {f : α → β}
- (hf : UniformEmbedding f) : UniformEmbedding (g ∘ f) :=
- { hg.toUniformInducing.comp hf.toUniformInducing with inj := hg.inj.comp hf.inj }
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_set_inclusion := isUniformEmbedding_set_inclusion
+
+theorem IsUniformEmbedding.comp {g : β → γ} (hg : IsUniformEmbedding g) {f : α → β}
+ (hf : IsUniformEmbedding f) : IsUniformEmbedding (g ∘ f) :=
+ { 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.isUniformInducing.of_comp_iff, hg.inj.of_comp_iff f]
-theorem UniformEmbedding.of_comp_iff {g : β → γ} (hg : UniformEmbedding g) {f : α → β} :
- UniformEmbedding (g ∘ f) ↔ UniformEmbedding f := by
- simp_rw [uniformEmbedding_iff, hg.toUniformInducing.of_comp_iff, hg.inj.of_comp_iff f]
+@[deprecated (since := "2024-10-01")]
+alias UniformEmbedding.of_comp_iff := IsUniformEmbedding.of_comp_iff
-theorem Equiv.uniformEmbedding {α β : Type*} [UniformSpace α] [UniformSpace β] (f : α ≃ β)
- (h₁ : UniformContinuous f) (h₂ : UniformContinuous f.symm) : UniformEmbedding f :=
- uniformEmbedding_iff'.2 ⟨f.injective, h₁, by rwa [← Equiv.prodCongr_apply, ← map_equiv_symm]⟩
+theorem Equiv.isUniformEmbedding {α β : Type*} [UniformSpace α] [UniformSpace β] (f : α ≃ β)
+ (h₁ : UniformContinuous f) (h₂ : UniformContinuous f.symm) : IsUniformEmbedding f :=
+ isUniformEmbedding_iff'.2 ⟨f.injective, h₁, by rwa [← Equiv.prodCongr_apply, ← map_equiv_symm]⟩
-theorem uniformEmbedding_inl : UniformEmbedding (Sum.inl : α → α ⊕ β) :=
- uniformEmbedding_iff'.2 ⟨Sum.inl_injective, uniformContinuous_inl, fun s hs =>
+@[deprecated (since := "2024-10-01")]
+alias Equiv.uniformEmbedding := Equiv.isUniformEmbedding
+
+theorem isUniformEmbedding_inl : IsUniformEmbedding (Sum.inl : α → α ⊕ β) :=
+ isUniformEmbedding_iff'.2 ⟨Sum.inl_injective, uniformContinuous_inl, fun s hs =>
⟨Prod.map Sum.inl Sum.inl '' s ∪ range (Prod.map Sum.inr Sum.inr),
union_mem_sup (image_mem_map hs) range_mem_map,
fun x h => by simpa [Prod.map_apply'] using h⟩⟩
-theorem uniformEmbedding_inr : UniformEmbedding (Sum.inr : β → α ⊕ β) :=
- uniformEmbedding_iff'.2 ⟨Sum.inr_injective, uniformContinuous_inr, fun s hs =>
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_inl := isUniformEmbedding_inl
+
+theorem isUniformEmbedding_inr : IsUniformEmbedding (Sum.inr : β → α ⊕ β) :=
+ isUniformEmbedding_iff'.2 ⟨Sum.inr_injective, uniformContinuous_inr, fun s hs =>
⟨range (Prod.map Sum.inl Sum.inl) ∪ Prod.map Sum.inr Sum.inr '' s,
union_mem_sup range_mem_map (image_mem_map hs),
fun x h => by simpa [Prod.map_apply'] using h⟩⟩
-/-- If the domain of a `UniformInducing` map `f` is a T₀ space, then `f` is injective,
-hence it is a `UniformEmbedding`. -/
-protected theorem UniformInducing.uniformEmbedding [T0Space α] {f : α → β}
- (hf : UniformInducing f) : UniformEmbedding f :=
- ⟨hf, hf.inducing.injective⟩
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_inr := isUniformEmbedding_inr
+
+/-- If the domain of a `IsUniformInducing` map `f` is a T₀ space, then `f` is injective,
+hence it is a `IsUniformEmbedding`. -/
+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
-theorem uniformEmbedding_iff_uniformInducing [T0Space α] {f : α → β} :
- UniformEmbedding f ↔ UniformInducing f :=
- ⟨UniformEmbedding.toUniformInducing, UniformInducing.uniformEmbedding⟩
+@[deprecated (since := "2024-10-01")]
+alias IsUniformInducing.uniformEmbedding := IsUniformInducing.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_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 `α`:
@@ -210,29 +327,48 @@ theorem comap_uniformity_of_spaced_out {α} {f : α → β} {s : Set (β × β)}
/-- If a map `f : α → β` sends any two distinct points to point that are **not** related by a fixed
`s ∈ 𝓤 β`, then `f` is a uniform embedding with respect to the discrete uniformity on `α`. -/
-theorem uniformEmbedding_of_spaced_out {α} {f : α → β} {s : Set (β × β)} (hs : s ∈ 𝓤 β)
- (hf : Pairwise fun x y => (f x, f y) ∉ s) : @UniformEmbedding α β ⊥ ‹_› f := by
+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.uniformEmbedding ⟨comap_uniformity_of_spaced_out hs hf⟩
+ exact IsUniformInducing.isUniformEmbedding ⟨comap_uniformity_of_spaced_out hs hf⟩
-protected theorem UniformEmbedding.embedding {f : α → β} (h : UniformEmbedding f) : Embedding f :=
- { toInducing := h.toUniformInducing.inducing
- inj := h.inj }
+@[deprecated (since := "2024-10-01")]
+alias uniformEmbedding_of_spaced_out := isUniformEmbedding_of_spaced_out
-theorem UniformEmbedding.denseEmbedding {f : α → β} (h : UniformEmbedding f) (hd : DenseRange f) :
- DenseEmbedding f :=
- { h.embedding with dense := hd }
+protected lemma IsUniformEmbedding.isEmbedding {f : α → β} (h : IsUniformEmbedding f) :
+ IsEmbedding f where
+ toIsInducing := h.toIsUniformInducing.isInducing
+ inj := h.inj
-theorem closedEmbedding_of_spaced_out {α} [TopologicalSpace α] [DiscreteTopology α]
+@[deprecated (since := "2024-10-26")]
+alias IsUniformEmbedding.embedding := IsUniformEmbedding.isEmbedding
+
+@[deprecated (since := "2024-10-01")]
+alias UniformEmbedding.embedding := IsUniformEmbedding.isEmbedding
+
+theorem IsUniformEmbedding.isDenseEmbedding {f : α → β} (h : IsUniformEmbedding f)
+ (hd : DenseRange f) : IsDenseEmbedding f :=
+ { h.isEmbedding with dense := hd }
+
+@[deprecated (since := "2024-10-01")]
+alias UniformEmbedding.isDenseEmbedding := IsUniformEmbedding.isDenseEmbedding
+
+@[deprecated (since := "2024-09-30")]
+alias IsUniformEmbedding.denseEmbedding := IsUniformEmbedding.isDenseEmbedding
+
+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
- { (uniformEmbedding_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₂ : DenseInducing 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
@@ -245,53 +381,101 @@ 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⟩
-theorem uniformEmbedding_subtypeEmb (p : α → Prop) {e : α → β} (ue : UniformEmbedding e)
- (de : DenseEmbedding e) : UniformEmbedding (DenseEmbedding.subtypeEmb p e) :=
+@[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
- simp [comap_comap, Function.comp_def, DenseEmbedding.subtypeEmb, uniformity_subtype,
+ simp [comap_comap, Function.comp_def, IsDenseEmbedding.subtypeEmb, uniformity_subtype,
ue.comap_uniformity.symm]
inj := (de.subtype p).inj }
-theorem UniformEmbedding.prod {α' : Type*} {β' : Type*} [UniformSpace α'] [UniformSpace β']
- {e₁ : α → α'} {e₂ : β → β'} (h₁ : UniformEmbedding e₁) (h₂ : UniformEmbedding e₂) :
- UniformEmbedding fun p : α × β => (e₁ p.1, e₂ p.2) :=
- { h₁.toUniformInducing.prod h₂.toUniformInducing with inj := h₁.inj.prodMap h₂.inj }
+@[deprecated (since := "2024-10-01")]
+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₁.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 `IsUniformInducing` map, the image `f '' s` of a set `s` is complete
+ if and only if `s` is complete. -/
+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.isUniformInducing.isComplete_iff
+
+@[deprecated (since := "2024-10-01")]
+alias UniformEmbedding.isComplete_iff := IsUniformEmbedding.isComplete_iff
+
+/-- Sets of a subtype are complete iff their image under the coercion is complete. -/
+theorem Subtype.isComplete_iff {p : α → Prop} {s : Set { x // p x }} :
+ IsComplete s ↔ IsComplete ((↑) '' s : Set α) :=
+ isUniformEmbedding_subtype_val.isComplete_iff.symm
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]
-theorem UniformInducing.isComplete_range [CompleteSpace α] {f : α → β} (hf : UniformInducing f) :
+alias ⟨_, IsUniformInducing.completeSpace⟩ := completeSpace_iff_isComplete_range
+
+@[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 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 α := by
- rw [completeSpace_iff_isComplete_univ, ← range_mk,
- ← completeSpace_iff_isComplete_range uniformInducing_mk]
+ CompleteSpace (SeparationQuotient α) ↔ CompleteSpace α :=
+ .symm <| isUniformInducing_mk.completeSpace_congr surjective_mk
instance SeparationQuotient.instCompleteSpace [CompleteSpace α] :
CompleteSpace (SeparationQuotient α) :=
completeSpace_iff.2 ‹_›
-theorem completeSpace_congr {e : α ≃ β} (he : UniformEmbedding e) :
- CompleteSpace α ↔ CompleteSpace β := by
- rw [completeSpace_iff_isComplete_range he.toUniformInducing, e.range_eq_univ,
- completeSpace_iff_isComplete_univ]
+/-- 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 :=
- (completeSpace_iff_isComplete_range uniformEmbedding_subtype_val.toUniformInducing).trans <| by
- rw [Subtype.range_coe]
+theorem completeSpace_coe_iff_isComplete {s : Set α} : CompleteSpace s ↔ IsComplete s := by
+ rw [completeSpace_iff_isComplete_range isUniformEmbedding_subtype_val.isUniformInducing,
+ Subtype.range_coe]
alias ⟨_, IsComplete.completeSpace_coe⟩ := completeSpace_coe_iff_isComplete
@@ -299,44 +483,46 @@ theorem IsClosed.completeSpace_coe [CompleteSpace α] {s : Set α} (hs : IsClose
CompleteSpace s :=
hs.isComplete.completeSpace_coe
+theorem completeSpace_ulift_iff : CompleteSpace (ULift α) ↔ CompleteSpace α :=
+ IsUniformInducing.completeSpace_congr ⟨rfl⟩ ULift.down_surjective
+
/-- The lift of a complete space to another universe is still complete. -/
-instance ULift.completeSpace [h : CompleteSpace α] : CompleteSpace (ULift α) :=
- haveI : UniformEmbedding (@Equiv.ulift α) := ⟨⟨rfl⟩, ULift.down_injective⟩
- (completeSpace_congr this).2 h
+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) ‹_›
@@ -350,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]
@@ -359,45 +545,54 @@ 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 uniformEmbedding_inl.toUniformInducing.isComplete_range.union
- uniformEmbedding_inr.toUniformInducing.isComplete_range
+ exact isUniformEmbedding_inl.isUniformInducing.isComplete_range.union
+ isUniformEmbedding_inr.isUniformInducing.isComplete_range
end
-theorem uniformEmbedding_comap {α : Type*} {β : Type*} {f : α → β} [u : UniformSpace β]
- (hf : Function.Injective f) : @UniformEmbedding α β (UniformSpace.comap f u) u f :=
- @UniformEmbedding.mk _ _ (UniformSpace.comap f u) _ _
- (@UniformInducing.mk _ _ (UniformSpace.comap f u) _ _ rfl) hf
+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) _ _
+ (@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_uniformEmbedding {α β} [TopologicalSpace α] [u : UniformSpace β] (f : α → β)
- (h : Embedding f) : @UniformEmbedding α β (h.comapUniformSpace f) u f :=
+theorem Embedding.to_isUniformEmbedding {α β} [TopologicalSpace α] [u : UniformSpace β] (f : α → β)
+ (h : IsEmbedding f) : @IsUniformEmbedding α β (h.comapUniformSpace f) u f :=
let _ := h.comapUniformSpace f
{ comap_uniformity := rfl
inj := h.inj }
+@[deprecated (since := "2024-10-01")]
+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 "ψ" => DenseInducing.extend (UniformInducing.denseInducing 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) :=
- let de := h_e.denseInducing h_dense
+ let de := h_e.isDenseInducing h_dense
have : Cauchy (𝓝 a) := cauchy_nhds
have : Cauchy (comap e (𝓝 a)) :=
this.comap' (le_of_eq h_e.comap_uniformity) (de.comap_nhds_neBot _)
@@ -405,24 +600,25 @@ theorem uniformly_extend_exists [CompleteSpace γ] (a : α) : ∃ c, Tendsto f (
CompleteSpace.complete this
theorem uniform_extend_subtype [CompleteSpace γ] {p : α → Prop} {e : α → β} {f : α → γ} {b : β}
- {s : Set α} (hf : UniformContinuous fun x : Subtype p => f x.val) (he : UniformEmbedding e)
+ {s : Set α} (hf : UniformContinuous fun x : Subtype p => f x.val) (he : IsUniformEmbedding e)
(hd : ∀ x : β, x ∈ closure (range e)) (hb : closure (e '' s) ∈ 𝓝 b) (hs : IsClosed s)
(hp : ∀ x ∈ s, p x) : ∃ c, Tendsto f (comap e (𝓝 b)) (𝓝 c) := by
- have de : DenseEmbedding e := he.denseEmbedding hd
- have de' : DenseEmbedding (DenseEmbedding.subtypeEmb p e) := de.subtype p
- have ue' : UniformEmbedding (DenseEmbedding.subtypeEmb p e) := uniformEmbedding_subtypeEmb _ he de
+ have de : IsDenseEmbedding e := he.isDenseEmbedding hd
+ have de' : IsDenseEmbedding (IsDenseEmbedding.subtypeEmb p e) := de.subtype p
+ have ue' : IsUniformEmbedding (IsDenseEmbedding.subtypeEmb p 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, DenseEmbedding.subtypeEmb_coe] using hc
+ 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
- simpa only [DenseInducing.extend] using
+ simpa only [IsDenseInducing.extend] using
tendsto_nhds_limUnder (uniformly_extend_exists h_e ‹_› h_f _)
include h_f in
@@ -431,7 +627,7 @@ theorem uniformContinuous_uniformly_extend [CompleteSpace γ] : UniformContinuou
have h_pnt : ∀ {a m}, m ∈ 𝓝 a → ∃ c ∈ f '' (e ⁻¹' m), (c, ψ a) ∈ s ∧ (ψ a, c) ∈ s :=
fun {a m} hm =>
have nb : NeBot (map f (comap e (𝓝 a))) :=
- ((h_e.denseInducing h_dense).comap_nhds_neBot _).map _
+ ((h_e.isDenseInducing h_dense).comap_nhds_neBot _).map _
have :
f '' (e ⁻¹' m) ∩ ({ c | (c, ψ a) ∈ s } ∩ { c | (ψ a, c) ∈ s }) ∈ map f (comap e (𝓝 a)) :=
inter_mem (image_mem_map <| preimage_mem_comap <| hm)
@@ -456,9 +652,9 @@ variable [T0Space γ]
include h_f in
theorem uniformly_extend_of_ind (b : β) : ψ (e b) = f b :=
- DenseInducing.extend_eq_at _ h_f.continuous.continuousAt
+ IsDenseInducing.extend_eq_at _ h_f.continuous.continuousAt
theorem uniformly_extend_unique {g : α → γ} (hg : ∀ b, g (e b) = f b) (hc : Continuous g) : ψ = g :=
- DenseInducing.extend_unique _ hg hc
+ IsDenseInducing.extend_unique _ hg hc
end UniformExtension
diff --git a/Mathlib/Topology/UnitInterval.lean b/Mathlib/Topology/UnitInterval.lean
index 52a1b15721742..40404390094c0 100644
--- a/Mathlib/Topology/UnitInterval.lean
+++ b/Mathlib/Topology/UnitInterval.lean
@@ -1,7 +1,7 @@
/-
Copyright (c) 2020 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Scott Morrison
+Authors: Patrick Massot, Kim Morrison
-/
import Mathlib.Algebra.Order.Interval.Set.Instances
import Mathlib.Order.Interval.Set.ProjIcc
@@ -40,10 +40,10 @@ theorem one_mem : (1 : ℝ) ∈ I :=
⟨zero_le_one, le_rfl⟩
theorem mul_mem {x y : ℝ} (hx : x ∈ I) (hy : y ∈ I) : x * y ∈ I :=
- ⟨mul_nonneg hx.1 hy.1, mul_le_one hx.2 hy.1 hy.2⟩
+ ⟨mul_nonneg hx.1 hy.1, mul_le_one₀ hx.2 hy.1 hy.2⟩
theorem div_mem {x y : ℝ} (hx : 0 ≤ x) (hy : 0 ≤ y) (hxy : x ≤ y) : x / y ∈ I :=
- ⟨div_nonneg hx hy, div_le_one_of_le hxy hy⟩
+ ⟨div_nonneg hx hy, div_le_one_of_le₀ hxy hy⟩
theorem fract_mem (x : ℝ) : fract x ∈ I :=
⟨fract_nonneg _, (fract_lt_one _).le⟩
@@ -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/UrysohnsBounded.lean b/Mathlib/Topology/UrysohnsBounded.lean
index fa436cb53dfbd..16835df30f181 100644
--- a/Mathlib/Topology/UrysohnsBounded.lean
+++ b/Mathlib/Topology/UrysohnsBounded.lean
@@ -4,14 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
import Mathlib.Topology.UrysohnsLemma
-import Mathlib.Topology.ContinuousFunction.Bounded
+import Mathlib.Topology.ContinuousMap.Bounded
/-!
# Urysohn's lemma for bounded continuous functions
In this file we reformulate Urysohn's lemma `exists_continuous_zero_one_of_isClosed` in terms of
bounded continuous functions `X →ᵇ ℝ`. These lemmas live in a separate file because
-`Topology.ContinuousFunction.Bounded` imports too many other files.
+`Topology.ContinuousMap.Bounded` imports too many other files.
## Tags
diff --git a/Mathlib/Topology/UrysohnsLemma.lean b/Mathlib/Topology/UrysohnsLemma.lean
index 4c07760f23a50..f645df48176ff 100644
--- a/Mathlib/Topology/UrysohnsLemma.lean
+++ b/Mathlib/Topology/UrysohnsLemma.lean
@@ -5,10 +5,10 @@ Authors: Yury Kudryashov
-/
import Mathlib.Analysis.Normed.Affine.AddTorsor
import Mathlib.LinearAlgebra.AffineSpace.Ordered
-import Mathlib.Topology.ContinuousFunction.Basic
-import Mathlib.Topology.GDelta
+import Mathlib.Topology.ContinuousMap.Basic
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/AddRelatedDecl.lean b/Mathlib/Util/AddRelatedDecl.lean
index f415c55828e22..ecea6a5c315b8 100644
--- a/Mathlib/Util/AddRelatedDecl.lean
+++ b/Mathlib/Util/AddRelatedDecl.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Floris van Doorn
+Authors: Kim Morrison, Floris van Doorn
-/
import Mathlib.Init
import Lean.Elab.DeclarationRange
diff --git a/Mathlib/Util/AssertExists.lean b/Mathlib/Util/AssertExists.lean
index 2995ff633ca25..386f6f122afc9 100644
--- a/Mathlib/Util/AssertExists.lean
+++ b/Mathlib/Util/AssertExists.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Patrick Massot, Scott Morrison
+Authors: Patrick Massot, Kim Morrison
-/
import Mathlib.Init
import Lean.Elab.Command
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 89f19cc7ea3ef..0b829028c0b11 100644
--- a/Mathlib/Util/AtomM.lean
+++ b/Mathlib/Util/AtomM.lean
@@ -11,13 +11,18 @@ import Lean.Meta.Tactic.Simp.Types
This monad is used by tactics like `ring` and `abel` to keep uninterpreted atoms in a consistent
order, and also to allow unifying atoms up to a specified transparency mode.
+
+Note: this can become very expensive because it is using `isDefEq`.
+For performance reasons, consider whether `Lean.Meta.Canonicalizer.canon` can be used instead.
+After canonicalizing, a `HashMap Expr Nat` suffices to keep track of previously seen atoms,
+and is much faster as it uses `Expr` equality rather than `isDefEq`.
-/
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,
@@ -26,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 795aac8b29aa1..65bb809fa657c 100644
--- a/Mathlib/Util/CountHeartbeats.lean
+++ b/Mathlib/Util/CountHeartbeats.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Lean.Util.Heartbeats
@@ -43,8 +43,8 @@ def runTacForHeartbeats (tac : TSyntax `Lean.Parser.Tactic.tacticSeq) (revert :
Given a `List Nat`, return the minimum, maximum, and standard deviation.
-/
def variation (counts : List Nat) : List Nat :=
- let min := counts.minimum?.getD 0
- let max := counts.maximum?.getD 0
+ let min := counts.min?.getD 0
+ let max := counts.max?.getD 0
let toFloat (n : Nat) := n.toUInt64.toFloat
let toNat (f : Float) := f.toUInt64.toNat
let counts' := counts.map toFloat
@@ -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/LongNames.lean b/Mathlib/Util/LongNames.lean
index 43e6789218bc4..081b0dfe749d6 100644
--- a/Mathlib/Util/LongNames.lean
+++ b/Mathlib/Util/LongNames.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Lean.Name
import Mathlib.Lean.Expr.Basic
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/Qq.lean b/Mathlib/Util/Qq.lean
index af1dbac4f7ad8..5232470c0d692 100644
--- a/Mathlib/Util/Qq.lean
+++ b/Mathlib/Util/Qq.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2023 Scott Morrison. All rights reserved.
+Copyright (c) 2023 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison, Alex J. Best
+Authors: Kim Morrison, Alex J. Best
-/
import Mathlib.Init
import Qq
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/SynthesizeUsing.lean b/Mathlib/Util/SynthesizeUsing.lean
index a9979d22f051f..6e65203680e84 100644
--- a/Mathlib/Util/SynthesizeUsing.lean
+++ b/Mathlib/Util/SynthesizeUsing.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2022 Scott Morrison. All rights reserved.
+Copyright (c) 2022 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Init
import Lean.Elab.Tactic.Basic
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/README.md b/README.md
index 53d266e917989..dfe49c658f2b5 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ For more pointers, see [Learning Lean](https://leanprover-community.github.io/le
## Documentation
Besides the installation guides above and [Lean's general
-documentation](https://leanprover.github.io/documentation/), the documentation
+documentation](https://docs.lean-lang.org/lean4/doc/), the documentation
of mathlib consists of:
- [The mathlib4 docs](https://leanprover-community.github.io/mathlib4_docs/index.html): documentation [generated
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/100.yaml b/docs/100.yaml
index d10c937e7c0eb..b1fb269096866 100644
--- a/docs/100.yaml
+++ b/docs/100.yaml
@@ -18,6 +18,12 @@
title : Prime Number Theorem
6:
title : Gödel’s Incompleteness Theorem
+ author : Shogo Saito
+ links :
+ results :
+ - First: https://github.com/FormalizedFormalLogic/Incompleteness/blob/master/Incompleteness/Arith/First.lean
+ - Second: https://github.com/FormalizedFormalLogic/Incompleteness/blob/master/Incompleteness/Arith/Second.lean
+ website: https://formalizedformallogic.github.io/Book/
7:
title : Law of Quadratic Reciprocity
decls :
@@ -177,7 +183,7 @@
49:
title : The Cayley-Hamilton Theorem
decl : Matrix.aeval_self_charpoly
- author : Scott Morrison
+ author : Kim Morrison
50:
title : The Number of Platonic Solids
51:
@@ -339,7 +345,7 @@
title : Morley’s Theorem
85:
title : Divisibility by 3 Rule
- author : Scott Morrison
+ author : Kim Morrison
decls :
- Nat.three_dvd_iff
86:
diff --git a/docs/overview.yaml b/docs/overview.yaml
index be28612dbf810..7113041d2dfc9 100644
--- a/docs/overview.yaml
+++ b/docs/overview.yaml
@@ -209,7 +209,7 @@ Topology:
cluster point: 'ClusterPt'
Hausdorff space: 'T2Space'
sequential space: 'SequentialSpace'
- extension by continuity: 'DenseInducing.extend'
+ extension by continuity: 'IsDenseInducing.extend'
compactness in terms of filters: 'IsCompact'
compactness in terms of open covers (Borel-Lebesgue): 'isCompact_iff_finite_subcover'
connectedness: 'ConnectedSpace'
@@ -352,7 +352,7 @@ Analysis:
Liouville theorem: 'Differentiable.apply_eq_apply_of_bounded'
maximum modulus principle: 'Complex.eventually_eq_of_isLocalMax_norm'
principle of isolated zeros: 'AnalyticAt.eventually_eq_zero_or_eventually_ne_zero'
- principle of analytic continuation: 'AnalyticOn.eqOn_of_preconnected_of_frequently_eq'
+ principle of analytic continuation: 'AnalyticOnNhd.eqOn_of_preconnected_of_frequently_eq'
analyticity of holomorphic functions: 'DifferentiableOn.analyticAt'
Schwarz lemma: 'Complex.abs_le_abs_of_mapsTo_ball_self'
removable singularity: 'Complex.differentiableOn_update_limUnder_insert_of_isLittleO'
@@ -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 71178e6a2c7f3..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},
@@ -1396,6 +1421,18 @@ @Book{ friedmanscarr2005
zbl = {1080.46001}
}
+@Book{ fritsch-piccinini1990,
+ place = {Cambridge},
+ series = {Cambridge Studies in Advanced Mathematics},
+ title = {Cellular Structures in Topology},
+ publisher = {Cambridge University Press},
+ author = {Fritsch, Rudolf and Piccinini, Renzo},
+ year = {1990},
+ collection = {Cambridge Studies in Advanced Mathematics},
+ url = {https://doi.org/10.1017/CBO9780511983948},
+ doi = {10.1017/CBO9780511983948}
+}
+
@Book{ fuchs1963,
author = {Fuchs, L.},
title = {Partially ordered algebraic systems},
@@ -1889,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},
@@ -2076,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}},
@@ -2211,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$}},
@@ -2827,6 +2872,17 @@ @Misc{ ponton2020chebyshev
primaryclass = {math.NT}
}
+@Article{ Prielipp1970,
+ author = {Robert W. Prielipp},
+ title = {PERFECT NUMBERS, ABUNDANT NUMBERS, AND DEFICIENT NUMBERS},
+ journal = {The Mathematics Teacher},
+ volume = {63},
+ year = {1970},
+ pages = {692--696},
+ issn = {00255769},
+ url = {http://www.jstor.org/stable/27958492}
+}
+
@InCollection{ ribenboim1971,
author = {Ribenboim, Paulo},
title = {\'{E}pimorphismes de modules qui sont n\'{e}cessairement
@@ -3245,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/docs/undergrad.yaml b/docs/undergrad.yaml
index 21619980559e5..4a3b5c75b8fd9 100644
--- a/docs/undergrad.yaml
+++ b/docs/undergrad.yaml
@@ -356,7 +356,9 @@ Single Variable Real Analysis:
Weierstrass trigonometric approximation theorem: 'span_fourier_closure_eq_top'
Convexity:
convex functions of a real variable: 'ConvexOn'
- continuity and differentiability of convex functions: 'https://en.wikipedia.org/wiki/Convex_function#Functions_of_one_variable'
+ continuity and differentiability of convex functions:
+ continuity: 'ConvexOn.continuousOn'
+ differentiability: 'https://en.wikipedia.org/wiki/Convex_function#Functions_of_one_variable'
characterizations of convexity: 'convexOn_of_deriv2_nonneg'
convexity inequalities: 'analysis/mean_inequalities.html'
@@ -387,7 +389,7 @@ Single Variable Complex Analysis:
Cauchy formulas: 'Complex.two_pi_I_inv_smul_circleIntegral_sub_inv_smul_of_differentiable_on_off_countable'
analyticity of a holomorphic function: 'DifferentiableOn.analyticAt'
principle of isolated zeros: 'AnalyticAt.eventually_eq_zero_or_eventually_ne_zero'
- principle of analytic continuation: 'AnalyticOn.eqOn_of_preconnected_of_frequently_eq'
+ principle of analytic continuation: 'AnalyticOnNhd.eqOn_of_preconnected_of_frequently_eq'
maximum principle: 'Complex.eventually_eq_of_isLocalMax_norm'
isolated singularities: ''
Laurent series: ''
diff --git a/lake-manifest.json b/lake-manifest.json
index 8c6cb478cd495..46776e768a762 100644
--- a/lake-manifest.json
+++ b/lake-manifest.json
@@ -5,17 +5,17 @@
"type": "git",
"subDir": null,
"scope": "leanprover-community",
- "rev": "d11566f4c8ca80dbe87630b606c608274c7380fd",
+ "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": "2c8ae451ce9ffc83554322b14437159c1a9703f9",
+ "rev": "1357f4f49450abb9dfd4783e38219f4ce84f9785",
"name": "Qq",
"manifestFile": "lake-manifest.json",
"inputRev": "master",
@@ -25,7 +25,7 @@
"type": "git",
"subDir": null,
"scope": "leanprover-community",
- "rev": "e291aa4de57079b3d2199b9eb7b4b00922b85a7c",
+ "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,11 +55,21 @@
"type": "git",
"subDir": null,
"scope": "leanprover-community",
- "rev": "fb7841a6f4fb389ec0e47dd4677844d49906af3c",
+ "rev": "c1970bea80ac3357a6a991a6d00d12e7435c12c7",
"name": "importGraph",
"manifestFile": "lake-manifest.json",
"inputRev": "main",
"inherited": false,
+ "configFile": "lakefile.toml"},
+ {"url": "https://github.com/leanprover-community/LeanSearchClient",
+ "type": "git",
+ "subDir": null,
+ "scope": "leanprover-community",
+ "rev": "7bedaed1ef024add1e171cc17706b012a9a37802",
+ "name": "LeanSearchClient",
+ "manifestFile": "lake-manifest.json",
+ "inputRev": "main",
+ "inherited": false,
"configFile": "lakefile.toml"}],
"name": "mathlib",
"lakeDir": ".lake"}
diff --git a/lakefile.lean b/lakefile.lean
index 212a25938edf1..bc09c6e252447 100644
--- a/lakefile.lean
+++ b/lakefile.lean
@@ -10,8 +10,10 @@ 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"
/-!
## Options for building mathlib
@@ -23,15 +25,18 @@ require "leanprover-community" / "importGraph" @ git "main"
(as well as `Archive`, `Counterexamples` and `test`).
-/
abbrev mathlibOnlyLinters : Array LeanOption := #[
+ ⟨`linter.docPrime, true⟩,
⟨`linter.hashCommand, true⟩,
⟨`linter.oldObtain, true,⟩,
⟨`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.multiGoal, true⟩,
⟨`linter.style.setOption, true⟩
]
@@ -47,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,
@@ -81,6 +88,16 @@ lean_lib docs where
## Executables provided by Mathlib
-/
+/--
+`lake exe autolabel 150100` adds a topic label to PR `150100` if there is a unique choice.
+This requires GitHub CLI `gh` to be installed!
+
+Calling `lake exe autolabel` without a PR number will print the result without applying
+any labels online.
+-/
+lean_exe autolabel where
+ srcDir := "scripts"
+
/-- `lake exe cache get` retrieves precompiled `.olean` files from a central server. -/
lean_exe cache where
root := `Cache.Main
@@ -118,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/lean-toolchain b/lean-toolchain
index 98556ba065e2a..eff86fd63de9e 100644
--- a/lean-toolchain
+++ b/lean-toolchain
@@ -1 +1 @@
-leanprover/lean4:v4.12.0-rc1
+leanprover/lean4:v4.13.0-rc3
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
new file mode 100644
index 0000000000000..76e42ae90b1fc
--- /dev/null
+++ b/scripts/autolabel.lean
@@ -0,0 +1,310 @@
+/-
+Copyright (c) 2024 Damiano Testa. All rights reserved.
+Released under Apache 2.0 license as described in the file LICENSE.
+Authors: Jon Eugster, Damiano Testa
+-/
+import Lean.Elab.Command
+
+/-!
+# Automatic labelling of PRs
+
+This file contains the script to automatically assign a GitHub label to a PR.
+
+## Label definition
+
+The mapping from GitHub labels to Mathlib folders is done in this file and
+needs to be updated here if necessary:
+
+* `AutoLabel.mathlibLabels` contains an assignment of GitHub labels to folders inside
+ the mathlib repository. If no folder is specified, a label like `t-set-theory` will be
+ interpreted as matching the folder `"Mathlib" / "SetTheory"`.
+* `AutoLabel.mathlibUnlabelled` contains subfolders of `Mathlib/` which are deliberately
+ left without topic label.
+
+## lake exe autolabel
+
+`lake exe autolabel` uses `git diff --name-only origin/master...HEAD` to determine which
+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
+to the PR specified. This requires the **GitHub CLI** `gh` to be installed!
+Example: `lake exe autolabel 10402` for PR #10402.
+
+For the time being, the script only adds a label if it finds a **single unique label**
+which would apply. If multiple labels are found, nothing happens.
+
+## Workflow
+
+There is a mathlib workflow `.github/workflows/add_label_from_diff.yaml` which executes
+this script automatically.
+
+Currently it is set to run only one time when a PR is created.
+
+## Tests
+
+Additionally, the script does a few consistency checks:
+
+- it ensures all paths in specified in `AutoLabel.mathlibLabels` exist
+- It makes sure all subfolders of `Mathlib/` belong to at least one label.
+ There is `AutoLabel.mathlibUnlabelled` to add exceptions for this test.
+
+-/
+
+open Lean System
+
+namespace AutoLabel
+
+/--
+A `Label` consists of the
+* The `label` field is the actual GitHub label name.
+* The `dirs` field is the array of all "root paths" such that a modification in a file contained
+ in one of these paths should be labelled with `label`.
+* The `exclusions` field is the array of all "root paths" that are excluded, among the
+ ones that start with the ones in `dirs`.
+ Any modifications to a file in an excluded path is ignored for the purposes of labelling.
+-/
+structure Label where
+ /-- The label name as it appears on GitHub -/
+ label : String
+ /-- Array of paths which fall under this label. e.g. `"Mathlib" / "Algebra"`.
+
+ For a label of the form `t-set-theory` this defaults to `#["Mathlib" / "SetTheory"]`. -/
+ dirs : Array FilePath := if label.startsWith "t-" then
+ #["Mathlib" / ("".intercalate (label.splitOn "-" |>.drop 1 |>.map .capitalize))]
+ else #[]
+ /-- Array of paths which should be excluded.
+ Any modifications to a file in an excluded path are ignored for the purposes of labelling. -/
+ exclusions : Array FilePath := #[]
+ deriving BEq, Hashable
+
+/--
+Mathlib labels and their corresponding folders. Add new labels and folders here!
+-/
+def mathlibLabels : Array Label := #[
+ { label := "t-algebra",
+ dirs := #[
+ "Mathlib" / "Algebra",
+ "Mathlib" / "FieldTheory",
+ "Mathlib" / "RingTheory",
+ "Mathlib" / "GroupTheory",
+ "Mathlib" / "RepresentationTheory",
+ "Mathlib" / "LinearAlgebra"] },
+ { label := "t-algebraic-geometry",
+ dirs := #[
+ "Mathlib" / "AlgebraicGeometry",
+ "Mathlib" / "Geometry" / "RingedSpace"] },
+ { label := "t-analysis" },
+ { label := "t-category-theory" },
+ { label := "t-combinatorics" },
+ { label := "t-computability" },
+ { label := "t-condensed" },
+ { label := "t-data" },
+ { label := "t-differential-geometry",
+ dirs := #["Mathlib" / "Geometry" / "Manifold"] },
+ { label := "t-dynamics" },
+ { label := "t-euclidean-geometry",
+ dirs := #["Mathlib" / "Geometry" / "Euclidean"] },
+ { label := "t-linter",
+ dirs := #["Mathlib" / "Tactic" / "Linter"] },
+ { label := "t-logic",
+ dirs := #[
+ "Mathlib" / "Logic",
+ "Mathlib" / "ModelTheory"] },
+ { label := "t-measure-probability",
+ dirs := #[
+ "Mathlib" / "MeasureTheory",
+ "Mathlib" / "Probability",
+ "Mathlib" / "InformationTheory"] },
+ { label := "t-meta",
+ dirs := #[
+ "Mathlib" / "Control",
+ "Mathlib" / "Lean",
+ "Mathlib" / "Mathport",
+ "Mathlib" / "Tactic",
+ "Mathlib" / "Util"],
+ exclusions := #["Mathlib" / "Tactic" / "Linter"] },
+ { label := "t-number-theory" },
+ { label := "t-order" },
+ { label := "t-set-theory" },
+ { label := "t-topology",
+ dirs := #[
+ "Mathlib" / "Topology",
+ "Mathlib" / "AlgebraicTopology"] },
+ { label := "CI",
+ dirs := #[".github"] },
+ { label := "IMO",
+ dirs := #["Archive" / "Imo"] } ]
+
+/-- Exceptions inside `Mathlib/` which are not covered by any label. -/
+def mathlibUnlabelled : Array FilePath := #[
+ "Mathlib" / "Deprecated",
+ "Mathlib" / "Init",
+ "Mathlib" / "Testing",
+ "Mathlib" / "Std" ]
+
+/-- Checks if the folder `path` lies inside the folder `dir`. -/
+def _root_.System.FilePath.isPrefixOf (dir path : FilePath) : Bool :=
+ -- use `dir / ""` to prevent partial matching of folder names
+ (dir / "").normalize.toString.isPrefixOf (path / "").normalize.toString
+
+/--
+Return all names of labels in `mathlibLabels` which match
+at least one of the `files`.
+
+* `files`: array of relative paths starting from the mathlib root directory.
+-/
+def getMatchingLabels (files : Array FilePath) : Array String :=
+ let applicable := mathlibLabels.filter fun label ↦
+ -- first exclude all files the label excludes,
+ -- then see if any file remains included by the label
+ let notExcludedFiles := files.filter fun file ↦
+ label.exclusions.all (!·.isPrefixOf file)
+ label.dirs.any (fun dir ↦ notExcludedFiles.any (dir.isPrefixOf ·))
+ -- return sorted list of label names
+ applicable.map (·.label) |>.qsort (· < ·)
+
+/-!
+Testing the functionality of the declarations defined in this script
+-/
+section Tests
+
+-- Test `FilePath.isPrefixOf`
+#guard ("Mathlib" / "Algebra" : FilePath).isPrefixOf ("Mathlib" / "Algebra" / "Basic.lean")
+
+-- Test `FilePath.isPrefixOf` does not trigger on partial prefixes
+#guard ! ("Mathlib" / "Algebra" : FilePath).isPrefixOf ("Mathlib" / "AlgebraicGeometry")
+
+#guard getMatchingLabels #[] == #[]
+-- Test default value for `label.dirs` works
+#guard getMatchingLabels #["Mathlib" / "SetTheory" / "ZFC"] == #["t-set-theory"]
+-- Test exclusion
+#guard getMatchingLabels #["Mathlib" / "Tactic"/ "Abel.lean"] == #["t-meta"]
+#guard getMatchingLabels #["Mathlib" / "Tactic"/ "Linter" / "Lint.lean"] == #["t-linter"]
+#guard getMatchingLabels #[
+ "Mathlib" / "Tactic"/ "Linter" / "Lint.lean",
+ "Mathlib" / "Tactic" / "Abel.lean" ] == #["t-linter", "t-meta"]
+
+/-- Testing function to ensure the labels defined in `mathlibLabels` cover all
+subfolders of `Mathlib/`. -/
+partial def findUncoveredPaths (path : FilePath) (exceptions : Array FilePath := #[]) :
+ IO <| Array FilePath := do
+ let mut notMatched : Array FilePath := #[]
+ -- all directories inside `path`
+ let subDirs ← (← path.readDir).map (·.path) |>.filterM (do FilePath.isDir ·)
+ for dir in subDirs do
+ -- if the sub directory is not matched by a label,
+ -- we go recursively into it
+ if (getMatchingLabels #[dir]).size == 0 then
+ notMatched := notMatched ++ (← findUncoveredPaths dir exceptions)
+ -- a directory should be flagged if none of its sub-directories is matched by a label
+ -- note: we assume here the base directory, i.e. "Mathlib" is never matched by a label,
+ -- therefore we skip this test.
+ if notMatched.size == subDirs.size then
+ if exceptions.contains path then
+ return #[]
+ else
+ return #[path]
+ else
+ return notMatched
+
+end Tests
+
+/--
+Create a message which GitHub CI parses as annotation and displays at the specified file.
+
+Note: `file` is duplicated below so that it is also visible in the plain text output.
+
+* `type`: "error" or "warning"
+* `file`: file where the annotation should be displayed
+* `title`: title of the annotation
+* `message`: annotation message
+-/
+def githubAnnotation (type file title message : String) : String :=
+ s!"::{type} file={file},title={title}::{file}: {message}"
+
+end AutoLabel
+
+open IO AutoLabel in
+
+/-- `args` is expected to have length 0 or 1, where the first argument is the PR number.
+
+If a PR number is provided, the script requires GitHub CLI `gh` to be installed in order
+to add the label to the PR.
+
+## Exit codes:
+
+- `0`: success
+- `1`: invalid arguments provided
+- `2`: invalid labels defined
+- `3`: ~labels do not cover all of `Mathlib/`~ (unused; only emitting warning)
+-/
+unsafe def main (args : List String): IO UInt32 := do
+ if args.length > 1 then
+ println s!"::error:: autolabel: invalid number of arguments ({args.length}), \
+ expected at most 1. Please run without arguments or provide the target PR's \
+ number as a single argument!"
+ return 1
+ let prNumber? := args[0]?
+
+ -- test: validate that all paths in `mathlibLabels` actually exist
+ let mut valid := true
+ for label in mathlibLabels do
+ for dir in label.dirs do
+ unless ← FilePath.pathExists dir do
+ -- print github annotation error
+ println <| AutoLabel.githubAnnotation "error" "scripts/autolabel.lean"
+ s!"Misformatted `{ ``AutoLabel.mathlibLabels }`"
+ s!"directory '{dir}' does not exist but is included by label '{label.label}'. \
+ Please update `{ ``AutoLabel.mathlibLabels }`!"
+ valid := false
+ for dir in label.exclusions do
+ unless ← FilePath.pathExists dir do
+ -- print github annotation error
+ println <| AutoLabel.githubAnnotation "error" "scripts/autolabel.lean"
+ s!"Misformatted `{ ``AutoLabel.mathlibLabels }`"
+ s!"directory '{dir}' does not exist but is excluded by label '{label.label}'. \
+ Please update `{ ``AutoLabel.mathlibLabels }`!"
+ valid := false
+ unless valid do
+ return 2
+
+ -- test: validate that the labels cover all of the `Mathlib/` folder
+ let notMatchedPaths ← findUncoveredPaths "Mathlib" (exceptions := mathlibUnlabelled)
+ if notMatchedPaths.size > 0 then
+ -- print github annotation warning
+ -- note: only emitting a warning because the workflow is only triggered on the first commit
+ -- of a PR and could therefore lead to unexpected behaviour if a folder was created later.
+ println <| AutoLabel.githubAnnotation "warning" "scripts/autolabel.lean"
+ s!"Incomplete `{ ``AutoLabel.mathlibLabels }`"
+ s!"the following paths inside `Mathlib/` are not covered \
+ by any label: {notMatchedPaths} Please modify `AutoLabel.mathlibLabels` accordingly!"
+ -- return 3
+
+ -- get the modified files
+ let gitDiff ← IO.Process.run {
+ cmd := "git",
+ args := #["diff", "--name-only", "origin/master...HEAD"] }
+ let modifiedFiles : Array FilePath := (gitDiff.splitOn "\n").toArray.map (⟨·⟩)
+
+ -- find labels covering the modified files
+ let labels := getMatchingLabels modifiedFiles
+
+ println s!"::notice::Applicable labels: {labels}"
+
+ match labels with
+ | #[] =>
+ println s!"::warning::no label to add"
+ | #[label] =>
+ match prNumber? with
+ | some n =>
+ let _ ← IO.Process.run {
+ cmd := "gh",
+ args := #["pr", "edit", n, "--add-label", label] }
+ println s!"::notice::added label: {label}"
+ | none =>
+ println s!"::warning::no PR-number provided, not adding labels. \
+ (call `lake exe autolabel 150602` to add the labels to PR `150602`)"
+ | _ =>
+ println s!"::notice::not adding multiple labels: {labels}"
+ return 0
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 23730a3fabb2e..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
@@ -22,11 +23,11 @@ def readJsonFile (α) [FromJson α] (path : System.FilePath) : IO α := do
let _ : MonadExceptOf String IO := ⟨throw ∘ IO.userError, fun x _ => x⟩
liftExcept <| fromJson? <|← liftExcept <| Json.parse <|← IO.FS.readFile path
-def databases : List (String × String) := [
- ("undergrad.json", "Entries in `docs/undergrad.yaml` refer to declarations that don't exist. Please correct the following:"),
- ("overview.json", "Entries in `docs/overview.yaml` refer to declarations that don't exist. Please correct the following:"),
- ("100.json", "Entries in `docs/100.yaml` refer to declarations that don't exist. Please correct the following:")
-]
+def databases : List (String × String) :=
+ ["undergrad", "overview", "100"].map fun dir =>
+ (dir ++ ".json",
+ s!"Entries in `docs/{dir}.yaml` refer to declarations that don't exist. \
+ Please correct the following:")
def processDb (decls : ConstMap) : String × String → IO Bool
| (file, msg) => do
diff --git a/scripts/create-adaptation-pr.sh b/scripts/create-adaptation-pr.sh
index 08db7705144c9..32067764818a0 100755
--- a/scripts/create-adaptation-pr.sh
+++ b/scripts/create-adaptation-pr.sh
@@ -14,15 +14,57 @@ set -e # abort whenever a command in the script fails
# So please do not delete the following line, or the final two lines of this script.
{
-if [ $# -ne 2 ]; then
+# Default values
+AUTO="yes"
+
+# Function to display usage
+usage() {
echo "Usage: $0 "
+ echo " or"
+ echo " $0 --bumpversion= --nightlydate= --nightlysha= [--auto=]"
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 'yes'"
exit 1
+}
+
+# Parse arguments
+if [ $# -eq 2 ] && [[ $1 != --* ]] && [[ $2 != --* ]]; then
+ BUMPVERSION=$1
+ NIGHTLYDATE=$2
+elif [ $# -ge 2 ]; then
+ for arg in "$@"; do
+ case $arg in
+ --bumpversion=*)
+ BUMPVERSION="${arg#*=}"
+ shift
+ ;;
+ --nightlydate=*)
+ NIGHTLYDATE="${arg#*=}"
+ shift
+ ;;
+ --nightlysha=*)
+ NIGHTLYSHA="${arg#*=}"
+ shift
+ ;;
+ --auto=*)
+ AUTO="${arg#*=}"
+ shift
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ done
+else
+ usage
fi
-BUMPVERSION=$1 # "v4.10.0"
-NIGHTLYDATE=$2 # "2024-06-25"
+# Validate required arguments
+if [ -z "$BUMPVERSION" ] || [ -z "$NIGHTLYDATE" ]; then
+ usage
+fi
# Check if 'gh' command is available
if ! command -v gh &> /dev/null; then
@@ -30,19 +72,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
- 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
-
echo "### Creating a PR for the nightly adaptation for $NIGHTLYDATE"
echo
@@ -61,7 +90,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
@@ -79,6 +108,13 @@ if git diff --name-only --diff-filter=U | grep -q .; then
fi
fi
+if git diff --name-only --diff-filter=U | grep -q . || ! git diff-index --quiet HEAD --; then
+ if [ "$AUTO" = "yes" ]; then
+ echo "Auto mode enabled. Bailing out due to unresolved conflicts or uncommitted changes."
+ exit 1
+ fi
+fi
+
# Loop until all conflicts are resolved and committed
while git diff --name-only --diff-filter=U | grep -q . || ! git diff-index --quiet HEAD --; do
echo
@@ -99,23 +135,31 @@ 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 origin/nightly-testing || 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
echo
echo "### [auto] Conflict resolution"
- echo "### Automatically choosing 'lean-toolchain' and 'lake-manifest.json' from the newer branch"
- echo "### In this case, the newer branch is 'origin/nightly-testing'"
- git checkout origin/nightly-testing -- lean-toolchain lake-manifest.json
+ echo "### Automatically choosing 'lean-toolchain' and 'lake-manifest.json' from 'nightly-testing'"
+ git checkout $NIGHTLYSHA -- lean-toolchain lake-manifest.json
git add lean-toolchain lake-manifest.json
fi
+if git diff --name-only --diff-filter=U | grep -q .; then
+ if [ "$AUTO" = "yes" ]; then
+ echo "Auto mode enabled. Bailing out due to unresolved conflicts or uncommitted changes."
+ exit 1
+ fi
+fi
+
# Check if there are more merge conflicts
if git diff --name-only --diff-filter=U | grep -q .; then
echo
echo "### [user] Conflict resolution"
echo "We are merging the latest changes from 'origin/nightly-testing' into 'bump/nightly-$NIGHTLYDATE'"
+ echo "Specifically, we are merging the following version of 'origin/nightly-testing':"
+ echo "$NIGHTLYSHA"
echo "There seem to be conflicts: please resolve them"
echo ""
echo " 1) Open `pwd` in a new terminal and run 'git status'"
@@ -143,8 +187,13 @@ if git diff --name-only bump/$BUMPVERSION bump/nightly-$NIGHTLYDATE | grep -q .;
echo "Here is a suggested 'gh' command to do this:"
gh_command="gh pr create -t \"$pr_title\" -b '' -B bump/$BUMPVERSION"
echo "> $gh_command"
- echo "Shall I run this command for you? (y/n)"
- read answer
+ if [ "$AUTO" = "yes" ]; then
+ echo "Auto mode enabled. Running the command..."
+ answer="y"
+ else
+ echo "Shall I run this command for you? (y/n)"
+ read answer
+ fi
if [ "$answer" != "${answer#[Yy]}" ]; then
gh_output=$(eval $gh_command)
# Extract the PR number from the output
@@ -152,16 +201,42 @@ if git diff --name-only bump/$BUMPVERSION bump/nightly-$NIGHTLYDATE | grep -q .;
fi
echo
- echo "### [user] post a link to the PR on Zulip"
+ 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:"
echo "Title: $zulip_title"
echo " Body: $zulip_body"
- read -p "Press enter to continue"
+
+ if command -v zulip-send >/dev/null 2>&1; then
+ zulip_command="zulip-send --stream nightly-testing --subject \"$zulip_title\" --message \"$zulip_body\""
+ echo "Here is a suggested 'zulip-send' command to do this:"
+ echo "> $zulip_command"
+
+ if [ "$AUTO" = "yes" ]; then
+ echo "Auto mode enabled. Running the command..."
+ answer="y"
+ else
+ echo "Shall I run this command for you? (y/n)"
+ read answer
+ fi
+
+ if [ "$answer" != "${answer#[Yy]}" ]; then
+ eval $zulip_command
+ fi
+ else
+ echo "Zulip CLI is not installed. Please install it to send messages automatically."
+ if [ "$AUTO" = "yes" ]; then
+ exit 1
+ fi
+ fi
+
+ if [ "$AUTO" != "yes" ]; then
+ read -p "Press enter to continue"
+ fi
# else, let the user know that no PR is needed
else
@@ -177,7 +252,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
@@ -195,6 +270,15 @@ if git diff --name-only --diff-filter=U | grep -q .; then
fi
fi
+if git diff --name-only --diff-filter=U | grep -q . || ! git diff-index --quiet HEAD --; then
+ 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 occurred while merging the new branch into 'nightly-testing'."
+ exit 2
+ fi
+fi
+
# Loop until all conflicts are resolved and committed
while git diff --name-only --diff-filter=U | grep -q . || ! git diff-index --quiet HEAD --; do
echo
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/get_tlabel.sh b/scripts/get_tlabel.sh
index 7672fcf5ca80e..6e03a8f27d23f 100755
--- a/scripts/get_tlabel.sh
+++ b/scripts/get_tlabel.sh
@@ -17,16 +17,16 @@ PR="${1}"
>&2 printf $'Using PR: \'%s\'\n' "${PR}"
-tlabels="$(gh api --jq '.labels.[].name' "${PR}" | grep -- '^t-' || printf 'generic\nlabel')"
+tlabels="$(gh api --jq '.labels.[].name' "${PR}" | grep -- '^\(t-\|CI\|IMO\)' || printf 'generic\nlabel')"
# print to error, since the stdout is captured into `GITHUB_OUTPUT
>&2 printf 't-labels:\n---\n%s\n---\n' "${tlabels}"
-# if there is exactly 1 `t-xxx` label, use `maintainer merge: t-xxx`
-# if there isn't exactly 1 `t-xxx` label, use `maintainer merge`
+# if there is exactly 1 `t-xxx`, `CI`, or `IMO` label, use `maintainer merge: t-xxx`
+# if there isn't exactly 1 `t-xxx`, `CI`, or `IMO` label, use `maintainer merge`
if [[ "$(wc -l <<<"${tlabels}")" -ne 1 ]]; then
topicName="maintainer merge"
else
topicName="maintainer merge: ${tlabels}"
fi
->&2 printf $'Post to topic: \'%s\'"\n' "${topicName}"
+>&2 printf $'Post to topic: \'%s\'\n' "${topicName}"
echo "topic=${topicName}"
diff --git a/scripts/import-graph-report.py b/scripts/import-graph-report.py
index cf072b916c5e8..86775bf4c2fc1 100755
--- a/scripts/import-graph-report.py
+++ b/scripts/import-graph-report.py
@@ -10,6 +10,8 @@
import json
import sys
+high_import_threshold = 2
+
def compare_counts(base_file, head_file, changed_files_txt):
# Load the counts
with open(head_file, 'r') as f:
@@ -29,6 +31,7 @@ def compare_counts(base_file, head_file, changed_files_txt):
# Compare the counts
changes = []
+ high_pct = []
for file in changed_files:
base_count = base_counts.get(file, 0)
head_count = head_counts.get(file, 0)
@@ -36,6 +39,8 @@ def compare_counts(base_file, head_file, changed_files_txt):
continue
diff = head_count - base_count
percent = (diff / base_count) * 100
+ if high_import_threshold < percent:
+ high_pct.append(f'| +{percent:.2f}% | `{file}` |')
if diff < 0: # Dependencies went down
changes.append((file, base_count, head_count, diff, percent))
elif diff > new_files: # Dependencies went up by more than the number of new files
@@ -59,11 +64,19 @@ def compare_counts(base_file, head_file, changed_files_txt):
message += '\n'.join(messages)
else:
message += 'No significant changes to the import graph'
- return message
+
+ high_pct_report = ''
+ if high_pct:
+ high_pct_report += f'Import changes exceeding {high_import_threshold}%\n\n'
+ high_pct_report += '| % | File |\n'
+ high_pct_report += '| - | - |\n'
+ high_pct_report += '\n'.join(high_pct)
+ return (message, high_pct_report)
if __name__ == '__main__':
base_file = sys.argv[1]
head_file = sys.argv[2]
changed_files_txt = sys.argv[3]
- message = compare_counts(base_file, head_file, changed_files_txt)
+ (message, high_pct) = compare_counts(base_file, head_file, changed_files_txt)
print(message)
+ print(high_pct)
diff --git a/scripts/init_creation.sh b/scripts/init_creation.sh
index f7469af5e39c6..7abca30241c43 100644
--- a/scripts/init_creation.sh
+++ b/scripts/init_creation.sh
@@ -2,11 +2,16 @@
: <<'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
+# Make this script robust against unintentional errors.
+# See e.g. http://redsymbol.net/articles/unofficial-bash-strict-mode/ for explanation.
+set -euo pipefail
+IFS=$'\n\t'
+
# `mathlibNonImportingFiles` generates the list of `Mathlib` files that do not have Mathlib imports.
# The output of `lake exe graph` are many lines like
# ` "Mathlib..." -> "Mathlib...";`
@@ -30,11 +35,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_debian.sh b/scripts/install_debian.sh
index d2085be2d8cfb..9d5caf69db239 100755
--- a/scripts/install_debian.sh
+++ b/scripts/install_debian.sh
@@ -1,6 +1,11 @@
#!/usr/bin/env bash
-set -exo pipefail
+# Make this script robust against unintentional errors.
+# See e.g. http://redsymbol.net/articles/unofficial-bash-strict-mode/ for explanation.
+set -euo pipefail
+IFS=$'\n\t'
+
+set -x
sudo apt install -y git curl
diff --git a/scripts/install_macos.sh b/scripts/install_macos.sh
index ef46de9dc19ff..eb3e0863ce886 100755
--- a/scripts/install_macos.sh
+++ b/scripts/install_macos.sh
@@ -1,6 +1,11 @@
#!/usr/bin/env bash
-set -exo pipefail
+# Make this script robust against unintentional errors.
+# See e.g. http://redsymbol.net/articles/unofficial-bash-strict-mode/ for explanation.
+set -euo pipefail
+IFS=$'\n\t'
+
+set -x
# Install elan using the official script
curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh
@@ -9,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/lean-pr-testing-comments.sh b/scripts/lean-pr-testing-comments.sh
index 189a6ea6ac536..ba5c9586b2e05 100755
--- a/scripts/lean-pr-testing-comments.sh
+++ b/scripts/lean-pr-testing-comments.sh
@@ -1,8 +1,13 @@
-## Create comments and labels on a Lean 4 PR after CI has finished on a `lean-pr-testing-NNNN` branch.
+## Create comments and labels on a Lean 4 or Batteries PR after CI has finished on a `*-pr-testing-NNNN` branch.
##
## See https://leanprover-community.github.io/contribute/tags_and_branches.html
set -e
+# Ensure first argument is either 'lean' or 'batteries'.
+if [ -z "$1" ]; then
+ echo "The first argument must be either 'lean' or 'batteries'"
+ exit 1
+fi
# TODO: The whole script ought to be rewritten in javascript, to avoid having to use curl for API calls.
#
@@ -19,14 +24,29 @@ set -e
# LINT_OUTCOME: ${{ steps.lint.outcome }}
# TEST_OUTCOME: ${{ steps.test.outcome }}
+# Adjust the branch pattern and URLs based on the repository.
+if [ "$1" == "lean" ]; then
+ branch_prefix="lean-pr-testing"
+ repo_url="https://api.github.com/repos/leanprover/lean4"
+ base_branch="nightly-testing" # This really should be the relevant `nightly-testing-YYYY-MM-DD` tag.
+elif [ "$1" == "batteries" ]; then
+ branch_prefix="batteries-pr-testing"
+ repo_url="https://api.github.com/repos/leanprover-community/batteries"
+ base_branch="master"
+else
+ echo "Unknown repository: $1. Must be either 'lean' or 'batteries'."
+ exit 1
+fi
+
# Extract branch name and check if it matches the pattern.
branch_name=$(echo "$GITHUB_CONTEXT" | jq -r .ref | cut -d'/' -f3)
-if [[ "$branch_name" =~ ^lean-pr-testing-([0-9]+)$ ]]; then
+if [[ "$branch_name" =~ ^$branch_prefix-([0-9]+)$ ]]; then
pr_number="${BASH_REMATCH[1]}"
current_time=$(date "+%Y-%m-%d %H:%M:%S")
- echo "This is a 'lean-pr-testing-$pr_number' branch, so we need to adjust labels and write a comment."
+ echo "This is a '$branch_prefix-$pr_number' branch, so we need to adjust labels and write a comment."
+ # Perform actions based on outcomes (same logic as before)
if [ "$TEST_OUTCOME" == "success" ]; then
echo "Removing label awaiting-mathlib"
curl -L -s \
@@ -34,21 +54,21 @@ if [[ "$branch_name" =~ ^lean-pr-testing-([0-9]+)$ ]]; then
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/leanprover/lean4/issues/$pr_number/labels/awaiting-mathlib
+ $repo_url/issues/$pr_number/labels/awaiting-mathlib
echo "Removing label breaks-mathlib"
curl -L -s \
-X DELETE \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/leanprover/lean4/issues/$pr_number/labels/breaks-mathlib
+ $repo_url/issues/$pr_number/labels/breaks-mathlib
echo "Adding label builds-mathlib"
curl -L -s \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/leanprover/lean4/issues/$pr_number/labels \
+ $repo_url/issues/$pr_number/labels \
-d '{"labels":["builds-mathlib"]}'
elif [ "$LINT_OUTCOME" == "failure" ] || [ "$TEST_OUTCOME" == "failure" ] || [ "$COUNTEREXAMPLES_OUTCOME" == "failure" ] || [ "$ARCHIVE_OUTCOME" == "failure" ] || [ "$NOISY_OUTCOME" == "failure" ] || [ "$BUILD_OUTCOME" == "failure" ]; then
echo "Removing label builds-mathlib"
@@ -57,32 +77,32 @@ if [[ "$branch_name" =~ ^lean-pr-testing-([0-9]+)$ ]]; then
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/leanprover/lean4/issues/$pr_number/labels/builds-mathlib
+ $repo_url/issues/$pr_number/labels/builds-mathlib
echo "Adding label breaks-mathlib"
curl -L -s \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/leanprover/lean4/issues/$pr_number/labels \
+ $repo_url/issues/$pr_number/labels \
-d '{"labels":["breaks-mathlib"]}'
fi
# Use GitHub API to check if a comment already exists
existing_comment=$(curl -L -s -H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
- "https://api.github.com/repos/leanprover/lean4/issues/$pr_number/comments" \
- | jq 'first(.[] | select(.body | test("^- . Mathlib") or startswith("Mathlib CI status")) | select(.user.login == "leanprover-community-mathlib4-bot"))')
+ "$repo_url/issues/$pr_number/comments" \
+ | jq 'first(.[] | select(.body | test("^- . Mathlib") or startswith("Mathlib CI status")) | select(.user.login == "leanprover-community-bot"))')
existing_comment_id=$(echo "$existing_comment" | jq -r .id)
existing_comment_body=$(echo "$existing_comment" | jq -r .body)
- branch="[lean-pr-testing-$pr_number](https://github.com/leanprover-community/mathlib4/compare/nightly-testing...lean-pr-testing-$pr_number)"
+ branch="[$branch_prefix-$pr_number](https://github.com/leanprover-community/mathlib4/compare/$base_branch...$branch_prefix-$pr_number)"
# Depending on the success/failure, set the appropriate message
if [ "$LINT_OUTCOME" == "cancelled" ] || [ "$TEST_OUTCOME" == "cancelled" ] || [ "$COUNTEREXAMPLES_OUTCOME" == "cancelled" ] || [ "$ARCHIVE_OUTCOME" == "cancelled" ] || [ "$NOISY_OUTCOME" == "cancelled" ] || [ "$BUILD_OUTCOME" == "cancelled" ]; then
message="- 🟡 Mathlib branch $branch build against this PR was cancelled. ($current_time) [View Log]($WORKFLOW_URL)"
elif [ "$TEST_OUTCOME" == "success" ]; then
message="- ✅ Mathlib branch $branch has successfully built against this PR. ($current_time) [View Log]($WORKFLOW_URL)"
- elif [ "$BUILD_OUTCOME" == "failure" ] ; then
+ elif [ "$BUILD_OUTCOME" == "failure" ]; then
message="- 💥 Mathlib branch $branch build failed against this PR. ($current_time) [View Log]($WORKFLOW_URL)"
elif [ "$LINT_OUTCOME" == "failure" ]; then
message="- ❌ Mathlib branch $branch built against this PR, but linting failed. ($current_time) [View Log]($WORKFLOW_URL)"
@@ -103,23 +123,22 @@ if [[ "$branch_name" =~ ^lean-pr-testing-([0-9]+)$ ]]; then
# Append new result to the existing comment or post a new comment
if [ -z "$existing_comment_id" ]; then
# Post new comment with a bullet point
- # Keep message in sync with https://github.com/leanprover/lean4/blob/master/.github/workflows/pr-release.yml
intro="Mathlib CI status ([docs](https://leanprover-community.github.io/contribute/tags_and_branches.html)):"
- echo "Posting as new comment at leanprover/lean4/issues/$pr_number/comments"
+ echo "Posting as new comment at $repo_url/issues/$pr_number/comments"
curl -L -s \
-X POST \
-H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-d "$(jq --null-input --arg intro "$intro" --arg val "$message" '{"body": ($intro + "\n" + $val)}')" \
- "https://api.github.com/repos/leanprover/lean4/issues/$pr_number/comments"
+ "$repo_url/issues/$pr_number/comments"
else
# Append new result to the existing comment
- echo "Appending to existing comment at leanprover/lean4/issues/$pr_number/comments"
+ echo "Appending to existing comment at $repo_url/issues/$pr_number/comments"
curl -L -s \
-X PATCH \
-H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-d "$(jq --null-input --arg existing "$existing_comment_body" --arg message "$message" '{"body":($existing + "\n" + $message)}')" \
- "https://api.github.com/repos/leanprover/lean4/issues/comments/$existing_comment_id"
+ "$repo_url/issues/comments/$existing_comment_id"
fi
fi
diff --git a/scripts/lint-bib.sh b/scripts/lint-bib.sh
index 630f64c625db2..500f8c19947b9 100755
--- a/scripts/lint-bib.sh
+++ b/scripts/lint-bib.sh
@@ -1,6 +1,11 @@
#!/usr/bin/env bash
-set -exo pipefail
+# Make this script robust against unintentional errors.
+# See e.g. http://redsymbol.net/articles/unofficial-bash-strict-mode/ for explanation.
+set -euo pipefail
+IFS=$'\n\t'
+
+set -x
# https://leanprover-community.github.io/contribute/doc.html#citing-other-works
cp docs/references.bib docs/references.bib.old
bibtool --preserve.key.case=on --preserve.keys=on --pass.comments=on --print.use.tab=off -s \
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
new file mode 100644
index 0000000000000..31bf8a6ea808e
--- /dev/null
+++ b/scripts/no_lints_prime_decls.txt
@@ -0,0 +1,4881 @@
+AbelRuffini.not_solvable_by_rad'
+abs_add'
+abs_le_of_sq_le_sq'
+abs_lt_of_sq_lt_sq'
+abs_norm'
+abs_norm_sub_norm_le'
+Absorbent.zero_mem'
+ack_strict_mono_left'
+Action.inhabited'
+Action.tensorUnit_ρ'
+Action.tensor_ρ'
+AddAction.orbitZMultiplesEquiv_symm_apply'
+AddChar.div_apply'
+AddChar.inv_apply'
+AddChar.neg_apply'
+AddChar.sub_apply'
+AddChar.zmodChar_apply'
+AddCircle.addOrderOf_div_of_gcd_eq_one'
+AddCircle.continuous_mk'
+AddCircle.measurable_mk'
+AddCircle.norm_eq'
+AddCommGroup.intCast_modEq_intCast'
+AddCommGroup.ModEq.add_left_cancel'
+AddCommGroup.ModEq.add_right_cancel'
+AddCommGroup.modEq_sub_iff_add_modEq'
+AddCommGroup.ModEq.sub_left_cancel'
+AddCommGroup.ModEq.sub_right_cancel'
+AddCommGroup.sub_modEq_iff_modEq_add'
+AddConstMapClass.map_add_int'
+AddConstMapClass.map_add_nat'
+AddConstMapClass.map_add_ofNat'
+AddConstMapClass.map_int_add'
+AddConstMapClass.map_nat'
+AddConstMapClass.map_nat_add'
+AddConstMapClass.map_ofNat'
+AddConstMapClass.map_ofNat_add'
+AddConstMapClass.map_sub_int'
+AddConstMapClass.map_sub_nat'
+AddConstMapClass.map_sub_ofNat'
+add_div'
+AddGroup.int_smulCommClass'
+Additive.isometricVAdd'
+Additive.isometricVAdd''
+add_le_mul'
+AddMonoidAlgebra.lift_apply'
+AddMonoidAlgebra.lift_of'
+AddMonoidAlgebra.lift_unique'
+AddMonoidAlgebra.mem_grade_iff'
+AddMonoidHom.coe_smul'
+AddMonoidHom.coe_toMultiplicative'
+AddMonoidHom.coe_toMultiplicative''
+AddMonoid.nat_smulCommClass'
+add_sq'
+AddSubgroup.torsionBy.mod_self_nsmul'
+AddValuation.map_add'
+AddValuation.map_lt_sum'
+ADEInequality.admissible_A'
+ADEInequality.admissible_D'
+ADEInequality.admissible_of_one_lt_sumInv_aux'
+AdjoinRoot.algebraMap_eq'
+AdjoinRoot.coe_injective'
+AdjoinRoot.isIntegral_root'
+AdjoinRoot.Minpoly.toAdjoin_apply'
+AEMeasurable.comp_aemeasurable'
+aemeasurable_const'
+AEMeasurable.const_smul'
+AEMeasurable.div'
+aemeasurable_id'
+aemeasurable_id''
+AEMeasurable.inf'
+AEMeasurable.mono'
+AEMeasurable.mul'
+aemeasurable_of_tendsto_metrizable_ae'
+AEMeasurable.sup'
+AffineEquiv.coe_mk'
+AffineEquiv.linear_mk'
+AffineIsometryEquiv.coe_mk'
+AffineIsometryEquiv.coe_vaddConst'
+AffineIsometryEquiv.dist_pointReflection_self'
+AffineIsometryEquiv.linearIsometryEquiv_mk'
+AffineMap.coe_mk'
+AffineMap.lineMap_apply_module'
+AffineMap.lineMap_apply_ring'
+AffineSubspace.mem_perpBisector_iff_dist_eq'
+AkraBazziRecurrence.asympBound_def'
+AkraBazziRecurrence.dist_r_b'
+Algebra.adjoin_induction''
+Algebra.algebraMap_eq_smul_one'
+Algebra.fg_trans'
+Algebra.FormallyUnramified.ext'
+Algebra.FormallyUnramified.lift_unique'
+Algebra.Generators.Cotangent.module'
+Algebra.Generators.Cotangent.val_smul'
+Algebra.Generators.Cotangent.val_smul''
+Algebra.Generators.Cotangent.val_smul'''
+AlgebraicClosure.toStepOfLE'
+AlgebraicGeometry.basicOpen_eq_of_affine'
+AlgebraicGeometry.IsAffineOpen.fromSpec_preimage_basicOpen'
+AlgebraicGeometry.IsAffineOpen.isLocalization_stalk'
+AlgebraicGeometry.IsOpenImmersion.hasLimit_cospan_forget_of_left'
+AlgebraicGeometry.IsOpenImmersion.hasLimit_cospan_forget_of_right'
+AlgebraicGeometry.LocallyRingedSpace.Hom.ext'
+AlgebraicGeometry.LocallyRingedSpace.id_val'
+AlgebraicGeometry.LocallyRingedSpace.stalkMap_germ'
+AlgebraicGeometry.morphismRestrict_app'
+AlgebraicGeometry.PresheafedSpace.GlueData.opensImagePreimageMap_app'
+AlgebraicGeometry.PresheafedSpace.IsOpenImmersion.c_iso'
+AlgebraicGeometry.PresheafedSpace.stalkMap_germ'
+AlgebraicGeometry.ProjectiveSpectrum.StructureSheaf.SectionSubring.add_mem'
+AlgebraicGeometry.ProjectiveSpectrum.StructureSheaf.SectionSubring.mul_mem'
+AlgebraicGeometry.ProjectiveSpectrum.StructureSheaf.SectionSubring.neg_mem'
+AlgebraicGeometry.ProjectiveSpectrum.StructureSheaf.SectionSubring.one_mem'
+AlgebraicGeometry.ProjectiveSpectrum.StructureSheaf.SectionSubring.zero_mem'
+AlgebraicGeometry.ProjIsoSpecTopComponent.FromSpec.mem_carrier_iff'
+AlgebraicGeometry.Proj.stalkIso'_germ'
+AlgebraicGeometry.Scheme.Hom.appIso_hom'
+AlgebraicGeometry.Scheme.Hom.appLE_map'
+AlgebraicGeometry.Scheme.Hom.map_appLE'
+AlgebraicGeometry.Scheme.map_basicOpen'
+AlgebraicGeometry.Scheme.mem_basicOpen_top'
+AlgebraicGeometry.Scheme.Opens.germ_stalkIso_hom'
+AlgebraicGeometry.Scheme.stalkMap_germ'
+AlgebraicGeometry.SheafedSpace.comp_c_app'
+AlgebraicGeometry.SheafedSpace.IsOpenImmersion.hasLimit_cospan_forget_of_left'
+AlgebraicGeometry.SheafedSpace.IsOpenImmersion.hasLimit_cospan_forget_of_right'
+AlgebraicGeometry.Spec.locallyRingedSpaceObj_presheaf'
+AlgebraicGeometry.Spec.locallyRingedSpaceObj_presheaf_map'
+AlgebraicGeometry.Spec.locallyRingedSpaceObj_sheaf'
+AlgebraicGeometry.stalkToFiberRingHom_germ'
+AlgebraicGeometry.StructureSheaf.comap_id'
+AlgebraicGeometry.StructureSheaf.const_apply'
+AlgebraicGeometry.StructureSheaf.const_mul_cancel'
+AlgebraicGeometry.StructureSheaf.IsFraction.eq_mk'
+AlgebraicGeometry.StructureSheaf.localizationToStalk_mk'
+AlgebraicGeometry.StructureSheaf.res_const'
+AlgebraicGeometry.StructureSheaf.stalkToFiberRingHom_germ'
+AlgebraicGeometry.StructureSheaf.toBasicOpen_mk'
+AlgebraicGeometry.ΓSpec.adjunction_counit_app'
+AlgebraicGeometry.ΓSpec.locallyRingedSpaceAdjunction_counit_app'
+AlgebraicGeometry.ΓSpec.locallyRingedSpaceAdjunction_homEquiv_apply'
+AlgebraicGeometry.ΓSpec.toOpen_unit_app_val_c_app'
+algebraicIndependent_equiv'
+AlgebraicIndependent.map'
+AlgebraicIndependent.to_subtype_range'
+AlgebraicTopology.DoldKan.hσ'_eq'
+AlgebraicTopology.DoldKan.Γ₀.Obj.map_on_summand'
+AlgebraicTopology.DoldKan.Γ₀.Obj.map_on_summand₀'
+AlgebraicTopology.DoldKan.Γ₀.Obj.Termwise.mapMono_δ₀'
+Algebra.IsAlgebraic.bijective_of_isScalarTower'
+Algebra.TensorProduct.algebraMap_apply'
+Algebra.TensorProduct.basis_repr_symm_apply'
+Algebra.TensorProduct.ext'
+Algebra.TensorProduct.intCast_def'
+Algebra.TensorProduct.natCast_def'
+Algebra.toMatrix_lmul'
+AlgEquiv.apply_smulCommClass'
+AlgEquiv.coe_restrictScalars'
+AlgEquiv.coe_ringEquiv'
+AlgEquiv.mk_coe'
+AlgHom.coe_mk'
+AlgHom.coe_restrictScalars'
+AlgHom.toAddMonoidHom'
+AlgHom.toMonoidHom'
+AlternatingMap.domCoprod.summand_mk''
+analyticOnNhd_congr'
+AnalyticOnNhd.congr'
+AnalyticOnNhd.eval_continuousLinearMap'
+AnalyticOnNhd.eval_linearMap'
+AntilipschitzWith.le_mul_nnnorm'
+AntilipschitzWith.le_mul_norm'
+AntilipschitzWith.to_rightInvOn'
+antisymm'
+Antitone.const_mul'
+Antitone.mul_const'
+AntitoneOn.const_mul'
+AntitoneOn.mul_const'
+Applicative.pure_seq_eq_map'
+ApplicativeTransformation.preserves_map'
+apply_abs_le_mul_of_one_le'
+ArithmeticFunction.mul_smul'
+ArithmeticFunction.one_smul'
+ArithmeticFunction.ppow_succ'
+ArithmeticFunction.sum_eq_iff_sum_smul_moebius_eq_on'
+Associated.dvd'
+Associated.of_pow_associated_of_prime'
+Associates.count_mul_of_coprime'
+Associates.dvd_of_mem_factors'
+Associates.map_subtype_coe_factors'
+Associates.mk_ne_zero'
+Associates.unique'
+Asymptotics.IsBigO.congr'
+Asymptotics.isBigO_const_mul_left_iff'
+Asymptotics.IsBigO.const_mul_right'
+Asymptotics.isBigO_const_mul_right_iff'
+Asymptotics.isBigO_fst_prod'
+Asymptotics.IsBigO.of_bound'
+Asymptotics.isBigO_of_le'
+Asymptotics.isBigO_self_const_mul'
+Asymptotics.isBigO_snd_prod'
+Asymptotics.IsBigOWith.congr'
+Asymptotics.IsBigOWith.const_mul_right'
+Asymptotics.isBigOWith_of_le'
+Asymptotics.IsBigOWith.pow'
+Asymptotics.isBigOWith_self_const_mul'
+Asymptotics.IsBigOWith.sup'
+Asymptotics.isBigOWith_zero'
+Asymptotics.isEquivalent_of_tendsto_one'
+Asymptotics.IsLittleO.congr'
+Asymptotics.isLittleO_const_mul_left_iff'
+Asymptotics.IsLittleO.const_mul_right'
+Asymptotics.isLittleO_const_mul_right_iff'
+Asymptotics.IsLittleO.def'
+Asymptotics.isLittleO_iff_nat_mul_le'
+Asymptotics.isLittleO_iff_tendsto'
+Asymptotics.isLittleO_irrefl'
+Asymptotics.IsLittleO.right_isBigO_add'
+Asymptotics.IsLittleO.right_isTheta_add'
+Asymptotics.isTheta_of_norm_eventuallyEq'
+Asymptotics.SuperpolynomialDecay.congr'
+ball_eq'
+Ballot.ballot_problem'
+Basis.det_map'
+Basis.det_reindex'
+Basis.mk_eq_rank'
+Basis.mk_eq_rank''
+Basis.reindexRange_repr'
+Basis.repr_eq_iff'
+Basis.tensorProduct_apply'
+Behrend.bound_aux'
+Behrend.lower_bound_le_one'
+Behrend.map_succ'
+bernoulli'_def'
+bernoulli'_spec'
+bernoulli_spec'
+bernsteinPolynomial.flip'
+Besicovitch.SatelliteConfig.hlast'
+Besicovitch.SatelliteConfig.inter'
+bihimp_eq'
+biInf_congr'
+biInf_finsetSigma'
+biInf_sigma'
+Bimod.AssociatorBimod.hom_left_act_hom'
+Bimod.AssociatorBimod.hom_right_act_hom'
+Bimod.comp_hom'
+Bimod.id_hom'
+Bimod.LeftUnitorBimod.hom_left_act_hom'
+Bimod.LeftUnitorBimod.hom_right_act_hom'
+Bimod.RightUnitorBimod.hom_left_act_hom'
+Bimod.RightUnitorBimod.hom_right_act_hom'
+Bimod.TensorBimod.actRight_one'
+Bimod.TensorBimod.left_assoc'
+Bimod.TensorBimod.middle_assoc'
+Bimod.TensorBimod.one_act_left'
+Bimod.TensorBimod.right_assoc'
+Bimon_.comp_hom'
+Bimon_.id_hom'
+birkhoffAverage_congr_ring'
+birkhoffAverage_one'
+birkhoffAverage_zero'
+birkhoffSum_one'
+birkhoffSum_succ'
+birkhoffSum_zero'
+biSup_congr'
+biSup_finsetSigma'
+biSup_sigma'
+BooleanRing.add_eq_zero'
+Bool.eq_false_of_not_eq_true'
+Bool.eq_true_of_not_eq_false'
+Bornology.ext_iff'
+Bornology.IsBounded.exists_pos_norm_le'
+Bornology.IsBounded.exists_pos_norm_lt'
+bound'
+BoundedContinuousFunction.const_apply'
+BoundedContinuousFunction.dist_le_two_norm'
+BoundedContinuousFunction.dist_nonneg'
+BoundedContinuousFunction.extend_apply'
+BoundedContinuousFunction.instModule'
+BoundedContinuousFunction.instSMul'
+BoundedLatticeHom.coe_comp_inf_hom'
+BoundedLatticeHom.coe_comp_lattice_hom'
+BoundedLatticeHom.coe_comp_sup_hom'
+BoxIntegral.Box.coe_mk'
+BoxIntegral.Box.volume_apply'
+BoxIntegral.IntegrationParams.toFilterDistortioniUnion_neBot'
+BoxIntegral.Prepartition.iUnion_def'
+BoxIntegral.Prepartition.mem_restrict'
+BoxIntegral.Prepartition.mem_split_iff'
+BoxIntegral.TaggedPrepartition.IsSubordinate.mono'
+Bundle.TotalSpace.mk'
+calc_eval_z'
+card_dvd_exponent_pow_rank'
+Cardinal.add_eq_max'
+Cardinal.add_le_add'
+Cardinal.add_mk_eq_max'
+Cardinal.aleph0_le_aleph'
+Cardinal.aleph_eq_aleph'
+Cardinal.alephIdx_aleph'
+Cardinal.cantor'
+Cardinal.lift_lt_univ'
+Cardinal.lift_mk_shrink'
+Cardinal.lift_mk_shrink''
+Cardinal.lt_univ'
+Cardinal.mk_eq_two_iff'
+Cardinal.mk_finsupp_lift_of_infinite'
+Cardinal.mk_finsupp_of_infinite'
+Cardinal.mul_comm'
+Cardinal.mul_eq_max'
+Cardinal.prod_const'
+Cardinal.sum_add_distrib'
+Cardinal.sum_const'
+Cardinal.two_le_iff'
+card_le_of_injective'
+card_le_of_surjective'
+catalan_succ'
+CategoryTheory.Abelian.coimageImageComparison_eq_coimageImageComparison'
+CategoryTheory.Abelian.epi_of_epi_of_epi_of_mono'
+CategoryTheory.Abelian.epi_of_mono_of_epi_of_mono'
+CategoryTheory.Abelian.Ext.add_hom'
+CategoryTheory.Abelian.Ext.neg_hom'
+CategoryTheory.Abelian.FunctorCategory.coimageImageComparison_app'
+CategoryTheory.Abelian.mono_of_epi_of_epi_mono'
+CategoryTheory.Abelian.mono_of_epi_of_mono_of_mono'
+CategoryTheory.Abelian.OfCoimageImageComparisonIsIso.imageMonoFactorisation_e'
+CategoryTheory.Abelian.Pseudoelement.pseudoApply_mk'
+CategoryTheory.Abelian.Pseudoelement.zero_eq_zero'
+CategoryTheory.Abelian.Pseudoelement.zero_morphism_ext'
+CategoryTheory.ActionCategory.cases'
+CategoryTheory.additive_coyonedaObj'
+CategoryTheory.additive_yonedaObj'
+CategoryTheory.Adhesive.van_kampen'
+CategoryTheory.Adjunction.he''
+CategoryTheory.Arrow.iso_w'
+CategoryTheory.BicategoricalCoherence.assoc'
+CategoryTheory.BicategoricalCoherence.left'
+CategoryTheory.BicategoricalCoherence.right'
+CategoryTheory.BicategoricalCoherence.tensorRight'
+CategoryTheory.Bifunctor.diagonal'
+CategoryTheory.Biproduct.column_nonzero_of_iso'
+CategoryTheory.BraidedCategory.yang_baxter'
+CategoryTheory.BraidedFunctor.ext'
+CategoryTheory.CategoryOfElements.CreatesLimitsAux.π_liftedConeElement'
+CategoryTheory.CechNerveTerminalFrom.hasWidePullback'
+CategoryTheory.CommSq.HasLift.mk'
+CategoryTheory.Comonad.Coalgebra.Hom.ext'
+CategoryTheory.ComonadHom.ext'
+CategoryTheory.comp_apply'
+CategoryTheory.ComposableArrows.Exact.exact'
+CategoryTheory.ComposableArrows.IsComplex.zero'
+CategoryTheory.ComposableArrows.map'_inv_eq_inv_map'
+CategoryTheory.ComposableArrows.naturality'
+CategoryTheory.ComposableArrows.Precomp.map_zero_one'
+CategoryTheory.composePath_comp'
+CategoryTheory.conj_eqToHom_iff_heq'
+CategoryTheory.CosimplicialObject.δ_comp_δ'
+CategoryTheory.CosimplicialObject.δ_comp_δ''
+CategoryTheory.CosimplicialObject.δ_comp_δ_self'
+CategoryTheory.CosimplicialObject.δ_comp_σ_of_gt'
+CategoryTheory.CosimplicialObject.δ_comp_σ_self'
+CategoryTheory.CosimplicialObject.δ_comp_σ_succ'
+CategoryTheory.DifferentialObject.eqToHom_f'
+CategoryTheory.e_assoc'
+CategoryTheory.Endofunctor.Algebra.Initial.left_inv'
+CategoryTheory.eq_of_comp_left_eq'
+CategoryTheory.eq_of_comp_right_eq'
+CategoryTheory.Equivalence.cancel_counitInv_right_assoc'
+CategoryTheory.Equivalence.cancel_unit_right_assoc'
+CategoryTheory.ExactPairing.coevaluation_evaluation''
+CategoryTheory.ExactPairing.evaluation_coevaluation''
+CategoryTheory.exists_zigzag'
+CategoryTheory.forgetEnrichment_id'
+CategoryTheory.Functor.commShiftIso_add'
+CategoryTheory.Functor.coreflective'
+CategoryTheory.Functor.HasRightDerivedFunctor.mk'
+CategoryTheory.Functor.inl_biprodComparison'
+CategoryTheory.Functor.inr_biprodComparison'
+CategoryTheory.Functor.isContinuous_comp'
+CategoryTheory.Functor.IsHomological.mk'
+CategoryTheory.Functor.IsLocalization.mk'
+CategoryTheory.Functor.Iteration.Hom.ext'
+CategoryTheory.Functor.map_comp_heq'
+CategoryTheory.Functor.postcomp_map_heq'
+CategoryTheory.Functor.reflective'
+CategoryTheory.Functor.relativelyRepresentable.map_fst'
+CategoryTheory.Functor.relativelyRepresentable.w'
+CategoryTheory.Functor.shiftIso_add'
+CategoryTheory.Functor.shiftMap_comp'
+CategoryTheory.FunctorToTypes.jointly_surjective'
+CategoryTheory.FunctorToTypes.prod_ext'
+CategoryTheory.Functor.uncurry_obj_curry_obj_flip_flip'
+CategoryTheory.Functor.ι_biproductComparison'
+CategoryTheory.Grothendieck.comp_fiber'
+CategoryTheory.Grothendieck.id_fiber'
+CategoryTheory.GrothendieckTopology.OneHypercoverFamily.IsSheafIff.fac'
+CategoryTheory.GrothendieckTopology.OneHypercover.mem_sieve₁'
+CategoryTheory.GrothendieckTopology.WEqualsLocallyBijective.mk'
+CategoryTheory.Grpd.str'
+CategoryTheory.HasPullbacksOfInclusions.hasPullbackInr'
+CategoryTheory.HasPullbacksOfInclusions.preservesPullbackInl'
+CategoryTheory.HasSheafify.mk'
+CategoryTheory.Injective.injective_iff_preservesEpimorphisms_preadditive_yoneda_obj'
+CategoryTheory.IsCoreflexivePair.mk'
+CategoryTheory.IsHomLift.fac'
+CategoryTheory.IsHomLift.of_fac'
+CategoryTheory.Iso.inv_ext'
+CategoryTheory.IsPullback.inl_snd'
+CategoryTheory.IsPullback.inr_fst'
+CategoryTheory.IsPullback.of_hasBinaryProduct'
+CategoryTheory.IsPullback.of_is_bilimit'
+CategoryTheory.IsPushout.inl_snd'
+CategoryTheory.IsPushout.inr_fst'
+CategoryTheory.IsPushout.of_hasBinaryCoproduct'
+CategoryTheory.IsPushout.of_is_bilimit'
+CategoryTheory.IsReflexivePair.mk'
+CategoryTheory.isSheaf_yoneda'
+CategoryTheory.LaxBraidedFunctor.ext'
+CategoryTheory.Limits.biprod.hom_ext'
+CategoryTheory.Limits.biprod.map_eq_map'
+CategoryTheory.Limits.biprod.symmetry'
+CategoryTheory.Limits.biproduct.hom_ext'
+CategoryTheory.Limits.biproduct.map_eq_map'
+CategoryTheory.Limits.Cofork.IsColimit.π_desc'
+CategoryTheory.Limits.colimit.pre_map'
+CategoryTheory.Limits.colimMap_epi'
+CategoryTheory.Limits.Concrete.widePullback_ext'
+CategoryTheory.Limits.Concrete.widePushout_exists_rep'
+CategoryTheory.Limits.coprod.symmetry'
+CategoryTheory.Limits.equalizerSubobject_arrow'
+CategoryTheory.Limits.Fork.IsLimit.lift_ι'
+CategoryTheory.Limits.ImageMap.mk.injEq'
+CategoryTheory.Limits.imageSubobject_arrow'
+CategoryTheory.Limits.kernelSubobject_arrow'
+CategoryTheory.Limits.limit.map_pre'
+CategoryTheory.Limits.limLax_obj'
+CategoryTheory.Limits.limMap_mono'
+CategoryTheory.Limits.MonoCoprod.mk'
+CategoryTheory.Limits.MonoCoprod.mono_binaryCofanSum_inl'
+CategoryTheory.Limits.MonoCoprod.mono_binaryCofanSum_inr'
+CategoryTheory.Limits.MonoCoprod.mono_of_injective'
+CategoryTheory.Limits.Multicoequalizer.multicofork_ι_app_right'
+CategoryTheory.Limits.Multicofork.ofSigmaCofork_ι_app_right'
+CategoryTheory.Limits.parallelPair_initial_mk'
+CategoryTheory.Limits.Pi.map'_comp_map'
+CategoryTheory.Limits.Pi.map_comp_map'
+CategoryTheory.Limits.prod.symmetry'
+CategoryTheory.Limits.Sigma.map'_comp_map'
+CategoryTheory.Limits.Sigma.map_comp_map'
+CategoryTheory.Limits.Sigma.ι_comp_map'
+CategoryTheory.Limits.Types.Colimit.w_apply'
+CategoryTheory.Limits.Types.Colimit.ι_desc_apply'
+CategoryTheory.Limits.Types.Colimit.ι_map_apply'
+CategoryTheory.Limits.Types.limit_ext'
+CategoryTheory.Limits.Types.limit_ext_iff'
+CategoryTheory.Limits.Types.Limit.lift_π_apply'
+CategoryTheory.Limits.Types.Limit.map_π_apply'
+CategoryTheory.Limits.Types.Limit.w_apply'
+CategoryTheory.Limits.Types.Pushout.equivalence_rel'
+CategoryTheory.Limits.WalkingParallelPairHom.id.sizeOf_spec'
+CategoryTheory.Limits.zero_of_source_iso_zero'
+CategoryTheory.Limits.zero_of_target_iso_zero'
+CategoryTheory.Localization.Preadditive.comp_add'
+CategoryTheory.Localization.Preadditive.zero_add'
+CategoryTheory.Localization.SmallShiftedHom.equiv_shift'
+CategoryTheory.LocalizerMorphism.guitartExact_of_isRightDerivabilityStructure'
+CategoryTheory.LocalizerMorphism.IsLocalizedEquivalence.mk'
+CategoryTheory.Mat_.additiveObjIsoBiproduct_naturality'
+CategoryTheory.Monad.Algebra.Hom.ext'
+CategoryTheory.MonadHom.ext'
+CategoryTheory.MonoidalCategory.hom_inv_id_tensor'
+CategoryTheory.MonoidalCategory.hom_inv_whiskerRight'
+CategoryTheory.MonoidalCategory.inv_hom_id_tensor'
+CategoryTheory.MonoidalCategory.inv_hom_whiskerRight'
+CategoryTheory.MonoidalCategory.leftUnitor_tensor'
+CategoryTheory.MonoidalCategory.leftUnitor_tensor''
+CategoryTheory.MonoidalCategory.leftUnitor_tensor_inv'
+CategoryTheory.MonoidalCategory.tensorHom_def'
+CategoryTheory.MonoidalCategory.tensor_hom_inv_id'
+CategoryTheory.MonoidalCategory.tensor_inv_hom_id'
+CategoryTheory.MonoidalCategory.tensorIso_def'
+CategoryTheory.MonoidalCategory.whiskerLeft_hom_inv'
+CategoryTheory.MonoidalCategory.whiskerLeft_inv_hom'
+CategoryTheory.MonoidalCoherence.assoc'
+CategoryTheory.MonoidalCoherence.left'
+CategoryTheory.MonoidalCoherence.right'
+CategoryTheory.MonoidalCoherence.tensor_right'
+CategoryTheory.MonoidalNatTrans.ext'
+CategoryTheory.MonoOver.mk'_coe'
+CategoryTheory.NatIso.naturality_1'
+CategoryTheory.NatIso.naturality_2'
+CategoryTheory.NatTrans.ext'
+CategoryTheory.NatTrans.id_app'
+CategoryTheory.NatTrans.vcomp_app'
+CategoryTheory.NonPreadditiveAbelian.neg_sub'
+CategoryTheory.OplaxNatTrans.Modification.comp_app'
+CategoryTheory.OplaxNatTrans.Modification.id_app'
+CategoryTheory.Preadditive.epi_iff_surjective'
+CategoryTheory.Preadditive.epi_of_isZero_cokernel'
+CategoryTheory.Preadditive.mono_iff_injective'
+CategoryTheory.Preadditive.mono_of_isZero_kernel'
+CategoryTheory.Prefunctor.mapPath_comp'
+CategoryTheory.PreOneHypercover.sieve₁_eq_pullback_sieve₁'
+CategoryTheory.PreservesPullbacksOfInclusions.preservesPullbackInl'
+CategoryTheory.PreservesPullbacksOfInclusions.preservesPullbackInr'
+CategoryTheory.Presheaf.isLocallyInjective_toSheafify'
+CategoryTheory.Presheaf.isLocallySurjective_iff_imagePresheaf_sheafify_eq_top'
+CategoryTheory.Presheaf.isLocallySurjective_toSheafify'
+CategoryTheory.Pretriangulated.mem_distTriang_op_iff'
+CategoryTheory.Pretriangulated.Opposite.mem_distinguishedTriangles_iff'
+CategoryTheory.Projective.projective_iff_preservesEpimorphisms_preadditiveCoyoneda_obj'
+CategoryTheory.ProjectiveResolution.pOpcycles_comp_fromLeftDerivedZero'
+CategoryTheory.Quiv.str'
+CategoryTheory.Quotient.lift_unique'
+CategoryTheory.RanIsSheafOfIsCocontinuous.fac'
+CategoryTheory.RanIsSheafOfIsCocontinuous.liftAux_map'
+CategoryTheory.regularTopology.equalizerCondition_w'
+CategoryTheory.Sheaf.epi_of_isLocallySurjective'
+CategoryTheory.Sheaf.isLocallySurjective_iff_epi'
+CategoryTheory.SheafOfTypes.Hom.ext'
+CategoryTheory.shift_neg_shift'
+CategoryTheory.shift_shift'
+CategoryTheory.shift_shift_neg'
+CategoryTheory.shiftZero'
+CategoryTheory.ShortComplex.abLeftHomologyData_f'
+CategoryTheory.ShortComplex.epi_homologyMap_of_epi_cyclesMap'
+CategoryTheory.ShortComplex.Exact.desc'
+CategoryTheory.ShortComplex.Exact.epi_f'
+CategoryTheory.ShortComplex.exact_iff_epi_imageToKernel'
+CategoryTheory.ShortComplex.Exact.isIso_f'
+CategoryTheory.ShortComplex.Exact.isIso_g'
+CategoryTheory.ShortComplex.Exact.lift'
+CategoryTheory.ShortComplex.Exact.mono_g'
+CategoryTheory.ShortComplex.f'_cyclesMap'
+CategoryTheory.ShortComplex.HasHomology.mk'
+CategoryTheory.ShortComplex.hasHomology_of_epi_of_isIso_of_mono'
+CategoryTheory.ShortComplex.hasHomology_of_isIso_leftRightHomologyComparison'
+CategoryTheory.ShortComplex.hasHomology_of_preserves'
+CategoryTheory.ShortComplex.HasLeftHomology.mk'
+CategoryTheory.ShortComplex.hasLeftHomology_of_epi_of_isIso_of_mono'
+CategoryTheory.ShortComplex.hasLeftHomology_of_preserves'
+CategoryTheory.ShortComplex.HasRightHomology.mk'
+CategoryTheory.ShortComplex.hasRightHomology_of_epi_of_isIso_of_mono'
+CategoryTheory.ShortComplex.hasRightHomology_of_preserves'
+CategoryTheory.ShortComplex.HomologyData.exact_iff'
+CategoryTheory.ShortComplex.HomologyData.map_homologyMap'
+CategoryTheory.ShortComplex.isIso₂_of_shortExact_of_isIso₁₃'
+CategoryTheory.ShortComplex.isIso_cyclesMap_of_isIso_of_mono'
+CategoryTheory.ShortComplex.isIso_homologyMap_of_epi_of_isIso_of_mono'
+CategoryTheory.ShortComplex.isIso_leftRightHomologyComparison'
+CategoryTheory.ShortComplex.isIso_opcyclesMap_of_isIso_of_epi'
+CategoryTheory.ShortComplex.LeftHomologyData.exact_iff_epi_f'
+CategoryTheory.ShortComplex.LeftHomologyData.map_cyclesMap'
+CategoryTheory.ShortComplex.LeftHomologyData.map_f'
+CategoryTheory.ShortComplex.LeftHomologyData.map_leftHomologyMap'
+CategoryTheory.ShortComplex.LeftHomologyData.ofEpiOfIsIsoOfMono'_f'
+CategoryTheory.ShortComplex.LeftHomologyData.ofIsColimitCokernelCofork_f'
+CategoryTheory.ShortComplex.LeftHomologyData.ofIsLimitKernelFork_f'
+CategoryTheory.ShortComplex.LeftHomologyData.ofZeros_f'
+CategoryTheory.ShortComplex.LeftHomologyData.op_g'
+CategoryTheory.ShortComplex.LeftHomologyData.unop_g'
+CategoryTheory.ShortComplex.LeftHomologyData.τ₁_ofEpiOfIsIsoOfMono_f'
+CategoryTheory.ShortComplex.leftHomologyπ_naturality'
+CategoryTheory.ShortComplex.leftRightHomologyComparison'_eq_leftHomologpMap'_comp_iso_hom_comp_rightHomologyMap'
+CategoryTheory.ShortComplex.moduleCatLeftHomologyData_f'
+CategoryTheory.ShortComplex.mono_homologyMap_of_mono_opcyclesMap'
+CategoryTheory.ShortComplex.opcyclesMap'_g'
+CategoryTheory.ShortComplex.p_opcyclesMap'
+CategoryTheory.ShortComplex.quasiIso_iff_isIso_homologyMap'
+CategoryTheory.ShortComplex.quasiIso_iff_isIso_leftHomologyMap'
+CategoryTheory.ShortComplex.quasiIso_iff_isIso_rightHomologyMap'
+CategoryTheory.ShortComplex.RightHomologyData.exact_iff_mono_g'
+CategoryTheory.ShortComplex.RightHomologyData.map_g'
+CategoryTheory.ShortComplex.RightHomologyData.map_opcyclesMap'
+CategoryTheory.ShortComplex.RightHomologyData.map_rightHomologyMap'
+CategoryTheory.ShortComplex.RightHomologyData.ofEpiOfIsIsoOfMono_g'
+CategoryTheory.ShortComplex.RightHomologyData.ofIsColimitCokernelCofork_g'
+CategoryTheory.ShortComplex.RightHomologyData.ofIsLimitKernelFork_g'
+CategoryTheory.ShortComplex.RightHomologyData.ofZeros_g'
+CategoryTheory.ShortComplex.RightHomologyData.op_f'
+CategoryTheory.ShortComplex.RightHomologyData.p_g'
+CategoryTheory.ShortComplex.RightHomologyData.unop_f'
+CategoryTheory.ShortComplex.RightHomologyData.ι_g'
+CategoryTheory.ShortComplex.rightHomologyι_naturality'
+CategoryTheory.ShortComplex.ShortExact.mk'
+CategoryTheory.ShortComplex.ShortExact.δ_apply'
+CategoryTheory.ShortComplex.ShortExact.δ_eq'
+CategoryTheory.SimplicialObject.δ_comp_δ'
+CategoryTheory.SimplicialObject.δ_comp_δ''
+CategoryTheory.SimplicialObject.δ_comp_δ_self'
+CategoryTheory.SimplicialObject.δ_comp_σ_of_gt'
+CategoryTheory.SimplicialObject.δ_comp_σ_self'
+CategoryTheory.SimplicialObject.δ_comp_σ_succ'
+CategoryTheory.SingleFunctors.shiftIso_add'
+CategoryTheory.StrongEpi.mk'
+CategoryTheory.StrongMono.mk'
+CategoryTheory.Subgroupoid.coe_inv_coe'
+CategoryTheory.Subgroupoid.IsNormal.conj'
+CategoryTheory.Subobject.inf_eq_map_pullback'
+CategoryTheory.Tor'_map_app'
+CategoryTheory.Triangulated.Subcategory.ext₁'
+CategoryTheory.Triangulated.Subcategory.ext₃'
+CategoryTheory.Triangulated.Subcategory.W_iff'
+CategoryTheory.Triangulated.Subcategory.W.mk'
+CategoryTheory.TwoSquare.GuitartExact.vComp'
+CategoryTheory.whiskerLeft_id'
+CategoryTheory.whiskerRight_id'
+CategoryTheory.yonedaEquiv_naturality'
+Cauchy.comap'
+CauchyFilter.mem_uniformity'
+cauchy_iff'
+cauchy_iInf_uniformSpace'
+cauchy_map_iff'
+Cauchy.mono'
+cauchy_pi_iff'
+cauchySeq_iff'
+CauSeq.bounded'
+CauSeq.mul_equiv_zero'
+cfc_comp'
+cfcₙ_comp'
+CharP.exists'
+CharP.natCast_eq_natCast'
+charP_of_injective_algebraMap'
+CharP.pi'
+CharP.subring'
+ChartedSpaceCore.open_source'
+CharTwo.neg_eq'
+CharTwo.sub_eq_add'
+ciInf_le'
+ciInf_le_of_le'
+ciInf_subtype'
+ciInf_subtype''
+CircleDeg1Lift.tendsto_translation_number'
+CircleDeg1Lift.tendsto_translation_number₀'
+CircleDeg1Lift.translationNumber_conj_eq'
+CircleDeg1Lift.translationNumber_eq_of_tendsto₀'
+circleIntegral.norm_integral_le_of_norm_le_const'
+circleMap_mem_sphere'
+ciSup_le'
+ciSup_le_iff'
+ciSup_mono'
+ciSup_or'
+ciSup_subtype'
+ciSup_subtype''
+Classical.choose_eq'
+CliffordAlgebra.instAlgebra'
+CliffordAlgebra.star_def'
+ClosedIciTopology.isClosed_ge'
+ClosedIicTopology.isClosed_le'
+closedUnderRestriction'
+closure_smul₀'
+clusterPt_iff_lift'_closure'
+ClusterPt.of_le_nhds'
+cmp_div_one'
+cmp_mul_left'
+cmp_mul_right'
+CochainComplex.HomComplex.Cochain.shift_v'
+CochainComplex.mappingCone.d_fst_v'
+CochainComplex.mappingCone.d_snd_v'
+CochainComplex.shiftFunctorAdd'_hom_app_f'
+CochainComplex.shiftFunctorAdd'_inv_app_f'
+CochainComplex.shiftFunctor_map_f'
+CochainComplex.shiftFunctor_obj_d'
+CochainComplex.shiftFunctor_obj_X'
+Codisjoint.ne_bot_of_ne_top'
+Codisjoint.of_codisjoint_sup_of_le'
+Codisjoint.sup_left'
+Codisjoint.sup_right'
+coe_comp_nnnorm'
+coe_nnnorm'
+CofiniteTopology.isOpen_iff'
+comap_norm_atTop'
+comap_norm_nhdsWithin_Ioi_zero'
+CommGrp.coe_comp'
+CommGrp.coe_id'
+CommMon_.comp'
+CommMon_.id'
+commProb_def'
+CommRingCat.equalizer_ι_is_local_ring_hom'
+CommRingCat.instCommRing'
+CommRingCat.instFunLike'
+CommRingCat.instFunLike''
+CommRingCat.instFunLike'''
+CommSemiRingCat.instCommSemiring'
+Commute.mul_self_sub_mul_self_eq'
+Comon_.comp_hom'
+Comon_.id_hom'
+CompactIccSpace.mk'
+CompactIccSpace.mk''
+CompHaus.toProfinite_obj'
+compl_beattySeq'
+CompleteLattice.Independent.comp'
+CompleteLattice.independent_def'
+CompleteLattice.independent_def''
+CompleteLattice.independent_of_dfinsupp_sumAddHom_injective'
+CompleteLattice.Independent.supIndep'
+CompleteLattice.inf_continuous'
+CompleteLattice.sSup_continuous'
+CompletelyDistribLattice.MinimalAxioms.iInf_iSup_eq'
+CompleteOrthogonalIdempotents.bijective_pi'
+CompleteSublattice.coe_sInf'
+CompleteSublattice.coe_sSup'
+Complex.abs_eq_one_iff'
+Complex.AbsTheory.abs_nonneg'
+Complex.affine_of_mapsTo_ball_of_exists_norm_dslope_eq_div'
+Complex.conj_mul'
+Complex.cos_eq_tsum'
+Complex.cos_sq'
+Complex.cos_two_mul'
+Complex.cpow_ofNat_mul'
+Complex.deriv_cos'
+Complex.equivRealProd_apply_le'
+Complex.exp_bound'
+Complex.hasStrictFDerivAt_cpow'
+Complex.hasSum_conj'
+Complex.hasSum_cos'
+Complex.hasSum_sin'
+Complex.mul_conj'
+Complex.ofReal_mul'
+Complex.rank_real_complex'
+Complex.restrictScalars_one_smulRight'
+ComplexShape.Embedding.not_boundaryGE_next'
+ComplexShape.Embedding.not_boundaryLE_prev'
+ComplexShape.next_add'
+ComplexShape.next_eq'
+ComplexShape.next_eq_self'
+ComplexShape.prev_eq'
+ComplexShape.prev_eq_self'
+Complex.sin_eq_tsum'
+Complex.stolzCone_subset_stolzSet_aux'
+Complex.tan_add'
+Complex.UnitDisc.instSMulCommClass_circle'
+Complex.UnitDisc.instSMulCommClass_closedBall'
+compl_sInf'
+compl_sSup'
+CompositionAsSet.lt_length'
+Composition.blocks_pos'
+Composition.mem_range_embedding_iff'
+Composition.one_le_blocks'
+Composition.sizeUpTo_succ'
+Computability.inhabitedΓ'
+ComputablePred.computable_iff_re_compl_re'
+Computable.vector_ofFn'
+Computation.bind_pure'
+Computation.eq_thinkN'
+Computation.map_pure'
+Computation.map_think'
+Computation.results_of_terminates'
+ConcaveOn.left_le_of_le_right'
+ConcaveOn.left_le_of_le_right''
+ConcaveOn.left_lt_of_lt_right'
+ConcaveOn.lt_right_of_left_lt'
+ConcaveOn.mul'
+ConcaveOn.mul_convexOn'
+ConcaveOn.right_le_of_le_left'
+ConcaveOn.right_le_of_le_left''
+ConcaveOn.smul'
+ConcaveOn.smul''
+ConcaveOn.smul_convexOn'
+Concept.ext'
+Con.coe_mk'
+conformalFactorAt_inner_eq_mul_inner'
+CongruenceSubgroup.Gamma1_mem'
+CongruenceSubgroup.Gamma_mem'
+ConjAct.smulCommClass'
+ConjAct.smulCommClass₀'
+ConjAct.unitsSMulCommClass'
+conjneg_neg'
+conjugate_le_conjugate'
+conjugate_lt_conjugate'
+conjugate_nonneg'
+conjugate_pos'
+Con.mrange_mk'
+ConnectedComponents.coe_eq_coe'
+connectedComponents_lift_unique'
+ContDiffAt.comp'
+contDiffAt_id'
+contDiffAt_pi'
+contDiffAt_prod'
+ContDiff.comp'
+contDiff_id'
+ContDiff.iterate_deriv'
+ContDiffOn.div'
+contDiffOn_id'
+contDiffOn_pi'
+contDiffOn_prod'
+contDiff_pi'
+contDiff_prod'
+ContDiffWithinAt.congr'
+ContDiffWithinAt.congr_of_eventually_eq'
+ContDiffWithinAt.contDiffOn'
+contDiffWithinAt_inter'
+contDiffWithinAt_prod'
+ContinuousAlgHom.coe_comp'
+ContinuousAlgHom.coe_fst'
+ContinuousAlgHom.coe_id'
+ContinuousAlgHom.coe_mk'
+ContinuousAlgHom.coe_prodMap'
+ContinuousAlgHom.coe_restrictScalars'
+ContinuousAlgHom.coe_snd'
+ContinuousAt.comp'
+continuousAt_const_cpow'
+ContinuousAt.div'
+continuousAt_extChartAt'
+continuousAt_extChartAt_symm'
+continuousAt_extChartAt_symm''
+ContinuousAt.finset_inf'
+ContinuousAt.finset_sup'
+continuousAt_id'
+continuousAt_iff_continuous_left'_right'
+ContinuousAt.inf'
+continuousAt_jacobiTheta₂'
+ContinuousAt.nnnorm'
+ContinuousAt.norm'
+continuousAt_pi'
+ContinuousAt.prod_map'
+ContinuousAt.sup'
+Continuous.comp'
+Continuous.comp_continuousOn'
+Continuous.div'
+continuous_div_left'
+continuous_div_right'
+Continuous.finset_inf'
+Continuous.finset_sup'
+continuous_id'
+continuous_if'
+Continuous.inf'
+ContinuousLinearEquiv.coe_refl'
+ContinuousLinearEquiv.comp_hasFDerivAt_iff'
+ContinuousLinearEquiv.comp_hasFDerivWithinAt_iff'
+ContinuousLinearEquiv.comp_right_hasFDerivAt_iff'
+ContinuousLinearEquiv.comp_right_hasFDerivWithinAt_iff'
+ContinuousLinearMap.apply_apply'
+ContinuousLinearMap.applySMulCommClass'
+ContinuousLinearMap.coe_add'
+ContinuousLinearMap.coe_comp'
+ContinuousLinearMap.coe_flipₗᵢ'
+ContinuousLinearMap.coeFn_compLp'
+ContinuousLinearMap.coe_fst'
+ContinuousLinearMap.coe_id'
+ContinuousLinearMap.coe_mk'
+ContinuousLinearMap.coe_neg'
+ContinuousLinearMap.coe_pi'
+ContinuousLinearMap.coe_prodMap'
+ContinuousLinearMap.coe_restrictScalars'
+ContinuousLinearMap.coe_restrict_scalarsL'
+ContinuousLinearMap.coe_smul'
+ContinuousLinearMap.coe_snd'
+ContinuousLinearMap.coe_sub'
+ContinuousLinearMap.coe_sum'
+ContinuousLinearMap.coe_zero'
+ContinuousLinearMap.compFormalMultilinearSeries_apply'
+ContinuousLinearMap.comp_memℒp'
+ContinuousLinearMap.integral_comp_comm'
+ContinuousLinearMap.measurable_apply'
+ContinuousLinearMap.mul_apply'
+ContinuousLinearMap.norm_extendTo𝕜'
+ContinuousLinearMap.opNorm_le_of_shell'
+ContinuousLinearMap.sub_apply'
+ContinuousLinearMap.toSpanSingleton_smul'
+ContinuousMap.coe_const'
+ContinuousMap.coe_inf'
+ContinuousMap.coe_sup'
+ContinuousMap.comp_yonedaPresheaf'
+ContinuousMap.continuous.comp'
+ContinuousMap.continuous_const'
+ContinuousMap.instSMul'
+ContinuousMap.liftCover_coe'
+ContinuousMap.liftCover_restrict'
+ContinuousMap.module'
+ContinuousMap.unitsLift_symm_apply_apply_inv'
+ContinuousMapZero.instIsScalarTower'
+ContinuousMapZero.instSMulCommClass'
+Continuous.matrix_blockDiag'
+Continuous.matrix_blockDiagonal'
+continuousMultilinearCurryRightEquiv_apply'
+continuousMultilinearCurryRightEquiv_symm_apply'
+continuous_nnnorm'
+Continuous.nnnorm'
+continuous_norm'
+Continuous.norm'
+ContinuousOn.circleIntegrable'
+ContinuousOn.comp'
+ContinuousOn.comp''
+ContinuousOn.div'
+ContinuousOn.finset_inf'
+ContinuousOn.finset_sup'
+continuousOn_id'
+ContinuousOn.if'
+continuousOn_iff'
+ContinuousOn.inf'
+ContinuousOn.nnnorm'
+ContinuousOn.norm'
+continuousOn_pi'
+ContinuousOn.piecewise'
+continuousOn_piecewise_ite'
+ContinuousOn.sup'
+Continuous.quotient_liftOn'
+Continuous.quotient_map'
+continuous_quotient_mk'
+Continuous.strictMono_of_inj_boundedOrder'
+Continuous.sup'
+ContinuousWithinAt.comp'
+ContinuousWithinAt.div'
+ContinuousWithinAt.finset_inf'
+ContinuousWithinAt.finset_sup'
+ContinuousWithinAt.inf'
+continuousWithinAt_inter'
+ContinuousWithinAt.nnnorm'
+ContinuousWithinAt.norm'
+ContinuousWithinAt.preimage_mem_nhdsWithin'
+ContinuousWithinAt.preimage_mem_nhdsWithin''
+ContinuousWithinAt.sup'
+contMDiffAt_extChartAt'
+contMDiffAt_finset_prod'
+ContMDiffAt.prod_map'
+contMDiff_finset_prod'
+ContMDiffMap.mdifferentiable'
+contMDiffOn_finset_prod'
+contMDiffOn_iff_of_mem_maximalAtlas'
+ContMDiffSection.mdifferentiable'
+contMDiffWithinAt_finset_prod'
+contMDiffWithinAt_iff_of_mem_source'
+contMDiffWithinAt_inter'
+ContractingWith.apriori_edist_iterate_efixedPoint_le'
+ContractingWith.edist_efixedPoint_le'
+ContractingWith.edist_efixedPoint_lt_top'
+ContractingWith.efixedPoint_isFixedPt'
+ContractingWith.efixedPoint_mem'
+ContractingWith.fixedPoint_unique'
+ContractingWith.one_sub_K_pos'
+ContractingWith.tendsto_iterate_efixedPoint'
+ConvexBody.coe_smul'
+Convex.mem_toCone'
+ConvexOn.le_left_of_right_le'
+ConvexOn.le_left_of_right_le''
+ConvexOn.le_right_of_left_le'
+ConvexOn.le_right_of_left_le''
+ConvexOn.lt_left_of_right_lt'
+ConvexOn.lt_right_of_left_lt'
+ConvexOn.mul'
+ConvexOn.mul_concaveOn'
+ConvexOn.smul'
+ConvexOn.smul''
+ConvexOn.smul_concaveOn'
+coord_norm'
+CovBy.ne'
+CoxeterSystem.alternatingWord_succ'
+CoxeterSystem.exists_reduced_word'
+CoxeterSystem.length_mul_ge_length_sub_length'
+CoxeterSystem.simple_mul_simple_pow'
+CPolynomialOn.congr'
+CPolynomialOn_congr'
+cpow_eq_nhds'
+cross_anticomm'
+csInf_le'
+csInf_le_csInf'
+csSup_le'
+csSup_le_csSup'
+csSup_le_iff'
+CStarAlgebra.conjugate_le_norm_smul'
+CStarAlgebra.instNonnegSpectrumClass'
+CStarRing.conjugate_le_norm_smul'
+CStarRing.instNonnegSpectrumClass'
+CStarRing.norm_star_mul_self'
+Ctop.Realizer.ext'
+Cubic.degree_of_a_eq_zero'
+Cubic.degree_of_a_ne_zero'
+Cubic.degree_of_b_eq_zero'
+Cubic.degree_of_b_ne_zero'
+Cubic.degree_of_c_eq_zero'
+Cubic.degree_of_c_ne_zero'
+Cubic.degree_of_d_eq_zero'
+Cubic.degree_of_d_ne_zero'
+Cubic.leadingCoeff_of_a_ne_zero'
+Cubic.leadingCoeff_of_b_ne_zero'
+Cubic.leadingCoeff_of_c_eq_zero'
+Cubic.leadingCoeff_of_c_ne_zero'
+Cubic.monic_of_a_eq_one'
+Cubic.monic_of_b_eq_one'
+Cubic.monic_of_c_eq_one'
+Cubic.monic_of_d_eq_one'
+Cubic.natDegree_of_a_eq_zero'
+Cubic.natDegree_of_a_ne_zero'
+Cubic.natDegree_of_b_eq_zero'
+Cubic.natDegree_of_b_ne_zero'
+Cubic.natDegree_of_c_eq_zero'
+Cubic.natDegree_of_c_ne_zero'
+Cubic.of_a_eq_zero'
+Cubic.of_b_eq_zero'
+Cubic.of_c_eq_zero'
+Cubic.of_d_eq_zero'
+Cycle.next_reverse_eq_prev'
+Cycle.prev_reverse_eq_next'
+CyclotomicField.algebra'
+dec_em'
+Decidable.mul_lt_mul''
+Decidable.Partrec.const'
+decide_False'
+decide_True'
+DedekindDomain.ProdAdicCompletions.algebra'
+DedekindDomain.ProdAdicCompletions.algebraMap_apply'
+DedekindDomain.ProdAdicCompletions.IsFiniteAdele.algebraMap'
+IsDenseEmbedding.mk'
+Dense.exists_ge'
+Dense.exists_le'
+IsDenseInducing.extend_eq_at'
+IsDenseInducing.mk'
+Denumerable.lower_raise'
+Denumerable.raise_lower'
+deriv_add_const'
+Derivation.apply_aeval_eq'
+Derivation.coe_mk'
+deriv_const'
+deriv_const_add'
+deriv_const_mul_field'
+deriv_id'
+deriv_id''
+deriv_inv'
+deriv_inv''
+deriv_mul_const_field'
+deriv.neg'
+deriv_neg'
+deriv_neg''
+deriv_pow'
+deriv_pow''
+deriv_sqrt_mul_log'
+deriv.star'
+derivWithin_congr_set'
+derivWithin_inv'
+derivWithin_pow'
+deriv_zpow'
+det_traceMatrix_ne_zero'
+DFinsupp.coe_mk'
+DFinsupp.filter_ne_eq_erase'
+DFinsupp.le_iff'
+DFinsupp.Lex.wellFounded'
+DFinsupp.wellFoundedLT'
+DFunLike.ext'
+DiffContOnCl.differentiableAt'
+Diffeomorph.symm_trans'
+DifferentiableAt.comp'
+differentiableAt_id'
+differentiableAt_inv'
+DifferentiableAt.inv'
+differentiableAt_pi''
+Differentiable.comp'
+differentiable_id'
+Differentiable.inv'
+DifferentiableOn.comp'
+differentiableOn_id'
+differentiableOn_inv'
+DifferentiableOn.inv'
+differentiableOn_pi''
+differentiable_pi''
+DifferentiableWithinAt.comp'
+differentiableWithinAt_congr_set'
+differentiableWithinAt_inter'
+differentiableWithinAt_inv'
+DifferentiableWithinAt.inv'
+differentiableWithinAt_pi''
+DirectedOn.mono'
+directedOn_pair'
+DirectSum.Gmodule.mul_smul'
+DirectSum.Gmodule.one_smul'
+DirichletCharacter.level_one'
+DirichletCharacter.toUnitHom_eq_char'
+discreteTopology_iff_orderTopology_of_pred_succ'
+DiscreteTopology.of_forall_le_norm'
+DiscreteTopology.orderTopology_of_pred_succ'
+DiscreteValuationRing.addVal_def'
+Disjoint.inf_left'
+Disjoint.inf_right'
+Disjoint.inter_left'
+Disjoint.inter_right'
+Disjoint.of_disjoint_inf_of_le'
+dist_eq_norm_div'
+dist_le_norm_add_norm'
+dist_midpoint_midpoint_le'
+dist_norm_norm_le'
+dist_partial_sum'
+dist_pi_le_iff'
+DistribMulActionHom.coe_fn_coe'
+dite_eq_iff'
+div_add'
+div_div_cancel'
+div_div_cancel_left'
+div_div_div_cancel_left'
+div_div_self'
+div_eq_iff_eq_mul'
+div_eq_of_eq_mul'
+div_eq_of_eq_mul''
+div_le_div''
+div_le_div_iff'
+div_le_div_left'
+div_le_div_right'
+div_left_inj'
+div_le_iff₀'
+div_le_iff_le_mul'
+div_le_iff_of_neg'
+div_le_one'
+div_lt_div'
+div_lt_div''
+div_lt_div_iff'
+div_lt_div_left'
+div_lt_div_right'
+div_lt_iff'
+div_lt_iff_lt_mul'
+div_lt_iff_of_neg'
+div_lt_one'
+div_mul_div_cancel'
+div_mul_div_cancel₀'
+div_self'
+div_self_mul_self'
+div_sub'
+Doset.disjoint_out'
+Doset.out_eq'
+DoubleCentralizer.nnnorm_def'
+DoubleCentralizer.norm_def'
+dvd_antisymm'
+dvd_geom_sum₂_iff_of_dvd_sub'
+edist_eq_coe_nnnorm'
+EllipticCurve.coe_inv_map_Δ'
+EllipticCurve.coe_inv_variableChange_Δ'
+EllipticCurve.coe_map_Δ'
+EllipticCurve.coe_variableChange_Δ'
+em'
+IsEmbedding.mk'
+EMetric.diam_pos_iff'
+EMetric.diam_union'
+EMetric.mem_ball'
+EMetric.mem_closedBall'
+EMetric.totallyBounded_iff'
+ENat.sSup_eq_zero'
+Encodable.mem_decode₂'
+ENNReal.add_biSup'
+ENNReal.biSup_add'
+ENNReal.biSup_add_biSup_le'
+ENNReal.div_le_iff'
+ENNReal.div_le_of_le_mul'
+ENNReal.div_lt_of_lt_mul'
+ENNReal.exists_frequently_lt_of_liminf_ne_top'
+ENNReal.exists_pos_sum_of_countable'
+ENNReal.iInf_mul_left'
+ENNReal.iInf_mul_right'
+ENNReal.inv_le_inv'
+ENNReal.inv_lt_inv'
+ENNReal.log_pos_real'
+ENNReal.mul_div_cancel'
+ENNReal.mul_le_of_le_div'
+ENNReal.mul_lt_mul_left'
+ENNReal.mul_lt_mul_right'
+ENNReal.mul_lt_of_lt_div'
+ENNReal.mul_top'
+ENNReal.nhds_top'
+ENNReal.ofReal_le_ofReal_iff'
+ENNReal.ofReal_lt_ofReal_iff'
+ENNReal.ofReal_mul'
+ENNReal.range_coe'
+ENNReal.some_eq_coe'
+ENNReal.toNNReal_eq_toNNReal_iff'
+ENNReal.top_mul'
+ENNReal.toReal_eq_toReal_iff'
+ENNReal.toReal_mono'
+ENNReal.toReal_ofReal'
+ENNReal.tsum_eq_iSup_nat'
+ENNReal.tsum_eq_iSup_sum'
+ENNReal.tsum_prod'
+ENNReal.tsum_sigma'
+Eq.cmp_eq_eq'
+eq_div_iff_mul_eq'
+eq_div_iff_mul_eq''
+eq_div_of_mul_eq'
+eq_div_of_mul_eq''
+eq_intCast'
+eq_mul_of_div_eq'
+eq_natCast'
+eq_of_forall_dvd'
+eq_of_prime_pow_eq'
+eqOn_closure₂'
+eq_one_of_inv_eq'
+eq_one_of_mul_left'
+eq_one_of_mul_right'
+eqRec_heq'
+Equiv.bijOn'
+Equiv.coe_piCongr'
+Equiv.exists_congr'
+Equiv.existsUnique_congr'
+Equiv.forall₂_congr'
+Equiv.forall₃_congr'
+Equiv.forall_congr'
+Equiv.inhabited'
+Equiv.lawfulFunctor'
+Equiv.left_inv'
+Equiv.Perm.cycleType_eq'
+Equiv.Perm.exists_fixed_point_of_prime'
+Equiv.Perm.isCycle_of_prime_order'
+Equiv.Perm.isCycle_of_prime_order''
+Equiv.Perm.IsCycleOn.exists_pow_eq'
+Equiv.Perm.IsCycle.pow_eq_one_iff'
+Equiv.Perm.IsCycle.pow_eq_one_iff''
+Equiv.Perm.mem_support_cycleOf_iff'
+Equiv.Perm.prod_comp'
+Equiv.Perm.SameCycle.exists_pow_eq'
+Equiv.Perm.SameCycle.exists_pow_eq''
+Equiv.Perm.signAux_swap_zero_one'
+Equiv.Perm.sign_of_cycleType'
+Equiv.Perm.sign_swap'
+Equiv.right_inv'
+EReal.add_lt_add_of_lt_of_le'
+EReal.coe_neg'
+EReal.nhds_bot'
+EReal.nhds_top'
+EReal.sign_mul_inv_abs'
+essInf_const'
+essSup_const'
+essSup_mono_measure'
+estimator'
+EuclideanDomain.div_add_mod'
+EuclideanDomain.mod_add_div'
+EuclideanDomain.mul_div_cancel'
+EuclideanGeometry.center_eq_inversion'
+EuclideanGeometry.dist_center_eq_dist_center_of_mem_sphere'
+EuclideanGeometry.inversion_dist_center'
+EuclideanGeometry.inversion_eq_center'
+EuclideanGeometry.mem_sphere'
+EuclideanGeometry.Sphere.mem_coe'
+eventually_cobounded_le_norm'
+exists_apply_eq_apply'
+exists_apply_eq_apply2'
+exists_apply_eq_apply3'
+exists_associated_pow_of_mul_eq_pow'
+exists_Ico_subset_of_mem_nhds'
+exists_increasing_or_nonincreasing_subseq'
+exists_Ioc_subset_of_mem_nhds'
+exists_lt_of_lt_ciSup'
+exists_lt_of_lt_csSup'
+exists_maximal_independent'
+exists_one_lt'
+exists_one_lt_mul_of_lt'
+exists_reduced_fraction'
+exists_seq_strictAnti_tendsto'
+exists_seq_strictMono_tendsto'
+exists_square_le'
+exists_sum_eq_one_iff_pairwise_coprime'
+exists_unique_eq'
+existsUnique_zpow_near_of_one_lt'
+extChartAt_preimage_mem_nhds'
+extChartAt_source_mem_nhds'
+extChartAt_source_mem_nhdsWithin'
+extChartAt_target_mem_nhdsWithin'
+ext_nat'
+fderiv_continuousLinearEquiv_comp'
+fderiv_id'
+fderiv_list_prod'
+fderiv_mul'
+fderiv_mul_const'
+fderivWithin_congr'
+fderivWithin_congr_set'
+fderivWithin_eventually_congr_set'
+fderivWithin_id'
+fderivWithin_list_prod'
+fderivWithin_mul'
+fderivWithin_mul_const'
+FDRep.char_tensor'
+FermatLastTheoremWith.fermatLastTheoremWith'
+FiberBundleCore.open_source'
+Field.finInsepDegree_def'
+Field.primitive_element_iff_algHom_eq_of_eval'
+Filter.atBot_basis'
+Filter.atBot_basis_Iio'
+Filter.atTop_basis'
+Filter.atTop_basis_Ioi'
+Filter.bliminf_congr'
+Filter.blimsup_congr'
+Filter.comap_eq_lift'
+Filter.comap_eval_neBot_iff'
+Filter.comap_id'
+Filter.const_eventuallyEq'
+Filter.coprodᵢ_bot'
+Filter.coprodᵢ_eq_bot_iff'
+Filter.coprodᵢ_neBot_iff'
+Filter.countable_biInf_eq_iInf_seq'
+Filter.disjoint_comap_iff_map'
+Filter.eventually_atBot_prod_self'
+Filter.eventually_atTop_prod_self'
+Filter.eventuallyConst_pred'
+Filter.eventuallyConst_set'
+Filter.EventuallyEq.fderivWithin'
+Filter.EventuallyEq.iteratedFDerivWithin'
+Filter.EventuallyLE.mul_le_mul'
+Filter.eventually_smallSets'
+Filter.exists_forall_mem_of_hasBasis_mem_blimsup'
+Filter.ext'
+Filter.extraction_forall_of_eventually'
+Filter.extraction_of_frequently_atTop'
+Filter.frequently_atBot'
+Filter.frequently_atTop'
+Filter.Germ.coe_compTendsto'
+Filter.Germ.coe_smul'
+Filter.Germ.const_compTendsto'
+Filter.Germ.instDistribMulAction'
+Filter.Germ.instModule'
+Filter.Germ.instMulAction'
+Filter.Germ.instSMul'
+Filter.hasBasis_biInf_of_directed'
+Filter.hasBasis_biInf_principal'
+Filter.HasBasis.cauchySeq_iff'
+Filter.hasBasis_cobounded_norm'
+Filter.HasBasis.cobounded_of_norm'
+Filter.HasBasis.eventuallyConst_iff'
+Filter.hasBasis_iInf'
+Filter.hasBasis_iInf_of_directed'
+Filter.HasBasis.inf'
+Filter.HasBasis.lift'
+Filter.HasBasis.nhds'
+Filter.HasBasis.prod_nhds'
+Filter.HasBasis.sup'
+Filter.HasBasis.to_hasBasis'
+Filter.HasBasis.to_image_id'
+Filter.HasBasis.isUniformEmbedding_iff'
+Filter.iInf_neBot_iff_of_directed'
+Filter.iInf_sets_eq_finite'
+Filter.isScalarTower'
+Filter.isScalarTower''
+Filter.le_lift'
+Filter.le_limsup_of_frequently_le'
+Filter.le_pure_iff'
+Filter.lift_lift'_same_eq_lift'
+Filter.lift_lift'_same_le_lift'
+Filter.lift'_mono'
+Filter.lift_mono'
+Filter.liminf_eq_iSup_iInf_of_nat'
+Filter.liminf_le_of_frequently_le'
+Filter.limsup_eq_iInf_iSup_of_nat'
+Filter.map_id'
+Filter.map_inf'
+Filter.map_inv'
+Filter.map_one'
+Filter.map_prod_eq_map₂'
+Filter.mem_bind'
+Filter.mem_coclosed_compact'
+Filter.mem_cocompact'
+Filter.mem_comap'
+Filter.mem_comap''
+Filter.mem_iInf'
+Filter.mem_iInf_finite'
+Filter.mem_inf_principal'
+Filter.mem_lift'
+Filter.mem_map'
+Filter.mem_nhds_iff'
+Filter.mem_pi'
+Filter.mem_rcomap'
+Filter.mono_bliminf'
+Filter.mono_blimsup'
+Filter.monotone_lift'
+Filter.neBot_inf_comap_iff_map'
+Filter.nhds_eq'
+Filter.principal_le_lift'
+Filter.prod_comm'
+Filter.prod_lift'_lift'
+Filter.prod_map_map_eq'
+Filter.ptendsto_of_ptendsto'
+Filter.push_pull'
+Filter.rcomap'_rcomap'
+Filter.sInf_neBot_of_directed'
+Filter.smulCommClass_filter'
+Filter.smulCommClass_filter''
+Filter.tendsto_atBot'
+Filter.tendsto_atBot_add_left_of_ge'
+Filter.tendsto_atBot_add_nonpos_left'
+Filter.tendsto_atBot_add_nonpos_right'
+Filter.tendsto_atBot_add_right_of_ge'
+Filter.tendsto_atBot_mono'
+Filter.tendsto_atBot_of_add_bdd_below_left'
+Filter.tendsto_atBot_of_add_bdd_below_right'
+Filter.tendsto_atTop'
+Filter.tendsto_atTop_add_left_of_le'
+Filter.tendsto_atTop_add_nonneg_left'
+Filter.tendsto_atTop_add_nonneg_right'
+Filter.tendsto_atTop_add_right_of_le'
+Filter.tendsto_atTop_mono'
+Filter.tendsto_atTop_of_add_bdd_above_left'
+Filter.tendsto_atTop_of_add_bdd_above_right'
+Filter.tendsto_congr'
+Filter.Tendsto.congr'
+Filter.Tendsto.const_div'
+Filter.Tendsto.div'
+Filter.Tendsto.div_const'
+Filter.Tendsto.eventually_ne_atTop'
+Filter.tendsto_id'
+Filter.Tendsto.if'
+Filter.tendsto_iff_rtendsto'
+Filter.tendsto_iInf'
+Filter.Tendsto.inf_nhds'
+Filter.tendsto_inv₀_cobounded'
+Filter.tendsto_lift'
+Filter.Tendsto.nnnorm'
+Filter.Tendsto.norm'
+Filter.tendsto_prod_iff'
+Filter.Tendsto.sup_nhds'
+Filter.unbounded_of_tendsto_atBot'
+Filter.unbounded_of_tendsto_atTop'
+Filter.univ_mem'
+Fin.card_filter_univ_succ'
+Fin.castPred_zero'
+Fin.cycleRange_zero'
+Fin.exists_fin_succ'
+Fin.find_min'
+Fin.forall_fin_succ'
+Fin.insertNth_last'
+Fin.insertNth_zero'
+Fin.isEmpty'
+FiniteDimensional.finiteDimensional_pi'
+FiniteField.card'
+Finite.Set.finite_biUnion'
+Fin.last_pos'
+Finmap.ext_iff'
+Fin.mem_piFinset_succ'
+Fin.mul_one'
+Fin.mul_zero'
+Fin.one_mul'
+Fin.one_pos'
+Fin.orderIso_subsingleton'
+Fin.partialProd_succ'
+Finpartition.IsEquipartition.card_biUnion_offDiag_le'
+Finpartition.IsEquipartition.sum_nonUniforms_lt'
+Fin.pred_one'
+Fin.preimage_apply_01_prod'
+Fin.prod_congr'
+finprod_emb_domain'
+finprod_mem_inter_mul_diff'
+finprod_mem_inter_mulSupport_eq'
+Fin.prod_univ_get'
+Fin.prod_univ_two'
+finrank_real_complex_fact'
+finRotate_last'
+Finset.abs_sum_of_nonneg'
+Finset.aemeasurable_prod'
+Finset.aestronglyMeasurable_prod'
+Finset.card_le_card_of_forall_subsingleton'
+Finset.card_mul_le_card_mul'
+Finset.coe_inf'
+Finset.coe_max'
+Finset.coe_min'
+Finset.coe_sup'
+Finset.Colex.toColex_sdiff_le_toColex_sdiff'
+Finset.Colex.toColex_sdiff_lt_toColex_sdiff'
+Finset.decidableMem'
+Finset.disjoint_filter_filter'
+Finset.eq_of_mem_uIcc_of_mem_uIcc'
+Finset.eq_prod_range_div'
+Finset.erase_injOn'
+Finset.exists_le_of_prod_le'
+Finset.exists_lt_of_prod_lt'
+Finset.exists_mem_eq_inf'
+Finset.exists_mem_eq_sup'
+Finset.exists_one_lt_of_prod_one_of_exists_ne_one'
+Finset.expect_boole_mul'
+Finset.expect_dite_eq'
+Finset.expect_ite_eq'
+Finset.extract_gcd'
+Finset.filter_attach'
+Finset.filter_inj'
+Finset.filter_ne'
+Finset.forall_mem_not_eq'
+Finset.Icc_mul_Icc_subset'
+Finset.Icc_mul_Ico_subset'
+Finset.Icc_subset_uIcc'
+Finset.Ici_mul_Ici_subset'
+Finset.Ici_mul_Ioi_subset'
+Finset.Ico_mul_Icc_subset'
+Finset.Ico_mul_Ioc_subset'
+Finset.Ico_union_Ico'
+Finset.Iic_mul_Iic_subset'
+Finset.Iic_mul_Iio_subset'
+Finset.Iio_mul_Iic_subset'
+Finset.image₂_singleton_left'
+Finset.image_id'
+Finset.image_mul_left'
+Finset.image_mul_right'
+Finset.inf'_sup_inf'
+Finset.insert_inj_on'
+Finset.insert_sdiff_insert'
+Finset.insert_val'
+Finset.Ioc_mul_Ico_subset'
+Finset.Ioi_mul_Ici_subset'
+Finset.isGreatest_max'
+Finset.isLeast_min'
+Finset.isScalarTower'
+Finset.isScalarTower''
+Finset.le_inf'
+Finset.le_max'
+Finset.le_min'
+Finset.le_sum_condensed'
+Finset.le_sum_schlomilch'
+Finset.le_sup'
+Finset.lt_max'_of_mem_erase_max'
+Finset.map_filter'
+Finset.max'_eq_sup'
+Finset.measurable_prod'
+Finset.measurable_range_sup'
+Finset.measurable_range_sup''
+Finset.measurable_sup'
+Finset.mem_finsuppAntidiag'
+Finset.mem_inv'
+Finset.mem_map'
+Finset.mem_range_iff_mem_finset_range_of_mod_eq'
+Finset.mem_uIcc'
+Finset.min'_eq_inf'
+Finset.min'_lt_max'
+Finset.min'_lt_of_mem_erase_min'
+Finset.mulEnergy_eq_sum_sq'
+Finset.Nat.antidiagonal_eq_image'
+Finset.Nat.antidiagonal_eq_map'
+Finset.Nat.antidiagonal_succ'
+Finset.Nat.antidiagonal_succ_succ'
+Finset.Nat.prod_antidiagonal_succ'
+Finset.Nat.sum_antidiagonal_succ'
+Finset.nnnorm_prod_le'
+Finset.noncommProd_cons'
+Finset.noncommProd_insert_of_not_mem'
+Finset.Nonempty.csInf_eq_min'
+Finset.Nonempty.csSup_eq_max'
+Finset.norm_prod_le'
+Finset.nsmul_inf'
+Finset.nsmul_sup'
+Finset.ofDual_inf'
+Finset.ofDual_max'
+Finset.ofDual_min'
+Finset.ofDual_sup'
+Finset.one_le_prod'
+Finset.one_le_prod''
+Finset.one_lt_prod'
+Finset.pairwise_cons'
+Finset.pairwise_subtype_iff_pairwise_finset'
+Finset.piecewise_le_piecewise'
+Finset.piecewise_mem_Icc'
+Finset.PiFinsetCoe.canLift'
+Finset.preimage_mul_left_one'
+Finset.preimage_mul_right_one'
+Finset.prod_dite_eq'
+Finset.prod_eq_one_iff'
+Finset.prod_eq_one_iff_of_le_one'
+Finset.prod_eq_one_iff_of_one_le'
+Finset.prod_fiberwise'
+Finset.prod_fiberwise_eq_prod_filter'
+Finset.prod_fiberwise_le_prod_of_one_le_prod_fiber'
+Finset.prod_fiberwise_of_maps_to'
+Finset.prod_finset_product'
+Finset.prod_finset_product_right'
+Finset.prod_Ico_add'
+Finset.prod_image'
+Finset.prod_le_one'
+Finset.prod_le_prod_fiberwise_of_prod_fiber_le_one'
+Finset.prod_le_prod_of_ne_one'
+Finset.prod_le_prod_of_subset'
+Finset.prod_le_prod_of_subset_of_one_le'
+Finset.prod_le_univ_prod_of_one_le'
+Finset.prod_lt_one'
+Finset.prod_lt_prod'
+Finset.prod_lt_prod_of_subset'
+Finset.prod_mono_set'
+Finset.prod_mono_set_of_one_le'
+Finset.prod_pi_mulSingle'
+Finset.prod_preimage'
+Finset.prod_range_div'
+Finset.prod_range_succ'
+Finset.prod_sigma'
+Finset.range_add_one'
+Finset.sdiff_sdiff_left'
+Finset.single_le_prod'
+Finset.single_lt_prod'
+Finset.smulCommClass_finset'
+Finset.smulCommClass_finset''
+Finset.smul_prod'
+Finset.smul_univ₀'
+Finset.sorted_last_eq_max'
+Finset.sorted_zero_eq_min'
+Finset.stronglyMeasurable_prod'
+Finset.subset_singleton_iff'
+Finset.sum_apply'
+Finset.sum_condensed_le'
+Finset.sum_pow'
+Finset.sum_schlomilch_le'
+Finset.sup'_inf_sup'
+Finset.sup_singleton'
+Finset.sup_singleton''
+Finset.toDual_inf'
+Finset.toDual_max'
+Finset.toDual_min'
+Finset.toDual_sup'
+Finset.tprod_subtype'
+Finset.uIcc_subset_uIcc_iff_le'
+Finset.untrop_sum'
+Fin.size_positive'
+Fin.succ_zero_eq_one'
+Finsupp.apply_single'
+Finsupp.card_support_eq_one'
+Finsupp.card_support_le_one'
+Finsupp.equivMapDomain_refl'
+Finsupp.equivMapDomain_trans'
+Finsupp.ext_iff'
+Finsupp.le_iff'
+Finsupp.le_weight_of_ne_zero'
+Finsupp.Lex.wellFounded'
+Finsupp.mapDomain_apply'
+Finsupp.mapRange_add'
+Finsupp.mapRange_neg'
+Finsupp.mapRange_sub'
+Finsupp.mem_supported'
+Finsupp.mulHom_ext'
+Finsupp.smul_single'
+Finsupp.subtypeDomain_eq_zero_iff'
+Finsupp.sum_apply'
+Finsupp.sum_cons'
+Finsupp.sum_ite_self_eq'
+Finsupp.sum_smul_index'
+Finsupp.sum_smul_index_linearMap'
+Finsupp.sum_sum_index'
+Finsupp.support_eq_singleton'
+Finsupp.support_subset_singleton'
+Finsupp.univ_sum_single_apply'
+Finsupp.wellFoundedLT'
+Fintype.card_congr'
+Fintype.card_of_finset'
+Fintype.card_subtype_eq'
+Fintype.expect_dite_eq'
+Fintype.expect_ite_eq'
+Fintype.prod_fiberwise'
+Fintype.prod_mono'
+Fintype.prod_strictMono'
+Fin.univ_image_get'
+Fin.univ_image_getElem'
+Fin.val_one'
+Fin.val_one''
+Fin.zero_mul'
+Fin.zero_ne_one'
+FirstOrder.Language.addEmptyConstants_is_expansion_on'
+FirstOrder.Language.DirectLimit.cg'
+FirstOrder.Language.DirectLimit.funMap_quotient_mk'_sigma_mk'
+FirstOrder.Language.DirectLimit.lift_quotient_mk'_sigma_mk'
+FirstOrder.Language.DirectLimit.relMap_quotient_mk'_sigma_mk'
+FirstOrder.Language.Embedding.codRestrict_apply'
+FirstOrder.Language.funMap_quotient_mk'
+FirstOrder.Language.relMap_quotient_mk'
+FirstOrder.Language.Term.realize_quotient_mk'
+FixedPoints.minpoly.eval₂'
+FixedPoints.smulCommClass'
+forall_apply_eq_imp_iff'
+forall_eq_apply_imp_iff'
+forall_lt_iff_le'
+forall_prop_congr'
+forall_true_iff'
+FormalMultilinearSeries.apply_order_ne_zero'
+FormalMultilinearSeries.comp_coeff_zero'
+FormalMultilinearSeries.order_eq_find'
+FormalMultilinearSeries.order_eq_zero_iff'
+fourier_add'
+fourier_coe_apply'
+fourierIntegral_gaussian_innerProductSpace'
+fourierIntegral_gaussian_pi'
+fourier_neg'
+fourier_zero'
+four_ne_zero'
+FP.Float.sign'
+FractionalIdeal.absNorm_eq'
+FractionalIdeal.coeIdeal_eq_zero'
+FractionalIdeal.coeIdeal_inj'
+FractionalIdeal.coeIdeal_injective'
+FractionalIdeal.coeIdeal_le_coeIdeal'
+FractionalIdeal.coeIdeal_ne_zero'
+FractionalIdeal.inv_zero'
+FreeAbelianGroup.induction_on'
+FreeAbelianGroup.lift.add'
+FreeAbelianGroup.lift_neg'
+FreeGroup.map.id'
+FreeMagma.lift_comp_of'
+FreeMagma.map_mul'
+FreeMagma.traverse_mul'
+FreeMagma.traverse_pure'
+FreeMonoid.countP_of'
+FreeSemigroup.lift_comp_of'
+FreeSemigroup.map_mul'
+FreeSemigroup.traverse_mul'
+FreeSemigroup.traverse_pure'
+frontier_closedBall'
+frontier_Ici'
+frontier_Iic'
+frontier_Iio'
+frontier_Ioi'
+frontier_sphere'
+Function.Antiperiodic.funext'
+Function.Antiperiodic.mul_const'
+Function.Antiperiodic.sub_eq'
+Function.Bijective.of_comp_iff'
+Function.Commute.iterate_pos_le_iff_map_le'
+Function.Commute.iterate_pos_lt_iff_map_lt'
+Function.Commute.iterate_pos_lt_of_map_lt'
+Function.Exact.of_ladder_addEquiv_of_exact'
+Function.Exact.split_tfae'
+Function.extend_apply'
+FunctionField.InftyValuation.map_add_le_max'
+FunctionField.InftyValuation.map_mul'
+FunctionField.InftyValuation.map_one'
+FunctionField.InftyValuation.map_zero'
+Function.Injective.eq_iff'
+Function.Injective.ne_iff'
+Function.Injective.of_comp_iff'
+Function.Injective.surjective_comp_right'
+Function.iterate_succ'
+Function.iterate_succ_apply'
+Function.minimalPeriod_iterate_eq_div_gcd'
+Function.mulSupport_add_one'
+Function.mulSupport_curry'
+Function.mulSupport_inv'
+Function.mulSupport_one'
+Function.mulSupport_one_add'
+Function.mulSupport_one_sub'
+Function.mulSupport_prod_mk'
+Function.mulSupport_subset_iff'
+Function.Periodic.mul_const'
+Function.periodicOrbit_chain'
+Function.Periodic.sub_eq'
+Function.support_div'
+Function.support_inv'
+Function.support_mul'
+Function.support_pow'
+Function.Surjective.of_comp_iff'
+Function.update_comp_eq_of_forall_ne'
+Function.update_comp_eq_of_injective'
+Function.update_comp_eq_of_not_mem_range'
+GaloisCoinsertion.isCoatom_iff'
+GaloisConnection.l_csSup'
+GaloisConnection.l_u_l_eq_l'
+GaloisConnection.u_csInf'
+GaloisConnection.u_l_u_eq_u'
+GaloisInsertion.isAtom_iff'
+gauge_gaugeRescale'
+gauge_lt_eq'
+gauge_zero'
+GaussianFourier.norm_cexp_neg_mul_sq_add_mul_I'
+GaussianInt.toComplex_def'
+gcd_assoc'
+gcd_comm'
+gcd_mul_left'
+gcd_mul_right'
+gcd_neg'
+gcd_one_left'
+gcd_one_right'
+gcd_zero_left'
+gcd_zero_right'
+GenContFract.of_convs_eq_convs'
+ge_of_tendsto'
+geom_sum_Ico'
+geom_sum_pos'
+geom_sum_succ'
+GradedTensorProduct.algebraMap_def'
+gradient_const'
+gradient_eq_deriv'
+gramSchmidt_def'
+gramSchmidt_def''
+gramSchmidtNormed_unit_length'
+gramSchmidtOrthonormalBasis_inv_triangular'
+Group.conjugatesOfSet_subset'
+Group.fg_iff'
+GroupTopology.ext'
+Grp.coe_comp'
+Grp.coe_id'
+Grp.SurjectiveOfEpiAuxs.h_apply_fromCoset'
+Grp.SurjectiveOfEpiAuxs.τ_apply_fromCoset'
+HahnModule.mul_smul'
+HahnModule.one_smul'
+HahnModule.support_smul_subset_vadd_support'
+HahnModule.zero_smul'
+HahnSeries.add_coeff'
+HahnSeries.algebraMap_apply'
+HahnSeries.mul_assoc'
+HahnSeries.mul_coeff_left'
+HahnSeries.mul_coeff_right'
+HahnSeries.neg_coeff'
+HahnSeries.sub_coeff'
+HasCompactMulSupport.intro'
+HasCompactMulSupport.inv'
+HasCompactMulSupport.mono'
+HasDerivAt.complexToReal_fderiv'
+hasDerivAt_exp_smul_const'
+hasDerivAt_exp_smul_const_of_mem_ball'
+HasDerivAtFilter.hasGradientAtFilter'
+HasDerivAt.hasGradientAt'
+hasDerivAt_id'
+hasDerivAt_neg'
+HasDerivWithinAt.complexToReal_fderiv'
+hasDerivWithinAt_congr_set'
+hasDerivWithinAt_iff_tendsto_slope'
+hasDerivWithinAt_inter'
+HasDerivWithinAt.limsup_slope_le'
+hasFDerivAt_exp_smul_const'
+hasFDerivAt_exp_smul_const_of_mem_ball'
+hasFDerivAtFilter_pi'
+hasFDerivAt_list_prod'
+hasFDerivAt_list_prod_attach'
+hasFDerivAt_list_prod_finRange'
+HasFDerivAt.mul'
+HasFDerivAt.mul_const'
+hasFDerivAt_pi'
+hasFDerivAt_pi''
+HasFDerivWithinAt.congr'
+hasFDerivWithinAt_congr_set'
+hasFDerivWithinAt_inter'
+HasFDerivWithinAt.list_prod'
+HasFDerivWithinAt.mul'
+HasFDerivWithinAt.mul_const'
+hasFDerivWithinAt_pi'
+hasFDerivWithinAt_pi''
+HasFiniteFPowerSeriesOnBall.mk'
+hasFPowerSeriesAt_iff'
+HasFPowerSeriesOnBall.factorial_smul'
+hasFTaylorSeriesUpToOn_pi'
+HasFTaylorSeriesUpToOn.zero_eq'
+HasFTaylorSeriesUpTo.zero_eq'
+HasGradientAtFilter.hasDerivAtFilter'
+HasGradientAt.hasDerivAt'
+hasGradientWithinAt_congr_set'
+HasLineDerivWithinAt.congr'
+HasLineDerivWithinAt.hasLineDerivAt'
+HasMFDerivAt.mul'
+hasMFDerivWithinAt_inter'
+HasMFDerivWithinAt.mul'
+HasOrthogonalProjection.map_linearIsometryEquiv'
+hasProd_nat_add_iff'
+HasStrictDerivAt.complexToReal_fderiv'
+hasStrictDerivAt_exp_smul_const'
+hasStrictDerivAt_exp_smul_const_of_mem_ball'
+hasStrictFDerivAt_exp_smul_const'
+hasStrictFDerivAt_exp_smul_const_of_mem_ball'
+hasStrictFDerivAt_list_prod'
+HasStrictFDerivAt.list_prod'
+hasStrictFDerivAt_list_prod_attach'
+hasStrictFDerivAt_list_prod_finRange'
+HasStrictFDerivAt.mul'
+HasStrictFDerivAt.mul_const'
+hasStrictFDerivAt_pi'
+hasStrictFDerivAt_pi''
+hasSum_choose_mul_geometric_of_norm_lt_one'
+hasSum_geometric_two'
+HasSum.matrix_blockDiag'
+HasSum.matrix_blockDiagonal'
+hasSum_sum_range_mul_of_summable_norm'
+Homeomorph.comp_continuousAt_iff'
+Homeomorph.comp_continuous_iff'
+Homeomorph.comp_isOpenMap_iff'
+HomogeneousIdeal.ext'
+HomologicalComplex₂.d₁_eq'
+HomologicalComplex₂.d₁_eq_zero'
+HomologicalComplex₂.d₂_eq'
+HomologicalComplex₂.d₂_eq_zero'
+HomologicalComplex₂.totalAux.d₁_eq'
+HomologicalComplex₂.totalAux.d₂_eq'
+HomologicalComplex.exactAt_iff'
+HomologicalComplex.extend.d_none_eq_zero'
+HomologicalComplex.homotopyCofiber.desc_f'
+HomologicalComplex.homotopyCofiber.ext_from_X'
+HomologicalComplex.homotopyCofiber.ext_to_X'
+HomologicalComplex.homotopyCofiber.inlX_d'
+HomologicalComplex.isZero_extend_X'
+HomologicalComplex.mapBifunctor.d₁_eq'
+HomologicalComplex.mapBifunctor.d₁_eq_zero'
+HomologicalComplex.mapBifunctor.d₂_eq'
+HomologicalComplex.mapBifunctor.d₂_eq_zero'
+HomologicalComplex.restrictionMap_f'
+HomotopyCategory.Pretriangulated.invRotate_distinguished_triangle'
+HomotopyCategory.Pretriangulated.rotate_distinguished_triangle'
+HurwitzZeta.jacobiTheta₂'_functional_equation'
+HurwitzZeta.oddKernel_def'
+Hyperreal.isSt_st'
+Icc_mem_nhdsWithin_Ici'
+Icc_mem_nhdsWithin_Iic'
+Icc_mem_nhdsWithin_Iio'
+Icc_mem_nhdsWithin_Ioi'
+Ico_mem_nhdsWithin_Ici'
+Ico_mem_nhdsWithin_Iio'
+Ico_mem_nhdsWithin_Ioi'
+Ideal.comap_map_of_surjective'
+Ideal.comap_sInf'
+Ideal.eq_jacobson_iff_sInf_maximal'
+Ideal.isJacobson_iff_sInf_maximal'
+Ideal.isJacobson_of_isIntegral'
+Ideal.isMaximal_comap_of_isIntegral_of_isMaximal'
+Ideal.IsMaximal.isPrime'
+Ideal.isMaximal_of_isIntegral_of_isMaximal_comap'
+Ideal.isPrime_ideal_prod_top'
+Ideal.IsPrime.inf_le'
+Ideal.isPrime_of_isPrime_prod_top'
+Ideal.mem_span_insert'
+Ideal.mem_span_singleton'
+Ideal.MvPolynomial.quotient_mk_comp_C_isIntegral_of_jacobson'
+Ideal.Polynomial.isMaximal_comap_C_of_isJacobson'
+Ideal.quotientInfToPiQuotient_mk'
+Ideal.Quotient.smulCommClass'
+Ideal.span_mul_span'
+Ideal.subset_union_prime'
+IfExpr.eval_ite_ite'
+iInf₂_mono'
+iInf_le'
+iInf_mono'
+iInf_prod'
+iInf_psigma'
+iInf_range'
+iInf_sigma'
+iInf_subtype'
+iInf_subtype''
+imageSubobjectIso_imageToKernel'
+Imo1962Q1.ProblemPredicate'
+imo1962_q4'
+Imo1969Q1.not_prime_of_int_mul'
+Imo2001Q2.imo2001_q2'
+imp_or'
+induced_orderTopology'
+IsInducing.continuousAt_iff'
+IsInducing.isClosed_iff'
+inf_compl_eq_bot'
+inf_eq_half_smul_add_sub_abs_sub'
+inner_map_polarization'
+InnerProductSpaceable.add_left_aux2'
+InnerProductSpaceable.add_left_aux4'
+Inseparable.specializes'
+Int.add_le_zero_iff_le_neg'
+Int.add_nonnneg_iff_neg_le'
+Int.ceil_eq_on_Ioc'
+Int.coprime_of_sq_sum'
+Int.dist_eq'
+integrable_cexp_quadratic'
+integrableOn_Icc_iff_integrableOn_Ico'
+integrableOn_Icc_iff_integrableOn_Ioc'
+integrableOn_Icc_iff_integrableOn_Ioo'
+integrableOn_Ici_iff_integrableOn_Ioi'
+integrableOn_Ico_iff_integrableOn_Ioo'
+integrableOn_Iic_iff_integrableOn_Iio'
+integrableOn_Ioc_iff_integrableOn_Ioo'
+Int.eq_one_or_neg_one_of_mul_eq_neg_one'
+Int.eq_one_or_neg_one_of_mul_eq_one'
+interior_closedBall'
+interior_eq_nhds'
+interior_Ici'
+interior_Iic'
+interior_sphere'
+IntermediateField.algebra'
+IntermediateField.charP'
+IntermediateField.eq_of_le_of_finrank_le''
+IntermediateField.exists_algHom_adjoin_of_splits''
+IntermediateField.exists_algHom_of_splits'
+IntermediateField.exists_finset_of_mem_supr'
+IntermediateField.exists_finset_of_mem_supr''
+IntermediateField.expChar'
+IntermediateField.finInsepDegree_bot'
+IntermediateField.finiteDimensional_iSup_of_finset'
+IntermediateField.finrank_bot'
+IntermediateField.finrank_top'
+IntermediateField.finSepDegree_bot'
+IntermediateField.insepDegree_bot'
+IntermediateField.lift_insepDegree_bot'
+IntermediateField.lift_sepDegree_bot'
+IntermediateField.module'
+IntermediateField.normalClosure_def'
+IntermediateField.normalClosure_def''
+IntermediateField.normal_iff_forall_map_eq'
+IntermediateField.normal_iff_forall_map_le'
+IntermediateField.rank_bot'
+IntermediateField.rank_top'
+IntermediateField.sepDegree_bot'
+intermediate_value_Ico'
+intermediate_value_Ioc'
+intermediate_value_Ioo'
+IntervalIntegrable.aestronglyMeasurable'
+intervalIntegrable_iff'
+IntervalIntegrable.mono_fun'
+IntervalIntegrable.mono_set'
+intervalIntegral.continuous_parametric_intervalIntegral_of_continuous'
+intervalIntegral.integral_congr_ae'
+intervalIntegral.integral_const'
+intervalIntegral.integral_deriv_comp_mul_deriv'
+intervalIntegral.integral_deriv_comp_smul_deriv'
+intervalIntegral.integral_deriv_eq_sub'
+intervalIntegral.integral_interval_sub_interval_comm'
+Int.even_add'
+Int.even_or_odd'
+Int.even_pow'
+Int.even_sub'
+Int.even_xor'_odd'
+Int.exists_gcd_one'
+Int.floor_eq_on_Ico'
+Int.Matrix.exists_ne_zero_int_vec_norm_le'
+Int.ModEq.add_left_cancel'
+Int.ModEq.add_right_cancel'
+Int.ModEq.mul_left'
+Int.ModEq.mul_right'
+Int.natAbs_ofNat'
+Int.odd_add'
+Int.odd_pow'
+Int.odd_sub'
+Int.Prime.dvd_mul'
+Int.Prime.dvd_pow'
+Int.toNat_lt'
+Int.two_pow_sub_pow'
+inv_div'
+inv_le'
+inv_le_div_iff_le_mul'
+inv_le_iff_one_le_mul'
+inv_le_inv'
+inv_lt'
+inv_lt_div_iff_lt_mul'
+inv_lt_iff_one_lt_mul'
+inv_lt_inv'
+inv_mul'
+inv_mul_le_iff'
+inv_mul_le_iff_le_mul'
+inv_mul_lt_iff'
+inv_mul_lt_iff_lt_mul'
+inv_neg'
+inv_neg''
+invOf_mul_cancel_left'
+invOf_mul_cancel_right'
+invOf_mul_self'
+invOf_one'
+inv_pos_le_iff_one_le_mul'
+inv_pos_lt_iff_one_lt_mul'
+inv_zpow'
+Ioc_mem_nhdsWithin_Iic'
+Ioc_mem_nhdsWithin_Iio'
+Ioc_mem_nhdsWithin_Ioi'
+Ioo_mem_nhdsWithin_Iio'
+Ioo_mem_nhdsWithin_Ioi'
+IsAbsoluteValue.abv_one'
+isAddFundamentalDomain_Ioc'
+isAdjointPair_toBilin'
+isAdjointPair_toLinearMap₂'
+IsAlgClosed.algebraMap_surjective_of_isIntegral'
+IsAntichain.eq'
+IsAntichain.interior_eq_empty'
+isArtinian_of_fg_of_artinian'
+isArtinian_submodule'
+IsBaseChange.algHom_ext'
+IsBoundedBilinearMap.isBigO'
+isBounded_iff_forall_norm_le'
+isBoundedUnder_ge_finset_inf'
+isBoundedUnder_le_finset_sup'
+IsCauSeq.bounded'
+isClosed_induced_iff'
+isCoboundedUnder_ge_finset_inf'
+isCoboundedUnder_le_finset_sup'
+IsCompact.elim_nhds_subcover'
+IsCompact.elim_nhds_subcover_nhdsSet'
+IsCompact.exists_bound_of_continuousOn'
+isCompact_iff_ultrafilter_le_nhds'
+IsCompact.tendsto_subseq'
+isComplete_iff_ultrafilter'
+IsCoprime.isUnit_of_dvd'
+IsCyclotomicExtension.neZero'
+IsCyclotomicExtension.Rat.discr_odd_prime'
+IsDedekindDomain.HeightOneSpectrum.adicCompletion.algebra'
+IsDedekindDomain.HeightOneSpectrum.adicCompletion.instIsScalarTower'
+IsDedekindDomain.HeightOneSpectrum.adicValued.has_uniform_continuous_const_smul'
+IsDedekindDomain.HeightOneSpectrum.algebraMap_adicCompletion'
+isField_of_isIntegral_of_isField'
+IsFractionRing.mk'_num_den'
+IsFractionRing.num_mul_den_eq_num_iff_eq'
+IsGLB.exists_between'
+IsGLB.exists_between_self_add'
+isGLB_inv'
+IsGroupHom.inv_iff_ker'
+IsGroupHom.inv_ker_one'
+IsGroupHom.map_mul'
+IsGroupHom.one_iff_ker_inv'
+IsGroupHom.one_ker_inv'
+IsIntegralClosure.algebraMap_mk'
+isIntegral_localization'
+IsIntegral.minpoly_splits_tower_top'
+IsIntegral.of_mem_closure''
+IsInvariantSubring.coe_subtypeHom'
+IsKleinFour.card_four'
+IsLindelof.elim_nhds_subcover'
+IsLinearMap.isLinearMap_smul'
+IsLocalization.algebraMap_mk'
+IsLocalization.algEquiv_mk'
+IsLocalization.algEquiv_symm_mk'
+IsLocalization.map_id_mk'
+IsLocalization.map_mk'
+IsLocalization.mem_invSubmonoid_iff_exists_mk'
+IsLocalization.mk'_eq_iff_eq'
+IsLocalization.mk'_eq_of_eq'
+IsLocalization.mk'_mul_mk'_eq_one'
+IsLocalization.mk'_self'
+IsLocalization.mk'_self''
+IsLocalization.mk'_spec'
+IsLocalization.ringEquivOfRingEquiv_mk'
+IsLocalization.smul_mk'
+IsLocalization.surj''
+IsLocalization.toInvSubmonoid_eq_mk'
+isLocalizedModule_iff_isLocalization'
+IsLocalizedModule.iso_symm_apply'
+IsLocalizedModule.map_mk'
+IsLocalizedModule.mk'_add_mk'
+IsLocalizedModule.mk'_cancel'
+IsLocalizedModule.mk_eq_mk'
+IsLocalizedModule.mk'_eq_zero'
+IsLocalizedModule.mk'_mul_mk'
+IsLocalizedModule.mk'_sub_mk'
+IsLowerSet.cthickening'
+IsLowerSet.thickening'
+isLUB_csSup'
+IsLUB.exists_between'
+IsLUB.exists_between_sub_self'
+isLUB_hasProd'
+isLUB_inv'
+IsMax.not_isMin'
+IsMin.not_isMax'
+isNoetherian_iff'
+isNoetherian_submodule'
+IsometryEquiv.comp_continuous_iff'
+isOpen_extChartAt_preimage'
+isOpen_gt'
+isOpen_iff_ultrafilter'
+IsOpen.ite'
+isOpen_lt'
+isOpen_pi_iff'
+IsPathConnected.exists_path_through_family'
+IsPGroup.to_sup_of_normal_left'
+IsPGroup.to_sup_of_normal_right'
+IsPreconnected.union'
+IsPrimitiveRoot.card_rootsOfUnity'
+IsPrimitiveRoot.finite_quotient_span_sub_one'
+IsPrimitiveRoot.isPrimitiveRoot_iff'
+IsPrimitiveRoot.isUnit_unit'
+IsPrimitiveRoot.neZero'
+IsPrimitiveRoot.zmodEquivZPowers_symm_apply_pow'
+IsPrimitiveRoot.zmodEquivZPowers_symm_apply_zpow'
+isQuasiregular_iff_isUnit'
+isRegular_iff_ne_zero'
+isRegular_of_ne_zero'
+IsScalarTower.coe_toAlgHom'
+IsScalarTower.subalgebra'
+IsScalarTower.to_smulCommClass'
+IsSelfAdjoint.conjugate'
+isSemisimpleModule_of_isSemisimpleModule_submodule'
+IsUnifLocDoublingMeasure.eventually_measure_le_scaling_constant_mul'
+IsUnifLocDoublingMeasure.exists_measure_closedBall_le_mul'
+isUnit_iff_exists_inv'
+IsUnit.map'
+IsUnit.val_inv_unit'
+iSup₂_mono'
+iSup_mono'
+iSup_of_empty'
+IsUpperSet.cthickening'
+IsUpperSet.thickening'
+iSup_prod'
+iSup_psigma'
+iSup_range'
+iSup_sigma'
+iSup_subtype'
+iSup_subtype''
+ite_eq_iff'
+iteratedFDeriv_add_apply'
+iteratedFDeriv_const_smul_apply'
+iteratedFDerivWithin_eventually_congr_set'
+iter_deriv_inv'
+iter_deriv_pow'
+iter_deriv_zpow'
+jacobiTheta₂'_add_left'
+KaehlerDifferential.isScalarTower'
+KaehlerDifferential.module'
+LatticeHom.coe_comp_inf_hom'
+LatticeHom.coe_comp_sup_hom'
+LawfulFix.fix_eq'
+lcm_assoc'
+lcm_comm'
+le_abs'
+le_add_tsub'
+Lean.Elab.Tactic.TacticM.runCore'
+le_ciInf_iff'
+le_ciSup_iff'
+le_csInf_iff'
+le_csInf_iff''
+le_csSup_iff'
+le_div_iff₀'
+le_div_iff_mul_le'
+le_div_iff_of_neg'
+LeftOrdContinuous.map_sSup'
+Left.pow_lt_one_iff'
+legendreSym.eq_neg_one_iff'
+legendreSym.eq_one_iff'
+le_hasProd'
+le_iff_exists_mul'
+le_iff_forall_one_lt_lt_mul'
+le_inv'
+le_iSup'
+le_map_add_map_div'
+le_mul_iff_one_le_left'
+le_mul_iff_one_le_right'
+le_mul_of_le_of_one_le'
+le_mul_of_one_le_left'
+le_mul_of_one_le_right'
+le_nhdsAdjoint_iff'
+le_of_eq_of_le'
+le_of_forall_le'
+le_of_forall_lt'
+le_of_forall_one_lt_lt_mul'
+le_of_le_of_eq'
+le_of_mul_le_mul_left'
+le_of_mul_le_mul_right'
+le_of_pow_le_pow_left'
+le_of_tendsto'
+le_of_tendsto_of_tendsto'
+le_tprod'
+le_trans'
+Lex.instDistribMulAction'
+Lex.instDistribSMul'
+Lex.instIsScalarTower'
+Lex.instIsScalarTower''
+Lex.instModule'
+Lex.instMulAction'
+Lex.instMulActionWithZero'
+Lex.instPow'
+Lex.instSMulCommClass'
+Lex.instSMulCommClass''
+Lex.instSMulWithZero'
+LieAlgebra.IsKilling.apply_coroot_eq_cast'
+LieAlgebra.IsKilling.coe_corootSpace_eq_span_singleton'
+LieAlgebra.lieCharacter_apply_lie'
+LieAlgebra.mem_corootSpace'
+LieIdeal.map_sup_ker_eq_map'
+LieModule.chainTop_isNonZero'
+LieModule.coe_chainTop'
+LieModule.genWeightSpaceChain_def'
+LieModule.independent_genWeightSpace'
+LieModule.instIsTrivialOfSubsingleton'
+LieModule.isNilpotent_of_top_iff'
+LieModule.iSup_genWeightSpace_eq_top'
+LieModule.Weight.ext_iff'
+LieSubalgebra.coe_incl'
+LieSubalgebra.ext_iff'
+LieSubalgebra.mem_normalizer_iff'
+LieSubmodule.iSup_induction'
+LieSubmodule.lieIdeal_oper_eq_linear_span'
+LieSubmodule.mem_mk_iff'
+LieSubmodule.module'
+LieSubmodule.Quotient.mk_eq_zero'
+LieSubmodule.Quotient.module'
+LieSubmodule.Quotient.range_mk'
+LieSubmodule.Quotient.surjective_mk'
+LieSubmodule.Quotient.toEnd_comp_mk'
+LieSubmodule.sInf_coe_toSubmodule'
+LieSubmodule.sSup_coe_toSubmodule'
+liftOfDerivationToSquareZero_mk_apply'
+lift_rank_lt_rank_dual'
+LightProfinite.proj_comp_transitionMap'
+LightProfinite.proj_comp_transitionMapLE'
+liminf_finset_inf'
+limsup_finset_sup'
+linearDependent_comp_subtype'
+LinearEquiv.apply_smulCommClass'
+LinearEquiv.coe_toContinuousLinearEquiv'
+LinearEquiv.coe_toContinuousLinearEquiv_symm'
+LinearEquiv.isRegular_congr'
+LinearEquiv.isSMulRegular_congr'
+LinearEquiv.isWeaklyRegular_congr'
+LinearEquiv.mk_coe'
+linearIndependent_algHom_toLinearMap'
+LinearIndependent.cardinal_le_rank'
+linearIndependent_equiv'
+LinearIndependent.eq_zero_of_pair'
+linearIndependent_fin_succ'
+linearIndependent_iff'
+linearIndependent_iff''
+linearIndependent_inl_union_inr'
+linearIndependent_insert'
+linearIndependent_le_span_aux'
+linearIndependent_option'
+LinearIndependent.span_eq_top_of_card_eq_finrank'
+LinearIndependent.to_subtype_range'
+LinearIsometry.completeSpace_map'
+LinearIsometryEquiv.coe_coe''
+LinearIsometryEquiv.comp_fderiv'
+LinearIsometryEquiv.comp_hasFDerivAt_iff'
+LinearIsometryEquiv.comp_hasFDerivWithinAt_iff'
+LinearIsometry.isComplete_image_iff'
+LinearIsometry.isComplete_map_iff'
+LinearIsometry.map_orthogonalProjection'
+LinearMap.apply_smulCommClass'
+LinearMap.BilinForm.mul_toMatrix'
+LinearMap.BilinForm.nondegenerate_toBilin'_of_det_ne_zero'
+LinearMap.BilinForm.Nondegenerate.toMatrix'
+LinearMap.BilinForm.toMatrix'_toBilin'
+LinearMap.coe_toContinuousLinearMap'
+LinearMap.detAux_def''
+LinearMap.det_toLin'
+LinearMap.det_toMatrix'
+LinearMap.det_zero'
+LinearMap.det_zero''
+LinearMap.disjoint_ker'
+LinearMap.dualMap_apply'
+LinearMap.extendScalarsOfIsLocalization_apply'
+LinearMap.IsProj.eq_conj_prod_map'
+LinearMap.IsScalarTower.compatibleSMul'
+LinearMap.IsSymmetric.orthogonalComplement_iSup_eigenspaces_eq_bot'
+LinearMap.IsSymmetric.orthogonalFamily_eigenspaces'
+LinearMap.ker_eq_bot'
+LinearMap.ker_smul'
+LinearMap.lcomp_apply'
+LinearMap.llcomp_apply'
+LinearMap.map_le_map_iff'
+LinearMap.minpoly_toMatrix'
+LinearMap.mkContinuous₂_norm_le'
+LinearMap.mul_apply'
+LinearMap.mul_toMatrix'
+LinearMap.ofIsCompl_eq'
+LinearMap.range_smul'
+LinearMap.separatingLeft_toLinearMap₂'_of_det_ne_zero'
+LinearMap.SeparatingLeft.toMatrix₂'
+LinearMap.stdBasis_apply'
+LinearMap.toMatrixAlgEquiv_apply'
+LinearMap.toMatrixAlgEquiv'_toLinAlgEquiv'
+LinearMap.toMatrixAlgEquiv_transpose_apply'
+LinearMap.toMatrix_apply'
+LinearMap.toMatrix'_toLin'
+LinearMap.toMatrix'_toLinearMap₂'
+LinearMap.toMatrix'_toLinearMapₛₗ₂'
+LinearMap.toMatrix_transpose_apply'
+LinearMap.trace_comp_comm'
+LinearMap.trace_conj'
+LinearMap.trace_eq_sum_trace_restrict'
+LinearMap.trace_mul_cycle'
+LinearMap.trace_prodMap'
+LinearMap.trace_tensorProduct'
+LinearMap.trace_transpose'
+LinearOrderedCommGroup.mul_lt_mul_left'
+LinearPMap.closure_def'
+LinearPMap.ext'
+LinearPMap.mem_graph_iff'
+LinearPMap.mem_graph_snd_inj'
+LinearPMap.toFun'
+lineDerivWithin_congr'
+LipschitzOnWith.of_dist_le'
+LipschitzWith.const'
+LipschitzWith.integral_inv_smul_sub_mul_tendsto_integral_lineDeriv_mul'
+LipschitzWith.nnorm_le_mul'
+LipschitzWith.norm_le_mul'
+LipschitzWith.of_dist_le'
+lipschitzWith_one_nnnorm'
+lipschitzWith_one_norm'
+List.aemeasurable_prod'
+List.aestronglyMeasurable_prod'
+List.alternatingProd_cons'
+List.alternatingProd_cons_cons'
+list_casesOn'
+List.chain'_cons'
+List.Chain'.cons'
+List.chain'_map_of_chain'
+list_cons'
+List.cons_sublist_cons'
+List.count_cons'
+List.decidableChain'
+List.dedup_cons_of_mem'
+List.dedup_cons_of_not_mem'
+List.destutter_cons'
+List.destutter'_is_chain'
+List.destutter_is_chain'
+List.destutter_of_chain'
+List.drop_take_succ_join_eq_get'
+List.exists_le_of_prod_le'
+List.exists_lt_of_prod_lt'
+List.ext_get?'
+List.ext_get?_iff'
+List.filter_attach'
+List.filter_subset'
+list_foldl'
+List.foldl_eq_foldr'
+List.foldl_eq_of_comm'
+List.foldl_fixed'
+List.foldr_eq_of_comm'
+List.foldr_fixed'
+List.Forall₂.prod_le_prod'
+List.getLast_append'
+List.getLast_concat'
+List.getLast_singleton'
+List.get_reverse'
+List.get?_zipWith'
+List.inter_nil'
+List.isRotated_nil_iff'
+List.isRotated_singleton_iff'
+List.LE'
+List.left_unique_forall₂'
+List.le_maximum_of_mem'
+List.length_foldr_permutationsAux2'
+List.length_mergeSort'
+List.length_rotate'
+List.length_sublists'
+List.lookmap_id'
+List.LT'
+List.map₂Left_eq_map₂Left'
+List.map₂Right_eq_map₂Right'
+List.map_filter'
+List.map_mergeSort'
+List.map_permutations'
+List.map_permutationsAux2'
+List.measurable_prod'
+List.mem_destutter'
+List.mem_mergeSort'
+List.mem_permutations'
+List.mem_permutationsAux2'
+List.mem_sublists'
+List.minimum_le_of_mem'
+List.Nat.antidiagonal_succ'
+List.Nat.antidiagonal_succ_succ'
+List.next_cons_cons_eq'
+List.nnnorm_prod_le'
+List.nodup_sublists'
+List.norm_prod_le'
+List.not_lt_maximum_of_mem'
+List.not_lt_minimum_of_mem'
+List.ofFn_succ'
+List.Pairwise.chain'
+List.pairwise_map'
+List.Pairwise.sublists'
+List.perm_mergeSort'
+List.Perm.permutations'
+List.permutations_perm_permutations'
+List.prev_cons_cons_eq'
+List.prev_cons_cons_of_ne'
+List.prev_getLast_cons'
+List.prod_le_prod'
+List.prod_lt_prod'
+List.replicate_right_inj'
+List.replicate_succ'
+list_reverse'
+List.reverse_concat'
+List.reverse_cons'
+List.revzip_sublists'
+List.right_unique_forall₂'
+List.rotate_eq_rotate'
+List.rotate'_rotate'
+Lists'
+Lists.lt_sizeof_cons'
+Lists'.mem_of_subset'
+List.smul_prod'
+List.sorted_mergeSort'
+List.stronglyMeasurable_prod'
+List.SublistForall₂.prod_le_prod'
+List.sublists_eq_sublists'
+List.sublistsLen_sublist_sublists'
+List.sublists_perm_sublists'
+List.support_formPerm_le'
+List.support_formPerm_of_nodup'
+List.takeD_left'
+List.takeI_left'
+List.tendsto_insertNth'
+List.zipLeft_eq_zipLeft'
+List.zipRight_eq_zipRight'
+List.zipWith_swap_prod_support'
+localCohomology.moduleCat_enoughProjectives'
+Localization.algEquiv_mk'
+Localization.algEquiv_symm_mk'
+Localization.Away.mk_eq_monoidOf_mk'
+Localization.epi'
+Localization.liftOn₂_mk'
+Localization.liftOn_mk'
+Localization.localRingHom_mk'
+Localization.mk_eq_mk'
+Localization.mk_eq_mk_iff'
+Localization.mk_eq_monoidOf_mk'
+Localization.mulEquivOfQuotient_mk'
+Localization.mulEquivOfQuotient_symm_mk'
+localization_unit_isIso'
+LocalizedModule.add_assoc'
+LocalizedModule.add_comm'
+LocalizedModule.add_zero'
+LocalizedModule.algebra'
+LocalizedModule.algebraMap_mk'
+LocalizedModule.isModule'
+LocalizedModule.mul_smul'
+LocalizedModule.nsmul_succ'
+LocalizedModule.nsmul_zero'
+LocalizedModule.zero_add'
+LocallyFinite.continuous'
+LocallyFinite.continuousOn_iUnion'
+LocallyFinite.option_elim'
+LocalRing.of_surjective'
+logDeriv_id'
+lowerClosure_interior_subset'
+lp.eq_zero'
+lp.norm_le_of_forall_le'
+lp.norm_nonneg'
+lp.tsum_mul_le_mul_norm'
+LSeries.abscissaOfAbsConv_le_of_forall_lt_LSeriesSummable'
+lt_div_iff'
+lt_div_iff_mul_lt'
+lt_div_iff_of_neg'
+lt_iff_lt_of_le_iff_le'
+lt_inv'
+lt_inv_iff_mul_lt_one'
+LT.lt.ne'
+lt_mul_iff_one_lt_left'
+lt_mul_iff_one_lt_right'
+lt_mul_of_le_of_one_lt'
+lt_mul_of_lt_of_one_le'
+lt_mul_of_lt_of_one_lt'
+lt_mul_of_one_lt_left'
+lt_mul_of_one_lt_of_lt'
+lt_mul_of_one_lt_right'
+lt_of_eq_of_lt'
+lt_of_le_of_lt'
+lt_of_le_of_ne'
+lt_of_lt_of_eq'
+lt_of_lt_of_le'
+lt_of_mul_lt_mul_left'
+lt_of_mul_lt_mul_right'
+lt_of_pow_lt_pow_left'
+lt_trans'
+mabs_le'
+Magma.AssocQuotient.lift_comp_of'
+MapClusterPt.tendsto_comp'
+map_comp_div'
+map_comp_zpow'
+map_div'
+map_extChartAt_nhds'
+map_extChartAt_nhdsWithin'
+map_extChartAt_nhdsWithin_eq_image'
+map_extChartAt_symm_nhdsWithin'
+map_extChartAt_symm_nhdsWithin_range'
+map_finset_inf'
+map_finset_sup'
+map_natCast'
+map_ofNat'
+map_preNormEDS'
+mapsTo_omegaLimit'
+map_zpow'
+Mathlib.Meta.Finset.range_succ'
+Mathlib.Meta.Finset.range_zero'
+Mathlib.Meta.FunProp.StateList.toList'
+Mathlib.Meta.List.range_succ_eq_map'
+Mathlib.Meta.List.range_zero'
+Mathlib.Meta.Multiset.range_succ'
+Mathlib.Meta.Multiset.range_zero'
+Mathlib.Meta.NormNum.jacobiSymNat.qr₁'
+Mathlib.Meta.Positivity.lt_of_le_of_ne'
+Mathlib.Tactic.ComputeDegree.coeff_pow_of_natDegree_le_of_eq_ite'
+Mathlib.Tactic.ComputeDegree.degree_eq_of_le_of_coeff_ne_zero'
+Mathlib.Tactic.Group.zpow_trick_one'
+Mathlib.Tactic.Ring.atom_pf'
+Mathlib.Util.addAndCompile'
+Mathlib.Vector.eraseIdx_insertNth'
+Mathlib.Vector.prod_set'
+Mathlib.WhatsNew.mkHeader'
+Matrix.blockDiag'_blockDiagonal'
+Matrix.blockDiagonal'_apply'
+Matrix.blockDiagonal_apply'
+Matrix.blockTriangular_blockDiagonal'
+Matrix.blockTriangular_stdBasisMatrix'
+Matrix.blockTriangular_transvection'
+Matrix.cons_val'
+Matrix.cons_val_succ'
+Matrix.cons_val_zero'
+Matrix.det_apply'
+Matrix.det_units_conj'
+Matrix.det_updateColumn_smul'
+Matrix.det_updateRow_smul'
+Matrix.diagonal_apply_ne'
+Matrix.diagonal_intCast'
+Matrix.diagonal_mul_diagonal'
+Matrix.diagonal_natCast'
+Matrix.diagonal_ofNat'
+Matrix.diagonal_toLin'
+Matrix.dotProduct_diagonal'
+Matrix.dotProduct_zero'
+Matrix.empty_val'
+Matrix.exists_mulVec_eq_zero_iff'
+Matrix.exp_blockDiagonal'
+Matrix.exp_conj'
+Matrix.exp_units_conj'
+Matrix.head_val'
+Matrix.induction_on'
+Matrix.inv_pow'
+Matrix.inv_smul'
+Matrix.inv_zpow'
+Matrix.isAdjointPair_equiv'
+Matrix.ker_diagonal_toLin'
+Matrix.kronecker_assoc'
+Matrix.kroneckerTMul_assoc'
+Matrix.map_id'
+Matrix.mem_orthogonalGroup_iff'
+Matrix.mem_unitaryGroup_iff'
+Matrix.minpoly_toLin'
+Matrix.mul_apply'
+Matrix.Nondegenerate.toBilin'
+Matrix.Nondegenerate.toLinearMap₂'
+Matrix.one_apply_ne'
+Matrix.PosDef.of_toQuadraticForm'
+Matrix.PosDef.toQuadraticForm'
+Matrix.pow_inv_comm'
+Matrix.pow_sub'
+Matrix.range_toLin'
+Matrix.represents_iff'
+Matrix.tail_val'
+Matrix.toBilin'_apply'
+Matrix.toBilin'_toMatrix'
+Matrix.toLinAlgEquiv'_toMatrixAlgEquiv'
+Matrix.toLin'_apply'
+Matrix.toLinearMap₂'_apply'
+Matrix.toLinearMap₂'_toMatrix'
+Matrix.toLinearMapₛₗ₂'_toMatrix'
+Matrix.toLin'_toMatrix'
+Matrix.trace_blockDiagonal'
+Matrix.trace_mul_cycle'
+Matrix.twoBlockTriangular_det'
+Matrix.vec2_dotProduct'
+Matrix.vec3_dotProduct'
+Matrix.zero_dotProduct'
+Matrix.zpow_mul'
+Matroid.Base.exchange_base_of_indep'
+Matroid.base_restrict_iff'
+Matroid.Basis.basis'
+Matroid.basis_iff'
+Matroid.basis_iff_basis_closure_of_subset'
+Matroid.basis_restrict_iff'
+Matroid.closure_def'
+Matroid.coindep_iff_exists'
+Matroid.dual_base_iff'
+Matroid.dual_indep_iff_exists'
+Matroid.exists_basis'
+Matroid.Finitary.sum'
+Matroid.Indep.mem_closure_iff'
+Matroid.map_basis_iff'
+Matroid.mapSetEmbedding_indep_iff'
+Matroid.mem_closure_of_mem'
+Matroid.restrictSubtype_dual'
+Matroid.subset_closure_of_subset'
+Matroid.uniqueBaseOn_indep_iff'
+Matroid.uniqueBaseOn_restrict'
+max_def'
+max_div_div_left'
+max_div_div_right'
+max_div_min_eq_mabs'
+maximal_subset_iff'
+max_inv_inv'
+max_mul_mul_le_max_mul_max'
+max_rec'
+mdifferentiableWithinAt_iff'
+mdifferentiableWithinAt_inter'
+Measurable.comp'
+Measurable.comp_aemeasurable'
+Measurable.const_smul'
+Measurable.div'
+MeasurableEmbedding.withDensity_ofReal_comap_apply_eq_integral_abs_deriv_mul'
+Measurable.ennreal_tsum'
+MeasurableEquiv.withDensity_ofReal_map_symm_apply_eq_integral_abs_deriv_mul'
+measurable_findGreatest'
+measurable_from_prod_countable'
+measurable_id'
+measurable_id''
+Measurable.inf'
+Measurable.iSup'
+Measurable.lintegral_kernel_prod_left'
+Measurable.lintegral_kernel_prod_right'
+Measurable.lintegral_kernel_prod_right''
+Measurable.mul'
+measurable_of_isClosed'
+measurable_quotient_mk'
+measurable_quotient_mk''
+measurableSet_eq_fun'
+MeasurableSet.image_inclusion'
+measurableSet_le'
+measurableSet_lt'
+Measurable.sup'
+measurable_to_countable'
+measurable_tProd_elim'
+MeasureTheory.abs_toReal_measure_sub_le_measure_symmDiff'
+MeasureTheory.adapted_predictablePart'
+MeasureTheory.addContent_union'
+MeasureTheory.AECover.integrable_of_lintegral_nnnorm_bounded'
+MeasureTheory.AECover.integrable_of_lintegral_nnnorm_tendsto'
+MeasureTheory.ae_eq_comp'
+MeasureTheory.ae_eq_dirac'
+MeasureTheory.ae_eq_of_forall_setIntegral_eq_of_sigmaFinite'
+MeasureTheory.ae_eq_trim_iff_of_aeStronglyMeasurable'
+MeasureTheory.ae_lt_top'
+MeasureTheory.aemeasurable_withDensity_ennreal_iff'
+MeasureTheory.ae_restrict_iff'
+MeasureTheory.AEStronglyMeasurable.comp_ae_measurable'
+MeasureTheory.AEStronglyMeasurable.const_smul'
+MeasureTheory.AEStronglyMeasurable.convolution_integrand'
+MeasureTheory.AEStronglyMeasurable.convolution_integrand_snd'
+MeasureTheory.AEStronglyMeasurable.convolution_integrand_swap_snd'
+MeasureTheory.AEStronglyMeasurable'.of_subsingleton'
+MeasureTheory.ae_withDensity_iff'
+MeasureTheory.ae_withDensity_iff_ae_restrict'
+MeasureTheory.average_eq'
+MeasureTheory.condexp_bot'
+MeasureTheory.condexpIndL1Fin_smul'
+MeasureTheory.condexpIndL1_smul'
+MeasureTheory.condexpInd_smul'
+MeasureTheory.condexpIndSMul_smul'
+MeasureTheory.condexpL1CLM_of_aestronglyMeasurable'
+MeasureTheory.condexpL1_of_aestronglyMeasurable'
+MeasureTheory.condexp_of_aestronglyMeasurable'
+MeasureTheory.Content.innerContent_mono'
+MeasureTheory.diracProba_toMeasure_apply'
+MeasureTheory.eLpNorm_add_le'
+MeasureTheory.eLpNorm'_const'
+MeasureTheory.eLpNorm_const'
+MeasureTheory.eLpNorm_eq_eLpNorm'
+MeasureTheory.eLpNorm'_eq_zero_of_ae_zero'
+MeasureTheory.eLpNorm_indicator_const'
+MeasureTheory.eLpNorm'_le_eLpNorm'_mul_eLpNorm'
+MeasureTheory.eLpNorm_nnreal_eq_eLpNorm'
+MeasureTheory.eLpNorm_one_le_of_le'
+MeasureTheory.eLpNorm'_smul_le_mul_eLpNorm'
+MeasureTheory.eLpNorm_sub_le'
+MeasureTheory.eLpNorm'_zero'
+MeasureTheory.eLpNorm_zero'
+MeasureTheory.exp_llr_of_ac'
+MeasureTheory.exp_neg_llr'
+MeasureTheory.Filtration.stronglyMeasurable_limit_process'
+MeasureTheory.hasFiniteIntegral_congr'
+MeasureTheory.HasFiniteIntegral.congr'
+MeasureTheory.HasFiniteIntegral.mono'
+MeasureTheory.hasFiniteIntegral_prod_iff'
+MeasureTheory.HasPDF.congr'
+MeasureTheory.Ico_ae_eq_Icc'
+MeasureTheory.Ico_ae_eq_Ioc'
+MeasureTheory.Iio_ae_eq_Iic'
+MeasureTheory.inducedOuterMeasure_eq'
+MeasureTheory.inducedOuterMeasure_eq_extend'
+MeasureTheory.Integrable.add'
+MeasureTheory.Integrable.bdd_mul'
+MeasureTheory.Integrable.comp_mul_left'
+MeasureTheory.Integrable.comp_mul_right'
+MeasureTheory.integrable_congr'
+MeasureTheory.Integrable.congr'
+MeasureTheory.Integrable.const_mul'
+MeasureTheory.integrable_finset_sum'
+MeasureTheory.Integrable.mono'
+MeasureTheory.Integrable.mul_const'
+MeasureTheory.integrable_of_forall_fin_meas_le'
+MeasureTheory.Integrable.simpleFunc_mul'
+MeasureTheory.Integrable.toL1_smul'
+MeasureTheory.integrable_withDensity_iff_integrable_smul'
+MeasureTheory.integral_add'
+MeasureTheory.integral_countable'
+MeasureTheory.integral_dirac'
+MeasureTheory.integral_Icc_eq_integral_Ico'
+MeasureTheory.integral_Icc_eq_integral_Ioc'
+MeasureTheory.integral_Icc_eq_integral_Ioo'
+MeasureTheory.integral_Ici_eq_integral_Ioi'
+MeasureTheory.integral_Ico_eq_integral_Ioo'
+MeasureTheory.integral_Iic_eq_integral_Iio'
+MeasureTheory.integral_Ioc_eq_integral_Ioo'
+MeasureTheory.integral_neg'
+MeasureTheory.integral_singleton'
+MeasureTheory.integral_sub'
+MeasureTheory.integral_zero'
+MeasureTheory.Ioc_ae_eq_Icc'
+MeasureTheory.Ioi_ae_eq_Ici'
+MeasureTheory.Ioo_ae_eq_Icc'
+MeasureTheory.Ioo_ae_eq_Ico'
+MeasureTheory.Ioo_ae_eq_Ioc'
+MeasureTheory.isClosed_aeStronglyMeasurable'
+MeasureTheory.isComplete_aeStronglyMeasurable'
+MeasureTheory.IsFundamentalDomain.integral_eq_tsum'
+MeasureTheory.IsFundamentalDomain.integral_eq_tsum''
+MeasureTheory.IsFundamentalDomain.lintegral_eq_tsum'
+MeasureTheory.IsFundamentalDomain.lintegral_eq_tsum''
+MeasureTheory.IsFundamentalDomain.measure_eq_tsum'
+MeasureTheory.IsFundamentalDomain.setIntegral_eq_tsum'
+MeasureTheory.IsFundamentalDomain.setLIntegral_eq_tsum'
+MeasureTheory.IsStoppingTime.measurableSet_eq'
+MeasureTheory.IsStoppingTime.measurableSet_eq_of_countable'
+MeasureTheory.IsStoppingTime.measurableSet_eq_of_countable_range'
+MeasureTheory.IsStoppingTime.measurableSet_ge'
+MeasureTheory.IsStoppingTime.measurableSet_ge_of_countable'
+MeasureTheory.IsStoppingTime.measurableSet_ge_of_countable_range'
+MeasureTheory.IsStoppingTime.measurableSet_gt'
+MeasureTheory.IsStoppingTime.measurableSet_le'
+MeasureTheory.IsStoppingTime.measurableSet_lt'
+MeasureTheory.IsStoppingTime.measurableSet_lt_of_countable'
+MeasureTheory.IsStoppingTime.measurableSet_lt_of_countable_range'
+MeasureTheory.IsStoppingTime.measurableSpace_le'
+MeasureTheory.L1.norm_setToL1_le'
+MeasureTheory.L1.norm_setToL1_le_mul_norm'
+MeasureTheory.L1.setToL1_add_left'
+MeasureTheory.L1.setToL1_congr_left'
+MeasureTheory.L1.setToL1_eq_setToL1'
+MeasureTheory.L1.setToL1_mono_left'
+MeasureTheory.L1.setToL1_smul_left'
+MeasureTheory.L1.setToL1_zero_left'
+MeasureTheory.L1.SimpleFunc.norm_setToL1SCLM_le'
+MeasureTheory.L1.SimpleFunc.setToL1S_add_left'
+MeasureTheory.L1.SimpleFunc.setToL1SCLM_add_left'
+MeasureTheory.L1.SimpleFunc.setToL1SCLM_congr_left'
+MeasureTheory.L1.SimpleFunc.setToL1SCLM_mono_left'
+MeasureTheory.L1.SimpleFunc.setToL1SCLM_smul_left'
+MeasureTheory.L1.SimpleFunc.setToL1SCLM_zero_left'
+MeasureTheory.L1.SimpleFunc.setToL1S_mono_left'
+MeasureTheory.L1.SimpleFunc.setToL1S_smul_left'
+MeasureTheory.L1.SimpleFunc.setToL1S_zero_left'
+MeasureTheory.L2.add_left'
+MeasureTheory.L2.norm_sq_eq_inner'
+MeasureTheory.L2.smul_left'
+MeasureTheory.laverage_eq'
+MeasureTheory.lintegral_add_left'
+MeasureTheory.lintegral_add_right'
+MeasureTheory.lintegral_const_mul'
+MeasureTheory.lintegral_const_mul''
+MeasureTheory.lintegral_count'
+MeasureTheory.lintegral_countable'
+MeasureTheory.lintegral_dirac'
+MeasureTheory.lintegral_eq_zero_iff'
+MeasureTheory.lintegral_finset_sum'
+MeasureTheory.lintegral_iInf'
+MeasureTheory.lintegral_map'
+MeasureTheory.lintegral_mono'
+MeasureTheory.lintegral_mono_fn'
+MeasureTheory.lintegral_mono_set'
+MeasureTheory.lintegral_mul_const'
+MeasureTheory.lintegral_mul_const''
+MeasureTheory.lintegral_rpow_nnnorm_eq_rpow_eLpNorm'
+MeasureTheory.lintegral_singleton'
+MeasureTheory.lintegral_sub'
+MeasureTheory.lintegral_sub_le'
+MeasureTheory.lmarginal_union'
+MeasureTheory.locallyIntegrable_finset_sum'
+MeasureTheory.lowerCrossingTime_stabilize'
+MeasureTheory.Lp.ae_tendsto_of_cauchy_eLpNorm'
+MeasureTheory.Lp.eLpNorm'_lim_le_liminf_eLpNorm'
+MeasureTheory.Lp.eLpNorm'_sum_norm_sub_le_tsum_of_cauchy_eLpNorm'
+MeasureTheory.lpMeas.aeStronglyMeasurable'
+MeasureTheory.Lp.norm_const'
+MeasureTheory.Lp.simpleFunc.eq'
+MeasureTheory.Lp.tendsto_Lp_iff_tendsto_ℒp'
+MeasureTheory.Lp.tendsto_Lp_iff_tendsto_ℒp''
+MeasureTheory.measurableSet_filtrationOfSet'
+MeasureTheory.measurableSet_sigmaFiniteSetWRT'
+MeasureTheory.Measure.ae_sum_iff'
+MeasureTheory.Measure.bind_zero_right'
+MeasureTheory.Measure.count_apply_eq_top'
+MeasureTheory.Measure.count_apply_finite'
+MeasureTheory.Measure.count_apply_finset'
+MeasureTheory.Measure.count_apply_lt_top'
+MeasureTheory.Measure.count_eq_zero_iff'
+MeasureTheory.Measure.count_injective_image'
+MeasureTheory.Measure.count_ne_zero'
+MeasureTheory.Measure.count_ne_zero''
+MeasureTheory.Measure.count_singleton'
+MeasureTheory.measure_diff'
+MeasureTheory.measure_diff_null'
+MeasureTheory.Measure.dirac_apply'
+MeasureTheory.Measure.empty_of_count_eq_zero'
+MeasureTheory.Measure.ext_iff'
+MeasureTheory.Measure.haveLebesgueDecompositionSMul'
+MeasureTheory.Measure.InnerRegularWRT.map'
+MeasureTheory.Measure.integral_toReal_rnDeriv'
+MeasureTheory.measure_inter_conull'
+MeasureTheory.Measure.inv_rnDeriv'
+MeasureTheory.measure_iUnion_null_iff'
+MeasureTheory.Measure.LebesgueDecomposition.iSup_mem_measurableLE'
+MeasureTheory.Measure.LebesgueDecomposition.iSup_monotone'
+MeasureTheory.Measure.le_iff'
+MeasureTheory.Measure.lt_iff'
+MeasureTheory.Measure.map_id'
+MeasureTheory.Measure.measurable_bind'
+MeasureTheory.Measure.MeasureDense.nonempty'
+MeasureTheory.Measure.nonpos_iff_eq_zero'
+MeasureTheory.Measure.pi_noAtoms'
+MeasureTheory.MeasurePreserving.integral_comp'
+MeasureTheory.Measure.restrict_apply₀'
+MeasureTheory.Measure.restrict_apply_eq_zero'
+MeasureTheory.Measure.restrict_restrict'
+MeasureTheory.Measure.restrict_restrict₀'
+MeasureTheory.Measure.restrict_singleton'
+MeasureTheory.Measure.restrict_union'
+MeasureTheory.Measure.restrict_union_add_inter'
+MeasureTheory.Measure.rnDeriv_mul_rnDeriv'
+MeasureTheory.Measure.rnDeriv_pos'
+MeasureTheory.Measure.setIntegral_toReal_rnDeriv'
+MeasureTheory.Measure.setIntegral_toReal_rnDeriv_eq_withDensity'
+MeasureTheory.Measure.setLIntegral_rnDeriv'
+MeasureTheory.Measure.sum_apply_eq_zero'
+MeasureTheory.Measure.toSphere_apply'
+MeasureTheory.Measure.toSphere_apply_univ'
+MeasureTheory.measure_union'
+MeasureTheory.measure_union₀'
+MeasureTheory.measure_union_add_inter'
+MeasureTheory.measure_union_add_inter₀'
+MeasureTheory.memℒp_finset_sum'
+MeasureTheory.Memℒp.integrable_norm_rpow'
+MeasureTheory.Memℒp.meas_ge_lt_top'
+MeasureTheory.mem_lpMeas_iff_aeStronglyMeasurable'
+MeasureTheory.mem_lpMeasSubgroup_iff_aeStronglyMeasurable'
+MeasureTheory.Memℒp.mono'
+MeasureTheory.norm_indicatorConstLp'
+MeasureTheory.norm_setIntegral_le_of_norm_le_const'
+MeasureTheory.norm_setIntegral_le_of_norm_le_const_ae'
+MeasureTheory.norm_setIntegral_le_of_norm_le_const_ae''
+MeasureTheory.norm_setToFun_le'
+MeasureTheory.norm_setToFun_le_mul_norm'
+MeasureTheory.NullMeasurable.measurable'
+MeasureTheory.OuterMeasure.empty'
+MeasureTheory.OuterMeasure.isCaratheodory_iff_le'
+MeasureTheory.OuterMeasure.iUnion_null_iff'
+MeasureTheory.OuterMeasure.le_boundedBy'
+MeasureTheory.OuterMeasure.mono'
+MeasureTheory.OuterMeasure.mono''
+MeasureTheory.OuterMeasure.top_apply'
+MeasureTheory.OuterMeasure.trim_eq_iInf'
+MeasureTheory.pdf.eq_of_map_eq_withDensity'
+MeasureTheory.pdf.quasiMeasurePreserving_hasPDF'
+MeasureTheory.piPremeasure_pi'
+MeasureTheory.ProbabilityMeasure.tendsto_measure_of_null_frontier_of_tendsto'
+MeasureTheory.ProgMeasurable.finset_prod'
+MeasureTheory.progMeasurable_of_tendsto'
+MeasureTheory.restrict_dirac'
+MeasureTheory.restrict_withDensity'
+MeasureTheory.setAverage_eq'
+MeasureTheory.setIntegral_dirac'
+MeasureTheory.setIntegral_tilted'
+MeasureTheory.setLaverage_eq'
+MeasureTheory.setLIntegral_dirac'
+MeasureTheory.setLIntegral_eq_zero_iff'
+MeasureTheory.setLIntegral_mono'
+MeasureTheory.setLIntegral_mono_ae'
+MeasureTheory.setLIntegral_tilted'
+MeasureTheory.setLIntegral_withDensity_eq_lintegral_mul₀'
+MeasureTheory.setLIntegral_withDensity_eq_setLIntegral_mul_non_measurable₀'
+MeasureTheory.setToFun_add_left'
+MeasureTheory.setToFun_congr_left'
+MeasureTheory.setToFun_finset_sum'
+MeasureTheory.setToFun_measure_zero'
+MeasureTheory.setToFun_mono_left'
+MeasureTheory.setToFun_smul_left'
+MeasureTheory.setToFun_zero_left'
+MeasureTheory.sigmaFinite_restrict_sigmaFiniteSetWRT'
+MeasureTheory.SigmaFinite.withDensity_of_ne_top'
+MeasureTheory.SignedMeasure.eq_singularPart'
+MeasureTheory.SignedMeasure.exists_subset_restrict_nonpos'
+MeasureTheory.SignedMeasure.haveLebesgueDecomposition_mk'
+MeasureTheory.SignedMeasure.restrictNonposSeq_disjoint'
+MeasureTheory.SignedMeasure.someExistsOneDivLT_subset'
+MeasureTheory.SimpleFunc.extend_apply'
+MeasureTheory.SimpleFunc.extend_comp_eq'
+MeasureTheory.SimpleFunc.lintegral_eq_of_subset'
+MeasureTheory.SimpleFunc.lintegral_map'
+MeasureTheory.SimpleFunc.setToSimpleFunc_add_left'
+MeasureTheory.SimpleFunc.setToSimpleFunc_congr'
+MeasureTheory.SimpleFunc.setToSimpleFunc_const'
+MeasureTheory.SimpleFunc.setToSimpleFunc_mono_left'
+MeasureTheory.SimpleFunc.setToSimpleFunc_nonneg'
+MeasureTheory.SimpleFunc.setToSimpleFunc_smul_left'
+MeasureTheory.SimpleFunc.setToSimpleFunc_zero'
+MeasureTheory.SimpleFunc.simpleFunc_bot'
+MeasureTheory.stoppedProcess_eq'
+MeasureTheory.stoppedProcess_eq''
+MeasureTheory.stoppedValue_eq'
+MeasureTheory.stoppedValue_piecewise_const'
+MeasureTheory.stoppedValue_sub_eq_sum'
+MeasureTheory.StronglyMeasurable.aeStronglyMeasurable'
+MeasureTheory.StronglyMeasurable.const_smul'
+MeasureTheory.StronglyMeasurable.integral_kernel_prod_left'
+MeasureTheory.StronglyMeasurable.integral_kernel_prod_left''
+MeasureTheory.StronglyMeasurable.integral_kernel_prod_right'
+MeasureTheory.StronglyMeasurable.integral_kernel_prod_right''
+MeasureTheory.Submartingale.stoppedValue_leastGE_eLpNorm_le'
+MeasureTheory.Subsingleton.aestronglyMeasurable'
+MeasureTheory.Subsingleton.stronglyMeasurable'
+MeasureTheory.TendstoInMeasure.congr'
+MeasureTheory.TendstoInMeasure.exists_seq_tendsto_ae'
+MeasureTheory.tendsto_sum_indicator_atTop_iff'
+MeasureTheory.tilted_apply'
+MeasureTheory.tilted_apply_eq_ofReal_integral'
+MeasureTheory.tilted_const'
+MeasureTheory.tilted_neg_same'
+MeasureTheory.tilted_zero'
+MeasureTheory.upcrossingsBefore_zero'
+MeasureTheory.upperCrossingTime_stabilize'
+MeasureTheory.upperCrossingTime_zero'
+MeasureTheory.VectorMeasure.ext_iff'
+MeasureTheory.VectorMeasure.le_iff'
+MeasureTheory.weightedSMul_union'
+MeasureTheory.withDensity_apply'
+MeasureTheory.withDensity_apply_eq_zero'
+MeasureTheory.withDensity_smul'
+MeasureTheory.withDensityᵥ_add'
+MeasureTheory.withDensityᵥ_neg'
+MeasureTheory.withDensityᵥ_smul'
+MeasureTheory.withDensityᵥ_smul_eq_withDensityᵥ_withDensity'
+MeasureTheory.withDensityᵥ_sub'
+MeasureTheory.zero_mem_ℒp'
+mem_ball_iff_norm''
+mem_ball_iff_norm'''
+mem_closedBall_iff_norm''
+mem_closedBall_iff_norm'''
+mem_closure_iff_nhds'
+mem_closure_iff_nhds_basis'
+mem_coclosed_Lindelof'
+mem_codiscrete'
+mem_coLindelof'
+memℓp_gen'
+mem_nhds_prod_iff'
+mem_pairSelfAdjointMatricesSubmodule'
+mem_rootsOfUnity'
+mem_rootsOfUnity_prime_pow_mul_iff'
+mem_selfAdjointMatricesSubmodule'
+mem_skewAdjointMatricesSubmodule'
+mem_sphere_iff_norm'
+Metric.ball_eq_ball'
+Metric.ball_subset_ball'
+Metric.closedBall_subset_ball'
+Metric.closedBall_subset_closedBall'
+Metric.closedBall_zero'
+Metric.continuousAt_iff'
+Metric.continuous_iff'
+Metric.continuousOn_iff'
+Metric.continuousWithinAt_iff'
+Metric.cthickening_eq_iInter_cthickening'
+Metric.cthickening_eq_iInter_thickening'
+Metric.cthickening_eq_iInter_thickening''
+Metric.mem_ball'
+Metric.mem_closedBall'
+Metric.mem_of_closed'
+Metric.mem_sphere'
+midpoint_eq_iff'
+min_def'
+min_div_div_left'
+min_div_div_right'
+minimal_subset_iff'
+min_inv_inv'
+min_mul_distrib'
+min_mul_min_le_min_mul_mul'
+minpoly.dvd_map_of_isScalarTower'
+minpoly.eq_X_sub_C'
+minpoly.unique'
+min_rec'
+Miu.le_pow2_and_pow2_eq_mod3'
+mk_eq_mk_of_basis'
+Mod_.comp_hom'
+Mod_.id_hom'
+ModularCyclotomicCharacter.toFun_spec'
+ModularCyclotomicCharacter.toFun_spec''
+ModularCyclotomicCharacter.toFun_unique'
+Module.Baer.ExtensionOfMaxAdjoin.extendIdealTo_wd'
+ModuleCat.CoextendScalars.smul_apply'
+ModuleCat.hasLimits'
+ModuleCat.restrictScalars.smul_def'
+Module.End_algebraMap_isUnit_inv_apply_eq_iff'
+Module.End.smulCommClass'
+Module.free_of_finite_type_torsion_free'
+Module.Free.of_subsingleton'
+Module.mem_support_iff'
+Module.not_mem_support_iff'
+Module.projective_def'
+Monad.mapM'
+Monad.sequence'
+Mon_.comp_hom'
+Mon_.id_hom'
+MonoidAlgebra.lift_apply'
+MonoidAlgebra.lift_unique'
+Monoid.CoprodI.lift_comp_of'
+Monoid.CoprodI.lift_of'
+Monoid.Coprod.induction_on'
+Monoid.exponent_eq_iSup_orderOf'
+Monoid.exponent_min'
+MonoidHom.coe_toAdditive'
+MonoidHom.coe_toAdditive''
+MonoidHom.comap_bot'
+MonoidHom.map_zpow'
+MonoidHom.prod_map_comap_prod'
+Monoid.PushoutI.NormalWord.base_smul_def'
+Monoid.PushoutI.NormalWord.summand_smul_def'
+Monotone.const_mul'
+Monotone.mul_const'
+MonotoneOn.const_mul'
+MonotoneOn.mul_const'
+MulActionHom.comp_inverse'
+MulActionHom.inverse_eq_inverse'
+MulActionHom.inverse'_inverse'
+MulAction.mem_fixedPoints'
+MulAction.mem_stabilizer_finset'
+MulAction.mem_stabilizer_set'
+MulAction.orbitRel.quotient_eq_of_quotient_subgroup_eq'
+MulAction.orbitRel.Quotient.mem_subgroup_orbit_iff'
+MulAction.orbitZPowersEquiv_symm_apply'
+MulAction.Quotient.coe_smul_out'
+MulAction.Quotient.mk_smul_out'
+MulAction.right_quotientAction'
+MulChar.star_apply'
+mul_div_assoc'
+mul_div_cancel_of_imp'
+mul_eq_mul_iff_eq_and_eq_of_pos'
+mul_eq_of_eq_div'
+mul_eq_one'
+MulEquiv.mk_coe'
+MulHom.prod_map_comap_prod'
+mul_inv_le_iff'
+mul_inv_le_iff_le_mul'
+mul_inv_le_mul_inv_iff'
+mul_inv_lt_iff'
+mul_inv_lt_iff_le_mul'
+mul_inv_lt_mul_inv_iff'
+mul_invOf_cancel_left'
+mul_invOf_cancel_right'
+mul_invOf_self'
+mul_left_cancel''
+mul_left_inj'
+mul_le_iff_le_one_left'
+mul_le_iff_le_one_right'
+mul_le_mul'
+mul_le_mul_left'
+mul_le_mul_of_nonneg'
+mul_le_mul_of_nonneg_of_nonpos'
+mul_le_mul_of_nonpos_of_nonneg'
+mul_le_mul_of_nonpos_of_nonpos'
+mul_le_mul_right'
+mul_le_of_le_of_le_one'
+mul_le_of_le_one_left'
+mul_le_of_le_one_of_le'
+mul_le_of_le_one_right'
+mul_lt_iff_lt_one_left'
+mul_lt_iff_lt_one_right'
+mul_lt_mul_left'
+mul_lt_mul_of_pos'
+mul_lt_mul_right'
+mul_lt_of_le_of_lt_one'
+mul_lt_of_le_one_of_lt'
+mul_lt_of_lt_of_le_one'
+mul_lt_of_lt_of_lt_one'
+mul_lt_of_lt_one_left'
+mul_lt_of_lt_one_of_le'
+mul_lt_of_lt_one_of_lt'
+mul_lt_of_lt_one_right'
+mul_ne_one'
+mul_right_cancel''
+mul_right_inj'
+mul_rotate'
+MulSemiringActionHom.coe_fn_coe'
+MultilinearMap.mkContinuousLinear_norm_le'
+MultilinearMap.mkContinuousMultilinear_norm_le'
+Multipliable.sigma'
+Multiplicative.isometricSMul'
+Multiplicative.isometricVAdd''
+multiplicity.is_greatest'
+multiplicity.mul'
+multiplicity.pow'
+multiplicity.unique'
+Multiset.add_le_add_iff_left'
+Multiset.aemeasurable_prod'
+Multiset.aestronglyMeasurable_prod'
+Multiset.antidiagonal_coe'
+Multiset.attach_map_val'
+Multiset.count_sum'
+Multiset.dedup_subset'
+Multiset.ext'
+Multiset.extract_gcd'
+Multiset.filter_attach'
+Multiset.filter_eq'
+Multiset.foldl_induction'
+Multiset.foldr_induction'
+Multiset.induction_on'
+Multiset.map_const'
+Multiset.map_filter'
+Multiset.map_id'
+Multiset.measurable_prod'
+Multiset.Nat.antidiagonal_succ'
+Multiset.Nat.antidiagonal_succ_succ'
+Multiset.noncommProd_cons'
+Multiset.powersetAux_perm_powersetAux'
+Multiset.powersetCard_coe'
+Multiset.powerset_coe'
+Multiset.prod_hom'
+Multiset.prod_lt_prod'
+Multiset.prod_lt_prod_of_nonempty'
+Multiset.prod_map_inv'
+Multiset.prod_X_add_C_coeff'
+Multiset.quot_mk_to_coe'
+Multiset.quot_mk_to_coe''
+Multiset.revzip_powersetAux'
+Multiset.revzip_powersetAux_perm_aux'
+Multiset.smul_prod'
+Multiset.stronglyMeasurable_prod'
+Multiset.subset_dedup'
+MvFunctor.f'
+MvFunctor.g'
+MvFunctor.id_map'
+MvPFunctor.liftP_iff'
+MvPFunctor.M.bisim'
+MvPFunctor.M.dest_corec'
+MvPFunctor.M.dest'_eq_dest'
+MvPFunctor.M.dest_eq_dest'
+MvPFunctor.wDest'_wMk'
+MvPolynomial.aeval_zero'
+MvPolynomial.algHom_ext'
+MvPolynomial.C_mul'
+MvPolynomial.coeff_monomial_mul'
+MvPolynomial.coeff_mul_monomial'
+MvPolynomial.coeff_mul_X'
+MvPolynomial.coeff_X'
+MvPolynomial.coeff_X_mul'
+MvPolynomial.degrees_X'
+MvPolynomial.eval₂_eq'
+MvPolynomial.eval₂Hom_congr'
+MvPolynomial.eval₂Hom_X'
+MvPolynomial.eval₂Hom_zero'
+MvPolynomial.eval_eq'
+MvPolynomial.eval_eq_eval_mv_eval'
+MvPolynomial.eval_zero'
+MvPolynomial.finSuccEquiv_support'
+MvPolynomial.homogeneousComponent_eq_zero'
+MvPolynomial.isLocalization_C_mk'
+MvPolynomial.monomial_zero'
+MvPolynomial.support_esymm'
+MvPolynomial.support_esymm''
+MvPolynomial.weightedHomogeneousComponent_eq_zero'
+MvPowerSeries.algebraMap_apply'
+MvPowerSeries.algebraMap_apply''
+MvPowerSeries.invOfUnit_eq'
+MvQPF.Cofix.dest_corec'
+MvQPF.liftR_map_last'
+MvQPF.recF_eq'
+MvQPF.wEquiv.abs'
+Nat.add_descFactorial_eq_ascFactorial'
+Nat.ascFactorial_eq_factorial_mul_choose'
+Nat.bit_add'
+Nat.card_eq_two_iff'
+Nat.cauchy_induction'
+Nat.choose_eq_asc_factorial_div_factorial'
+Nat.choose_succ_succ'
+Nat.coprime_of_dvd'
+Nat.count_add'
+Nat.count_succ'
+Nat.decreasingInduction_succ'
+Nat.digits_def'
+Nat.digits_zero_succ'
+Nat.dist_tri_left'
+Nat.dist_tri_right'
+Nat.div_add_mod'
+Nat.div_le_of_le_mul'
+Nat.div_le_self'
+Nat.div_lt_iff_lt_mul'
+Nat.dvd_sub'
+Nat.eq_sqrt'
+Nat.eq_sub_of_add_eq'
+Nat.equivProdNatFactoredNumbers_apply'
+Nat.equivProdNatSmoothNumbers_apply'
+Nat.even_add'
+Nat.even_or_odd'
+Nat.even_pow'
+Nat.even_sub'
+Nat.even_xor_odd'
+Nat.exists_mul_self'
+Nat.factorial_inj'
+Nat.find_min'
+Nat.floor_eq_iff'
+Nat.floor_eq_on_Ico'
+Nat.floor_lt'
+Nat.Icc_eq_range'
+Nat.Ico_eq_range'
+Nat.iInf_le_succ'
+Nat.iInf_lt_succ'
+Nat.Ioc_eq_range'
+Nat.Ioo_eq_range'
+Nat.iSup_le_succ'
+Nat.iSup_lt_succ'
+Nat.le_div_iff_mul_le'
+Nat.le_floor_iff'
+Nat.le_minFac'
+Nat.le_nth_count'
+Nat.leRecOn_succ'
+Nat.leRec_succ'
+Nat.le_sqrt'
+Nat.log_eq_one_iff'
+Nat.lt_sub_iff_add_lt'
+Nat.lt_succ_sqrt'
+Nat.mem_primeFactorsList'
+Nat.mod_add_div'
+Nat.ModEq.add_left_cancel'
+Nat.ModEq.add_right_cancel'
+Nat.ModEq.cancel_left_div_gcd'
+Nat.ModEq.cancel_right_div_gcd'
+Nat.modEq_list_prod_iff'
+Nat.ModEq.mul_left'
+Nat.ModEq.mul_left_cancel_iff'
+Nat.ModEq.mul_right'
+Nat.ModEq.mul_right_cancel_iff'
+Nat.monotone_primeCounting'
+Nat.mul_add_mod'
+Nat.mul_div_cancel_left'
+nat_mul_inj'
+Nat.mul_lt_mul''
+Nat.not_exists_sq'
+Nat.not_prime_mul'
+Nat.nth_le_nth'
+Nat.nth_lt_nth'
+Nat.odd_add'
+Nat.odd_sub'
+Nat.ofDigits_modEq'
+Nat.ofDigits_zmodeq'
+Nat.one_le_pow'
+Nat.one_lt_pow'
+Nat.one_lt_two_pow'
+Nat.pair_unpair'
+Nat.Partrec.Code.encode_lt_rfind'
+Nat.Partrec.Code.rec_prim'
+Nat.Partrec'.comp'
+Nat.Partrec.merge'
+Nat.Partrec.prec'
+Nat.Partrec.rfind'
+Nat.pow_lt_ascFactorial'
+Nat.pow_sub_lt_descFactorial'
+Nat.prime_def_lt'
+Nat.prime_def_lt''
+Nat.Prime.eq_two_or_odd'
+Nat.primeFactorsList_chain'
+Nat.Prime.not_prime_pow'
+Nat.Prime.one_lt'
+Nat.Primrec.casesOn'
+Nat.Primrec'.comp'
+Nat.Primrec'.prec'
+Nat.Primrec.swap'
+Nat.prod_divisorsAntidiagonal'
+Nat.rfind_dom'
+Nat.rfind_min'
+Nat.sInf_add'
+Nat.size_shiftLeft'
+Nat.sq_mul_squarefree_of_pos'
+Nat.sqrt_add_eq'
+Nat.sqrt_eq'
+Nat.sqrt_le'
+Nat.sqrt_lt'
+Nat.sqrt_mul_sqrt_lt_succ'
+Nat.sub_eq_of_eq_add'
+Nat.sub_lt_iff_lt_add'
+Nat.succ_le_succ_sqrt'
+Nat.succ_pos'
+Nat.sum_totient'
+Nat.surjective_primeCounting'
+Nat.tendsto_primeCounting'
+Nat.uIcc_eq_range'
+Ne.bot_lt'
+neg_div'
+neg_gcd'
+neg_of_smul_neg_left'
+neg_of_smul_neg_right'
+neg_pow'
+Ne.lt_of_le'
+Ne.lt_top'
+ne_of_irrefl'
+ne_of_ne_of_eq'
+newton_seq_dist_tendsto'
+NeZero.ne'
+NeZero.of_gt'
+ne_zero_of_irreducible_X_pow_sub_C'
+nhds_basis_Ioo'
+nhds_basis_uniformity'
+nhds_def'
+nhds_eq_comap_uniformity'
+nhds_eq_uniformity'
+nhds_left'_sup_nhds_right'
+nhds_left_sup_nhds_right'
+nhds_one_symm'
+nhdsWithin_eq_nhdsWithin'
+nhdsWithin_extChartAt_target_eq'
+nhdsWithin_Ici_basis'
+nhdsWithin_Ici_eq'
+nhdsWithin_Ici_eq''
+nhdsWithin_Iic_basis'
+nhdsWithin_Iic_eq'
+nhdsWithin_Iic_eq''
+nhdsWithin_Iio_basis'
+nhdsWithin_Iio_neBot'
+nhdsWithin_Iio_self_neBot'
+nhdsWithin_inter'
+nhdsWithin_inter_of_mem'
+nhdsWithin_Ioi_basis'
+nhdsWithin_Ioi_neBot'
+nhdsWithin_Ioi_self_neBot'
+nhdsWithin_pi_eq'
+nhdsWithin_restrict'
+nhdsWithin_restrict''
+nndist_eq_nnnorm_vsub'
+nndist_midpoint_midpoint_le'
+nndist_nnnorm_nnnorm_le'
+nnnorm_algebraMap'
+nnnorm_eq_zero'
+nnnorm_inv'
+nnnorm_le_nnnorm_add_nnnorm_div'
+nnnorm_le_pi_nnnorm'
+nnnorm_mul_le'
+nnnorm_ne_zero_iff'
+nnnorm_one'
+nnnorm_pos'
+NNRat.instSMulCommClass'
+NNReal.ball_zero_eq_Ico'
+NNReal.closedBall_zero_eq_Icc'
+NNReal.div_le_iff'
+NNReal.div_le_of_le_mul'
+NNReal.div_lt_iff'
+NNReal.inner_le_Lp_mul_Lq_tsum'
+NNReal.le_div_iff'
+NNReal.list_prod_map_rpow'
+NNReal.Lp_add_le_tsum'
+NNReal.lt_div_iff'
+NNReal.nndist_zero_eq_val'
+NNReal.rpow_add'
+NNReal.rpow_add_intCast'
+NNReal.rpow_add_natCast'
+NNReal.rpow_add_one'
+NNReal.rpow_one_add'
+NNReal.rpow_one_sub'
+NNReal.rpow_sub'
+NNReal.rpow_sub_intCast'
+NNReal.rpow_sub_natCast'
+NNReal.rpow_sub_one'
+NNReal.tendsto_coe'
+NonUnitalAlgHom.coe_inverse'
+NonUnitalAlgHom.coe_restrictScalars'
+NonUnitalStarAlgebra.adjoin_induction'
+NonUnitalStarAlgHom.coe_mk'
+NonUnitalStarAlgHom.coe_restrictScalars'
+NonUnitalStarSubalgebra.instIsScalarTower'
+NonUnitalStarSubalgebra.instSMulCommClass'
+NonUnitalStarSubalgebra.module'
+NonUnitalSubalgebra.instIsScalarTower'
+NonUnitalSubalgebra.instModule'
+NonUnitalSubalgebra.instSMulCommClass'
+NonUnitalSubring.coe_mk'
+NonUnitalSubring.eq_top_iff'
+NonUnitalSubring.mem_mk'
+NonUnitalSubsemiring.coe_mk'
+NonUnitalSubsemiring.eq_top_iff'
+NonUnitalSubsemiring.mem_mk'
+normalClosure_eq_iSup_adjoin'
+norm_algebraMap'
+NormedAddCommGroup.cauchy_series_of_le_geometric'
+NormedAddCommGroup.cauchy_series_of_le_geometric''
+NormedAddGroupHom.coe_mkNormedAddGroupHom'
+NormedAddGroupHom.completion_coe'
+NormedAddGroupHom.norm_comp_le_of_le'
+NormedRing.inverse_one_sub_nth_order'
+NormedSpace.exp_conj'
+NormedSpace.expSeries_apply_eq'
+NormedSpace.expSeries_apply_eq_div'
+NormedSpace.exp_series_hasSum_exp'
+NormedSpace.expSeries_hasSum_exp_of_mem_ball'
+NormedSpace.expSeries_summable'
+NormedSpace.expSeries_summable_of_mem_ball'
+NormedSpace.exp_units_conj'
+NormedSpace.isVonNBounded_iff'
+NormedSpace.norm_expSeries_summable'
+NormedSpace.norm_expSeries_summable_of_mem_ball'
+norm_eq_of_mem_sphere'
+norm_eq_zero''
+norm_eq_zero'''
+norm_inv'
+norm_le_norm_add_const_of_dist_le'
+norm_le_norm_add_norm_div'
+norm_le_of_mem_closedBall'
+norm_le_pi_norm'
+norm_le_zero_iff''
+norm_le_zero_iff'''
+norm_lt_of_mem_ball'
+norm_ne_zero_iff'
+norm_nonneg'
+norm_of_subsingleton'
+norm_one'
+norm_pos_iff''
+norm_pos_iff'''
+norm_sub_norm_le'
+norm_toNNReal'
+not_dvd_index_sylow'
+not_lt_zero'
+not_mem_of_lt_csInf'
+npow_mul'
+nsmul_eq_mul'
+nullMeasurableSet_lt'
+Num.add_ofNat'
+NumberField.InfinitePlace.orbitRelEquiv_apply_mk''
+NumberField.mixedEmbedding.convexBodySumFun_apply'
+NumberField.mixedEmbedding.norm_eq_zero_iff'
+NumberField.Units.regulator_eq_det'
+Num.cast_sub'
+Num.cast_succ'
+Num.cast_zero'
+Num.mem_ofZNum'
+Num.of_to_nat'
+Num.succ_ofInt'
+odd_add_one_self'
+odd_add_self_one'
+ofReal_norm_eq_coe_nnnorm'
+OmegaCompletePartialOrder.const_continuous'
+OmegaCompletePartialOrder.ContinuousHom.bind_continuous'
+OmegaCompletePartialOrder.ContinuousHom.forall_forall_merge'
+OmegaCompletePartialOrder.ContinuousHom.ite_continuous'
+OmegaCompletePartialOrder.ContinuousHom.map_continuous'
+OmegaCompletePartialOrder.ContinuousHom.seq_continuous'
+OmegaCompletePartialOrder.Continuous.of_bundled'
+OmegaCompletePartialOrder.flip₁_continuous'
+OmegaCompletePartialOrder.flip₂_continuous'
+OmegaCompletePartialOrder.id_continuous'
+OmegaCompletePartialOrder.ScottContinuous.continuous'
+one_le_div'
+one_le_finprod'
+one_le_pow_of_one_le'
+one_le_thickenedIndicator_apply'
+one_le_two'
+one_lt_div'
+one_lt_finprod'
+one_lt_pow'
+one_lt_zpow'
+one_ne_zero'
+OnePoint.continuousAt_infty'
+OnePoint.isOpen_iff_of_mem'
+OnePoint.tendsto_nhds_infty'
+ONote.exists_lt_mul_omega0'
+ONote.exists_lt_omega0_opow'
+ONote.fastGrowing_zero'
+ONote.NF.below_of_lt'
+ONote.nf_repr_split'
+ONote.NF.snd'
+ONote.split_eq_scale_split'
+IsOpenEmbedding.tendsto_nhds_iff'
+openSegment_eq_image'
+openSegment_eq_Ioo'
+Option.bind_congr'
+Option.bind_eq_bind'
+Option.bind_eq_some'
+Option.guard_eq_some'
+Option.map_bind'
+Option.map_coe'
+Option.none_bind'
+Option.none_orElse'
+Option.orElse_eq_none'
+Option.orElse_eq_some'
+Option.orElse_none'
+Option.some_bind'
+Option.some_orElse'
+or_congr_left'
+or_congr_right'
+OrderDual.continuousConstSMul'
+OrderDual.instDistribMulAction'
+OrderDual.instDistribSMul'
+OrderDual.instIsScalarTower'
+OrderDual.instIsScalarTower''
+OrderDual.instModule'
+OrderDual.instMulAction'
+OrderDual.instMulActionWithZero'
+OrderDual.instPow'
+OrderDual.instSMulCommClass'
+OrderDual.instSMulCommClass''
+OrderDual.instSMulWithZero'
+Order.height_le_iff'
+Order.Ideal.IsMaximal.isCoatom'
+OrderIso.isGLB_image'
+OrderIso.isGLB_preimage'
+OrderIso.isLUB_image'
+OrderIso.isLUB_preimage'
+OrderIso.map_bot'
+OrderIso.map_csInf'
+OrderIso.map_csSup'
+OrderIso.map_top'
+OrderIso.subsingleton_of_wellFoundedGT'
+OrderIso.subsingleton_of_wellFoundedLT'
+Order.isPredPrelimitRecOn_pred'
+Order.isSuccPrelimitRecOn_succ'
+Order.not_isPredPrelimit_iff'
+Order.not_isSuccPrelimit_iff'
+orderOf_eq_zero_iff'
+orderOf_pow'
+Ordinal.add_lt_add_iff_left'
+Ordinal.blsub_eq_lsub'
+Ordinal.brange_bfamilyOfFamily'
+Ordinal.bsup_eq_sup'
+Ordinal.cof_eq'
+Ordinal.comp_bfamilyOfFamily'
+Ordinal.comp_familyOfBFamily'
+Ordinal.enum_le_enum'
+Ordinal.enum_zero_le'
+Ordinal.IsNormal.le_set'
+Ordinal.lift_down'
+Ordinal.lift.principalSeg_top'
+Ordinal.liftPrincipalSeg_top'
+Ordinal.lsub_eq_blsub'
+Ordinal.lt_nmul_iff₃'
+Ordinal.mul_eq_zero'
+Ordinal.nhds_right'
+Ordinal.nmul_le_iff₃'
+Ordinal.nmul_nadd_le₃'
+Ordinal.nmul_nadd_lt₃'
+Ordinal.pred_eq_iff_not_succ'
+Ordinal.range_familyOfBFamily'
+Ordinal.relIso_enum'
+Ordinal.succ_le_iff'
+Ordinal.sup_eq_bsup'
+Ordinal.toPGame_moveLeft'
+Ordinal.type_def'
+Ordinal.typein_le_typein'
+Ordinal.type_le_iff'
+Ordinal.zero_opow'
+Ordnode.all_balance'
+Ordnode.all_node'
+Ordnode.balance_eq_balance'
+Ordnode.balanceL_eq_balance'
+Ordnode.balanceR_eq_balance'
+Ordnode.dual_balance'
+Ordnode.dual_node'
+Ordnode.length_toList'
+Ordnode.Raised.dist_le'
+Ordnode.size_balance'
+Ordnode.Sized.balance'
+Ordnode.Sized.eq_node'
+Ordnode.Sized.node'
+Ordnode.Valid'.balance'
+Ordnode.Valid'.node'
+OreLocalization.add'
+OreLocalization.add''
+OreLocalization.div_eq_one'
+OreLocalization.inv'
+OreLocalization.mul_cancel'
+OreLocalization.oreDiv_add_char'
+OreLocalization.smul'
+OreLocalization.smul_cancel'
+OreLocalization.zero_oreDiv'
+Orientation.inner_rightAngleRotation_swap'
+Orientation.kahler_comp_rightAngleRotation'
+Orientation.rightAngleRotation_map'
+Orientation.volumeForm_robust'
+Padic.complete'
+Padic.complete''
+Padic.lim'
+padicNormE.eq_padic_norm'
+padicNormE.image'
+padicNorm.sum_le'
+padicNorm.sum_lt'
+Padic.rat_dense'
+padicValNat_def'
+padicValNat.div'
+PartENat.casesOn'
+PartENat.get_natCast'
+PartENat.get_ofNat'
+PartENat.toWithTop_natCast'
+PartENat.toWithTop_one'
+PartENat.toWithTop_top'
+PartENat.toWithTop_zero'
+Part.eq_none_iff'
+Part.Fix.approx_mono'
+Part.fix_def'
+PartialEquiv.image_source_inter_eq'
+PartialEquiv.symm_image_target_inter_eq'
+PartialEquiv.trans_refl_restr'
+PartialEquiv.trans_source'
+PartialEquiv.trans_source''
+PartialEquiv.trans_target'
+PartialEquiv.trans_target''
+PartialHomeomorph.contDiffWithinAt_extend_coord_change'
+PartialHomeomorph.continuousAt_extend_symm'
+PartialHomeomorph.eventually_left_inverse'
+PartialHomeomorph.eventually_nhds'
+PartialHomeomorph.eventually_nhdsWithin'
+PartialHomeomorph.eventually_right_inverse'
+PartialHomeomorph.extend_coord_change_source_mem_nhdsWithin'
+PartialHomeomorph.extend_target'
+PartialHomeomorph.image_source_inter_eq'
+PartialHomeomorph.IsImage.iff_preimage_eq'
+PartialHomeomorph.IsImage.iff_symm_preimage_eq'
+PartialHomeomorph.isOpen_extend_preimage'
+PartialHomeomorph.ofSet_trans'
+PartialHomeomorph.prod_eq_prod_of_nonempty'
+PartialHomeomorph.restr_source'
+PartialHomeomorph.restr_toPartialEquiv'
+PartialHomeomorph.trans_of_set'
+PartialHomeomorph.trans_source'
+PartialHomeomorph.trans_source''
+PartialHomeomorph.trans_target'
+PartialHomeomorph.trans_target''
+PartitionOfUnity.exists_finset_nhd'
+PartitionOfUnity.sum_finsupport'
+Part.map_id'
+Partrec₂.unpaired'
+Partrec.const'
+Partrec.merge'
+PathConnectedSpace.exists_path_through_family'
+Path.extend_extends'
+pcontinuous_iff'
+Pell.eq_of_xn_modEq'
+Perfection.coeff_iterate_frobenius'
+Perfection.coeff_pow_p'
+PerfectionMap.comp_equiv'
+PerfectionMap.comp_symm_equiv'
+PFunctor.Approx.head_succ'
+PFunctor.liftp_iff'
+PFunctor.M.agree_iff_agree'
+PFunctor.M.bisim'
+PFunctor.M.casesOn_mk'
+PFunctor.M.ext'
+PFunctor.M.head_eq_head'
+PFunctor.M.isPath_cons'
+Pi.compact_Icc_space'
+Pi.continuous_postcomp'
+Pi.continuous_precomp'
+Pi.cstarRing'
+Pi.distribMulAction'
+Pi.distribSMul'
+pi_Icc_mem_nhds'
+pi_Ici_mem_nhds'
+pi_Ico_mem_nhds'
+pi_Iic_mem_nhds'
+pi_Iio_mem_nhds'
+Pi.induced_precomp'
+Pi.infConvergenceClass'
+Pi.instBoundedSMul'
+pi_Ioc_mem_nhds'
+pi_Ioi_mem_nhds'
+pi_Ioo_mem_nhds'
+Pi.isometricSMul'
+Pi.isometricSMul''
+Pi.isScalarTower'
+Pi.isScalarTower''
+Pi.lawfulFix'
+Pi.Lex.noMaxOrder'
+Pi.module'
+Pi.mulAction'
+Pi.mulActionWithZero'
+Pi.mulDistribMulAction'
+pinGroup.star_eq_inv'
+pi_nnnorm_const'
+pi_nnnorm_const_le'
+Pi.nnnorm_def'
+pi_nnnorm_le_iff'
+pi_nnnorm_lt_iff'
+pi_norm_const'
+pi_norm_const_le'
+Pi.norm_def'
+pi_norm_le_iff_of_nonempty'
+Pi.orderClosedTopology'
+Pi.smul'
+Pi.smul_apply'
+Pi.smulCommClass'
+Pi.smulCommClass''
+Pi.smul_def'
+Pi.smulWithZero'
+Pi.smulZeroClass'
+PiSubtype.canLift'
+Pi.supConvergenceClass'
+PiTensorProduct.add_tprodCoeff'
+PiTensorProduct.distribMulAction'
+PiTensorProduct.hasSMul'
+PiTensorProduct.isScalarTower'
+PiTensorProduct.lift.unique'
+PiTensorProduct.module'
+PiTensorProduct.smulCommClass'
+PiTensorProduct.smul_tprodCoeff'
+PiTensorProduct.zero_tprodCoeff'
+Pi.uniformContinuous_postcomp'
+Pi.uniformContinuous_precomp'
+Pi.uniformSpace_comap_precomp'
+PNat.coe_toPNat'
+PNat.div_add_mod'
+PNat.dvd_iff'
+PNat.factorMultiset_le_iff'
+PNat.find_min'
+PNat.gcd_rel_left'
+PNat.gcd_rel_right'
+PNat.mod_add_div'
+PNat.XgcdType.reduce_isReduced'
+PNat.XgcdType.reduce_isSpecial'
+pNilradical_eq_bot'
+Pointed.Hom.comp_toFun'
+Pointed.Hom.id_toFun'
+Polynomial.add'
+Polynomial.addHom_ext'
+Polynomial.aeval_apply_smul_mem_of_le_comap'
+Polynomial.aeval_eq_sum_range'
+Polynomial.as_sum_range'
+Polynomial.card_roots'
+Polynomial.card_roots_sub_C'
+Polynomial.card_support_eq'
+Polynomial.card_support_eraseLead'
+Polynomial.C_mul'
+Polynomial.coeff_expand_mul'
+Polynomial.coeff_mul_X_pow'
+Polynomial.coeff_restriction'
+Polynomial.coeff_toSubring'
+Polynomial.coeff_X_pow_mul'
+Polynomial.coeff_zero_eq_aeval_zero'
+Polynomial.degree_eq_card_roots'
+Polynomial.degree_mul'
+Polynomial.degree_pow'
+Polynomial.div_tendsto_atBot_of_degree_gt'
+Polynomial.div_tendsto_atTop_of_degree_gt'
+Polynomial.eq_zero_of_natDegree_lt_card_of_eval_eq_zero'
+Polynomial.eval₂_comp'
+Polynomial.eval₂_eq_sum_range'
+Polynomial.eval₂_mul'
+Polynomial.eval₂_mul_C'
+Polynomial.eval₂_pow'
+Polynomial.eval_eq_sum_range'
+Polynomial.eval_smul'
+Polynomial.exists_root_of_splits'
+Polynomial.expand_contract'
+Polynomial.hasseDeriv_one'
+Polynomial.hasseDeriv_zero'
+Polynomial.HasSeparableContraction.dvd_degree'
+Polynomial.hermite_eq_deriv_gaussian'
+Polynomial.isRoot_cyclotomic_iff'
+Polynomial.isUnit_iff'
+Polynomial.isUnitTrinomial_iff'
+Polynomial.isUnitTrinomial_iff''
+Polynomial.leadingCoeff_add_of_degree_lt'
+Polynomial.leadingCoeff_map'
+Polynomial.leadingCoeff_mul'
+Polynomial.leadingCoeff_pow'
+Polynomial.leadingCoeff_sub_of_degree_lt'
+Polynomial.lhom_ext'
+Polynomial.lt_rootMultiplicity_iff_isRoot_iterate_derivative_of_mem_nonZeroDivisors'
+Polynomial.lt_rootMultiplicity_of_isRoot_iterate_derivative_of_mem_nonZeroDivisors'
+Polynomial.map_dvd_map'
+Polynomial.map_rootOfSplits'
+Polynomial.mem_aroots'
+Polynomial.mem_roots'
+Polynomial.mem_rootSet'
+Polynomial.mem_roots_sub_C'
+Polynomial.mkDerivation_one_eq_derivative'
+PolynomialModule.eval_map'
+PolynomialModule.isScalarTower'
+Polynomial.Monic.geom_sum'
+Polynomial.Monic.irreducible_iff_natDegree'
+Polynomial.Monic.natDegree_mul'
+Polynomial.monic_zero_iff_subsingleton'
+Polynomial.mul'
+Polynomial.mul_scaleRoots'
+Polynomial.natDegree_eq_card_roots'
+Polynomial.natDegree_eq_support_max'
+Polynomial.natDegree_mul'
+Polynomial.natDegree_pow'
+Polynomial.natDegree_removeFactor'
+Polynomial.natTrailingDegree_eq_support_min'
+Polynomial.natTrailingDegree_mul'
+Polynomial.neg'
+Polynomial.ringHom_ext'
+Polynomial.rootMultiplicity_mul'
+Polynomial.rootMultiplicity_pos'
+Polynomial.rootSet_maps_to'
+Polynomial.roots_ne_zero_of_splits'
+Polynomial.scaleRoots_dvd'
+Polynomial.separable_def'
+Polynomial.Separable.of_pow'
+Polynomial.separable_prod'
+Polynomial.separable_prod_X_sub_C_iff'
+polynomial_smul_apply'
+Polynomial.splits_of_splits_mul'
+Polynomial.SplittingField.algebra'
+Polynomial.SplittingFieldAux.algebra'
+Polynomial.SplittingFieldAux.algebra''
+Polynomial.SplittingFieldAux.algebra'''
+Polynomial.SplittingFieldAux.scalar_tower'
+Polynomial.sum_add'
+Polynomial.sum_smul_index'
+Polynomial.support_binomial'
+Polynomial.support_C_mul_X'
+Polynomial.support_C_mul_X_pow'
+Polynomial.support_monomial'
+Polynomial.support_trinomial'
+Polynomial.taylor_zero'
+Polynomial.trailingDegree_mul'
+Polynomial.trinomial_leading_coeff'
+Polynomial.trinomial_trailing_coeff'
+PosNum.cast_one'
+PosNum.cast_sub'
+PosNum.of_to_nat'
+PosNum.one_sub'
+PosNum.pred'_succ'
+PosNum.succ'_pred'
+pow_add_pow_le'
+pow_card_eq_one'
+pow_eq_zero_iff'
+PowerBasis.exists_eq_aeval'
+PowerBasis.mem_span_pow'
+PowerSeries.algebraMap_apply'
+PowerSeries.algebraMap_apply''
+PowerSeries.algebraPolynomial'
+PowerSeries.coeff_mul_X_pow'
+PowerSeries.coeff_X_pow_mul'
+PowerSeries.derivative_inv'
+PowerSeries.invOfUnit_eq'
+PowerSeries.trunc_derivative'
+PowerSeries.trunc_zero'
+pow_le_one'
+pow_le_pow_iff_right'
+pow_le_pow_left'
+pow_le_pow_right'
+pow_le_pow_right_of_le_one'
+pow_lt_one'
+pow_lt_pow_iff_right'
+pow_lt_pow_left'
+pow_lt_pow_right'
+pow_mul'
+pow_mul_comm'
+pow_right_strictMono'
+pow_succ'
+pow_three'
+ppow_mul'
+PProd.exists'
+PProd.forall'
+PredOrder.prelimitRecOn_pred'
+preimage_nhdsWithin_coinduced'
+PresheafOfModules.sheafificationHomEquiv_hom'
+Pretrivialization.apply_symm_apply'
+Pretrivialization.coe_fst'
+Pretrivialization.continuousLinearMap_symm_apply'
+Pretrivialization.ext'
+Pretrivialization.mk_proj_snd'
+Pretrivialization.proj_symm_apply'
+PrimeMultiset.prod_dvd_iff'
+PrimeSpectrum.iSup_basicOpen_eq_top_iff'
+Primrec₂.nat_iff'
+Primrec₂.unpaired'
+Primrec.nat_casesOn'
+Primrec.nat_omega_rec'
+Primrec.nat_rec'
+Primrec.vector_get'
+Primrec.vector_ofFn'
+PrincipalSeg.coe_coe_fn'
+ProbabilityTheory.centralMoment_one'
+ProbabilityTheory.cgf_const'
+ProbabilityTheory.cgf_zero'
+ProbabilityTheory.cond_apply'
+ProbabilityTheory.cond_cond_eq_cond_inter'
+ProbabilityTheory.uniformOn_inter'
+ProbabilityTheory.condexp_ae_eq_integral_condexpKernel'
+ProbabilityTheory.condexpKernel_ae_eq_condexp'
+ProbabilityTheory.CondIndepSets.condIndep'
+ProbabilityTheory.cond_mul_eq_inter'
+ProbabilityTheory.evariance_def'
+ProbabilityTheory.gaussianReal_absolutelyContinuous'
+ProbabilityTheory.hasFiniteIntegral_compProd_iff'
+ProbabilityTheory.iIndep.iIndepSets'
+ProbabilityTheory.IndepFun.integral_mul'
+ProbabilityTheory.IndepFun.mgf_add'
+ProbabilityTheory.IndepSets.indep'
+ProbabilityTheory.IsMarkovKernel.is_probability_measure'
+ProbabilityTheory.IsMeasurableRatCDF.stieltjesFunctionAux_def'
+ProbabilityTheory.Kernel.borelMarkovFromReal_apply'
+ProbabilityTheory.Kernel.comap_apply'
+ProbabilityTheory.Kernel.comap_id'
+ProbabilityTheory.Kernel.comapRight_apply'
+ProbabilityTheory.Kernel.comp_apply'
+ProbabilityTheory.Kernel.const_comp'
+ProbabilityTheory.Kernel.deterministic_apply'
+ProbabilityTheory.Kernel.ext_iff'
+ProbabilityTheory.Kernel.finset_sum_apply'
+ProbabilityTheory.Kernel.fst_apply'
+ProbabilityTheory.Kernel.iIndep.iIndepSets'
+ProbabilityTheory.Kernel.IndepSets.indep'
+ProbabilityTheory.Kernel.integral_deterministic'
+ProbabilityTheory.Kernel.integral_integral_add'
+ProbabilityTheory.Kernel.integral_integral_sub'
+ProbabilityTheory.Kernel.lintegral_deterministic'
+ProbabilityTheory.Kernel.map_apply'
+ProbabilityTheory.Kernel.map_id'
+ProbabilityTheory.Kernel.measurable_kernel_prod_mk_left'
+ProbabilityTheory.Kernel.measure_eq_zero_or_one_of_indepSet_self'
+ProbabilityTheory.Kernel.piecewise_apply'
+ProbabilityTheory.Kernel.prod_apply'
+ProbabilityTheory.Kernel.prodMkLeft_apply'
+ProbabilityTheory.Kernel.prodMkRight_apply'
+ProbabilityTheory.Kernel.restrict_apply'
+ProbabilityTheory.Kernel.rnDeriv_def'
+ProbabilityTheory.Kernel.rnDeriv_eq_top_iff'
+ProbabilityTheory.Kernel.setIntegral_deterministic'
+ProbabilityTheory.Kernel.setLIntegral_deterministic'
+ProbabilityTheory.Kernel.snd_apply'
+ProbabilityTheory.Kernel.sum_apply'
+ProbabilityTheory.Kernel.swapLeft_apply'
+ProbabilityTheory.Kernel.swapRight_apply'
+ProbabilityTheory.Kernel.withDensity_apply'
+ProbabilityTheory.Kernel.withDensity_one'
+ProbabilityTheory.Kernel.withDensity_zero'
+ProbabilityTheory.lintegral_mul_eq_lintegral_mul_lintegral_of_indepFun''
+ProbabilityTheory.measurable_preCDF'
+ProbabilityTheory.mgf_const'
+ProbabilityTheory.mgf_pos'
+ProbabilityTheory.mgf_zero'
+ProbabilityTheory.variance_def'
+ProbabilityTheory.variance_smul'
+Prod.exists'
+Prod.forall'
+Prod.isometricSMul'
+Prod.isometricSMul''
+Prod.map_apply'
+Prod.map_fst'
+Prod.map_id'
+Prod.map_snd'
+prod_mul_tprod_nat_mul'
+Profinite.NobelingProof.coe_πs'
+Profinite.NobelingProof.contained_C'
+Profinite.NobelingProof.injective_πs'
+Profinite.NobelingProof.Products.eval_πs'
+Profinite.NobelingProof.Products.eval_πs_image'
+Profinite.NobelingProof.Products.max_eq_o_cons_tail'
+Projectivization.submodule_mk''
+Prop.countable'
+QPF.Cofix.bisim'
+QPF.liftp_iff'
+QPF.recF_eq'
+QPF.Wequiv.abs'
+quadraticChar_eq_pow_of_char_ne_two'
+QuadraticForm.equivalent_weightedSumSquares_units_of_nondegenerate'
+QuadraticForm.posDef_of_toMatrix'
+QuadraticForm.posDef_toMatrix'
+QuadraticMap.isSymm_toMatrix'
+QuadraticMap.map_sum'
+quasiIsoAt_iff'
+quasiIsoAt_iff_exactAt'
+QuaternionAlgebra.self_add_star'
+QuaternionAlgebra.star_add_self'
+Quaternion.normSq_def'
+Quaternion.self_add_star'
+Quaternion.star_add_self'
+Quiver.Hom.unop_op'
+Quiver.Path.comp_inj'
+QuotientAddGroup.btw_coe_iff'
+Quotient.eq'
+Quotient.eq''
+Quotient.exact'
+QuotientGroup.coe_mk'
+QuotientGroup.congr_mk'
+QuotientGroup.kerLift_mk'
+QuotientGroup.ker_mk'
+QuotientGroup.lift_mk'
+QuotientGroup.map_mk'
+QuotientGroup.mk'_eq_mk'
+QuotientGroup.out_eq'
+Quotient.hrecOn₂'_mk''
+Quotient.hrecOn'_mk''
+Quotient.liftOn₂'_mk''
+Quotient.liftOn'_mk''
+Quotient.map₂'_mk''
+Quotient.map'_mk''
+isQuotientMap_quotient_mk'
+Quotient.mk_out'
+Quotient.out_eq'
+Quotient.sound'
+Quotient.surjective_liftOn'
+range_pow_padicValNat_subset_divisors'
+rank_finsupp'
+rank_fun'
+rank_lt_rank_dual'
+Rat.add_def''
+Rat.add_num_den'
+Rat.cast_mk'
+Rat.div_def'
+Rat.divInt_mul_divInt'
+Rat.divInt_self'
+Rat.floor_def'
+RatFunc.liftAlgHom_apply_div'
+RatFunc.liftMonoidWithZeroHom_apply_div'
+RatFunc.liftRingHom_apply_div'
+RatFunc.mk_eq_div'
+RatFunc.mk_eq_mk'
+RatFunc.mk_one'
+RatFunc.num_div'
+RatFunc.ofFractionRing_mk'
+Rat.instSMulCommClass'
+Rat.inv_def'
+Rat.inv_divInt'
+Rat.le_toNNRat_iff_coe_le'
+Rat.mk'_mul_mk'
+Rat.mul_num_den'
+Rat.normalize_eq_mk'
+Rat.sub_def''
+Rat.substr_num_den'
+Rat.toNNRat_div'
+Rat.toNNRat_lt_toNNRat_iff'
+RCLike.hasSum_conj'
+RCLike.I_im'
+RCLike.normSq_eq_def'
+RCLike.zero_re'
+Real.arcsin_le_iff_le_sin'
+Real.arcsin_lt_iff_lt_sin'
+Real.arcsin_sin'
+Real.binEntropy_eq_negMulLog_add_negMulLog_one_sub'
+Real.b_ne_one'
+Real.coe_toNNReal'
+Real.continuousAt_const_rpow'
+Real.continuous_log'
+Real.cosh_sq'
+Real.cos_sq'
+Real.cos_two_mul'
+Real.deriv_cos'
+Real.deriv_log'
+Real.deriv_rpow_const'
+Real.eulerMascheroniConstant_lt_eulerMascheroniSeq'
+Real.eulerMascheroniSeq_lt_eulerMascheroniSeq'
+Real.exp_approx_end'
+Real.exp_bound'
+Real.exp_bound_div_one_sub_of_interval'
+Real.fourierIntegral_continuousLinearMap_apply'
+Real.fourierIntegral_continuousMultilinearMap_apply'
+Real.fourierIntegral_eq'
+Real.fourierIntegralInv_eq'
+Real.hasDerivAt_arctan'
+Real.inner_le_Lp_mul_Lq_tsum_of_nonneg'
+Real.le_arcsin_iff_sin_le'
+Real.le_def'
+Real.le_sqrt'
+Real.le_toNNReal_iff_coe_le'
+Real.list_prod_map_rpow'
+Real.logb_nonpos_iff'
+Real.log_nonpos_iff'
+Real.Lp_add_le_tsum_of_nonneg'
+Real.lt_arcsin_iff_sin_lt'
+Real.natCastle_toNNReal'
+Real.nndist_eq'
+Real.rpow_add'
+Real.rpow_add_intCast'
+Real.rpow_add_natCast'
+Real.rpow_add_one'
+Real.rpow_le_rpow_of_exponent_ge'
+Real.rpow_lt_one_iff'
+Real.rpow_one_add'
+Real.rpow_one_sub'
+Real.rpow_sub'
+Real.rpow_sub_intCast'
+Real.rpow_sub_natCast'
+Real.rpow_sub_one'
+Real.sin_arcsin'
+Real.sqrt_div'
+Real.sqrt_div_self'
+Real.sqrt_eq_zero'
+Real.sqrt_le_sqrt_iff'
+Real.sqrt_lt'
+Real.sqrt_mul'
+Real.sqrt_ne_zero'
+Real.strictAnti_eulerMascheroniSeq'
+Real.surjOn_log'
+Real.surjOn_logb'
+Real.tan_add'
+Real.tan_eq_zero_iff'
+Real.tendsto_eulerMascheroniSeq'
+Real.tendsto_integral_gaussian_smul'
+Real.toNNReal_div'
+Real.toNNReal_le_toNNReal_iff'
+Real.toNNReal_lt_natCast'
+Real.toNNReal_lt_toNNReal_iff'
+RegularExpression.rmatch_iff_matches'
+Relation.ReflTransGen.lift'
+Relation.TransGen.closed'
+Relation.TransGen.head'
+Relation.TransGen.lift'
+Relation.TransGen.tail'
+RelSeries.last_snoc'
+RelSeries.toList_chain'
+RightOrdContinuous.map_sInf'
+Ring.choose_one_right'
+Ring.choose_zero_right'
+RingCon.smulCommClass'
+RingEquiv.mk_coe'
+RingHom.eq_intCast'
+RingHom.surjectiveOnStalks_iff_forall_maximal'
+Ring.inverse_eq_inv'
+Ring.mul_inverse_rev'
+Ring.multichoose_one_right'
+Ring.multichoose_zero_right'
+RingQuot.ringQuot_ext'
+RingTheory.Sequence.IsRegular.cons'
+RingTheory.Sequence.isRegular_cons_iff'
+RingTheory.Sequence.isWeaklyRegular_append_iff'
+RingTheory.Sequence.IsWeaklyRegular.cons'
+RingTheory.Sequence.isWeaklyRegular_cons_iff'
+RootPairing.coroot_eq_coreflection_of_root_eq'
+RootPairing.ne_zero'
+rootsOfUnity.integer_power_of_ringEquiv'
+root_X_pow_sub_C_ne_zero'
+SameRay.of_subsingleton'
+schnirelmannDensity_congr'
+sdiff_eq_self_iff_disjoint'
+sdiff_le'
+sdiff_le_iff'
+sdiff_sdiff_left'
+sdiff_sdiff_right'
+sdiff_sdiff_sup_sdiff'
+sdiff_sup_self'
+sdiff_symmDiff'
+segment_eq_Icc'
+segment_eq_image'
+Semigroup.opposite_smulCommClass'
+Seminorm.ball_finset_sup'
+Seminorm.ball_zero'
+Seminorm.closedBall_finset_sup'
+Seminorm.closedBall_zero'
+Seminorm.coe_sSup_eq'
+Seminorm.continuous'
+Seminorm.continuousAt_zero'
+Seminorm.uniformContinuous'
+Semiquot.blur_eq_blur'
+Semiquot.mem_blur'
+Semiquot.mem_pure'
+SeparationQuotient.uniformContinuous_lift'
+Set.biInter_and'
+Set.biInter_finsetSigma'
+Set.biInter_le_succ'
+Set.biInter_lt_succ'
+Set.biInter_sigma'
+Set.bijOn_of_subsingleton'
+Set.biUnion_and'
+Set.biUnion_finsetSigma'
+Set.biUnion_finsetSigma_univ'
+Set.biUnion_le_succ'
+Set.biUnion_lt_succ'
+Set.biUnion_sigma'
+SetCoe.exists'
+SetCoe.forall'
+Set.empty_card'
+Set.encard_exchange'
+Set.eq_of_mem_uIcc_of_mem_uIcc'
+Set.eq_of_mem_uIoc_of_mem_uIoc'
+Set.eq_of_nonempty_of_subsingleton'
+Set.EqOn.piecewise_ite'
+Set.eval_preimage'
+Set.exists_intermediate_set'
+Set.finite'
+Set.finite_diff_iUnion_Ioo'
+Set.Finite.eq_of_subset_of_encard_le'
+Set.Finite.preimage'
+Set.Finite.seq'
+Set.Finite.toFinset_insert'
+Set.fintypeBind'
+Set.fintypeBiUnion'
+Set.fintypeSeq'
+Set.Icc_mul_Icc_subset'
+Set.Icc_mul_Ico_subset'
+Set.Icc_subset_uIcc'
+Set.Icc_union_Icc'
+Set.Icc_union_Ici'
+Set.Ici_mul_Ici_subset'
+Set.Ici_mul_Ioi_subset'
+Set.Ico_mul_Icc_subset'
+Set.Ico_mul_Ioc_subset'
+Set.Ico_union_Ici'
+Set.Ico_union_Ico'
+Set.Iic_mul_Iic_subset'
+Set.Iic_mul_Iio_subset'
+Set.Iic_union_Icc'
+Set.Iic_union_Ioc'
+Set.iInter₂_mono'
+Set.iInter_iInter_eq'
+Set.iInter_mono'
+Set.iInter_mono''
+Set.iInter_sigma'
+Set.Iio_mul_Iic_subset'
+Set.Iio_union_Ico'
+Set.Iio_union_Ioo'
+Set.image_affine_Icc'
+Set.image_mul_left'
+Set.image_mul_left_Icc'
+Set.image_mul_right'
+Set.image_mul_right_Icc'
+Set.Infinite.preimage'
+setIntegral_withDensity_eq_setIntegral_smul₀'
+Set.Ioc_mul_Ico_subset'
+Set.Ioc_subset_uIoc'
+Set.Ioc_union_Ioc'
+Set.Ioc_union_Ioi'
+Set.Ioi_mul_Ici_subset'
+Set.Ioo_union_Ioi'
+Set.Ioo_union_Ioo'
+Set.isScalarTower'
+Set.isScalarTower''
+Set.iUnion₂_mono'
+Set.iUnion_iUnion_eq'
+Set.iUnion_mono'
+Set.iUnion_mono''
+Set.iUnion_sigma'
+Set.LeftInvOn.image_image'
+Set.LeftInvOn.image_inter'
+SetLike.ext'
+Set.mapsTo'
+Set.mapsTo_of_subsingleton'
+Set.mulIndicator_apply_le'
+Set.mulIndicator_compl'
+Set.mulIndicator_diff'
+Set.mulIndicator_div'
+Set.mulIndicator_empty'
+Set.mulIndicator_eq_one'
+Set.mulIndicator_inv'
+Set.mulIndicator_le'
+Set.mulIndicator_le_mulIndicator'
+Set.mulIndicator_le_self'
+Set.mulIndicator_mul'
+Set.mulIndicator_one'
+Set.ncard_eq_toFinset_card'
+Set.ncard_exchange'
+Set.nonempty_of_ssubset'
+Set.Nonempty.preimage'
+Setoid.comm'
+Setoid.eqv_class_mem'
+Setoid.ext'
+Setoid.ker_apply_mk_out'
+Setoid.refl'
+Setoid.symm'
+Setoid.trans'
+Set.ordConnected_iInter'
+Set.OrdConnected.inter'
+Set.ordConnected_pi'
+Set.PairwiseDisjoint.elim'
+Set.Pairwise.mono'
+Set.piecewise_mem_Icc'
+Set.pi_eq_empty_iff'
+Set.PiSetCoe.canLift'
+Set.preimage_eq_preimage'
+Set.preimage_id'
+Set.preimage_mul_left_one'
+Set.preimage_mul_right_one'
+Set.Quotient.range_mk''
+Set.range_id'
+Set.range_ite_subset'
+Set.range_quotient_lift_on'
+Set.range_quotient_mk'
+Set.setOf_eq_eq_singleton'
+Set.singleton_pi'
+Set.Sized.subsingleton'
+Set.smulCommClass_set'
+Set.smulCommClass_set''
+Set.smul_inter_ne_empty_iff'
+Set.smul_univ₀'
+Set.star_inv'
+Set.star_mem_centralizer'
+Set.surjOn_of_subsingleton'
+SetTheory.Game.birthday_neg'
+SetTheory.PGame.add_le_add_right'
+SetTheory.PGame.Equiv.not_fuzzy'
+SetTheory.PGame.Fuzzy.not_equiv'
+SetTheory.PGame.LF.not_equiv'
+SetTheory.PGame.moveLeft_neg'
+SetTheory.PGame.moveLeft_neg_symm'
+SetTheory.PGame.moveLeft_nim'
+SetTheory.PGame.moveRight_neg'
+SetTheory.PGame.moveRight_neg_symm'
+SetTheory.PGame.moveRight_nim'
+SetTheory.PGame.ofLists_moveLeft'
+SetTheory.PGame.ofLists_moveRight'
+SetTheory.PGame.relabel_moveLeft'
+SetTheory.PGame.relabel_moveRight'
+SetTheory.PGame.Subsequent.mk_right'
+SetTheory.PGame.zero_lf_inv'
+Set.uIcc_subset_uIcc_iff_le'
+Set.union_diff_cancel'
+Set.WellFoundedOn.mono'
+Sigma.exists'
+Sigma.forall'
+sigma_mk_preimage_image'
+SimpleGraph.Adj.ne'
+SimpleGraph.cliqueSet_mono'
+SimpleGraph.cycleGraph_adj'
+SimpleGraph.dart_edge_eq_mk'_iff'
+SimpleGraph.FarFromTriangleFree.cliqueFinset_nonempty'
+SimpleGraph.Subgraph.connected_iff'
+SimpleGraph.Subgraph.Connected.mono'
+SimpleGraph.Subgraph.degree_le'
+SimpleGraph.TripartiteFromTriangles.Graph.in₀₁_iff'
+SimpleGraph.TripartiteFromTriangles.Graph.in₀₂_iff'
+SimpleGraph.TripartiteFromTriangles.Graph.in₁₀_iff'
+SimpleGraph.TripartiteFromTriangles.Graph.in₁₂_iff'
+SimpleGraph.TripartiteFromTriangles.Graph.in₂₀_iff'
+SimpleGraph.TripartiteFromTriangles.Graph.in₂₁_iff'
+SimpleGraph.Walk.coe_support_append'
+SimpleGraph.Walk.IsPath.mk'
+simple_iff_isSimpleModule'
+SimplexCategory.eq_comp_δ_of_not_surjective'
+SimplexCategory.eq_σ_comp_of_not_injective'
+SimplexCategory.Hom.ext'
+SimplexCategory.δ_comp_δ'
+SimplexCategory.δ_comp_δ''
+SimplexCategory.δ_comp_δ_self'
+SimplexCategory.δ_comp_σ_of_gt'
+SimplexCategory.δ_comp_σ_self'
+SimplexCategory.δ_comp_σ_succ'
+SimplicialObject.Splitting.hom_ext'
+SimplicialObject.Splitting.IndexSet.ext'
+sInf_eq_iInf'
+sInf_image'
+skewAdjoint.conjugate'
+SlashInvariantForm.slash_action_eqn'
+small_biInter'
+small_iInter'
+small_sInter'
+smoothAt_finset_prod'
+smooth_finset_prod'
+SmoothManifoldWithCorners.mk'
+SmoothMap.instSMul'
+SmoothMap.module'
+SmoothMap.smul_comp'
+smoothOn_finset_prod'
+SmoothPartitionOfUnity.sum_finsupport'
+smoothWithinAt_finset_prod'
+smul_ball''
+smul_closedBall'
+smul_closedBall''
+SMulCommClass.nnrat'
+SMulCommClass.rat'
+smul_div'
+smul_eq_smul_iff_eq_and_eq_of_pos'
+smul_finprod'
+smul_inv'
+smul_left_injective'
+smul_le_smul'
+smul_lt_smul'
+smul_lt_smul_of_le_of_lt'
+smul_lt_smul_of_lt_of_le'
+smul_mul'
+smul_nonneg'
+smul_pos'
+smul_pow'
+smul_sphere'
+spec'
+SpectralMap.coe_comp_continuousMap'
+spinGroup.star_eq_inv'
+sq_le_sq'
+sq_lt_sq'
+sSup_eq_bot'
+sSup_eq_iSup'
+sSup_image'
+StarAlgHom.coe_mk'
+star_comm_self'
+StarConvex.sub'
+star_inv'
+Stream'
+Stream'.corec'
+Stream'.drop_tail'
+Stream'.get_succ_iterate'
+Stream'.Seq1.map_join'
+Stream'.tail_drop'
+Stream'.take_succ'
+StrictAnti.const_mul'
+StrictAnti.ite'
+StrictAnti.mul_const'
+StrictAntiOn.const_mul'
+StrictAntiOn.mul_const'
+StrictMono.const_mul'
+StrictMono.ite'
+StrictMono.mul_const'
+StrictMonoOn.const_mul'
+StrictMonoOn.mul_const'
+StrictWeakOrder.not_lt_of_equiv'
+String.LT'
+StructureGroupoid.LocalInvariantProp.congr'
+StructureGroupoid.LocalInvariantProp.congr_nhdsWithin'
+StructureGroupoid.LocalInvariantProp.liftPropWithinAt_inter'
+Subalgebra.algebra'
+Subalgebra.coe_valA'
+Subalgebra.module'
+Subbimodule.smul_mem'
+sub_div'
+Subgroup.center_eq_infi'
+Subgroup.comap_equiv_eq_map_symm'
+Subgroup.commutator_def'
+Subgroup.disjoint_def'
+Subgroup.eq_top_iff'
+Subgroup.finiteIndex_iInf'
+Subgroup.map_equiv_eq_comap_symm'
+Subgroup.map_le_map_iff'
+Subgroup.mem_normalizer_iff'
+Subgroup.mem_normalizer_iff''
+Subgroup.mem_sup'
+Subgroup.Normal.conj_mem'
+Subgroup.quotient_finite_of_isOpen'
+Subgroup.smul_diff'
+Subgroup.smul_diff_smul'
+Subgroup.smul_opposite_image_mul_preimage'
+Subgroup.transferTransversal_apply'
+Subgroup.transferTransversal_apply''
+Sublattice.coe_inf'
+SubmoduleClass.module'
+Submodule.coe_continuous_linearProjOfClosedCompl'
+Submodule.coe_prodEquivOfIsCompl'
+Submodule.coe_subtypeL'
+Submodule.comap_smul'
+Submodule.disjoint_def'
+Submodule.disjoint_span_singleton'
+Submodule.eq_top_iff'
+Submodule.hasSMul'
+Submodule.inhabited'
+Submodule.isScalarTower'
+Submodule.ker_liftQ_eq_bot'
+Submodule.le_sInf'
+Submodule.linearProjOfIsCompl_apply_right'
+Submodule.map_smul'
+Submodule.map_smul''
+Submodule.map_toAddSubmonoid'
+Submodule.mem_annihilator'
+Submodule.mem_colon'
+Submodule.mem_ideal_smul_span_iff_exists_sum'
+Submodule.mem_localized'
+Submodule.mem_span_insert'
+Submodule.mem_sup'
+Submodule.module'
+Submodule.orderIsoMapComap_apply'
+Submodule.orderIsoMapComap_symm_apply'
+Submodule.Quotient.distribMulAction'
+Submodule.Quotient.distribSMul'
+Submodule.Quotient.eq'
+Submodule.Quotient.instSMul'
+Submodule.Quotient.mk'_eq_mk'
+Submodule.Quotient.module'
+Submodule.Quotient.mulAction'
+Submodule.Quotient.smulZeroClass'
+Submodule.sInf_le'
+Submodule.smul_mem_iff'
+Submodule.smul_mem_span_smul'
+Submodule.span_image'
+Submodule.unique'
+Submonoid.disjoint_def'
+Submonoid.eq_top_iff'
+Submonoid.LocalizationMap.eq'
+Submonoid.LocalizationMap.map_mk'
+Submonoid.LocalizationMap.mk'_eq_iff_eq'
+Submonoid.LocalizationMap.mk'_eq_of_eq'
+Submonoid.LocalizationMap.mk'_self'
+Submonoid.LocalizationMap.mk'_spec'
+Submonoid.LocalizationMap.mulEquivOfMulEquiv_mk'
+Submonoid.LocalizationMap.mul_mk'_one_eq_mk'
+Submonoid.LocalizationMap.sec_spec'
+Submonoid.LocalizationMap.symm_comp_ofMulEquivOfLocalizations_apply'
+Submonoid.mrange_inl'
+Submonoid.mrange_inr'
+SubMulAction.isScalarTower'
+SubMulAction.mem_one'
+SubMulAction.smul'
+SubMulAction.smul_mem_iff'
+Subring.closure_induction'
+Subring.coe_mk'
+Subring.eq_top_iff'
+Subring.mem_mk'
+Subsemigroup.eq_top_iff'
+Subsemiring.closure_induction'
+Subsemiring.coe_mk'
+Subsemiring.eq_top_iff'
+Subsemiring.mem_mk'
+subset_interior_mul'
+Subsingleton.antitone'
+Subsingleton.monotone'
+sub_sq'
+Subtype.preimage_coe_compl'
+SuccOrder.prelimitRecOn_succ'
+suffixLevenshtein_nil'
+sum_bernoulli'
+summable_geometric_two'
+Summable.matrix_blockDiag'
+summable_matrix_blockDiagonal'
+Summable.matrix_blockDiagonal'
+summable_mul_of_summable_norm'
+summable_of_isBigO'
+summable_of_isBigO_nat'
+summable_star_iff'
+summable_sum_mul_antidiagonal_of_summable_norm'
+summable_sum_mul_range_of_summable_norm'
+sup_eq_half_smul_add_add_abs_sub'
+sup_sdiff_cancel'
+Surreal.dyadicMap_apply_pow'
+Surreal.nsmul_pow_two_powHalf'
+Sym2.instDecidableRel'
+Sym2.mem_iff'
+Sym2.other_eq_other'
+Sym2.other_invol'
+Sym2.other_mem'
+Sym2.other_spec'
+Sym2.rel_iff'
+Sym.inhabitedSym'
+symmDiff_eq'
+symmDiff_eq_Xor'
+symmDiff_symmDiff_right'
+symmDiff_symmDiff_self'
+symmDiff_top'
+SymplecticGroup.coe_inv'
+SymplecticGroup.mem_iff'
+t0Space_iff_uniformity'
+Tactic.NormNum.int_gcd_helper'
+Tactic.NormNum.nat_gcd_helper_1'
+Tactic.NormNum.nat_gcd_helper_2'
+tendsto_ceil_left'
+tendsto_ceil_right'
+tendsto_const_mul_pow_nhds_iff'
+tendsto_floor_left'
+tendsto_floor_right'
+tendsto_fract_left'
+tendsto_fract_right'
+tendsto_gauge_nhds_zero'
+tendsto_indicator_const_apply_iff_eventually'
+tendsto_indicator_const_iff_forall_eventually'
+tendsto_indicator_const_iff_tendsto_pi_pure'
+tendsto_measure_Icc_nhdsWithin_right'
+tendsto_nhds_bot_mono'
+tendsto_nhds_top_mono'
+tendsto_nhds_unique'
+tendsto_norm'
+tendsto_norm_atTop_iff_cobounded'
+tendsto_norm_cobounded_atTop'
+tendsto_norm_cocompact_atTop'
+tendsto_norm_zero'
+TensorProduct.ext'
+TensorProduct.finsuppLeft_smul'
+TensorProduct.isPushout'
+TensorProduct.lift.tmul'
+TensorProduct.smul_tmul'
+Theorems100.«82».Cube.hw'
+Theorems100.num_series'
+three_ne_zero'
+toIcoDiv_add_left'
+toIcoDiv_add_right'
+toIcoDiv_add_zsmul'
+toIcoDiv_neg'
+toIcoDiv_sub'
+toIcoDiv_sub_eq_toIcoDiv_add'
+toIcoDiv_sub_zsmul'
+toIcoMod_add_left'
+toIcoMod_add_right'
+toIcoMod_add_zsmul'
+toIcoMod_mem_Ico'
+toIcoMod_neg'
+toIcoMod_sub'
+toIcoMod_sub_zsmul'
+toIcoMod_zsmul_add'
+toIocDiv_add_left'
+toIocDiv_add_right'
+toIocDiv_add_zsmul'
+toIocDiv_neg'
+toIocDiv_sub'
+toIocDiv_sub_eq_toIocDiv_add'
+toIocDiv_sub_zsmul'
+toIocMod_add_left'
+toIocMod_add_right'
+toIocMod_add_zsmul'
+toIocMod_neg'
+toIocMod_sub'
+toIocMod_sub_zsmul'
+toIocMod_zsmul_add'
+toIxxMod_total'
+TopCat.GlueData.preimage_image_eq_image'
+TopCat.isOpenEmbedding_iff_comp_isIso'
+TopCat.isOpenEmbedding_iff_isIso_comp'
+TopCat.Presheaf.germ_stalkSpecializes'
+TopCat.Presheaf.pushforward_eq'
+TopCat.Presheaf.pushforward_map_app'
+TopologicalGroup.of_nhds_one'
+TopologicalSpace.OpenNhds.map_id_obj'
+TopologicalSpace.Opens.coe_inclusion'
+TopologicalSpace.Opens.map_comp_obj'
+TopologicalSpace.Opens.map_functor_eq'
+TopologicalSpace.Opens.map_id_obj'
+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'
+top_symmDiff'
+toSubalgebra_toIntermediateField'
+T_pow'
+tprod_comm'
+tprod_eq_prod'
+tprod_eq_zero_mul'
+tprod_le_of_prod_le'
+tprod_prod'
+tprod_sigma'
+Traversable.map_traverse'
+Traversable.naturality'
+Traversable.traverse_eq_map_id'
+Traversable.traverse_map'
+Trivialization.apply_symm_apply'
+Trivialization.coe_coordChangeL'
+Trivialization.coe_fst'
+Trivialization.coe_fst_eventuallyEq_proj'
+Trivialization.continuousLinearEquivAt_apply'
+Trivialization.ext'
+Trivialization.mk_proj_snd'
+Trivialization.proj_symm_apply'
+TrivSqZeroExt.algebra'
+TrivSqZeroExt.algebraMap_eq_inl'
+TrivSqZeroExt.algHom_ext'
+TrivSqZeroExt.snd_pow_of_smul_comm'
+TruncatedWittVector.commutes'
+TruncatedWittVector.commutes_symm'
+tsum_choose_mul_geometric_of_norm_lt_one'
+tsum_geometric_two'
+tsum_mul_tsum_eq_tsum_sum_antidiagonal_of_summable_norm'
+tsum_mul_tsum_eq_tsum_sum_range_of_summable_norm'
+tsum_mul_tsum_of_summable_norm'
+Tuple.proj_equiv₁'
+Turing.PartrecToTM2.trStmts₁_supports'
+Turing.Reaches₀.tail'
+Turing.Tape.exists_mk'
+Turing.Tape.map_mk'
+Turing.Tape.move_left_mk'
+Turing.Tape.move_right_mk'
+Turing.Tape.write_mk'
+Turing.TM1to1.trTape_mk'
+Turing.tr_eval'
+two_ne_zero'
+TwoSidedIdeal.mem_mk'
+TypeVec.appendFun_comp'
+TypeVec.drop_append1'
+TypeVec.dropFun_RelLast'
+TypeVec.subtypeVal_toSubtype'
+TypeVec.toSubtype'_of_subtype'
+ULift.distribMulAction'
+ULift.distribSMul'
+ULift.isometricSMul'
+ULift.isScalarTower'
+ULift.isScalarTower''
+ULift.module'
+ULift.mulAction'
+ULift.mulActionWithZero'
+ULift.mulDistribMulAction'
+ULift.smulWithZero'
+ULift.smulZeroClass'
+Ultrafilter.le_of_inf_neBot'
+Ultrafilter.map_id'
+UniformCauchySeqOn.prod'
+uniformContinuous_comap'
+UniformContinuous.const_mul'
+uniformContinuous_div_const'
+UniformContinuous.div_const'
+UniformContinuous.mul_const'
+uniformContinuous_mul_left'
+uniformContinuous_mul_right'
+uniformContinuous_nnnorm'
+uniformContinuous_norm'
+isUniformEmbedding_iff'
+UniformGroup.mk'
+isUniformInducing_iff'
+IsUniformInducing.mk'
+uniformity_basis_edist'
+uniformity_basis_edist_le'
+uniformity_eq_comap_nhds_one'
+UniformSpace.Completion.ext'
+unique'
+uniqueDiffWithinAt_inter'
+UniqueDiffWithinAt.inter'
+UniqueFactorizationMonoid.exists_reduced_factors'
+UniqueMDiffWithinAt.inter'
+UniqueMDiffWithinAt.smooth_bundle_preimage'
+Unique.subsingleton_unique'
+Unique.subtypeEq'
+unitary.star_eq_inv'
+Unitization.algHom_ext''
+Unitization.quasispectrum_eq_spectrum_inr'
+Units.coe_map'
+Units.conj_pow'
+Units.inv_mul'
+Units.mul_inv'
+UniversalEnvelopingAlgebra.lift_ι_apply'
+update_le_update_iff'
+upperClosure_interior_subset'
+UpperHalfPlane.cosh_dist'
+UpperHalfPlane.ext_iff'
+UpperHalfPlane.ModularGroup.det_coe'
+UpperHalfPlane.mul_smul'
+UV.compress_of_disjoint_of_le'
+Valuation.Integers.one_of_isUnit'
+Valuation.map_add'
+Valuation.map_sum_lt'
+ValuationSubring.isIntegral_of_mem_ringOfIntegers'
+Vector.continuous_insertNth'
+VitaliFamily.ae_tendsto_lintegral_div'
+volume_regionBetween_eq_integral'
+volume_regionBetween_eq_lintegral'
+WCovBy.of_le_of_le'
+WeakBilin.instModule'
+WeakSpace.instModule'
+WeierstrassCurve.Affine.CoordinateRing.mk_XYIdeal'_mul_mk_XYIdeal'
+WeierstrassCurve.Affine.equation_iff'
+WeierstrassCurve.Affine.nonsingular_iff'
+WeierstrassCurve.Affine.Point.add_of_X_ne'
+WeierstrassCurve.Affine.Point.add_of_Y_ne'
+WeierstrassCurve.Affine.Point.add_self_of_Y_ne'
+WeierstrassCurve.baseChange_preΨ'
+WeierstrassCurve.coeff_preΨ'
+WeierstrassCurve.Jacobian.add_of_Y_ne'
+WeierstrassCurve.Jacobian.addX_eq'
+WeierstrassCurve.Jacobian.addX_of_X_eq'
+WeierstrassCurve.Jacobian.addY_of_X_eq'
+WeierstrassCurve.Jacobian.dblXYZ_of_Y_eq'
+WeierstrassCurve.Jacobian.dblZ_ne_zero_of_Y_ne'
+WeierstrassCurve.Jacobian.equiv_iff_eq_of_Z_eq'
+WeierstrassCurve.Jacobian.isUnit_dblZ_of_Y_ne'
+WeierstrassCurve.Jacobian.negAddY_eq'
+WeierstrassCurve.Jacobian.negAddY_of_X_eq'
+WeierstrassCurve.Jacobian.neg_of_Z_eq_zero'
+WeierstrassCurve.Jacobian.Y_eq_iff'
+WeierstrassCurve.Jacobian.Y_eq_of_Y_ne'
+WeierstrassCurve.Jacobian.Y_ne_negY_of_Y_ne'
+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'
+WeierstrassCurve.Projective.dblX_eq'
+WeierstrassCurve.Projective.dblY_of_Y_eq'
+WeierstrassCurve.Projective.dblZ_ne_zero_of_Y_ne'
+WeierstrassCurve.Projective.equiv_iff_eq_of_Z_eq'
+WeierstrassCurve.Projective.isUnit_dblZ_of_Y_ne'
+WeierstrassCurve.Projective.negAddY_eq'
+WeierstrassCurve.Projective.negAddY_of_X_eq'
+WeierstrassCurve.Projective.negDblY_eq'
+WeierstrassCurve.Projective.negDblY_of_Y_eq'
+WeierstrassCurve.Projective.Y_eq_iff'
+WeierstrassCurve.Projective.Y_eq_of_Y_ne'
+WeierstrassCurve.Projective.Y_ne_negY_of_Y_ne'
+WellFounded.monotone_chain_condition'
+WfDvdMonoid.max_power_factor'
+WithBot.bot_mul'
+WithBot.coe_sInf'
+WithBot.coe_sSup'
+WithBot.le_coe_unbot'
+WithBot.mul_bot'
+WithBot.unbot_one'
+WithTop.coe_sInf'
+WithTop.coe_sSup'
+WithTop.distrib'
+WithTop.mul_top'
+WithTop.top_mul'
+WithTop.untop_one'
+WithZero.map'_map'
+WittVector.aeval_verschiebung_poly'
+WittVector.exists_eq_pow_p_mul'
+WittVector.idIsPolyI'
+WittVector.nth_mul_coeff'
+WittVector.poly_eq_of_wittPolynomial_bind_eq'
+WittVector.RecursionBase.solution_spec'
+WittVector.RecursionMain.succNthVal_spec'
+WittVector.truncate_mk'
+WriterT.callCC'
+WriterT.goto_mkLabel'
+WriterT.mkLabel'
+WType.cardinal_mk_eq_sum'
+WType.WType'
+Xor'
+xor_iff_not_iff'
+X_pow_sub_C_eq_prod'
+zero_le'
+zero_lt_one_add_norm_sq'
+zero_mem_ℓp'
+zero_ne_one'
+ZFSet.IsTransitive.sUnion'
+ZMod.cast_add'
+ZMod.cast_id'
+ZMod.cast_intCast'
+ZMod.cast_mul'
+ZMod.cast_natCast'
+ZMod.cast_one'
+ZMod.cast_pow'
+ZMod.cast_sub'
+ZMod.intCast_eq_intCast_iff'
+ZMod.invDFT_apply'
+ZMod.invDFT_def'
+ZMod.natCast_eq_natCast_iff'
+ZMod.natCast_self'
+ZMod.neg_val'
+ZMod.nontrivial'
+ZMod.val_mul'
+ZMod.val_neg'
+ZMod.val_one'
+ZMod.val_one''
+ZMod.val_unit'
+ZNum.cast_zero'
+ZNum.of_to_int'
+zpow_add'
+zpow_eq_zpow_emod'
+zpow_le_zpow'
+zpow_le_zpow_iff'
+zpow_lt_zpow'
+zpow_lt_zpow_iff'
+zpow_mul'
+zsmul_eq_mul'
+Zsqrtd.norm_eq_one_iff'
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 cd10aac529d97..438084797d9f2 100644
--- a/scripts/nolints.json
+++ b/scripts/nolints.json
@@ -6,30 +6,23 @@
["docBlame", "CongrState"],
["docBlame", "Cont"],
["docBlame", "ContT"],
- ["docBlame", "ExistsUnique"],
["docBlame", "IsDecEq"],
["docBlame", "IsDecRefl"],
- ["docBlame", "IsIdempotent"],
["docBlame", "IsLeftCancel"],
["docBlame", "IsRightCancel"],
- ["docBlame", "IsSymmOp"],
["docBlame", "LawfulMonadCont"],
["docBlame", "LeftCancelative"],
- ["docBlame", "LeftCommutative"],
["docBlame", "LeftDistributive"],
["docBlame", "LeftIdentity"],
["docBlame", "MonadCont"],
["docBlame", "MonadWriter"],
["docBlame", "One"],
["docBlame", "RightCancelative"],
- ["docBlame", "RightCommutative"],
["docBlame", "RightDistributive"],
["docBlame", "RightIdentity"],
["docBlame", "RightInverse"],
["docBlame", "Writer"],
["docBlame", "WriterT"],
- ["docBlame", "Xor'"],
- ["docBlame", "Zero"],
["docBlame", "cancelDenominators"],
["docBlame", "cancelDenominatorsAt"],
["docBlame", "cancelDenominatorsTarget"],
@@ -54,7 +47,6 @@
["docBlame", "«term∫_In_.._,_∂_»"],
["docBlame", "«term∮_InC(_,_),_»"],
["docBlame", "«term⨍_In_.._,_»"],
- ["docBlame", "timeCmd"],
["docBlame", "when"],
["docBlame", "whenM"],
["docBlame", "Action.V"],
@@ -92,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"],
@@ -275,7 +265,6 @@
["docBlame", "Nat.subInduction"],
["docBlame", "Nat.«termOrd_compl[_]_»"],
["docBlame", "Nat.«termOrd_proj[_]_»"],
- ["docBlame", "Nat.twoStepInduction"],
["docBlame", "One.one"],
["docBlame", "OptionT.callCC"],
["docBlame", "OptionT.mkLabel"],
@@ -293,7 +282,6 @@
["docBlame", "PowerBasis.basis"],
["docBlame", "PowerBasis.dim"],
["docBlame", "PowerBasis.gen"],
- ["docBlame", "PresheafOfModules.presheaf"],
["docBlame", "Pretrivialization.baseSet"],
["docBlame", "PrimeSpectrum.asIdeal"],
["docBlame", "ProbabilityTheory.«termEVar[_]»"],
@@ -301,9 +289,7 @@
["docBlame", "ProbabilityTheory.«term_=ₐₛ_»"],
["docBlame", "ProbabilityTheory.«term_[_]»"],
["docBlame", "ProbabilityTheory.«term_×ₖ_»"],
- ["docBlame", "ProbabilityTheory.«term_∘ₖ_»"],
["docBlame", "ProbabilityTheory.«term_≤ₐₛ_»"],
- ["docBlame", "ProbabilityTheory.«term_⊗ₖ_»"],
["docBlame", "ProbabilityTheory.«term_⟦_|_⟧»"],
["docBlame", "ProbabilityTheory.termℙ"],
["docBlame", "ProbabilityTheory.«term∂_/∂_»"],
@@ -324,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"],
@@ -385,7 +369,6 @@
["docBlame", "WriterT.mkLabel'"],
["docBlame", "WriterT.run"],
["docBlame", "WriterT.runThe"],
- ["docBlame", "Zero.zero"],
["docBlame", "Zsqrtd.im"],
["docBlame", "Zsqrtd.re"],
["docBlame", "algebraMap.coeHTCT"],
@@ -519,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"],
@@ -553,7 +535,6 @@
["docBlame", "Order.PFilter.dual"],
["docBlame", "PProd.mk.injArrow"],
["docBlame", "PicardLindelof.FunSpace.toFun"],
- ["docBlame", "PresheafOfModules.Hom.hom"],
["docBlame", "Prod.mk.injArrow"],
["docBlame", "QuaternionAlgebra.Basis.i"],
["docBlame", "QuaternionAlgebra.Basis.j"],
@@ -584,7 +565,6 @@
["docBlame", "SlimCheck.Testable.run"],
["docBlame", "SlimCheck.Testable.runProp"],
["docBlame", "Stream'.WSeq.«term_~ʷ_»"],
- ["docBlame", "String.toAsciiByteArray.loop"],
["docBlame", "Submodule.quotientPi_aux.invFun"],
["docBlame", "Submodule.quotientPi_aux.toFun"],
["docBlame", "Tactic.Elementwise.tacticElementwise!___"],
@@ -642,7 +622,6 @@
["docBlame", "CategoryTheory.Triangulated.Octahedron.m₃"],
["docBlame", "FirstOrder.Language.ElementaryEmbedding.toFun"],
["docBlame", "FirstOrder.Language.ElementarySubstructure.toSubstructure"],
- ["docBlame", "FirstOrder.Language.IsOrdered.leSymb"],
["docBlame", "FirstOrder.Language.LEquiv.invLHom"],
["docBlame", "FirstOrder.Language.LEquiv.toLHom"],
["docBlame", "FirstOrder.Language.LHom.onFunction"],
@@ -728,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"],
@@ -765,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"]]
\ No newline at end of file
+ ["unusedArguments", "Combinator.K"]]
diff --git a/scripts/noshake.json b/scripts/noshake.json
index c46e9cdf6313c..f2f21e3466599 100644
--- a/scripts/noshake.json
+++ b/scripts/noshake.json
@@ -39,7 +39,9 @@
"Mathlib.CategoryTheory.Category.Init",
"Mathlib.Combinatorics.SimpleGraph.Init",
"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",
@@ -101,7 +103,7 @@
"Mathlib.Tactic.FinCases",
"Mathlib.Tactic.Find",
"Mathlib.Tactic.GCongr",
- "Mathlib.Tactic.GCongr.Core",
+ "Mathlib.Tactic.GCongr.CoreAttrs",
"Mathlib.Tactic.Generalize",
"Mathlib.Tactic.GeneralizeProofs",
"Mathlib.Tactic.Group",
@@ -147,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",
@@ -193,8 +194,12 @@
"ignoreAll":
["Batteries.Tactic.Basic", "Mathlib.Mathport.Syntax", "Mathlib.Tactic.Linter"],
"ignore":
- {"Mathlib.Topology.Sheaves.Forget": ["Mathlib.Algebra.Category.Ring.Limits"],
- "Mathlib.Topology.Order.LeftRightNhds": ["Mathlib.Algebra.Ring.Pointwise.Set"],
+ {"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":
@@ -209,14 +214,16 @@
"Mathlib.Tactic.Use": ["Batteries.Logic"],
"Mathlib.Tactic.TermCongr": ["Mathlib.Logic.Basic"],
"Mathlib.Tactic.Tauto": ["Mathlib.Logic.Basic"],
- "Mathlib.Tactic.TFAE": ["Mathlib.Data.List.TFAE"],
+ "Mathlib.Tactic.TFAE": ["Mathlib.Data.List.TFAE", "Mathlib.Tactic.Have"],
"Mathlib.Tactic.Subsingleton": ["Mathlib.Logic.Basic", "Std.Logic"],
"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",
@@ -234,10 +241,11 @@
"Mathlib.Tactic.Measurability":
["Mathlib.Algebra.Group.Defs", "Mathlib.Tactic.Measurability.Init"],
"Mathlib.Tactic.Linter.UnusedTactic": ["Batteries.Tactic.Unreachable"],
+ "Mathlib.Tactic.LinearCombination":
+ ["Mathlib.Tactic.LinearCombination.Lemmas"],
"Mathlib.Tactic.Lemma": ["Lean.Parser.Command"],
"Mathlib.Tactic.IrreducibleDef": ["Mathlib.Data.Subtype"],
- "Mathlib.Tactic.ITauto":
- ["Batteries.Logic", "Batteries.Tactic.Init", "Mathlib.Init.Logic"],
+ "Mathlib.Tactic.ITauto": ["Batteries.Tactic.Init", "Mathlib.Logic.Basic"],
"Mathlib.Tactic.Group": ["Mathlib.Algebra.Group.Commutator"],
"Mathlib.Tactic.GCongr.Core": ["Mathlib.Order.Defs"],
"Mathlib.Tactic.GCongr": ["Mathlib.Tactic.Positivity.Core"],
@@ -258,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",
@@ -269,6 +282,8 @@
"Mathlib.Tactic.Continuity": ["Mathlib.Tactic.Continuity.Init"],
"Mathlib.Tactic.CongrExclamation": ["Mathlib.Logic.Basic"],
"Mathlib.Tactic.Choose": ["Mathlib.Logic.Function.Basic"],
+ "Mathlib.Tactic.CategoryTheory.ToApp":
+ ["Mathlib.CategoryTheory.Category.Cat"],
"Mathlib.Tactic.CategoryTheory.Slice":
["Mathlib.CategoryTheory.Category.Basic"],
"Mathlib.Tactic.CategoryTheory.Reassoc":
@@ -289,18 +304,24 @@
["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"],
"Mathlib.Tactic.Basic": ["Mathlib.Tactic.Linter.OldObtain"],
"Mathlib.Tactic.Attr.Register": ["Lean.Meta.Tactic.Simp.SimpTheorems"],
"Mathlib.Tactic.ArithMult": ["Mathlib.Tactic.ArithMult.Init"],
+ "Mathlib.Tactic.Algebraize": ["Mathlib.Algebra.Algebra.Tower"],
"Mathlib.RingTheory.PowerSeries.Basic":
["Mathlib.Algebra.CharP.Defs", "Mathlib.Tactic.MoveAdd"],
"Mathlib.RingTheory.PolynomialAlgebra": ["Mathlib.Data.Matrix.DMatrix"],
"Mathlib.RingTheory.MvPolynomial.Homogeneous":
["Mathlib.Algebra.DirectSum.Internal"],
+ "Mathlib.RingTheory.KrullDimension.Basic":
+ ["Mathlib.Algebra.MvPolynomial.CommRing", "Mathlib.Algebra.Polynomial.Basic"],
+ "Mathlib.RingTheory.IntegralClosure.IsIntegral.Defs":
+ ["Mathlib.Tactic.Algebraize"],
+ "Mathlib.RingTheory.Finiteness":
+ ["Mathlib.Algebra.Algebra.RestrictScalars", "Mathlib.Tactic.Algebraize"],
"Mathlib.RingTheory.Binomial": ["Mathlib.Algebra.Order.Floor"],
"Mathlib.RepresentationTheory.FdRep":
["Mathlib.CategoryTheory.Monoidal.Rigid.Braided"],
@@ -312,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"],
@@ -323,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"],
@@ -331,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"],
@@ -350,15 +372,14 @@
"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.Data.Option.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"],
- "Mathlib.Data.DFinsupp.Notation": ["Mathlib.Data.Finsupp.Notation"],
"Mathlib.Data.ByteArray": ["Batteries.Data.ByteSubarray"],
"Mathlib.Data.Bool.Basic": ["Batteries.Tactic.Init"],
"Mathlib.Control.Traversable.Instances": ["Mathlib.Control.Applicative"],
@@ -368,10 +389,22 @@
["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":
+ ["Mathlib.Tactic.CategoryTheory.Monoidal.Basic"],
"Mathlib.CategoryTheory.Limits.Shapes.FiniteLimits":
["Mathlib.CategoryTheory.Limits.Shapes.Pullback.HasPullback",
"Mathlib.CategoryTheory.Limits.Shapes.Pullbacks"],
"Mathlib.CategoryTheory.Limits.IsLimit": ["Batteries.Tactic.Congr"],
+ "Mathlib.CategoryTheory.Category.Basic": ["Mathlib.Tactic.StacksAttribute"],
+ "Mathlib.CategoryTheory.Bicategory.Functor.Oplax":
+ ["Mathlib.Tactic.CategoryTheory.ToApp"],
+ "Mathlib.CategoryTheory.Bicategory.Functor.Lax":
+ ["Mathlib.Tactic.CategoryTheory.ToApp"],
+ "Mathlib.CategoryTheory.Bicategory.Adjunction":
+ ["Mathlib.Tactic.CategoryTheory.Bicategory.Basic"],
"Mathlib.Analysis.Normed.Operator.LinearIsometry":
["Mathlib.Algebra.Star.Basic"],
"Mathlib.Analysis.InnerProductSpace.Basic":
@@ -394,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/print-style-errors.sh b/scripts/print-style-errors.sh
index f9aad79d7e63d..f48fdd08c79a1 100755
--- a/scripts/print-style-errors.sh
+++ b/scripts/print-style-errors.sh
@@ -1,11 +1,16 @@
#!/usr/bin/env bash
+# Make this script robust against unintentional errors.
+# See e.g. http://redsymbol.net/articles/unofficial-bash-strict-mode/ for explanation.
+set -euo pipefail
+IFS=$'\n\t'
+
# Print all errors of the python style linter. This script is temporary and should be removed
# once the Python style linters have been rewritten in Lean.
# Humans should never run this directly, but at most through `lean exe lint-style --fix`
# use C locale so that sorting is the same on macOS and Linux
# see https://unix.stackexchange.com/questions/362728/why-does-gnu-sort-sort-differently-on-my-osx-machine-and-linux-machine
-find Mathlib -name '*.lean' | xargs ./scripts/lint-style.py "$@" | LC_ALL=C sort
-find Archive -name '*.lean' | xargs ./scripts/lint-style.py "$@" | LC_ALL=C sort
-find Counterexamples -name '*.lean' | xargs ./scripts/lint-style.py "$@" | LC_ALL=C sort
+find Mathlib -name '*.lean' -print0 | xargs --null ./scripts/lint-style.py "$@" | LC_ALL=C sort || true
+find Archive -name '*.lean' -print0 | xargs --null ./scripts/lint-style.py "$@" | LC_ALL=C sort || true
+find Counterexamples -name '*.lean' -print0 | xargs --null ./scripts/lint-style.py "$@" | LC_ALL=C sort || true
diff --git a/scripts/technical-debt-metrics.sh b/scripts/technical-debt-metrics.sh
index 0d6a7018286bf..12a296f624908 100755
--- a/scripts/technical-debt-metrics.sh
+++ b/scripts/technical-debt-metrics.sh
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
+# 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,
# reporting also the change with respect to the same counts in
# Mathlib from last week.
@@ -7,18 +25,30 @@
# the script takes two optional arguments ``
# and tallies the same technical debts on `` using ``
# as a reference.
-
-if [ -n "${1}" ]; then
- currCommit="${1}"
-else
- currCommit="$(git rev-parse HEAD)"
-fi
-
-if [ -n "${2}" ]; then
- refCommit="${2}"
-else
- refCommit="$(git log --pretty=%H --since="$(date -I -d 'last week')" | tail -n -1)"
-fi
+currCommit="${1:-"$(git rev-parse HEAD)"}"
+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
# ...
@@ -28,28 +58,28 @@ fi
# 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
@@ -57,50 +87,45 @@ printf '%s|%s\n' "$(grep -c 'docBlame' scripts/nolints.json)" "documentation nol
# We count the number of large files, making sure to avoid counting the test file `test/Lint.lean`.
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"
-# We print the number of files, not the number of matches --- hence, the nested grep.
-printf '%s|%s\n' "$(git grep -c 'autoImplicit true' | grep -c -v 'test')" "non-test files with autoImplicit true"
+
+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 -)"
+
+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)}'
)"
-}
-
-# 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=|@$=='
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/scripts/update_nolints_CI.sh b/scripts/update_nolints_CI.sh
index ee3880c3a4aa2..551b6664fa1e5 100755
--- a/scripts/update_nolints_CI.sh
+++ b/scripts/update_nolints_CI.sh
@@ -3,7 +3,11 @@
# Check if there are changes to `nolints.json` and file a PR updating it if necessary.
# DO NOT run this as a human; this is meant only for automation usage!
-set -e
+# Make this script robust against unintentional errors.
+# See e.g. http://redsymbol.net/articles/unofficial-bash-strict-mode/ for explanation.
+set -euo pipefail
+IFS=$'\n\t'
+
set -x
remote_name=origin-bot
@@ -17,7 +21,7 @@ git rev-parse --verify --quiet "refs/remotes/${remote_name}/${branch_name}" && e
# Exit if there are no changes relative to master
git diff-index --quiet "refs/remotes/${remote_name}/master" -- scripts/nolints.json && exit 0
-pr_title='chore(scripts): update nolints.json
+pr_title='chore(scripts): update nolints.json'
pr_body='I am happy to remove some nolints for you!'
git checkout -b "$branch_name"
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/Bicategory/Basic.lean b/test/CategoryTheory/Bicategory/Basic.lean
new file mode 100644
index 0000000000000..14c74e2ad760c
--- /dev/null
+++ b/test/CategoryTheory/Bicategory/Basic.lean
@@ -0,0 +1,21 @@
+import Mathlib.Tactic.CategoryTheory.Bicategory.Basic
+
+open CategoryTheory Mathlib.Tactic BicategoryLike
+open Bicategory
+
+universe w v u
+
+variable {B : Type u} [Bicategory.{w, v} B]
+variable {a b c d : B}
+
+example {f j : a ⟶ d} {g : a ⟶ b} {h : b ⟶ c} {i : c ⟶ d}
+ (η : f ⟶ g ≫ (h ≫ i)) (θ : (g ≫ h) ≫ i ⟶ j) :
+ η ⊗≫ θ = η ≫ (α_ _ _ _).inv ≫ θ := by
+ bicategory
+
+example {f : a ⟶ b} {g : b ⟶ c} {h i : c ⟶ d} (η : h ⟶ i) :
+ (f ≫ g) ◁ η = (α_ _ _ _).hom ≫ f ◁ g ◁ η ≫ (α_ _ _ _).inv := by
+ bicategory
+
+example {f g h : a ⟶ b} {η : f ⟶ g} {θ : g ⟶ h} : η ≫ θ = η ≫ θ := by
+ bicategory
diff --git a/test/CategoryTheory/Bicategory/Normalize.lean b/test/CategoryTheory/Bicategory/Normalize.lean
new file mode 100644
index 0000000000000..7e6b171a32ec0
--- /dev/null
+++ b/test/CategoryTheory/Bicategory/Normalize.lean
@@ -0,0 +1,54 @@
+import Mathlib.Tactic.CategoryTheory.Bicategory.Normalize
+
+open CategoryTheory Mathlib.Tactic BicategoryLike
+open Bicategory
+
+/-- `normalize% η` is the normalization of the 2-morphism `η`.
+1. The normalized 2-morphism is of the form `α₀ ≫ η₀ ≫ α₁ ≫ η₁ ≫ ... αₘ ≫ ηₘ ≫ αₘ₊₁` where
+ each `αᵢ` is a structural 2-morphism (consisting of associators and unitors),
+2. each `ηᵢ` is a non-structural 2-morphism of the form `f₁ ◁ ... ◁ fₘ ◁ θ`, and
+3. `θ` is of the form `ι ▷ g₁ ▷ ... ▷ gₗ`
+-/
+elab "normalize% " t:term:51 : term => do
+ let e ← Lean.Elab.Term.elabTerm t none
+ let ctx : Bicategory.Context ← BicategoryLike.mkContext e
+ CoherenceM.run (ctx := ctx) do
+ return (← BicategoryLike.eval `bicategory (← MkMor₂.ofExpr e)).expr.e.e
+
+universe w v u
+
+variable {B : Type u} [Bicategory.{w, v} B]
+variable {a b c d e : B}
+
+variable {f : a ⟶ b} {g : b ⟶ c} in
+#guard_expr normalize% f ◁ 𝟙 g = (whiskerLeftIso f (Iso.refl g)).hom
+variable {f : a ⟶ b} {g : b ⟶ c} in
+#guard_expr normalize% 𝟙 f ▷ g = (whiskerRightIso (Iso.refl f) g).hom
+variable {f : a ⟶ b} {g h i : b ⟶ c} {η : g ⟶ h} {θ : h ⟶ i} in
+#guard_expr normalize% f ◁ (η ≫ θ) = _ ≫ f ◁ η ≫ _ ≫ f ◁ θ ≫ _
+variable {f g h : a ⟶ b} {i : b ⟶ c} {η : f ⟶ g} {θ : g ⟶ h} in
+#guard_expr normalize% (η ≫ θ) ▷ i = _ ≫ η ▷ i ≫ _ ≫ θ ▷ i ≫ _
+variable {η : 𝟙 a ⟶ 𝟙 a} in
+#guard_expr normalize% 𝟙 a ◁ η = _ ≫ η ≫ _
+variable {f : a ⟶ b} {g : b ⟶ c} {h i : c ⟶ d} {η : h ⟶ i} in
+#guard_expr normalize% (f ≫ g) ◁ η = _ ≫ f ◁ g ◁ η ≫ _
+variable {η : 𝟙 a ⟶ 𝟙 a} in
+#guard_expr normalize% η ▷ 𝟙 a = _ ≫ η ≫ _
+variable {f g : a ⟶ b} {h : b ⟶ c} {i : c ⟶ d} {η : f ⟶ g} in
+#guard_expr normalize% η ▷ (h ≫ i) = _ ≫ η ▷ h ▷ i ≫ _
+variable {f : a ⟶ b} {g h : b ⟶ c} {i : c ⟶ d} {η : g ⟶ h} in
+#guard_expr normalize% (f ◁ η) ▷ i = _ ≫ f ◁ η ▷ i ≫ _
+variable {f : a ⟶ b} in
+#guard_expr normalize% (λ_ f).hom = (λ_ f).hom
+variable {f : a ⟶ b} in
+#guard_expr normalize% (λ_ f).inv = ((λ_ f).symm).hom
+variable {f : a ⟶ b} in
+#guard_expr normalize% (ρ_ f).hom = (ρ_ f).hom
+variable {f : a ⟶ b} in
+#guard_expr normalize% (ρ_ f).inv = ((ρ_ f).symm).hom
+variable {f : a ⟶ b} {g : b ⟶ c} {h : c ⟶ d} in
+#guard_expr normalize% (α_ f g h).hom = (α_ _ _ _).hom
+variable {f : a ⟶ b} {g : b ⟶ c} {h : c ⟶ d} in
+#guard_expr normalize% (α_ f g h).inv = ((α_ f g h).symm).hom
+variable {f : a ⟶ b} {g : b ⟶ c} in
+#guard_expr normalize% 𝟙 (f ≫ g) = (Iso.refl (f ≫ g)).hom
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/Monoidal.lean b/test/CategoryTheory/Monoidal.lean
deleted file mode 100644
index ef581db2d213a..0000000000000
--- a/test/CategoryTheory/Monoidal.lean
+++ /dev/null
@@ -1,52 +0,0 @@
-import Mathlib.Tactic.CategoryTheory.Monoidal
-import Mathlib.Tactic.CategoryTheory.Coherence
-
-open CategoryTheory
-open scoped MonoidalCategory
-
-universe v u
-
-variable {C : Type u} [Category.{v} C] [MonoidalCategory C]
-variable {X Y Z W : C} (f : X ⟶ Y) (g : Y ⟶ Z)
-
-#guard_expr normalize% X ◁ 𝟙 Y = X ◁ 𝟙 Y
-#guard_expr normalize% 𝟙 X ▷ Y = 𝟙 X ▷ Y
-#guard_expr normalize% X ◁ (f ≫ g) = _ ≫ X ◁ f ≫ _ ≫ X ◁ g ≫ _
-#guard_expr normalize% (f ≫ g) ▷ Y = _ ≫ f ▷ Y ≫ _ ≫ g ▷ Y ≫ _
-#guard_expr normalize% 𝟙_ C ◁ f = _ ≫ f ≫ _
-#guard_expr normalize% (X ⊗ Y) ◁ f = _ ≫ X ◁ Y ◁ f ≫ _
-#guard_expr normalize% f ▷ 𝟙_ C = _ ≫ f ≫ _
-#guard_expr normalize% f ▷ (X ⊗ Y) = _ ≫ f ▷ X ▷ Y ≫ _
-#guard_expr normalize% (X ◁ f) ▷ Y = _ ≫ X ◁ f ▷ Y ≫ _
-#guard_expr normalize% (λ_ X).hom = (λ_ X).hom
-#guard_expr normalize% (λ_ X).inv = (λ_ X).inv
-#guard_expr normalize% (ρ_ X).hom = (ρ_ X).hom
-#guard_expr normalize% (ρ_ X).inv = (ρ_ X).inv
-#guard_expr normalize% (α_ X Y Z).hom = (α_ _ _ _).hom
-#guard_expr normalize% (α_ X Y Z).inv = (α_ _ _ _).inv
-#guard_expr normalize% 𝟙 (X ⊗ Y) = 𝟙 (X ⊗ Y)
-variable {V₁ V₂ V₃ : C} (R : ∀ V₁ V₂ : C, V₁ ⊗ V₂ ⟶ V₂ ⊗ V₁) in
-#guard_expr normalize% R V₁ V₂ ▷ V₃ ⊗≫ V₂ ◁ R V₁ V₃ = _ ≫ R V₁ V₂ ▷ V₃ ≫ _ ≫ V₂ ◁ R V₁ V₃ ≫ _
-
-example (f : U ⟶ V ⊗ (W ⊗ X)) (g : (V ⊗ W) ⊗ X ⟶ Y) :
- f ⊗≫ g = f ≫ 𝟙 _ ≫ (α_ _ _ _).inv ≫ g := by
- monoidal_nf
- repeat' apply congrArg₂ (· ≫ ·) ?_ <| congrArg₂ (· ≫ ·) rfl ?_
- all_goals pure_coherence
-
-example : (X ⊗ Y) ◁ f = (α_ _ _ _).hom ≫ X ◁ Y ◁ f ≫ (α_ _ _ _).inv := by
- monoidal_nf
- repeat' apply congrArg₂ (· ≫ ·) ?_ <| congrArg₂ (· ≫ ·) rfl ?_
- all_goals pure_coherence
-
-example : f ≫ g = f ≫ g := by
- monoidal_nf
- repeat' apply congrArg₂ (· ≫ ·) ?_ <| congrArg₂ (· ≫ ·) rfl ?_
- all_goals pure_coherence
-
-example {V₁ V₂ V₃ : C} (R : ∀ V₁ V₂ : C, V₁ ⊗ V₂ ⟶ V₂ ⊗ V₁) :
- R V₁ V₂ ▷ V₃ ⊗≫ V₂ ◁ R V₁ V₃ =
- R V₁ V₂ ▷ V₃ ≫ (α_ _ _ _).hom ⊗≫ 𝟙 _ ≫ V₂ ◁ R V₁ V₃ := by
- monoidal_nf
- repeat' apply congrArg₂ (· ≫ ·) ?_ <| congrArg₂ (· ≫ ·) rfl ?_
- all_goals pure_coherence
diff --git a/test/CategoryTheory/Monoidal/Basic.lean b/test/CategoryTheory/Monoidal/Basic.lean
new file mode 100644
index 0000000000000..c003140e47a35
--- /dev/null
+++ b/test/CategoryTheory/Monoidal/Basic.lean
@@ -0,0 +1,27 @@
+import Mathlib.Tactic.CategoryTheory.Monoidal.Basic
+
+open CategoryTheory Mathlib.Tactic BicategoryLike
+open MonoidalCategory
+
+universe v u
+
+variable {C : Type u} [Category.{v} C] [MonoidalCategory C]
+variable {X Y Z W : C} (f : X ⟶ Y) (g : Y ⟶ Z)
+
+example (f : U ⟶ V ⊗ (W ⊗ X)) (g : (V ⊗ W) ⊗ X ⟶ Y) :
+ f ⊗≫ g = f ≫ (α_ _ _ _).inv ≫ g := by
+ monoidal
+
+example (f : Z ⟶ W) : (X ⊗ Y) ◁ f = (α_ _ _ _).hom ≫ X ◁ Y ◁ f ≫ (α_ _ _ _).inv := by
+ monoidal
+
+example : f ≫ g = f ≫ g := by
+ monoidal
+
+example : (f ⊗ g) ▷ X = (α_ _ _ _).hom ≫ (f ⊗ g ▷ X) ≫ (α_ _ _ _).inv := by
+ monoidal
+
+example {V₁ V₂ V₃ : C} (R : ∀ V₁ V₂ : C, V₁ ⊗ V₂ ⟶ V₂ ⊗ V₁) :
+ R V₁ V₂ ▷ V₃ ⊗≫ V₂ ◁ R V₁ V₃ =
+ R V₁ V₂ ▷ V₃ ≫ (α_ _ _ _).hom ⊗≫ 𝟙 _ ≫ V₂ ◁ R V₁ V₃ := by
+ monoidal
diff --git a/test/CategoryTheory/Monoidal/Normalize.lean b/test/CategoryTheory/Monoidal/Normalize.lean
new file mode 100644
index 0000000000000..9ae14f44ac833
--- /dev/null
+++ b/test/CategoryTheory/Monoidal/Normalize.lean
@@ -0,0 +1,41 @@
+import Mathlib.Tactic.CategoryTheory.Monoidal.Normalize
+
+open CategoryTheory Mathlib.Tactic BicategoryLike
+open MonoidalCategory
+
+/-- `normalize% η` is the normalization of the 2-morphism `η`.
+1. The normalized 2-morphism is of the form `α₀ ≫ η₀ ≫ α₁ ≫ η₁ ≫ ... αₘ ≫ ηₘ ≫ αₘ₊₁` where
+ each `αᵢ` is a structural 2-morphism (consisting of associators and unitors),
+2. each `ηᵢ` is a non-structural 2-morphism of the form `f₁ ◁ ... ◁ fₘ ◁ θ`, and
+3. `θ` is of the form `ι ▷ g₁ ▷ ... ▷ gₗ`
+-/
+elab "normalize% " t:term:51 : term => do
+ let e ← Lean.Elab.Term.elabTerm t none
+ let ctx : Monoidal.Context ← BicategoryLike.mkContext e
+ CoherenceM.run (ctx := ctx) do
+ return (← BicategoryLike.eval `monoidal (← MkMor₂.ofExpr e)).expr.e.e
+
+universe v u
+
+variable {C : Type u} [Category.{v} C] [MonoidalCategory C]
+variable {X Y Z W : C} (f : X ⟶ Y) (g : Y ⟶ Z)
+
+#guard_expr normalize% X ◁ 𝟙 Y = (whiskerLeftIso X (Iso.refl Y)).hom
+#guard_expr normalize% 𝟙 X ▷ Y = (whiskerRightIso (Iso.refl X) Y).hom
+#guard_expr normalize% X ◁ (f ≫ g) = _ ≫ X ◁ f ≫ _ ≫ X ◁ g ≫ _
+#guard_expr normalize% (f ≫ g) ▷ Y = _ ≫ f ▷ Y ≫ _ ≫ g ▷ Y ≫ _
+#guard_expr normalize% 𝟙_ C ◁ f = _ ≫ f ≫ _
+#guard_expr normalize% (X ⊗ Y) ◁ f = _ ≫ X ◁ Y ◁ f ≫ _
+#guard_expr normalize% f ▷ 𝟙_ C = _ ≫ f ≫ _
+#guard_expr normalize% f ▷ (X ⊗ Y) = _ ≫ f ▷ X ▷ Y ≫ _
+#guard_expr normalize% (X ◁ f) ▷ Y = _ ≫ X ◁ f ▷ Y ≫ _
+#guard_expr normalize% (λ_ X).hom = (λ_ X).hom
+#guard_expr normalize% (λ_ X).inv = ((λ_ X).symm).hom
+#guard_expr normalize% (ρ_ X).hom = (ρ_ X).hom
+#guard_expr normalize% (ρ_ X).inv = ((ρ_ X).symm).hom
+#guard_expr normalize% (α_ X Y Z).hom = (α_ _ _ _).hom
+#guard_expr normalize% (α_ X Y Z).inv = ((α_ X Y Z).symm).hom
+#guard_expr normalize% 𝟙 (X ⊗ Y) = (Iso.refl (X ⊗ Y)).hom
+#guard_expr normalize% f ⊗ g = _ ≫ (f ⊗ g) ≫ _
+variable {V₁ V₂ V₃ : C} (R : ∀ V₁ V₂ : C, V₁ ⊗ V₂ ⟶ V₂ ⊗ V₁) in
+#guard_expr normalize% R V₁ V₂ ▷ V₃ ⊗≫ V₂ ◁ R V₁ V₃ = _ ≫ R V₁ V₂ ▷ V₃ ≫ _ ≫ V₂ ◁ R V₁ V₃ ≫ _
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/CategoryTheory/SubstHomLift.lean b/test/CategoryTheory/SubstHomLift.lean
new file mode 100644
index 0000000000000..fc07db561cd82
--- /dev/null
+++ b/test/CategoryTheory/SubstHomLift.lean
@@ -0,0 +1,25 @@
+import Mathlib.CategoryTheory.FiberedCategory.HomLift
+
+universe u₁ v₁ u₂ v₂
+
+open CategoryTheory Category
+
+variable {𝒮 : Type u₁} {𝒳 : Type u₂} [Category.{v₁} 𝒳] [Category.{v₂} 𝒮] (p : 𝒳 ⥤ 𝒮)
+
+
+/-- Testing simple substitution -/
+example {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) [p.IsHomLift f φ] : f = f := by
+ subst_hom_lift p f φ
+ rename_i h
+ guard_hyp h : p.IsHomLift (p.map φ) φ
+ guard_target = p.map φ = p.map φ
+ trivial
+
+/-- Test substitution with more complicated expression -/
+example {R S T : 𝒮} {a b c : 𝒳} (f : R ⟶ S) (g : S ⟶ T) (φ : a ⟶ b) (ψ : b ⟶ c)
+ [p.IsHomLift f (φ ≫ ψ)] : f = f := by
+ subst_hom_lift p f (φ ≫ ψ)
+ rename_i h
+ guard_hyp h : p.IsHomLift (p.map (φ ≫ ψ)) (φ ≫ ψ)
+ guard_target = p.map (φ ≫ ψ) = p.map (φ ≫ ψ)
+ trivial
diff --git a/test/CategoryTheory/ToApp.lean b/test/CategoryTheory/ToApp.lean
new file mode 100644
index 0000000000000..6a4da3643397e
--- /dev/null
+++ b/test/CategoryTheory/ToApp.lean
@@ -0,0 +1,41 @@
+import Mathlib.Tactic.CategoryTheory.ToApp
+import Mathlib.CategoryTheory.Bicategory.Functor.Prelax
+
+universe w v u
+
+namespace CategoryTheory.ToAppTest
+
+open Bicategory Category
+
+variable {B : Type u} [Bicategory.{w, v} B] {a b c d e : B}
+
+@[to_app]
+theorem whiskerLeft_hom_inv (f : a ⟶ b) {g h : b ⟶ c} (η : g ≅ h) :
+ f ◁ η.hom ≫ f ◁ η.inv = 𝟙 (f ≫ g) := by
+ rw [← Bicategory.whiskerLeft_comp, Iso.hom_inv_id, Bicategory.whiskerLeft_id]
+
+example {a b c : Cat} (f : a ⟶ b) {g h : b ⟶ c} (η : g ≅ h) (X : a) :
+ η.hom.app (f.obj X) ≫ η.inv.app (f.obj X) = 𝟙 ((f ≫ g).obj X) :=
+ whiskerLeft_hom_inv_app f η X
+
+@[to_app]
+theorem pentagon_hom_hom_inv_inv_hom (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) (i : d ⟶ e) :
+ (α_ f (g ≫ h) i).hom ≫ f ◁ (α_ g h i).hom ≫ (α_ f g (h ≫ i)).inv =
+ (α_ f g h).inv ▷ i ≫ (α_ (f ≫ g) h i).hom :=
+ eq_of_inv_eq_inv (by simp)
+
+example {a b c d e : Cat} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) (i : d ⟶ e) (X : ↑a) :
+ (α_ f (g ≫ h) i).hom.app X ≫ (α_ g h i).hom.app (f.obj X) ≫ (α_ f g (h ≫ i)).inv.app X =
+ i.map ((α_ f g h).inv.app X) ≫ (α_ (f ≫ g) h i).hom.app X :=
+ pentagon_hom_hom_inv_inv_hom_app f g h i X
+
+@[to_app]
+theorem testThm {C : Type*} [Bicategory C] (F : PrelaxFunctor B C) {a b : B} {f g : a ⟶ b}
+ (η : f ⟶ g) : F.map₂ η ≫ F.map₂ (𝟙 g) = F.map₂ η := by simp
+
+example {B : Type u_1} [Bicategory B] (F : PrelaxFunctor B Cat)
+ {a b : B} {f g : a ⟶ b} (η : f ⟶ g) (X : ↑(F.obj a)) :
+ (F.map₂ η).app X ≫ (F.map₂ (𝟙 g)).app X = (F.map₂ η).app X :=
+ testThm_app F η X
+
+end CategoryTheory.ToAppTest
diff --git a/test/Continuity.lean b/test/Continuity.lean
index 7df66051c1b4e..bf0d389a95e2a 100644
--- a/test/Continuity.lean
+++ b/test/Continuity.lean
@@ -1,6 +1,6 @@
import Mathlib.Analysis.SpecialFunctions.Trigonometric.Basic
import Mathlib.Topology.Basic
-import Mathlib.Topology.ContinuousFunction.Basic
+import Mathlib.Topology.ContinuousMap.Basic
set_option autoImplicit true
section basic
@@ -45,7 +45,7 @@ example : Continuous (fun x : ℝ => exp ((max x (-x)) + sin x)^2) := by
example : Continuous (fun x : ℝ => exp ((max x (-x)) + sin (cos x))^2) := by
continuity
--- Examples taken from `Topology.ContinuousFunction.Basic`:
+-- Examples taken from `Topology.ContinuousMap.Basic`:
example (b : Y) : Continuous (fun _ : X => b) := by continuity
@@ -53,8 +53,7 @@ example (f : C(X, Y)) (g : C(Y, Z)) : Continuous (g ∘ f) := by continuity
example (f : C(X, Y)) (g : C(X, Z)) : Continuous (fun x => (f x, g x)) := by continuity
-example (f : C(X, Y)) (g : C(W, Z)) : Continuous (Prod.map f g) := --by continuity
- f.continuous.prod_map g.continuous
+example (f : C(X, Y)) (g : C(W, Z)) : Continuous (Prod.map f g) := by continuity
example (f : ∀ i, C(X, X' i)) : Continuous (fun a i => f i a) := by continuity
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/DefEqTransformations.lean b/test/DefEqTransformations.lean
index c71039b544292..496e641a680f8 100644
--- a/test/DefEqTransformations.lean
+++ b/test/DefEqTransformations.lean
@@ -1,5 +1,4 @@
import Mathlib.Tactic.DefEqTransformations
-import Mathlib.Init.Logic
set_option autoImplicit true
diff --git a/test/DocPrime.lean b/test/DocPrime.lean
new file mode 100644
index 0000000000000..3809fa9675e65
--- /dev/null
+++ b/test/DocPrime.lean
@@ -0,0 +1,80 @@
+import Mathlib.Tactic.Linter.DocPrime
+import Mathlib.Tactic.Lemma
+
+set_option linter.docPrime true
+
+-- no warning on a primed-declaration with a doc-string containing `'`
+/-- X' has a doc-string -/
+def X' := 0
+
+-- no warning on a declaration whose name contains a `'` *and does not end with it*
+def X'X := 0
+
+-- A list of universe names in the declaration is handled correctly, i.e. warns.
+/--
+warning: `Y'` is missing a doc-string, please add one.
+Declarations whose name ends with a `'` are expected to contain an explanation for the presence of a `'` in their doc-string. This may consist of discussion of the difference relative to the unprimed version, or an explanation as to why no better naming scheme is possible.
+note: this linter can be disabled with `set_option linter.docPrime false`
+-/
+#guard_msgs in
+def Y'.{u} := ULift.{u} Nat
+
+namespace X
+/--
+warning: `ABC.thm_no_doc1'` is missing a doc-string, please add one.
+Declarations whose name ends with a `'` are expected to contain an explanation for the presence of a `'` in their doc-string. This may consist of discussion of the difference relative to the unprimed version, or an explanation as to why no better naming scheme is possible.
+note: this linter can be disabled with `set_option linter.docPrime false`
+-/
+#guard_msgs in
+theorem _root_.ABC.thm_no_doc1' : True := .intro
+
+/--
+warning: `X.thm_no_doc2'` is missing a doc-string, please add one.
+Declarations whose name ends with a `'` are expected to contain an explanation for the presence of a `'` in their doc-string. This may consist of discussion of the difference relative to the unprimed version, or an explanation as to why no better naming scheme is possible.
+note: this linter can be disabled with `set_option linter.docPrime false`
+-/
+#guard_msgs in
+theorem thm_no_doc2' : True := .intro
+
+end X
+
+/--
+warning: `thm_no_doc'` is missing a doc-string, please add one.
+Declarations whose name ends with a `'` are expected to contain an explanation for the presence of a `'` in their doc-string. This may consist of discussion of the difference relative to the unprimed version, or an explanation as to why no better naming scheme is possible.
+note: this linter can be disabled with `set_option linter.docPrime false`
+-/
+#guard_msgs in
+theorem thm_no_doc' : True := .intro
+
+/--
+warning: `thm_with_attr_no_doc'` is missing a doc-string, please add one.
+Declarations whose name ends with a `'` are expected to contain an explanation for the presence of a `'` in their doc-string. This may consist of discussion of the difference relative to the unprimed version, or an explanation as to why no better naming scheme is possible.
+note: this linter can be disabled with `set_option linter.docPrime false`
+-/
+#guard_msgs in
+@[simp]
+theorem thm_with_attr_no_doc' : True := .intro
+
+/--
+warning: `inst_no_doc'` is missing a doc-string, please add one.
+Declarations whose name ends with a `'` are expected to contain an explanation for the presence of a `'` in their doc-string. This may consist of discussion of the difference relative to the unprimed version, or an explanation as to why no better naming scheme is possible.
+note: this linter can be disabled with `set_option linter.docPrime false`
+-/
+#guard_msgs in
+instance inst_no_doc' : True := .intro
+
+/--
+warning: `abbrev_no_doc'` is missing a doc-string, please add one.
+Declarations whose name ends with a `'` are expected to contain an explanation for the presence of a `'` in their doc-string. This may consist of discussion of the difference relative to the unprimed version, or an explanation as to why no better naming scheme is possible.
+note: this linter can be disabled with `set_option linter.docPrime false`
+-/
+#guard_msgs in
+abbrev abbrev_no_doc' : True := .intro
+
+/--
+warning: `def_no_doc'` is missing a doc-string, please add one.
+Declarations whose name ends with a `'` are expected to contain an explanation for the presence of a `'` in their doc-string. This may consist of discussion of the difference relative to the unprimed version, or an explanation as to why no better naming scheme is possible.
+note: this linter can be disabled with `set_option linter.docPrime false`
+-/
+#guard_msgs in
+def def_no_doc' : True := .intro
diff --git a/test/GCongr/inequalities.lean b/test/GCongr/inequalities.lean
index da96f38939562..02f0a2850793c 100644
--- a/test/GCongr/inequalities.lean
+++ b/test/GCongr/inequalities.lean
@@ -228,3 +228,13 @@ example {α β : Type*} [SemilatticeSup α] (f : β → α)
{s₁ s₂ : Finset β} (h : s₁ ⊆ s₂) (h₁ : s₁.Nonempty) (h₂ : s₂.Nonempty) :
s₁.sup' h₁ f ≤ s₂.sup' h₂ f := by
gcongr
+
+/-! Test that `gcongr` can solve side goals of the form `∀ i, f i` when `f i` is in scope for
+`positivity` -/
+
+example {ι : Type*} [Fintype ι] {f g : ι → ℝ} : ∏ i, f i ^ 2 ≤ ∏ i, g i ^ 2 := by
+ gcongr with i _ i _
+ · guard_target = 0 ≤ f i
+ exact test_sorry
+ · guard_target = f i ≤ g i
+ exact test_sorry
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 8a0bb34a3dbb1..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
@@ -284,69 +308,13 @@ info: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
#guard_msgs in
#eval List.range 27
-/-
-# Testing the `longFile` linter
-
-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;
-* `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.
-
--/
-
-section longFile
-
-/--
-warning: The default value of the `longFile` linter is 1500.
-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
-set_option linter.style.longFile 1500
-
/--
-warning: using 'exit' to interrupt Lean
+info: " \" " : String
---
-warning: The default value of the `longFile` linter is 1500.
-This file is 320 lines long which does not exceed the allowed bound.
-Please, remove the `set_option linter.style.longFile 1600`.
--/
-#guard_msgs in
--- Do not allow unnecessarily increasing the `longFile` linter option
-set_option linter.style.longFile 1600 in
-#exit
-
-/--
-warning: using 'exit' to interrupt Lean
----
-warning: This file is 335 lines long, but the limit is 10.
-
-You can extend the allowed length of the file using `set_option linter.style.longFile 1500`.
-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
-#exit
-
-/--
-warning: using 'exit' to interrupt Lean
----
-warning: The default value of the `longFile` linter is 1500.
-This file is 350 lines long which does not exceed the allowed bound.
-Please, remove the `set_option linter.style.longFile 1700`.
+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.
+note: this linter can be disabled with `set_option linter.style.longLine false`
-/
#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
-#exit
-
-end longFile
+set_option linter.style.longLine true in
+#check " \" "
diff --git a/test/LongFile.lean b/test/LongFile.lean
new file mode 100644
index 0000000000000..635f2ab485c30
--- /dev/null
+++ b/test/LongFile.lean
@@ -0,0 +1,126 @@
+import Mathlib.Tactic.Linter.Lint
+
+/-
+# Testing the `longFile` linter
+
+Things to note:
+* `set_option linter.style.longFile 0` disables the linter, allowing us to set a value smaller than
+ `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.
+
+-/
+
+section longFile
+
+/--
+warning: The default value of the `longFile` linter is 1500.
+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 `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 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.longFileDefValue 50 in
+set_option linter.style.longFile 60 in
+#exit
+
+/--
+warning: using 'exit' to interrupt Lean
+---
+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 200`.
+You can completely disable this linter by setting the length limit to `0`.
+-/
+#guard_msgs 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: 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
+-- 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/Polynomial.lean b/test/Polynomial.lean
index dde09d7984a81..e56b3b9a2c5b5 100644
--- a/test/Polynomial.lean
+++ b/test/Polynomial.lean
@@ -1,4 +1,5 @@
import Mathlib.Algebra.Polynomial.Basic
+import Mathlib.Algebra.Module.ULift
open Polynomial
diff --git a/test/ProdAssoc.lean b/test/ProdAssoc.lean
index 7802ba1458acd..38927efb92ffa 100644
--- a/test/ProdAssoc.lean
+++ b/test/ProdAssoc.lean
@@ -3,8 +3,7 @@ import Mathlib.Tactic.ProdAssoc
variable {α β γ δ : Type*}
example : (α × β) × (γ × δ) ≃ α × (β × γ) × δ := by
- have := (prod_assoc% : (α × β) × (γ × δ) ≃ α × (β × γ) × δ)
- exact this
+ exact (prod_assoc% : (α × β) × (γ × δ) ≃ α × (β × γ) × δ)
example : (α × β) × (γ × δ) ≃ α × (β × γ) × δ := prod_assoc%
diff --git a/test/RewriteSearch/Polynomial.lean b/test/RewriteSearch/Polynomial.lean
index 2fcec787de1f2..cf1cab0e57a5f 100644
--- a/test/RewriteSearch/Polynomial.lean
+++ b/test/RewriteSearch/Polynomial.lean
@@ -174,7 +174,7 @@ example {R : Type u} [Ring R] [Nontrivial R] (x : R) :
#guard_msgs(drop info) in
example {S : Type v} [Ring S] (c : S) :
Polynomial.nextCoeff (Polynomial.X - Polynomial.C c) = -c := by
- rw_search [-Polynomial.nextCoeff_X_sub_C]
+ rw_search
-- Mathlib proof:
-- rw [sub_eq_add_neg, ← map_neg C c, nextCoeff_X_add_C]
done
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/StacksAttribute.lean b/test/StacksAttribute.lean
index 6c50ed45a9269..92fe5efb40fcd 100644
--- a/test/StacksAttribute.lean
+++ b/test/StacksAttribute.lean
@@ -6,13 +6,13 @@ import Mathlib.Tactic.StacksAttribute
namespace X
-@[stacks A04Q "A comment"]
+@[stacks A04Q "A comment", kerodon B15R "Also a comment"]
theorem tagged : True := .intro
end X
#guard_msgs in
-@[stacks 0BR2, stacks 0X12]
+@[stacks 0BR2, kerodon 0X12]
example : True := .intro
@[stacks 0BR2, stacks 0X14 "I can also have a comment"]
@@ -36,9 +36,17 @@ True
#guard_msgs in
#stacks_tags!
+/--
+info:
+[Stacks Tag B15R](https://kerodon.net/tag/B15R) corresponds to declaration 'X.tagged'. (Also a comment)
+True
+-/
+#guard_msgs in
+#kerodon_tags!
+
section errors
-open Lean Parser Mathlib.Stacks
+open Lean Parser Mathlib.StacksTag
def captureException (env : Environment) (s : ParserFn) (input : String) : Except String Syntax :=
let ictx := mkInputContext input ""
diff --git a/test/StringDiagram.lean b/test/StringDiagram.lean
index 1933c6add2017..f6c65dc77c848 100644
--- a/test/StringDiagram.lean
+++ b/test/StringDiagram.lean
@@ -3,10 +3,10 @@ import ProofWidgets.Component.Panel.SelectionPanel
/-! ## Example use of string diagram widgets -/
-section MonoidalCategory
-
open ProofWidgets Mathlib.Tactic.Widget
+section MonoidalCategory
+
open CategoryTheory
open scoped MonoidalCategory
@@ -14,6 +14,8 @@ universe v u
variable {C : Type u} [Category.{v} C] [MonoidalCategory C]
+section
+
lemma left_triangle {X Y : C} (η : 𝟙_ _ ⟶ X ⊗ Y) (ε : Y ⊗ X ⟶ 𝟙_ _) (w : False) :
η ▷ X ≫ (α_ _ _ _).hom ≫ X ◁ ε = (λ_ _).hom ≫ (ρ_ _).inv := by
/- Displays string diagrams for the both sides of the goal. -/
@@ -57,4 +59,432 @@ example {X₁ Y₁ X₂ Y₂ : C} (f : X₁ ⟶ Y₁) (g : X₂ ⟶ Y₂) : f
rw [MonoidalCategory.whisker_exchange]
rw [MonoidalCategory.tensorHom_def]
+end
+
+set_option trace.string_diagram true
+
+variable {C : Type u} [Category.{v} C] [i : MonoidalCategory C] {X Y : C}
+
+/--
+info: [string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_1_0_0, E_1_1_1)
+ Left(E_2_0_0, E_2_1_1)
+ Left(E_3_0_0, E_3_1_1)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_1_1)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_2 := MakeString (E_1_1_1, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_1_1)
+
+[string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_1_0_0, E_1_1_1)
+ Left(E_2_0_0, E_2_1_1)
+ Left(E_3_0_0, E_3_1_1)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_1_1)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_2 := MakeString (E_1_1_1, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_1_1)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram MonoidalCategory.whisker_exchange
+
+/-- info: [string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_1_0_0, E_1_1_1)
+ Left(E_2_0_0, E_2_1_1)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_1_1)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_2 := MakeString (E_1_1_1, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_0_0)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+
+[string_diagram] Penrose substance: Left(E_0_0_0, E_0_1_1)
+ Left(E_1_0_0, E_1_1_1)
+ Left(E_2_0_0, E_2_1_1)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_1_1)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_2 := MakeString (E_1_1_1, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_0_0)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram MonoidalCategory.whisker_exchange_assoc
+
+/--
+info: [string_diagram] Penrose substance:
+
+[string_diagram] Penrose substance:
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram MonoidalCategory.pentagon
+
+/--
+info: [string_diagram] Penrose substance:
+
+[string_diagram] Penrose substance:
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram MonoidalCategory.whiskerLeft_id
+
+/--
+info: [string_diagram] Penrose substance:
+ Left(E_1_0_0, E_1_0_2)
+ Left(E_2_0_0, E_2_1_1)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_2)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_1 := MakeString (E_1_0_0, E_2_1_1)
+ Mor1 f_1_4 := MakeString (E_1_0_2, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+
+[string_diagram] Penrose substance:
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram left_triangle
+
+/--
+info: [string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_0_1_1, E_0_2_2)
+ Left(E_1_0_0, E_1_2_2)
+ Left(E_2_0_0, E_2_1_1)
+ Left(E_3_0_0, E_3_2_2)
+ Left(E_4_0_0, E_4_1_1)
+ Left(E_4_1_1, E_4_2_2)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_0_0)
+ Mor1 f_0_4 := MakeString (E_0_2_2, E_1_2_2)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_1 := MakeString (E_1_0_0, E_2_1_1)
+ Mor1 f_1_4 := MakeString (E_1_2_2, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_0_0)
+ Mor1 f_2_3 := MakeString (E_2_1_1, E_3_2_2)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+ Mor1 f_3_1 := MakeString (E_3_0_0, E_4_1_1)
+ Mor1 f_3_4 := MakeString (E_3_2_2, E_4_2_2)
+
+[string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_0_1_1, E_0_2_2)
+ Left(E_1_0_0, E_1_1_1)
+ Left(E_2_0_0, E_2_2_2)
+ Left(E_3_0_0, E_3_1_1)
+ Left(E_4_0_0, E_4_1_1)
+ Left(E_4_1_1, E_4_2_2)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_1_1)
+ Mor1 f_0_4 := MakeString (E_0_2_2, E_1_1_1)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_2 := MakeString (E_1_1_1, E_2_0_0)
+ Mor1 f_1_3 := MakeString (E_1_1_1, E_2_2_2)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_1 := MakeString (E_2_0_0, E_3_1_1)
+ Mor1 f_2_4 := MakeString (E_2_2_2, E_3_1_1)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+ Mor1 f_3_2 := MakeString (E_3_1_1, E_4_1_1)
+ Mor1 f_3_3 := MakeString (E_3_1_1, E_4_2_2)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram yang_baxter
+
+/--
+info: [string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_0_1_1, E_0_2_2)
+ Left(E_1_0_0, E_1_2_2)
+ Left(E_2_0_0, E_2_1_1)
+ Left(E_3_0_0, E_3_2_2)
+ Left(E_4_0_0, E_4_1_1)
+ Left(E_4_1_1, E_4_2_2)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_0_0)
+ Mor1 f_0_4 := MakeString (E_0_2_2, E_1_2_2)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_1 := MakeString (E_1_0_0, E_2_1_1)
+ Mor1 f_1_4 := MakeString (E_1_2_2, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_0_0)
+ Mor1 f_2_3 := MakeString (E_2_1_1, E_3_2_2)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+ Mor1 f_3_1 := MakeString (E_3_0_0, E_4_1_1)
+ Mor1 f_3_4 := MakeString (E_3_2_2, E_4_2_2)
+
+[string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_0_1_1, E_0_2_2)
+ Left(E_1_0_0, E_1_1_1)
+ Left(E_2_0_0, E_2_2_2)
+ Left(E_3_0_0, E_3_1_1)
+ Left(E_4_0_0, E_4_1_1)
+ Left(E_4_1_1, E_4_2_2)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_1_1)
+ Mor1 f_0_4 := MakeString (E_0_2_2, E_1_1_1)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_2 := MakeString (E_1_1_1, E_2_0_0)
+ Mor1 f_1_3 := MakeString (E_1_1_1, E_2_2_2)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_1 := MakeString (E_2_0_0, E_3_1_1)
+ Mor1 f_2_4 := MakeString (E_2_2_2, E_3_1_1)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+ Mor1 f_3_2 := MakeString (E_3_1_1, E_4_1_1)
+ Mor1 f_3_3 := MakeString (E_3_1_1, E_4_2_2)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram yang_baxter'
+
+/--
+info: [string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_0_1_1, E_0_2_2)
+ Left(E_1_0_0, E_1_2_2)
+ Left(E_2_0_0, E_2_1_1)
+ Left(E_3_0_0, E_3_2_2)
+ Left(E_4_0_0, E_4_1_1)
+ Left(E_4_1_1, E_4_2_2)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_0_0)
+ Mor1 f_0_4 := MakeString (E_0_2_2, E_1_2_2)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_1 := MakeString (E_1_0_0, E_2_1_1)
+ Mor1 f_1_4 := MakeString (E_1_2_2, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_0_0)
+ Mor1 f_2_3 := MakeString (E_2_1_1, E_3_2_2)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+ Mor1 f_3_1 := MakeString (E_3_0_0, E_4_1_1)
+ Mor1 f_3_4 := MakeString (E_3_2_2, E_4_2_2)
+
+[string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_0_1_1, E_0_2_2)
+ Left(E_1_0_0, E_1_1_1)
+ Left(E_2_0_0, E_2_2_2)
+ Left(E_3_0_0, E_3_1_1)
+ Left(E_4_0_0, E_4_1_1)
+ Left(E_4_1_1, E_4_2_2)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_1_1)
+ Mor1 f_0_4 := MakeString (E_0_2_2, E_1_1_1)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_2 := MakeString (E_1_1_1, E_2_0_0)
+ Mor1 f_1_3 := MakeString (E_1_1_1, E_2_2_2)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_1 := MakeString (E_2_0_0, E_3_1_1)
+ Mor1 f_2_4 := MakeString (E_2_2_2, E_3_1_1)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+ Mor1 f_3_2 := MakeString (E_3_1_1, E_4_1_1)
+ Mor1 f_3_3 := MakeString (E_3_1_1, E_4_2_2)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram yang_baxter''
+
+/--
+info: [string_diagram] Penrose substance:
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+
+[string_diagram] Penrose substance:
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram Category.assoc
+
+/--
+info: [string_diagram] Penrose substance:
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+
+[string_diagram] Penrose substance:
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram Functor.map_comp
+
+/--
+info: [string_diagram] Penrose substance:
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+
+[string_diagram] Penrose substance:
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram NatTrans.naturality
+
+variable (f : 𝟙_ _ ⟶ X ⊗ Y) in
+/--
+info: [string_diagram] Penrose substance:
+ Left(E_2_0_0, E_2_1_1)
+ Above(E_1_0_0, E_2_0_0)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_1 := MakeString (E_1_0_0, E_2_1_1)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram f
+
+variable (g : Y ⊗ X ⟶ 𝟙_ _) in
+/--
+info: [string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Above(E_0_0_0, E_1_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_0_0)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram g
+
+abbrev yangBaxterLhs {V₁ V₂ V₃ : C} (R : ∀ V₁ V₂ : C, V₁ ⊗ V₂ ⟶ V₂ ⊗ V₁) :=
+ R V₁ V₂ ▷ V₃ ≫ (α_ _ ..).hom ≫ _ ◁ R _ _ ≫ (α_ _ ..).inv ≫ R _ _ ▷ _ ≫ (α_ _ ..).hom
+
+/--
+info: [string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_0_1_1, E_0_2_2)
+ Left(E_1_0_0, E_1_2_2)
+ Left(E_2_0_0, E_2_1_1)
+ Left(E_3_0_0, E_3_2_2)
+ Left(E_4_0_0, E_4_1_1)
+ Left(E_4_1_1, E_4_2_2)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Above(E_3_0_0, E_4_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_0_0)
+ Mor1 f_0_4 := MakeString (E_0_2_2, E_1_2_2)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_1 := MakeString (E_1_0_0, E_2_1_1)
+ Mor1 f_1_4 := MakeString (E_1_2_2, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_0_0)
+ Mor1 f_2_3 := MakeString (E_2_1_1, E_3_2_2)
+ Mor1 f_3_0 := MakeString (E_3_0_0, E_4_0_0)
+ Mor1 f_3_1 := MakeString (E_3_0_0, E_4_1_1)
+ Mor1 f_3_4 := MakeString (E_3_2_2, E_4_2_2)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram yangBaxterLhs
+
end MonoidalCategory
+
+section Bicategory
+
+open CategoryTheory
+
+set_option trace.string_diagram true
+
+/--
+info: [string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_1_0_0, E_1_1_1)
+ Left(E_2_0_0, E_2_1_1)
+ Left(E_3_0_0, E_3_1_1)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_1_1)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_2 := MakeString (E_1_1_1, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_1_1)
+
+[string_diagram] Penrose substance:
+ Left(E_0_0_0, E_0_1_1)
+ Left(E_1_0_0, E_1_1_1)
+ Left(E_2_0_0, E_2_1_1)
+ Left(E_3_0_0, E_3_1_1)
+ Above(E_0_0_0, E_1_0_0)
+ Above(E_1_0_0, E_2_0_0)
+ Above(E_2_0_0, E_3_0_0)
+ Mor1 f_0_0 := MakeString (E_0_0_0, E_1_0_0)
+ Mor1 f_0_2 := MakeString (E_0_1_1, E_1_1_1)
+ Mor1 f_1_0 := MakeString (E_1_0_0, E_2_0_0)
+ Mor1 f_1_2 := MakeString (E_1_1_1, E_2_1_1)
+ Mor1 f_2_0 := MakeString (E_2_0_0, E_3_0_0)
+ Mor1 f_2_2 := MakeString (E_2_1_1, E_3_1_1)
+-/
+#guard_msgs (whitespace := lax) in
+#string_diagram Bicategory.whisker_exchange
+
+end Bicategory
diff --git a/test/TCSynth.lean b/test/TCSynth.lean
index f26afeaae9055..2371d40e8e971 100644
--- a/test/TCSynth.lean
+++ b/test/TCSynth.lean
@@ -84,9 +84,10 @@ end
section
-- Initial issue: https://github.com/leanprover-community/mathlib4/issues/12232
+-- reduced from 9000 to 1000 after `@[simp low] map_zero` in #16679 (only 10 needed)
open Equiv in
-set_option synthInstance.maxHeartbeats 9000 in
+set_option synthInstance.maxHeartbeats 1000 in
example {n : ℕ} (p : Fin (n + 1)) (e : Perm (Fin n)) :
Equiv.Perm.decomposeFin.symm (p, e) 0 = p := by simp
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/ValuedCSP.lean b/test/ValuedCSP.lean
index f60e3aed3e421..48b89612eacdc 100644
--- a/test/ValuedCSP.lean
+++ b/test/ValuedCSP.lean
@@ -40,6 +40,8 @@ private def exampleFiniteValuedInstance : exampleFiniteValuedCSP.Instance (Fin 2
example : exampleFiniteValuedInstance.IsOptimumSolution ![(0 : ℚ), (0 : ℚ)] := by
intro s
convert_to 0 ≤ exampleFiniteValuedInstance.evalSolution s
+ · simp [exampleFiniteValuedInstance, ValuedCSP.Instance.evalSolution]
+ exact Rat.zero_add 0
rw [ValuedCSP.Instance.evalSolution, exampleFiniteValuedInstance]
convert_to 0 ≤ |s 0| + |s 1|
· simp [ValuedCSP.unaryTerm, ValuedCSP.Term.evalSolution, Function.OfArity.uncurry]
diff --git a/test/aesop_cat.lean b/test/aesop_cat.lean
index 7790b9c1b983c..549cd69b92adb 100644
--- a/test/aesop_cat.lean
+++ b/test/aesop_cat.lean
@@ -10,6 +10,8 @@ example : Foo where
x := sorry
/--
+error: could not synthesize default value for field 'w' of 'Foo' using tactics
+---
error: tactic 'aesop' failed, failed to prove the goal after exhaustive search.
Initial goal:
⊢ 35 = 37
diff --git a/test/algebraize.lean b/test/algebraize.lean
new file mode 100644
index 0000000000000..1ccd695d0b920
--- /dev/null
+++ b/test/algebraize.lean
@@ -0,0 +1,131 @@
+import Mathlib.Tactic.Algebraize
+
+section example_definitions
+
+/-- Test property for when `RingHom` and `Algebra` properties are definitionally the same,
+see e.g. `RingHom.FiniteType` for a concrete example of this. -/
+class Algebra.testProperty1 (A B : Type*) [CommRing A] [CommRing B] [Algebra A B] : Prop where
+ out : ∀ x : A, algebraMap A B x = 0
+
+/-- Test property for when `RingHom` and `Algebra` properties are definitionally the same,
+see e.g. `RingHom.FiniteType` for a concrete example of this. -/
+@[algebraize]
+def RingHom.testProperty1 {A B : Type*} [CommRing A] [CommRing B] (f : A →+* B) : Prop :=
+ @Algebra.testProperty1 A B _ _ f.toAlgebra
+
+/-- Test property for when the `RingHom` porperty corresponds to a `Module` property (that is
+definitionally the same). See e.g. `Module.Finite` for a concrete example of this. -/
+class Module.testProperty2 (A M : Type*) [Semiring A] [AddCommMonoid M] [Module A M] : Prop where
+ out : ∀ x : A, ∀ M : M, x • M = 0
+
+/-- Test property for when the `RingHom` porperty corresponds to a `Module` property (that is
+definitionally the same). See e.g. `Module.Finite` for a concrete example of this. -/
+@[algebraize Module.testProperty2]
+def RingHom.testProperty2 {A B : Type*} [CommRing A] [CommRing B] (f : A →+* B) : Prop :=
+ letI : Algebra A B := f.toAlgebra
+ Module.testProperty2 A B
+
+/-- Test property for when the `RingHom` porperty corresponds to a `Algebra` property that is not
+definitionally the same, and needs to be created through a lemma. See e.g. `Algebra.IsIntegral` for
+an example. -/
+class Algebra.testProperty3 (A B : Type*) [CommRing A] [CommRing B] [Algebra A B] : Prop where
+ out : Algebra.testProperty1 A B
+
+/- Test property for when the `RingHom` porperty corresponds to a `Algebra` property that is not
+definitionally the same, and needs to be created through a lemma. See e.g. `Algebra.IsIntegral` for
+an example. -/
+@[algebraize Algebra.testProperty3.mk]
+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
+
+/-- Synthesize algebra instance from ring hom. -/
+example (A B : Type*) [CommRing A] [CommRing B] (f : A →+* B) : True := by
+ 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 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
+ fail_if_success -- Check that this instance is not available by default
+ have h : Algebra A C := inferInstance
+ algebraize [g.comp f]
+ guard_hyp algInst := (g.comp f).toAlgebra
+ trivial
+
+/-- Synthesize algebra instance and scalar tower instance from a composition -/
+example (A B C : Type*) [CommRing A] [CommRing B] [CommRing C] (f : A →+* B) (g : B →+* C) :
+ True := by
+ fail_if_success -- Check that this instance is not available by default
+ have h : IsScalarTower A B C := inferInstance
+ algebraize [f, g, g.comp f]
+ guard_hyp scalarTowerInst := IsScalarTower.of_algebraMap_eq' rfl
+ trivial
+
+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
+ 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
+ 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
+ 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). -/
+example (A B C : Type*) [CommRing A] [CommRing B] [CommRing C] (f : A →+* B) (g : B →+* C)
+ (hfg : (g.comp f).testProperty1) : True := by
+ fail_if_success -- Check that this instance is not available by default
+ have h : Algebra.Flat A C := inferInstance
+ fail_if_success
+ have h : IsScalarTower A B C := inferInstance
+ algebraize [f, g, g.comp f]
+ 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/cases.lean b/test/cases.lean
index b199a9b8748e9..664d0db8f51f8 100644
--- a/test/cases.lean
+++ b/test/cases.lean
@@ -1,6 +1,5 @@
import Batteries.Logic
import Mathlib.Tactic.Cases
-import Mathlib.Init.Logic
import Mathlib.Data.Nat.Notation
set_option autoImplicit true
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/fun_prop_dev.lean b/test/fun_prop_dev.lean
index f3f139b1913a3..f78abae43617a 100644
--- a/test/fun_prop_dev.lean
+++ b/test/fun_prop_dev.lean
@@ -107,10 +107,10 @@ structure LinHom (α β) where
infixr:25 " -o " => LinHom
instance : CoeFun (α ->> β) (fun _ => α → β) where
- coe := fun f => f.toFun
+ coe f := f.toFun
instance : FunLike (α -o β) α β where
- coe := fun f => f.toFun
+ coe f := f.toFun
coe_injective' := silentSorry
#eval Lean.Elab.Command.liftTermElabM do
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/interval_cases.lean b/test/interval_cases.lean
index bf08cde4046dd..02cbfc56c324a 100644
--- a/test/interval_cases.lean
+++ b/test/interval_cases.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2019 Scott Morrison. All rights reserved.
+Copyright (c) 2019 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Tactic.IntervalCases
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 720e3be8dae8d..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 : ℚ
@@ -260,10 +270,27 @@ example (a b : ℤ) (x y : ℝ) (hab : a = b) (hxy : x = y) : 2 * x = 2 * y := b
fail_if_success linear_combination 2 * hab
linear_combination 2 * hxy
-/-- error: To run 'linear_combination' without hypotheses, call it without input -/
+/--
+warning: this constant has no effect on the linear combination; it can be dropped from the term
+-/
+#guard_msgs in
+example (x y : ℤ) (h1 : 3 * x + 2 * y = 10) : 3 * x + 2 * y = 10 := by
+ linear_combination h1 + 3
+
+/--
+warning: this constant has no effect on the linear combination; it can be dropped from the term
+-/
#guard_msgs in
example (x : ℤ) : x ^ 2 = x ^ 2 := by linear_combination x ^ 2
+/-- error: 'linear_combination' supports only linear operations -/
+#guard_msgs in
+example {x y : ℤ} (h : x = y) : x ^ 2 = y ^ 2 := by linear_combination h * h
+
+/-- error: 'linear_combination' supports only linear operations -/
+#guard_msgs in
+example {x y : ℤ} (h : x = y) : 3 / x = 3 / y := by linear_combination 3 / h
+
/-! ### Cases with exponent -/
example (x y z : ℚ) (h : x = y) (h2 : x * y = 0) : x + y*z = 0 := by
diff --git a/test/matrix.lean b/test/matrix.lean
index 962e193b1ef97..522acbe923c7d 100644
--- a/test/matrix.lean
+++ b/test/matrix.lean
@@ -154,7 +154,7 @@ example {α : Type _} [CommRing α] {a b c d : α} :
Fin.isValue, of_apply, cons_val', empty_val', cons_val_fin_one, cons_val_zero, det_unique,
Fin.default_eq_zero, submatrix_apply, Fin.succ_zero_eq_one, cons_val_one, head_fin_const,
Fin.sum_univ_succ, Fin.val_zero, pow_zero, one_mul, Fin.zero_succAbove, head_cons,
- Finset.univ_unique, Fin.val_succ, Fin.coe_fin_one, zero_add, pow_one, cons_val_succ, neg_mul,
+ Finset.univ_unique, Fin.val_succ, Fin.val_eq_zero, zero_add, pow_one, cons_val_succ, neg_mul,
Fin.succ_succAbove_zero, Finset.sum_const, Finset.card_singleton, smul_neg, one_smul]
ring
@@ -167,7 +167,7 @@ example {α : Type _} [CommRing α] {a b c d e f g h i : α} :
submatrix_apply, Fin.succ_zero_eq_one, cons_val_one, head_cons, submatrix_submatrix,
det_unique, Fin.default_eq_zero, Function.comp_apply, Fin.succ_one_eq_two, cons_val_two,
tail_cons, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, pow_zero, one_mul,
- Fin.zero_succAbove, Finset.univ_unique, Fin.val_succ, Fin.coe_fin_one, zero_add, pow_one,
+ Fin.zero_succAbove, Finset.univ_unique, Fin.val_succ, Fin.val_eq_zero, zero_add, pow_one,
neg_mul, Fin.succ_succAbove_zero, Finset.sum_neg_distrib, Finset.sum_singleton, cons_val_succ,
Fin.succ_succAbove_one, even_two, Even.neg_pow, one_pow, Finset.sum_const,
Finset.card_singleton, one_smul]
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
new file mode 100644
index 0000000000000..b3ec8f57b5789
--- /dev/null
+++ b/test/module.lean
@@ -0,0 +1,309 @@
+/-
+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
+import Mathlib.Tactic.NoncommRing
+import Mathlib.Tactic.Positivity
+
+/-! # Tests for the module-normalization tactic -/
+
+open Mathlib.Tactic.LinearCombination
+
+variable {V : Type*} {K : Type*} {t u v w x y z : V} {a b c d e f μ ν ρ : K}
+
+/-! ### `ℕ` (most tests copied from the `abel` tactic) -/
+
+section Nat
+variable [AddCommMonoid V]
+
+example : x + (y + x) = x + x + y := by module
+example : (3 : ℕ) • x = x + (2 : ℕ) • x := by module
+example : 0 + x = x := by module
+example (n : ℕ) : n • x = n • x := by module
+example (n : ℕ) : 0 + n • x = n • x := by module
+example : x + (y + (x + (z + (x + (u + (x + v)))))) = v + u + z + y + 4 • x := by module
+example : x + y = y + x := by module
+example : x + 2 • x = 2 • x + x := by module
+
+example : x + (y + x) = x + x + y ∨ False := by
+ left
+ module
+
+/--
+error: unsolved goals
+V : Type u_1
+K : Type u_2
+t u v w x y z : V
+a b c d e f μ ν ρ : K
+inst✝ : AddCommMonoid V
+⊢ 1 = 1
+
+V : Type u_1
+K : Type u_2
+t u v w x y z : V
+a b c d e f μ ν ρ : K
+inst✝ : AddCommMonoid V
+⊢ 1 = 2 * 1
+-/
+#guard_msgs in
+example : x + y = x + 2 • y := by match_scalars
+
+/--
+error: ring failed, ring expressions not equal
+V : Type u_1
+K : Type u_2
+t u v w x y z : V
+a b c d e f μ ν ρ : K
+inst✝ : AddCommMonoid V
+⊢ 1 = 2
+-/
+#guard_msgs in
+example : x + y = x + 2 • y := by module
+
+/-- error: goal x ≠ y is not an equality -/
+#guard_msgs in
+example : x ≠ y := by module
+
+end Nat
+
+/-! ### `ℤ` (most tests copied from the `abel` tactic) -/
+
+variable [AddCommGroup V]
+
+example : (x + y) - ((y + x) + x) = -x := by module
+example : x - 0 = x := by module
+example : (3 : ℤ) • x = x + (2 : ℤ) • x := by module
+example : x - 2 • y = x - 2 • y := by module
+example : (x + y) - ((y + x) + x) = -x := by module
+example : x + y + (z + w - x) = y + z + w := by module
+example : x + y + z + (z - x - x) = (-1) • x + y + 2 • z := by module
+example : -x + x = 0 := by module
+example : x - (0 - 0) = x := by module
+example : x + (y - x) = y := by module
+example : -y + (z - x) = z - y - x := by module
+
+example : x + y = y + x ∧ (↑((1:ℕ) + 1) : ℚ) = 2 := by
+ constructor
+ module -- do not focus this tactic: the double goal is the point of the test
+ guard_target =ₐ (↑((1:ℕ) + 1) : ℚ) = 2
+ norm_cast
+
+-- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Interaction.20of.20abel.20with.20casting/near/319895001
+example : True := by
+ have : ∀ (p q r s : V), s + p - q = s - r - (q - r - p) := by
+ intro p q r s
+ module
+ trivial
+
+example : True := by
+ have : ∀ (p q r s : V), s + p - q = s - r - (q - r - p) := by
+ intro p q r s
+ match_scalars
+ · decide
+ · decide
+ · decide
+ · decide
+ trivial
+
+-- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Interaction.20of.20abel.20with.20casting/near/319897374
+example : y = x + z - (x - y + z) := by
+ have : True := trivial
+ module
+
+example : y = x + z - (x - y + z) := by
+ have : True := trivial
+ match_scalars <;> decide
+
+/--
+error: unsolved goals
+V : Type u_1
+K : Type u_2
+t u v w x y z : V
+a b c d e f μ ν ρ : K
+inst✝ : AddCommGroup V
+⊢ -1 + 1 = 0
+-/
+#guard_msgs in
+example : -x + x = 0 := by
+ match_scalars
+
+/-! ### Commutative ring -/
+
+section CommRing
+variable [CommRing K] [Module K V]
+
+example : a • x + b • x = (a + b) • x := by module
+example : a • x - b • x = (a - b) • x := by module
+example : a • x - b • y = a • x + (-b) • y := by module
+example : 2 • a • x = a • 2 • x := by module
+example : a • x - b • y = a • x + (-b) • y := by module
+example : (μ - ν) • a • x = (a • μ • x + b • ν • y) - ν • (a • x + b • y) := by module
+example : (μ - ν) • b • y = μ • (a • x + b • y) - (a • μ • x + b • ν • y) := by module
+
+-- from https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/smul.20diamond/near/457163013
+example : (4 : ℤ) • v = (4 : K) • v := by module
+example : (4 : ℕ) • v = (4 : K) • v := by module
+
+-- from https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/linear_combination.20for.20groups/near/437042918
+example : (1 + a ^ 2) • (v + w) - a • (a • v - w) = v + (1 + a + a ^ 2) • w := by module
+
+example (h : a = b) : a • x = b • x := by
+ match_scalars
+ linear_combination h
+
+/- `linear_combination` does not currently handle `•`. The following mimics what should eventually
+be performed by a `linear_combination` call, with exact syntax TBD -- maybe
+`linear_combination (norm := module) h • x` or `module_combination h • x`. -/
+example (h : a = b) : a • x = b • x := by
+ apply eq_of_add (congr($h • x):)
+ module
+
+example (h : a ^ 2 + b ^ 2 = 1) : a • (a • x - b • y) + (b • a • y + b • b • x) = x := by
+ match_scalars
+ · linear_combination h
+ · ring
+
+example (h : a ^ 2 + b ^ 2 = 1) : a • (a • x - b • y) + (b • a • y + b • b • x) = x := by
+ -- `linear_combination (norm := module) h • x`
+ apply eq_of_add (congr($h • x):)
+ module
+
+example (h1 : a • x + b • y = 0) (h2 : a • μ • x + b • ν • y = 0) :
+ (μ - ν) • a • x = 0 ∧ (μ - ν) • b • y = 0 := by
+ constructor
+ · -- `linear_combination (norm := module) h2 - ν • h1`
+ apply eq_of_add (congr($h2 - ν • $h1):)
+ module
+ · -- `linear_combination (norm := module) μ • h1 + h2`
+ apply eq_of_add (congr(μ • $h1 - $h2):)
+ module
+
+example (h1 : 0 • z + a • x + b • y = 0) (h2 : 0 • ρ • z + a • μ • x + b • ν • y = 0) :
+ (μ - ν) • a • x = 0 := by
+ -- `linear_combination (norm := module) h2 - ν • h1`
+ apply eq_of_add (congr($h2 - ν • $h1):)
+ module
+
+example
+ (h1 : a • x + b • y + c • z = 0)
+ (h2 : a • μ • x + b • ν • y + c • ρ • z = 0)
+ (h3 : a • μ • μ • x + b • ν • ν • y + c • ρ • ρ • z = 0) :
+ (μ - ν) • (μ - ρ) • a • x = 0 ∧ (μ - ν) • (ν - ρ) • b • y = 0
+ ∧ (μ - ρ) • (ν - ρ) • c • z = 0 := by
+ refine ⟨?_, ?_, ?_⟩
+ · -- `linear_combination (norm := module) h3 - (ν + ρ) • h2 + ν • ρ • h1`
+ apply eq_of_add (congr($h3 - (ν + ρ) • $h2 + ν • ρ • $h1):)
+ module
+ · -- `linear_combination (norm := module) - h3 + (μ + ρ) • h2 - μ • ρ • h1`
+ apply eq_of_add (congr(- $h3 + (μ + ρ) • $h2 - μ • ρ • $h1):)
+ module
+ · -- `linear_combination (norm := module) h3 - (μ + ν) • h2 + μ • ν • h1`
+ apply eq_of_add (congr($h3 - (μ + ν) • $h2 + μ • ν • $h1):)
+ module
+
+/--
+error: ring failed, ring expressions not equal
+V : Type u_1
+K : Type u_2
+t u v w x y z : V
+a b c d e f μ ν ρ : K
+inst✝² : AddCommGroup V
+inst✝¹ : CommRing K
+inst✝ : Module K V
+⊢ a * 2 = 2
+-/
+#guard_msgs in
+example : 2 • a • x = 2 • x := by module
+
+end CommRing
+
+/-! ### (Noncommutative) ring -/
+
+section Ring
+variable [Ring K] [Module K V]
+
+example : a • x + b • x = (b + a) • x := by
+ match_scalars
+ noncomm_ring
+
+example : 2 • a • x = a • (2:ℤ) • x := by
+ match_scalars
+ noncomm_ring
+
+example (h : a = b) : a • x = b • x := by
+ match_scalars
+ simp [h]
+
+example : (a - b) • a • x + b • b • x = a • a • x + b • (-a + b) • x := by
+ match_scalars
+ noncomm_ring
+
+end Ring
+
+/-! ### Characteristic-zero field -/
+
+section CharZeroField
+variable [Field K] [CharZero K] [Module K V]
+
+example : (2:K)⁻¹ • x + (3:K)⁻¹ • x + (6:K)⁻¹ • x = x := by module
+
+example (h₁ : t - u = -(v - w)) (h₂ : t + u = v + w) : t = w := by
+ -- `linear_combination (norm := module) 2⁻¹ • h₁ + 2⁻¹ • h₂`
+ apply eq_of_add (congr((2:K)⁻¹ • $h₁ + (2:K)⁻¹ • $h₂):)
+ module
+
+end CharZeroField
+
+/-! ### Linearly ordered field -/
+
+section LinearOrderedField
+variable [LinearOrderedField K] [Module K V]
+
+example (ha : 0 ≤ a) (hb : 0 < b) :
+ x = (a / (a + b)) • y + (b / (a + b)) • (x + (a / b) • (x - y)) := by
+ match_scalars
+ · field_simp
+ ring
+ · field_simp
+ ring
+
+-- From Analysis.Convex.StoneSeparation
+example (hab : 0 < a * b + c * d) :
+ (a * b / (a * b + c * d) * e) • u + (c * d / (a * b + c * d) * f) • v +
+ ((a * b / (a * b + c * d)) • d • x + (c * d / (a * b + c * d)) • b • y) =
+ (a * b + c * d)⁻¹ • ((a * b * e) • u + ((c * d * f) • v +
+ ((a * b) • d • x + (c * d) • b • y))) := by
+ match_scalars
+ · field_simp
+ · field_simp
+ · field_simp
+ · field_simp
+
+example (h₁ : 1 = a ^ 2 + b ^ 2) (h₂ : 1 - a ≠ 0) :
+ ((2 / (1 - a)) ^ 2 * b ^ 2 + 4)⁻¹ • (4:K) • ((2 / (1 - a)) • y)
+ + ((2 / (1 - a)) ^ 2 * b ^ 2 + 4)⁻¹ • ((2 / (1 - a)) ^ 2 * b ^ 2 - 4) • x
+ = a • x + y := by
+ -- `linear_combination (norm := skip) (h₁ * (b ^ 2 + (1 - a) ^ 2)⁻¹) • (y + (a - 1) • x)`
+ apply eq_of_add (congr(($h₁ * (b ^ 2 + (1 - a) ^ 2)⁻¹) • (y + (a - 1) • x)):)
+ match_scalars
+ · field_simp
+ ring
+ · field_simp
+ ring
+
+example (h₁ : 1 = a ^ 2 + b ^ 2) (h₂ : 1 - a ≠ 0) :
+ ((2 / (1 - a)) ^ 2 * b ^ 2 + 4)⁻¹ • (4:K) • ((2 / (1 - a)) • y)
+ + ((2 / (1 - a)) ^ 2 * b ^ 2 + 4)⁻¹ • ((2 / (1 - a)) ^ 2 * b ^ 2 - 4) • x
+ = a • x + y := by
+ match_scalars
+ · field_simp
+ linear_combination 4 * (1 - a) * h₁
+ · field_simp
+ linear_combination 4 * (a - 1) ^ 3 * h₁
+
+end LinearOrderedField
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 d75fda862bd69..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
@@ -23,6 +24,9 @@ example : 0 ≤ 3 := by positivity
example : 0 < 3 := by positivity
+example : (0 : ℝ≥0∞) < 1 := by positivity
+example : (0 : ℝ≥0∞) < 2 := by positivity
+
/- ## Goals working directly from a hypothesis -/
-- set_option trace.Meta.debug true
-- sudo set_option trace.Tactic.positivity true
@@ -286,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/propose.lean b/test/propose.lean
index 99c6ece1d4e46..04d97bb804156 100644
--- a/test/propose.lean
+++ b/test/propose.lean
@@ -2,6 +2,7 @@ import Mathlib.Tactic.Propose
import Mathlib.Tactic.GuardHypNums
import Mathlib.Algebra.Associated.Basic
import Mathlib.Data.Set.Subsingleton
+import Batteries.Data.List.Lemmas
-- For debugging, you may find these options useful:
-- set_option trace.Tactic.propose true
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/says.lean b/test/says.lean
index e2f9a3f834662..4315e51cb870d 100644
--- a/test/says.lean
+++ b/test/says.lean
@@ -101,7 +101,8 @@ def very_long_lemma_name_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa : Q → P := fun _
@[simp]
def very_long_lemma_name_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb : Q := trivial
/--
-info: Try this: aesop? says simp_all only [very_long_lemma_name_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
+info: Try this: aesop? says
+ simp_all only [very_long_lemma_name_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
very_long_lemma_name_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
-/
#guard_msgs in
diff --git a/test/set_like.lean b/test/set_like.lean
index a322a2c96e894..2847a594eb156 100644
--- a/test/set_like.lean
+++ b/test/set_like.lean
@@ -8,10 +8,10 @@ set_option autoImplicit true
section Delab
variable {M : Type u} [Monoid M] (S S' : Submonoid M)
-/-- info: { x // x ∈ S } → { x // x ∈ S' } : Type u -/
+/-- info: ↥S → ↥S' : Type u -/
#guard_msgs in #check S → S'
-/-- info: { x // x ∈ S } : Type u -/
+/-- info: ↥S : Type u -/
#guard_msgs in #check {x // x ∈ S}
/-- info: { x // 1 * x ∈ S } : Type u -/
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/solve_by_elim/basic.lean b/test/solve_by_elim/basic.lean
index 100df3cf25fd5..ce407f3089f28 100644
--- a/test/solve_by_elim/basic.lean
+++ b/test/solve_by_elim/basic.lean
@@ -1,9 +1,9 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
-import Mathlib.Init.Logic
+import Lean.Meta.Tactic.SolveByElim
import Mathlib.Tactic.Constructor
import Batteries.Tactic.PermuteGoals
import Batteries.Test.Internal.DummyLabelAttr
diff --git a/test/solve_by_elim/instances.lean b/test/solve_by_elim/instances.lean
index f92a260c4d24d..6c060e07c9f27 100644
--- a/test/solve_by_elim/instances.lean
+++ b/test/solve_by_elim/instances.lean
@@ -1,7 +1,7 @@
/-
-Copyright (c) 2021 Scott Morrison. All rights reserved.
+Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Scott Morrison
+Authors: Kim Morrison
-/
import Mathlib.Algebra.Order.GroupWithZero.Synonym
import Mathlib.Algebra.Order.Ring.Nat
diff --git a/test/tactic_timeout.lean b/test/tactic_timeout.lean
new file mode 100644
index 0000000000000..455b2ff5e2399
--- /dev/null
+++ b/test/tactic_timeout.lean
@@ -0,0 +1,98 @@
+import Mathlib.Tactic.Linarith
+
+/-!
+# Test that tactics respond to a cancellation request
+-/
+
+
+variable {α}
+
+open Lean Elab Tactic
+
+/-! versions of try/catch that catch `interrupted` too -/
+section catch_interrupted
+attribute [-instance]
+ Lean.instMonadExceptOfExceptionCoreM Lean.Elab.Tactic.instMonadExceptExceptionTacticM
+
+def Meta.tryCatchAll (m : MetaM α) (h : Exception → MetaM α) : MetaM α := tryCatch m h
+def Term.tryCatchAll (m : TermElabM α) (h : Exception → TermElabM α) : TermElabM α := tryCatch m h
+def Tactic.tryCatchAll (x : TacticM α) (h : Exception → TacticM α) : TacticM α := do
+ let b ← saveState
+ try x catch ex => b.restore; h ex
+
+end catch_interrupted
+
+section test_infra
+
+def Tactic.withTimeout (ms : UInt32) (t : TacticM α) : TacticM (α ⊕ Nat) := do
+ let tk ← IO.CancelToken.new
+ withTheReader Core.Context (fun s => { s with cancelTk? := some tk }) do
+ let t0 ← IO.monoMsNow
+ let watchdog ← IO.asTask do
+ IO.sleep ms
+ tk.set
+ let r ← Tactic.tryCatchAll (.inl <$> t)
+ (fun e => do
+ IO.cancel watchdog
+ if !e.isInterrupt || !(← tk.isSet) then
+ throw e
+ else
+ let duration := (← IO.monoMsNow) - t0
+ return .inr duration)
+ IO.cancel watchdog
+ return r
+
+/-- `with_timeout 100 => tac` allows `tac` only 100ms to run. -/
+elab "with_timeout " ms:num "=>" tac:tacticSeq : tactic => do
+ let ms := ms.getNat.toUInt32
+ if let .inr _duration ← Tactic.withTimeout ms (evalTactic tac) then
+ throwError f!"Tactic took more than {ms}ms"
+
+set_option linter.unusedTactic false
+
+/-- error: Tactic took more than 500ms -/
+#guard_msgs in
+example : True := by
+ with_timeout 500 =>
+ sleep 1000
+ trivial
+
+example: True := by
+ with_timeout 500 =>
+ sleep 100
+ trivial
+
+end test_infra
+
+/-- `check_timeouts 100 => tac` checks that `tac` never goes longer than `100ms` without checking
+for cancellation. -/
+elab "check_timeouts " tol_ms:num "=>" tac:tacticSeq : tactic => do
+ let mut t := 0
+ let tol_ms := tol_ms.getNat
+ repeat do
+ if let .inr duration ← Tactic.withTimeout t.toUInt32 (evalTactic tac) then
+ if duration > t + tol_ms then
+ logError f!"Tactic took much more than {t}ms ({duration}ms)"
+ trace[debug] "Tactic overran from {t}ms to {duration}ms"
+ else
+ break
+ t := t + tol_ms
+
+set_option maxHeartbeats 0
+set_option linter.unusedTactic false
+set_option linter.unusedVariables false
+
+theorem linear_combination_with_10_terms
+ (a b c d e f g h i j : Int)
+ (h0 : -e + g + -h + i = 0)
+ (h1 : b + -d + -e + f + g + i = 0)
+ (h2 : -b + j = 0)
+ (h3 : c + d + -f + -i = 0)
+ (h4 : b + c + e + -g + -h + i + j = 0)
+ (h5 : -a + b + d + f + -h + -i = 0)
+ (h6 : a + d + e + -g + -h = 0)
+ (h7 : -a + d + -f + -h + j = 0)
+ (h8 : a + -d + e + f + g + h + -i + j = 0)
+ (h9 : -a + b + c + -e + -f + h + j = 0) :
+ -2*a + b + 2*c + d + -3*f + -g + 3*h + -3*i = 0 := by
+ check_timeouts 250 => nlinarith
diff --git a/test/tfae.lean b/test/tfae.lean
index 71bab17d358db..677908af74af9 100644
--- a/test/tfae.lean
+++ b/test/tfae.lean
@@ -1,4 +1,5 @@
import Mathlib.Tactic.TFAE
+import Mathlib.Tactic.SuccessIfFailWithMsg
open List
set_option autoImplicit true
@@ -121,3 +122,47 @@ example (h₁ : P → Q) (h₂ : Q → P) : TFAE [P, Q] := by
tfae_finish
end context
+
+section term
+
+axiom P : Prop
+axiom Q : Prop
+axiom pq : P → Q
+axiom qp : Q → P
+
+example : TFAE [P, Q] := by
+ tfae_have h : 1 → 2 := pq
+ guard_hyp h : P → Q
+ tfae_have _ : 1 ← 2 := qp
+ tfae_finish
+
+example : TFAE [P, Q] := by
+ have n : ℕ := 4
+ tfae_have 1 → 2 := by
+ guard_hyp n : ℕ -- hypotheses are accessible (context is correct)
+ guard_target =ₛ P → Q -- expected type is known
+ exact pq
+ tfae_have 1 ← 2 := qp
+ tfae_finish
+
+example : TFAE [P, Q] := by
+ have n : ℕ := 3
+ tfae_have 2 ← 1 := fun p => ?Qgoal
+ case Qgoal => exact pq p
+ refine ?a
+ fail_if_success (tfae_have 1 ← 2 := ((?a).out 1 2 sorry sorry).mpr)
+ tfae_have 2 → 1 := qp
+ tfae_finish
+
+example : TFAE [P, Q] := by
+ tfae_have 1 → 2
+ | p => pq p
+ tfae_have 2 → 1
+ | q => qp q
+ tfae_finish
+
+example : TFAE [P, Q] := by
+ tfae_have ⟨mp, mpr⟩ : 1 ↔ 2 := ⟨pq, qp⟩
+ tfae_finish
+
+end term
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)